> I decided to further add:
>
>        Tables 128 and above are reserved for use by the switch
>        itself; please use only tables 0 through 127.
>
> I'd like to document this somewhere else in the tree but it's not
> clear where.

Are we planning to enforce this?

Ethan



>
> On Tue, Aug 09, 2011 at 09:22:29AM -0700, Ben Pfaff wrote:
>> Good idea.  I added:
>>
>>     - ovs-vswitchd:
>>       - The software switch now supports 255 OpenFlow tables, instead
>>         of just one.  By default, only table 0 is consulted, but the
>>         new NXAST_RESUBMIT_TABLE action can look up in additional
>>         tables.
>>
>> I'll push this soon.
>>
>> On Mon, Aug 08, 2011 at 05:25:59PM -0700, Ethan Jackson wrote:
>> > Looks good,
>> >
>> > May want to update NEWS for this series.
>> > Ethan
>> >
>> > On Thu, Aug 4, 2011 at 16:29, Ben Pfaff <b...@nicira.com> 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
>> > > dev@openvswitch.org
>> > > http://openvswitch.org/mailman/listinfo/dev
>> > >
>
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to