2
0
mirror of https://github.com/openvswitch/ovs synced 2025-10-23 14:57:06 +00:00

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.
This commit is contained in:
Ben Pfaff
2010-11-23 10:06:28 -08:00
parent 2d8b103caa
commit 66642cb40b
13 changed files with 249 additions and 237 deletions

View File

@@ -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;
}
rule->flow.vlan_tci = tci & mask;
rule->wc.vlan_tci_mask = mask;
}
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;
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;
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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 *);

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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
<any>
# 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)

View File

@@ -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();
}

View File

@@ -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;
}