From: dlg Date: Fri, 26 Feb 2021 01:12:37 +0000 (+0000) Subject: add some helpers for working with ethernet addresses as uint64_t X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=cf89a71d9e248649a2adb23d76cc1cef5a7a7bba;p=openbsd add some helpers for working with ethernet addresses as uint64_t the main bits are ether_addr_to_e64 and ether_e64_to addr for loading an ethernet address into a uin64_t and visa versa. there's also some macros for testing if an address in a uint64_t is multicast, broadcast, anyaddr, or if it's an 802.1q reserved multicast group address. the reason for this functionality is once you have an ethernet address as a uint64_t, operations like compares, bit tests, and so on are fast and easy. tested on amd64 and sparc64 --- diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index 47d74957fdf..aeee969f26a 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_ethersubr.c,v 1.270 2021/02/06 13:15:37 bluhm Exp $ */ +/* $OpenBSD: if_ethersubr.c,v 1.271 2021/02/26 01:12:37 dlg Exp $ */ /* $NetBSD: if_ethersubr.c,v 1.19 1996/05/07 02:40:30 thorpej Exp $ */ /* @@ -996,3 +996,28 @@ ether_delmulti(struct ifreq *ifr, struct arpcom *ac) */ return (ENETRESET); } + +uint64_t +ether_addr_to_e64(const struct ether_addr *ea) +{ + uint64_t e64 = 0; + size_t i; + + for (i = 0; i < nitems(ea->ether_addr_octet); i++) { + e64 <<= 8; + e64 |= ea->ether_addr_octet[i]; + } + + return (e64); +} + +void +ether_e64_to_addr(struct ether_addr *ea, uint64_t e64) +{ + size_t i = nitems(ea->ether_addr_octet); + + do { + ea->ether_addr_octet[--i] = e64; + e64 >>= 8; + } while (i > 0); +} diff --git a/sys/netinet/if_ether.h b/sys/netinet/if_ether.h index 8ae1f2b3bce..04d92124df6 100644 --- a/sys/netinet/if_ether.h +++ b/sys/netinet/if_ether.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_ether.h,v 1.78 2020/07/22 02:16:02 dlg Exp $ */ +/* $OpenBSD: if_ether.h,v 1.79 2021/02/26 01:12:37 dlg Exp $ */ /* $NetBSD: if_ether.h,v 1.22 1996/05/11 13:00:00 mycroft Exp $ */ /* @@ -116,6 +116,24 @@ struct ether_vlan_header { (addr)[3] | (addr)[4] | (addr)[5]) == 0x00) #define ETHER_IS_EQ(a1, a2) (memcmp((a1), (a2), ETHER_ADDR_LEN) == 0) +/* + * It can be faster to work with ethernet addresses as a uint64_t. + * Provide some constants and functionality centrally to better + * support this. + */ + +#define ETH64_IS_MULTICAST(_e64) ((_e64) & 0x010000000000ULL) +#define ETH64_IS_BROADCAST(_e64) ((_e64) == 0xffffffffffffULL) +#define ETH64_IS_ANYADDR(_e64) ((_e64) == 0x000000000000ULL) + +#define ETH64_8021_RSVD_PREFIX 0x0180c2000000ULL +#define ETH64_8021_RSVD_MASK 0xfffffffffff0ULL +#define ETH64_IS_8021_RSVD(_e64) \ + (((_e64) & ETH64_8021_RSVD_MASK) == ETH64_8021_RSVD_PREFIX) + +/* + * Ethernet MTU constants. + */ #define ETHERMTU (ETHER_MAX_LEN - ETHER_HDR_LEN - ETHER_CRC_LEN) #define ETHERMIN (ETHER_MIN_LEN - ETHER_HDR_LEN - ETHER_CRC_LEN) @@ -272,6 +290,9 @@ const struct ether_brport * const struct ether_brport * ether_brport_get_locked(struct ifnet *); +uint64_t ether_addr_to_e64(const struct ether_addr *); +void ether_e64_to_addr(struct ether_addr *, uint64_t); + /* * Ethernet multicast address structure. There is one of these for each * multicast address or range of multicast addresses that we are supposed