Thanks for the review! I applied this series to master.
On Thu, Feb 01, 2018 at 09:57:24AM -0800, Yifeng Sun wrote: > Thanks for the nice feature. It looks good to me. > > Reviewed-by: Yifeng Sun <pkusunyif...@gmail.com> > > > On Wed, Jan 31, 2018 at 11:36 AM, Ben Pfaff <b...@ovn.org> 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 <k...@nohguchi.com> > > Signed-off-by: Ben Pfaff <b...@ovn.org> > > --- > > 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 > > d...@openvswitch.org > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev