[ovs-dev] [generic tci mask 6/8] flow: Fully separate flow_wildcards from OpenFlow wildcard bits.
Justin Pettit
jpettit at nicira.com
Sat Nov 20 02:36:27 UTC 2010
Looks good.
--Justin
On Nov 10, 2010, at 3:38 PM, Ben Pfaff wrote:
> Originally, wildcards were just the OpenFlow OFPFW_* bits. Then, when
> OpenFlow added CIDR masks for IP addresses, struct flow_wildcards was born
> with additional members for those masks, derived from the wildcard bits.
> Then, when OVS added support for tunnels, we added another bit
> NXFW_TUN_ID that coexisted with the OFPFW_*. Later we added even more bits
> that do not appear in the OpenFlow 1.0 match structure at all. This had
> become really confusing, and the difficulties were especially visible in
> the long list of invariants in comments on struct flow_wildcards.
>
> This commit cleanly separates the OpenFlow 1.0 wildcard bits from the
> bits used inside Open vSwitch, by defining a new set of bits that are
> used only internally to Open vSwitch and converting to and from those
> wildcard bits at the point where data comes off or goes onto the wire.
> It also moves those functions into ofp-util.[ch] since they are only for
> dealing with OpenFlow wire protocol now.
> ---
> include/openvswitch/types.h | 2 +
> lib/classifier.c | 156 ++++++++++++------------------------------
> lib/classifier.h | 5 --
> lib/flow.c | 108 +++++++++---------------------
> lib/flow.h | 64 +++++++-----------
> lib/nx-match.c | 67 +++++++++---------
> lib/nx-match.def | 50 +++++++-------
> lib/ofp-parse.c | 28 ++++----
> lib/ofp-util.c | 136 +++++++++++++++++++++++++++++++++++++
> lib/ofp-util.h | 13 +++-
> ofproto/ofproto.c | 16 +++--
> tests/test-classifier.c | 100 +++++++++++++---------------
> tests/test-flows.c | 2 +-
> utilities/ovs-ofctl.c | 4 +-
> 14 files changed, 383 insertions(+), 368 deletions(-)
>
> diff --git a/include/openvswitch/types.h b/include/openvswitch/types.h
> index 2f670c0..fbd2997 100644
> --- a/include/openvswitch/types.h
> +++ b/include/openvswitch/types.h
> @@ -21,8 +21,10 @@
>
> #ifdef __CHECKER__
> #define OVS_BITWISE __attribute__((bitwise))
> +#define OVS_FORCE __attribute__((force))
> #else
> #define OVS_BITWISE
> +#define OVS_FORCE
> #endif
>
> /* The ovs_be<N> types indicate that an object is in big-endian, not
> diff --git a/lib/classifier.c b/lib/classifier.c
> index fb87b63..5c09f77 100644
> --- a/lib/classifier.c
> +++ b/lib/classifier.c
> @@ -23,6 +23,7 @@
> #include "dynamic-string.h"
> #include "flow.h"
> #include "hash.h"
> +#include "ofp-util.h"
> #include "packets.h"
>
> static struct cls_table *find_table(const struct classifier *,
> @@ -91,78 +92,10 @@ void
> cls_rule_init_catchall(struct cls_rule *rule, unsigned int priority)
> {
> memset(&rule->flow, 0, sizeof rule->flow);
> - flow_wildcards_init(&rule->wc, OVSFW_ALL | FWW_ALL);
> + flow_wildcards_init_catchall(&rule->wc);
> rule->priority = priority;
> }
>
> -/* Converts the ofp_match in 'match' (with format 'flow_format', one of NXFF_*)
> - * into a cls_rule in 'rule', with the given 'priority'. 'cookie' is used
> - * when 'flow_format' is NXFF_TUN_ID_FROM_COOKIE. */
> -void
> -cls_rule_from_match(const struct ofp_match *match, unsigned int priority,
> - int flow_format, uint64_t cookie,
> - struct cls_rule *rule)
> -{
> - uint32_t wildcards = ntohl(match->wildcards) & OVSFW_ALL;
> -
> - rule->priority = !wildcards ? UINT16_MAX : priority;
> -
> - rule->flow.tun_id = 0;
> - if (flow_format != NXFF_TUN_ID_FROM_COOKIE) {
> - wildcards |= NXFW_TUN_ID;
> - } else {
> - if (!(wildcards & NXFW_TUN_ID)) {
> - rule->flow.tun_id = htonl(ntohll(cookie) >> 32);
> - }
> - }
> - if (wildcards & OFPFW_DL_DST) {
> - wildcards |= FWW_ETH_MCAST;
> - }
> - flow_wildcards_init(&rule->wc, wildcards);
> -
> - rule->flow.nw_src = match->nw_src;
> - rule->flow.nw_dst = match->nw_dst;
> - rule->flow.in_port = (match->in_port == htons(OFPP_LOCAL) ? ODPP_LOCAL
> - : ntohs(match->in_port));
> - rule->flow.dl_vlan = match->dl_vlan;
> - rule->flow.dl_vlan_pcp = match->dl_vlan_pcp;
> - rule->flow.dl_type = match->dl_type;
> - rule->flow.tp_src = match->tp_src;
> - rule->flow.tp_dst = match->tp_dst;
> - memcpy(rule->flow.dl_src, match->dl_src, ETH_ADDR_LEN);
> - memcpy(rule->flow.dl_dst, match->dl_dst, ETH_ADDR_LEN);
> - rule->flow.nw_tos = match->nw_tos;
> - rule->flow.nw_proto = match->nw_proto;
> -
> - cls_rule_zero_wildcarded_fields(rule);
> -}
> -
> -/* Conerts 'rule' into an OpenFlow match structure 'match' with the given flow
> - * format 'flow_format' (one of NXFF_*). */
> -void
> -cls_rule_to_match(const struct cls_rule *rule, int flow_format,
> - struct ofp_match *match)
> -{
> - match->wildcards = htonl(rule->wc.wildcards
> - & (flow_format == NXFF_TUN_ID_FROM_COOKIE
> - ? OVSFW_ALL : OFPFW_ALL));
> - match->in_port = htons(rule->flow.in_port == ODPP_LOCAL ? OFPP_LOCAL
> - : rule->flow.in_port);
> - match->dl_vlan = rule->flow.dl_vlan;
> - match->dl_vlan_pcp = rule->flow.dl_vlan_pcp;
> - memcpy(match->dl_src, rule->flow.dl_src, ETH_ADDR_LEN);
> - memcpy(match->dl_dst, rule->flow.dl_dst, ETH_ADDR_LEN);
> - match->dl_type = rule->flow.dl_type;
> - match->nw_src = rule->flow.nw_src;
> - match->nw_dst = rule->flow.nw_dst;
> - match->nw_tos = rule->flow.nw_tos;
> - match->nw_proto = rule->flow.nw_proto;
> - match->tp_src = rule->flow.tp_src;
> - match->tp_dst = rule->flow.tp_dst;
> - memset(match->pad1, '\0', sizeof match->pad1);
> - memset(match->pad2, '\0', sizeof match->pad2);
> -}
> -
> /* For each bit or field wildcarded in 'rule', sets the corresponding bit or
> * field in 'flow' to all-0-bits. It is important to maintain this invariant
> * in a clr_rule that might be inserted into a classifier.
> @@ -180,28 +113,28 @@ cls_rule_zero_wildcarded_fields(struct cls_rule *rule)
> void
> cls_rule_set_in_port(struct cls_rule *rule, uint16_t odp_port)
> {
> - rule->wc.wildcards &= ~OFPFW_IN_PORT;
> + rule->wc.wildcards &= ~FWW_IN_PORT;
> rule->flow.in_port = odp_port;
> }
>
> void
> cls_rule_set_dl_type(struct cls_rule *rule, ovs_be16 dl_type)
> {
> - rule->wc.wildcards &= ~OFPFW_DL_TYPE;
> + rule->wc.wildcards &= ~FWW_DL_TYPE;
> rule->flow.dl_type = dl_type;
> }
>
> void
> cls_rule_set_dl_src(struct cls_rule *rule, const uint8_t dl_src[ETH_ADDR_LEN])
> {
> - rule->wc.wildcards &= ~OFPFW_DL_SRC;
> + rule->wc.wildcards &= ~FWW_DL_SRC;
> memcpy(rule->flow.dl_src, dl_src, ETH_ADDR_LEN);
> }
>
> void
> cls_rule_set_dl_dst(struct cls_rule *rule, const uint8_t dl_dst[ETH_ADDR_LEN])
> {
> - rule->wc.wildcards &= ~(OFPFW_DL_DST | FWW_ETH_MCAST);
> + rule->wc.wildcards &= ~(FWW_DL_DST | FWW_ETH_MCAST);
> memcpy(rule->flow.dl_dst, dl_dst, ETH_ADDR_LEN);
> }
>
> @@ -218,13 +151,13 @@ cls_rule_set_dl_tci_masked(struct cls_rule *rule, ovs_be16 tci, ovs_be16 mask)
> case 0xffff:
> if (tci == htons(0)) {
> /* Match only packets that have no 802.1Q header. */
> - rule->wc.wildcards &= ~(OFPFW_DL_VLAN | OFPFW_DL_VLAN_PCP);
> + rule->wc.wildcards &= ~(FWW_DL_VLAN | FWW_DL_VLAN_PCP);
> rule->flow.dl_vlan = htons(OFP_VLAN_NONE);
> rule->flow.dl_vlan_pcp = 0;
> return true;
> } else if (tci & htons(VLAN_CFI)) {
> /* Match only packets that have a specific 802.1Q VID and PCP. */
> - rule->wc.wildcards &= ~(OFPFW_DL_VLAN | OFPFW_DL_VLAN_PCP);
> + rule->wc.wildcards &= ~(FWW_DL_VLAN | FWW_DL_VLAN_PCP);
> rule->flow.dl_vlan = htons(vlan_tci_to_vid(tci));
> rule->flow.dl_vlan_pcp = vlan_tci_to_pcp(tci);
> return true;
> @@ -239,7 +172,7 @@ cls_rule_set_dl_tci_masked(struct cls_rule *rule, ovs_be16 tci, ovs_be16 mask)
> } else {
> /* Match only packets that have a specific 802.1Q VID. */
> cls_rule_set_dl_vlan(rule, tci & htons(VLAN_VID_MASK));
> - rule->wc.wildcards |= OFPFW_DL_VLAN_PCP;
> + rule->wc.wildcards |= FWW_DL_VLAN_PCP;
> rule->flow.dl_vlan_pcp = 0;
> return true;
> }
> @@ -250,14 +183,14 @@ cls_rule_set_dl_tci_masked(struct cls_rule *rule, ovs_be16 tci, ovs_be16 mask)
> } else {
> /* Match only packets that have a specific 802.1Q PCP. */
> cls_rule_set_dl_vlan_pcp(rule, vlan_tci_to_pcp(tci));
> - rule->wc.wildcards |= OFPFW_DL_VLAN;
> + rule->wc.wildcards |= FWW_DL_VLAN;
> rule->flow.dl_vlan = 0;
> return true;
> }
>
> case 0x0000:
> /* Match anything. */
> - rule->wc.wildcards |= OFPFW_DL_VLAN | OFPFW_DL_VLAN_PCP;
> + rule->wc.wildcards |= FWW_DL_VLAN | FWW_DL_VLAN_PCP;
> rule->flow.dl_vlan = htons(0);
> rule->flow.dl_vlan_pcp = 0;
> return true;
> @@ -274,35 +207,35 @@ cls_rule_set_dl_vlan(struct cls_rule *rule, ovs_be16 dl_vlan)
> dl_vlan &= htons(VLAN_VID_MASK);
> }
>
> - rule->wc.wildcards &= ~OFPFW_DL_VLAN;
> + rule->wc.wildcards &= ~FWW_DL_VLAN;
> rule->flow.dl_vlan = dl_vlan;
> }
>
> void
> cls_rule_set_dl_vlan_pcp(struct cls_rule *rule, uint8_t dl_vlan_pcp)
> {
> - rule->wc.wildcards &= ~OFPFW_DL_VLAN_PCP;
> + rule->wc.wildcards &= ~FWW_DL_VLAN_PCP;
> rule->flow.dl_vlan_pcp = dl_vlan_pcp & 0x07;
> }
>
> void
> cls_rule_set_tp_src(struct cls_rule *rule, ovs_be16 tp_src)
> {
> - rule->wc.wildcards &= ~OFPFW_TP_SRC;
> + rule->wc.wildcards &= ~FWW_TP_SRC;
> rule->flow.tp_src = tp_src;
> }
>
> void
> cls_rule_set_tp_dst(struct cls_rule *rule, ovs_be16 tp_dst)
> {
> - rule->wc.wildcards &= ~OFPFW_TP_DST;
> + rule->wc.wildcards &= ~FWW_TP_DST;
> rule->flow.tp_dst = tp_dst;
> }
>
> void
> cls_rule_set_nw_proto(struct cls_rule *rule, uint8_t nw_proto)
> {
> - rule->wc.wildcards &= ~OFPFW_NW_PROTO;
> + rule->wc.wildcards &= ~FWW_NW_PROTO;
> rule->flow.nw_proto = nw_proto;
> }
>
> @@ -343,14 +276,14 @@ cls_rule_set_nw_dst_masked(struct cls_rule *rule, ovs_be32 ip, ovs_be32 mask)
> void
> cls_rule_set_nw_tos(struct cls_rule *rule, uint8_t nw_tos)
> {
> - rule->wc.wildcards &= ~OFPFW_NW_TOS;
> + rule->wc.wildcards &= ~FWW_NW_TOS;
> rule->flow.nw_tos = nw_tos & IP_DSCP_MASK;
> }
>
> void
> cls_rule_set_icmp_type(struct cls_rule *rule, uint8_t icmp_type)
> {
> - rule->wc.wildcards &= ~OFPFW_ICMP_TYPE;
> + rule->wc.wildcards &= ~FWW_TP_SRC;
> rule->flow.icmp_type = htons(icmp_type);
>
> }
> @@ -358,7 +291,7 @@ cls_rule_set_icmp_type(struct cls_rule *rule, uint8_t icmp_type)
> void
> cls_rule_set_icmp_code(struct cls_rule *rule, uint8_t icmp_code)
> {
> - rule->wc.wildcards &= ~OFPFW_ICMP_CODE;
> + rule->wc.wildcards &= ~FWW_TP_DST;
> rule->flow.icmp_code = htons(icmp_code);
> }
>
> @@ -820,7 +753,7 @@ static bool
> flow_equal_except(const struct flow *a, const struct flow *b,
> const struct flow_wildcards *wildcards)
> {
> - const uint32_t wc = wildcards->wildcards;
> + const flow_wildcards_t wc = wildcards->wildcards;
> int i;
>
> BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 37 + FLOW_N_REGS * 4);
> @@ -831,32 +764,33 @@ flow_equal_except(const struct flow *a, const struct flow *b,
> }
> }
>
> - return ((wc & NXFW_TUN_ID || a->tun_id == b->tun_id)
> + return ((wc & FWW_TUN_ID || a->tun_id == b->tun_id)
> && !((a->nw_src ^ b->nw_src) & wildcards->nw_src_mask)
> && !((a->nw_dst ^ b->nw_dst) & wildcards->nw_dst_mask)
> - && (wc & OFPFW_IN_PORT || a->in_port == b->in_port)
> - && (wc & OFPFW_DL_VLAN || a->dl_vlan == b->dl_vlan)
> - && (wc & OFPFW_DL_TYPE || a->dl_type == b->dl_type)
> - && (wc & OFPFW_TP_SRC || a->tp_src == b->tp_src)
> - && (wc & OFPFW_TP_DST || a->tp_dst == b->tp_dst)
> - && (wc & OFPFW_DL_SRC || eth_addr_equals(a->dl_src, b->dl_src))
> - && (wc & OFPFW_DL_DST
> + && (wc & FWW_IN_PORT || a->in_port == b->in_port)
> + && (wc & FWW_DL_VLAN || a->dl_vlan == b->dl_vlan)
> + && (wc & FWW_DL_TYPE || a->dl_type == b->dl_type)
> + && (wc & FWW_TP_SRC || a->tp_src == b->tp_src)
> + && (wc & FWW_TP_DST || a->tp_dst == b->tp_dst)
> + && (wc & FWW_DL_SRC || eth_addr_equals(a->dl_src, b->dl_src))
> + && (wc & FWW_DL_DST
> || (!((a->dl_dst[0] ^ b->dl_dst[0]) & 0xfe)
> && a->dl_dst[1] == b->dl_dst[1]
> && a->dl_dst[2] == b->dl_dst[2]
> && a->dl_dst[3] == b->dl_dst[3]
> && a->dl_dst[4] == b->dl_dst[4]
> && a->dl_dst[5] == b->dl_dst[5]))
> - && (wc & FWW_ETH_MCAST || !((a->dl_dst[0] ^ b->dl_dst[0]) & 0x01))
> - && (wc & OFPFW_NW_PROTO || a->nw_proto == b->nw_proto)
> - && (wc & OFPFW_DL_VLAN_PCP || a->dl_vlan_pcp == b->dl_vlan_pcp)
> - && (wc & OFPFW_NW_TOS || a->nw_tos == b->nw_tos));
> + && (wc & FWW_ETH_MCAST
> + || !((a->dl_dst[0] ^ b->dl_dst[0]) & 0x01))
> + && (wc & FWW_NW_PROTO || a->nw_proto == b->nw_proto)
> + && (wc & FWW_DL_VLAN_PCP || a->dl_vlan_pcp == b->dl_vlan_pcp)
> + && (wc & FWW_NW_TOS || a->nw_tos == b->nw_tos));
> }
>
> static void
> zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards)
> {
> - const uint32_t wc = wildcards->wildcards;
> + const flow_wildcards_t wc = wildcards->wildcards;
> int i;
>
> BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 37 + 4 * FLOW_N_REGS);
> @@ -864,43 +798,43 @@ zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards)
> for (i = 0; i < FLOW_N_REGS; i++) {
> flow->regs[i] &= wildcards->reg_masks[i];
> }
> - if (wc & NXFW_TUN_ID) {
> + if (wc & FWW_TUN_ID) {
> flow->tun_id = 0;
> }
> flow->nw_src &= wildcards->nw_src_mask;
> flow->nw_dst &= wildcards->nw_dst_mask;
> - if (wc & OFPFW_IN_PORT) {
> + if (wc & FWW_IN_PORT) {
> flow->in_port = 0;
> }
> - if (wc & OFPFW_DL_VLAN) {
> + if (wc & FWW_DL_VLAN) {
> flow->dl_vlan = 0;
> }
> - if (wc & OFPFW_DL_TYPE) {
> + if (wc & FWW_DL_TYPE) {
> flow->dl_type = 0;
> }
> - if (wc & OFPFW_TP_SRC) {
> + if (wc & FWW_TP_SRC) {
> flow->tp_src = 0;
> }
> - if (wc & OFPFW_TP_DST) {
> + if (wc & FWW_TP_DST) {
> flow->tp_dst = 0;
> }
> - if (wc & OFPFW_DL_SRC) {
> + if (wc & FWW_DL_SRC) {
> memset(flow->dl_src, 0, sizeof flow->dl_src);
> }
> - if (wc & OFPFW_DL_DST) {
> + if (wc & FWW_DL_DST) {
> flow->dl_dst[0] &= 0x01;
> memset(&flow->dl_dst[1], 0, 5);
> }
> if (wc & FWW_ETH_MCAST) {
> flow->dl_dst[0] &= 0xfe;
> }
> - if (wc & OFPFW_NW_PROTO) {
> + if (wc & FWW_NW_PROTO) {
> flow->nw_proto = 0;
> }
> - if (wc & OFPFW_DL_VLAN_PCP) {
> + if (wc & FWW_DL_VLAN_PCP) {
> flow->dl_vlan_pcp = 0;
> }
> - if (wc & OFPFW_NW_TOS) {
> + if (wc & FWW_NW_TOS) {
> flow->nw_tos = 0;
> }
> }
> diff --git a/lib/classifier.h b/lib/classifier.h
> index d8135e9..e4b7f5f 100644
> --- a/lib/classifier.h
> +++ b/lib/classifier.h
> @@ -72,11 +72,6 @@ void cls_rule_init_exact(const struct flow *, unsigned int priority,
> struct cls_rule *);
> void cls_rule_init_catchall(struct cls_rule *, unsigned int priority);
>
> -void cls_rule_from_match(const struct ofp_match *, unsigned int priority,
> - int flow_format, uint64_t cookie, struct cls_rule *);
> -void cls_rule_to_match(const struct cls_rule *, int flow_format,
> - struct ofp_match *);
> -
> void cls_rule_zero_wildcarded_fields(struct cls_rule *);
>
> void cls_rule_set_in_port(struct cls_rule *, uint16_t odp_port);
> diff --git a/lib/flow.c b/lib/flow.c
> index 7c3ad51..8146519 100644
> --- a/lib/flow.c
> +++ b/lib/flow.c
> @@ -294,38 +294,13 @@ flow_print(FILE *stream, const struct flow *flow)
>
> /* flow_wildcards functions. */
>
> -/* Return 'wildcards' in "normal form":
> - *
> - * - Forces unknown bits to 0.
> - *
> - * - Forces nw_src and nw_dst masks greater than 32 to exactly 32.
> - */
> -static inline uint32_t
> -flow_wildcards_normalize(uint32_t wildcards)
> -{
> - wildcards &= wildcards & (OVSFW_ALL | FWW_ALL);
> - if (wildcards & (0x20 << OFPFW_NW_SRC_SHIFT)) {
> - wildcards &= ~(0x1f << OFPFW_NW_SRC_SHIFT);
> - }
> - if (wildcards & (0x20 << OFPFW_NW_DST_SHIFT)) {
> - wildcards &= ~(0x1f << OFPFW_NW_DST_SHIFT);
> - }
> - return wildcards;
> -}
> -
> -/* Initializes 'wc' from 'wildcards', which may be any combination of the
> - * OFPFW_* and OVSFW_* wildcard bits.
> - *
> - * All registers (NXM_NX_REG*) are always completely wildcarded, because
> - * 'wildcards' doesn't have enough bits to give the details on which
> - * particular bits should be wildcarded (if any). The caller may use
> - * flow_wildcards_set_reg_mask() to update the register wildcard masks. */
> +/* Initializes 'wc' as a set of wildcards that matches every packet. */
> void
> -flow_wildcards_init(struct flow_wildcards *wc, uint32_t wildcards)
> +flow_wildcards_init_catchall(struct flow_wildcards *wc)
> {
> - wc->wildcards = flow_wildcards_normalize(wildcards) | FWW_REGS;
> - wc->nw_src_mask = ofputil_wcbits_to_netmask(wildcards >> OFPFW_NW_SRC_SHIFT);
> - wc->nw_dst_mask = ofputil_wcbits_to_netmask(wildcards >> OFPFW_NW_DST_SHIFT);
> + wc->wildcards = FWW_ALL;
> + wc->nw_src_mask = htonl(0);
> + wc->nw_dst_mask = htonl(0);
> memset(wc->reg_masks, 0, sizeof wc->reg_masks);
> }
>
> @@ -345,15 +320,21 @@ flow_wildcards_init_exact(struct flow_wildcards *wc)
> bool
> flow_wildcards_is_exact(const struct flow_wildcards *wc)
> {
> - return !wc->wildcards;
> -}
> + int i;
>
> -static inline uint32_t
> -combine_nw_bits(uint32_t wb1, uint32_t wb2, int shift)
> -{
> - uint32_t sb1 = (wb1 >> shift) & 0x3f;
> - uint32_t sb2 = (wb2 >> shift) & 0x3f;
> - return MAX(sb1, sb2) << shift;
> + if (wc->wildcards
> + || wc->nw_src_mask != htonl(UINT32_MAX)
> + || wc->nw_dst_mask != htonl(UINT32_MAX)) {
> + return false;
> + }
> +
> + for (i = 0; i < FLOW_N_REGS; i++) {
> + if (wc->reg_masks[i] != htonl(UINT32_MAX)) {
> + return false;
> + }
> + }
> +
> + return true;
> }
>
> /* Initializes 'dst' as the combination of wildcards in 'src1' and 'src2'.
> @@ -364,13 +345,9 @@ flow_wildcards_combine(struct flow_wildcards *dst,
> const struct flow_wildcards *src1,
> const struct flow_wildcards *src2)
> {
> - uint32_t wb1 = src1->wildcards;
> - uint32_t wb2 = src2->wildcards;
> int i;
>
> - dst->wildcards = (wb1 | wb2) & ~(OFPFW_NW_SRC_MASK | OFPFW_NW_DST_MASK);
> - dst->wildcards |= combine_nw_bits(wb1, wb2, OFPFW_NW_SRC_SHIFT);
> - dst->wildcards |= combine_nw_bits(wb1, wb2, OFPFW_NW_DST_SHIFT);
> + dst->wildcards = src1->wildcards | src2->wildcards;
> dst->nw_src_mask = src1->nw_src_mask & src2->nw_src_mask;
> dst->nw_dst_mask = src1->nw_dst_mask & src2->nw_dst_mask;
> for (i = 0; i < FLOW_N_REGS; i++) {
> @@ -382,13 +359,11 @@ flow_wildcards_combine(struct flow_wildcards *dst,
> uint32_t
> flow_wildcards_hash(const struct flow_wildcards *wc)
> {
> - /* There is no need to include nw_src_mask or nw_dst_mask because they do
> - * not add any information (they can be computed from wc->wildcards). */
> - BUILD_ASSERT_DECL(sizeof wc->wildcards == 4);
> - BUILD_ASSERT_DECL(sizeof wc->reg_masks == 4 * FLOW_N_REGS);
> - BUILD_ASSERT_DECL(offsetof(struct flow_wildcards, wildcards) == 0);
> - BUILD_ASSERT_DECL(offsetof(struct flow_wildcards, reg_masks) == 4);
> - return hash_words((const uint32_t *) wc, 1 + FLOW_N_REGS, 0);
> + /* If you change struct flow_wildcards and thereby trigger this
> + * assertion, please check that the new struct flow_wildcards has no holes
> + * in it before you update the assertion. */
> + BUILD_ASSERT_DECL(sizeof *wc == 12 + FLOW_N_REGS * 4);
> + return hash_bytes(wc, sizeof *wc, 0);
> }
>
> /* Returns true if 'a' and 'b' represent the same wildcards, false if they are
> @@ -399,7 +374,9 @@ flow_wildcards_equal(const struct flow_wildcards *a,
> {
> int i;
>
> - if (a->wildcards != b->wildcards) {
> + if (a->wildcards != b->wildcards
> + || a->nw_src_mask != b->nw_src_mask
> + || a->nw_dst_mask != b->nw_dst_mask) {
> return false;
> }
>
> @@ -426,19 +403,15 @@ flow_wildcards_has_extra(const struct flow_wildcards *a,
> }
> }
>
> -#define OFPFW_NW_MASK (OFPFW_NW_SRC_MASK | OFPFW_NW_DST_MASK)
> - return ((a->wildcards & ~(b->wildcards | OFPFW_NW_MASK))
> + return (a->wildcards & ~b->wildcards
> || (a->nw_src_mask & b->nw_src_mask) != b->nw_src_mask
> || (a->nw_dst_mask & b->nw_dst_mask) != b->nw_dst_mask);
> }
>
> static bool
> -set_nw_mask(struct flow_wildcards *wc, ovs_be32 mask,
> - ovs_be32 *maskp, int shift)
> +set_nw_mask(ovs_be32 *maskp, ovs_be32 mask)
> {
> if (ip_is_cidr(mask)) {
> - wc->wildcards &= ~(0x3f << shift);
> - wc->wildcards |= ofputil_netmask_to_wcbits(mask) << shift;
> *maskp = mask;
> return true;
> } else {
> @@ -452,7 +425,7 @@ set_nw_mask(struct flow_wildcards *wc, ovs_be32 mask,
> bool
> flow_wildcards_set_nw_src_mask(struct flow_wildcards *wc, ovs_be32 mask)
> {
> - return set_nw_mask(wc, mask, &wc->nw_src_mask, OFPFW_NW_SRC_SHIFT);
> + return set_nw_mask(&wc->nw_src_mask, mask);
> }
>
> /* Sets the IP (or ARP) destination wildcard mask to CIDR 'mask' (consisting of
> @@ -461,7 +434,7 @@ flow_wildcards_set_nw_src_mask(struct flow_wildcards *wc, ovs_be32 mask)
> bool
> flow_wildcards_set_nw_dst_mask(struct flow_wildcards *wc, ovs_be32 mask)
> {
> - return set_nw_mask(wc, mask, &wc->nw_dst_mask, OFPFW_NW_DST_SHIFT);
> + return set_nw_mask(&wc->nw_dst_mask, mask);
> }
>
> /* Sets the wildcard mask for register 'idx' in 'wc' to 'mask'.
> @@ -469,20 +442,5 @@ flow_wildcards_set_nw_dst_mask(struct flow_wildcards *wc, ovs_be32 mask)
> void
> flow_wildcards_set_reg_mask(struct flow_wildcards *wc, int idx, uint32_t mask)
> {
> - if (mask != wc->reg_masks[idx]) {
> - wc->reg_masks[idx] = mask;
> - if (mask != UINT32_MAX) {
> - wc->wildcards |= FWW_REGS;
> - } else {
> - int i;
> -
> - for (i = 0; i < FLOW_N_REGS; i++) {
> - if (wc->reg_masks[i] != UINT32_MAX) {
> - wc->wildcards |= FWW_REGS;
> - return;
> - }
> - }
> - wc->wildcards &= ~FWW_REGS;
> - }
> - }
> + wc->reg_masks[idx] = mask;
> }
> diff --git a/lib/flow.h b/lib/flow.h
> index 058b5e8..f772936 100644
> --- a/lib/flow.h
> +++ b/lib/flow.h
> @@ -89,58 +89,46 @@ flow_hash(const struct flow *flow, uint32_t basis)
> return hash_bytes(flow, FLOW_SIG_SIZE, basis);
> }
>
> -/* Open vSwitch internal-only wildcard bits.
> +/* Open vSwitch flow wildcard bits.
> *
> * These are used only internally to Open vSwitch, in the 'wildcards' member of
> * struct flow_wildcards. They never appear in the wire protocol in this
> * form. */
>
> -/* Set to 1 if any bits in any of the reg_masks are wildcarded. This maintains
> - * the invariant that 'wildcards' is nonzero if and only if any bits are
> - * wildcarded. */
> -#define FWW_REGS (1u << 31)
> -
> -/* Set to 1 if bit 0 (the multicast bit) of the flow's dl_dst is wildcarded.
> - *
> - * (We reinterpret OFPFW_DL_DST as excluding bit 0.) */
> -#define FWW_ETH_MCAST (1u << 30)
> -
> -/* Avoid collisions. */
> -#define FWW_ALL (FWW_REGS | FWW_ETH_MCAST)
> -BUILD_ASSERT_DECL(!(FWW_ALL & OVSFW_ALL));
> +typedef unsigned int OVS_BITWISE flow_wildcards_t;
> +
> +/* Same values and meanings as corresponding OFPFW_* bits. */
> +#define FWW_IN_PORT ((OVS_FORCE flow_wildcards_t) (1 << 0))
> +#define FWW_DL_VLAN ((OVS_FORCE flow_wildcards_t) (1 << 1))
> +#define FWW_DL_SRC ((OVS_FORCE flow_wildcards_t) (1 << 2))
> +#define FWW_DL_DST ((OVS_FORCE flow_wildcards_t) (1 << 3))
> + /* excluding the multicast bit */
> +#define FWW_DL_TYPE ((OVS_FORCE flow_wildcards_t) (1 << 4))
> +#define FWW_NW_PROTO ((OVS_FORCE flow_wildcards_t) (1 << 5))
> +#define FWW_TP_SRC ((OVS_FORCE flow_wildcards_t) (1 << 6))
> +#define FWW_TP_DST ((OVS_FORCE flow_wildcards_t) (1 << 7))
> +/* Same meanings as corresponding OFPFW_* bits, but differ in value. */
> +#define FWW_DL_VLAN_PCP ((OVS_FORCE flow_wildcards_t) (1 << 8))
> +#define FWW_NW_TOS ((OVS_FORCE flow_wildcards_t) (1 << 9))
> +/* No OFPFW_* bits, but they do have corresponding OVSFW_* bits. */
> +#define FWW_TUN_ID ((OVS_FORCE flow_wildcards_t) (1 << 10))
> +/* No corresponding OFPFW_* or OVSFW_* bits. */
> +#define FWW_ETH_MCAST ((OVS_FORCE flow_wildcards_t) (1 << 11))
> + /* multicast bit only */
> +#define FWW_ALL ((OVS_FORCE flow_wildcards_t) (((1 << 12)) - 1))
>
> /* Information on wildcards for a flow, as a supplement to "struct flow".
> *
> - * The flow_wildcards_*() functions below both depend on and maintain the
> - * following important invariants:
> - *
> - * 1. 'wildcards' is nonzero if and only if at least one bit or field is
> - * wildcarded.
> - *
> - * 2. Bits in 'wildcards' not included in OVSFW_ALL or FWW_ALL are set to 0.
> - * (This is a corollary to invariant #1.)
> - *
> - * 3. The fields in 'wildcards' masked by OFPFW_NW_SRC_MASK and
> - * OFPFW_NW_DST_MASK have values between 0 and 32, inclusive.
> - *
> - * 4. The fields masked by OFPFW_NW_SRC_MASK and OFPFW_NW_DST_MASK correspond
> - * correctly to the masks in 'nw_src_mask' and 'nw_dst_mask', respectively.
> - *
> - * 5. FWW_REGS is set to 1 in 'wildcards' if and only if at least one bit in
> - * 'reg_masks[]' is nonzero. (This allows wildcarded 'reg_masks[]' to
> - * satisfy invariant #1.)
> - *
> - * 6. If FWW_REGS is set to 0 in 'wildcards', then the values of all of the
> - * other members can be correctly predicted based on 'wildcards' alone.
> - */
> + * Note that the meaning of 1-bits in 'wildcards' is opposite that of 1-bits in
> + * the rest of the members. */
> struct flow_wildcards {
> - uint32_t wildcards; /* OFPFW_* | OVSFW_* | FWW_*. */
> + flow_wildcards_t wildcards; /* 1-bit in each FWW_* wildcarded field. */
> uint32_t reg_masks[FLOW_N_REGS]; /* 1-bit in each significant regs bit. */
> ovs_be32 nw_src_mask; /* 1-bit in each significant nw_src bit. */
> ovs_be32 nw_dst_mask; /* 1-bit in each significant nw_dst bit. */
> };
>
> -void flow_wildcards_init(struct flow_wildcards *, uint32_t wildcards);
> +void flow_wildcards_init_catchall(struct flow_wildcards *);
> void flow_wildcards_init_exact(struct flow_wildcards *);
>
> bool flow_wildcards_is_exact(const struct flow_wildcards *);
> diff --git a/lib/nx-match.c b/lib/nx-match.c
> index 0ba33f7..210ca9a 100644
> --- a/lib/nx-match.c
> +++ b/lib/nx-match.c
> @@ -55,7 +55,7 @@ struct nxm_field {
> struct hmap_node hmap_node;
> enum nxm_field_index index; /* NFI_* value. */
> uint32_t header; /* NXM_* value. */
> - uint32_t wildcard; /* Wildcard bit, if exactly one. */
> + flow_wildcards_t wildcard; /* FWW_* bit, if exactly one. */
> ovs_be16 dl_type; /* dl_type prerequisite, if nonzero. */
> uint8_t nw_proto; /* nw_proto prerequisite, if nonzero. */
> const char *name; /* "NXM_*" string. */
> @@ -143,8 +143,9 @@ nxm_field_bits(uint32_t header)
> static int
> parse_tci(struct cls_rule *rule, ovs_be16 tci, ovs_be16 mask)
> {
> - enum { OFPFW_DL_TCI = OFPFW_DL_VLAN | OFPFW_DL_VLAN_PCP };
> - if ((rule->wc.wildcards & OFPFW_DL_TCI) != OFPFW_DL_TCI) {
> + const flow_wildcards_t FWW_DL_TCI = FWW_DL_VLAN | FWW_DL_VLAN_PCP;
> +
> + if ((rule->wc.wildcards & FWW_DL_TCI) != FWW_DL_TCI) {
> return NXM_DUP_TYPE;
> } else {
> return cls_rule_set_dl_tci_masked(rule, tci, mask) ? 0 : NXM_INVALID;
> @@ -188,29 +189,29 @@ parse_nxm_entry(struct cls_rule *rule, const struct nxm_field *f,
>
> /* Ethernet header. */
> case NFI_NXM_OF_ETH_DST:
> - if ((wc->wildcards & (OFPFW_DL_DST | FWW_ETH_MCAST))
> - != (OFPFW_DL_DST | FWW_ETH_MCAST)) {
> + if ((wc->wildcards & (FWW_DL_DST | FWW_ETH_MCAST))
> + != (FWW_DL_DST | FWW_ETH_MCAST)) {
> return NXM_DUP_TYPE;
> } else {
> - wc->wildcards &= ~(OFPFW_DL_DST | FWW_ETH_MCAST);
> + wc->wildcards &= ~(FWW_DL_DST | FWW_ETH_MCAST);
> memcpy(flow->dl_dst, value, ETH_ADDR_LEN);
> return 0;
> }
> case NFI_NXM_OF_ETH_DST_W:
> - if ((wc->wildcards & (OFPFW_DL_DST | FWW_ETH_MCAST))
> - != (OFPFW_DL_DST | FWW_ETH_MCAST)) {
> + if ((wc->wildcards & (FWW_DL_DST | FWW_ETH_MCAST))
> + != (FWW_DL_DST | FWW_ETH_MCAST)) {
> return NXM_DUP_TYPE;
> } else if (eth_addr_equals(mask, eth_mcast_1)) {
> wc->wildcards &= ~FWW_ETH_MCAST;
> flow->dl_dst[0] = *(uint8_t *) value & 0x01;
> } else if (eth_addr_equals(mask, eth_mcast_0)) {
> - wc->wildcards &= ~OFPFW_DL_DST;
> + wc->wildcards &= ~FWW_DL_DST;
> memcpy(flow->dl_dst, value, ETH_ADDR_LEN);
> flow->dl_dst[0] &= 0xfe;
> } else if (eth_addr_equals(mask, eth_all_0s)) {
> return 0;
> } else if (eth_addr_equals(mask, eth_all_1s)) {
> - wc->wildcards &= ~(OFPFW_DL_DST | FWW_ETH_MCAST);
> + wc->wildcards &= ~(FWW_DL_DST | FWW_ETH_MCAST);
> memcpy(flow->dl_dst, value, ETH_ADDR_LEN);
> return 0;
> } else {
> @@ -528,10 +529,10 @@ static void
> nxm_put_eth_dst(struct ofpbuf *b,
> uint32_t wc, const uint8_t value[ETH_ADDR_LEN])
> {
> - switch (wc & (OFPFW_DL_DST | FWW_ETH_MCAST)) {
> - case OFPFW_DL_DST | FWW_ETH_MCAST:
> + switch (wc & (FWW_DL_DST | FWW_ETH_MCAST)) {
> + case FWW_DL_DST | FWW_ETH_MCAST:
> break;
> - case OFPFW_DL_DST:
> + case FWW_DL_DST:
> nxm_put_header(b, NXM_OF_ETH_DST_W);
> ofpbuf_put(b, value, ETH_ADDR_LEN);
> ofpbuf_put(b, eth_mcast_1, ETH_ADDR_LEN);
> @@ -551,7 +552,7 @@ nxm_put_eth_dst(struct ofpbuf *b,
> int
> nx_put_match(struct ofpbuf *b, const struct cls_rule *cr)
> {
> - const uint32_t wc = cr->wc.wildcards;
> + const flow_wildcards_t wc = cr->wc.wildcards;
> const struct flow *flow = &cr->flow;
> const size_t start_len = b->size;
> ovs_be16 vid, pcp;
> @@ -559,7 +560,7 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr)
> int i;
>
> /* Metadata. */
> - if (!(wc & OFPFW_IN_PORT)) {
> + if (!(wc & FWW_IN_PORT)) {
> uint16_t in_port = flow->in_port;
> if (in_port == ODPP_LOCAL) {
> in_port = OFPP_LOCAL;
> @@ -569,24 +570,24 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr)
>
> /* Ethernet. */
> nxm_put_eth_dst(b, wc, flow->dl_dst);
> - if (!(wc & OFPFW_DL_SRC)) {
> + if (!(wc & FWW_DL_SRC)) {
> nxm_put_eth(b, NXM_OF_ETH_SRC, flow->dl_src);
> }
> - if (!(wc & OFPFW_DL_TYPE)) {
> + if (!(wc & FWW_DL_TYPE)) {
> nxm_put_16(b, NXM_OF_ETH_TYPE, flow->dl_type);
> }
>
> /* 802.1Q. */
> vid = flow->dl_vlan & htons(VLAN_VID_MASK);
> pcp = htons((flow->dl_vlan_pcp << VLAN_PCP_SHIFT) & VLAN_PCP_MASK);
> - switch (wc & (OFPFW_DL_VLAN | OFPFW_DL_VLAN_PCP)) {
> - case OFPFW_DL_VLAN | OFPFW_DL_VLAN_PCP:
> + switch (wc & (FWW_DL_VLAN | FWW_DL_VLAN_PCP)) {
> + case FWW_DL_VLAN | FWW_DL_VLAN_PCP:
> break;
> - case OFPFW_DL_VLAN:
> + case FWW_DL_VLAN:
> nxm_put_16w(b, NXM_OF_VLAN_TCI_W, pcp | htons(VLAN_CFI),
> htons(VLAN_PCP_MASK | VLAN_CFI));
> break;
> - case OFPFW_DL_VLAN_PCP:
> + case FWW_DL_VLAN_PCP:
> if (flow->dl_vlan == htons(OFP_VLAN_NONE)) {
> nxm_put_16(b, NXM_OF_VLAN_TCI, 0);
> } else {
> @@ -603,51 +604,51 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr)
> break;
> }
>
> - if (!(wc & OFPFW_DL_TYPE) && flow->dl_type == htons(ETH_TYPE_IP)) {
> + if (!(wc & FWW_DL_TYPE) && flow->dl_type == htons(ETH_TYPE_IP)) {
> /* IP. */
> - if (!(wc & OFPFW_NW_TOS)) {
> + if (!(wc & FWW_NW_TOS)) {
> nxm_put_8(b, NXM_OF_IP_TOS, flow->nw_tos & 0xfc);
> }
> nxm_put_32m(b, NXM_OF_IP_SRC, flow->nw_src, cr->wc.nw_src_mask);
> nxm_put_32m(b, NXM_OF_IP_DST, flow->nw_dst, cr->wc.nw_dst_mask);
>
> - if (!(wc & OFPFW_NW_PROTO)) {
> + if (!(wc & FWW_NW_PROTO)) {
> nxm_put_8(b, NXM_OF_IP_PROTO, flow->nw_proto);
> switch (flow->nw_proto) {
> /* TCP. */
> case IP_TYPE_TCP:
> - if (!(wc & OFPFW_TP_SRC)) {
> + if (!(wc & FWW_TP_SRC)) {
> nxm_put_16(b, NXM_OF_TCP_SRC, flow->tp_src);
> }
> - if (!(wc & OFPFW_TP_DST)) {
> + if (!(wc & FWW_TP_DST)) {
> nxm_put_16(b, NXM_OF_TCP_DST, flow->tp_dst);
> }
> break;
>
> /* UDP. */
> case IP_TYPE_UDP:
> - if (!(wc & OFPFW_TP_SRC)) {
> + if (!(wc & FWW_TP_SRC)) {
> nxm_put_16(b, NXM_OF_UDP_SRC, flow->tp_src);
> }
> - if (!(wc & OFPFW_TP_DST)) {
> + if (!(wc & FWW_TP_DST)) {
> nxm_put_16(b, NXM_OF_UDP_DST, flow->tp_dst);
> }
> break;
>
> /* ICMP. */
> case IP_TYPE_ICMP:
> - if (!(wc & OFPFW_TP_SRC)) {
> + if (!(wc & FWW_TP_SRC)) {
> nxm_put_8(b, NXM_OF_ICMP_TYPE, ntohs(flow->tp_src));
> }
> - if (!(wc & OFPFW_TP_DST)) {
> + if (!(wc & FWW_TP_DST)) {
> nxm_put_8(b, NXM_OF_ICMP_CODE, ntohs(flow->tp_dst));
> }
> break;
> }
> }
> - } else if (!(wc & OFPFW_DL_TYPE) && flow->dl_type == htons(ETH_TYPE_ARP)) {
> + } else if (!(wc & FWW_DL_TYPE) && flow->dl_type == htons(ETH_TYPE_ARP)) {
> /* ARP. */
> - if (!(wc & OFPFW_NW_PROTO)) {
> + if (!(wc & FWW_NW_PROTO)) {
> nxm_put_16(b, NXM_OF_ARP_OP, htons(flow->nw_proto));
> }
> nxm_put_32m(b, NXM_OF_ARP_SPA, flow->nw_src, cr->wc.nw_src_mask);
> @@ -655,7 +656,7 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr)
> }
>
> /* Tunnel ID. */
> - if (!(wc & NXFW_TUN_ID)) {
> + if (!(wc & FWW_TUN_ID)) {
> nxm_put_64(b, NXM_NX_TUN_ID, htonll(ntohl(flow->tun_id)));
> }
>
> diff --git a/lib/nx-match.def b/lib/nx-match.def
> index f6167af..e045d0f 100644
> --- a/lib/nx-match.def
> +++ b/lib/nx-match.def
> @@ -18,37 +18,37 @@
> DEFINE_FIELD(HEADER, WILDCARD, DL_TYPE, NW_PROTO) \
> DEFINE_FIELD(HEADER##_W, WILDCARD, DL_TYPE, NW_PROTO)
>
> -/* NXM_ bit OFPFW_* bit dl_type nw_proto */
> -/* ------------ -------------- ----------- ------------- */
> -DEFINE_FIELD (OF_IN_PORT, OFPFW_IN_PORT, 0, 0)
> -DEFINE_FIELD_M(OF_ETH_DST, 0, 0, 0)
> -DEFINE_FIELD (OF_ETH_SRC, OFPFW_DL_SRC, 0, 0)
> -DEFINE_FIELD (OF_ETH_TYPE, OFPFW_DL_TYPE, 0, 0)
> -DEFINE_FIELD_M(OF_VLAN_TCI, 0, 0, 0)
> -DEFINE_FIELD (OF_IP_TOS, OFPFW_NW_TOS, ETH_TYPE_IP, 0)
> -DEFINE_FIELD (OF_IP_PROTO, OFPFW_NW_PROTO, ETH_TYPE_IP, 0)
> -DEFINE_FIELD_M(OF_IP_SRC, 0, ETH_TYPE_IP, 0)
> -DEFINE_FIELD_M(OF_IP_DST, 0, ETH_TYPE_IP, 0)
> -DEFINE_FIELD (OF_TCP_SRC, OFPFW_TP_SRC, ETH_TYPE_IP, IP_TYPE_TCP)
> -DEFINE_FIELD (OF_TCP_DST, OFPFW_TP_DST, ETH_TYPE_IP, IP_TYPE_TCP)
> -DEFINE_FIELD (OF_UDP_SRC, OFPFW_TP_SRC, ETH_TYPE_IP, IP_TYPE_UDP)
> -DEFINE_FIELD (OF_UDP_DST, OFPFW_TP_DST, ETH_TYPE_IP, IP_TYPE_UDP)
> -DEFINE_FIELD (OF_ICMP_TYPE, OFPFW_TP_SRC, ETH_TYPE_IP, IP_TYPE_ICMP)
> -DEFINE_FIELD (OF_ICMP_CODE, OFPFW_TP_DST, ETH_TYPE_IP, IP_TYPE_ICMP)
> -DEFINE_FIELD (OF_ARP_OP, OFPFW_NW_PROTO, ETH_TYPE_ARP, 0)
> -DEFINE_FIELD_M(OF_ARP_SPA, 0, ETH_TYPE_ARP, 0)
> -DEFINE_FIELD_M(OF_ARP_TPA, 0, ETH_TYPE_ARP, 0)
> -DEFINE_FIELD (NX_TUN_ID, NXFW_TUN_ID, 0, 0)
> +/* NXM_ suffix FWW_* bit dl_type nw_proto */
> +/* ------------ ------------ ----------- ------------- */
> +DEFINE_FIELD (OF_IN_PORT, FWW_IN_PORT, 0, 0)
> +DEFINE_FIELD_M(OF_ETH_DST, 0, 0, 0)
> +DEFINE_FIELD (OF_ETH_SRC, FWW_DL_SRC, 0, 0)
> +DEFINE_FIELD (OF_ETH_TYPE, FWW_DL_TYPE, 0, 0)
> +DEFINE_FIELD_M(OF_VLAN_TCI, 0, 0, 0)
> +DEFINE_FIELD (OF_IP_TOS, FWW_NW_TOS, ETH_TYPE_IP, 0)
> +DEFINE_FIELD (OF_IP_PROTO, FWW_NW_PROTO, ETH_TYPE_IP, 0)
> +DEFINE_FIELD_M(OF_IP_SRC, 0, ETH_TYPE_IP, 0)
> +DEFINE_FIELD_M(OF_IP_DST, 0, ETH_TYPE_IP, 0)
> +DEFINE_FIELD (OF_TCP_SRC, FWW_TP_SRC, ETH_TYPE_IP, IP_TYPE_TCP)
> +DEFINE_FIELD (OF_TCP_DST, FWW_TP_DST, ETH_TYPE_IP, IP_TYPE_TCP)
> +DEFINE_FIELD (OF_UDP_SRC, FWW_TP_SRC, ETH_TYPE_IP, IP_TYPE_UDP)
> +DEFINE_FIELD (OF_UDP_DST, FWW_TP_DST, ETH_TYPE_IP, IP_TYPE_UDP)
> +DEFINE_FIELD (OF_ICMP_TYPE, FWW_TP_SRC, ETH_TYPE_IP, IP_TYPE_ICMP)
> +DEFINE_FIELD (OF_ICMP_CODE, FWW_TP_DST, ETH_TYPE_IP, IP_TYPE_ICMP)
> +DEFINE_FIELD (OF_ARP_OP, FWW_NW_PROTO, ETH_TYPE_ARP, 0)
> +DEFINE_FIELD_M(OF_ARP_SPA, 0, ETH_TYPE_ARP, 0)
> +DEFINE_FIELD_M(OF_ARP_TPA, 0, ETH_TYPE_ARP, 0)
> +DEFINE_FIELD (NX_TUN_ID, FWW_TUN_ID, 0, 0)
>
> -DEFINE_FIELD_M(NX_REG0, 0, 0, 0)
> +DEFINE_FIELD_M(NX_REG0, 0, 0, 0)
> #if FLOW_N_REGS >= 2
> -DEFINE_FIELD_M(NX_REG1, 0, 0, 0)
> +DEFINE_FIELD_M(NX_REG1, 0, 0, 0)
> #endif
> #if FLOW_N_REGS >= 3
> -DEFINE_FIELD_M(NX_REG2, 0, 0, 0)
> +DEFINE_FIELD_M(NX_REG2, 0, 0, 0)
> #endif
> #if FLOW_N_REGS >= 4
> -DEFINE_FIELD_M(NX_REG3, 0, 0, 0)
> +DEFINE_FIELD_M(NX_REG3, 0, 0, 0)
> #endif
> #if FLOW_N_REGS > 4
> #error
> diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
> index f572f4e..4de9708 100644
> --- a/lib/ofp-parse.c
> +++ b/lib/ofp-parse.c
> @@ -345,20 +345,20 @@ parse_protocol(const char *name, const struct protocol **p_out)
> }
>
> #define FIELDS \
> - FIELD(F_IN_PORT, "in_port", OFPFW_IN_PORT) \
> - FIELD(F_DL_VLAN, "dl_vlan", OFPFW_DL_VLAN) \
> - FIELD(F_DL_VLAN_PCP, "dl_vlan_pcp", OFPFW_DL_VLAN_PCP) \
> - FIELD(F_DL_SRC, "dl_src", OFPFW_DL_SRC) \
> - FIELD(F_DL_DST, "dl_dst", OFPFW_DL_DST) \
> - FIELD(F_DL_TYPE, "dl_type", OFPFW_DL_TYPE) \
> + FIELD(F_IN_PORT, "in_port", FWW_IN_PORT) \
> + FIELD(F_DL_VLAN, "dl_vlan", FWW_DL_VLAN) \
> + FIELD(F_DL_VLAN_PCP, "dl_vlan_pcp", FWW_DL_VLAN_PCP) \
> + FIELD(F_DL_SRC, "dl_src", FWW_DL_SRC) \
> + FIELD(F_DL_DST, "dl_dst", FWW_DL_DST) \
> + FIELD(F_DL_TYPE, "dl_type", FWW_DL_TYPE) \
> FIELD(F_NW_SRC, "nw_src", 0) \
> FIELD(F_NW_DST, "nw_dst", 0) \
> - FIELD(F_NW_PROTO, "nw_proto", OFPFW_NW_PROTO) \
> - FIELD(F_NW_TOS, "nw_tos", OFPFW_NW_TOS) \
> - FIELD(F_TP_SRC, "tp_src", OFPFW_TP_SRC) \
> - FIELD(F_TP_DST, "tp_dst", OFPFW_TP_DST) \
> - FIELD(F_ICMP_TYPE, "icmp_type", OFPFW_ICMP_TYPE) \
> - FIELD(F_ICMP_CODE, "icmp_code", OFPFW_ICMP_CODE)
> + FIELD(F_NW_PROTO, "nw_proto", FWW_NW_PROTO) \
> + FIELD(F_NW_TOS, "nw_tos", FWW_NW_TOS) \
> + FIELD(F_TP_SRC, "tp_src", FWW_TP_SRC) \
> + FIELD(F_TP_DST, "tp_dst", FWW_TP_DST) \
> + FIELD(F_ICMP_TYPE, "icmp_type", FWW_TP_SRC) \
> + FIELD(F_ICMP_CODE, "icmp_code", FWW_TP_DST)
>
> enum field_index {
> #define FIELD(ENUM, NAME, WILDCARD) ENUM,
> @@ -370,7 +370,7 @@ enum field_index {
> struct field {
> enum field_index index;
> const char *name;
> - uint32_t wildcard;
> + flow_wildcards_t wildcard; /* FWW_* bit. */
> };
>
> static bool
> @@ -571,7 +571,7 @@ parse_ofp_flow_mod(char *string, uint16_t command)
> parse_ofp_str(&pf, buffer, string);
>
> ofm = buffer->data;
> - cls_rule_to_match(&pf.rule, NXFF_OPENFLOW10, &ofm->match);
> + ofputil_cls_rule_to_match(&pf.rule, NXFF_OPENFLOW10, &ofm->match);
> ofm->command = htons(command);
> ofm->cookie = htonll(pf.cookie);
> ofm->idle_timeout = htons(pf.idle_timeout);
> diff --git a/lib/ofp-util.c b/lib/ofp-util.c
> index 6712dd1..7d4cb14 100644
> --- a/lib/ofp-util.c
> +++ b/lib/ofp-util.c
> @@ -19,6 +19,7 @@
> #include <inttypes.h>
> #include <stdlib.h>
> #include "byte-order.h"
> +#include "classifier.h"
> #include "nx-match.h"
> #include "ofp-util.h"
> #include "ofpbuf.h"
> @@ -67,6 +68,141 @@ ofputil_netmask_to_wcbits(ovs_be32 netmask)
> #endif
> }
>
> +/* A list of the FWW_* and OFPFW_ bits that have the same value, meaning, and
> + * name. */
> +#define WC_INVARIANT_LIST \
> + WC_INVARIANT_BIT(IN_PORT) \
> + WC_INVARIANT_BIT(DL_VLAN) \
> + WC_INVARIANT_BIT(DL_SRC) \
> + WC_INVARIANT_BIT(DL_DST) \
> + WC_INVARIANT_BIT(DL_TYPE) \
> + WC_INVARIANT_BIT(NW_PROTO) \
> + WC_INVARIANT_BIT(TP_SRC) \
> + WC_INVARIANT_BIT(TP_DST)
> +
> +/* Verify that all of the invariant bits (as defined on WC_INVARIANT_LIST)
> + * actually have the same names and values. */
> +#define WC_INVARIANT_BIT(NAME) BUILD_ASSERT_DECL(FWW_##NAME == OFPFW_##NAME);
> + WC_INVARIANT_LIST
> +#undef WC_INVARIANT_BIT
> +
> +/* WC_INVARIANTS is the invariant bits (as defined on WC_INVARIANT_LIST) all
> + * OR'd together. */
> +enum {
> + WC_INVARIANTS = 0
> +#define WC_INVARIANT_BIT(NAME) | FWW_##NAME
> + WC_INVARIANT_LIST
> +#undef WC_INVARIANT_BIT
> +};
> +
> +/* Converts the ofp_match in 'match' into a cls_rule in 'rule', with the given
> + * 'priority'.
> + *
> + * 'flow_format' must either NXFF_OPENFLOW10 or NXFF_TUN_ID_FROM_COOKIE. In
> + * the latter case only, 'flow''s tun_id field will be taken from the high bits
> + * of 'cookie', if 'match''s wildcards do not indicate that tun_id is
> + * wildcarded. */
> +void
> +ofputil_cls_rule_from_match(const struct ofp_match *match,
> + unsigned int priority, int flow_format,
> + uint64_t cookie, struct cls_rule *rule)
> +{
> + struct flow_wildcards *wc = &rule->wc;
> + unsigned int ofpfw;
> +
> + /* Initialize rule->priority. */
> + ofpfw = ntohl(match->wildcards);
> + ofpfw &= flow_format == NXFF_TUN_ID_FROM_COOKIE ? OVSFW_ALL : OFPFW_ALL;
> + rule->priority = !ofpfw ? UINT16_MAX : priority;
> +
> + /* Initialize most of rule->wc. */
> + wc->wildcards = ofpfw & WC_INVARIANTS;
> + if (ofpfw & OFPFW_DL_VLAN_PCP) {
> + wc->wildcards |= FWW_DL_VLAN_PCP;
> + }
> + if (ofpfw & OFPFW_NW_TOS) {
> + wc->wildcards |= FWW_NW_TOS;
> + }
> + memset(wc->reg_masks, 0, sizeof wc->reg_masks);
> + wc->nw_src_mask = ofputil_wcbits_to_netmask(ofpfw >> OFPFW_NW_SRC_SHIFT);
> + wc->nw_dst_mask = ofputil_wcbits_to_netmask(ofpfw >> OFPFW_NW_DST_SHIFT);
> +
> + if (!(ofpfw & NXFW_TUN_ID)) {
> + rule->flow.tun_id = htonl(ntohll(cookie) >> 32);
> + } else {
> + wc->wildcards |= FWW_TUN_ID;
> + rule->flow.tun_id = 0;
> + }
> +
> + if (ofpfw & OFPFW_DL_DST) {
> + wc->wildcards |= FWW_ETH_MCAST;
> + }
> +
> + /* Initialize rule->flow. */
> + rule->flow.nw_src = match->nw_src;
> + rule->flow.nw_dst = match->nw_dst;
> + rule->flow.in_port = (match->in_port == htons(OFPP_LOCAL) ? ODPP_LOCAL
> + : ntohs(match->in_port));
> + rule->flow.dl_vlan = match->dl_vlan;
> + rule->flow.dl_vlan_pcp = match->dl_vlan_pcp;
> + rule->flow.dl_type = match->dl_type;
> + rule->flow.tp_src = match->tp_src;
> + rule->flow.tp_dst = match->tp_dst;
> + memcpy(rule->flow.dl_src, match->dl_src, ETH_ADDR_LEN);
> + memcpy(rule->flow.dl_dst, match->dl_dst, ETH_ADDR_LEN);
> + rule->flow.nw_tos = match->nw_tos;
> + rule->flow.nw_proto = match->nw_proto;
> +
> + /* Clean up. */
> + cls_rule_zero_wildcarded_fields(rule);
> +}
> +
> +/* Extract 'flow' with 'wildcards' into the OpenFlow match structure
> + * 'match'.
> + *
> + * 'flow_format' must either NXFF_OPENFLOW10 or NXFF_TUN_ID_FROM_COOKIE. In
> + * the latter case only, 'match''s NXFW_TUN_ID bit will be filled in; otherwise
> + * it is always set to 0. */
> +void
> +ofputil_cls_rule_to_match(const struct cls_rule *rule, int flow_format,
> + struct ofp_match *match)
> +{
> + const struct flow_wildcards *wc = &rule->wc;
> + unsigned int ofpfw;
> +
> + /* Figure out OpenFlow wildcards. */
> + ofpfw = wc->wildcards & WC_INVARIANTS;
> + ofpfw |= ofputil_netmask_to_wcbits(wc->nw_src_mask) << OFPFW_NW_SRC_SHIFT;
> + ofpfw |= ofputil_netmask_to_wcbits(wc->nw_dst_mask) << OFPFW_NW_DST_SHIFT;
> + if (wc->wildcards & FWW_DL_VLAN_PCP) {
> + ofpfw |= OFPFW_DL_VLAN_PCP;
> + }
> + if (wc->wildcards & FWW_NW_TOS) {
> + ofpfw |= OFPFW_NW_TOS;
> + }
> + if (flow_format == NXFF_TUN_ID_FROM_COOKIE && wc->wildcards & FWW_TUN_ID) {
> + ofpfw |= NXFW_TUN_ID;
> + }
> +
> + /* Compose match structure. */
> + match->wildcards = htonl(ofpfw);
> + match->in_port = htons(rule->flow.in_port == ODPP_LOCAL ? OFPP_LOCAL
> + : rule->flow.in_port);
> + match->dl_vlan = rule->flow.dl_vlan;
> + match->dl_vlan_pcp = rule->flow.dl_vlan_pcp;
> + memcpy(match->dl_src, rule->flow.dl_src, ETH_ADDR_LEN);
> + memcpy(match->dl_dst, rule->flow.dl_dst, ETH_ADDR_LEN);
> + match->dl_type = rule->flow.dl_type;
> + match->nw_src = rule->flow.nw_src;
> + match->nw_dst = rule->flow.nw_dst;
> + match->nw_tos = rule->flow.nw_tos;
> + match->nw_proto = rule->flow.nw_proto;
> + match->tp_src = rule->flow.tp_src;
> + match->tp_dst = rule->flow.tp_dst;
> + memset(match->pad1, '\0', sizeof match->pad1);
> + memset(match->pad2, '\0', sizeof match->pad2);
> +}
> +
> /* XXX we should really use consecutive xids to avoid probabilistic
> * failures. */
> static inline uint32_t
> diff --git a/lib/ofp-util.h b/lib/ofp-util.h
> index d3dd692..1c02600 100644
> --- a/lib/ofp-util.h
> +++ b/lib/ofp-util.h
> @@ -23,6 +23,7 @@
> #include <stdint.h>
> #include "flow.h"
>
> +struct cls_rule;
> struct ofpbuf;
> struct ofp_action_header;
>
> @@ -31,6 +32,15 @@ struct ofp_action_header;
> ovs_be32 ofputil_wcbits_to_netmask(int wcbits);
> int ofputil_netmask_to_wcbits(ovs_be32 netmask);
>
> +/* Work with OpenFlow 1.0 ofp_match. */
> +void ofputil_cls_rule_from_match(const struct ofp_match *,
> + unsigned int priority, int flow_format,
> + uint64_t cookie, struct cls_rule *);
> +void ofputil_cls_rule_to_match(const struct cls_rule *, int flow_format,
> + struct ofp_match *);
> +void normalize_match(struct ofp_match *);
> +char *ofp_match_to_literal_string(const struct ofp_match *match);
> +
> /* OpenFlow protocol utility functions. */
> void *make_openflow(size_t openflow_len, uint8_t type, struct ofpbuf **);
> void *make_nxmsg(size_t openflow_len, uint32_t subtype, struct ofpbuf **);
> @@ -86,9 +96,6 @@ int validate_actions(const union ofp_action *, size_t n_actions,
> const struct flow *, int max_ports);
> bool action_outputs_to_port(const union ofp_action *, uint16_t port);
>
> -void normalize_match(struct ofp_match *);
> -char *ofp_match_to_literal_string(const struct ofp_match *match);
> -
> int ofputil_pull_actions(struct ofpbuf *, unsigned int actions_len,
> union ofp_action **, size_t *);
>
> diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
> index e5b565c..9e287e7 100644
> --- a/ofproto/ofproto.c
> +++ b/ofproto/ofproto.c
> @@ -3404,7 +3404,7 @@ put_ofp_flow_stats(struct ofconn *ofconn, struct rule *rule,
> ofs->length = htons(len);
> ofs->table_id = 0;
> ofs->pad = 0;
> - cls_rule_to_match(&rule->cr, ofconn->flow_format, &ofs->match);
> + ofputil_cls_rule_to_match(&rule->cr, ofconn->flow_format, &ofs->match);
> calc_flow_duration(rule->created, &ofs->duration_sec, &ofs->duration_nsec);
> ofs->cookie = rule->flow_cookie;
> ofs->priority = htons(rule->cr.priority);
> @@ -3443,7 +3443,8 @@ handle_flow_stats_request(struct ofconn *ofconn,
> struct cls_rule target;
> struct rule *rule;
>
> - cls_rule_from_match(&fsr->match, 0, NXFF_OPENFLOW10, 0, &target);
> + ofputil_cls_rule_from_match(&fsr->match, 0, NXFF_OPENFLOW10, 0,
> + &target);
> cls_cursor_init(&cursor, &ofconn->ofproto->cls, &target);
> CLS_CURSOR_FOR_EACH (rule, cr, &cursor) {
> put_ofp_flow_stats(ofconn, rule, fsr->out_port, &reply);
> @@ -3535,7 +3536,7 @@ flow_stats_ds(struct ofproto *ofproto, struct rule *rule, struct ds *results)
> size_t act_len = sizeof *rule->actions * rule->n_actions;
>
> query_stats(ofproto, rule, &packet_count, &byte_count);
> - cls_rule_to_match(&rule->cr, NXFF_OPENFLOW10, &match);
> + ofputil_cls_rule_to_match(&rule->cr, NXFF_OPENFLOW10, &match);
>
> ds_put_format(results, "duration=%llds, ",
> (time_msec() - rule->created) / 1000);
> @@ -3616,7 +3617,8 @@ handle_aggregate_stats_request(struct ofconn *ofconn,
> }
> request = (struct ofp_aggregate_stats_request *) osr->body;
>
> - cls_rule_from_match(&request->match, 0, NXFF_OPENFLOW10, 0, &target);
> + ofputil_cls_rule_from_match(&request->match, 0, NXFF_OPENFLOW10, 0,
> + &target);
>
> msg = start_ofp_stats_reply(osr, sizeof *reply);
> reply = append_ofp_stats_reply(sizeof *reply, ofconn, &msg);
> @@ -4172,8 +4174,8 @@ handle_ofpt_flow_mod(struct ofconn *ofconn, struct ofp_header *oh)
> }
>
> /* Translate the message. */
> - cls_rule_from_match(&ofm->match, ntohs(ofm->priority), ofconn->flow_format,
> - ofm->cookie, &fm.cr);
> + ofputil_cls_rule_from_match(&ofm->match, ntohs(ofm->priority),
> + ofconn->flow_format, ofm->cookie, &fm.cr);
> fm.cookie = ofm->cookie;
> fm.command = ntohs(ofm->command);
> fm.idle_timeout = ntohs(ofm->idle_timeout);
> @@ -4802,7 +4804,7 @@ compose_ofp_flow_removed(struct ofconn *ofconn, const struct rule *rule,
> struct ofpbuf *buf;
>
> ofr = make_openflow(sizeof *ofr, OFPT_FLOW_REMOVED, &buf);
> - cls_rule_to_match(&rule->cr, ofconn->flow_format, &ofr->match);
> + ofputil_cls_rule_to_match(&rule->cr, ofconn->flow_format, &ofr->match);
> ofr->cookie = rule->flow_cookie;
> ofr->priority = htons(rule->cr.priority);
> ofr->reason = reason;
> diff --git a/tests/test-classifier.c b/tests/test-classifier.c
> index 2de1eb3..fc1470e 100644
> --- a/tests/test-classifier.c
> +++ b/tests/test-classifier.c
> @@ -40,24 +40,23 @@
> #include <assert.h>
>
> /* Fields in a rule. */
> -#define CLS_FIELDS \
> - /* struct flow all-caps */ \
> - /* wildcard bit(s) member name name */ \
> - /* ----------------- ----------- -------- */ \
> - CLS_FIELD(NXFW_TUN_ID, tun_id, TUN_ID) \
> - CLS_FIELD(OFPFW_NW_SRC_MASK, nw_src, NW_SRC) \
> - CLS_FIELD(OFPFW_NW_DST_MASK, nw_dst, NW_DST) \
> - CLS_FIELD(OFPFW_IN_PORT, in_port, IN_PORT) \
> - CLS_FIELD(OFPFW_DL_VLAN, dl_vlan, DL_VLAN) \
> - CLS_FIELD(OFPFW_DL_TYPE, dl_type, DL_TYPE) \
> - CLS_FIELD(OFPFW_TP_SRC, tp_src, TP_SRC) \
> - CLS_FIELD(OFPFW_TP_DST, tp_dst, TP_DST) \
> - CLS_FIELD(OFPFW_DL_SRC, dl_src, DL_SRC) \
> - CLS_FIELD(OFPFW_DL_DST | FWW_ETH_MCAST, \
> - dl_dst, DL_DST) \
> - CLS_FIELD(OFPFW_NW_PROTO, nw_proto, NW_PROTO) \
> - CLS_FIELD(OFPFW_DL_VLAN_PCP, dl_vlan_pcp, DL_VLAN_PCP) \
> - CLS_FIELD(OFPFW_NW_TOS, nw_tos, NW_TOS)
> +#define CLS_FIELDS \
> + /* struct flow all-caps */ \
> + /* FWW_* bit(s) member name name */ \
> + /* -------------------------- ----------- -------- */ \
> + CLS_FIELD(FWW_TUN_ID, tun_id, TUN_ID) \
> + CLS_FIELD(0, nw_src, NW_SRC) \
> + CLS_FIELD(0, nw_dst, NW_DST) \
> + CLS_FIELD(FWW_IN_PORT, in_port, IN_PORT) \
> + CLS_FIELD(FWW_DL_VLAN, dl_vlan, DL_VLAN) \
> + CLS_FIELD(FWW_DL_TYPE, dl_type, DL_TYPE) \
> + CLS_FIELD(FWW_TP_SRC, tp_src, TP_SRC) \
> + CLS_FIELD(FWW_TP_DST, tp_dst, TP_DST) \
> + CLS_FIELD(FWW_DL_SRC, dl_src, DL_SRC) \
> + CLS_FIELD(FWW_DL_DST | FWW_ETH_MCAST, dl_dst, DL_DST) \
> + CLS_FIELD(FWW_NW_PROTO, nw_proto, NW_PROTO) \
> + CLS_FIELD(FWW_DL_VLAN_PCP, dl_vlan_pcp, DL_VLAN_PCP) \
> + CLS_FIELD(FWW_NW_TOS, nw_tos, NW_TOS)
>
> /* Field indexes.
> *
> @@ -73,7 +72,7 @@ enum {
> struct cls_field {
> int ofs; /* Offset in struct flow. */
> int len; /* Length in bytes. */
> - uint32_t wildcards; /* OFPFW_* bit or bits for this field. */
> + flow_wildcards_t wildcards; /* FWW_* bit or bits for this field. */
> const char *name; /* Name (for debugging). */
> };
>
> @@ -189,30 +188,24 @@ match(const struct cls_rule *wild, const struct flow *fixed)
>
> for (f_idx = 0; f_idx < CLS_N_FIELDS; f_idx++) {
> const struct cls_field *f = &cls_fields[f_idx];
> - void *wild_field = (char *) &wild->flow + f->ofs;
> - void *fixed_field = (char *) fixed + f->ofs;
> -
> - if ((wild->wc.wildcards & f->wildcards) == f->wildcards ||
> - !memcmp(wild_field, fixed_field, f->len)) {
> - /* Definite match. */
> - continue;
> + bool eq;
> +
> + if (f->wildcards) {
> + void *wild_field = (char *) &wild->flow + f->ofs;
> + void *fixed_field = (char *) fixed + f->ofs;
> + eq = ((wild->wc.wildcards & f->wildcards) == f->wildcards
> + || !memcmp(wild_field, fixed_field, f->len));
> + } else if (f_idx == CLS_F_IDX_NW_SRC) {
> + eq = !((fixed->nw_src ^ wild->flow.nw_src) & wild->wc.nw_src_mask);
> + } else if (f_idx == CLS_F_IDX_NW_DST) {
> + eq = !((fixed->nw_dst ^ wild->flow.nw_dst) & wild->wc.nw_dst_mask);
> + } else {
> + NOT_REACHED();
> }
>
> - if (wild->wc.wildcards & f->wildcards) {
> - uint32_t test = get_unaligned_u32(wild_field);
> - uint32_t ip = get_unaligned_u32(fixed_field);
> - uint32_t mask;
> - int shift;
> -
> - shift = (f_idx == CLS_F_IDX_NW_SRC
> - ? OFPFW_NW_SRC_SHIFT : OFPFW_NW_DST_SHIFT);
> - mask = ofputil_wcbits_to_netmask(wild->wc.wildcards) >> shift;
> - if (!((test ^ ip) & mask)) {
> - continue;
> - }
> + if (!eq) {
> + return false;
> }
> -
> - return false;
> }
> return true;
> }
> @@ -445,27 +438,26 @@ static struct test_rule *
> make_rule(int wc_fields, unsigned int priority, int value_pat)
> {
> const struct cls_field *f;
> - struct flow_wildcards wc;
> struct test_rule *rule;
> - uint32_t wildcards;
> - struct flow flow;
>
> - wildcards = 0;
> - memset(&flow, 0, sizeof flow);
> + rule = xzalloc(sizeof *rule);
> + cls_rule_init_catchall(&rule->cls_rule, wc_fields ? priority : UINT_MAX);
> for (f = &cls_fields[0]; f < &cls_fields[CLS_N_FIELDS]; f++) {
> int f_idx = f - cls_fields;
> - if (wc_fields & (1u << f_idx)) {
> - wildcards |= f->wildcards;
> + int value_idx = (value_pat & (1u << f_idx)) != 0;
> + memcpy((char *) &rule->cls_rule.flow + f->ofs,
> + values[f_idx][value_idx], f->len);
> +
> + if (f->wildcards) {
> + rule->cls_rule.wc.wildcards &= ~f->wildcards;
> + } else if (f_idx == CLS_F_IDX_NW_SRC) {
> + rule->cls_rule.wc.nw_src_mask = htonl(UINT32_MAX);
> + } else if (f_idx == CLS_F_IDX_NW_DST) {
> + rule->cls_rule.wc.nw_dst_mask = htonl(UINT32_MAX);
> } else {
> - int value_idx = (value_pat & (1u << f_idx)) != 0;
> - memcpy((char *) &flow + f->ofs, values[f_idx][value_idx], f->len);
> + NOT_REACHED();
> }
> }
> -
> - rule = xzalloc(sizeof *rule);
> - flow_wildcards_init(&wc, wildcards);
> - cls_rule_init(&flow, &wc, !wildcards ? UINT_MAX : priority,
> - &rule->cls_rule);
> return rule;
> }
>
> diff --git a/tests/test-flows.c b/tests/test-flows.c
> index b53d853..4ae198b 100644
> --- a/tests/test-flows.c
> +++ b/tests/test-flows.c
> @@ -70,7 +70,7 @@ main(int argc OVS_UNUSED, char *argv[])
>
> flow_extract(packet, 0, 1, &flow);
> cls_rule_init_exact(&flow, 0, &rule);
> - cls_rule_to_match(&rule, NXFF_OPENFLOW10, &extracted_match);
> + ofputil_cls_rule_to_match(&rule, NXFF_OPENFLOW10, &extracted_match);
>
> if (memcmp(&expected_match, &extracted_match, sizeof expected_match)) {
> char *exp_s = ofp_match_to_string(&expected_match, 2);
> diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
> index 8581c56..4e49fd6 100644
> --- a/utilities/ovs-ofctl.c
> +++ b/utilities/ovs-ofctl.c
> @@ -443,7 +443,7 @@ do_dump_flows(int argc, char *argv[])
>
> req = alloc_stats_request(sizeof *req, OFPST_FLOW, &request);
> parse_ofp_str(&pf, NULL, argc > 2 ? argv[2] : "");
> - cls_rule_to_match(&pf.rule, NXFF_OPENFLOW10, &req->match);
> + ofputil_cls_rule_to_match(&pf.rule, NXFF_OPENFLOW10, &req->match);
> memset(&req->pad, 0, sizeof req->pad);
> req->out_port = htons(pf.out_port);
>
> @@ -459,7 +459,7 @@ do_dump_aggregate(int argc, char *argv[])
>
> req = alloc_stats_request(sizeof *req, OFPST_AGGREGATE, &request);
> parse_ofp_str(&pf, NULL, argc > 2 ? argv[2] : "");
> - cls_rule_to_match(&pf.rule, NXFF_OPENFLOW10, &req->match);
> + ofputil_cls_rule_to_match(&pf.rule, NXFF_OPENFLOW10, &req->match);
> memset(&req->pad, 0, sizeof req->pad);
> req->out_port = htons(pf.out_port);
>
> --
> 1.7.1
>
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev_openvswitch.org
More information about the dev
mailing list