From 9902f46a446cdf3338326457c4075d82c6e2768c Mon Sep 17 00:00:00 2001 From: kevans Date: Wed, 17 Apr 2019 17:18:43 +0000 Subject: [PATCH] net: adjust randomized address bits Give devices that need a MAC a 16-bit allocation out of the FreeBSD Foundation OUI range. Change the name ether_fakeaddr to ether_gen_addr now that we're dealing real MAC addresses with a real OUI rather than random locally-administered addresses. Reviewed by: bz, rgrimes Differential Revision: https://reviews.freebsd.org/D19587 --- sys/net/ethernet.h | 2 +- sys/net/ieee_oui.h | 11 +++++++++++ sys/net/if_bridge.c | 2 +- sys/net/if_ethersubr.c | 45 +++++++++++++++++++++++++++++++----------- sys/net/if_vxlan.c | 2 +- 5 files changed, 48 insertions(+), 14 deletions(-) diff --git a/sys/net/ethernet.h b/sys/net/ethernet.h index d331cb76a55..0753e31d323 100644 --- a/sys/net/ethernet.h +++ b/sys/net/ethernet.h @@ -422,7 +422,7 @@ void ether_vlan_mtap(struct bpf_if *, struct mbuf *, struct mbuf *ether_vlanencap(struct mbuf *, uint16_t); bool ether_8021q_frame(struct mbuf **mp, struct ifnet *ife, struct ifnet *p, uint16_t vid, uint8_t pcp); -void ether_fakeaddr(struct ether_addr *hwaddr); +void ether_gen_addr(struct ifnet *ifp, struct ether_addr *hwaddr); #ifdef _SYS_EVENTHANDLER_H_ /* new ethernet interface attached event */ diff --git a/sys/net/ieee_oui.h b/sys/net/ieee_oui.h index 566e5a3d4cd..f543f561e43 100644 --- a/sys/net/ieee_oui.h +++ b/sys/net/ieee_oui.h @@ -67,3 +67,14 @@ /* Allocate 20 bits to bhyve */ #define OUI_FREEBSD_BHYVE_LOW OUI_FREEBSD(0x000001) #define OUI_FREEBSD_BHYVE_HIGH OUI_FREEBSD(0x0fffff) + +/* + * Allocate 16 bits for a pool to give to various interfaces that need a + * generated address, but don't quite need to slice off a whole section of + * the OUI (e.g. cloned interfaces, one-off NICs of various vendors). + * + * ether_gen_addr should be used to generate an address from this pool. + */ +#define OUI_FREEBSD_GENERATED_MASK 0x10ffff +#define OUI_FREEBSD_GENERATED_LOW OUI_FREEBSD(0x100000) +#define OUI_FREEBSD_GENERATED_HIGH OUI_FREEBSD(OU_FREEBSD_GENERATED_MASK) diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c index 52232b35a57..f293f136f58 100644 --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -671,7 +671,7 @@ bridge_clone_create(struct if_clone *ifc, int unit, caddr_t params) getcredhostid(curthread->td_ucred, &hostid); do { if (fb || hostid == 0) { - ether_fakeaddr(&sc->sc_defaddr); + ether_gen_addr(ifp, &sc->sc_defaddr); } else { sc->sc_defaddr.octet[0] = 0x2; sc->sc_defaddr.octet[1] = (hostid >> 24) & 0xff; diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index d4a8601b583..1647d6ee903 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -42,11 +42,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -54,6 +56,7 @@ #include #include +#include #include #include #include @@ -85,6 +88,8 @@ #endif #include +#include + #ifdef CTASSERT CTASSERT(sizeof (struct ether_header) == ETHER_ADDR_LEN * 2 + 2); CTASSERT(sizeof (struct ether_addr) == ETHER_ADDR_LEN); @@ -1401,19 +1406,37 @@ ether_8021q_frame(struct mbuf **mp, struct ifnet *ife, struct ifnet *p, return (true); } +/* + * Allocate an address from the FreeBSD Foundation OUI. This uses a + * cryptographic hash function on the containing jail's UUID and the interface + * name to attempt to provide a unique but stable address. Pseudo-interfaces + * which require a MAC address should use this function to allocate + * non-locally-administered addresses. + */ void -ether_fakeaddr(struct ether_addr *hwaddr) +ether_gen_addr(struct ifnet *ifp, struct ether_addr *hwaddr) { - - /* - * Generate a convenient locally administered address, - * 'bsd' + random 24 low-order bits. 'b' is 0x62, which has the locally - * assigned bit set, and the broadcast/multicast bit clear. - */ - arc4rand(hwaddr->octet, ETHER_ADDR_LEN, 1); - hwaddr->octet[0] = 'b'; - hwaddr->octet[1] = 's'; - hwaddr->octet[2] = 'd'; +#define ETHER_GEN_ADDR_BUFSIZ HOSTUUIDLEN + IFNAMSIZ + 2 + SHA1_CTX ctx; + char buf[ETHER_GEN_ADDR_BUFSIZ]; + char uuid[HOSTUUIDLEN + 1]; + uint64_t addr; + int i, sz; + char digest[SHA1_RESULTLEN]; + + getcredhostuuid(curthread->td_ucred, uuid, sizeof(uuid)); + sz = snprintf(buf, ETHER_GEN_ADDR_BUFSIZ, "%s-%s", uuid, ifp->if_xname); + SHA1Init(&ctx); + SHA1Update(&ctx, buf, sz); + SHA1Final(digest, &ctx); + + addr = ((digest[0] << 16) | (digest[1] << 8) | digest[2]) & + OUI_FREEBSD_GENERATED_MASK; + addr = OUI_FREEBSD(addr); + for (i = 0; i < ETHER_ADDR_LEN; ++i) { + hwaddr->octet[i] = addr >> ((ETHER_ADDR_LEN - i - 1) * 8) & + 0xFF; + } } DECLARE_MODULE(ether, ether_mod, SI_SUB_INIT_IF, SI_ORDER_ANY); diff --git a/sys/net/if_vxlan.c b/sys/net/if_vxlan.c index 19b2f6dbe7e..81065bcec43 100644 --- a/sys/net/if_vxlan.c +++ b/sys/net/if_vxlan.c @@ -2754,7 +2754,7 @@ vxlan_clone_create(struct if_clone *ifc, int unit, caddr_t params) ifmedia_add(&sc->vxl_media, IFM_ETHER | IFM_AUTO, 0, NULL); ifmedia_set(&sc->vxl_media, IFM_ETHER | IFM_AUTO); - ether_fakeaddr(&sc->vxl_hwaddr); + ether_gen_addr(ifp, &sc->vxl_hwaddr); ether_ifattach(ifp, sc->vxl_hwaddr.octet); ifp->if_baudrate = 0; -- 2.45.2