Index: sys/net/ethernet.h =================================================================== --- sys/net/ethernet.h +++ sys/net/ethernet.h @@ -422,7 +422,7 @@ 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 */ 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,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,39 @@ 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; + struct thread *td; + int i, sz; + char digest[SHA1_RESULTLEN]; + + td = curthread; + getcredhostuuid(td->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); 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 @@ -37,15 +37,12 @@ #include #include #include -#include #include #include -#include #include #include #include #include -#include #include #include #include @@ -207,7 +204,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]; }; @@ -250,7 +247,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 @@ -1275,38 +1272,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) { @@ -4579,7 +4544,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); @@ -4668,7 +4633,7 @@ goto fail_unlock; } 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); @@ -4689,7 +4654,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); @@ -4796,7 +4761,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;