diff options
author | grehan <grehan@FreeBSD.org> | 2013-07-04 05:35:56 +0000 |
---|---|---|
committer | grehan <grehan@FreeBSD.org> | 2013-07-04 05:35:56 +0000 |
commit | 4afc69bc7618a2445997ba51f65a74a54d461acb (patch) | |
tree | 1475820278721b7a4feacaea3c2716ad349e638a /usr.sbin | |
parent | 67f40d0cd39e244cabb915e7828711647be1f159 (diff) | |
download | FreeBSD-src-4afc69bc7618a2445997ba51f65a74a54d461acb.zip FreeBSD-src-4afc69bc7618a2445997ba51f65a74a54d461acb.tar.gz |
Support an optional "mac=" parameter to virtio-net config, to allow
users to set the MAC address for a device.
Clean up some obsolete code in pci_virtio_net.c
Allow an error return from a PCI device emulation's init routine
to be propagated all the way back to the top-level and result in
the process exiting.
Submitted by: Dinakar Medavaram dinnu sun at gmail (original version)
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/bhyve/bhyverun.c | 8 | ||||
-rw-r--r-- | usr.sbin/bhyve/pci_emul.c | 21 | ||||
-rw-r--r-- | usr.sbin/bhyve/pci_emul.h | 2 | ||||
-rw-r--r-- | usr.sbin/bhyve/pci_virtio_net.c | 83 |
4 files changed, 85 insertions, 29 deletions
diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c index 66883be..ae22de2 100644 --- a/usr.sbin/bhyve/bhyverun.c +++ b/usr.sbin/bhyve/bhyverun.c @@ -734,7 +734,13 @@ main(int argc, char *argv[]) init_mem(); init_inout(); - init_pci(ctx); + + /* + * Exit if a device emulation finds an error in it's initilization + */ + if (init_pci(ctx) != 0) + exit(1); + if (ioapic) ioapic_init(0); diff --git a/usr.sbin/bhyve/pci_emul.c b/usr.sbin/bhyve/pci_emul.c index 76e536c..00adf62 100644 --- a/usr.sbin/bhyve/pci_emul.c +++ b/usr.sbin/bhyve/pci_emul.c @@ -662,11 +662,13 @@ pci_emul_finddev(char *name) return (NULL); } -static void +static int pci_emul_init(struct vmctx *ctx, struct pci_devemu *pde, int slot, int func, char *params) { struct pci_devinst *pdi; + int err; + pdi = malloc(sizeof(struct pci_devinst)); bzero(pdi, sizeof(*pdi)); @@ -684,12 +686,15 @@ pci_emul_init(struct vmctx *ctx, struct pci_devemu *pde, int slot, int func, pci_set_cfgdata8(pdi, PCIR_COMMAND, PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN); - if ((*pde->pe_init)(ctx, pdi, params) != 0) { + err = (*pde->pe_init)(ctx, pdi, params); + if (err != 0) { free(pdi); } else { pci_emul_devices++; pci_slotinfo[slot][func].si_devi = pdi; - } + } + + return (err); } void @@ -989,7 +994,7 @@ pci_emul_fallback_handler(struct vmctx *ctx, int vcpu, int dir, uint64_t addr, return (0); } -void +int init_pci(struct vmctx *ctx) { struct mem_range memp; @@ -1009,8 +1014,10 @@ init_pci(struct vmctx *ctx) if (si->si_name != NULL) { pde = pci_emul_finddev(si->si_name); assert(pde != NULL); - pci_emul_init(ctx, pde, slot, func, - si->si_param); + error = pci_emul_init(ctx, pde, slot, func, + si->si_param); + if (error) + return (error); } } } @@ -1047,6 +1054,8 @@ init_pci(struct vmctx *ctx) error = register_mem_fallback(&memp); assert(error == 0); + + return (0); } int diff --git a/usr.sbin/bhyve/pci_emul.h b/usr.sbin/bhyve/pci_emul.h index 654b2f6..4e04a1e 100644 --- a/usr.sbin/bhyve/pci_emul.h +++ b/usr.sbin/bhyve/pci_emul.h @@ -183,7 +183,7 @@ struct pciecap { uint16_t slot_status2; } __packed; -void init_pci(struct vmctx *ctx); +int init_pci(struct vmctx *ctx); void msicap_cfgwrite(struct pci_devinst *pi, int capoff, int offset, int bytes, uint32_t val); void msixcap_cfgwrite(struct pci_devinst *pi, int capoff, int offset, diff --git a/usr.sbin/bhyve/pci_virtio_net.c b/usr.sbin/bhyve/pci_virtio_net.c index 4c03463..19f9ffe 100644 --- a/usr.sbin/bhyve/pci_virtio_net.c +++ b/usr.sbin/bhyve/pci_virtio_net.c @@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$"); #include <sys/select.h> #include <sys/uio.h> #include <sys/ioctl.h> +#include <net/ethernet.h> #include <errno.h> #include <fcntl.h> @@ -638,6 +639,30 @@ pci_vtnet_ring_init(struct pci_vtnet_softc *sc, uint64_t pfn) } static int +pci_vtnet_parsemac(char *mac_str, uint8_t *mac_addr) +{ + struct ether_addr *ea; + char *tmpstr; + char zero_addr[ETHER_ADDR_LEN] = { 0, 0, 0, 0, 0, 0 }; + + tmpstr = strsep(&mac_str,"="); + + if ((mac_str != NULL) && (!strcmp(tmpstr,"mac"))) { + ea = ether_aton(mac_str); + + if (ea == NULL || ETHER_IS_MULTICAST(ea->octet) || + memcmp(ea->octet, zero_addr, ETHER_ADDR_LEN) == 0) { + fprintf(stderr, "Invalid MAC %s\n", mac_str); + return (EINVAL); + } else + memcpy(mac_addr, ea->octet, ETHER_ADDR_LEN); + } + + return (0); +} + + +static int pci_vtnet_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) { MD5_CTX mdctx; @@ -646,6 +671,9 @@ pci_vtnet_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) char tname[MAXCOMLEN + 1]; struct pci_vtnet_softc *sc; const char *env_msi; + char *devname; + char *vtopts; + int mac_provided; sc = malloc(sizeof(struct pci_vtnet_softc)); memset(sc, 0, sizeof(struct pci_vtnet_softc)); @@ -664,14 +692,31 @@ pci_vtnet_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) } /* - * Attempt to open the tap device + * Attempt to open the tap device and read the MAC address + * if specified */ + mac_provided = 0; sc->vsc_tapfd = -1; if (opts != NULL) { char tbuf[80]; + int err; + + devname = vtopts = strdup(opts); + (void) strsep(&vtopts, ","); + + if (vtopts != NULL) { + err = pci_vtnet_parsemac(vtopts, sc->vsc_macaddr); + if (err != 0) { + free(devname); + return (err); + } + mac_provided = 1; + } strcpy(tbuf, "/dev/"); - strlcat(tbuf, opts, sizeof(tbuf)); + strlcat(tbuf, devname, sizeof(tbuf)); + + free(devname); sc->vsc_tapfd = open(tbuf, O_RDWR); if (sc->vsc_tapfd == -1) { @@ -701,29 +746,25 @@ pci_vtnet_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) } /* - * The MAC address is the standard NetApp OUI of 00-a0-98, - * followed by an MD5 of the vm name. The slot/func number is - * prepended to this for slots other than 1:0, so that - * a bootloader can netboot from the equivalent of slot 1. + * The default MAC address is the standard NetApp OUI of 00-a0-98, + * followed by an MD5 of the PCI slot/func number and dev name */ - if (pi->pi_slot == 1 && pi->pi_func == 0) { - strncpy(nstr, vmname, sizeof(nstr)); - } else { + if (!mac_provided) { snprintf(nstr, sizeof(nstr), "%d-%d-%s", pi->pi_slot, - pi->pi_func, vmname); + pi->pi_func, vmname); + + MD5Init(&mdctx); + MD5Update(&mdctx, nstr, strlen(nstr)); + MD5Final(digest, &mdctx); + + sc->vsc_macaddr[0] = 0x00; + sc->vsc_macaddr[1] = 0xa0; + sc->vsc_macaddr[2] = 0x98; + sc->vsc_macaddr[3] = digest[0]; + sc->vsc_macaddr[4] = digest[1]; + sc->vsc_macaddr[5] = digest[2]; } - MD5Init(&mdctx); - MD5Update(&mdctx, nstr, strlen(nstr)); - MD5Final(digest, &mdctx); - - sc->vsc_macaddr[0] = 0x00; - sc->vsc_macaddr[1] = 0xa0; - sc->vsc_macaddr[2] = 0x98; - sc->vsc_macaddr[3] = digest[0]; - sc->vsc_macaddr[4] = digest[1]; - sc->vsc_macaddr[5] = digest[2]; - /* initialize config space */ pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_NET); pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR); |