mirror of
https://github.com/openvswitch/ovs
synced 2025-10-27 15:18:06 +00:00
Add support for matching Ethernet multicast frames.
This commit is contained in:
@@ -669,8 +669,12 @@ OFP_ASSERT(sizeof(struct nx_action_reg_load) == 24);
|
||||
*
|
||||
* Format: 48-bit Ethernet MAC address.
|
||||
*
|
||||
* Masking: Not maskable. */
|
||||
* Masking: The nxm_mask patterns 01:00:00:00:00:00 and FE:FF:FF:FF:FF:FF must
|
||||
* be supported for NXM_OF_ETH_DST_W (as well as the trivial patterns that
|
||||
* are all-0-bits or all-1-bits). Support for other patterns and for masking
|
||||
* of NXM_OF_ETH_SRC is optional. */
|
||||
#define NXM_OF_ETH_DST NXM_HEADER (0x0000, 1, 6)
|
||||
#define NXM_OF_ETH_DST_W NXM_HEADER_W(0x0000, 1, 6)
|
||||
#define NXM_OF_ETH_SRC NXM_HEADER (0x0000, 2, 6)
|
||||
|
||||
/* Packet's Ethernet type.
|
||||
|
||||
@@ -142,7 +142,7 @@ 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);
|
||||
flow_wildcards_init(&rule->wc, OVSFW_ALL | FWW_ALL);
|
||||
rule->priority = priority;
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ cls_rule_set_dl_src(struct cls_rule *rule, const uint8_t 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;
|
||||
rule->wc.wildcards &= ~(OFPFW_DL_DST | FWW_ETH_MCAST);
|
||||
memcpy(rule->flow.dl_dst, dl_dst, ETH_ADDR_LEN);
|
||||
}
|
||||
|
||||
@@ -828,7 +828,14 @@ flow_equal_except(const struct flow *a, const struct flow *b,
|
||||
&& (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 || eth_addr_equals(a->dl_dst, b->dl_dst))
|
||||
&& (wc & OFPFW_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));
|
||||
@@ -869,7 +876,11 @@ zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards)
|
||||
memset(flow->dl_src, 0, sizeof flow->dl_src);
|
||||
}
|
||||
if (wc & OFPFW_DL_DST) {
|
||||
memset(flow->dl_dst, 0, sizeof flow->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) {
|
||||
flow->nw_proto = 0;
|
||||
|
||||
@@ -291,6 +291,12 @@ flow_from_match(const struct ofp_match *match, int flow_format,
|
||||
flow->tun_id = htonl(ntohll(cookie) >> 32);
|
||||
}
|
||||
}
|
||||
if (wildcards & OFPFW_DL_DST) {
|
||||
/* OpenFlow 1.0 OFPFW_DL_DST covers the whole Ethernet destination, but
|
||||
* internally to OVS it excludes the multicast bit, which has to be set
|
||||
* separately with FWW_ETH_MCAST. */
|
||||
wildcards |= FWW_ETH_MCAST;
|
||||
}
|
||||
flow_wildcards_init(wc, wildcards);
|
||||
|
||||
flow->nw_src = match->nw_src;
|
||||
@@ -377,7 +383,7 @@ flow_nw_bits_to_mask(uint32_t wildcards, int shift)
|
||||
static inline uint32_t
|
||||
flow_wildcards_normalize(uint32_t wildcards)
|
||||
{
|
||||
wildcards &= wildcards & OVSFW_ALL;
|
||||
wildcards &= wildcards & (OVSFW_ALL | FWW_ALL);
|
||||
if (wildcards & (0x20 << OFPFW_NW_SRC_SHIFT)) {
|
||||
wildcards &= ~(0x1f << OFPFW_NW_SRC_SHIFT);
|
||||
}
|
||||
|
||||
29
lib/flow.h
29
lib/flow.h
@@ -93,14 +93,27 @@ flow_hash(const struct flow *flow, uint32_t basis)
|
||||
return hash_bytes(flow, FLOW_SIG_SIZE, basis);
|
||||
}
|
||||
|
||||
/* Set to 1 in the 'wildcards' member of struct flow_wildcards 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.
|
||||
/* Open vSwitch internal-only wildcard bits.
|
||||
*
|
||||
* This is used only internally to Open vSwitch--it never appears in the wire
|
||||
* protocol. */
|
||||
* 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)
|
||||
BUILD_ASSERT_DECL(!(FWW_REGS & OVSFW_ALL)); /* Avoid collisions. */
|
||||
|
||||
/* 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. Both OFPFW_DL_DST and
|
||||
* FWW_ETH_MCAST have to be set to wildcard the entire Ethernet destination
|
||||
* address.) */
|
||||
#define FWW_ETH_MCAST (1u << 30)
|
||||
|
||||
/* Avoid collisions. */
|
||||
#define FWW_ALL (FWW_REGS | FWW_ETH_MCAST)
|
||||
BUILD_ASSERT_DECL(!(FWW_ALL & OVSFW_ALL));
|
||||
|
||||
/* Information on wildcards for a flow, as a supplement to "struct flow".
|
||||
*
|
||||
@@ -110,7 +123,7 @@ BUILD_ASSERT_DECL(!(FWW_REGS & OVSFW_ALL)); /* Avoid collisions. */
|
||||
* 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_REGS are set to 0.
|
||||
* 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
|
||||
@@ -127,7 +140,7 @@ BUILD_ASSERT_DECL(!(FWW_REGS & OVSFW_ALL)); /* Avoid collisions. */
|
||||
* other members can be correctly predicted based on 'wildcards' alone.
|
||||
*/
|
||||
struct flow_wildcards {
|
||||
uint32_t wildcards; /* enum ofp_flow_wildcards. */
|
||||
uint32_t wildcards; /* OFPFW_* | OVSFW_* | FWW_*. */
|
||||
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. */
|
||||
|
||||
@@ -72,6 +72,16 @@ static struct nxm_field nxm_fields[N_NXM_FIELDS] = {
|
||||
/* Hash table of 'nxm_fields'. */
|
||||
static struct hmap all_nxm_fields = HMAP_INITIALIZER(&all_nxm_fields);
|
||||
|
||||
/* Possible masks for NXM_OF_ETH_DST_W. */
|
||||
static const uint8_t eth_all_0s[ETH_ADDR_LEN]
|
||||
= {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
static const uint8_t eth_all_1s[ETH_ADDR_LEN]
|
||||
= {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
static const uint8_t eth_mcast_1[ETH_ADDR_LEN]
|
||||
= {0x01, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
static const uint8_t eth_mcast_0[ETH_ADDR_LEN]
|
||||
= {0xfe, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
|
||||
static void
|
||||
nxm_init(void)
|
||||
{
|
||||
@@ -178,8 +188,34 @@ parse_nxm_entry(struct cls_rule *rule, const struct nxm_field *f,
|
||||
|
||||
/* Ethernet header. */
|
||||
case NFI_NXM_OF_ETH_DST:
|
||||
memcpy(flow->dl_dst, value, ETH_ADDR_LEN);
|
||||
return 0;
|
||||
if ((wc->wildcards & (OFPFW_DL_DST | FWW_ETH_MCAST))
|
||||
!= (OFPFW_DL_DST | FWW_ETH_MCAST)) {
|
||||
return NXM_DUP_TYPE;
|
||||
} else {
|
||||
wc->wildcards &= ~(OFPFW_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)) {
|
||||
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;
|
||||
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);
|
||||
memcpy(flow->dl_dst, value, ETH_ADDR_LEN);
|
||||
return 0;
|
||||
} else {
|
||||
return NXM_BAD_MASK;
|
||||
}
|
||||
case NFI_NXM_OF_ETH_SRC:
|
||||
memcpy(flow->dl_src, value, ETH_ADDR_LEN);
|
||||
return 0;
|
||||
@@ -480,7 +516,6 @@ nxm_put_64(struct ofpbuf *b, uint32_t header, ovs_be64 value)
|
||||
ofpbuf_put(b, &value, sizeof value);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
nxm_put_eth(struct ofpbuf *b, uint32_t header,
|
||||
const uint8_t value[ETH_ADDR_LEN])
|
||||
@@ -489,6 +524,29 @@ nxm_put_eth(struct ofpbuf *b, uint32_t header,
|
||||
ofpbuf_put(b, value, ETH_ADDR_LEN);
|
||||
}
|
||||
|
||||
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:
|
||||
break;
|
||||
case OFPFW_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);
|
||||
break;
|
||||
case FWW_ETH_MCAST:
|
||||
nxm_put_header(b, NXM_OF_ETH_DST_W);
|
||||
ofpbuf_put(b, value, ETH_ADDR_LEN);
|
||||
ofpbuf_put(b, eth_mcast_0, ETH_ADDR_LEN);
|
||||
break;
|
||||
case 0:
|
||||
nxm_put_eth(b, NXM_OF_ETH_DST, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
nx_put_match(struct ofpbuf *b, const struct cls_rule *cr)
|
||||
{
|
||||
@@ -509,9 +567,7 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr)
|
||||
}
|
||||
|
||||
/* Ethernet. */
|
||||
if (!(wc & OFPFW_DL_DST)) {
|
||||
nxm_put_eth(b, NXM_OF_ETH_DST, flow->dl_dst);
|
||||
}
|
||||
nxm_put_eth_dst(b, wc, flow->dl_dst);
|
||||
if (!(wc & OFPFW_DL_SRC)) {
|
||||
nxm_put_eth(b, NXM_OF_ETH_SRC, flow->dl_src);
|
||||
}
|
||||
@@ -907,6 +963,7 @@ nxm_read_field(const struct nxm_field *src, const struct flow *flow)
|
||||
#error
|
||||
#endif
|
||||
|
||||
case NFI_NXM_OF_ETH_DST_W:
|
||||
case NFI_NXM_OF_VLAN_TCI_W:
|
||||
case NFI_NXM_OF_IP_SRC_W:
|
||||
case NFI_NXM_OF_IP_DST_W:
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
/* NXM_ bit OFPFW_* bit dl_type nw_proto */
|
||||
/* ------------ -------------- ----------- ------------- */
|
||||
DEFINE_FIELD (OF_IN_PORT, OFPFW_IN_PORT, 0, 0)
|
||||
DEFINE_FIELD (OF_ETH_DST, OFPFW_DL_DST, 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)
|
||||
|
||||
@@ -36,6 +36,10 @@ NXM_OF_IN_PORT(fffe)
|
||||
|
||||
# eth dst
|
||||
NXM_OF_ETH_DST(0002e30f80a4)
|
||||
NXM_OF_ETH_DST_W(010000000000/010000000000)
|
||||
NXM_OF_ETH_DST_W(000000000000/010000000000)
|
||||
NXM_OF_ETH_DST_W(0002e30f80a4/ffffffffffff)
|
||||
NXM_OF_ETH_DST_W(0002e30f80a4/feffffffffff)
|
||||
|
||||
# eth src
|
||||
NXM_OF_ETH_SRC(020898456ddb)
|
||||
@@ -137,6 +141,10 @@ NXM_OF_IN_PORT(fffe)
|
||||
|
||||
# eth dst
|
||||
NXM_OF_ETH_DST(0002e30f80a4)
|
||||
NXM_OF_ETH_DST_W(010000000000/010000000000)
|
||||
NXM_OF_ETH_DST_W(000000000000/010000000000)
|
||||
NXM_OF_ETH_DST(0002e30f80a4)
|
||||
NXM_OF_ETH_DST_W(0002e30f80a4/feffffffffff)
|
||||
|
||||
# eth src
|
||||
NXM_OF_ETH_SRC(020898456ddb)
|
||||
|
||||
@@ -51,7 +51,8 @@
|
||||
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, dl_dst, DL_DST) \
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user