Looks good, May want to update NEWS for this series. Ethan
On Thu, Aug 4, 2011 at 16:29, Ben Pfaff <[email protected]> wrote: > This makes multiple table support in ofproto-dpif useful, by allowing > resubmits into tables other than 0. > --- > include/openflow/nicira-ext.h | 52 ++++++++++++++++++++++--------- > lib/ofp-parse.c | 39 +++++++++++++++++++++-- > lib/ofp-print.c | 13 ++++++++ > lib/ofp-util.c | 15 +++++++++ > lib/ofp-util.h | 1 + > ofproto/ofproto-dpif.c | 68 +++++++++++++++++++++++++++++----------- > tests/automake.mk | 1 + > tests/ofproto-dpif.at | 19 +++++++++++ > tests/ovs-ofctl.at | 3 ++ > tests/testsuite.at | 1 + > utilities/ovs-ofctl.8.in | 14 ++++++-- > 11 files changed, 184 insertions(+), 42 deletions(-) > create mode 100644 tests/ofproto-dpif.at > > diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h > index 5cf02e7..776ec39 100644 > --- a/include/openflow/nicira-ext.h > +++ b/include/openflow/nicira-ext.h > @@ -279,7 +279,8 @@ enum nx_action_subtype { > NXAST_MULTIPATH, /* struct nx_action_multipath */ > NXAST_AUTOPATH, /* struct nx_action_autopath */ > NXAST_BUNDLE, /* struct nx_action_bundle */ > - NXAST_BUNDLE_LOAD /* struct nx_action_bundle */ > + NXAST_BUNDLE_LOAD, /* struct nx_action_bundle */ > + NXAST_RESUBMIT_TABLE /* struct nx_action_resubmit */ > }; > > /* Header for Nicira-defined actions. */ > @@ -292,31 +293,51 @@ struct nx_action_header { > }; > OFP_ASSERT(sizeof(struct nx_action_header) == 16); > > -/* Action structure for NXAST_RESUBMIT. > +/* Action structures for NXAST_RESUBMIT and NXAST_RESUBMIT_TABLE. > * > - * NXAST_RESUBMIT searches the flow table again, using a flow that is > slightly > - * modified from the original lookup: > + * These actions search one of the switch's flow tables: > * > - * - The 'in_port' member of struct nx_action_resubmit is used as the > flow's > - * in_port. > + * - For NXAST_RESUBMIT_TABLE only, if the 'table' member is not 255, then > + * it specifies the table to search. > * > - * - If NXAST_RESUBMIT is preceded by actions that affect the flow > - * (e.g. OFPAT_SET_VLAN_VID), then the flow is updated with the new > - * values. > + * - Otherwise (for NXAST_RESUBMIT_TABLE with a 'table' of 255, or for > + * NXAST_RESUBMIT regardless of 'table'), it searches the current flow > + * table, that is, the OpenFlow flow table that contains the flow from > + * which this action was obtained. If this action did not come from a > + * flow table (e.g. it came from an OFPT_PACKET_OUT message), then > table 0 > + * is the current table. > + * > + * The flow table lookup uses a flow that may be slightly modified from the > + * original lookup: > + * > + * - For NXAST_RESUBMIT, the 'in_port' member of struct nx_action_resubmit > + * is used as the flow's in_port. > + * > + * - For NXAST_RESUBMIT_TABLE, if the 'in_port' member is not > OFPP_IN_PORT, > + * then its value is used as the flow's in_port. Otherwise, the > original > + * in_port is used. > + * > + * - If actions that modify the flow (e.g. OFPAT_SET_VLAN_VID) precede the > + * resubmit action, then the flow is updated with the new values. > * > * Following the lookup, the original in_port is restored. > * > * If the modified flow matched in the flow table, then the corresponding > - * actions are executed. Afterward, actions following NXAST_RESUBMIT in the > + * actions are executed. Afterward, actions following the resubmit in the > * original set of actions, if any, are executed; any changes made to the > * packet (e.g. changes to VLAN) by secondary actions persist when those > * actions are executed, although the original in_port is restored. > * > - * NXAST_RESUBMIT may be used any number of times within a set of actions. > + * Resubmit actions may be used any number of times within a set of actions. > + * > + * Resubmit actions may nest to an implementation-defined depth. Beyond this > + * implementation-defined depth, further resubmit actions are simply ignored. > + * > + * NXAST_RESUBMIT ignores 'table' and 'pad'. NXAST_RESUBMIT_TABLE requires > + * 'pad' to be all-bits-zero. > * > - * NXAST_RESUBMIT may nest to an implementation-defined depth. Beyond this > - * implementation-defined depth, further NXAST_RESUBMIT actions are simply > - * ignored. (Open vSwitch 1.0.1 and earlier did not support recursion.) > + * Open vSwitch 1.0.1 and earlier did not support recursion. Open vSwitch > + * before 1.2.90 did not support NXAST_RESUBMIT_TABLE. > */ > struct nx_action_resubmit { > ovs_be16 type; /* OFPAT_VENDOR. */ > @@ -324,7 +345,8 @@ struct nx_action_resubmit { > ovs_be32 vendor; /* NX_VENDOR_ID. */ > ovs_be16 subtype; /* NXAST_RESUBMIT. */ > ovs_be16 in_port; /* New in_port for checking flow table. */ > - uint8_t pad[4]; > + uint8_t table; /* NXAST_RESUBMIT_TABLE: table to use. */ > + uint8_t pad[3]; > }; > OFP_ASSERT(sizeof(struct nx_action_resubmit) == 16); > > diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c > index 58b0da1..c171293 100644 > --- a/lib/ofp-parse.c > +++ b/lib/ofp-parse.c > @@ -285,7 +285,6 @@ put_dl_addr_action(struct ofpbuf *b, uint16_t type, const > char *addr) > str_to_mac(addr, oada->dl_addr); > } > > - > static bool > parse_port_name(const char *name, uint16_t *port) > { > @@ -318,6 +317,40 @@ parse_port_name(const char *name, uint16_t *port) > } > > static void > +parse_resubmit(struct nx_action_resubmit *nar, char *arg) > +{ > + char *in_port_s, *table_s; > + uint16_t in_port; > + uint8_t table; > + > + in_port_s = strsep(&arg, ","); > + if (in_port_s && in_port_s[0]) { > + if (!parse_port_name(in_port_s, &in_port)) { > + in_port = str_to_u32(in_port_s); > + } > + } else { > + in_port = OFPP_IN_PORT; > + } > + > + table_s = strsep(&arg, ","); > + table = table_s && table_s[0] ? str_to_u32(table_s) : 255; > + > + if (in_port == OFPP_IN_PORT && table == 255) { > + ovs_fatal(0, "at least one \"in_port\" or \"table\" must be > specified " > + " on resubmit"); > + } > + > + nar->vendor = htonl(NX_VENDOR_ID); > + nar->in_port = htons(in_port); > + if (in_port != OFPP_IN_PORT && table == 255) { > + nar->subtype = htons(NXAST_RESUBMIT); > + } else { > + nar->subtype = htons(NXAST_RESUBMIT_TABLE); > + nar->table = table; > + } > +} > + > +static void > str_to_action(char *str, struct ofpbuf *b) > { > bool drop = false; > @@ -421,9 +454,7 @@ str_to_action(char *str, struct ofpbuf *b) > } else if (!strcasecmp(act, "resubmit")) { > struct nx_action_resubmit *nar; > nar = put_action(b, sizeof *nar, OFPAT_VENDOR); > - nar->vendor = htonl(NX_VENDOR_ID); > - nar->subtype = htons(NXAST_RESUBMIT); > - nar->in_port = htons(str_to_u32(arg)); > + parse_resubmit(nar, arg); > } else if (!strcasecmp(act, "set_tunnel") > || !strcasecmp(act, "set_tunnel64")) { > uint64_t tun_id = str_to_u64(arg); > diff --git a/lib/ofp-print.c b/lib/ofp-print.c > index 0265f30..9311c14 100644 > --- a/lib/ofp-print.c > +++ b/lib/ofp-print.c > @@ -295,6 +295,19 @@ ofp_print_action(struct ds *s, const union ofp_action *a, > ofp_print_port_name(s, ntohs(nar->in_port)); > break; > > + case OFPUTIL_NXAST_RESUBMIT_TABLE: > + nar = (struct nx_action_resubmit *)a; > + ds_put_format(s, "resubmit("); > + if (nar->in_port != htons(OFPP_IN_PORT)) { > + ofp_print_port_name(s, ntohs(nar->in_port)); > + } > + ds_put_char(s, ','); > + if (nar->table != 255) { > + ds_put_format(s, "%"PRIu8, nar->table); > + } > + ds_put_char(s, ')'); > + break; > + > case OFPUTIL_NXAST_SET_TUNNEL: > nast = (struct nx_action_set_tunnel *)a; > ds_put_format(s, "set_tunnel:%#"PRIx32, ntohl(nast->tun_id)); > diff --git a/lib/ofp-util.c b/lib/ofp-util.c > index df3377a..fdd61fb 100644 > --- a/lib/ofp-util.c > +++ b/lib/ofp-util.c > @@ -1966,6 +1966,15 @@ ofputil_check_output_port(uint16_t port, int max_ports) > } > } > > +static int > +check_resubmit_table(const struct nx_action_resubmit *nar) > +{ > + if (nar->pad[0] || nar->pad[1] || nar->pad[2]) { > + return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT); > + } > + return 0; > +} > + > int > validate_actions(const union ofp_action *actions, size_t n_actions, > const struct flow *flow, int max_ports) > @@ -2044,6 +2053,11 @@ validate_actions(const union ofp_action *actions, > size_t n_actions, > max_ports, flow); > break; > > + case OFPUTIL_NXAST_RESUBMIT_TABLE: > + error = check_resubmit_table( > + (const struct nx_action_resubmit *) a); > + break; > + > case OFPUTIL_OFPAT_STRIP_VLAN: > case OFPUTIL_OFPAT_SET_NW_SRC: > case OFPUTIL_OFPAT_SET_NW_DST: > @@ -2118,6 +2132,7 @@ static const struct ofputil_nxast_action > nxast_actions[] = { > { OFPUTIL_NXAST_AUTOPATH, 24, 24 }, > { OFPUTIL_NXAST_BUNDLE, 32, UINT_MAX }, > { OFPUTIL_NXAST_BUNDLE_LOAD, 32, UINT_MAX }, > + { OFPUTIL_NXAST_RESUBMIT_TABLE, 16, 16 }, > }; > > static int > diff --git a/lib/ofp-util.h b/lib/ofp-util.h > index 7ee3e69..a473364 100644 > --- a/lib/ofp-util.h > +++ b/lib/ofp-util.h > @@ -304,6 +304,7 @@ enum ofputil_action_code { > OFPUTIL_NXAST_AUTOPATH, > OFPUTIL_NXAST_BUNDLE, > OFPUTIL_NXAST_BUNDLE_LOAD, > + OFPUTIL_NXAST_RESUBMIT_TABLE > }; > > int ofputil_decode_action(const union ofp_action *); > diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c > index 1ec7dc2..1b5854e 100644 > --- a/ofproto/ofproto-dpif.c > +++ b/ofproto/ofproto-dpif.c > @@ -60,7 +60,7 @@ COVERAGE_DEFINE(facet_invalidated); > COVERAGE_DEFINE(facet_revalidate); > COVERAGE_DEFINE(facet_unexpected); > > -/* Maximum depth of flow table recursion (due to NXAST_RESUBMIT actions) in a > +/* Maximum depth of flow table recursion (due to resubmit actions) in a > * flow translation. */ > #define MAX_RESUBMIT_RECURSION 16 > > @@ -96,8 +96,8 @@ static struct rule_dpif *rule_dpif_cast(const struct rule > *rule) > return rule ? CONTAINER_OF(rule, struct rule_dpif, up) : NULL; > } > > -static struct rule_dpif *rule_dpif_lookup(struct ofproto_dpif *ofproto, > - const struct flow *flow); > +static struct rule_dpif *rule_dpif_lookup(struct ofproto_dpif *, > + const struct flow *, uint8_t > table); > > #define MAX_MIRRORS 32 > typedef uint32_t mirror_mask_t; > @@ -188,6 +188,7 @@ struct action_xlate_ctx { > uint32_t priority; /* Current flow priority. 0 if none. */ > struct flow base_flow; /* Flow at the last commit. */ > uint32_t base_priority; /* Priority at the last commit. */ > + uint8_t table_id; /* OpenFlow table ID where flow was found. */ > }; > > static void action_xlate_ctx_init(struct action_xlate_ctx *, > @@ -1654,7 +1655,7 @@ handle_miss_upcall(struct ofproto_dpif *ofproto, struct > dpif_upcall *upcall) > > facet = facet_lookup_valid(ofproto, &flow); > if (!facet) { > - struct rule_dpif *rule = rule_dpif_lookup(ofproto, &flow); > + struct rule_dpif *rule = rule_dpif_lookup(ofproto, &flow, 0); > if (!rule) { > /* Don't send a packet-in if OFPPC_NO_PACKET_IN asserted. */ > struct ofport_dpif *port = get_ofp_port(ofproto, flow.in_port); > @@ -2434,7 +2435,7 @@ facet_revalidate(struct ofproto_dpif *ofproto, struct > facet *facet) > COVERAGE_INC(facet_revalidate); > > /* Determine the new rule. */ > - new_rule = rule_dpif_lookup(ofproto, &facet->flow); > + new_rule = rule_dpif_lookup(ofproto, &facet->flow, 0); > if (!new_rule) { > /* No new rule, so delete the facet. */ > facet_remove(ofproto, facet); > @@ -2592,10 +2593,11 @@ flow_push_stats(const struct rule_dpif *rule, > /* Rules. */ > > static struct rule_dpif * > -rule_dpif_lookup(struct ofproto_dpif *ofproto, const struct flow *flow) > +rule_dpif_lookup(struct ofproto_dpif *ofproto, const struct flow *flow, > + uint8_t table_id) > { > return rule_dpif_cast(rule_from_cls_rule( > - classifier_lookup(&ofproto->up.tables[0], > + > classifier_lookup(&ofproto->up.tables[table_id], > flow))); > } > > @@ -2717,7 +2719,7 @@ rule_execute(struct rule *rule_, struct flow *flow, > struct ofpbuf *packet) > > /* Otherwise, if 'rule' is in fact the correct rule for 'packet', then > * create a new facet for it and use that. */ > - if (rule_dpif_lookup(ofproto, flow) == rule) { > + if (rule_dpif_lookup(ofproto, flow, 0) == rule) { > facet = facet_create(rule, flow, packet); > facet_execute(ofproto, facet, packet); > facet_install(ofproto, facet, true); > @@ -2889,18 +2891,23 @@ add_output_action(struct action_xlate_ctx *ctx, > uint16_t ofp_port) > } > > static void > -xlate_table_action(struct action_xlate_ctx *ctx, uint16_t in_port) > +xlate_table_action(struct action_xlate_ctx *ctx, > + uint16_t in_port, uint8_t table_id) > { > if (ctx->recurse < MAX_RESUBMIT_RECURSION) { > struct rule_dpif *rule; > uint16_t old_in_port; > + uint8_t old_table_id; > + > + old_table_id = ctx->table_id; > + ctx->table_id = table_id; > > /* Look up a flow with 'in_port' as the input port. Then restore the > * original input port (otherwise OFPP_NORMAL and OFPP_IN_PORT will > * have surprising behavior). */ > old_in_port = ctx->flow.in_port; > ctx->flow.in_port = in_port; > - rule = rule_dpif_lookup(ctx->ofproto, &ctx->flow); > + rule = rule_dpif_lookup(ctx->ofproto, &ctx->flow, table_id); > ctx->flow.in_port = old_in_port; > > if (ctx->resubmit_hook) { > @@ -2912,15 +2919,32 @@ xlate_table_action(struct action_xlate_ctx *ctx, > uint16_t in_port) > do_xlate_actions(rule->up.actions, rule->up.n_actions, ctx); > ctx->recurse--; > } > + > + ctx->table_id = old_table_id; > } else { > static struct vlog_rate_limit recurse_rl = VLOG_RATE_LIMIT_INIT(1, 1); > > - VLOG_ERR_RL(&recurse_rl, "NXAST_RESUBMIT recursed over %d times", > + VLOG_ERR_RL(&recurse_rl, "resubmit actions recursed over %d times", > MAX_RESUBMIT_RECURSION); > } > } > > static void > +xlate_resubmit_table(struct action_xlate_ctx *ctx, > + const struct nx_action_resubmit *nar) > +{ > + uint16_t in_port; > + uint8_t table_id; > + > + in_port = (nar->in_port == htons(OFPP_IN_PORT) > + ? ctx->flow.in_port > + : ntohs(nar->in_port)); > + table_id = nar->table == 255 ? ctx->table_id : nar->table; > + > + xlate_table_action(ctx, in_port, table_id); > +} > + > +static void > flood_packets(struct action_xlate_ctx *ctx, ovs_be32 mask) > { > struct ofport_dpif *ofport; > @@ -2950,7 +2974,7 @@ xlate_output_action__(struct action_xlate_ctx *ctx, > add_output_action(ctx, ctx->flow.in_port); > break; > case OFPP_TABLE: > - xlate_table_action(ctx, ctx->flow.in_port); > + xlate_table_action(ctx, ctx->flow.in_port, ctx->table_id); > break; > case OFPP_NORMAL: > xlate_normal(ctx); > @@ -3182,7 +3206,11 @@ do_xlate_actions(const union ofp_action *in, size_t > n_in, > > case OFPUTIL_NXAST_RESUBMIT: > nar = (const struct nx_action_resubmit *) ia; > - xlate_table_action(ctx, ntohs(nar->in_port)); > + xlate_table_action(ctx, ntohs(nar->in_port), ctx->table_id); > + break; > + > + case OFPUTIL_NXAST_RESUBMIT_TABLE: > + xlate_resubmit_table(ctx, (const struct nx_action_resubmit *) > ia); > break; > > case OFPUTIL_NXAST_SET_TUNNEL: > @@ -3272,6 +3300,7 @@ xlate_actions(struct action_xlate_ctx *ctx, > ctx->priority = 0; > ctx->base_priority = 0; > ctx->base_flow = ctx->flow; > + ctx->table_id = 0; > > if (process_special(ctx->ofproto, &ctx->flow, ctx->packet)) { > ctx->may_set_up_flow = false; > @@ -3925,7 +3954,8 @@ struct ofproto_trace { > }; > > static void > -trace_format_rule(struct ds *result, int level, const struct rule *rule) > +trace_format_rule(struct ds *result, uint8_t table_id, int level, > + const struct rule *rule) > { > ds_put_char_multiple(result, '\t', level); > if (!rule) { > @@ -3933,8 +3963,8 @@ trace_format_rule(struct ds *result, int level, const > struct rule *rule) > return; > } > > - ds_put_format(result, "Rule: cookie=%#"PRIx64" ", > - ntohll(rule->flow_cookie)); > + ds_put_format(result, "Rule: table=%"PRIu8" cookie=%#"PRIx64" ", > + table_id, ntohll(rule->flow_cookie)); > cls_rule_format(&rule->cr, result); > ds_put_char(result, '\n'); > > @@ -3967,7 +3997,7 @@ trace_resubmit(struct action_xlate_ctx *ctx, struct > rule_dpif *rule) > > ds_put_char(result, '\n'); > trace_format_flow(result, ctx->recurse + 1, "Resubmitted flow", trace); > - trace_format_rule(result, ctx->recurse + 1, &rule->up); > + trace_format_rule(result, ctx->table_id, ctx->recurse + 1, &rule->up); > } > > static void > @@ -4054,8 +4084,8 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, const > char *args_, > flow_format(&result, &flow); > ds_put_char(&result, '\n'); > > - rule = rule_dpif_lookup(ofproto, &flow); > - trace_format_rule(&result, 0, &rule->up); > + rule = rule_dpif_lookup(ofproto, &flow, 0); > + trace_format_rule(&result, 0, 0, &rule->up); > if (rule) { > struct ofproto_trace trace; > struct ofpbuf *odp_actions; > diff --git a/tests/automake.mk b/tests/automake.mk > index eb6351f..28b4e1d 100644 > --- a/tests/automake.mk > +++ b/tests/automake.mk > @@ -28,6 +28,7 @@ TESTSUITE_AT = \ > tests/timeval.at \ > tests/lockfile.at \ > tests/reconnect.at \ > + tests/ofproto-dpif.at \ > tests/ofproto-macros.at \ > tests/ofproto.at \ > tests/ovsdb.at \ > diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at > new file mode 100644 > index 0000000..846eccb > --- /dev/null > +++ b/tests/ofproto-dpif.at > @@ -0,0 +1,19 @@ > +AT_BANNER([ofproto-dpif]) > + > +AT_SETUP([ofproto-dpif - resubmit]) > +OFPROTO_START > +AT_DATA([flows.txt], [dnl > +table=0 in_port=1 priority=1000 icmp > actions=output(10),resubmit(2),output(19),resubmit(3),output(21) > +table=0 in_port=2 priority=1500 icmp > actions=output(11),resubmit(,1),output(16),resubmit(2,1),output(18) > +table=0 in_port=3 priority=2000 icmp actions=output(20) > +table=1 in_port=1 priority=1000 icmp > actions=output(12),resubmit(4,1),output(13),resubmit(3),output(15) > +table=1 in_port=2 priority=1500 icmp actions=output(17),resubmit(,2) > +table=1 in_port=3 priority=1500 icmp actions=output(14),resubmit(,2) > +]) > +AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) > +AT_CHECK([ovs-appctl -t test-openflowd ofproto/trace br0 > 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0),icmp(type=8,code=0)'], > [0], [stdout]) > +AT_CHECK([tail -1 stdout], [0], > + [Datapath actions: 10,11,12,13,14,15,16,17,18,19,20,21 > +]) > +OFPROTO_STOP > +AT_CLEANUP > diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at > index 20dcc90..1edfb62 100644 > --- a/tests/ovs-ofctl.at > +++ b/tests/ovs-ofctl.at > @@ -23,7 +23,9 @@ > actions=bundle_load(eth_src,50,active_backup,ofport,NXM_NX_REG0[],slaves:1) > actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..15],slaves:2,3) > actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..30],slaves:) > actions=output:1,bundle_load(eth_src,0,hrw,ofport,NXM_NX_REG0[16..31],slaves:1),output:2 > +actions=resubmit:1,resubmit(2),resubmit(,3),resubmit(2,3) > ]]) > + > AT_CHECK([ovs-ofctl parse-flows flows.txt > ], [0], [stdout]) > AT_CHECK([[sed 's/ (xid=0x[0-9a-fA-F]*)//' stdout]], [0], > @@ -49,6 +51,7 @@ NXT_FLOW_MOD: ADD table:255 > actions=bundle_load(eth_src,50,active_backup,ofport, > NXT_FLOW_MOD: ADD table:255 > actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..15],slaves:2,3) > NXT_FLOW_MOD: ADD table:255 > actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..30],slaves:) > NXT_FLOW_MOD: ADD table:255 > actions=output:1,bundle_load(eth_src,0,hrw,ofport,NXM_NX_REG0[16..31],slaves:1),output:2 > +NXT_FLOW_MOD: ADD table:255 > actions=resubmit:1,resubmit:2,resubmit(,3),resubmit(2,3) > ]]) > AT_CLEANUP > > diff --git a/tests/testsuite.at b/tests/testsuite.at > index c22ece7..b394cb6 100644 > --- a/tests/testsuite.at > +++ b/tests/testsuite.at > @@ -60,6 +60,7 @@ m4_include([tests/timeval.at]) > m4_include([tests/lockfile.at]) > m4_include([tests/reconnect.at]) > m4_include([tests/ofproto.at]) > +m4_include([tests/ofproto-dpif.at]) > m4_include([tests/ovsdb.at]) > m4_include([tests/ovs-vsctl.at]) > m4_include([tests/interface-reconfigure.at]) > diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in > index c59bca9..aa37969 100644 > --- a/utilities/ovs-ofctl.8.in > +++ b/utilities/ovs-ofctl.8.in > @@ -655,10 +655,16 @@ only known to be implemented by Open vSwitch: > .RS > . > .IP \fBresubmit\fB:\fIport\fR > -Re-searches the OpenFlow flow table with the \fBin_port\fR field > -replaced by \fIport\fR and executes the actions found, if any, in > -addition to any other actions in this flow entry. Recursive > -\fBresubmit\fR actions are ignored. > +.IQ \fBresubmit\fB(\fR[\fIport\fR]\fB,\fR[\fItable\fR]\fB) > +Re-searches this OpenFlow flow table (or the table whose number is > +specified by \fItable\fR) with the \fBin_port\fR field replaced by > +\fIport\fR (if \fIport\fR is specified) and executes the actions > +found, if any, in addition to any other actions in this flow entry. > +.IP > +Recursive \fBresubmit\fR actions are obeyed up to an > +implementation-defined maximum depth. Open vSwitch 1.0.1 and earlier > +did not support recursion; Open vSwitch before 1.2.90 did not support > +\fItable\fR. > . > .IP \fBset_tunnel\fB:\fIid\fR > .IQ \fBset_tunnel64\fB:\fIid\fR > -- > 1.7.4.4 > > _______________________________________________ > dev mailing list > [email protected] > http://openvswitch.org/mailman/listinfo/dev > _______________________________________________ dev mailing list [email protected] http://openvswitch.org/mailman/listinfo/dev
