add some helpers for working with ethernet addresses as uint64_t
authordlg <dlg@openbsd.org>
Fri, 26 Feb 2021 01:12:37 +0000 (01:12 +0000)
committerdlg <dlg@openbsd.org>
Fri, 26 Feb 2021 01:12:37 +0000 (01:12 +0000)
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

sys/net/if_ethersubr.c
sys/netinet/if_ether.h

index 47d7495..aeee969 100644 (file)
@@ -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);
+}
index 8ae1f2b..04d9212 100644 (file)
@@ -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