From 3b4d8ad3070ad30da9cf52d4f2abf792bc07f20d Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Tue, 29 May 2012 11:07:16 -0700 Subject: [PATCH] packets: Adds ethernet-matching helper functions With OpenFlow 1.1 requiring arbitrary ethernet match support, it simplifies other code if we have some extra helper functions. This patch adds eth_mask_is_exact(mask), eth_addr_bitand(src, mask, dst), eth_addr_equal_except(a, b, mask) and eth_format_masked(eth, mask, output). Signed-off-by: Joe Stringer Signed-off-by: Ben Pfaff --- AUTHORS | 1 + lib/meta-flow.c | 5 +---- lib/packets.c | 22 ++++++++++++++++++++++ lib/packets.h | 22 ++++++++++++++++++++++ 4 files changed, 46 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index 6e344ab0..2ea91109 100644 --- a/AUTHORS +++ b/AUTHORS @@ -33,6 +33,7 @@ Jean Tourrilhes jt@hpl.hp.com Jeremy Stribling strib@nicira.com Jesse Gross jesse@nicira.com Joe Perches joe@perches.com +Joe Stringer joe@wand.net.nz Jun Nakajima jun.nakajima@intel.com Justin Pettit jpettit@nicira.com Keith Amidon keith@nicira.com diff --git a/lib/meta-flow.c b/lib/meta-flow.c index 8b60b35f..9387d3a4 100644 --- a/lib/meta-flow.c +++ b/lib/meta-flow.c @@ -2273,10 +2273,7 @@ mf_format(const struct mf_field *mf, break; case MFS_ETHERNET: - ds_put_format(s, ETH_ADDR_FMT, ETH_ADDR_ARGS(value->mac)); - if (mask) { - ds_put_format(s, "/"ETH_ADDR_FMT, ETH_ADDR_ARGS(mask->mac)); - } + eth_format_masked(value->mac, mask->mac, s); break; case MFS_IPV4: diff --git a/lib/packets.c b/lib/packets.c index 84ca590b..b3851280 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -148,6 +148,28 @@ eth_from_hex(const char *hex, struct ofpbuf **packetp) return NULL; } +void +eth_format_masked(const uint8_t eth[ETH_ADDR_LEN], + const uint8_t mask[ETH_ADDR_LEN], struct ds *s) +{ + ds_put_format(s, ETH_ADDR_FMT, ETH_ADDR_ARGS(eth)); + if (mask) { + ds_put_format(s, "/"ETH_ADDR_FMT, ETH_ADDR_ARGS(mask)); + } +} + +void +eth_addr_bitand(const uint8_t src[ETH_ADDR_LEN], + const uint8_t mask[ETH_ADDR_LEN], + uint8_t dst[ETH_ADDR_LEN]) +{ + int i; + + for (i = 0; i < ETH_ADDR_LEN; i++) { + dst[i] = src[i] & mask[i]; + } +} + /* Given the IP netmask 'netmask', returns the number of bits of the IP address * that it specifies, that is, the number of 1-bits in 'netmask'. 'netmask' * must be a CIDR netmask (see ip_is_cidr()). */ diff --git a/lib/packets.h b/lib/packets.h index f9e5bb6c..00c2b75b 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -64,6 +64,12 @@ static inline bool eth_addr_is_zero(const uint8_t ea[6]) { return !(ea[0] | ea[1] | ea[2] | ea[3] | ea[4] | ea[5]); } + +static inline int eth_mask_is_exact(const uint8_t ea[ETH_ADDR_LEN]) +{ + return (ea[0] & ea[1] & ea[2] & ea[3] & ea[4] & ea[5]) == 0xff; +} + static inline int eth_addr_compare_3way(const uint8_t a[ETH_ADDR_LEN], const uint8_t b[ETH_ADDR_LEN]) { @@ -74,6 +80,17 @@ static inline bool eth_addr_equals(const uint8_t a[ETH_ADDR_LEN], { return !eth_addr_compare_3way(a, b); } +static inline bool eth_addr_equal_except(const uint8_t a[ETH_ADDR_LEN], + const uint8_t b[ETH_ADDR_LEN], + const uint8_t mask[ETH_ADDR_LEN]) +{ + return (((a[0] ^ b[0]) & mask[0]) + || ((a[1] ^ b[1]) & mask[1]) + || ((a[2] ^ b[2]) & mask[2]) + || ((a[3] ^ b[3]) & mask[3]) + || ((a[4] ^ b[4]) & mask[4]) + || ((a[5] ^ b[5]) & mask[5])); +} static inline uint64_t eth_addr_to_uint64(const uint8_t ea[ETH_ADDR_LEN]) { return (((uint64_t) ea[0] << 40) @@ -136,6 +153,11 @@ void eth_push_vlan(struct ofpbuf *, ovs_be16 tci); void eth_pop_vlan(struct ofpbuf *); const char *eth_from_hex(const char *hex, struct ofpbuf **packetp); +void eth_format_masked(const uint8_t eth[ETH_ADDR_LEN], + const uint8_t mask[ETH_ADDR_LEN], struct ds *s); +void eth_addr_bitand(const uint8_t src[ETH_ADDR_LEN], + const uint8_t mask[ETH_ADDR_LEN], + uint8_t dst[ETH_ADDR_LEN]); /* Example: * -- 2.30.2