Index: sys/net/ethernet.h =================================================================== --- sys/net/ethernet.h +++ sys/net/ethernet.h @@ -422,7 +422,9 @@ 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_masked(struct ifnet *ifp, struct ether_addr *hwaddr, + uint32_t mask); +void ether_gen_addr(struct ifnet *ifp, struct ether_addr *hwaddr); #ifdef _SYS_EVENTHANDLER_H_ /* new ethernet interface attached event */ Index: sys/net/ieee_oui.h =================================================================== --- sys/net/ieee_oui.h +++ 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) Index: sys/net/if_bridge.c =================================================================== --- sys/net/if_bridge.c +++ sys/net/if_bridge.c @@ -671,7 +671,7 @@ 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; Index: sys/net/if_ethersubr.c =================================================================== --- sys/net/if_ethersubr.c +++ sys/net/if_ethersubr.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -54,6 +55,7 @@ #include #include +#include #include #include #include @@ -85,6 +87,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 +1405,55 @@ return (true); } +/* + * Allocate a random address from the FreeBSD Foundation OUI. The mask should + * indicate the specific sub-allocation that the address should come out of. + * This is intended to centralize the various 'random' generation methods using + * non-locally-administered addresses to avoid trampling on potentially + * conflicting environments that consumers of this will be deployed in. + */ void -ether_fakeaddr(struct ether_addr *hwaddr) +ether_gen_addr_masked(struct ifnet *ifp, struct ether_addr *hwaddr, + uint32_t lomask) { +#define ETHER_GEN_ADDR_BUFSIZ HOSTUUIDLEN + IFNAMSIZ + 2 + SHA1_CTX ctx; + char buf[ETHER_GEN_ADDR_BUFSIZ]; + char uuid[HOSTUUIDLEN + 1]; + uint64_t addr; + struct thread *td; + int i, sz; + char digest[SHA1_RESULTLEN]; /* - * 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. + * We can not honor the full 32-bit bit-space that we take. It won't + * do any harm to allow larger masks right now because we only grab + * three bytes of the digest anyways, but protect against misuse in + * case the future leads to calculating the lower bits differently. */ - arc4rand(hwaddr->octet, ETHER_ADDR_LEN, 1); - hwaddr->octet[0] = 'b'; - hwaddr->octet[1] = 's'; - hwaddr->octet[2] = 'd'; + KASSERT((lomask & ~0xFFFFFF) == 0, + ("Request for lower address mask %x larger than 24-bits", lomask)); + td = curthread; + uuid[HOSTUUIDLEN] = '\0'; + bcopy(td->td_ucred->cr_prison->pr_hostuuid, uuid, HOSTUUIDLEN); + 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]) & lomask; + addr = OUI_FREEBSD(addr); + for (i = 0; i < ETHER_ADDR_LEN; ++i) { + hwaddr->octet[i] = addr >> ((ETHER_ADDR_LEN - i - 1) * 8) & + 0xFF; + } +} + +void +ether_gen_addr(struct ifnet *ifp, struct ether_addr *hwaddr) +{ + + ether_gen_addr_masked(ifp, hwaddr, OUI_FREEBSD_GENERATED_MASK); } DECLARE_MODULE(ether, ether_mod, SI_SUB_INIT_IF, SI_ORDER_ANY); Index: sys/net/if_vxlan.c =================================================================== --- sys/net/if_vxlan.c +++ sys/net/if_vxlan.c @@ -2754,7 +2754,7 @@ 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; Index: sys/net/iflib.c =================================================================== --- sys/net/iflib.c +++ sys/net/iflib.c @@ -206,7 +206,7 @@ #define isc_legacy_intr ifc_txrx.ift_legacy_intr eventhandler_tag ifc_vlan_attach_event; eventhandler_tag ifc_vlan_detach_event; - uint8_t ifc_mac[ETHER_ADDR_LEN]; + struct ether_addr ifc_mac; char ifc_mtx_name[16]; }; @@ -249,7 +249,7 @@ iflib_set_mac(if_ctx_t ctx, uint8_t mac[ETHER_ADDR_LEN]) { - bcopy(mac, ctx->ifc_mac, ETHER_ADDR_LEN); + bcopy(mac, ctx->ifc_mac.octet, ETHER_ADDR_LEN); } if_softc_ctx_t @@ -1274,38 +1274,6 @@ #define prefetch2cachelines(x) #endif -static void -iflib_gen_mac(if_ctx_t ctx) -{ - struct thread *td; - MD5_CTX mdctx; - char uuid[HOSTUUIDLEN+1]; - char buf[HOSTUUIDLEN+16]; - uint8_t *mac; - unsigned char digest[16]; - - td = curthread; - mac = ctx->ifc_mac; - uuid[HOSTUUIDLEN] = 0; - bcopy(td->td_ucred->cr_prison->pr_hostuuid, uuid, HOSTUUIDLEN); - snprintf(buf, HOSTUUIDLEN+16, "%s-%s", uuid, device_get_nameunit(ctx->ifc_dev)); - /* - * Generate a pseudo-random, deterministic MAC - * address based on the UUID and unit number. - * The FreeBSD Foundation OUI of 58-9C-FC is used. - */ - MD5Init(&mdctx); - MD5Update(&mdctx, buf, strlen(buf)); - MD5Final(digest, &mdctx); - - mac[0] = 0x58; - mac[1] = 0x9C; - mac[2] = 0xFC; - mac[3] = digest[0]; - mac[4] = digest[1]; - mac[5] = digest[2]; -} - static void iru_init(if_rxd_update_t iru, iflib_rxq_t rxq, uint8_t flid) { @@ -4552,7 +4520,7 @@ } } - ether_ifattach(ctx->ifc_ifp, ctx->ifc_mac); + ether_ifattach(ctx->ifc_ifp, ctx->ifc_mac.octet); if ((err = IFDI_ATTACH_POST(ctx)) != 0) { device_printf(dev, "IFDI_ATTACH_POST failed %d\n", err); @@ -4641,7 +4609,7 @@ goto fail_ctx_free; } if (sctx->isc_flags & IFLIB_GEN_MAC) - iflib_gen_mac(ctx); + ether_gen_addr(ifp, &ctx->ifc_mac); if ((err = IFDI_CLONEATTACH(ctx, clctx->cc_ifc, clctx->cc_name, clctx->cc_params)) != 0) { device_printf(dev, "IFDI_CLONEATTACH failed %d\n", err); @@ -4662,7 +4630,7 @@ ifp->if_flags |= IFF_NOGROUP; if (sctx->isc_flags & IFLIB_PSEUDO) { - ether_ifattach(ctx->ifc_ifp, ctx->ifc_mac); + ether_ifattach(ctx->ifc_ifp, ctx->ifc_mac.octet); if ((err = IFDI_ATTACH_POST(ctx)) != 0) { device_printf(dev, "IFDI_ATTACH_POST failed %d\n", err); @@ -4769,7 +4737,7 @@ /* * XXX What if anything do we want to do about interrupts? */ - ether_ifattach(ctx->ifc_ifp, ctx->ifc_mac); + ether_ifattach(ctx->ifc_ifp, ctx->ifc_mac.octet); if ((err = IFDI_ATTACH_POST(ctx)) != 0) { device_printf(dev, "IFDI_ATTACH_POST failed %d\n", err); goto fail_detach;