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