summaryrefslogtreecommitdiff
path: root/lib/nx-match.c
diff options
context:
space:
mode:
authorBen Pfaff <blp@nicira.com>2010-11-11 10:46:23 -0800
committerBen Pfaff <blp@nicira.com>2010-11-11 10:46:23 -0800
commit1e37a2d75196c6e10ac078213ad94afb4f3e219a (patch)
tree7cd21f2d63ac0b70ab7c91e68eb4aee748f445e9 /lib/nx-match.c
parentb6c9e612fa0801037c60339a931d29413e8fa08f (diff)
downloadopenvswitch-1e37a2d75196c6e10ac078213ad94afb4f3e219a.tar.gz
Add support for matching Ethernet multicast frames.
Diffstat (limited to 'lib/nx-match.c')
-rw-r--r--lib/nx-match.c69
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: