Thanks for the nice feature. It looks good to me. Reviewed-by: Yifeng Sun <[email protected]>
On Wed, Jan 31, 2018 at 11:36 AM, Ben Pfaff <[email protected]> wrote: > OpenFlow has little-known support for naming tables. Open vSwitch has > supported table names for ages, but it has never used or displayed them > outside of commands dedicated to table manipulation. This commit adds > support for table names in ovs-ofctl. When a table has a name, it displays > that name in flows and actions, so that, for example, the following: > table=1, arp, actions=resubmit(,2) > might become: > table=ingress_acl, arp, actions=resubmit(,mac_learning) > given appropriately named tables. > > For backward compatibility, only interactive ovs-ofctl commands by default > display table names; to display them in scripts, use the new --names > option. > > This feature was inspired by a talk that Kei Nohguchi presented at Open > vSwitch 2017 Fall Conference. > > CC: Kei Nohguchi <[email protected]> > Signed-off-by: Ben Pfaff <[email protected]> > --- > NEWS | 8 ++ > include/openvswitch/ofp-actions.h | 2 + > include/openvswitch/ofp-parse.h | 20 ++- > include/openvswitch/ofp-print.h | 12 +- > include/openvswitch/ofp-util.h | 8 ++ > lib/learn.c | 20 ++- > lib/learn.h | 6 +- > lib/learning-switch.c | 2 +- > lib/ofp-actions.c | 45 +++--- > lib/ofp-parse.c | 80 +++++++---- > lib/ofp-print.c | 202 ++++++++++++++++---------- > lib/ofp-util.c | 109 ++++++++++++-- > lib/vconn.c | 10 +- > ofproto/ofproto-dpif.c | 4 +- > ofproto/ofproto.c | 2 +- > ovn/controller/ofctrl.c | 12 +- > ovn/controller/pinctrl.c | 2 +- > ovn/utilities/ovn-sbctl.c | 2 +- > ovn/utilities/ovn-trace.c | 2 +- > tests/ofproto.at | 89 ++++++++---- > utilities/ovs-ofctl.8.in | 90 +++++++----- > utilities/ovs-ofctl.c | 294 ++++++++++++++++++++++++++++++ > +------- > utilities/ovs-testcontroller.c | 2 +- > 23 files changed, 736 insertions(+), 287 deletions(-) > > diff --git a/NEWS b/NEWS > index 726589ce3896..d76958b8adc0 100644 > --- a/NEWS > +++ b/NEWS > @@ -2,6 +2,14 @@ Post-v2.9.0 > -------------------- > - ovs-vswitchd: > * New options --l7 and --l7-len to "ofproto/trace" command. > + - ovs-ofctl: > + * ovs-ofctl now accepts and display table names in place of > numbers. By > + default it always accepts names and in interactive use it displays > them; > + use --names or --no-names to override. See ovs-ofctl(8) for > details. > + - ovs-vswitchd: > + * Previous versions gave OpenFlow tables default names of the form > + "table#". These are not helpful names for the purpose of accepting > + and displaying table names, so now tables by default have no names. > > > v2.9.0 - xx xxx xxxx > diff --git a/include/openvswitch/ofp-actions.h b/include/openvswitch/ofp- > actions.h > index 454c705ccf73..cba027b1d945 100644 > --- a/include/openvswitch/ofp-actions.h > +++ b/include/openvswitch/ofp-actions.h > @@ -1068,6 +1068,7 @@ uint32_t ofpacts_get_meter(const struct ofpact[], > size_t ofpacts_len); > struct ofpact_format_params { > /* Input. */ > const struct ofputil_port_map *port_map; > + const struct ofputil_table_map *table_map; > > /* Output. */ > struct ds *s; > @@ -1080,6 +1081,7 @@ const char *ofpact_name(enum ofpact_type); > struct ofpact_parse_params { > /* Input. */ > const struct ofputil_port_map *port_map; > + const struct ofputil_table_map *table_map; > > /* Output. */ > struct ofpbuf *ofpacts; > diff --git a/include/openvswitch/ofp-parse.h b/include/openvswitch/ofp- > parse.h > index 013a8f3edf70..c4228a50358f 100644 > --- a/include/openvswitch/ofp-parse.h > +++ b/include/openvswitch/ofp-parse.h > @@ -45,26 +45,33 @@ enum ofputil_protocol; > > char *parse_ofp_str(struct ofputil_flow_mod *, int command, const char > *str_, > const struct ofputil_port_map *, > + const struct ofputil_table_map *, > enum ofputil_protocol *usable_protocols) > OVS_WARN_UNUSED_RESULT; > > char *parse_ofp_flow_mod_str(struct ofputil_flow_mod *, const char > *string, > - const struct ofputil_port_map *, int command, > + const struct ofputil_port_map *, > + const struct ofputil_table_map *, > + int command, > enum ofputil_protocol *usable_protocols) > OVS_WARN_UNUSED_RESULT; > > char *parse_ofp_packet_out_str(struct ofputil_packet_out *po, const char > *str_, > const struct ofputil_port_map *, > + const struct ofputil_table_map *, > enum ofputil_protocol *usable_protocols) > OVS_WARN_UNUSED_RESULT; > > char *parse_ofp_table_mod(struct ofputil_table_mod *, > const char *table_id, const char > *flow_miss_handling, > + const struct ofputil_table_map *, > uint32_t *usable_versions) > OVS_WARN_UNUSED_RESULT; > > char *parse_ofp_flow_mod_file(const char *file_name, > - const struct ofputil_port_map *, int > command, > + const struct ofputil_port_map *, > + const struct ofputil_table_map *, > + int command, > struct ofputil_flow_mod **fms, size_t > *n_fms, > enum ofputil_protocol *usable_protocols) > OVS_WARN_UNUSED_RESULT; > @@ -72,6 +79,7 @@ char *parse_ofp_flow_mod_file(const char *file_name, > char *parse_ofp_flow_stats_request_str(struct ofputil_flow_stats_request > *, > bool aggregate, const char *string, > const struct ofputil_port_map *, > + const struct ofputil_table_map *, > enum ofputil_protocol > *usable_protocols) > OVS_WARN_UNUSED_RESULT; > > @@ -86,12 +94,14 @@ char *parse_ofp_meter_mod_str(struct > ofputil_meter_mod *, const char *string, > > char *parse_flow_monitor_request(struct ofputil_flow_monitor_request *, > const char *, > - const struct ofputil_port_map *port_map, > + const struct ofputil_port_map *, > + const struct ofputil_table_map *, > enum ofputil_protocol *usable_protocols) > OVS_WARN_UNUSED_RESULT; > > char *parse_ofp_group_mod_file(const char *file_name, > - const struct ofputil_port_map *, int > command, > + const struct ofputil_port_map *, > + const struct ofputil_table_map *, int > command, > struct ofputil_group_mod **gms, size_t > *n_gms, > enum ofputil_protocol *usable_protocols) > OVS_WARN_UNUSED_RESULT; > @@ -99,11 +109,13 @@ char *parse_ofp_group_mod_file(const char *file_name, > char *parse_ofp_group_mod_str(struct ofputil_group_mod *, int command, > const char *string, > const struct ofputil_port_map *, > + const struct ofputil_table_map *, > enum ofputil_protocol *usable_protocols) > OVS_WARN_UNUSED_RESULT; > > char *parse_ofp_bundle_file(const char *file_name, > const struct ofputil_port_map *, > + const struct ofputil_table_map *, > struct ofputil_bundle_msg **, size_t *n_bms, > enum ofputil_protocol *) > OVS_WARN_UNUSED_RESULT; > diff --git a/include/openvswitch/ofp-print.h b/include/openvswitch/ofp- > print.h > index d02634e3e91c..ed113786a28c 100644 > --- a/include/openvswitch/ofp-print.h > +++ b/include/openvswitch/ofp-print.h > @@ -31,6 +31,7 @@ struct ofp_header; > struct ofputil_flow_stats; > struct ofputil_port_map; > struct ofputil_table_features; > +struct ofputil_table_map; > struct ofputil_table_stats; > struct dp_packet; > > @@ -39,7 +40,7 @@ extern "C" { > #endif > > void ofp_print(FILE *, const void *, size_t, const struct > ofputil_port_map *, > - int verbosity); > + const struct ofputil_table_map *, int verbosity); > void ofp_print_packet(FILE *stream, const void *data, > size_t len, ovs_be32 packet_type); > void ofp_print_dp_packet(FILE *stream, const struct dp_packet *packet); > @@ -48,7 +49,7 @@ void ofp10_match_print(struct ds *, const struct > ofp10_match *, > const struct ofputil_port_map *, int verbosity); > > char *ofp_to_string(const void *, size_t, const struct ofputil_port_map *, > - int verbosity); > + const struct ofputil_table_map *, int verbosity); > char *ofp10_match_to_string(const struct ofp10_match *, > const struct ofputil_port_map *, int > verbosity); > char *ofp_packet_to_string(const void *data, size_t len, ovs_be32 > packet_type); > @@ -59,10 +60,13 @@ void ofp_print_table_features( > struct ds *, const struct ofputil_table_features *features, > const struct ofputil_table_features *prev_features, > const struct ofputil_table_stats *stats, > - const struct ofputil_table_stats *prev_stats); > + const struct ofputil_table_stats *prev_stats, > + const struct ofputil_table_map *table_map); > > void ofp_print_flow_stats(struct ds *, const struct ofputil_flow_stats *, > - const struct ofputil_port_map *, bool > show_stats); > + const struct ofputil_port_map *, > + const struct ofputil_table_map *, > + bool show_stats); > > #ifdef __cplusplus > } > diff --git a/include/openvswitch/ofp-util.h b/include/openvswitch/ofp- > util.h > index d9780dd44582..5dd1b34c216b 100644 > --- a/include/openvswitch/ofp-util.h > +++ b/include/openvswitch/ofp-util.h > @@ -816,6 +816,14 @@ void ofputil_table_map_put(struct ofputil_table_map *, > uint8_t, const char *name); > void ofputil_table_map_destroy(struct ofputil_table_map *); > > +/* Table numbers. */ > +bool ofputil_table_from_string(const char *, const struct > ofputil_table_map *, > + uint8_t *tablep); > +void ofputil_format_table(uint8_t table, const struct ofputil_table_map *, > + struct ds *); > +void ofputil_table_to_string(uint8_t, const struct ofputil_table_map *, > + char *namebuf, size_t bufsize); > + > /* Abstract ofp_table_mod. */ > struct ofputil_table_mod { > uint8_t table_id; /* ID of the table, 0xff indicates all > tables. */ > diff --git a/lib/learn.c b/lib/learn.c > index 9e321371c0a5..5164082f8e52 100644 > --- a/lib/learn.c > +++ b/lib/learn.c > @@ -381,6 +381,7 @@ learn_parse_spec(const char *orig, char *name, char > *value, > * error. The caller is responsible for freeing the returned string. */ > static char * OVS_WARN_UNUSED_RESULT > learn_parse__(char *orig, char *arg, const struct ofputil_port_map > *port_map, > + const struct ofputil_table_map *table_map, > struct ofpbuf *ofpacts) > { > struct ofpact_learn *learn; > @@ -396,8 +397,10 @@ learn_parse__(char *orig, char *arg, const struct > ofputil_port_map *port_map, > match_init_catchall(&match); > while (ofputil_parse_key_value(&arg, &name, &value)) { > if (!strcmp(name, "table")) { > - learn->table_id = atoi(value); > - if (learn->table_id == 255) { > + if (!ofputil_table_from_string(value, table_map, > + &learn->table_id)) { > + return xasprintf("unknown table \"%s\"", value); > + } else if (learn->table_id == 255) { > return xasprintf("%s: table id 255 not valid for `learn' " > "action", orig); > } > @@ -465,10 +468,11 @@ learn_parse__(char *orig, char *arg, const struct > ofputil_port_map *port_map, > * Modifies 'arg'. */ > char * OVS_WARN_UNUSED_RESULT > learn_parse(char *arg, const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map, > struct ofpbuf *ofpacts) > { > char *orig = xstrdup(arg); > - char *error = learn_parse__(orig, arg, port_map, ofpacts); > + char *error = learn_parse__(orig, arg, port_map, table_map, ofpacts); > free(orig); > return error; > } > @@ -477,16 +481,18 @@ learn_parse(char *arg, const struct ofputil_port_map > *port_map, > * describes. */ > void > learn_format(const struct ofpact_learn *learn, > - const struct ofputil_port_map *port_map, struct ds *s) > + const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map, > + struct ds *s) > { > const struct ofpact_learn_spec *spec; > struct match match; > > match_init_catchall(&match); > > - ds_put_format(s, "%slearn(%s%stable=%s%"PRIu8, > - colors.learn, colors.end, colors.special, colors.end, > - learn->table_id); > + ds_put_format(s, "%slearn(%s%stable=%s", > + colors.learn, colors.end, colors.special, colors.end); > + ofputil_format_table(learn->table_id, table_map, s); > if (learn->idle_timeout != OFP_FLOW_PERMANENT) { > ds_put_format(s, ",%sidle_timeout=%s%"PRIu16, > colors.param, colors.end, learn->idle_timeout); > diff --git a/lib/learn.h b/lib/learn.h > index 31d3a14e827a..2bdfee702dac 100644 > --- a/lib/learn.h > +++ b/lib/learn.h > @@ -28,6 +28,7 @@ struct ofpbuf; > struct ofpact_learn; > struct ofputil_flow_mod; > struct ofputil_port_map; > +struct ofputil_table_map; > struct nx_action_learn; > > /* NXAST_LEARN helper functions. > @@ -41,9 +42,10 @@ void learn_execute(const struct ofpact_learn *, const > struct flow *, > void learn_mask(const struct ofpact_learn *, struct flow_wildcards *); > > char *learn_parse(char *, const struct ofputil_port_map *, > - struct ofpbuf *ofpacts) > + const struct ofputil_table_map *, struct ofpbuf > *ofpacts) > OVS_WARN_UNUSED_RESULT; > void learn_format(const struct ofpact_learn *, > - const struct ofputil_port_map *, struct ds *); > + const struct ofputil_port_map *, > + const struct ofputil_table_map *, struct ds *); > > #endif /* learn.h */ > diff --git a/lib/learning-switch.c b/lib/learning-switch.c > index 5b014e5f3757..f840f034875f 100644 > --- a/lib/learning-switch.c > +++ b/lib/learning-switch.c > @@ -369,7 +369,7 @@ lswitch_process_packet(struct lswitch *sw, const > struct ofpbuf *msg) > } else if (type == OFPTYPE_FLOW_REMOVED) { > /* Nothing to do. */ > } else if (VLOG_IS_DBG_ENABLED()) { > - char *s = ofp_to_string(msg->data, msg->size, NULL, 2); > + char *s = ofp_to_string(msg->data, msg->size, NULL, NULL, 2); > VLOG_DBG_RL(&rl, "%016llx: OpenFlow packet ignored: %s", > sw->datapath_id, s); > free(s); > diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c > index 1000d6d1de6d..80dbd6dc57d6 100644 > --- a/lib/ofp-actions.c > +++ b/lib/ofp-actions.c > @@ -4398,14 +4398,10 @@ parse_RESUBMIT(char *arg, const struct > ofpact_parse_params *pp) > > table_s = strsep(&arg, ","); > if (table_s && table_s[0]) { > - uint32_t table_id = 0; > - char *error; > - > - error = str_to_u32(table_s, &table_id); > - if (error) { > - return error; > + if (!ofputil_table_from_string(table_s, pp->table_map, > + &resubmit->table_id)) { > + return xasprintf("%s: resubmit to unknown table", table_s); > } > - resubmit->table_id = table_id; > } else { > resubmit->table_id = 255; > } > @@ -4441,7 +4437,7 @@ format_RESUBMIT(const struct ofpact_resubmit *a, > } > ds_put_char(fp->s, ','); > if (a->table_id != 255) { > - ds_put_format(fp->s, "%"PRIu8, a->table_id); > + ofputil_format_table(a->table_id, fp->table_map, fp->s); > } > if (a->with_ct_orig) { > ds_put_cstr(fp->s, ",ct"); > @@ -5024,14 +5020,14 @@ encode_LEARN(const struct ofpact_learn *learn, > static char * OVS_WARN_UNUSED_RESULT > parse_LEARN(char *arg, const struct ofpact_parse_params *pp) > { > - return learn_parse(arg, pp->port_map, pp->ofpacts); > + return learn_parse(arg, pp->port_map, pp->table_map, pp->ofpacts); > } > > static void > format_LEARN(const struct ofpact_learn *a, > const struct ofpact_format_params *fp) > { > - learn_format(a, fp->port_map, fp->s); > + learn_format(a, fp->port_map, fp->table_map, fp->s); > } > > /* Action structure for NXAST_CONJUNCTION. */ > @@ -5372,10 +5368,11 @@ static void > format_UNROLL_XLATE(const struct ofpact_unroll_xlate *a, > const struct ofpact_format_params *fp) > { > - ds_put_format(fp->s, "%sunroll_xlate(%s%stable=%s%"PRIu8 > - ", %scookie=%s%"PRIu64"%s)%s", > + ds_put_format(fp->s, "%sunroll_xlate(%s%stable=%s", > colors.paren, colors.end, > - colors.special, colors.end, a->rule_table_id, > + colors.special, colors.end); > + ofputil_format_table(a->rule_table_id, fp->table_map, fp->s); > + ds_put_format(fp->s, ", %scookie=%s%"PRIu64"%s)%s", > colors.param, colors.end, ntohll(a->rule_cookie), > colors.paren, colors.end); > } > @@ -6038,8 +6035,10 @@ parse_CT(char *arg, const struct > ofpact_parse_params *pp) > } else if (!strcmp(key, "force")) { > oc->flags |= NX_CT_F_FORCE; > } else if (!strcmp(key, "table")) { > - error = str_to_u8(value, "recirc_table", &oc->recirc_table); > - if (!error && oc->recirc_table == NX_CT_RECIRC_NONE) { > + if (!ofputil_table_from_string(value, pp->table_map, > + &oc->recirc_table)) { > + error = xasprintf("unknown table %s", value); > + } else if (oc->recirc_table == NX_CT_RECIRC_NONE) { > error = xasprintf("invalid table %#"PRIx8, > oc->recirc_table); > } > } else if (!strcmp(key, "zone")) { > @@ -6125,8 +6124,9 @@ format_CT(const struct ofpact_conntrack *a, > ds_put_format(fp->s, "%sforce%s,", colors.value, colors.end); > } > if (a->recirc_table != NX_CT_RECIRC_NONE) { > - ds_put_format(fp->s, "%stable=%s%"PRIu8",", > - colors.special, colors.end, a->recirc_table); > + ds_put_format(fp->s, "%stable=%s", colors.special, colors.end); > + ofputil_format_table(a->recirc_table, fp->table_map, fp->s); > + ds_put_char(fp->s, ','); > } > if (a->zone_src.field) { > ds_put_format(fp->s, "%szone=%s", colors.param, colors.end); > @@ -6816,19 +6816,18 @@ static char * OVS_WARN_UNUSED_RESULT > parse_GOTO_TABLE(char *arg, const struct ofpact_parse_params *pp) > { > struct ofpact_goto_table *ogt = ofpact_put_GOTO_TABLE(pp->ofpacts); > - char *table_s = strsep(&arg, ","); > - if (!table_s || !table_s[0]) { > - return xstrdup("instruction goto-table needs table id"); > + if (!ofputil_table_from_string(arg, pp->table_map, &ogt->table_id)) { > + return xasprintf("unknown table \"%s\"", arg); > } > - return str_to_u8(table_s, "table", &ogt->table_id); > + return NULL; > } > > static void > format_GOTO_TABLE(const struct ofpact_goto_table *a, > const struct ofpact_format_params *fp) > { > - ds_put_format(fp->s, "%sgoto_table:%s%"PRIu8, > - colors.param, colors.end, a->table_id); > + ds_put_format(fp->s, "%sgoto_table:%s", colors.param, colors.end); > + ofputil_format_table(a->table_id, fp->table_map, fp->s); > } > > static void > diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c > index b68081740f09..1e30c20f4966 100644 > --- a/lib/ofp-parse.c > +++ b/lib/ofp-parse.c > @@ -322,6 +322,7 @@ extract_actions(char *s) > static char * OVS_WARN_UNUSED_RESULT > parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string, > const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map, > enum ofputil_protocol *usable_protocols) > { > enum { > @@ -450,7 +451,10 @@ parse_ofp_str__(struct ofputil_flow_mod *fm, int > command, char *string, > } > > if (!strcmp(name, "table")) { > - error = str_to_u8(value, "table", &fm->table_id); > + if (!ofputil_table_from_string(value, table_map, > + &fm->table_id)) { > + return xasprintf("unknown table \"%s\"", value); > + } > if (fm->table_id != 0xff) { > *usable_protocols &= OFPUTIL_P_TID; > } > @@ -559,6 +563,7 @@ parse_ofp_str__(struct ofputil_flow_mod *fm, int > command, char *string, > ofpbuf_init(&ofpacts, 32); > struct ofpact_parse_params pp = { > .port_map = port_map, > + .table_map = table_map, > .ofpacts = &ofpacts, > .usable_protocols = &action_usable_protocols > }; > @@ -610,12 +615,14 @@ parse_ofp_str__(struct ofputil_flow_mod *fm, int > command, char *string, > char * OVS_WARN_UNUSED_RESULT > parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, > const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map, > enum ofputil_protocol *usable_protocols) > { > char *string = xstrdup(str_); > char *error; > > - error = parse_ofp_str__(fm, command, string, port_map, > usable_protocols); > + error = parse_ofp_str__(fm, command, string, port_map, table_map, > + usable_protocols); > if (error) { > fm->ofpacts = NULL; > fm->ofpacts_len = 0; > @@ -630,6 +637,7 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int > command, const char *str_, > static char * OVS_WARN_UNUSED_RESULT > parse_ofp_packet_out_str__(struct ofputil_packet_out *po, char *string, > const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map, > enum ofputil_protocol *usable_protocols) > { > enum ofputil_protocol action_usable_protocols; > @@ -719,6 +727,7 @@ parse_ofp_packet_out_str__(struct ofputil_packet_out > *po, char *string, > if (act_str) { > struct ofpact_parse_params pp = { > .port_map = port_map, > + .table_map = table_map, > .ofpacts = &ofpacts, > .usable_protocols = &action_usable_protocols, > }; > @@ -750,12 +759,14 @@ out: > char * OVS_WARN_UNUSED_RESULT > parse_ofp_packet_out_str(struct ofputil_packet_out *po, const char *str_, > const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map, > enum ofputil_protocol *usable_protocols) > { > char *string = xstrdup(str_); > char *error; > > - error = parse_ofp_packet_out_str__(po, string, port_map, > usable_protocols); > + error = parse_ofp_packet_out_str__(po, string, port_map, table_map, > + usable_protocols); > if (error) { > po->ofpacts = NULL; > po->ofpacts_len = 0; > @@ -996,6 +1007,7 @@ static char * OVS_WARN_UNUSED_RESULT > parse_flow_monitor_request__(struct ofputil_flow_monitor_request *fmr, > const char *str_, > const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map, > char *string, > enum ofputil_protocol *usable_protocols) > { > @@ -1040,7 +1052,10 @@ parse_flow_monitor_request__(struct > ofputil_flow_monitor_request *fmr, > } > > if (!strcmp(name, "table")) { > - error = str_to_u8(value, "table", &fmr->table_id); > + if (!ofputil_table_from_string(value, table_map, > + &fmr->table_id)) { > + error = xasprintf("unknown table \"%s\"", value); > + } > } else if (!strcmp(name, "out_port")) { > fmr->out_port = u16_to_ofp(atoi(value)); > } else { > @@ -1064,11 +1079,12 @@ char * OVS_WARN_UNUSED_RESULT > parse_flow_monitor_request(struct ofputil_flow_monitor_request *fmr, > const char *str_, > const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map, > enum ofputil_protocol *usable_protocols) > { > char *string = xstrdup(str_); > - char *error = parse_flow_monitor_request__(fmr, str_, port_map, > string, > - usable_protocols); > + char *error = parse_flow_monitor_request__(fmr, str_, port_map, > table_map, > + string, usable_protocols); > free(string); > return error; > } > @@ -1084,10 +1100,12 @@ parse_flow_monitor_request(struct > ofputil_flow_monitor_request *fmr, > * error. The caller is responsible for freeing the returned string. */ > char * OVS_WARN_UNUSED_RESULT > parse_ofp_flow_mod_str(struct ofputil_flow_mod *fm, const char *string, > - const struct ofputil_port_map *port_map, int > command, > + const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map, > + int command, > enum ofputil_protocol *usable_protocols) > { > - char *error = parse_ofp_str(fm, command, string, port_map, > + char *error = parse_ofp_str(fm, command, string, port_map, table_map, > usable_protocols); > > if (!error) { > @@ -1167,16 +1185,16 @@ exit: > * error. The caller is responsible for freeing the returned string. */ > char * OVS_WARN_UNUSED_RESULT > parse_ofp_table_mod(struct ofputil_table_mod *tm, const char *table_id, > - const char *setting, uint32_t *usable_versions) > + const char *setting, > + const struct ofputil_table_map *table_map, > + uint32_t *usable_versions) > { > *usable_versions = 0; > if (!strcasecmp(table_id, "all")) { > tm->table_id = OFPTT_ALL; > - } else { > - char *error = str_to_u8(table_id, "table_id", &tm->table_id); > - if (error) { > - return error; > - } > + } else if (!ofputil_table_from_string(table_id, table_map, > + &tm->table_id)) { > + return xasprintf("unknown table \"%s\"", table_id); > } > > tm->miss = OFPUTIL_TABLE_MISS_DEFAULT; > @@ -1240,7 +1258,9 @@ parse_ofp_table_mod(struct ofputil_table_mod *tm, > const char *table_id, > * error. The caller is responsible for freeing the returned string. */ > char * OVS_WARN_UNUSED_RESULT > parse_ofp_flow_mod_file(const char *file_name, > - const struct ofputil_port_map *port_map, int > command, > + const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map, > + int command, > struct ofputil_flow_mod **fms, size_t *n_fms, > enum ofputil_protocol *usable_protocols) > { > @@ -1271,7 +1291,7 @@ parse_ofp_flow_mod_file(const char *file_name, > *fms = x2nrealloc(*fms, &allocated_fms, sizeof **fms); > } > error = parse_ofp_flow_mod_str(&(*fms)[*n_fms], ds_cstr(&s), > port_map, > - command, &usable); > + table_map, command, &usable); > if (error) { > char *err_msg; > size_t i; > @@ -1307,12 +1327,14 @@ char * OVS_WARN_UNUSED_RESULT > parse_ofp_flow_stats_request_str(struct ofputil_flow_stats_request *fsr, > bool aggregate, const char *string, > const struct ofputil_port_map *port_map, > + const struct ofputil_table_map > *table_map, > enum ofputil_protocol *usable_protocols) > { > struct ofputil_flow_mod fm; > char *error; > > - error = parse_ofp_str(&fm, -1, string, port_map, usable_protocols); > + error = parse_ofp_str(&fm, -1, string, port_map, table_map, > + usable_protocols); > if (error) { > return error; > } > @@ -1438,8 +1460,9 @@ exit: > > static char * OVS_WARN_UNUSED_RESULT > parse_bucket_str(struct ofputil_bucket *bucket, char *str_, > - const struct ofputil_port_map *port_map, uint8_t > group_type, > - enum ofputil_protocol *usable_protocols) > + const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map, > + uint8_t group_type, enum ofputil_protocol > *usable_protocols) > { > char *pos, *key, *value; > struct ofpbuf ofpacts; > @@ -1497,6 +1520,7 @@ parse_bucket_str(struct ofputil_bucket *bucket, char > *str_, > ofpbuf_init(&ofpacts, 0); > struct ofpact_parse_params pp = { > .port_map = port_map, > + .table_map = table_map, > .ofpacts = &ofpacts, > .usable_protocols = usable_protocols, > }; > @@ -1575,6 +1599,7 @@ static char * OVS_WARN_UNUSED_RESULT > parse_ofp_group_mod_str__(struct ofputil_group_mod *gm, int command, > char *string, > const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map, > enum ofputil_protocol *usable_protocols) > { > enum { > @@ -1828,7 +1853,7 @@ parse_ofp_group_mod_str__(struct ofputil_group_mod > *gm, int command, > } > > bucket = xzalloc(sizeof(struct ofputil_bucket)); > - error = parse_bucket_str(bucket, bkt_str, port_map, > + error = parse_bucket_str(bucket, bkt_str, port_map, table_map, > gm->type, usable_protocols); > if (error) { > free(bucket); > @@ -1862,11 +1887,12 @@ char * OVS_WARN_UNUSED_RESULT > parse_ofp_group_mod_str(struct ofputil_group_mod *gm, int command, > const char *str_, > const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map, > enum ofputil_protocol *usable_protocols) > { > char *string = xstrdup(str_); > - char *error = parse_ofp_group_mod_str__(gm, command, string, > - port_map, usable_protocols); > + char *error = parse_ofp_group_mod_str__(gm, command, string, port_map, > + table_map, usable_protocols); > free(string); > return error; > } > @@ -1878,6 +1904,7 @@ parse_ofp_group_mod_str(struct ofputil_group_mod > *gm, int command, > char * OVS_WARN_UNUSED_RESULT > parse_ofp_group_mod_file(const char *file_name, > const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map, > int command, > struct ofputil_group_mod **gms, size_t *n_gms, > enum ofputil_protocol *usable_protocols) > @@ -1915,7 +1942,7 @@ parse_ofp_group_mod_file(const char *file_name, > *gms = new_gms; > } > error = parse_ofp_group_mod_str(&(*gms)[*n_gms], command, > ds_cstr(&s), > - port_map, &usable); > + port_map, table_map, &usable); > if (error) { > size_t i; > > @@ -1956,6 +1983,7 @@ parse_ofp_group_mod_file(const char *file_name, > char * OVS_WARN_UNUSED_RESULT > parse_ofp_bundle_file(const char *file_name, > const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map, > struct ofputil_bundle_msg **bms, size_t *n_bms, > enum ofputil_protocol *usable_protocols) > { > @@ -2003,7 +2031,7 @@ parse_ofp_bundle_file(const char *file_name, > if (!strncmp(s, "flow", len)) { > s += len; > error = parse_ofp_flow_mod_str(&(*bms)[*n_bms].fm, s, > port_map, > - -2, &usable); > + table_map, -2, &usable); > if (error) { > break; > } > @@ -2011,7 +2039,7 @@ parse_ofp_bundle_file(const char *file_name, > } else if (!strncmp(s, "group", len)) { > s += len; > error = parse_ofp_group_mod_str(&(*bms)[*n_bms].gm, -2, s, > - port_map, &usable); > + port_map, table_map, &usable); > if (error) { > break; > } > @@ -2019,7 +2047,7 @@ parse_ofp_bundle_file(const char *file_name, > } else if (!strncmp(s, "packet-out", len)) { > s += len; > error = parse_ofp_packet_out_str(&(*bms)[*n_bms].po, s, > port_map, > - &usable); > + table_map, &usable); > if (error) { > break; > } > diff --git a/lib/ofp-print.c b/lib/ofp-print.c > index 639d3bddf36d..dede3197cb98 100644 > --- a/lib/ofp-print.c > +++ b/lib/ofp-print.c > @@ -119,7 +119,8 @@ format_hex_arg(struct ds *s, const uint8_t *data, > size_t len) > > static enum ofperr > ofp_print_packet_in(struct ds *string, const struct ofp_header *oh, > - const struct ofputil_port_map *port_map, int > verbosity) > + const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map, int > verbosity) > { > char reasonbuf[OFPUTIL_PACKET_IN_REASON_BUFSIZE]; > struct ofputil_packet_in_private pin; > @@ -134,8 +135,10 @@ ofp_print_packet_in(struct ds *string, const struct > ofp_header *oh, > return error; > } > > - if (public->table_id) { > - ds_put_format(string, " table_id=%"PRIu8, public->table_id); > + if (public->table_id > + || ofputil_table_map_get_name(table_map, public->table_id)) { > + ds_put_format(string, " table_id="); > + ofputil_format_table(public->table_id, table_map, string); > } > > if (public->cookie != OVS_BE64_MAX) { > @@ -207,6 +210,7 @@ ofp_print_packet_in(struct ds *string, const struct > ofp_header *oh, > > struct ofpact_format_params fp = { > .port_map = port_map, > + .table_map = table_map, > .s = string, > }; > > @@ -240,7 +244,8 @@ ofp_print_packet_in(struct ds *string, const struct > ofp_header *oh, > > static enum ofperr > ofp_print_packet_out(struct ds *string, const struct ofp_header *oh, > - const struct ofputil_port_map *port_map, int > verbosity) > + const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map, int > verbosity) > { > struct ofputil_packet_out po; > struct ofpbuf ofpacts; > @@ -259,6 +264,7 @@ ofp_print_packet_out(struct ds *string, const struct > ofp_header *oh, > ds_put_cstr(string, " actions="); > struct ofpact_format_params fp = { > .port_map = port_map, > + .table_map = table_map, > .s = string, > }; > ofpacts_format(po.ofpacts, po.ofpacts_len, &fp); > @@ -815,7 +821,8 @@ ofp_print_flow_flags(struct ds *s, enum > ofputil_flow_mod_flags flags) > > static enum ofperr > ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh, > - const struct ofputil_port_map *port_map, int verbosity) > + const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map, int > verbosity) > { > struct ofputil_flow_mod fm; > struct ofpbuf ofpacts; > @@ -855,8 +862,10 @@ ofp_print_flow_mod(struct ds *s, const struct > ofp_header *oh, > default: > ds_put_format(s, "cmd:%d", fm.command); > } > - if (fm.table_id != 0) { > - ds_put_format(s, " table:%d", fm.table_id); > + if (fm.table_id != 0 > + || ofputil_table_map_get_name(table_map, fm.table_id)) { > + ds_put_format(s, " table:"); > + ofputil_format_table(fm.table_id, table_map, s); > } > > ds_put_char(s, ' '); > @@ -927,6 +936,7 @@ ofp_print_flow_mod(struct ds *s, const struct > ofp_header *oh, > ds_put_cstr(s, "actions="); > struct ofpact_format_params fp = { > .port_map = port_map, > + .table_map = table_map, > .s = s, > }; > ofpacts_format(fm.ofpacts, fm.ofpacts_len, &fp); > @@ -994,7 +1004,8 @@ ofp_flow_removed_reason_to_string(enum > ofp_flow_removed_reason reason, > > static enum ofperr > ofp_print_flow_removed(struct ds *string, const struct ofp_header *oh, > - const struct ofputil_port_map *port_map) > + const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map) > { > char reasonbuf[OFP_FLOW_REMOVED_REASON_BUFSIZE]; > struct ofputil_flow_removed fr; > @@ -1013,7 +1024,8 @@ ofp_print_flow_removed(struct ds *string, const > struct ofp_header *oh, > sizeof reasonbuf)); > > if (fr.table_id != 255) { > - ds_put_format(string, " table_id=%"PRIu8, fr.table_id); > + ds_put_format(string, " table_id="); > + ofputil_format_table(fr.table_id, table_map, string); > } > > if (fr.cookie != htonll(0)) { > @@ -1133,7 +1145,8 @@ ofputil_table_vacancy_to_string(enum > ofputil_table_vacancy vacancy) > } > > static enum ofperr > -ofp_print_table_mod(struct ds *string, const struct ofp_header *oh) > +ofp_print_table_mod(struct ds *string, const struct ofp_header *oh, > + const struct ofputil_table_map *table_map) > { > struct ofputil_table_mod pm; > enum ofperr error; > @@ -1146,7 +1159,8 @@ ofp_print_table_mod(struct ds *string, const struct > ofp_header *oh) > if (pm.table_id == 0xff) { > ds_put_cstr(string, " table_id: ALL_TABLES"); > } else { > - ds_put_format(string, " table_id=%"PRIu8, pm.table_id); > + ds_put_format(string, " table_id="); > + ofputil_format_table(pm.table_id, table_map, string); > } > > if (pm.miss != OFPUTIL_TABLE_MISS_DEFAULT) { > @@ -1176,9 +1190,11 @@ ofp_print_table_mod(struct ds *string, const struct > ofp_header *oh) > > /* This function will print the Table description properties. */ > static void > -ofp_print_table_desc(struct ds *string, const struct ofputil_table_desc > *td) > +ofp_print_table_desc(struct ds *string, const struct ofputil_table_desc > *td, > + const struct ofputil_table_map *table_map) > { > - ds_put_format(string, "\n table %"PRIu8, td->table_id); > + ds_put_format(string, "\n table "); > + ofputil_format_table(td->table_id, table_map, string); > ds_put_cstr(string, ":\n"); > ds_put_format(string, " eviction=%s eviction_flags=", > ofputil_table_eviction_to_string(td->eviction)); > @@ -1198,7 +1214,8 @@ ofp_print_table_desc(struct ds *string, const struct > ofputil_table_desc *td) > } > > static enum ofperr > -ofp_print_table_status_message(struct ds *string, const struct > ofp_header *oh) > +ofp_print_table_status_message(struct ds *string, const struct > ofp_header *oh, > + const struct ofputil_table_map *table_map) > { > struct ofputil_table_status ts; > enum ofperr error; > @@ -1215,7 +1232,7 @@ ofp_print_table_status_message(struct ds *string, > const struct ofp_header *oh) > } > > ds_put_format(string, "\ntable_desc:-"); > - ofp_print_table_desc(string, &ts.desc); > + ofp_print_table_desc(string, &ts.desc, table_map); > > return 0; > } > @@ -1606,7 +1623,8 @@ ofp_print_hello(struct ds *string, const struct > ofp_header *oh) > > static enum ofperr > ofp_print_error_msg(struct ds *string, const struct ofp_header *oh, > - const struct ofputil_port_map *port_map) > + const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map) > { > struct ofpbuf payload; > enum ofperr error; > @@ -1622,7 +1640,7 @@ ofp_print_error_msg(struct ds *string, const struct > ofp_header *oh, > if (error == OFPERR_OFPHFC_INCOMPATIBLE || error == > OFPERR_OFPHFC_EPERM) { > ds_put_printable(string, payload.data, payload.size); > } else { > - s = ofp_to_string(payload.data, payload.size, port_map, 1); > + s = ofp_to_string(payload.data, payload.size, port_map, > table_map, 1); > ds_put_cstr(string, s); > free(s); > } > @@ -1676,7 +1694,8 @@ ofp_print_ofpst_desc_reply(struct ds *string, const > struct ofp_header *oh) > > static enum ofperr > ofp_print_flow_stats_request(struct ds *string, const struct ofp_header > *oh, > - const struct ofputil_port_map *port_map) > + const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map) > { > struct ofputil_flow_stats_request fsr; > enum ofperr error; > @@ -1687,7 +1706,8 @@ ofp_print_flow_stats_request(struct ds *string, > const struct ofp_header *oh, > } > > if (fsr.table_id != 0xff) { > - ds_put_format(string, " table=%"PRIu8, fsr.table_id); > + ds_put_format(string, " table="); > + ofputil_format_table(fsr.table_id, table_map, string); > } > > if (fsr.out_port != OFPP_ANY) { > @@ -1707,7 +1727,9 @@ ofp_print_flow_stats_request(struct ds *string, > const struct ofp_header *oh, > * ages, otherwise they are omitted. */ > void > ofp_print_flow_stats(struct ds *string, const struct ofputil_flow_stats > *fs, > - const struct ofputil_port_map *port_map, bool > show_stats) > + const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map, > + bool show_stats) > { > if (show_stats || fs->cookie) { > ds_put_format(string, "%scookie=%s0x%"PRIx64", ", > @@ -1719,9 +1741,11 @@ ofp_print_flow_stats(struct ds *string, const > struct ofputil_flow_stats *fs, > ds_put_cstr(string, ", "); > } > > - if (show_stats || fs->table_id) { > - ds_put_format(string, "%stable=%s%"PRIu8", ", > - colors.special, colors.end, fs->table_id); > + if (show_stats || fs->table_id > + || ofputil_table_map_get_name(table_map, fs->table_id) != NULL) { > + ds_put_format(string, "%stable=%s", colors.special, colors.end); > + ofputil_format_table(fs->table_id, table_map, string); > + ds_put_cstr(string, ", "); > } > if (show_stats) { > ds_put_format(string, "%sn_packets=%s%"PRIu64", ", > @@ -1764,6 +1788,7 @@ ofp_print_flow_stats(struct ds *string, const struct > ofputil_flow_stats *fs, > ds_put_format(string, "%sactions=%s", colors.actions, colors.end); > struct ofpact_format_params fp = { > .port_map = port_map, > + .table_map = table_map, > .s = string, > }; > ofpacts_format(fs->ofpacts, fs->ofpacts_len, &fp); > @@ -1771,7 +1796,8 @@ ofp_print_flow_stats(struct ds *string, const struct > ofputil_flow_stats *fs, > > static enum ofperr > ofp_print_flow_stats_reply(struct ds *string, const struct ofp_header > *oh, > - const struct ofputil_port_map *port_map) > + const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map) > { > struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); > struct ofpbuf ofpacts; > @@ -1786,7 +1812,7 @@ ofp_print_flow_stats_reply(struct ds *string, const > struct ofp_header *oh, > break; > } > ds_put_cstr(string, "\n "); > - ofp_print_flow_stats(string, &fs, port_map, true); > + ofp_print_flow_stats(string, &fs, port_map, table_map, true); > } > ofpbuf_uninit(&ofpacts); > > @@ -1991,7 +2017,8 @@ ofp_print_ofpst_port_reply(struct ds *string, const > struct ofp_header *oh, > } > > static enum ofperr > -ofp_print_table_stats_reply(struct ds *string, const struct ofp_header > *oh) > +ofp_print_table_stats_reply(struct ds *string, const struct ofp_header > *oh, > + const struct ofputil_table_map *table_map) > { > struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); > ofpraw_pull_assert(&b); > @@ -2011,7 +2038,8 @@ ofp_print_table_stats_reply(struct ds *string, > const struct ofp_header *oh) > ds_put_char(string, '\n'); > ofp_print_table_features(string, > &features, i ? &prev_features : NULL, > - &stats, i ? &prev_stats : NULL); > + &stats, i ? &prev_stats : NULL, > + table_map); > prev_features = features; > prev_stats = stats; > } > @@ -2469,7 +2497,8 @@ nx_flow_monitor_flags_to_name(uint32_t bit) > static enum ofperr > ofp_print_nxst_flow_monitor_request(struct ds *string, > const struct ofp_header *oh, > - const struct ofputil_port_map > *port_map) > + const struct ofputil_port_map > *port_map, > + const struct ofputil_table_map > *table_map) > { > struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); > for (;;) { > @@ -2491,7 +2520,8 @@ ofp_print_nxst_flow_monitor_request(struct ds > *string, > } > > if (request.table_id != 0xff) { > - ds_put_format(string, " table=%"PRIu8, request.table_id); > + ds_put_format(string, " table="); > + ofputil_format_table(request.table_id, table_map, string); > } > > ds_put_char(string, ' '); > @@ -2503,7 +2533,8 @@ ofp_print_nxst_flow_monitor_request(struct ds > *string, > static enum ofperr > ofp_print_nxst_flow_monitor_reply(struct ds *string, > const struct ofp_header *oh, > - const struct ofputil_port_map *port_map) > + const struct ofputil_port_map *port_map, > + const struct ofputil_table_map > *table_map) > { > uint64_t ofpacts_stub[1024 / 8]; > struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub); > @@ -2542,7 +2573,8 @@ ofp_print_nxst_flow_monitor_reply(struct ds *string, > continue; > } > > - ds_put_format(string, " table=%"PRIu8, update.table_id); > + ds_put_format(string, " table="); > + ofputil_format_table(update.table_id, table_map, string); > if (update.idle_timeout != OFP_FLOW_PERMANENT) { > ds_put_format(string, " idle_timeout=%"PRIu16, > update.idle_timeout); > @@ -2563,6 +2595,7 @@ ofp_print_nxst_flow_monitor_reply(struct ds *string, > ds_put_cstr(string, "actions="); > struct ofpact_format_params fp = { > .port_map = port_map, > + .table_map = table_map, > .s = string, > }; > ofpacts_format(update.ofpacts, update.ofpacts_len, &fp); > @@ -2643,7 +2676,8 @@ ofp_print_group(struct ds *s, uint32_t group_id, > uint8_t type, > const struct ovs_list *p_buckets, > const struct ofputil_group_props *props, > enum ofp_version ofp_version, bool suppress_type, > - const struct ofputil_port_map *port_map) > + const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map) > { > struct ofputil_bucket *bucket; > > @@ -2698,6 +2732,7 @@ ofp_print_group(struct ds *s, uint32_t group_id, > uint8_t type, > ds_put_cstr(s, "actions="); > struct ofpact_format_params fp = { > .port_map = port_map, > + .table_map = table_map, > .s = s, > }; > ofpacts_format(bucket->ofpacts, bucket->ofpacts_len, &fp); > @@ -2720,7 +2755,8 @@ ofp_print_ofpst_group_desc_request(struct ds > *string, > > static enum ofperr > ofp_print_group_desc(struct ds *s, const struct ofp_header *oh, > - const struct ofputil_port_map *port_map) > + const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map) > { > struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); > for (;;) { > @@ -2735,7 +2771,7 @@ ofp_print_group_desc(struct ds *s, const struct > ofp_header *oh, > ds_put_char(s, '\n'); > ds_put_char(s, ' '); > ofp_print_group(s, gd.group_id, gd.type, &gd.buckets, &gd.props, > - oh->version, false, port_map); > + oh->version, false, port_map, table_map); > ofputil_uninit_group_desc(&gd); > } > } > @@ -2842,7 +2878,8 @@ ofp_print_group_features(struct ds *string, const > struct ofp_header *oh) > static void > ofp_print_group_mod__(struct ds *s, enum ofp_version ofp_version, > const struct ofputil_group_mod *gm, > - const struct ofputil_port_map *port_map) > + const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map) > { > bool bucket_command = false; > > @@ -2887,12 +2924,13 @@ ofp_print_group_mod__(struct ds *s, enum > ofp_version ofp_version, > } > > ofp_print_group(s, gm->group_id, gm->type, &gm->buckets, &gm->props, > - ofp_version, bucket_command, port_map); > + ofp_version, bucket_command, port_map, table_map); > } > > static enum ofperr > ofp_print_group_mod(struct ds *s, const struct ofp_header *oh, > - const struct ofputil_port_map *port_map) > + const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map) > { > struct ofputil_group_mod gm; > int error; > @@ -2901,7 +2939,7 @@ ofp_print_group_mod(struct ds *s, const struct > ofp_header *oh, > if (error) { > return error; > } > - ofp_print_group_mod__(s, oh->version, &gm, port_map); > + ofp_print_group_mod__(s, oh->version, &gm, port_map, table_map); > ofputil_uninit_group_mod(&gm); > return 0; > } > @@ -3071,11 +3109,13 @@ ofp_print_table_features(struct ds *s, > const struct ofputil_table_features *features, > const struct ofputil_table_features > *prev_features, > const struct ofputil_table_stats *stats, > - const struct ofputil_table_stats *prev_stats) > + const struct ofputil_table_stats *prev_stats, > + const struct ofputil_table_map *table_map) > { > int i; > > - ds_put_format(s, " table %"PRIu8, features->table_id); > + ds_put_format(s, " table "); > + ofputil_format_table(features->table_id, table_map, s); > if (features->name[0]) { > ds_put_format(s, " (\"%s\")", features->name); > } > @@ -3170,7 +3210,8 @@ ofp_print_table_features(struct ds *s, > } > > static enum ofperr > -ofp_print_table_features_reply(struct ds *s, const struct ofp_header *oh) > +ofp_print_table_features_reply(struct ds *s, const struct ofp_header *oh, > + const struct ofputil_table_map *table_map) > { > struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); > > @@ -3185,13 +3226,15 @@ ofp_print_table_features_reply(struct ds *s, > const struct ofp_header *oh) > } > > ds_put_char(s, '\n'); > - ofp_print_table_features(s, &tf, i ? &prev : NULL, NULL, NULL); > + ofp_print_table_features(s, &tf, i ? &prev : NULL, NULL, NULL, > + table_map); > prev = tf; > } > } > > static enum ofperr > -ofp_print_table_desc_reply(struct ds *s, const struct ofp_header *oh) > +ofp_print_table_desc_reply(struct ds *s, const struct ofp_header *oh, > + const struct ofputil_table_map *table_map) > { > struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); > for (;;) { > @@ -3202,7 +3245,7 @@ ofp_print_table_desc_reply(struct ds *s, const > struct ofp_header *oh) > if (retval) { > return retval != EOF ? retval : 0; > } > - ofp_print_table_desc(s, &td); > + ofp_print_table_desc(s, &td, table_map); > } > } > > @@ -3268,7 +3311,9 @@ ofp_print_bundle_ctrl(struct ds *s, const struct > ofp_header *oh) > > static enum ofperr > ofp_print_bundle_add(struct ds *s, const struct ofp_header *oh, > - const struct ofputil_port_map *port_map, int > verbosity) > + const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map, > + int verbosity) > { > int error; > struct ofputil_bundle_add_msg badd; > @@ -3285,7 +3330,7 @@ ofp_print_bundle_add(struct ds *s, const struct > ofp_header *oh, > > ds_put_char(s, '\n'); > char *msg = ofp_to_string(badd.msg, ntohs(badd.msg->length), port_map, > - verbosity); > + table_map, verbosity); > ds_put_and_free_cstr(s, msg); > > return 0; > @@ -3376,7 +3421,8 @@ ofp_print_tlv_table_reply(struct ds *s, const > struct ofp_header *oh) > * request forward is taken from rf.request.type */ > static enum ofperr > ofp_print_requestforward(struct ds *string, const struct ofp_header *oh, > - const struct ofputil_port_map *port_map) > + const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map) > { > struct ofputil_requestforward rf; > enum ofperr error; > @@ -3391,7 +3437,8 @@ ofp_print_requestforward(struct ds *string, const > struct ofp_header *oh, > switch (rf.reason) { > case OFPRFR_GROUP_MOD: > ds_put_cstr(string, "group_mod"); > - ofp_print_group_mod__(string, oh->version, rf.group_mod, > port_map); > + ofp_print_group_mod__(string, oh->version, rf.group_mod, port_map, > + table_map); > break; > > case OFPRFR_METER_MOD: > @@ -3491,7 +3538,8 @@ ofp_print_nxt_ct_flush_zone(struct ds *string, > const struct nx_zone_id *nzi) > > static enum ofperr > ofp_to_string__(const struct ofp_header *oh, > - const struct ofputil_port_map *port_map, enum ofpraw raw, > + const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map, enum ofpraw > raw, > struct ds *string, int verbosity) > { > const void *msg = oh; > @@ -3509,7 +3557,7 @@ ofp_to_string__(const struct ofp_header *oh, > return ofp_print_ofpst_group_desc_request(string, oh); > > case OFPTYPE_GROUP_DESC_STATS_REPLY: > - return ofp_print_group_desc(string, oh, port_map); > + return ofp_print_group_desc(string, oh, port_map, table_map); > > case OFPTYPE_GROUP_FEATURES_STATS_REQUEST: > ofp_print_stats(string, oh); > @@ -3519,21 +3567,21 @@ ofp_to_string__(const struct ofp_header *oh, > return ofp_print_group_features(string, oh); > > case OFPTYPE_GROUP_MOD: > - return ofp_print_group_mod(string, oh, port_map); > + return ofp_print_group_mod(string, oh, port_map, table_map); > > case OFPTYPE_TABLE_FEATURES_STATS_REQUEST: > case OFPTYPE_TABLE_FEATURES_STATS_REPLY: > - return ofp_print_table_features_reply(string, oh); > + return ofp_print_table_features_reply(string, oh, table_map); > > case OFPTYPE_TABLE_DESC_REQUEST: > case OFPTYPE_TABLE_DESC_REPLY: > - return ofp_print_table_desc_reply(string, oh); > + return ofp_print_table_desc_reply(string, oh, table_map); > > case OFPTYPE_HELLO: > return ofp_print_hello(string, oh); > > case OFPTYPE_ERROR: > - return ofp_print_error_msg(string, oh, port_map); > + return ofp_print_error_msg(string, oh, port_map, table_map); > > case OFPTYPE_ECHO_REQUEST: > case OFPTYPE_ECHO_REPLY: > @@ -3555,25 +3603,26 @@ ofp_to_string__(const struct ofp_header *oh, > return ofp_print_set_config(string, oh); > > case OFPTYPE_PACKET_IN: > - return ofp_print_packet_in(string, oh, port_map, verbosity); > + return ofp_print_packet_in(string, oh, port_map, table_map, > verbosity); > > case OFPTYPE_FLOW_REMOVED: > - return ofp_print_flow_removed(string, oh, port_map); > + return ofp_print_flow_removed(string, oh, port_map, table_map); > > case OFPTYPE_PORT_STATUS: > return ofp_print_port_status(string, oh); > > case OFPTYPE_PACKET_OUT: > - return ofp_print_packet_out(string, oh, port_map, verbosity); > + return ofp_print_packet_out(string, oh, port_map, table_map, > + verbosity); > > case OFPTYPE_FLOW_MOD: > - return ofp_print_flow_mod(string, oh, port_map, verbosity); > + return ofp_print_flow_mod(string, oh, port_map, table_map, > verbosity); > > case OFPTYPE_PORT_MOD: > return ofp_print_port_mod(string, oh, port_map); > > case OFPTYPE_TABLE_MOD: > - return ofp_print_table_mod(string, oh); > + return ofp_print_table_mod(string, oh, table_map); > > case OFPTYPE_METER_MOD: > return ofp_print_meter_mod(string, oh); > @@ -3595,10 +3644,10 @@ ofp_to_string__(const struct ofp_header *oh, > return ofp_print_role_status_message(string, oh); > > case OFPTYPE_REQUESTFORWARD: > - return ofp_print_requestforward(string, oh, port_map); > + return ofp_print_requestforward(string, oh, port_map, table_map); > > case OFPTYPE_TABLE_STATUS: > - return ofp_print_table_status_message(string, oh); > + return ofp_print_table_status_message(string, oh, table_map); > > case OFPTYPE_METER_STATS_REQUEST: > case OFPTYPE_METER_CONFIG_STATS_REQUEST: > @@ -3625,7 +3674,7 @@ ofp_to_string__(const struct ofp_header *oh, > case OFPTYPE_FLOW_STATS_REQUEST: > case OFPTYPE_AGGREGATE_STATS_REQUEST: > ofp_print_stats(string, oh); > - return ofp_print_flow_stats_request(string, oh, port_map); > + return ofp_print_flow_stats_request(string, oh, port_map, > table_map); > > case OFPTYPE_TABLE_STATS_REQUEST: > ofp_print_stats(string, oh); > @@ -3645,7 +3694,7 @@ ofp_to_string__(const struct ofp_header *oh, > > case OFPTYPE_FLOW_STATS_REPLY: > ofp_print_stats(string, oh); > - return ofp_print_flow_stats_reply(string, oh, port_map); > + return ofp_print_flow_stats_reply(string, oh, port_map, > table_map); > > case OFPTYPE_QUEUE_STATS_REPLY: > ofp_print_stats(string, oh); > @@ -3657,7 +3706,7 @@ ofp_to_string__(const struct ofp_header *oh, > > case OFPTYPE_TABLE_STATS_REPLY: > ofp_print_stats(string, oh); > - return ofp_print_table_stats_reply(string, oh); > + return ofp_print_table_stats_reply(string, oh, table_map); > > case OFPTYPE_AGGREGATE_STATS_REPLY: > ofp_print_stats(string, oh); > @@ -3699,16 +3748,19 @@ ofp_to_string__(const struct ofp_header *oh, > break; > > case OFPTYPE_FLOW_MONITOR_STATS_REQUEST: > - return ofp_print_nxst_flow_monitor_request(string, msg, > port_map); > + return ofp_print_nxst_flow_monitor_request(string, msg, port_map, > + table_map); > > case OFPTYPE_FLOW_MONITOR_STATS_REPLY: > - return ofp_print_nxst_flow_monitor_reply(string, msg, port_map); > + return ofp_print_nxst_flow_monitor_reply(string, msg, port_map, > + table_map); > > case OFPTYPE_BUNDLE_CONTROL: > return ofp_print_bundle_ctrl(string, msg); > > case OFPTYPE_BUNDLE_ADD_MESSAGE: > - return ofp_print_bundle_add(string, msg, port_map, verbosity); > + return ofp_print_bundle_add(string, msg, port_map, table_map, > + verbosity); > > case OFPTYPE_NXT_TLV_TABLE_MOD: > return ofp_print_tlv_table_mod(string, msg); > @@ -3720,7 +3772,8 @@ ofp_to_string__(const struct ofp_header *oh, > return ofp_print_tlv_table_reply(string, msg); > > case OFPTYPE_NXT_RESUME: > - return ofp_print_packet_in(string, msg, port_map, verbosity); > + return ofp_print_packet_in(string, msg, port_map, table_map, > + verbosity); > case OFPTYPE_IPFIX_BRIDGE_STATS_REQUEST: > break; > case OFPTYPE_IPFIX_BRIDGE_STATS_REPLY: > @@ -3751,7 +3804,9 @@ add_newline(struct ds *s) > * for freeing the string. */ > char * > ofp_to_string(const void *oh_, size_t len, > - const struct ofputil_port_map *port_map, int verbosity) > + const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map, > + int verbosity) > { > struct ds string = DS_EMPTY_INITIALIZER; > const struct ofp_header *oh = oh_; > @@ -3787,7 +3842,8 @@ ofp_to_string(const void *oh_, size_t len, > ofp_header_to_string__(oh, raw, &string); > size_t header_len = string.length; > > - error = ofp_to_string__(oh, port_map, raw, &string, > verbosity); > + error = ofp_to_string__(oh, port_map, table_map, > + raw, &string, verbosity); > if (error) { > if (string.length > header_len) { > ds_chomp(&string, ' '); > @@ -3827,9 +3883,11 @@ print_and_free(FILE *stream, char *string) > * numbers increase verbosity. */ > void > ofp_print(FILE *stream, const void *oh, size_t len, > - const struct ofputil_port_map *port_map, int verbosity) > + const struct ofputil_port_map *port_map, > + const struct ofputil_table_map *table_map, int verbosity) > { > - print_and_free(stream, ofp_to_string(oh, len, port_map, verbosity)); > + print_and_free(stream, ofp_to_string(oh, len, port_map, table_map, > + verbosity)); > } > > /* Dumps the contents of the Ethernet frame in the 'len' bytes starting at > diff --git a/lib/ofp-util.c b/lib/ofp-util.c > index f3b2e3f6108c..09ad93132918 100644 > --- a/lib/ofp-util.c > +++ b/lib/ofp-util.c > @@ -7378,16 +7378,16 @@ ofputil_port_get_reserved_name(ofp_port_t port) > } > } > > -/* A port name doesn't need to be quoted if it is alphanumeric and starts > with > - * a letter. */ > +/* A table or port name doesn't need to be quoted if it is alphanumeric > and > + * starts with a letter. */ > static bool > -port_name_needs_quotes(const char *port_name) > +name_needs_quotes(const char *name) > { > - if (!isalpha((unsigned char) port_name[0])) { > + if (!isalpha((unsigned char) name[0])) { > return true; > } > > - for (const char *p = port_name + 1; *p; p++) { > + for (const char *p = name + 1; *p; p++) { > if (!isalnum((unsigned char) *p)) { > return true; > } > @@ -7395,13 +7395,14 @@ port_name_needs_quotes(const char *port_name) > return false; > } > > +/* Appends port or table 'name' to 's', quoting it if necessary. */ > static void > -put_port_name(const char *port_name, struct ds *s) > +put_name(const char *name, struct ds *s) > { > - if (port_name_needs_quotes(port_name)) { > - json_string_escape(port_name, s); > + if (name_needs_quotes(name)) { > + json_string_escape(name, s); > } else { > - ds_put_cstr(s, port_name); > + ds_put_cstr(s, name); > } > } > > @@ -7420,7 +7421,7 @@ ofputil_format_port(ofp_port_t port, const struct > ofputil_port_map *port_map, > > const char *port_name = ofputil_port_map_get_name(port_map, port); > if (port_name) { > - put_port_name(port_name, s); > + put_name(port_name, s); > return; > } > > @@ -7445,7 +7446,7 @@ ofputil_port_to_string(ofp_port_t port, > const char *port_name = ofputil_port_map_get_name(port_map, port); > if (port_name) { > struct ds s = DS_EMPTY_INITIALIZER; > - put_port_name(port_name, &s); > + put_name(port_name, &s); > ovs_strlcpy(namebuf, ds_cstr(&s), bufsize); > ds_destroy(&s); > return; > @@ -7644,6 +7645,92 @@ ofputil_table_map_destroy(struct ofputil_table_map > *map) > ofputil_name_map_destroy(&map->map); > } > > +/* Table numbers. */ > + > +/* Stores the table number represented by 's' into '*tablep'. 's' may be > an > + * integer or, if 'table_map' is nonnull, a name (quoted or unquoted). > + * > + * Returns true if successful, false if 's' is not a valid OpenFlow table > + * number or name. The caller should issue an error message in this case, > + * because this function usually does not. (This gives the caller an > + * opportunity to look up the table name another way, e.g. by contacting > the > + * switch and listing the names of all its tables). */ > +bool > +ofputil_table_from_string(const char *s, > + const struct ofputil_table_map *table_map, > + uint8_t *tablep) > +{ > + *tablep = 0; > + if (*s == '-') { > + VLOG_WARN("Negative value %s is not a valid table number.", s); > + return false; > + } > + > + unsigned int table; > + if (str_to_uint(s, 10, &table)) { > + if (table > 255) { > + VLOG_WARN("table %u is outside the supported range 0 through > 255", > + table); > + return false; > + } > + *tablep = table; > + return true; > + } else { > + if (s[0] != '"') { > + table = ofputil_table_map_get_number(table_map, s); > + } else { > + size_t length = strlen(s); > + char *name = NULL; > + if (length > 1 > + && s[length - 1] == '"' > + && json_string_unescape(s + 1, length - 2, &name)) { > + table = ofputil_table_map_get_number(table_map, name); > + } > + free(name); > + } > + if (table != UINT8_MAX) { > + *tablep = table; > + return true; > + } > + > + return false; > + } > +} > + > +/* Appends to 's' a string representation of the OpenFlow table number > 'table', > + * either the table number or a name drawn from 'table_map'. */ > +void > +ofputil_format_table(uint8_t table, const struct ofputil_table_map > *table_map, > + struct ds *s) > +{ > + const char *table_name = ofputil_table_map_get_name(table_map, > table); > + if (table_name) { > + put_name(table_name, s); > + } else { > + ds_put_format(s, "%"PRIu8, table); > + } > +} > + > +/* Puts in the 'bufsize' byte in 'namebuf' a null-terminated string > + * representation of OpenFlow table number 'table', either the table's > number > + * or a name drawn from 'table_map'. */ > +void > +ofputil_table_to_string(uint8_t table, > + const struct ofputil_table_map *table_map, > + char *namebuf, size_t bufsize) > +{ > + const char *table_name = ofputil_table_map_get_name(table_map, > table); > + if (table_name) { > + struct ds s = DS_EMPTY_INITIALIZER; > + put_name(table_name, &s); > + ovs_strlcpy(namebuf, ds_cstr(&s), bufsize); > + ds_destroy(&s); > + return; > + } > + > + snprintf(namebuf, bufsize, "%"PRIu8, table); > +} > + > /* Stores the group id represented by 's' into '*group_idp'. 's' may be > an > * integer or, for reserved group IDs, the standard OpenFlow name for the > group > * (either "ANY" or "ALL"). > diff --git a/lib/vconn.c b/lib/vconn.c > index bb56be2d2901..f0d00eec104f 100644 > --- a/lib/vconn.c > +++ b/lib/vconn.c > @@ -496,7 +496,7 @@ vcs_recv_hello(struct vconn *vconn) > ofpbuf_delete(b); > return; > } else { > - char *s = ofp_to_string(b->data, b->size, NULL, 1); > + char *s = ofp_to_string(b->data, b->size, NULL, NULL, 1); > VLOG_WARN_RL(&bad_ofmsg_rl, > "%s: received message while expecting hello: %s", > vconn->name, s); > @@ -642,7 +642,8 @@ do_recv(struct vconn *vconn, struct ofpbuf **msgp) > if (!retval) { > COVERAGE_INC(vconn_received); > if (VLOG_IS_DBG_ENABLED()) { > - char *s = ofp_to_string((*msgp)->data, (*msgp)->size, NULL, > 1); > + char *s = ofp_to_string((*msgp)->data, (*msgp)->size, > + NULL, NULL, 1); > VLOG_DBG_RL(&ofmsg_rl, "%s: received: %s", vconn->name, s); > free(s); > } > @@ -682,7 +683,7 @@ do_send(struct vconn *vconn, struct ofpbuf *msg) > COVERAGE_INC(vconn_sent); > retval = (vconn->vclass->send)(vconn, msg); > } else { > - char *s = ofp_to_string(msg->data, msg->size, NULL, 1); > + char *s = ofp_to_string(msg->data, msg->size, NULL, NULL, 1); > retval = (vconn->vclass->send)(vconn, msg); > if (retval != EAGAIN) { > VLOG_DBG_RL(&ofmsg_rl, "%s: sent (%s): %s", > @@ -958,7 +959,8 @@ recv_flow_stats_reply(struct vconn *vconn, ovs_be32 > send_xid, > error = ofptype_decode(&type, reply->data); > if (error || type != OFPTYPE_FLOW_STATS_REPLY) { > VLOG_WARN_RL(&rl, "received bad reply: %s", > - ofp_to_string(reply->data, reply->size, > NULL, 1)); > + ofp_to_string(reply->data, reply->size, > + NULL, NULL, 1)); > return EPROTO; > } > } > diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c > index 329a775828a1..16aeaec9047e 100644 > --- a/ofproto/ofproto-dpif.c > +++ b/ofproto/ofproto-dpif.c > @@ -1734,11 +1734,9 @@ flush(struct ofproto *ofproto_) > > static void > query_tables(struct ofproto *ofproto, > - struct ofputil_table_features *features, > + struct ofputil_table_features *features OVS_UNUSED, > struct ofputil_table_stats *stats) > { > - strcpy(features->name, "classifier"); > - > if (stats) { > int i; > > diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c > index 6e360a8fc1e0..02dd12b50f6a 100644 > --- a/ofproto/ofproto.c > +++ b/ofproto/ofproto.c > @@ -3221,7 +3221,7 @@ query_tables(struct ofproto *ofproto, > struct ofputil_table_features *f = &features[i]; > > f->table_id = i; > - sprintf(f->name, "table%d", i); > + f->name[0] = '\0'; > f->metadata_match = OVS_BE64_MAX; > f->metadata_write = OVS_BE64_MAX; > atomic_read_relaxed(&ofproto->tables[i].miss_config, > &f->miss_config); > diff --git a/ovn/controller/ofctrl.c b/ovn/controller/ofctrl.c > index b2a6d7f53ff7..f0a0f4aa9885 100644 > --- a/ovn/controller/ofctrl.c > +++ b/ovn/controller/ofctrl.c > @@ -294,7 +294,7 @@ recv_S_TLV_TABLE_REQUESTED(const struct ofp_header > *oh, enum ofptype type, > VLOG_ERR("switch refused to allocate Geneve option (%s)", > ofperr_to_string(ofperr_decode_msg(oh, NULL))); > } else { > - char *s = ofp_to_string(oh, ntohs(oh->length), NULL, 1); > + char *s = ofp_to_string(oh, ntohs(oh->length), NULL, NULL, 1); > VLOG_ERR("unexpected reply to TLV table request (%s)", s); > free(s); > } > @@ -348,7 +348,7 @@ recv_S_TLV_TABLE_MOD_SENT(const struct ofp_header > *oh, enum ofptype type, > goto error; > } > } else { > - char *s = ofp_to_string(oh, ntohs(oh->length), NULL, 1); > + char *s = ofp_to_string(oh, ntohs(oh->length), NULL, NULL, 1); > VLOG_ERR("unexpected reply to Geneve option allocation request > (%s)", > s); > free(s); > @@ -533,7 +533,7 @@ ofctrl_run(const struct ovsrec_bridge *br_int, struct > shash *pending_ct_zones) > OVS_NOT_REACHED(); > } > } else { > - char *s = ofp_to_string(oh, ntohs(oh->length), NULL, 1); > + char *s = ofp_to_string(oh, ntohs(oh->length), NULL, > NULL, 1); > VLOG_WARN("could not decode OpenFlow message (%s): %s", > ofperr_to_string(error), s); > free(s); > @@ -593,7 +593,7 @@ log_openflow_rl(struct vlog_rate_limit *rl, enum > vlog_level level, > const struct ofp_header *oh, const char *title) > { > if (!vlog_should_drop(&this_module, level, rl)) { > - char *s = ofp_to_string(oh, ntohs(oh->length), NULL, 2); > + char *s = ofp_to_string(oh, ntohs(oh->length), NULL, NULL, 2); > vlog(&this_module, level, "%s: %s", title, s); > free(s); > } > @@ -870,7 +870,7 @@ ofctrl_put(struct hmap *flow_table, struct shash > *pending_ct_zones, > desired->table_id, > ds_cstr(&desired->info)); > char *error = parse_ofp_group_mod_str(&gm, OFPGC11_ADD, > group_string, > - NULL, &usable_protocols); > + NULL, NULL, > &usable_protocols); > if (!error) { > add_group_mod(&gm, &msgs); > } else { > @@ -985,7 +985,7 @@ ofctrl_put(struct hmap *flow_table, struct shash > *pending_ct_zones, > char *group_string = xasprintf("group_id=%"PRIu32"", > installed->table_id); > char *error = parse_ofp_group_mod_str(&gm, OFPGC11_DELETE, > - group_string, NULL, > + group_string, NULL, NULL, > &usable_protocols); > if (!error) { > add_group_mod(&gm, &msgs); > diff --git a/ovn/controller/pinctrl.c b/ovn/controller/pinctrl.c > index d8bfde09c4cd..faeb3f932350 100644 > --- a/ovn/controller/pinctrl.c > +++ b/ovn/controller/pinctrl.c > @@ -1039,7 +1039,7 @@ pinctrl_recv(const struct ofp_header *oh, enum > ofptype type, > if (VLOG_IS_DBG_ENABLED()) { > static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, > 300); > > - char *s = ofp_to_string(oh, ntohs(oh->length), NULL, 2); > + char *s = ofp_to_string(oh, ntohs(oh->length), NULL, NULL, 2); > > VLOG_DBG_RL(&rl, "OpenFlow packet ignored: %s", s); > free(s); > diff --git a/ovn/utilities/ovn-sbctl.c b/ovn/utilities/ovn-sbctl.c > index 0cb8ea480438..dc56d864c986 100644 > --- a/ovn/utilities/ovn-sbctl.c > +++ b/ovn/utilities/ovn-sbctl.c > @@ -796,7 +796,7 @@ sbctl_dump_openflow(struct vconn *vconn, const struct > uuid *uuid, bool stats) > > ds_clear(&s); > if (stats) { > - ofp_print_flow_stats(&s, fs, NULL, true); > + ofp_print_flow_stats(&s, fs, NULL, NULL, true); > } else { > ds_put_format(&s, "%stable=%s%"PRIu8" ", > colors.special, colors.end, fs->table_id); > diff --git a/ovn/utilities/ovn-trace.c b/ovn/utilities/ovn-trace.c > index 06d4ddf8e2a0..7e88594faa18 100644 > --- a/ovn/utilities/ovn-trace.c > +++ b/ovn/utilities/ovn-trace.c > @@ -1936,7 +1936,7 @@ trace_openflow(const struct ovntrace_flow *f, struct > ovs_list *super) > struct ds s = DS_EMPTY_INITIALIZER; > for (size_t i = 0; i < n_fses; i++) { > ds_clear(&s); > - ofp_print_flow_stats(&s, &fses[i], NULL, true); > + ofp_print_flow_stats(&s, &fses[i], NULL, NULL, true); > ovntrace_node_append(super, OVNTRACE_NODE_ACTION, > "%s", ds_cstr(&s)); > } > diff --git a/tests/ofproto.at b/tests/ofproto.at > index b49f546afa67..1b0ba94fd837 100644 > --- a/tests/ofproto.at > +++ b/tests/ofproto.at > @@ -2174,7 +2174,7 @@ OVS_VSWITCHD_START > # Check the default configuration. > head_table() { > printf 'OFPST_TABLE reply (xid=0x2): > - table 0 ("%s"): > + table 0%s: > active=0, lookup=0, matched=0 > max_entries=1000000 > matching: > @@ -2191,14 +2191,14 @@ head_table() { > tcp_src: exact match or wildcard > tcp_dst: exact match or wildcard > > -' $1 > +' "$1" > } > ditto() { > for i in `seq $1 $2`; do > - printf ' table %d ("table%d"): ditto\n' $i $i > + printf ' table %d: ditto\n' $i > done > } > -(head_table classifier; ditto 1 253) > expout > +(head_table; ditto 1 253) > expout > AT_CHECK([ovs-ofctl dump-tables br0], [0], [expout]) > # Change the configuration. > AT_CHECK( > @@ -2211,12 +2211,12 @@ AT_CHECK( > <1> > ]) > # Check that the configuration was updated. > -(head_table main; echo ' table 1 ("table1"): > +(head_table ' ("main")'; echo ' table 1: > active=0, lookup=0, matched=0 > max_entries=1024 > (same matching) > > - table 2 ("table2"): > + table 2: > active=0, lookup=0, matched=0 > max_entries=1000000 > (same matching) > @@ -2250,7 +2250,7 @@ AT_CHECK([test `grep '240\.0\.0\.1' stdout | grep -v > table_id= | wc -l` -gt 0]) > # Check that dump-tables doesn't count the hidden flows. > head_table() { > printf 'OFPST_TABLE reply: > - table 0 ("%s"): > + table 0: > active=0, lookup=0, matched=0 > max_entries=1000000 > matching: > @@ -2267,14 +2267,14 @@ head_table() { > tcp_src: exact match or wildcard > tcp_dst: exact match or wildcard > > -' $1 > +' > } > ditto() { > for i in `seq $1 $2`; do > - printf ' table %d ("table%d"): ditto\n' $i $i > + printf ' table %d: ditto\n' $i > done > } > -(head_table classifier; ditto 1 253) > expout > +(head_table; ditto 1 253) > expout > AT_CHECK([ovs-ofctl dump-tables br0 | strip_xids], [0], [expout]) > OVS_VSWITCHD_STOP(["/240\.0\.0\.1/d"]) > AT_CLEANUP > @@ -2284,7 +2284,7 @@ OVS_VSWITCHD_START > # Check the default configuration. > head_table() { > printf 'OFPST_TABLE reply (OF1.2) (xid=0x2): > - table 0 ("%s"): > + table 0%s: > active=0, lookup=0, matched=0 > metadata: match=0xffffffffffffffff write=0xffffffffffffffff > config=controller > @@ -2331,15 +2331,15 @@ head_table() { > nd_sll: exact match or wildcard > nd_tll: exact match or wildcard > > -' $1 > +' "$1" > } > ditto() { > for i in `seq $1 $2`; do > - printf ' table %d ("table%d"): ditto\n' $i $i > + printf ' table %d: ditto\n' $i > done > } > tail_table() { > - printf ' table 253 ("table253"): > + printf ' table 253: > active=0, lookup=0, matched=0 > metadata: match=0xffffffffffffffff write=0xffffffffffffffff > config=controller > @@ -2350,7 +2350,7 @@ tail_table() { > (same matching) > ' > } > -(head_table classifier; ditto 1 252; tail_table) > expout > +(head_table; ditto 1 252; tail_table) > expout > AT_CHECK([ovs-ofctl -O OpenFlow12 dump-tables br0], [0], [expout]) > # Change the configuration. > AT_CHECK( > @@ -2363,7 +2363,7 @@ AT_CHECK( > <1> > ]) > # Check that the configuration was updated. > -(head_table main; echo ' table 1 ("table1"): > +(head_table ' ("main")'; echo ' table 1: > active=0, lookup=0, matched=0 > metadata: match=0xffffffffffffffff write=0xffffffffffffffff > config=controller > @@ -2371,7 +2371,7 @@ AT_CHECK( > (same instructions) > (same matching) > > - table 2 ("table2"): > + table 2: > active=0, lookup=0, matched=0 > metadata: match=0xffffffffffffffff write=0xffffffffffffffff > config=controller > @@ -2386,7 +2386,7 @@ AT_CLEANUP > AT_SETUP([ofproto - table features (OpenFlow 1.3)]) > OVS_VSWITCHD_START > head_table () { > - printf ' table 0 ("%s"): > + printf ' table 0%s: > metadata: match=0xffffffffffffffff write=0xffffffffffffffff > max_entries=1000000 > instructions (table miss and others): > @@ -2569,10 +2569,10 @@ metadata in_port in_port_oxm pkt_mark ct_mark > ct_label reg0 reg1 reg2 reg3 reg4 > nsh_c4: arbitrary mask > nsh_ttl: exact match or wildcard > > -' $1 > +' "$1" > } > ditto() { > - printf ' table %d ("%s"): > + printf ' table %d: > metadata: match=0xffffffffffffffff write=0xffffffffffffffff > max_entries=%d > instructions (table miss and others): > @@ -2581,10 +2581,10 @@ ditto() { > (same actions) > (same matching) > > -' $1 $2 $3 `expr $1 + 1` > +' $1 $2 `expr $1 + 1` > } > tail_tables() { > -echo ' table 252 ("table252"): > +echo ' table 252: > metadata: match=0xffffffffffffffff write=0xffffffffffffffff > max_entries=1000000 > instructions (table miss and others): > @@ -2593,7 +2593,7 @@ echo ' table 252 ("table252"): > (same actions) > (same matching) > > - table 253 ("table253"): > + table 253: > metadata: match=0xffffffffffffffff write=0xffffffffffffffff > max_entries=1000000 > instructions (table miss and others): > @@ -2602,9 +2602,9 @@ echo ' table 252 ("table252"): > (same matching) > ' > } > -(head_table classifier > +(head_table > for i in `seq 1 251`; do > - ditto $i table$i 1000000 > + ditto $i 1000000 > done > tail_tables) > expout > AT_CHECK([ovs-ofctl -O OpenFlow13 dump-table-features br0], [0], [expout]) > @@ -2619,16 +2619,49 @@ AT_CHECK( > <1> > ]) > # Check that the configuration was updated. > -(head_table main > - ditto 1 table1 1024 > +(head_table ' ("main")' > + ditto 1 1024 > for i in `seq 2 251`; do > - ditto $i table$i 1000000 > + ditto $i 1000000 > done > tail_tables) > expout > AT_CHECK([ovs-ofctl -O OpenFlow13 dump-table-features br0], [0], [expout]) > OVS_VSWITCHD_STOP > AT_CLEANUP > > +AT_SETUP([ofproto - flow table names]) > +OVS_VSWITCHD_START > +add_of_ports br0 1 2 > +AT_CHECK( > + [ovs-vsctl \ > + -- --id=@t0 create Flow_Table name=zero \ > + -- --id=@t1 create Flow_Table name=one \ > + -- --id=@t2 create Flow_Table name=two \ > + -- set bridge br0 'flow_tables={0=@t0,1=@t1,2=@t2}' \ > + | uuidfilt], > + [0], [<0> > +<1> > +<2> > +]) > +AT_DATA([flows.txt], [dnl > +table=zero in_port=p2 actions=p1,resubmit(,one) > +table=one,in_port=p1,ip,actions=ct(table=two) > +table=one,in_port=p1,arp,actions=goto_table(two) > +]) > +AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) > +AT_CHECK([ovs-ofctl --names --no-stats dump-flows br0], [0], [dnl > + table=zero, in_port=p2 actions=output:p1,resubmit(,one) > + table=one, ip,in_port=p1 actions=ct(table=two) > + table=one, arp,in_port=p1 actions=resubmit(,two) > +]) > +AT_CHECK([ovs-ofctl --no-names --no-stats dump-flows br0], [0], [dnl > + in_port=2 actions=output:1,resubmit(,1) > + table=1, ip,in_port=1 actions=ct(table=2) > + table=1, arp,in_port=1 actions=resubmit(,2) > +]) > +OVS_VSWITCHD_STOP > +AT_CLEANUP > + > AT_SETUP([ofproto - table description (OpenFlow 1.4)]) > OVS_VSWITCHD_START > (x=0 > diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in > index 95344c7e3872..7649bc5c4c50 100644 > --- a/utilities/ovs-ofctl.8.in > +++ b/utilities/ovs-ofctl.8.in > @@ -66,9 +66,12 @@ Prints to the console features for each of the flow > tables used by > \fBdump\-table\-desc \fIswitch\fR > Prints to the console configuration for each of the flow tables used > by \fIswitch\fR for OpenFlow 1.4+. > -.IP "\fBmod\-table \fIswitch\fR \fItable_id\fR \fIsetting\fR" > -This command configures flow table settings for OpenFlow table > -\fItable_id\fR within \fIswitch\fR. The available settings depend on > +.IP "\fBmod\-table \fIswitch\fR \fItable\fR \fIsetting\fR" > +This command configures flow table settings in \fIswitch\fR for > +OpenFlow table \fItable\fR, which may be expressed as a number or > +(unless \fB\-\-no\-names\fR is specified) a name. > +.IP > +The available settings depend on > the OpenFlow version in use. In OpenFlow 1.1 and 1.2 (which must be > enabled with the \fB\-O\fR option) only, \fBmod\-table\fR configures > behavior when no flow is found when a packet is looked up in a flow > @@ -606,9 +609,11 @@ connection to the switch. (These could only occur > using the > COMMANDS\fR.) > .IP "\fB!actions\fR" > Do not report actions as part of flow updates. > -.IP "\fBtable=\fInumber\fR" > -Limits the monitoring to the table with the given \fInumber\fR between > -0 and 254. By default, all tables are monitored. > +.IP "\fBtable=\fItable\fR" > +Limits the monitoring to the table with the given \fItable\fR, which > +may be expressed as a number between 0 and 254 or (unless > +\fB\-\-no\-names\fR is specified) a name. By default, all tables are > +monitored. > .IP "\fBout_port=\fIport\fR" > If set, only flows that output to \fIport\fR are monitored. The > \fIport\fR may be an OpenFlow port number or keyword > @@ -699,10 +704,11 @@ flows not in normal form. > them. In addition to match fields, commands that operate on flows > accept a few additional key-value pairs: > . > -.IP \fBtable=\fInumber\fR > -For flow dump commands, limits the flows dumped to those in the table > -with the given \fInumber\fR between 0 and 254. If not specified (or if > -255 is specified as \fInumber\fR), then flows in all tables are > +.IP \fBtable=\fItable\fR > +For flow dump commands, limits the flows dumped to those in > +\fItable\fR, which may be expressed as a number between 0 and 255 or > +(unless \fB\-\-no\-names\fR is specified) a name. If not specified > +(or if 255 is specified as \fItable\fR), then flows in all tables are > dumped. > . > .IP > @@ -970,8 +976,8 @@ only known to be implemented by Open vSwitch: > .IP \fBresubmit\fB:\fIport\fR > .IQ \fBresubmit\fB(\fR[\fIport\fR]\fB,\fR[\fItable\fR]\fB) > .IQ \fBresubmit\fB(\fR[\fIport\fR]\fB,\fR[\fItable\fR]\fB,ct) > -Re-searches this OpenFlow flow table (or the table whose number is > -specified by \fItable\fR) with the \fBin_port\fR field replaced by > +Re-searches this OpenFlow flow table (or table \fItable\fR, if > +specified) with the \fBin_port\fR field replaced by > \fIport\fR (if \fIport\fR is specified) and the packet 5-tuple fields > swapped with the corresponding conntrack original direction tuple > fields (if \fBct\fR is specified, see \fBct_nw_src\fR above), and > @@ -980,6 +986,9 @@ in this flow entry. The \fBin_port\fR and swapped > 5-tuple fields are > restored immediately after the search, before any actions are > executed. > .IP > +The \fItable\fR may be expressed as a number between 0 and 254 or > +(unless \fB\-\-no\-names\fR is specified) a name. > +.IP > The \fBct\fR option requires a valid connection tracking state as a > match prerequisite in the flow where this action is placed. Examples > of valid connection tracking state matches include > @@ -1057,12 +1066,14 @@ existing connection and start a new one in the > current direction. > This flag has no effect if the original direction of the connection is > already the same as that of the current packet. > .RE > -.IP \fBtable=\fInumber\fR > +.IP \fBtable=\fItable\fR > Fork pipeline processing in two. The original instance of the packet will > continue processing the current actions list as an untracked packet. An > additional instance of the packet will be sent to the connection tracker, > which > will be re-injected into the OpenFlow pipeline to resume processing in > table > -\fInumber\fR, with the \fBct_state\fR and other ct match fields set. If > the > +\fInumber\fR (which may be specified as a number between 0 and 254 or, > +unless \fB\-\-no\-names\fR is specified, a name), with the > +\fBct_state\fR and other ct match fields set. If > \fBtable\fR is not specified, then the packet which is submitted to the > connection tracker is not re-injected into the OpenFlow pipeline. It is > strongly recommended to specify a table later than the current table to > prevent > @@ -1472,10 +1483,10 @@ flow syntax. > Adds a \fBfin_timeout\fR action with the specified arguments to the > new flow. This feature was added in Open vSwitch 1.5.90. > . > -.IP \fBtable=\fInumber\fR > +.IP \fBtable=\fItable\fR > The table in which the new flow should be inserted. Specify a decimal > -number between 0 and 254. The default, if \fBtable\fR is unspecified, > -is table 1. > +number between 0 and 254 or (unless \fB\-\-no\-names\fR is specified) > +a name. The default, if \fBtable\fR is unspecified, is table 1. > . > .IP \fBdelete_learned\fR > This flag enables deletion of the learned flows when the flow with the > @@ -1547,12 +1558,6 @@ Add an \fBoutput\fR action to the new flow's > actions, that outputs to > the OpenFlow port taken from \fIfield\fB[\fIstart\fB..\fIend\fB]\fR, > which must be an NXM field as described above. > .RE > -.IP > -For best performance, segregate learned flows into a table (using > -\fBtable=\fInumber\fR) that is not used for any other flows except > -possibly for a lowest-priority ``catch-all'' flow, that is, a flow > -with no match criteria. (This is why the default \fBtable\fR is 1, to > -keep the learned flows separate from the primary flow table 0.) > .RE > . > .RS > @@ -1675,7 +1680,9 @@ band type. See the description of the \fBMeter Table > Commands\fR, above, > for more details. > . > .IP \fBgoto_table\fR:\fItable\fR > -Indicates the next table in the process pipeline. > +Jumps to \fItable\Fr as the next table in the process pipeline. The > +\fItable\fR may be a number between 0 and 254 or (unless > +\fB\-\-no\-names\fR is specified) a name. > . > .IP "\fBfin_timeout(\fIargument\fR[\fB,\fIargument\fR]\fB)" > This action changes the idle timeout or hard timeout, or both, of this > @@ -2286,21 +2293,24 @@ Uses strict matching when running flow > modification commands. > . > .IP "\fB\-\-names\fR" > .IQ "\fB\-\-no\-names\fR" > -Every OpenFlow port has a name and a number. By default, > -\fBovs\-ofctl\fR commands accept both port names and numbers, and they > -display port names if \fBovs\-ofctl\fR is running on an interactive > -console, port numbers otherwise. With \fB\-\-names\fR, > -\fBovs\-ofctl\fR commands both accept and display port names; with > -\fB\-\-no\-names\fR, commands neither accept nor display port names. > -.IP > -If a port name contains special characters or might be confused with a > -keyword within a flow, it may be enclosed in double quotes (escaped > -from the shell). If necessary, JSON-style escape sequences may be > -used inside quotes, as specified in RFC 7159. When it displays port > -names, \fBovs\-ofctl\fR quotes any name that does not start with a > -letter followed by letters or digits. > -.IP > -These options are new in Open vSwitch 2.8. Earlier versions always > +Every OpenFlow port has a name and a number, and every OpenFlow flow > +table has a number and sometimes a name. By default, \fBovs\-ofctl\fR > +commands accept both port and table names and numbers, and they > +display port and table names if \fBovs\-ofctl\fR is running on an > +interactive console, numbers otherwise. With \fB\-\-names\fR, > +\fBovs\-ofctl\fR commands both accept and display port and table > +names; with \fB\-\-no\-names\fR, commands neither accept nor display > +port and table names. > +.IP > +If a port or table name contains special characters or might be > +confused with a keyword within a flow, it may be enclosed in double > +quotes (escaped from the shell). If necessary, JSON-style escape > +sequences may be used inside quotes, as specified in RFC 7159. When > +it displays port and table names, \fBovs\-ofctl\fR quotes any name > +that does not start with a letter followed by letters or digits. > +.IP > +Open vSwitch added support for port names and these options. Open > +vSwitch 2.10 added support for table names. Earlier versions always > behaved as if \fB\-\-no\-names\fR were specified. > .IP > Open vSwitch does not place its own limit on the length of port names, > @@ -2312,6 +2322,8 @@ Truncation can also cause long names that are > different to appear to > be the same; when a switch has two ports with the same (truncated) > name, \fBovs\-ofctl\fR refuses to display or accept the name, using > the number instead. > +.IP > +OpenFlow and Open vSwitch limit table names to 32 bytes. > . > .IP "\fB\-\-stats\fR" > .IQ "\fB\-\-no\-stats\fR" > diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c > index 53e303400a11..6a30efe8c4c3 100644 > --- a/utilities/ovs-ofctl.c > +++ b/utilities/ovs-ofctl.c > @@ -125,15 +125,18 @@ struct sort_criterion { > static struct sort_criterion *criteria; > static size_t n_criteria, allocated_criteria; > > -/* --names, --no-names: Show port names in output and accept port numbers > in > - * input. (When neither is specified, the default is to accept port > numbers > - * but, for backward compatibility, not to show them unless this is an > - * interactive console session.) */ > -static int use_port_names = -1; > +/* --names, --no-names: Show port and table names in output and accept > them in > + * input. (When neither is specified, the default is to accept port > names but, > + * for backward compatibility, not to show them unless this is an > interactive > + * console session.) */ > +static int use_names = -1; > static const struct ofputil_port_map *ports_to_accept(const char > *vconn_name); > static const struct ofputil_port_map *ports_to_show(const char > *vconn_name); > -static bool should_accept_ports(void); > -static bool should_show_ports(void); > +static const struct ofputil_table_map *tables_to_accept( > + const char *vconn_name); > +static const struct ofputil_table_map *tables_to_show(const char > *vconn_name); > +static bool should_accept_names(void); > +static bool should_show_names(void); > > /* --stats, --no-stats: Show statistics in flow dumps? */ > static int show_stats = 1; > @@ -216,8 +219,8 @@ parse_options(int argc, char *argv[]) > {"timestamp", no_argument, NULL, OPT_TIMESTAMP}, > {"sort", optional_argument, NULL, OPT_SORT}, > {"rsort", optional_argument, NULL, OPT_RSORT}, > - {"names", no_argument, &use_port_names, 1}, > - {"no-names", no_argument, &use_port_names, 0}, > + {"names", no_argument, &use_names, 1}, > + {"no-names", no_argument, &use_names, 0}, > {"stats", no_argument, &show_stats, 1}, > {"no-stats", no_argument, &show_stats, 0}, > {"unixctl", required_argument, NULL, OPT_UNIXCTL}, > @@ -640,7 +643,9 @@ dump_transaction(struct vconn *vconn, struct ofpbuf > *request) > enum ofpraw raw; > > ofp_print(stdout, reply->data, reply->size, > - ports_to_show(vconn_get_name(vconn)), > verbosity + 1); > + ports_to_show(vconn_get_name(vconn)), > + tables_to_show(vconn_get_name(vconn)), > + verbosity + 1); > > ofpraw_decode(&raw, reply->data); > if (ofptype_from_ofpraw(raw) == OFPTYPE_ERROR) { > @@ -652,6 +657,7 @@ dump_transaction(struct vconn *vconn, struct ofpbuf > *request) > ofp_to_string( > reply->data, reply->size, > ports_to_show(vconn_get_name(vconn)), > + tables_to_show(vconn_get_name(vconn)), > verbosity + 1)); > } > } else { > @@ -666,7 +672,9 @@ dump_transaction(struct vconn *vconn, struct ofpbuf > *request) > run(vconn_transact(vconn, request, &reply), "talking to %s", > vconn_get_name(vconn)); > ofp_print(stdout, reply->data, reply->size, > - ports_to_show(vconn_get_name(vconn)), verbosity + 1); > + ports_to_show(vconn_get_name(vconn)), > + tables_to_show(vconn_get_name(vconn)), > + verbosity + 1); > ofpbuf_delete(reply); > } > } > @@ -697,7 +705,9 @@ transact_multiple_noreply(struct vconn *vconn, struct > ovs_list *requests) > "talking to %s", vconn_get_name(vconn)); > if (reply) { > ofp_print(stderr, reply->data, reply->size, > - ports_to_show(vconn_get_name(vconn)), verbosity + 2); > + ports_to_show(vconn_get_name(vconn)), > + tables_to_show(vconn_get_name(vconn)), > + verbosity + 2); > exit(1); > } > ofpbuf_delete(reply); > @@ -743,7 +753,7 @@ bundle_print_errors(struct ovs_list *errors, struct > ovs_list *requests, > } > fprintf(stderr, "Error %s for: ", ofperr_get_name(ofperr)); > ofp_print(stderr, ofp_msg, msg_len, ports_to_show(vconn_name), > - verbosity + 1); > + tables_to_show(vconn_name), verbosity + 1); > } > ofpbuf_uninit(&payload); > ofpbuf_delete(error); > @@ -823,7 +833,7 @@ ofctl_show(struct ovs_cmdl_context *ctx) > run(vconn_transact(vconn, request, &reply), "talking to %s", > vconn_name); > > has_ports = ofputil_switch_features_has_ports(reply); > - ofp_print(stdout, reply->data, reply->size, NULL, verbosity + 1); > + ofp_print(stdout, reply->data, reply->size, NULL, NULL, verbosity + > 1); > ofpbuf_delete(reply); > > if (!has_ports) { > @@ -884,7 +894,7 @@ ofctl_dump_table_features(struct ovs_cmdl_context > *ctx) > if (error) { > ovs_fatal(0, "decode error: %s", ofperr_get_name(error)); > } else if (type == OFPTYPE_ERROR) { > - ofp_print(stdout, reply->data, reply->size, NULL, > + ofp_print(stdout, reply->data, reply->size, NULL, NULL, > verbosity + 1); > done = true; > } else if (type == OFPTYPE_TABLE_FEATURES_STATS_REPLY) { > @@ -904,7 +914,8 @@ ofctl_dump_table_features(struct ovs_cmdl_context > *ctx) > > struct ds s = DS_EMPTY_INITIALIZER; > ofp_print_table_features(&s, &tf, n ? &prev : NULL, > - NULL, NULL); > + NULL, NULL, > + > tables_to_show(ctx->argv[1])); > puts(ds_cstr(&s)); > ds_destroy(&s); > > @@ -915,6 +926,7 @@ ofctl_dump_table_features(struct ovs_cmdl_context > *ctx) > ovs_fatal(0, "received bad reply: %s", > ofp_to_string(reply->data, reply->size, > ports_to_show(ctx->argv[1]), > + tables_to_show(ctx->argv[1]), > verbosity + 1)); > } > } else { > @@ -1044,7 +1056,7 @@ port_iterator_next(struct port_iterator *pi, struct > ofputil_phy_port *pp) > } else if (retval != EOF) { > ovs_fatal(0, "received bad reply: %s", > ofp_to_string(pi->reply->data, pi->reply->size, > - NULL, verbosity + 1)); > + NULL, NULL, verbosity + 1)); > } > } > > @@ -1066,7 +1078,7 @@ port_iterator_next(struct port_iterator *pi, struct > ofputil_phy_port *pp) > || type != OFPTYPE_PORT_DESC_STATS_REPLY) { > ovs_fatal(0, "received bad reply: %s", > ofp_to_string(pi->reply->data, pi->reply->size, > NULL, > - verbosity + 1)); > + NULL, verbosity + 1)); > } > > pi->more = (ofpmp_flags(oh) & OFPSF_REPLY_MORE) != 0; > @@ -1163,33 +1175,189 @@ get_port_map(const char *vconn_name) > static const struct ofputil_port_map * > ports_to_accept(const char *vconn_name) > { > - return should_accept_ports() ? get_port_map(vconn_name) : NULL; > + return should_accept_names() ? get_port_map(vconn_name) : NULL; > } > > static const struct ofputil_port_map * > ports_to_show(const char *vconn_name) > { > - return should_show_ports() ? get_port_map(vconn_name) : NULL; > + return should_show_names() ? get_port_map(vconn_name) : NULL; > +} > + > +struct table_iterator { > + struct vconn *vconn; > + > + enum { TI_STATS, TI_FEATURES } variant; > + struct ofpbuf *reply; > + ovs_be32 send_xid; > + bool more; > + > + struct ofputil_table_features features; > +}; > + > +/* Initializes 'ti' to prepare for iterating through all of the tables on > the > + * OpenFlow switch to which 'vconn' is connected. > + * > + * During iteration, the client should not make other use of 'vconn', > because > + * that can cause other messages to be interleaved with the replies used > by the > + * iterator and thus some tables may be missed or a hang can occur. */ > +static void > +table_iterator_init(struct table_iterator *ti, struct vconn *vconn) > +{ > + memset(ti, 0, sizeof *ti); > + ti->vconn = vconn; > + ti->variant = (vconn_get_version(vconn) < OFP13_VERSION > + ? TI_STATS : TI_FEATURES); > + ti->more = true; > + > + enum ofpraw raw = (ti->variant == TI_STATS > + ? OFPRAW_OFPST_TABLE_REQUEST > + : OFPRAW_OFPST13_TABLE_FEATURES_REQUEST); > + struct ofpbuf *rq = ofpraw_alloc(raw, vconn_get_version(vconn), 0); > + ti->send_xid = ((struct ofp_header *) rq->data)->xid; > + send_openflow_buffer(ti->vconn, rq); > +} > + > +/* Obtains the next table from 'ti'. On success, returns the next table's > + * features; on failure, returns NULL. */ > +static const struct ofputil_table_features * > +table_iterator_next(struct table_iterator *ti) > +{ > + for (;;) { > + if (ti->reply) { > + int retval; > + if (ti->variant == TI_STATS) { > + struct ofputil_table_stats ts; > + retval = ofputil_decode_table_stats_reply(ti->reply, > + &ts, > &ti->features); > + } else { > + ovs_assert(ti->variant == TI_FEATURES); > + retval = ofputil_decode_table_features(ti->reply, > + &ti->features, > + true); > + } > + if (!retval) { > + return &ti->features; > + } else if (retval != EOF) { > + ovs_fatal(0, "received bad reply: %s", > + ofp_to_string(ti->reply->data, ti->reply->size, > + NULL, NULL, verbosity + 1)); > + } > + } > + > + if (!ti->more) { > + return NULL; > + } > + > + ovs_be32 recv_xid; > + do { > + ofpbuf_delete(ti->reply); > + run(vconn_recv_block(ti->vconn, &ti->reply), > + "OpenFlow receive failed"); > + recv_xid = ((struct ofp_header *) ti->reply->data)->xid; > + } while (ti->send_xid != recv_xid); > + > + struct ofp_header *oh = ti->reply->data; > + enum ofptype type; > + if (ofptype_pull(&type, ti->reply) > + || type != (ti->variant == TI_STATS > + ? OFPTYPE_TABLE_STATS_REPLY > + : OFPTYPE_TABLE_FEATURES_STATS_REPLY)) { > + ovs_fatal(0, "received bad reply: %s", > + ofp_to_string(ti->reply->data, ti->reply->size, > NULL, > + NULL, verbosity + 1)); > + } > + > + ti->more = (ofpmp_flags(oh) & OFPSF_REPLY_MORE) != 0; > + } > +} > + > +/* Destroys iterator 'ti'. */ > +static void > +table_iterator_destroy(struct table_iterator *ti) > +{ > + if (ti) { > + while (ti->more) { > + /* Drain vconn's queue of any other replies for this request. > */ > + table_iterator_next(ti); > + } > + > + ofpbuf_delete(ti->reply); > + } > +} > + > +static const struct ofputil_table_map * > +get_table_map(const char *vconn_name) > +{ > + static struct shash table_maps = SHASH_INITIALIZER(&table_maps); > + struct ofputil_table_map *map = shash_find_data(&table_maps, > vconn_name); > + if (!map) { > + map = xmalloc(sizeof *map); > + ofputil_table_map_init(map); > + shash_add(&table_maps, vconn_name, map); > + > + if (!strchr(vconn_name, ':') || !vconn_verify_name(vconn_name)) { > + /* For an active vconn (which includes a vconn constructed > from a > + * bridge name), connect to it and pull down the port > name-number > + * mapping. */ > + struct vconn *vconn; > + open_vconn(vconn_name, &vconn); > + > + struct table_iterator ti; > + table_iterator_init(&ti, vconn); > + for (;;) { > + const struct ofputil_table_features *tf > + = table_iterator_next(&ti); > + if (!tf) { > + break; > + } > + if (tf->name[0]) { > + ofputil_table_map_put(map, tf->table_id, tf->name); > + } > + } > + table_iterator_destroy(&ti); > + > + vconn_close(vconn); > + } else { > + /* Don't bother with passive vconns, since it could take a > long > + * time for the remote to try to connect to us. Don't bother > with > + * invalid vconn names either. */ > + } > + } > + return map; > +} > + > +static const struct ofputil_table_map * > +tables_to_accept(const char *vconn_name) > +{ > + return should_accept_names() ? get_table_map(vconn_name) : NULL; > +} > + > +static const struct ofputil_table_map * > +tables_to_show(const char *vconn_name) > +{ > + return should_show_names() ? get_table_map(vconn_name) : NULL; > } > > -/* We accept port names unless the feature is turned off explicitly. */ > +/* We accept port and table names unless the feature is turned off > + * explicitly. */ > static bool > -should_accept_ports(void) > +should_accept_names(void) > { > - return use_port_names != 0; > + return use_names != 0; > } > > -/* We show port names only if the feature is turned on explicitly, or if > we're > - * interacting with a user on the console. */ > +/* We show port and table names only if the feature is turned on > explicitly, or > + * if we're interacting with a user on the console. */ > static bool > -should_show_ports(void) > +should_show_names(void) > { > static int interactive = -1; > if (interactive == -1) { > interactive = isatty(STDOUT_FILENO); > } > > - return use_port_names > 0 || (use_port_names == -1 && interactive); > + return use_names > 0 || (use_names == -1 && interactive); > } > > /* Returns the port number corresponding to 'port_name' (which may be a > port > @@ -1222,7 +1390,7 @@ try_set_protocol(struct vconn *vconn, enum > ofputil_protocol want, > run(vconn_transact_noreply(vconn, request, &reply), > "talking to %s", vconn_get_name(vconn)); > if (reply) { > - char *s = ofp_to_string(reply->data, reply->size, NULL, 2); > + char *s = ofp_to_string(reply->data, reply->size, NULL, NULL, > 2); > VLOG_DBG("%s: failed to set protocol, switch replied: %s", > vconn_get_name(vconn), s); > free(s); > @@ -1274,8 +1442,11 @@ prepare_dump_flows(int argc, char *argv[], bool > aggregate, > const char *match = argc > 2 ? argv[2] : ""; > const struct ofputil_port_map *port_map > = *match ? ports_to_accept(vconn_name) : NULL; > + const struct ofputil_table_map *table_map > + = *match ? tables_to_accept(vconn_name) : NULL; > error = parse_ofp_flow_stats_request_str(fsr, aggregate, match, > - port_map, &usable_protocols); > + port_map, table_map, > + &usable_protocols); > if (error) { > ovs_fatal(0, "%s", error); > } > @@ -1366,7 +1537,7 @@ compare_flows(const void *afs_, const void *bfs_) > static void > ofctl_dump_flows(struct ovs_cmdl_context *ctx) > { > - if (!n_criteria && !should_show_ports() && show_stats) { > + if (!n_criteria && !should_show_names() && show_stats) { > ofctl_dump_flows__(ctx->argc, ctx->argv, false); > return; > } else { > @@ -1388,7 +1559,7 @@ ofctl_dump_flows(struct ovs_cmdl_context *ctx) > for (size_t i = 0; i < n_fses; i++) { > ds_clear(&s); > ofp_print_flow_stats(&s, &fses[i], > ports_to_show(ctx->argv[1]), > - show_stats); > + tables_to_show(ctx->argv[1]), > show_stats); > printf(" %s\n", ds_cstr(&s)); > } > ds_destroy(&s); > @@ -1579,7 +1750,8 @@ ofctl_flow_mod_file(int argc OVS_UNUSED, char > *argv[], int command) > * this is backwards compatible. */ > command = -2; > } > - error = parse_ofp_flow_mod_file(argv[2], ports_to_accept(argv[1]), > command, > + error = parse_ofp_flow_mod_file(argv[2], ports_to_accept(argv[1]), > + tables_to_accept(argv[1]), command, > &fms, &n_fms, &usable_protocols); > if (error) { > ovs_fatal(0, "%s", error); > @@ -1599,7 +1771,8 @@ ofctl_flow_mod(int argc, char *argv[], uint16_t > command) > enum ofputil_protocol usable_protocols; > > error = parse_ofp_flow_mod_str(&fm, argc > 2 ? argv[2] : "", > - ports_to_accept(argv[1]), command, > + ports_to_accept(argv[1]), > + tables_to_accept(argv[1]), command, > &usable_protocols); > if (error) { > ovs_fatal(0, "%s", error); > @@ -1649,7 +1822,7 @@ set_packet_in_format(struct vconn *vconn, > run(vconn_transact_noreply(vconn, spif, &reply), > "talking to %s", vconn_get_name(vconn)); > if (reply) { > - char *s = ofp_to_string(reply->data, reply->size, NULL, 2); > + char *s = ofp_to_string(reply->data, reply->size, NULL, NULL, > 2); > VLOG_DBG("%s: failed to set packet in format to nx_packet_in, > " > "controller replied: %s.", > vconn_get_name(vconn), s); > @@ -1745,7 +1918,8 @@ ofctl_send(struct unixctl_conn *conn, int argc, > > fprintf(stderr, "send: "); > ofp_print(stderr, msg->data, msg->size, > - ports_to_show(vconn_get_name(vconn)), verbosity); > + ports_to_show(vconn_get_name(vconn)), > + tables_to_show(vconn_get_name(vconn)), verbosity); > > error = vconn_send_block(vconn, msg); > if (error) { > @@ -1781,7 +1955,7 @@ unixctl_packet_out(struct unixctl_conn *conn, int > OVS_UNUSED argc, > > error_msg = parse_ofp_packet_out_str( > &po, argv[1], ports_to_accept(vconn_get_name(vconn)), > - &usable_protocols); > + tables_to_accept(vconn_get_name(vconn)), &usable_protocols); > if (error_msg) { > ds_put_format(&reply, "%s\n", error_msg); > free(error_msg); > @@ -1797,7 +1971,8 @@ unixctl_packet_out(struct unixctl_conn *conn, int > OVS_UNUSED argc, > struct ofpbuf *msg = ofputil_encode_packet_out(&po, protocol); > > ofp_print(stderr, msg->data, msg->size, > - ports_to_show(vconn_get_name(vconn)), verbosity); > + ports_to_show(vconn_get_name(vconn)), > + tables_to_show(vconn_get_name(vconn)), verbosity); > > int error = vconn_send_block(vconn, msg); > if (error) { > @@ -1961,7 +2136,8 @@ monitor_vconn(struct vconn *vconn, bool > reply_to_echo_requests, > > ofptype_decode(&type, b->data); > ofp_print(stderr, b->data, b->size, > - ports_to_show(vconn_get_name(vconn)), verbosity + > 2); > + ports_to_show(vconn_get_name(vconn)), > + tables_to_show(vconn_get_name(vconn)), verbosity + > 2); > fflush(stderr); > > switch ((int) type) { > @@ -2004,6 +2180,7 @@ monitor_vconn(struct vconn *vconn, bool > reply_to_echo_requests, > fprintf(stderr, "send: "); > ofp_print(stderr, reply->data, reply->size, > ports_to_show(vconn_get_name(vconn)), > + tables_to_show(vconn_get_name(vconn)), > verbosity + 2); > fflush(stderr); > > @@ -2083,6 +2260,7 @@ ofctl_monitor(struct ovs_cmdl_context *ctx) > > error = parse_flow_monitor_request(&fmr, arg + 6, > > ports_to_accept(ctx->argv[1]), > + > tables_to_accept(ctx->argv[1]), > &usable_protocols); > if (error) { > ovs_fatal(0, "%s", error); > @@ -2200,6 +2378,7 @@ ofctl_packet_out(struct ovs_cmdl_context *ctx) > ofpbuf_init(&ofpacts, 64); > struct ofpact_parse_params pp = { > .port_map = ports_to_accept(ctx->argv[1]), > + .table_map = tables_to_accept(ctx->argv[1]), > .ofpacts = &ofpacts, > .usable_protocols = &usable_protocols > }; > @@ -2237,6 +2416,7 @@ ofctl_packet_out(struct ovs_cmdl_context *ctx) > } else if (ctx->argc == 3) { > error = parse_ofp_packet_out_str(&po, ctx->argv[2], > ports_to_accept(ctx->argv[1]), > + tables_to_accept(ctx->argv[1]), > &usable_protocols); > if (error) { > ovs_fatal(0, "%s", error); > @@ -2343,7 +2523,7 @@ fetch_table_desc(struct vconn *vconn, struct > ofputil_table_mod *tm, > if (ofptype_pull(&type, &b) > || type != OFPTYPE_TABLE_DESC_REPLY) { > ovs_fatal(0, "received bad reply: %s", > - ofp_to_string(reply->data, reply->size, NULL, > + ofp_to_string(reply->data, reply->size, NULL, > NULL, > verbosity + 1)); > } > uint16_t flags = ofpmp_flags(oh); > @@ -2386,6 +2566,7 @@ ofctl_mod_table(struct ovs_cmdl_context *ctx) > int i; > > error = parse_ofp_table_mod(&tm, ctx->argv[2], ctx->argv[3], > + tables_to_accept(ctx->argv[1]), > &usable_versions); > if (error) { > ovs_fatal(0, "%s", error); > @@ -2511,7 +2692,7 @@ ofctl_ofp_parse(struct ovs_cmdl_context *ctx) > ovs_fatal(0, "%s: unexpected end of file mid-message", > filename); > } > > - ofp_print(stdout, b.data, b.size, NULL, verbosity + 2); > + ofp_print(stdout, b.data, b.size, NULL, NULL, verbosity + 2); > } > ofpbuf_uninit(&b); > > @@ -2599,7 +2780,7 @@ ofctl_ofp_parse_pcap(struct ovs_cmdl_context *ctx) > IP_ARGS(flow.nw_src), ntohs(flow.tp_src), > IP_ARGS(flow.nw_dst), ntohs(flow.tp_dst)); > ofp_print(stdout, dp_packet_data(payload), length, > - NULL, verbosity + 1); > + NULL, NULL, verbosity + 1); > dp_packet_pull(payload, length); > } > } > @@ -2644,9 +2825,10 @@ ofctl_ping(struct ovs_cmdl_context *ctx) > || reply->size != payload > || memcmp(request->msg, reply->msg, payload)) { > printf("Reply does not match request. Request:\n"); > - ofp_print(stdout, request, request->size, NULL, verbosity + > 2); > + ofp_print(stdout, request, request->size, NULL, NULL, > + verbosity + 2); > printf("Reply:\n"); > - ofp_print(stdout, reply, reply->size, NULL, verbosity + 2); > + ofp_print(stdout, reply, reply->size, NULL, NULL, verbosity + > 2); > } > printf("%"PRIu32" bytes from %s: xid=%08"PRIx32" time=%.1f ms\n", > reply->size, ctx->argv[1], ntohl(rpy_hdr->xid), > @@ -2809,6 +2991,7 @@ ofctl_group_mod_file(int argc OVS_UNUSED, char > *argv[], int command) > command = -2; > } > error = parse_ofp_group_mod_file(argv[2], ports_to_accept(argv[1]), > + tables_to_accept(argv[1]), > command, &gms, &n_gms, > &usable_protocols); > if (error) { > ovs_fatal(0, "%s", error); > @@ -2829,6 +3012,7 @@ ofctl_group_mod(int argc, char *argv[], uint16_t > command) > > error = parse_ofp_group_mod_str(&gm, command, argc > 2 ? argv[2] > : "", > ports_to_accept(argv[1]), > + tables_to_accept(argv[1]), > &usable_protocols); > if (error) { > ovs_fatal(0, "%s", error); > @@ -2889,6 +3073,7 @@ ofctl_dump_group_stats(struct ovs_cmdl_context *ctx) > error = parse_ofp_group_mod_str(&gm, OFPGC11_DELETE, > ctx->argc > 2 ? ctx->argv[2] : "", > ports_to_accept(ctx->argv[1]), > + tables_to_accept(ctx->argv[1]), > &usable_protocols); > if (error) { > ovs_fatal(0, "%s", error); > @@ -2954,6 +3139,7 @@ ofctl_bundle(struct ovs_cmdl_context *ctx) > char *error; > > error = parse_ofp_bundle_file(ctx->argv[2], > ports_to_accept(ctx->argv[1]), > + tables_to_accept(ctx->argv[1]), > &bms, &n_bms, &usable_protocols); > if (error) { > ovs_fatal(0, "%s", error); > @@ -3126,9 +3312,11 @@ struct fte_state { > /* The final metadata table that we have constructed. */ > struct tun_table *tun_tab; > > - /* Port map. There is only one port map, not one per source, because > it > - * only makes sense to display a single name for a given port number. > */ > + /* Port and table map. There is only one of each, not one per source, > + * because it only makes sense to display a single name for a given > port > + * or table number. */ > const struct ofputil_port_map *port_map; > + const struct ofputil_table_map *table_map; > }; > > /* Frees 'version' and the data that it owns. */ > @@ -3362,6 +3550,7 @@ fte_state_init(struct fte_state *state) > ovs_list_init(&state->fte_pending_list); > state->tun_tab = NULL; > state->port_map = NULL; > + state->table_map = NULL; > } > > static void > @@ -3447,7 +3636,7 @@ read_flows_from_file(const char *filename, struct > fte_state *state, int index) > enum ofputil_protocol usable; > > error = parse_ofp_str(&fm, OFPFC_ADD, ds_cstr(&s), > state->port_map, > - &usable); > + state->table_map, &usable); > if (error) { > ovs_fatal(0, "%s:%d: %s", filename, line_number, error); > } > @@ -3568,6 +3757,7 @@ ofctl_replace_flows(struct ovs_cmdl_context *ctx) > > fte_state_init(&fte_state); > fte_state.port_map = ports_to_accept(ctx->argv[1]); > + fte_state.table_map = tables_to_accept(ctx->argv[1]); > usable_protocols = read_flows_from_file(ctx->argv[2], &fte_state, > FILE_IDX); > > protocol = open_vconn(ctx->argv[1], &vconn); > @@ -3819,7 +4009,7 @@ ofctl_parse_flows__(struct ofputil_flow_mod *fms, > size_t n_fms, > struct ofpbuf *msg; > > msg = ofputil_encode_flow_mod(fm, protocol); > - ofp_print(stdout, msg->data, msg->size, NULL, verbosity); > + ofp_print(stdout, msg->data, msg->size, NULL, NULL, verbosity); > ofpbuf_delete(msg); > > free(CONST_CAST(struct ofpact *, fm->ofpacts)); > @@ -3835,7 +4025,7 @@ ofctl_parse_flow(struct ovs_cmdl_context *ctx) > struct ofputil_flow_mod fm; > char *error; > > - error = parse_ofp_flow_mod_str(&fm, ctx->argv[1], NULL, > + error = parse_ofp_flow_mod_str(&fm, ctx->argv[1], NULL, NULL, > OFPFC_ADD, &usable_protocols); > if (error) { > ovs_fatal(0, "%s", error); > @@ -3853,7 +4043,7 @@ ofctl_parse_flows(struct ovs_cmdl_context *ctx) > size_t n_fms = 0; > char *error; > > - error = parse_ofp_flow_mod_file(ctx->argv[1], NULL, OFPFC_ADD, > + error = parse_ofp_flow_mod_file(ctx->argv[1], NULL, NULL, OFPFC_ADD, > &fms, &n_fms, &usable_protocols); > if (error) { > ovs_fatal(0, "%s", error); > @@ -4295,7 +4485,7 @@ ofctl_check_vlan(struct ovs_cmdl_context *ctx) > string_s = match_to_string(&match, NULL, OFP_DEFAULT_PRIORITY); > printf("%s -> ", string_s); > fflush(stdout); > - error_s = parse_ofp_str(&fm, -1, string_s, NULL, &usable_protocols); > + error_s = parse_ofp_str(&fm, -1, string_s, NULL, NULL, > &usable_protocols); > if (error_s) { > ovs_fatal(0, "%s", error_s); > } > @@ -4464,7 +4654,7 @@ ofctl_ofp_print(struct ovs_cmdl_context *ctx) > if (ofpbuf_put_hex(&packet, buffer, NULL)[0] != '\0') { > ovs_fatal(0, "trailing garbage following hex bytes"); > } > - ofp_print(stdout, packet.data, packet.size, NULL, verbosity); > + ofp_print(stdout, packet.data, packet.size, NULL, NULL, verbosity); > ofpbuf_uninit(&packet); > ds_destroy(&line); > } > @@ -4479,7 +4669,7 @@ ofctl_encode_hello(struct ovs_cmdl_context *ctx) > > hello = ofputil_encode_hello(bitmap); > ovs_hex_dump(stdout, hello->data, hello->size, 0, false); > - ofp_print(stdout, hello->data, hello->size, NULL, verbosity); > + ofp_print(stdout, hello->data, hello->size, NULL, NULL, verbosity); > ofpbuf_delete(hello); > } > > diff --git a/utilities/ovs-testcontroller.c b/utilities/ovs- > testcontroller.c > index 8f8fc2bb13a1..571af0c7f971 100644 > --- a/utilities/ovs-testcontroller.c > +++ b/utilities/ovs-testcontroller.c > @@ -335,7 +335,7 @@ parse_options(int argc, char *argv[]) > break; > > case OPT_WITH_FLOWS: > - error = parse_ofp_flow_mod_file(optarg, NULL, OFPFC_ADD, > + error = parse_ofp_flow_mod_file(optarg, NULL, NULL, > OFPFC_ADD, > &default_flows, > &n_default_flows, > &usable_protocols); > if (error) { > -- > 2.15.1 > > _______________________________________________ > dev mailing list > [email protected] > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
