From 66642cb40b12594c62f3d3037f1e4efa528416b7 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Tue, 23 Nov 2010 10:06:28 -0800 Subject: [PATCH] nx-match: Implement support for arbitrary VLAN TCI masks. Since the Nicira Extended Match was specified nicira-ext.h has claimed that arbitrary masks are allowed, but in fact only certain masks were actually implemented. This commit implements general masking for the 802.1Q VLAN TCI field. --- lib/classifier.c | 121 ++++++++++++++++++---------------------- lib/classifier.h | 6 +- lib/flow.c | 37 +++++++----- lib/flow.h | 19 +++---- lib/nx-match.c | 88 ++++++++++++----------------- lib/odp-util.c | 17 +----- lib/ofp-parse.c | 8 ++- lib/ofp-util.c | 83 ++++++++++++++++++++++----- ofproto/ofproto-sflow.c | 4 +- ofproto/ofproto.c | 24 ++++---- tests/ovs-ofctl.at | 11 ++-- tests/test-classifier.c | 28 ++++------ vswitchd/bridge.c | 38 ++++++------- 13 files changed, 248 insertions(+), 236 deletions(-) diff --git a/lib/classifier.c b/lib/classifier.c index 7c3eb8528..52a77d717 100644 --- a/lib/classifier.c +++ b/lib/classifier.c @@ -139,84 +139,77 @@ cls_rule_set_dl_dst(struct cls_rule *rule, const uint8_t dl_dst[ETH_ADDR_LEN]) memcpy(rule->flow.dl_dst, dl_dst, ETH_ADDR_LEN); } -bool +void cls_rule_set_dl_tci(struct cls_rule *rule, ovs_be16 tci) { - return cls_rule_set_dl_tci_masked(rule, tci, htons(0xffff)); + cls_rule_set_dl_tci_masked(rule, tci, htons(0xffff)); } -bool +void cls_rule_set_dl_tci_masked(struct cls_rule *rule, ovs_be16 tci, ovs_be16 mask) { - switch (ntohs(mask)) { - case 0xffff: - if (tci == htons(0)) { - /* Match only packets that have no 802.1Q header. */ - 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 &= ~(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; - } else { - /* Impossible. */ - return false; - } - - case 0x1fff: - if (!(tci & htons(VLAN_CFI))) { - return false; - } 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 |= FWW_DL_VLAN_PCP; - rule->flow.dl_vlan_pcp = 0; - return true; - } - - case 0xf000: - if (!(tci & htons(VLAN_CFI))) { - return false; - } 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 |= FWW_DL_VLAN; - rule->flow.dl_vlan = 0; - return true; - } - - case 0x0000: - /* Match anything. */ - rule->wc.wildcards |= FWW_DL_VLAN | FWW_DL_VLAN_PCP; - rule->flow.dl_vlan = htons(0); - rule->flow.dl_vlan_pcp = 0; - return true; + rule->flow.vlan_tci = tci & mask; + rule->wc.vlan_tci_mask = mask; +} - default: - return false; +/* Modifies 'rule' so that the VLAN VID is wildcarded. If the PCP is already + * wildcarded, then 'rule' will match a packet regardless of whether it has an + * 802.1Q header or not. */ +void +cls_rule_set_any_vid(struct cls_rule *rule) +{ + if (rule->wc.vlan_tci_mask & htons(VLAN_PCP_MASK)) { + rule->wc.vlan_tci_mask &= ~htons(VLAN_VID_MASK); + rule->flow.vlan_tci &= ~htons(VLAN_VID_MASK); + } else { + cls_rule_set_dl_tci_masked(rule, htons(0), htons(0)); } } +/* Modifies 'rule' depending on 'dl_vlan': + * + * - If 'dl_vlan' is htons(OFP_VLAN_NONE), makes 'rule' match only packets + * without an 802.1Q header. + * + * - Otherwise, makes 'rule' match only packets with an 802.1Q header whose + * VID equals the low 12 bits of 'dl_vlan'. + */ void cls_rule_set_dl_vlan(struct cls_rule *rule, ovs_be16 dl_vlan) { - if (dl_vlan != htons(OFP_VLAN_NONE)) { + if (dl_vlan == htons(OFP_VLAN_NONE)) { + cls_rule_set_dl_tci(rule, htons(0)); + } else { dl_vlan &= htons(VLAN_VID_MASK); + rule->flow.vlan_tci &= ~htons(VLAN_VID_MASK); + rule->flow.vlan_tci |= htons(VLAN_CFI) | dl_vlan; + rule->wc.vlan_tci_mask |= htons(VLAN_VID_MASK | VLAN_CFI); } +} - rule->wc.wildcards &= ~FWW_DL_VLAN; - rule->flow.dl_vlan = dl_vlan; +/* Modifies 'rule' so that the VLAN PCP is wildcarded. If the VID is already + * wildcarded, then 'rule' will match a packet regardless of whether it has an + * 802.1Q header or not. */ +void +cls_rule_set_any_pcp(struct cls_rule *rule) +{ + if (rule->wc.vlan_tci_mask & htons(VLAN_VID_MASK)) { + rule->wc.vlan_tci_mask &= ~htons(VLAN_PCP_MASK); + rule->flow.vlan_tci &= ~htons(VLAN_PCP_MASK); + } else { + cls_rule_set_dl_tci_masked(rule, htons(0), htons(0)); + } } +/* Modifies 'rule' so that it matches only packets with an 802.1Q header whose + * PCP equals the low 3 bits of 'dl_vlan_pcp'. */ void cls_rule_set_dl_vlan_pcp(struct cls_rule *rule, uint8_t dl_vlan_pcp) { - rule->wc.wildcards &= ~FWW_DL_VLAN_PCP; - rule->flow.dl_vlan_pcp = dl_vlan_pcp & 0x07; + dl_vlan_pcp &= 0x07; + rule->flow.vlan_tci &= ~htons(VLAN_PCP_MASK); + rule->flow.vlan_tci |= htons((dl_vlan_pcp << VLAN_PCP_SHIFT) | VLAN_CFI); + rule->wc.vlan_tci_mask |= htons(VLAN_CFI | VLAN_PCP_MASK); } void @@ -768,7 +761,7 @@ flow_equal_except(const struct flow *a, const struct flow *b, const flow_wildcards_t wc = wildcards->wildcards; int i; - BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 37 + FLOW_N_REGS * 4); + BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 36 + FLOW_N_REGS * 4); for (i = 0; i < FLOW_N_REGS; i++) { if ((a->regs[i] ^ b->regs[i]) & wildcards->reg_masks[i]) { @@ -780,7 +773,7 @@ flow_equal_except(const struct flow *a, const struct flow *b, && !((a->nw_src ^ b->nw_src) & wildcards->nw_src_mask) && !((a->nw_dst ^ b->nw_dst) & wildcards->nw_dst_mask) && (wc & FWW_IN_PORT || a->in_port == b->in_port) - && (wc & FWW_DL_VLAN || a->dl_vlan == b->dl_vlan) + && !((a->vlan_tci ^ b->vlan_tci) & wildcards->vlan_tci_mask) && (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) @@ -795,7 +788,6 @@ flow_equal_except(const struct flow *a, const struct flow *b, && (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)); } @@ -805,7 +797,7 @@ zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards) const flow_wildcards_t wc = wildcards->wildcards; int i; - BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 37 + 4 * FLOW_N_REGS); + BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 36 + 4 * FLOW_N_REGS); for (i = 0; i < FLOW_N_REGS; i++) { flow->regs[i] &= wildcards->reg_masks[i]; @@ -818,9 +810,7 @@ zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards) if (wc & FWW_IN_PORT) { flow->in_port = 0; } - if (wc & FWW_DL_VLAN) { - flow->dl_vlan = 0; - } + flow->vlan_tci &= wildcards->vlan_tci_mask; if (wc & FWW_DL_TYPE) { flow->dl_type = 0; } @@ -843,9 +833,6 @@ zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards) if (wc & FWW_NW_PROTO) { flow->nw_proto = 0; } - if (wc & FWW_DL_VLAN_PCP) { - flow->dl_vlan_pcp = 0; - } if (wc & FWW_NW_TOS) { flow->nw_tos = 0; } diff --git a/lib/classifier.h b/lib/classifier.h index e4b7f5f83..2dc0bdf91 100644 --- a/lib/classifier.h +++ b/lib/classifier.h @@ -78,10 +78,12 @@ void cls_rule_set_in_port(struct cls_rule *, uint16_t odp_port); void cls_rule_set_dl_type(struct cls_rule *, ovs_be16); void cls_rule_set_dl_src(struct cls_rule *, const uint8_t[6]); void cls_rule_set_dl_dst(struct cls_rule *, const uint8_t[6]); -bool cls_rule_set_dl_tci(struct cls_rule *, ovs_be16 tci); -bool cls_rule_set_dl_tci_masked(struct cls_rule *, +void cls_rule_set_dl_tci(struct cls_rule *, ovs_be16 tci); +void cls_rule_set_dl_tci_masked(struct cls_rule *, ovs_be16 tci, ovs_be16 mask); +void cls_rule_set_any_vid(struct cls_rule *); void cls_rule_set_dl_vlan(struct cls_rule *, ovs_be16); +void cls_rule_set_any_pcp(struct cls_rule *); void cls_rule_set_dl_vlan_pcp(struct cls_rule *, uint8_t); void cls_rule_set_tp_src(struct cls_rule *, ovs_be16); void cls_rule_set_tp_dst(struct cls_rule *, ovs_be16); diff --git a/lib/flow.c b/lib/flow.c index 8146519dc..26d03fd43 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -88,8 +88,7 @@ parse_vlan(struct ofpbuf *b, struct flow *flow) if (b->size >= sizeof(struct qtag_prefix) + sizeof(ovs_be16)) { struct qtag_prefix *qp = ofpbuf_pull(b, sizeof *qp); - flow->dl_vlan = qp->tci & htons(VLAN_VID_MASK); - flow->dl_vlan_pcp = vlan_tci_to_pcp(qp->tci); + flow->vlan_tci = qp->tci | htons(VLAN_CFI); } } @@ -149,7 +148,6 @@ flow_extract(struct ofpbuf *packet, ovs_be32 tun_id, uint16_t in_port, memset(flow, 0, sizeof *flow); flow->tun_id = tun_id; flow->in_port = in_port; - flow->dl_vlan = htons(OFP_VLAN_NONE); packet->l2 = b.data; packet->l3 = NULL; @@ -165,7 +163,7 @@ flow_extract(struct ofpbuf *packet, ovs_be32 tun_id, uint16_t in_port, memcpy(flow->dl_src, eth->eth_src, ETH_ADDR_LEN); memcpy(flow->dl_dst, eth->eth_dst, ETH_ADDR_LEN); - /* dl_type, dl_vlan, dl_vlan_pcp. */ + /* dl_type, vlan_tci. */ ofpbuf_pull(&b, ETH_ADDR_LEN * 2); if (eth->eth_type == htons(ETH_TYPE_VLAN)) { parse_vlan(&b, flow); @@ -261,18 +259,21 @@ flow_to_string(const struct flow *flow) void flow_format(struct ds *ds, const struct flow *flow) { - ds_put_format(ds, "tunnel%08"PRIx32":in_port%04"PRIx16 - ":vlan%"PRIu16":pcp%"PRIu8 - " mac"ETH_ADDR_FMT"->"ETH_ADDR_FMT + ds_put_format(ds, "tunnel%08"PRIx32":in_port%04"PRIx16":tci(", + ntohl(flow->tun_id), flow->in_port); + if (flow->vlan_tci) { + ds_put_format(ds, "vlan%"PRIu16",pcp%d", + vlan_tci_to_vid(flow->vlan_tci), + vlan_tci_to_pcp(flow->vlan_tci)); + } else { + ds_put_char(ds, '0'); + } + ds_put_format(ds, ") mac"ETH_ADDR_FMT"->"ETH_ADDR_FMT " type%04"PRIx16 " proto%"PRIu8 " tos%"PRIu8 " ip"IP_FMT"->"IP_FMT " port%"PRIu16"->%"PRIu16, - ntohl(flow->tun_id), - flow->in_port, - ntohs(flow->dl_vlan), - flow->dl_vlan_pcp, ETH_ADDR_ARGS(flow->dl_src), ETH_ADDR_ARGS(flow->dl_dst), ntohs(flow->dl_type), @@ -302,6 +303,7 @@ flow_wildcards_init_catchall(struct flow_wildcards *wc) wc->nw_src_mask = htonl(0); wc->nw_dst_mask = htonl(0); memset(wc->reg_masks, 0, sizeof wc->reg_masks); + wc->vlan_tci_mask = htons(0); } /* Initializes 'wc' as an exact-match set of wildcards; that is, 'wc' does not @@ -313,6 +315,7 @@ flow_wildcards_init_exact(struct flow_wildcards *wc) wc->nw_src_mask = htonl(UINT32_MAX); wc->nw_dst_mask = htonl(UINT32_MAX); memset(wc->reg_masks, 0xff, sizeof wc->reg_masks); + wc->vlan_tci_mask = htons(UINT16_MAX); } /* Returns true if 'wc' is exact-match, false if 'wc' wildcards any bits or @@ -324,7 +327,8 @@ flow_wildcards_is_exact(const struct flow_wildcards *wc) if (wc->wildcards || wc->nw_src_mask != htonl(UINT32_MAX) - || wc->nw_dst_mask != htonl(UINT32_MAX)) { + || wc->nw_dst_mask != htonl(UINT32_MAX) + || wc->vlan_tci_mask != htons(UINT16_MAX)) { return false; } @@ -353,6 +357,7 @@ flow_wildcards_combine(struct flow_wildcards *dst, for (i = 0; i < FLOW_N_REGS; i++) { dst->reg_masks[i] = src1->reg_masks[i] & src2->reg_masks[i]; } + dst->vlan_tci_mask = src1->vlan_tci_mask & src2->vlan_tci_mask; } /* Returns a hash of the wildcards in 'wc'. */ @@ -362,7 +367,7 @@ flow_wildcards_hash(const struct flow_wildcards *wc) /* 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); + BUILD_ASSERT_DECL(sizeof *wc == 16 + FLOW_N_REGS * 4); return hash_bytes(wc, sizeof *wc, 0); } @@ -376,7 +381,8 @@ flow_wildcards_equal(const struct flow_wildcards *a, if (a->wildcards != b->wildcards || a->nw_src_mask != b->nw_src_mask - || a->nw_dst_mask != b->nw_dst_mask) { + || a->nw_dst_mask != b->nw_dst_mask + || a->vlan_tci_mask != b->vlan_tci_mask) { return false; } @@ -405,7 +411,8 @@ flow_wildcards_has_extra(const struct flow_wildcards *a, 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); + || (a->nw_dst_mask & b->nw_dst_mask) != b->nw_dst_mask + || (a->vlan_tci_mask & b->vlan_tci_mask) != b->vlan_tci_mask); } static bool diff --git a/lib/flow.h b/lib/flow.h index f772936ec..a0dc7a18d 100644 --- a/lib/flow.h +++ b/lib/flow.h @@ -41,21 +41,20 @@ struct flow { ovs_be32 nw_src; /* IP source address. */ ovs_be32 nw_dst; /* IP destination address. */ uint16_t in_port; /* Input switch port. */ - ovs_be16 dl_vlan; /* Input VLAN. */ + ovs_be16 vlan_tci; /* If 802.1Q, TCI | VLAN_CFI; otherwise 0. */ ovs_be16 dl_type; /* Ethernet frame type. */ ovs_be16 tp_src; /* TCP/UDP source port. */ ovs_be16 tp_dst; /* TCP/UDP destination port. */ uint8_t dl_src[6]; /* Ethernet source address. */ uint8_t dl_dst[6]; /* Ethernet destination address. */ uint8_t nw_proto; /* IP protocol or low 8 bits of ARP opcode. */ - uint8_t dl_vlan_pcp; /* Input VLAN priority. */ uint8_t nw_tos; /* IP ToS (DSCP field, 6 bits). */ }; /* Assert that there are FLOW_SIG_SIZE bytes of significant data in "struct * flow", followed by FLOW_PAD_SIZE bytes of padding. */ -#define FLOW_SIG_SIZE (37 + FLOW_N_REGS * 4) -#define FLOW_PAD_SIZE 3 +#define FLOW_SIG_SIZE (36 + FLOW_N_REGS * 4) +#define FLOW_PAD_SIZE 0 BUILD_ASSERT_DECL(offsetof(struct flow, nw_tos) == FLOW_SIG_SIZE - 1); BUILD_ASSERT_DECL(sizeof(((struct flow *)0)->nw_tos) == 1); BUILD_ASSERT_DECL(sizeof(struct flow) == FLOW_SIG_SIZE + FLOW_PAD_SIZE); @@ -99,7 +98,6 @@ 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 */ @@ -108,14 +106,14 @@ typedef unsigned int OVS_BITWISE flow_wildcards_t; #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)) +#define FWW_NW_TOS ((OVS_FORCE flow_wildcards_t) (1 << 1)) /* No OFPFW_* bits, but they do have corresponding OVSFW_* bits. */ -#define FWW_TUN_ID ((OVS_FORCE flow_wildcards_t) (1 << 10)) +#define FWW_TUN_ID ((OVS_FORCE flow_wildcards_t) (1 << 8)) /* No corresponding OFPFW_* or OVSFW_* bits. */ -#define FWW_ETH_MCAST ((OVS_FORCE flow_wildcards_t) (1 << 11)) +#define FWW_VLAN_TCI ((OVS_FORCE flow_wildcards_t) (1 << 9) +#define FWW_ETH_MCAST ((OVS_FORCE flow_wildcards_t) (1 << 10)) /* multicast bit only */ -#define FWW_ALL ((OVS_FORCE flow_wildcards_t) (((1 << 12)) - 1)) +#define FWW_ALL ((OVS_FORCE flow_wildcards_t) (((1 << 11)) - 1)) /* Information on wildcards for a flow, as a supplement to "struct flow". * @@ -126,6 +124,7 @@ struct flow_wildcards { 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. */ + ovs_be16 vlan_tci_mask; /* 1-bit in each significant vlan_tci bit. */ }; void flow_wildcards_init_catchall(struct flow_wildcards *); diff --git a/lib/nx-match.c b/lib/nx-match.c index 94d7de9ed..6c8ee1341 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -140,18 +140,6 @@ nxm_field_bits(uint32_t header) /* nx_pull_match() and helpers. */ -static int -parse_tci(struct cls_rule *rule, ovs_be16 tci, ovs_be16 mask) -{ - 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; - } -} - static int parse_nx_reg(const struct nxm_field *f, struct flow *flow, struct flow_wildcards *wc, @@ -226,11 +214,20 @@ parse_nxm_entry(struct cls_rule *rule, const struct nxm_field *f, /* 802.1Q header. */ case NFI_NXM_OF_VLAN_TCI: - return parse_tci(rule, get_unaligned_u16(value), htons(UINT16_MAX)); - + if (wc->vlan_tci_mask) { + return NXM_DUP_TYPE; + } else { + cls_rule_set_dl_tci(rule, get_unaligned_u16(value)); + return 0; + } case NFI_NXM_OF_VLAN_TCI_W: - return parse_tci(rule, get_unaligned_u16(value), - get_unaligned_u16(mask)); + if (wc->vlan_tci_mask) { + return NXM_DUP_TYPE; + } else { + cls_rule_set_dl_tci_masked(rule, get_unaligned_u16(value), + get_unaligned_u16(mask)); + return 0; + } /* IP header. */ case NFI_NXM_OF_IP_TOS: @@ -478,6 +475,23 @@ nxm_put_16w(struct ofpbuf *b, uint32_t header, ovs_be16 value, ovs_be16 mask) ofpbuf_put(b, &mask, sizeof mask); } +static void +nxm_put_16m(struct ofpbuf *b, uint32_t header, ovs_be16 value, ovs_be16 mask) +{ + switch (mask) { + case 0: + break; + + case CONSTANT_HTONS(UINT16_MAX): + nxm_put_16(b, header, value); + break; + + default: + nxm_put_16w(b, NXM_MAKE_WILD_HEADER(header), value, mask); + break; + } +} + static void nxm_put_32(struct ofpbuf *b, uint32_t header, ovs_be32 value) { @@ -500,7 +514,7 @@ nxm_put_32m(struct ofpbuf *b, uint32_t header, ovs_be32 value, ovs_be32 mask) case 0: break; - case UINT32_MAX: + case CONSTANT_HTONL(UINT32_MAX): nxm_put_32(b, header, value); break; @@ -554,7 +568,6 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr) 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; int match_len; int i; @@ -577,32 +590,9 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr) } /* 802.1Q. */ - vid = flow->dl_vlan & htons(VLAN_VID_MASK); - pcp = htons((flow->dl_vlan_pcp << VLAN_PCP_SHIFT) & VLAN_PCP_MASK); - switch (wc & (FWW_DL_VLAN | FWW_DL_VLAN_PCP)) { - case FWW_DL_VLAN | FWW_DL_VLAN_PCP: - break; - 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 FWW_DL_VLAN_PCP: - if (flow->dl_vlan == htons(OFP_VLAN_NONE)) { - nxm_put_16(b, NXM_OF_VLAN_TCI, 0); - } else { - nxm_put_16w(b, NXM_OF_VLAN_TCI_W, vid | htons(VLAN_CFI), - htons(VLAN_VID_MASK | VLAN_CFI)); - } - break; - case 0: - if (flow->dl_vlan == htons(OFP_VLAN_NONE)) { - nxm_put_16(b, NXM_OF_VLAN_TCI, 0); - } else { - nxm_put_16(b, NXM_OF_VLAN_TCI, vid | pcp | htons(VLAN_CFI)); - } - break; - } + nxm_put_16m(b, NXM_OF_VLAN_TCI, flow->vlan_tci, cr->wc.vlan_tci_mask); + /* L3. */ if (!(wc & FWW_DL_TYPE) && flow->dl_type == htons(ETH_TYPE_IP)) { /* IP. */ if (!(wc & FWW_NW_TOS)) { @@ -902,13 +892,7 @@ nxm_read_field(const struct nxm_field *src, const struct flow *flow) return ntohs(flow->dl_type); case NFI_NXM_OF_VLAN_TCI: - if (flow->dl_vlan == htons(OFP_VLAN_NONE)) { - return 0; - } else { - return (ntohs(flow->dl_vlan & htons(VLAN_VID_MASK)) - | ((flow->dl_vlan_pcp << VLAN_PCP_SHIFT) & VLAN_PCP_MASK) - | VLAN_CFI); - } + return ntohs(flow->vlan_tci); case NFI_NXM_OF_IP_TOS: return flow->nw_tos; @@ -1000,9 +984,7 @@ nxm_execute_reg_move(const struct nx_action_reg_move *action, if (NXM_IS_NX_REG(dst->header)) { flow->regs[NXM_NX_REG_IDX(dst->header)] = new_data; } else if (dst->header == NXM_OF_VLAN_TCI) { - ovs_be16 vlan_tci = htons(new_data & VLAN_CFI ? new_data : 0); - flow->dl_vlan = htons(vlan_tci_to_vid(vlan_tci)); - flow->dl_vlan_pcp = vlan_tci_to_pcp(vlan_tci); + flow->vlan_tci = htons(new_data); } else if (dst->header == NXM_NX_TUN_ID) { flow->tun_id = htonl(new_data); } else { diff --git a/lib/odp-util.c b/lib/odp-util.c index e57a7cb09..0c8caabb0 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -167,14 +167,7 @@ odp_flow_key_from_flow(struct odp_flow_key *key, const struct flow *flow) key->nw_src = flow->nw_src; key->nw_dst = flow->nw_dst; key->in_port = flow->in_port; - if (flow->dl_vlan == htons(OFP_VLAN_NONE)) { - key->dl_tci = htons(0); - } else { - uint16_t vid = flow->dl_vlan & htons(VLAN_VID_MASK); - uint16_t pcp = htons((flow->dl_vlan_pcp << VLAN_PCP_SHIFT) - & VLAN_PCP_MASK); - key->dl_tci = vid | pcp | htons(ODP_TCI_PRESENT); - } + key->dl_tci = flow->vlan_tci; key->dl_type = flow->dl_type; key->tp_src = flow->tp_src; key->tp_dst = flow->tp_dst; @@ -192,13 +185,7 @@ odp_flow_key_to_flow(const struct odp_flow_key *key, struct flow *flow) flow->nw_src = key->nw_src; flow->nw_dst = key->nw_dst; flow->in_port = key->in_port; - if (key->dl_tci) { - flow->dl_vlan = htons(vlan_tci_to_vid(key->dl_tci)); - flow->dl_vlan_pcp = vlan_tci_to_pcp(key->dl_tci); - } else { - flow->dl_vlan = htons(OFP_VLAN_NONE); - flow->dl_vlan_pcp = 0; - } + flow->vlan_tci = key->dl_tci; flow->dl_type = key->dl_type; flow->tp_src = key->tp_src; flow->tp_dst = key->tp_dst; diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index 1ec0a00ee..490c9dff3 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -383,8 +383,8 @@ parse_protocol(const char *name, const struct protocol **p_out) #define FIELDS \ 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_VLAN, "dl_vlan", 0) \ + FIELD(F_DL_VLAN_PCP, "dl_vlan_pcp", 0) \ 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) \ @@ -580,6 +580,10 @@ parse_ofp_str(struct parsed_flow *pf, struct ofpbuf *actions, char *string) cls_rule_set_nw_src_masked(&pf->rule, 0, 0); } else if (f->index == F_NW_DST) { cls_rule_set_nw_dst_masked(&pf->rule, 0, 0); + } else if (f->index == F_DL_VLAN) { + cls_rule_set_any_vid(&pf->rule); + } else if (f->index == F_DL_VLAN_PCP) { + cls_rule_set_any_pcp(&pf->rule); } else { NOT_REACHED(); } diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 208eabb5c..cc38105b5 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -72,7 +72,6 @@ ofputil_netmask_to_wcbits(ovs_be32 netmask) * 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) \ @@ -109,6 +108,7 @@ ofputil_cls_rule_from_match(const struct ofp_match *match, { struct flow_wildcards *wc = &rule->wc; unsigned int ofpfw; + ovs_be16 vid, pcp; /* Initialize rule->priority. */ ofpfw = ntohl(match->wildcards); @@ -117,9 +117,6 @@ ofputil_cls_rule_from_match(const struct ofp_match *match, /* 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; } @@ -141,13 +138,11 @@ ofputil_cls_rule_from_match(const struct ofp_match *match, wc->wildcards |= FWW_ETH_MCAST; } - /* Initialize rule->flow. */ + /* Initialize most of 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; @@ -156,6 +151,49 @@ ofputil_cls_rule_from_match(const struct ofp_match *match, rule->flow.nw_tos = match->nw_tos; rule->flow.nw_proto = match->nw_proto; + /* Translate VLANs. */ + vid = match->dl_vlan & htons(VLAN_VID_MASK); + pcp = htons((match->dl_vlan_pcp << VLAN_PCP_SHIFT) & VLAN_PCP_MASK); + switch (ofpfw & (OFPFW_DL_VLAN | OFPFW_DL_VLAN_PCP)) { + case OFPFW_DL_VLAN | OFPFW_DL_VLAN_PCP: + /* Wildcard everything. */ + rule->flow.vlan_tci = htons(0); + rule->wc.vlan_tci_mask = htons(0); + break; + + case OFPFW_DL_VLAN_PCP: + if (match->dl_vlan == htons(OFP_VLAN_NONE)) { + /* Match only packets without 802.1Q header. */ + rule->flow.vlan_tci = htons(0); + rule->wc.vlan_tci_mask = htons(0xffff); + } else { + /* Wildcard PCP, specific VID. */ + rule->flow.vlan_tci = vid | htons(VLAN_CFI); + rule->wc.vlan_tci_mask = htons(VLAN_VID_MASK | VLAN_CFI); + } + break; + + case OFPFW_DL_VLAN: + /* Wildcard VID, specific PCP. */ + rule->flow.vlan_tci = pcp | htons(VLAN_CFI); + rule->wc.vlan_tci_mask = htons(VLAN_PCP_MASK | VLAN_CFI); + break; + + case 0: + if (match->dl_vlan == htons(OFP_VLAN_NONE)) { + /* This case is odd, since we can't have a specific PCP without an + * 802.1Q header. However, older versions of OVS treated this as + * matching packets withut an 802.1Q header, so we do here too. */ + rule->flow.vlan_tci = htons(0); + rule->wc.vlan_tci_mask = htons(0xffff); + } else { + /* Specific VID and PCP. */ + rule->flow.vlan_tci = vid | pcp | htons(VLAN_CFI); + rule->wc.vlan_tci_mask = htons(0xffff); + } + break; + } + /* Clean up. */ cls_rule_zero_wildcarded_fields(rule); } @@ -173,13 +211,10 @@ ofputil_cls_rule_to_match(const struct cls_rule *rule, int flow_format, const struct flow_wildcards *wc = &rule->wc; unsigned int ofpfw; - /* Figure out OpenFlow wildcards. */ + /* Figure out most 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; } @@ -187,12 +222,32 @@ ofputil_cls_rule_to_match(const struct cls_rule *rule, int flow_format, ofpfw |= NXFW_TUN_ID; } - /* Compose match structure. */ + /* Translate VLANs. */ + match->dl_vlan = htons(0); + match->dl_vlan_pcp = 0; + if (rule->wc.vlan_tci_mask == htons(0)) { + ofpfw |= OFPFW_DL_VLAN | OFPFW_DL_VLAN_PCP; + } else if (rule->wc.vlan_tci_mask & htons(VLAN_CFI) + && !(rule->flow.vlan_tci & htons(VLAN_CFI))) { + match->dl_vlan = htons(OFP_VLAN_NONE); + } else { + if (!(rule->wc.vlan_tci_mask & htons(VLAN_VID_MASK))) { + ofpfw |= OFPFW_DL_VLAN; + } else { + match->dl_vlan = htons(vlan_tci_to_vid(rule->flow.vlan_tci)); + } + + if (!(rule->wc.vlan_tci_mask & htons(VLAN_PCP_MASK))) { + ofpfw |= OFPFW_DL_VLAN_PCP; + } else { + match->dl_vlan_pcp = vlan_tci_to_pcp(rule->flow.vlan_tci); + } + } + + /* Compose most of the 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; diff --git a/ofproto/ofproto-sflow.c b/ofproto/ofproto-sflow.c index 04e834705..87abef97b 100644 --- a/ofproto/ofproto-sflow.c +++ b/ofproto/ofproto-sflow.c @@ -554,8 +554,8 @@ ofproto_sflow_received(struct ofproto_sflow *os, struct odp_msg *msg) /* Add extended switch element. */ memset(&switchElem, 0, sizeof(switchElem)); switchElem.tag = SFLFLOW_EX_SWITCH; - switchElem.flowType.sw.src_vlan = ntohs(flow.dl_vlan); - switchElem.flowType.sw.src_priority = -1; /* XXX */ + switchElem.flowType.sw.src_vlan = vlan_tci_to_vid(flow.vlan_tci); + switchElem.flowType.sw.src_priority = vlan_tci_to_pcp(flow.vlan_tci); /* Initialize the output VLAN and priority to be the same as the input, but these fields can be overriden below if affected by an action. */ switchElem.flowType.sw.dst_vlan = switchElem.flowType.sw.src_vlan; diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 285775729..c2b38b2b0 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -2785,15 +2785,12 @@ xlate_set_queue_action(struct action_xlate_ctx *ctx, static void xlate_set_dl_tci(struct action_xlate_ctx *ctx) { - ovs_be16 dl_vlan = ctx->flow.dl_vlan; - uint8_t dl_vlan_pcp = ctx->flow.dl_vlan_pcp; - - if (dl_vlan == htons(OFP_VLAN_NONE)) { + ovs_be16 tci = ctx->flow.vlan_tci; + if (!(tci & htons(VLAN_CFI))) { odp_actions_add(ctx->out, ODPAT_STRIP_VLAN); } else { union odp_action *oa = odp_actions_add(ctx->out, ODPAT_SET_DL_TCI); - oa->dl_tci.tci = htons(ntohs(dl_vlan & htons(VLAN_VID_MASK)) - | (dl_vlan_pcp << VLAN_PCP_SHIFT)); + oa->dl_tci.tci = tci & ~htons(VLAN_CFI); } } @@ -2801,12 +2798,11 @@ static void xlate_reg_move_action(struct action_xlate_ctx *ctx, const struct nx_action_reg_move *narm) { - ovs_be16 old_vlan = ctx->flow.dl_vlan; - uint8_t old_pcp = ctx->flow.dl_vlan_pcp; + ovs_be16 old_tci = ctx->flow.vlan_tci; nxm_execute_reg_move(narm, &ctx->flow); - if (ctx->flow.dl_vlan != old_vlan || ctx->flow.dl_vlan_pcp != old_pcp) { + if (ctx->flow.vlan_tci != old_tci) { xlate_set_dl_tci(ctx); } } @@ -2896,18 +2892,20 @@ do_xlate_actions(const union ofp_action *in, size_t n_in, break; case OFPAT_SET_VLAN_VID: - ctx->flow.dl_vlan = ia->vlan_vid.vlan_vid; + ctx->flow.vlan_tci &= ~htons(VLAN_VID_MASK); + ctx->flow.vlan_tci |= ia->vlan_vid.vlan_vid | htons(VLAN_CFI); xlate_set_dl_tci(ctx); break; case OFPAT_SET_VLAN_PCP: - ctx->flow.dl_vlan_pcp = ia->vlan_pcp.vlan_pcp; + ctx->flow.vlan_tci &= ~htons(VLAN_PCP_MASK); + ctx->flow.vlan_tci |= htons( + (ia->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT) | VLAN_CFI); xlate_set_dl_tci(ctx); break; case OFPAT_STRIP_VLAN: - ctx->flow.dl_vlan = htons(OFP_VLAN_NONE); - ctx->flow.dl_vlan_pcp = 0; + ctx->flow.vlan_tci = htons(0); xlate_set_dl_tci(ctx); break; diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at index 88d50a507..793e1d5a5 100644 --- a/tests/ovs-ofctl.at +++ b/tests/ovs-ofctl.at @@ -56,10 +56,10 @@ NXM_OF_VLAN_TCI(f009) NXM_OF_VLAN_TCI(f009) NXM_OF_VLAN_TCI(f009) NXM_OF_VLAN_TCI(0000) # Packets without 802.1Q header. NXM_OF_VLAN_TCI(3123) # Packets with VID=123, PCP=1. -NXM_OF_VLAN_TCI(0123) # Does not make sense. +NXM_OF_VLAN_TCI(0123) # Does not make sense (but supported anyway) NXM_OF_VLAN_TCI_W(1123/1fff) # Packets with VID=123, any PCP. NXM_OF_VLAN_TCI_W(f000/f000) # Packets with any VID, PCP=7. -NXM_OF_VLAN_TCI_W(0000/e000) # No 802.1Q or with VID=0 (not yet supported) +NXM_OF_VLAN_TCI_W(0000/e000) # No 802.1Q or with VID=0 # IP TOS NXM_OF_ETH_TYPE(0800) NXM_OF_IP_TOS(f0) @@ -134,8 +134,7 @@ NXM_NX_TUN_ID(00000000abcdef01) NXM_NX_REG0(acebdf56) NXM_NX_REG0_W(a0e0d050/f0f0f0f0) ]) -AT_CHECK([ovs-ofctl parse-nx-match < nx-match.txt], [0], [stdout]) -AT_CHECK([cat stdout], [0], [dnl +AT_CHECK([ovs-ofctl parse-nx-match < nx-match.txt], [0], [dnl # in port @@ -162,10 +161,10 @@ NXM_OF_VLAN_TCI(f009) nx_pull_match() returned error 44010105 NXM_OF_VLAN_TCI(0000) NXM_OF_VLAN_TCI(3123) -nx_pull_match() returned error 44010100 +NXM_OF_VLAN_TCI(0123) NXM_OF_VLAN_TCI_W(1123/1fff) NXM_OF_VLAN_TCI_W(f000/f000) -nx_pull_match() returned error 44010100 +NXM_OF_VLAN_TCI_W(0000/e000) # IP TOS NXM_OF_ETH_TYPE(0800), NXM_OF_IP_TOS(f0) diff --git a/tests/test-classifier.c b/tests/test-classifier.c index e8434f0a7..461074d6f 100644 --- a/tests/test-classifier.c +++ b/tests/test-classifier.c @@ -48,14 +48,13 @@ 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(0, vlan_tci, VLAN_TCI) \ 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. @@ -199,6 +198,9 @@ match(const struct cls_rule *wild, const struct flow *fixed) 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 if (f_idx == CLS_F_IDX_VLAN_TCI) { + eq = !((fixed->vlan_tci ^ wild->flow.vlan_tci) + & wild->wc.vlan_tci_mask); } else { NOT_REACHED(); } @@ -246,8 +248,7 @@ static ovs_be32 nw_dst_values[] = { CONSTANT_HTONL(0xc0a80002), CONSTANT_HTONL(0xc0a04455) }; static ovs_be32 tun_id_values[] = { 0, 0xffff0000 }; static uint16_t in_port_values[] = { 1, ODPP_LOCAL }; -static ovs_be16 dl_vlan_values[] = { CONSTANT_HTONS(101), CONSTANT_HTONS(0) }; -static uint8_t dl_vlan_pcp_values[] = { 7, 0 }; +static ovs_be16 vlan_tci_values[] = { CONSTANT_HTONS(101), CONSTANT_HTONS(0) }; static ovs_be16 dl_type_values[] = { CONSTANT_HTONS(ETH_TYPE_IP), CONSTANT_HTONS(ETH_TYPE_ARP) }; static ovs_be16 tp_src_values[] = { CONSTANT_HTONS(49362), @@ -271,11 +272,8 @@ init_values(void) values[CLS_F_IDX_IN_PORT][0] = &in_port_values[0]; values[CLS_F_IDX_IN_PORT][1] = &in_port_values[1]; - values[CLS_F_IDX_DL_VLAN][0] = &dl_vlan_values[0]; - values[CLS_F_IDX_DL_VLAN][1] = &dl_vlan_values[1]; - - values[CLS_F_IDX_DL_VLAN_PCP][0] = &dl_vlan_pcp_values[0]; - values[CLS_F_IDX_DL_VLAN_PCP][1] = &dl_vlan_pcp_values[1]; + values[CLS_F_IDX_VLAN_TCI][0] = &vlan_tci_values[0]; + values[CLS_F_IDX_VLAN_TCI][1] = &vlan_tci_values[1]; values[CLS_F_IDX_DL_SRC][0] = dl_src_values[0]; values[CLS_F_IDX_DL_SRC][1] = dl_src_values[1]; @@ -309,8 +307,7 @@ init_values(void) #define N_NW_DST_VALUES ARRAY_SIZE(nw_dst_values) #define N_TUN_ID_VALUES ARRAY_SIZE(tun_id_values) #define N_IN_PORT_VALUES ARRAY_SIZE(in_port_values) -#define N_DL_VLAN_VALUES ARRAY_SIZE(dl_vlan_values) -#define N_DL_VLAN_PCP_VALUES ARRAY_SIZE(dl_vlan_pcp_values) +#define N_VLAN_TCI_VALUES ARRAY_SIZE(vlan_tci_values) #define N_DL_TYPE_VALUES ARRAY_SIZE(dl_type_values) #define N_TP_SRC_VALUES ARRAY_SIZE(tp_src_values) #define N_TP_DST_VALUES ARRAY_SIZE(tp_dst_values) @@ -323,8 +320,7 @@ init_values(void) N_NW_DST_VALUES * \ N_TUN_ID_VALUES * \ N_IN_PORT_VALUES * \ - N_DL_VLAN_VALUES * \ - N_DL_VLAN_PCP_VALUES * \ + N_VLAN_TCI_VALUES * \ N_DL_TYPE_VALUES * \ N_TP_SRC_VALUES * \ N_TP_DST_VALUES * \ @@ -358,9 +354,7 @@ compare_classifiers(struct classifier *cls, struct tcls *tcls) flow.nw_dst = nw_dst_values[get_value(&x, N_NW_DST_VALUES)]; flow.tun_id = tun_id_values[get_value(&x, N_TUN_ID_VALUES)]; flow.in_port = in_port_values[get_value(&x, N_IN_PORT_VALUES)]; - flow.dl_vlan = dl_vlan_values[get_value(&x, N_DL_VLAN_VALUES)]; - flow.dl_vlan_pcp = dl_vlan_pcp_values[get_value(&x, - N_DL_VLAN_PCP_VALUES)]; + flow.vlan_tci = vlan_tci_values[get_value(&x, N_VLAN_TCI_VALUES)]; flow.dl_type = dl_type_values[get_value(&x, N_DL_TYPE_VALUES)]; flow.tp_src = tp_src_values[get_value(&x, N_TP_SRC_VALUES)]; flow.tp_dst = tp_dst_values[get_value(&x, N_TP_DST_VALUES)]; @@ -465,6 +459,8 @@ make_rule(int wc_fields, unsigned int priority, int value_pat) 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 if (f_idx == CLS_F_IDX_VLAN_TCI) { + rule->cls_rule.wc.vlan_tci_mask = htons(UINT16_MAX); } else { NOT_REACHED(); } diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index 13e897fd5..e7bc5ab33 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -2168,7 +2168,8 @@ set_dst(struct dst *p, const struct flow *flow, { p->vlan = (out_port->vlan >= 0 ? OFP_VLAN_NONE : in_port->vlan >= 0 ? in_port->vlan - : ntohs(flow->dl_vlan)); + : flow->vlan_tci == 0 ? OFP_VLAN_NONE + : vlan_tci_to_vid(flow->vlan_tci)); return choose_output_iface(out_port, flow->dl_src, &p->dp_ifidx, tags); } @@ -2270,9 +2271,15 @@ compose_dsts(const struct bridge *br, const struct flow *flow, uint16_t vlan, struct dst dsts[], tag_type *tags, uint16_t *nf_output_iface) { mirror_mask_t mirrors = in_port->src_mirrors; + int flow_vlan; struct dst *dst = dsts; size_t i; + flow_vlan = vlan_tci_to_vid(flow->vlan_tci); + if (flow_vlan == 0) { + flow_vlan = OFP_VLAN_NONE; + } + if (out_port == FLOOD_PORT) { /* XXX use ODP_FLOOD if no vlans or bonding. */ /* XXX even better, define each VLAN as a datapath port group */ @@ -2308,7 +2315,6 @@ compose_dsts(const struct bridge *br, const struct flow *flow, uint16_t vlan, if (port_includes_vlan(port, m->out_vlan) && set_dst(dst, flow, in_port, port, tags)) { - int flow_vlan; if (port->vlan < 0) { dst->vlan = m->out_vlan; @@ -2323,10 +2329,6 @@ compose_dsts(const struct bridge *br, const struct flow *flow, uint16_t vlan, * tagging tags place. This is necessary because * dst->vlan is the final vlan, after removing implicit * tags. */ - flow_vlan = ntohs(flow->dl_vlan); - if (flow_vlan == 0) { - flow_vlan = OFP_VLAN_NONE; - } if (port == in_port && dst->vlan == flow_vlan) { /* Don't send out input port on same VLAN. */ continue; @@ -2339,7 +2341,7 @@ compose_dsts(const struct bridge *br, const struct flow *flow, uint16_t vlan, mirrors &= mirrors - 1; } - partition_dsts(dsts, dst - dsts, ntohs(flow->dl_vlan)); + partition_dsts(dsts, dst - dsts, flow_vlan); return dst - dsts; } @@ -2368,7 +2370,10 @@ compose_actions(struct bridge *br, const struct flow *flow, uint16_t vlan, n_dsts = compose_dsts(br, flow, vlan, in_port, out_port, dsts, tags, nf_output_iface); - cur_vlan = ntohs(flow->dl_vlan); + cur_vlan = vlan_tci_to_vid(flow->vlan_tci); + if (cur_vlan == 0) { + cur_vlan = OFP_VLAN_NONE; + } for (p = dsts; p < &dsts[n_dsts]; p++) { union odp_action *a; if (p->vlan != cur_vlan) { @@ -2377,7 +2382,7 @@ compose_actions(struct bridge *br, const struct flow *flow, uint16_t vlan, } else { a = odp_actions_add(actions, ODPAT_SET_DL_TCI); a->dl_tci.tci = htons(p->vlan & VLAN_VID_MASK); - a->dl_tci.tci |= htons(flow->dl_vlan_pcp << VLAN_PCP_SHIFT); + a->dl_tci.tci |= flow->vlan_tci & htons(VLAN_PCP_MASK); } cur_vlan = p->vlan; } @@ -2393,25 +2398,16 @@ compose_actions(struct bridge *br, const struct flow *flow, uint16_t vlan, static int flow_get_vlan(struct bridge *br, const struct flow *flow, struct port *in_port, bool have_packet) { - /* Note that dl_vlan of 0 and of OFP_VLAN_NONE both mean that the packet - * belongs to VLAN 0, so we should treat both cases identically. (In the - * former case, the packet has an 802.1Q header that specifies VLAN 0, - * presumably to allow a priority to be specified. In the latter case, the - * packet does not have any 802.1Q header.) */ - int vlan = ntohs(flow->dl_vlan); - if (vlan == OFP_VLAN_NONE) { - vlan = 0; - } + int vlan = vlan_tci_to_vid(flow->vlan_tci); if (in_port->vlan >= 0) { if (vlan) { /* XXX support double tagging? */ if (have_packet) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); - VLOG_WARN_RL(&rl, "bridge %s: dropping VLAN %"PRIu16" tagged " + VLOG_WARN_RL(&rl, "bridge %s: dropping VLAN %d tagged " "packet received on port %s configured with " "implicit VLAN %"PRIu16, - br->name, ntohs(flow->dl_vlan), - in_port->name, in_port->vlan); + br->name, vlan, in_port->name, in_port->vlan); } return -1; } -- 2.43.0