I decided that it was minor enough (a bug in ofproto/trace) to just
push the series and then send out another series with the bug fix:
        http://openvswitch.org/pipermail/dev/2014-November/048173.html
        http://openvswitch.org/pipermail/dev/2014-November/048175.html
        http://openvswitch.org/pipermail/dev/2014-November/048176.html

Thanks,

Ben.

On Mon, Nov 03, 2014 at 02:21:30PM -0800, Ben Pfaff wrote:
> Thanks.  I'll fold those in.
> 
> Jean Tourrilhes pointed out a possible bug in this patch, in the ONF
> JIRA for EXT-233.  I'm going to look at that before I apply this.
> 
> On Thu, Oct 30, 2014 at 04:06:40PM -0700, Jarno Rajahalme wrote:
> > With the following changes (some due to master changing in the meanwhile):
> > 
> > Acked-by: Jarno Rajahalme <jrajaha...@nicira.com>
> > 
> > ---
> >  lib/flow.c |    9 ++++++---
> >  lib/flow.h |    1 +
> >  2 files changed, 7 insertions(+), 3 deletions(-)
> > 
> > diff --git a/lib/flow.c b/lib/flow.c
> > index ecd580a..a742e23 100644
> > --- a/lib/flow.c
> > +++ b/lib/flow.c
> > @@ -815,7 +815,7 @@ void flow_wildcards_init_for_packet(struct 
> > flow_wildcards *wc,
> >      memset(&wc->masks, 0x0, sizeof wc->masks);
> >  
> >      /* Update this function whenever struct flow changes. */
> > -    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 27);
> > +    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 28);
> >  
> >      if (flow->tunnel.ip_dst) {
> >          if (flow->tunnel.flags & FLOW_TNL_F_KEY) {
> > @@ -840,6 +840,8 @@ void flow_wildcards_init_for_packet(struct 
> > flow_wildcards *wc,
> >      WC_MASK_FIELD(wc, dp_hash);
> >      WC_MASK_FIELD(wc, in_port);
> >  
> > +    /* actset_output wildcarded. */
> > +
> >      WC_MASK_FIELD(wc, dl_dst);
> >      WC_MASK_FIELD(wc, dl_src);
> >      WC_MASK_FIELD(wc, dl_type);
> > @@ -910,7 +912,7 @@ uint64_t
> >  flow_wc_map(const struct flow *flow)
> >  {
> >      /* Update this function whenever struct flow changes. */
> > -    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 27);
> > +    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 28);
> >  
> >      uint64_t map = (flow->tunnel.ip_dst) ? MINIFLOW_MAP(tunnel) : 0;
> >  
> > @@ -962,10 +964,11 @@ void
> >  flow_wildcards_clear_non_packet_fields(struct flow_wildcards *wc)
> >  {
> >      /* Update this function whenever struct flow changes. */
> > -    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 27);
> > +    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 28);
> >  
> >      memset(&wc->masks.metadata, 0, sizeof wc->masks.metadata);
> >      memset(&wc->masks.regs, 0, sizeof wc->masks.regs);
> > +    memset(&wc->masks.actset_output, 0, sizeof wc->masks.actset_output);
> >  }
> >  
> >  /* Returns true if 'wc' matches every packet, false if 'wc' fixes any bits 
> > or
> > diff --git a/lib/flow.h b/lib/flow.h
> > index 891355a..2259680 100644
> > --- a/lib/flow.h
> > +++ b/lib/flow.h
> > @@ -146,6 +146,7 @@ BUILD_ASSERT_DECL(sizeof(struct flow) % 4 == 0);
> >  #define FLOW_MAX_PACKET_U32S (FLOW_U32S                                   \
> >      /* Unused in datapath */  - FLOW_U32_SIZE(regs)                       \
> >                                - FLOW_U32_SIZE(metadata)                   \
> > +                              - FLOW_U32_SIZE(actset_output)              \
> >      /* L2.5/3 */              - FLOW_U32_SIZE(nw_src)                     \
> >                                - FLOW_U32_SIZE(nw_dst)                     \
> >                                - FLOW_U32_SIZE(mpls_lse)                   \
> > 
> > 
> > On Oct 9, 2014, at 11:10 PM, Ben Pfaff <b...@nicira.com> wrote:
> > 
> > > This field allows a flow table to match on the output port currently in 
> > > the
> > > action set.
> > > 
> > > ONF-JIRA: EXT-233
> > > Signed-off-by: Ben Pfaff <b...@nicira.com>
> > > Acked-by: Jarno Rajahalme <jrajaha...@nicira.com>
> > > ---
> > > NEWS                            |  1 +
> > > build-aux/extract-ofp-fields    |  1 +
> > > include/openflow/openflow-1.0.h |  7 ++++---
> > > lib/flow.c                      | 10 +++++-----
> > > lib/flow.h                      | 10 ++++++----
> > > lib/match.c                     | 15 ++++++++++++++-
> > > lib/match.h                     |  1 +
> > > lib/meta-flow.c                 | 29 +++++++++++++++++++++++------
> > > lib/meta-flow.h                 | 13 +++++++++++++
> > > lib/nx-match.c                  |  6 +++++-
> > > lib/odp-util.h                  |  2 +-
> > > lib/ofp-util.c                  |  5 +++--
> > > ofproto/ofproto-dpif-xlate.c    | 36 +++++++++++++++++++++++++++++++++---
> > > tests/ofproto-dpif.at           | 40 
> > > ++++++++++++++++++++++++++++++++++++++++
> > > tests/ofproto.at                |  3 ++-
> > > tests/ovs-ofctl.at              | 41 
> > > ++++++++++++++++++++++++++++++++++++++++-
> > > utilities/ovs-ofctl.8.in        | 10 ++++++++++
> > > 17 files changed, 202 insertions(+), 28 deletions(-)
> > > 
> > > diff --git a/NEWS b/NEWS
> > > index 3307754..56d7a9f 100644
> > > --- a/NEWS
> > > +++ b/NEWS
> > > @@ -14,6 +14,7 @@ Post-v2.3.0
> > >      release.  See ovs-vswitchd(8) for details.
> > >    - OpenFlow:
> > >      * OpenFlow 1.5 (draft) extended registers are now supported.
> > > +     * The OpenFlow 1.5 (draft) actset_output field is now supported.
> > >      * OpenFlow 1.5 (draft) Copy-Field action is now supported.
> > >      * OpenFlow 1.5 (draft) masked Set-Field action is now supported.
> > >      * OpenFlow 1.3+ table features requests are now supported 
> > > (read-only).
> > > diff --git a/build-aux/extract-ofp-fields b/build-aux/extract-ofp-fields
> > > index bdbba75..b15b01d 100755
> > > --- a/build-aux/extract-ofp-fields
> > > +++ b/build-aux/extract-ofp-fields
> > > @@ -59,6 +59,7 @@ OXM_CLASSES = {"NXM_OF_":        (0,          0x0000),
> > >                "NXM_NX_":        (0,          0x0001),
> > >                "OXM_OF_":        (0,          0x8000),
> > >                "OXM_OF_PKT_REG": (0,          0x8001),
> > > +               "ONFOXM_ET_":     (0x4f4e4600, 0xffff),
> > > 
> > >                # This is the experimenter OXM class for Nicira, which is 
> > > the
> > >                # one that OVS would be using instead of NXM_OF_ and 
> > > NXM_NX_
> > > diff --git a/include/openflow/openflow-1.0.h 
> > > b/include/openflow/openflow-1.0.h
> > > index c67edd9..22c4be2 100644
> > > --- a/include/openflow/openflow-1.0.h
> > > +++ b/include/openflow/openflow-1.0.h
> > > @@ -25,16 +25,17 @@
> > >  * ---------------  --------------------------------------
> > >  * 0x0000           not assigned a meaning by OpenFlow 1.0
> > >  * 0x0001...0xfeff  "physical" ports
> > > - * 0xff00...0xfff7  "reserved" but not assigned a meaning by OpenFlow 1.0
> > > - * 0xfff8...0xffff  "reserved" OFPP_* ports with assigned meanings
> > > + * 0xff00...0xfff6  "reserved" but not assigned a meaning by OpenFlow 1.x
> > > + * 0xfff7...0xffff  "reserved" OFPP_* ports with assigned meanings
> > >  */
> > > 
> > > /* Ranges. */
> > > #define OFPP_MAX        OFP_PORT_C(0xff00) /* Max # of switch ports. */
> > > -#define OFPP_FIRST_RESV OFP_PORT_C(0xfff8) /* First assigned reserved 
> > > port. */
> > > +#define OFPP_FIRST_RESV OFP_PORT_C(0xfff7) /* First assigned reserved 
> > > port. */
> > > #define OFPP_LAST_RESV  OFP_PORT_C(0xffff) /* Last assigned reserved 
> > > port. */
> > > 
> > > /* Reserved output "ports". */
> > > +#define OFPP_UNSET      OFP_PORT_C(0xfff7) /* For OXM_OF_ACTSET_OUTPUT 
> > > only. */
> > > #define OFPP_IN_PORT    OFP_PORT_C(0xfff8) /* Where the packet came in. */
> > > #define OFPP_TABLE      OFP_PORT_C(0xfff9) /* Perform actions in flow 
> > > table. */
> > > #define OFPP_NORMAL     OFP_PORT_C(0xfffa) /* Process with normal L2/L3. 
> > > */
> > > diff --git a/lib/flow.c b/lib/flow.c
> > > index 7fb53de..dce0497 100644
> > > --- a/lib/flow.c
> > > +++ b/lib/flow.c
> > > @@ -72,9 +72,9 @@ BUILD_ASSERT_DECL(offsetof(struct flow, nw_frag) + 3
> > > 
> > > /* TCP flags in the first half of a BE32, zeroes in the other half. */
> > > BUILD_ASSERT_DECL(offsetof(struct flow, tcp_flags) + 2
> > > -                  == offsetof(struct flow, pad) &&
> > > +                  == offsetof(struct flow, pad2) &&
> > >                   offsetof(struct flow, tcp_flags) / 4
> > > -                  == offsetof(struct flow, pad) / 4);
> > > +                  == offsetof(struct flow, pad2) / 4);
> > > #if WORDS_BIGENDIAN
> > > #define TCP_FLAGS_BE32(tcp_ctl) ((OVS_FORCE 
> > > ovs_be32)TCP_FLAGS_BE16(tcp_ctl) \
> > >                                  << 16)
> > > @@ -121,7 +121,7 @@ struct mf_ctx {
> > >  * away.  Some GCC versions gave warnings on ALWAYS_INLINE, so these are
> > >  * defined as macros. */
> > > 
> > > -#if (FLOW_WC_SEQ != 27)
> > > +#if (FLOW_WC_SEQ != 28)
> > > #define MINIFLOW_ASSERT(X) ovs_assert(X)
> > > BUILD_MESSAGE("FLOW_WC_SEQ changed: miniflow_extract() will have runtime "
> > >                "assertions enabled. Consider updating FLOW_WC_SEQ after "
> > > @@ -668,7 +668,7 @@ flow_unwildcard_tp_ports(const struct flow *flow, 
> > > struct flow_wildcards *wc)
> > > void
> > > flow_get_metadata(const struct flow *flow, struct flow_metadata *fmd)
> > > {
> > > -    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 27);
> > > +    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 28);
> > > 
> > >     fmd->dp_hash = flow->dp_hash;
> > >     fmd->recirc_id = flow->recirc_id;
> > > @@ -1458,7 +1458,7 @@ flow_push_mpls(struct flow *flow, int n, ovs_be16 
> > > mpls_eth_type,
> > >         flow->mpls_lse[0] = set_mpls_lse_values(ttl, tc, 1, htonl(label));
> > > 
> > >         /* Clear all L3 and L4 fields. */
> > > -        BUILD_ASSERT(FLOW_WC_SEQ == 27);
> > > +        BUILD_ASSERT(FLOW_WC_SEQ == 28);
> > >         memset((char *) flow + FLOW_SEGMENT_2_ENDS_AT, 0,
> > >                sizeof(struct flow) - FLOW_SEGMENT_2_ENDS_AT);
> > >     }
> > > diff --git a/lib/flow.h b/lib/flow.h
> > > index 2b053da..e4bee42 100644
> > > --- a/lib/flow.h
> > > +++ b/lib/flow.h
> > > @@ -38,7 +38,7 @@ struct pkt_metadata;
> > > /* This sequence number should be incremented whenever anything involving 
> > > flows
> > >  * or the wildcarding of flows changes.  This will cause build assertion
> > >  * failures in places which likely need to be updated. */
> > > -#define FLOW_WC_SEQ 27
> > > +#define FLOW_WC_SEQ 28
> > > 
> > > /* Number of Open vSwitch extension 32-bit registers. */
> > > #define FLOW_N_REGS 8
> > > @@ -102,6 +102,8 @@ struct flow {
> > >     uint32_t pkt_mark;          /* Packet mark. */
> > >     uint32_t recirc_id;         /* Must be exact match. */
> > >     union flow_in_port in_port; /* Input port.*/
> > > +    ofp_port_t actset_output;   /* Output port in action set. */
> > > +    ovs_be16 pad1;              /* Pad to 32 bits. */
> > > 
> > >     /* L2, Order the same as in the Ethernet header! */
> > >     uint8_t dl_dst[6];          /* Ethernet destination address. */
> > > @@ -124,7 +126,7 @@ struct flow {
> > >     uint8_t arp_tha[6];         /* ARP/ND target hardware address. */
> > >     struct in6_addr nd_target;  /* IPv6 neighbor discovery (ND) target. */
> > >     ovs_be16 tcp_flags;         /* TCP flags. With L3 to avoid matching 
> > > L4. */
> > > -    ovs_be16 pad;               /* Padding. */
> > > +    ovs_be16 pad2;              /* Pad to 32 bits. */
> > > 
> > >     /* L4 */
> > >     ovs_be16 tp_src;            /* TCP/UDP/SCTP source port. */
> > > @@ -153,8 +155,8 @@ BUILD_ASSERT_DECL(sizeof(struct flow) % 4 == 0);
> > > 
> > > /* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */
> > > BUILD_ASSERT_DECL(offsetof(struct flow, dp_hash) + sizeof(uint32_t)
> > > -                  == sizeof(struct flow_tnl) + 176
> > > -                  && FLOW_WC_SEQ == 27);
> > > +                  == sizeof(struct flow_tnl) + 180
> > > +                  && FLOW_WC_SEQ == 28);
> > > 
> > > /* Incremental points at which flow classification may be performed in
> > >  * segments.
> > > diff --git a/lib/match.c b/lib/match.c
> > > index 0eb11f0..73e0404 100644
> > > --- a/lib/match.c
> > > +++ b/lib/match.c
> > > @@ -119,6 +119,13 @@ match_set_xreg_masked(struct match *match, unsigned 
> > > int xreg_idx,
> > > }
> > > 
> > > void
> > > +match_set_actset_output(struct match *match, ofp_port_t actset_output)
> > > +{
> > > +    match->wc.masks.actset_output = u16_to_ofp(UINT16_MAX);
> > > +    match->flow.actset_output = actset_output;
> > > +}
> > > +
> > > +void
> > > match_set_metadata(struct match *match, ovs_be64 metadata)
> > > {
> > >     match_set_metadata_masked(match, metadata, OVS_BE64_MAX);
> > > @@ -862,7 +869,7 @@ match_format(const struct match *match, struct ds *s, 
> > > unsigned int priority)
> > > 
> > >     int i;
> > > 
> > > -    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 27);
> > > +    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 28);
> > > 
> > >     if (priority != OFP_DEFAULT_PRIORITY) {
> > >         ds_put_format(s, "priority=%u,", priority);
> > > @@ -884,6 +891,12 @@ match_format(const struct match *match, struct ds 
> > > *s, unsigned int priority)
> > >         ds_put_format(s, "skb_priority=%#"PRIx32",", f->skb_priority);
> > >     }
> > > 
> > > +    if (wc->masks.actset_output) {
> > > +        ds_put_cstr(s, "actset_output=");
> > > +        ofputil_format_port(f->actset_output, s);
> > > +        ds_put_char(s, ',');
> > > +    }
> > > +
> > >     if (wc->masks.dl_type) {
> > >         skip_type = true;
> > >         if (f->dl_type == htons(ETH_TYPE_IP)) {
> > > diff --git a/lib/match.h b/lib/match.h
> > > index ce9fb28..5c0ea55 100644
> > > --- a/lib/match.h
> > > +++ b/lib/match.h
> > > @@ -53,6 +53,7 @@ void match_set_reg_masked(struct match *, unsigned int 
> > > reg_idx,
> > > void match_set_xreg(struct match *, unsigned int xreg_idx, uint64_t 
> > > value);
> > > void match_set_xreg_masked(struct match *, unsigned int xreg_idx,
> > >                            uint64_t value, uint64_t mask);
> > > +void match_set_actset_output(struct match *, ofp_port_t actset_output);
> > > void match_set_metadata(struct match *, ovs_be64 metadata);
> > > void match_set_metadata_masked(struct match *,
> > >                                ovs_be64 metadata, ovs_be64 mask);
> > > diff --git a/lib/meta-flow.c b/lib/meta-flow.c
> > > index 7871545..ddf0431 100644
> > > --- a/lib/meta-flow.c
> > > +++ b/lib/meta-flow.c
> > > @@ -129,6 +129,8 @@ mf_is_all_wild(const struct mf_field *mf, const 
> > > struct flow_wildcards *wc)
> > >         return !wc->masks.regs[mf->id - MFF_REG0];
> > >     CASE_MFF_XREGS:
> > >         return !flow_get_xreg(&wc->masks, mf->id - MFF_XREG0);
> > > +    case MFF_ACTSET_OUTPUT:
> > > +        return !wc->masks.actset_output;
> > > 
> > >     case MFF_ETH_SRC:
> > >         return eth_addr_is_zero(wc->masks.dl_src);
> > > @@ -397,7 +399,8 @@ mf_is_value_valid(const struct mf_field *mf, const 
> > > union mf_value *value)
> > >     case MFF_ND_TLL:
> > >         return true;
> > > 
> > > -    case MFF_IN_PORT_OXM: {
> > > +    case MFF_IN_PORT_OXM:
> > > +    case MFF_ACTSET_OUTPUT: {
> > >         ofp_port_t port;
> > >         return !ofputil_port_from_ofp11(value->be32, &port);
> > >     }
> > > @@ -485,6 +488,9 @@ mf_get_value(const struct mf_field *mf, const struct 
> > > flow *flow,
> > >     case MFF_IN_PORT_OXM:
> > >         value->be32 = ofputil_port_to_ofp11(flow->in_port.ofp_port);
> > >         break;
> > > +    case MFF_ACTSET_OUTPUT:
> > > +        value->be32 = ofputil_port_to_ofp11(flow->actset_output);
> > > +        break;
> > > 
> > >     case MFF_SKB_PRIORITY:
> > >         value->be32 = htonl(flow->skb_priority);
> > > @@ -691,6 +697,12 @@ mf_set_value(const struct mf_field *mf,
> > >         match_set_in_port(match, port);
> > >         break;
> > >     }
> > > +    case MFF_ACTSET_OUTPUT: {
> > > +        ofp_port_t port;
> > > +        ofputil_port_from_ofp11(value->be32, &port);
> > > +        match_set_actset_output(match, port);
> > > +        break;
> > > +    }
> > > 
> > >     case MFF_SKB_PRIORITY:
> > >         match_set_skb_priority(match, ntohl(value->be32));
> > > @@ -908,12 +920,12 @@ mf_set_flow_value(const struct mf_field *mf,
> > >         flow->in_port.ofp_port = u16_to_ofp(ntohs(value->be16));
> > >         break;
> > > 
> > > -    case MFF_IN_PORT_OXM: {
> > > -        ofp_port_t port;
> > > -        ofputil_port_from_ofp11(value->be32, &port);
> > > -        flow->in_port.ofp_port = port;
> > > +    case MFF_IN_PORT_OXM:
> > > +        ofputil_port_from_ofp11(value->be32, &flow->in_port.ofp_port);
> > > +        break;
> > > +    case MFF_ACTSET_OUTPUT:
> > > +        ofputil_port_from_ofp11(value->be32, &flow->actset_output);
> > >         break;
> > > -    }
> > > 
> > >     case MFF_SKB_PRIORITY:
> > >         flow->skb_priority = ntohl(value->be32);
> > > @@ -1163,6 +1175,10 @@ mf_set_wild(const struct mf_field *mf, struct 
> > > match *match)
> > >         match->flow.in_port.ofp_port = 0;
> > >         match->wc.masks.in_port.ofp_port = 0;
> > >         break;
> > > +    case MFF_ACTSET_OUTPUT:
> > > +        match->flow.actset_output = 0;
> > > +        match->wc.masks.actset_output = 0;
> > > +        break;
> > > 
> > >     case MFF_SKB_PRIORITY:
> > >         match->flow.skb_priority = 0;
> > > @@ -1354,6 +1370,7 @@ mf_set(const struct mf_field *mf,
> > >     case MFF_RECIRC_ID:
> > >     case MFF_IN_PORT:
> > >     case MFF_IN_PORT_OXM:
> > > +    case MFF_ACTSET_OUTPUT:
> > >     case MFF_SKB_PRIORITY:
> > >     case MFF_ETH_TYPE:
> > >     case MFF_DL_VLAN:
> > > diff --git a/lib/meta-flow.h b/lib/meta-flow.h
> > > index 9518ba0..1659522 100644
> > > --- a/lib/meta-flow.h
> > > +++ b/lib/meta-flow.h
> > > @@ -450,6 +450,19 @@ enum OVS_PACKED_ENUM mf_field_id {
> > >      */
> > >     MFF_IN_PORT_OXM,
> > > 
> > > +    /* "actset_output".
> > > +     *
> > > +     * Type: be32.
> > > +     * Maskable: no.
> > > +     * Formatting: OpenFlow 1.1+ port.
> > > +     * Prerequisites: none.
> > > +     * Access: read-only.
> > > +     * NXM: none.
> > > +     * OXM: ONFOXM_ET_ACTSET_OUTPUT(43) since OF1.3 and v2.4,
> > > +     *      OXM_OF_ACTSET_OUTPUT(43) since OF1.5 and v2.4.
> > > +     */
> > > +    MFF_ACTSET_OUTPUT,
> > > +
> > >     /* "skb_priority".
> > >      *
> > >      * Designates the queue to which output will be directed.  The value 
> > > in
> > > diff --git a/lib/nx-match.c b/lib/nx-match.c
> > > index 04e0791..e70eeac 100644
> > > --- a/lib/nx-match.c
> > > +++ b/lib/nx-match.c
> > > @@ -817,7 +817,7 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, 
> > > const struct match *match,
> > >     int match_len;
> > >     int i;
> > > 
> > > -    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 27);
> > > +    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 28);
> > > 
> > >     /* Metadata. */
> > >     if (match->wc.masks.dp_hash) {
> > > @@ -839,6 +839,10 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, 
> > > const struct match *match,
> > >                        htons(ofp_to_u16(in_port)));
> > >         }
> > >     }
> > > +    if (match->wc.masks.actset_output) {
> > > +        nxm_put_32(b, MFF_ACTSET_OUTPUT, oxm,
> > > +                   ofputil_port_to_ofp11(flow->actset_output));
> > > +    }
> > > 
> > >     /* Ethernet. */
> > >     nxm_put_eth_masked(b, MFF_ETH_SRC, oxm,
> > > diff --git a/lib/odp-util.h b/lib/odp-util.h
> > > index 11b54dd..ef4e82c 100644
> > > --- a/lib/odp-util.h
> > > +++ b/lib/odp-util.h
> > > @@ -133,7 +133,7 @@ void odp_portno_names_destroy(struct hmap 
> > > *portno_names);
> > >  * add another field and forget to adjust this value.
> > >  */
> > > #define ODPUTIL_FLOW_KEY_BYTES 512
> > > -BUILD_ASSERT_DECL(FLOW_WC_SEQ == 27);
> > > +BUILD_ASSERT_DECL(FLOW_WC_SEQ == 28);
> > > 
> > > /* A buffer with sufficient size and alignment to hold an 
> > > nlattr-formatted flow
> > >  * key.  An array of "struct nlattr" might not, in theory, be sufficiently
> > > diff --git a/lib/ofp-util.c b/lib/ofp-util.c
> > > index d765d03..b0b2f1c 100644
> > > --- a/lib/ofp-util.c
> > > +++ b/lib/ofp-util.c
> > > @@ -185,7 +185,7 @@ ofputil_netmask_to_wcbits(ovs_be32 netmask)
> > > void
> > > ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *wc)
> > > {
> > > -    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 27);
> > > +    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 28);
> > > 
> > >     /* Initialize most of wc. */
> > >     flow_wildcards_init_catchall(wc);
> > > @@ -6020,7 +6020,8 @@ ofputil_port_to_ofp11(ofp_port_t ofp10_port)
> > >         OFPUTIL_NAMED_PORT(ALL)                 \
> > >         OFPUTIL_NAMED_PORT(CONTROLLER)          \
> > >         OFPUTIL_NAMED_PORT(LOCAL)               \
> > > -        OFPUTIL_NAMED_PORT(ANY)
> > > +        OFPUTIL_NAMED_PORT(ANY)                 \
> > > +        OFPUTIL_NAMED_PORT(UNSET)
> > > 
> > > /* For backwards compatibility, so that "none" is recognized as OFPP_ANY 
> > > */
> > > #define OFPUTIL_NAMED_PORTS_WITH_NONE           \
> > > diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
> > > index 07a1f29..50d9fb6 100644
> > > --- a/ofproto/ofproto-dpif-xlate.c
> > > +++ b/ofproto/ofproto-dpif-xlate.c
> > > @@ -219,6 +219,7 @@ struct xlate_ctx {
> > >      * When translation is otherwise complete, 
> > > ofpacts_execute_action_set()
> > >      * converts it to a set of "struct ofpact"s that can be translated 
> > > into
> > >      * datapath actions.   */
> > > +    bool action_set_has_group;  /* Action set contains OFPACT_GROUP? */
> > >     struct ofpbuf action_set;   /* Action set. */
> > >     uint64_t action_set_stub[1024 / 8];
> > > };
> > > @@ -2484,7 +2485,7 @@ compose_output_action__(struct xlate_ctx *ctx, 
> > > ofp_port_t ofp_port,
> > > 
> > >     /* If 'struct flow' gets additional metadata, we'll need to zero it 
> > > out
> > >      * before traversing a patch port. */
> > > -    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 27);
> > > +    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 28);
> > > 
> > >     if (!xport) {
> > >         xlate_report(ctx, "Nonexistent output port");
> > > @@ -2533,6 +2534,7 @@ compose_output_action__(struct xlate_ctx *ctx, 
> > > ofp_port_t ofp_port,
> > >         flow->metadata = htonll(0);
> > >         memset(&flow->tunnel, 0, sizeof flow->tunnel);
> > >         memset(flow->regs, 0, sizeof flow->regs);
> > > +        flow->actset_output = OFPP_UNSET;
> > > 
> > >         special = process_special(ctx, &ctx->xin->flow, peer,
> > >                                   ctx->xin->packet);
> > > @@ -3534,8 +3536,31 @@ may_receive(const struct xport *xport, struct 
> > > xlate_ctx *ctx)
> > > static void
> > > xlate_write_actions(struct xlate_ctx *ctx, const struct ofpact *a)
> > > {
> > > -    struct ofpact_nest *on = ofpact_get_WRITE_ACTIONS(a);
> > > -    ofpbuf_put(&ctx->action_set, on->actions, 
> > > ofpact_nest_get_action_len(on));
> > > +    const struct ofpact_nest *on = ofpact_get_WRITE_ACTIONS(a);
> > > +    size_t on_len = ofpact_nest_get_action_len(on);
> > > +    const struct ofpact *inner;
> > > +
> > > +    /* Maintain actset_output depending on the contents of the action 
> > > set:
> > > +     *
> > > +     *   - OFPP_UNSET, if there is no "output" action.
> > > +     *
> > > +     *   - The output port, if there is an "output" action and no "group"
> > > +     *     action.
> > > +     *
> > > +     *   - OFPP_UNSET, if there is a "group" action.
> > > +     */
> > > +    if (!ctx->action_set_has_group) {
> > > +        OFPACT_FOR_EACH (inner, on->actions, on_len) {
> > > +            if (inner->type == OFPACT_OUTPUT) {
> > > +                ctx->xin->flow.actset_output = 
> > > ofpact_get_OUTPUT(inner)->port;
> > > +            } else if (inner->type == OFPACT_GROUP) {
> > > +                ctx->xin->flow.actset_output = OFPP_UNSET;
> > > +                ctx->action_set_has_group = true;
> > > +            }
> > > +        }
> > > +    }
> > > +
> > > +    ofpbuf_put(&ctx->action_set, on->actions, on_len);
> > >     ofpact_pad(&ctx->action_set);
> > > }
> > > 
> > > @@ -3891,6 +3916,8 @@ do_xlate_actions(const struct ofpact *ofpacts, 
> > > size_t ofpacts_len,
> > > 
> > >         case OFPACT_CLEAR_ACTIONS:
> > >             ofpbuf_clear(&ctx->action_set);
> > > +            ctx->xin->flow.actset_output = OFPP_UNSET;
> > > +            ctx->action_set_has_group = false;
> > >             break;
> > > 
> > >         case OFPACT_WRITE_ACTIONS:
> > > @@ -3937,6 +3964,7 @@ xlate_in_init(struct xlate_in *xin, struct 
> > > ofproto_dpif *ofproto,
> > >     xin->ofproto = ofproto;
> > >     xin->flow = *flow;
> > >     xin->flow.in_port.ofp_port = in_port;
> > > +    xin->flow.actset_output = OFPP_UNSET;
> > >     xin->packet = packet;
> > >     xin->may_learn = packet != NULL;
> > >     xin->rule = rule;
> > > @@ -4253,6 +4281,8 @@ xlate_actions(struct xlate_in *xin, struct 
> > > xlate_out *xout)
> > >     }
> > > 
> > >     ofpbuf_use_stub(&ctx.stack, ctx.init_stack, sizeof ctx.init_stack);
> > > +
> > > +    ctx.action_set_has_group = false;
> > >     ofpbuf_use_stub(&ctx.action_set,
> > >                     ctx.action_set_stub, sizeof ctx.action_set_stub);
> > > 
> > > diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
> > > index 652a2a3..3f111cb 100644
> > > --- a/tests/ofproto-dpif.at
> > > +++ b/tests/ofproto-dpif.at
> > > @@ -490,6 +490,46 @@ AT_CHECK([tail -1 stdout], [0], [Datapath actions: 2
> > > OVS_VSWITCHD_STOP
> > > AT_CLEANUP
> > > 
> > > +
> > > +AT_SETUP([ofproto-dpif - actset_output])
> > > +OVS_VSWITCHD_START
> > > +ADD_OF_PORTS(
> > > +  [br0], [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12], 
> > > [13])
> > > +AT_DATA([flows.txt], [dnl
> > > +table=0     actions=write_actions(output(2)),goto_table(1)
> > > +table=1     
> > > actions=move:ONFOXM_ET_ACTSET_OUTPUT[[0..31]]->OXM_OF_PKT_REG0[[0..31]],goto_table(2)
> > > +
> > > +# Verify that actset_output got set.
> > > +table=2,priority=20,actset_output=2  actions=4,goto_table(3)
> > > +table=2,priority=10                  actions=5,goto_table(3)
> > > +
> > > +# Verify that xreg0 got copied properly from actset_output.
> > > +table=3,priority=20,xreg0=2  actions=6,goto_table(4)
> > > +table=3,priority=10          actions=7,goto_table(4)
> > > +
> > > +# Verify that adding a group action unsets actset_output.
> > > +table=4 actions=write_actions(group(5)),goto_table(5)
> > > +table=5,priority=20,actset_output=unset  actions=8,goto_table(6)
> > > +table=5,priority=10                      actions=9,goto_table(6)
> > > +
> > > +# Verify that adding another output action doesn't change actset_output
> > > +# (since there's still a group).
> > > +table=6 actions=write_actions(output(3)),goto_table(7)
> > > +table=7,priority=20,actset_output=unset  actions=10,goto_table(8)
> > > +table=7,priority=10                      actions=11,goto_table(8)
> > > +
> > > +# Verify that clearing the action set, then writing an output action,
> > > +# causes actset_output to be set again.
> > > +table=8,actions=clear_actions,write_actions(output(3),output(2)),goto_table(9)
> > > +table=9,priority=20,actset_output=2 actions=12
> > > +table=9,priority=10                 actions=13
> > > +])
> > > +AT_CHECK([ovs-ofctl -O OpenFlow13 add-flows br0 flows.txt])
> > > +AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 
> > > '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,ttl=128,frag=no),icmp(type=8,code=0)'],
> > >  [0], [stdout])
> > > +AT_CHECK([tail -1 stdout], [0], [Datapath actions: 4,6,8,10,12,2
> > > +])
> > > +OVS_VSWITCHD_STOP
> > > +AT_CLEANUP
> > > AT_SETUP([ofproto-dpif - push-pop])
> > > OVS_VSWITCHD_START
> > > ADD_OF_PORTS([br0], [20], [21], [22], [33], [90])
> > > diff --git a/tests/ofproto.at b/tests/ofproto.at
> > > index 51efd37..9f35d5e 100644
> > > --- a/tests/ofproto.at
> > > +++ b/tests/ofproto.at
> > > @@ -1177,6 +1177,7 @@ OVS_VSWITCHD_START
> > >       metadata: arbitrary mask
> > >       in_port: exact match or wildcard
> > >       in_port_oxm: exact match or wildcard
> > > +      actset_output: exact match or wildcard
> > >       pkt_mark: arbitrary mask
> > >       reg0: arbitrary mask
> > >       reg1: arbitrary mask
> > > @@ -1247,7 +1248,7 @@ AT_CHECK(
> > > # Check that the configuration was updated.
> > > mv expout orig-expout
> > > sed 's/classifier/main/
> > > -73s/1000000/1024/' < orig-expout > expout
> > > +74s/1000000/1024/' < orig-expout > expout
> > > AT_CHECK([ovs-ofctl -O OpenFlow13 dump-table-features br0 | sed '/^$/d
> > > /^OFPST_TABLE_FEATURES/d'], [0], [expout])
> > > OVS_VSWITCHD_STOP
> > > diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at
> > > index d29b4de..446d8f5 100644
> > > --- a/tests/ovs-ofctl.at
> > > +++ b/tests/ovs-ofctl.at
> > > @@ -1681,7 +1681,7 @@ NXM_OF_IN_PORT(0001), NXM_OF_ETH_TYPE(0800)
> > > ])
> > > AT_CLEANUP
> > > 
> > > -AT_SETUP([ovs-ofctl parse-oxm (OpenFlow 1.5)])
> > > +AT_SETUP([ovs-ofctl parse-oxm (OpenFlow 1.2)])
> > > AT_KEYWORDS([oxm])
> > > AT_DATA([oxm.txt], [dnl
> > > <any>
> > > @@ -2175,6 +2175,29 @@ nx_match|WARN|Rejecting NXM/OXM entry 
> > > 0:32768:2:1:16 with 1-bits in value for bi
> > > AT_CHECK([grep -v '1-bits in value' stderr], [1])
> > > AT_CLEANUP
> > > 
> > > +AT_SETUP([ovs-ofctl parse-oxm (OpenFlow 1.3)])
> > > +AT_KEYWORDS([oxm])
> > > +AT_DATA([oxm.txt], [dnl
> > > +# actset_output
> > > +ONFOXM_ET_ACTSET_OUTPUT(00000000)
> > > +ONFOXM_ET_ACTSET_OUTPUT(fffffffe)
> > > +ONFOXM_ET_ACTSET_OUTPUT(fffffff7)
> > > +OXM_OF_ACTSET_OUTPUT(00000000)
> > > +OXM_OF_ACTSET_OUTPUT(fffffffe)
> > > +OXM_OF_ACTSET_OUTPUT(fffffff7)
> > > +])
> > > +AT_CHECK([ovs-ofctl '-vPATTERN:console:%c|%p|%m' --strict parse-oxm 
> > > OpenFlow13 < oxm.txt],
> > > +  [0], [dnl
> > > +# actset_output
> > > +ONFOXM_ET_ACTSET_OUTPUT(00000000)
> > > +ONFOXM_ET_ACTSET_OUTPUT(fffffffe)
> > > +ONFOXM_ET_ACTSET_OUTPUT(fffffff7)
> > > +ONFOXM_ET_ACTSET_OUTPUT(00000000)
> > > +ONFOXM_ET_ACTSET_OUTPUT(fffffffe)
> > > +ONFOXM_ET_ACTSET_OUTPUT(fffffff7)
> > > +], [])
> > > +AT_CLEANUP
> > > +
> > > AT_SETUP([ovs-ofctl parse-oxm (OpenFlow 1.5)])
> > > AT_KEYWORDS([oxm])
> > > AT_DATA([oxm.txt], [dnl
> > > @@ -2198,6 +2221,14 @@ NXM_NX_REG0_W(a0e0d050/f0f0f0f0), 
> > > NXM_NX_REG1_W(a0e0d050/f0f0f0f0)
> > > NXM_NX_REG0_W(a0e0d050/f0f0f0f0), NXM_NX_REG1(a0e0d050)
> > > NXM_NX_REG1_W(a0e0d050/f0f0f0f0), NXM_NX_REG2_W(a0e0d050/f0f0f0f0)
> > > NXM_NX_REG1_W(a0e0d050/f0f0f0f0), NXM_NX_REG2(a0e0d050)
> > > +
> > > +# actset_output
> > > +ONFOXM_ET_ACTSET_OUTPUT(00000000)
> > > +ONFOXM_ET_ACTSET_OUTPUT(fffffffe)
> > > +ONFOXM_ET_ACTSET_OUTPUT(fffffff7)
> > > +OXM_OF_ACTSET_OUTPUT(00000000)
> > > +OXM_OF_ACTSET_OUTPUT(fffffffe)
> > > +OXM_OF_ACTSET_OUTPUT(fffffff7)
> > > ])
> > > AT_CHECK([ovs-ofctl '-vPATTERN:console:%c|%p|%m' --strict parse-oxm 
> > > OpenFlow15 < oxm.txt],
> > >   [0], [dnl
> > > @@ -2221,6 +2252,14 @@ 
> > > OXM_OF_PKT_REG0_W(a0e0d050a0e0d050/f0f0f0f0f0f0f0f0)
> > > OXM_OF_PKT_REG0_W(a0e0d050a0e0d050/f0f0f0f0ffffffff)
> > > OXM_OF_PKT_REG0_W(00000000a0e0d050/00000000f0f0f0f0), 
> > > OXM_OF_PKT_REG1_W(a0e0d05000000000/f0f0f0f000000000)
> > > OXM_OF_PKT_REG0_W(00000000a0e0d050/00000000f0f0f0f0), 
> > > OXM_OF_PKT_REG1_W(a0e0d05000000000/ffffffff00000000)
> > > +
> > > +# actset_output
> > > +OXM_OF_ACTSET_OUTPUT(00000000)
> > > +OXM_OF_ACTSET_OUTPUT(fffffffe)
> > > +OXM_OF_ACTSET_OUTPUT(fffffff7)
> > > +OXM_OF_ACTSET_OUTPUT(00000000)
> > > +OXM_OF_ACTSET_OUTPUT(fffffffe)
> > > +OXM_OF_ACTSET_OUTPUT(fffffff7)
> > > ], [])
> > > AT_CLEANUP
> > > 
> > > diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in
> > > index bcc3f33..b8d41fb 100644
> > > --- a/utilities/ovs-ofctl.8.in
> > > +++ b/utilities/ovs-ofctl.8.in
> > > @@ -1119,6 +1119,16 @@ system components in order to facilitate 
> > > interaction between subsystems.
> > > On Linux this corresponds to the skb mark but the exact implementation is
> > > platform-dependent.
> > > .
> > > +.IP \fBactset_output=\fIport\fR
> > > +Matches the output port currently in the OpenFlow action set, where
> > > +\fIport\fR may be an OpenFlow port number or keyword
> > > +(e.g. \fBLOCAL\fR).  If there is no output port in the OpenFlow action
> > > +set, or if the output port will be ignored (e.g. because there is an
> > > +output group in the OpenFlow action set), then the value will be
> > > +\fBUNSET\fR.
> > > +.IP
> > > +This field was introduced in Open vSwitch 2.4 to conform with the
> > > +OpenFlow 1.5 (draft) specification.
> > > .PP
> > > Defining IPv6 flows (those with \fBdl_type\fR equal to 0x86dd) requires
> > > support for NXM.  The following shorthand notations are available for
> > > -- 
> > > 2.1.0
> > > 
> > 
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to