diff options
| author | Ben Pfaff <blp@nicira.com> | 2010-11-11 10:46:23 -0800 |
|---|---|---|
| committer | Ben Pfaff <blp@nicira.com> | 2010-11-11 10:46:23 -0800 |
| commit | 1e37a2d75196c6e10ac078213ad94afb4f3e219a (patch) | |
| tree | 7cd21f2d63ac0b70ab7c91e68eb4aee748f445e9 /lib/nx-match.c | |
| parent | b6c9e612fa0801037c60339a931d29413e8fa08f (diff) | |
| download | openvswitch-1e37a2d75196c6e10ac078213ad94afb4f3e219a.tar.gz | |
Add support for matching Ethernet multicast frames.
Diffstat (limited to 'lib/nx-match.c')
| -rw-r--r-- | lib/nx-match.c | 69 |
1 files changed, 63 insertions, 6 deletions
diff --git a/lib/nx-match.c b/lib/nx-match.c index 8e918ebb4..12ea4fb8c 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -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: |
