Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/pci_virtio_net.c
| Show First 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | |||||
| #include <string.h> | #include <string.h> | ||||
| #include <strings.h> | #include <strings.h> | ||||
| #include <unistd.h> | #include <unistd.h> | ||||
| #include <assert.h> | #include <assert.h> | ||||
| #include <pthread.h> | #include <pthread.h> | ||||
| #include <pthread_np.h> | #include <pthread_np.h> | ||||
| #include "bhyverun.h" | #include "bhyverun.h" | ||||
| #include "config.h" | |||||
| #include "debug.h" | #include "debug.h" | ||||
| #include "pci_emul.h" | #include "pci_emul.h" | ||||
| #include "mevent.h" | #include "mevent.h" | ||||
| #include "virtio.h" | #include "virtio.h" | ||||
| #include "net_utils.h" | #include "net_utils.h" | ||||
| #include "net_backends.h" | #include "net_backends.h" | ||||
| #include "iov.h" | #include "iov.h" | ||||
| ▲ Show 20 Lines • Show All 488 Lines • ▼ Show 20 Lines | |||||
| pci_vtnet_ping_ctlq(void *vsc, struct vqueue_info *vq) | pci_vtnet_ping_ctlq(void *vsc, struct vqueue_info *vq) | ||||
| { | { | ||||
| DPRINTF(("vtnet: control qnotify!")); | DPRINTF(("vtnet: control qnotify!")); | ||||
| } | } | ||||
| #endif | #endif | ||||
| static int | static int | ||||
| pci_vtnet_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) | pci_vtnet_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) | ||||
| { | { | ||||
| struct pci_vtnet_softc *sc; | struct pci_vtnet_softc *sc; | ||||
| const char *value; | |||||
| char tname[MAXCOMLEN + 1]; | char tname[MAXCOMLEN + 1]; | ||||
| int mac_provided; | |||||
| int mtu_provided; | |||||
| unsigned long mtu = ETHERMTU; | unsigned long mtu = ETHERMTU; | ||||
| int err; | |||||
| /* | /* | ||||
| * Allocate data structures for further virtio initializations. | * Allocate data structures for further virtio initializations. | ||||
| * sc also contains a copy of vtnet_vi_consts, since capabilities | * sc also contains a copy of vtnet_vi_consts, since capabilities | ||||
| * change depending on the backend. | * change depending on the backend. | ||||
| */ | */ | ||||
| sc = calloc(1, sizeof(struct pci_vtnet_softc)); | sc = calloc(1, sizeof(struct pci_vtnet_softc)); | ||||
| sc->vsc_consts = vtnet_vi_consts; | sc->vsc_consts = vtnet_vi_consts; | ||||
| pthread_mutex_init(&sc->vsc_mtx, NULL); | pthread_mutex_init(&sc->vsc_mtx, NULL); | ||||
| sc->vsc_queues[VTNET_RXQ].vq_qsize = VTNET_RINGSZ; | sc->vsc_queues[VTNET_RXQ].vq_qsize = VTNET_RINGSZ; | ||||
| sc->vsc_queues[VTNET_RXQ].vq_notify = pci_vtnet_ping_rxq; | sc->vsc_queues[VTNET_RXQ].vq_notify = pci_vtnet_ping_rxq; | ||||
| sc->vsc_queues[VTNET_TXQ].vq_qsize = VTNET_RINGSZ; | sc->vsc_queues[VTNET_TXQ].vq_qsize = VTNET_RINGSZ; | ||||
| sc->vsc_queues[VTNET_TXQ].vq_notify = pci_vtnet_ping_txq; | sc->vsc_queues[VTNET_TXQ].vq_notify = pci_vtnet_ping_txq; | ||||
| #ifdef notyet | #ifdef notyet | ||||
| sc->vsc_queues[VTNET_CTLQ].vq_qsize = VTNET_RINGSZ; | sc->vsc_queues[VTNET_CTLQ].vq_qsize = VTNET_RINGSZ; | ||||
| sc->vsc_queues[VTNET_CTLQ].vq_notify = pci_vtnet_ping_ctlq; | sc->vsc_queues[VTNET_CTLQ].vq_notify = pci_vtnet_ping_ctlq; | ||||
| #endif | #endif | ||||
| /* | value = get_config_value_node(nvl, "mac"); | ||||
| * Attempt to open the backend device and read the MAC address | if (value != NULL) { | ||||
| * if specified. | |||||
| */ | |||||
| mac_provided = 0; | |||||
| mtu_provided = 0; | |||||
| if (opts != NULL) { | |||||
| char *optscopy; | |||||
| char *vtopts; | |||||
| int err = 0; | |||||
| /* Get the device name. */ | |||||
| optscopy = vtopts = strdup(opts); | |||||
| (void) strsep(&vtopts, ","); | |||||
| /* | |||||
| * Parse the list of options in the form | |||||
| * key1=value1,...,keyN=valueN. | |||||
| */ | |||||
| while (vtopts != NULL) { | |||||
| char *value = vtopts; | |||||
| char *key; | |||||
| key = strsep(&value, "="); | |||||
| if (value == NULL) | |||||
| break; | |||||
| vtopts = value; | |||||
| (void) strsep(&vtopts, ","); | |||||
| if (strcmp(key, "mac") == 0) { | |||||
| err = net_parsemac(value, sc->vsc_config.mac); | err = net_parsemac(value, sc->vsc_config.mac); | ||||
| if (err) | if (err) { | ||||
| break; | free(sc); | ||||
| mac_provided = 1; | return (err); | ||||
| } else if (strcmp(key, "mtu") == 0) { | } | ||||
| } else | |||||
| net_genmac(pi, sc->vsc_config.mac); | |||||
| value = get_config_value_node(nvl, "mtu"); | |||||
| if (value != NULL) { | |||||
| err = net_parsemtu(value, &mtu); | err = net_parsemtu(value, &mtu); | ||||
| if (err) | if (err) { | ||||
| break; | free(sc); | ||||
| return (err); | |||||
| } | |||||
| if (mtu < VTNET_MIN_MTU || mtu > VTNET_MAX_MTU) { | if (mtu < VTNET_MIN_MTU || mtu > VTNET_MAX_MTU) { | ||||
| err = EINVAL; | err = EINVAL; | ||||
| errno = EINVAL; | errno = EINVAL; | ||||
| break; | |||||
| } | |||||
| mtu_provided = 1; | |||||
| } | |||||
| } | |||||
| free(optscopy); | |||||
| if (err) { | |||||
| free(sc); | free(sc); | ||||
| return (err); | return (err); | ||||
| } | } | ||||
| sc->vsc_consts.vc_hv_caps |= VIRTIO_NET_F_MTU; | |||||
| } | |||||
| sc->vsc_config.mtu = mtu; | |||||
| err = netbe_init(&sc->vsc_be, opts, pci_vtnet_rx_callback, | /* Permit interfaces without a configured backend. */ | ||||
| sc); | if (get_config_value_node(nvl, "backend") != NULL) { | ||||
| err = netbe_init(&sc->vsc_be, nvl, pci_vtnet_rx_callback, sc); | |||||
| if (err) { | if (err) { | ||||
| free(sc); | free(sc); | ||||
| return (err); | return (err); | ||||
| } | } | ||||
| } | |||||
| sc->vsc_consts.vc_hv_caps |= VIRTIO_NET_F_MRG_RXBUF | | sc->vsc_consts.vc_hv_caps |= VIRTIO_NET_F_MRG_RXBUF | | ||||
| netbe_get_cap(sc->vsc_be); | netbe_get_cap(sc->vsc_be); | ||||
| } | |||||
| if (!mac_provided) { | |||||
| net_genmac(pi, sc->vsc_config.mac); | |||||
| } | |||||
| sc->vsc_config.mtu = mtu; | |||||
| if (mtu_provided) { | |||||
| sc->vsc_consts.vc_hv_caps |= VIRTIO_NET_F_MTU; | |||||
| } | |||||
| /* | /* | ||||
| * Since we do not actually support multiqueue, | * Since we do not actually support multiqueue, | ||||
| * set the maximum virtqueue pairs to 1. | * set the maximum virtqueue pairs to 1. | ||||
| */ | */ | ||||
| sc->vsc_config.max_virtqueue_pairs = 1; | sc->vsc_config.max_virtqueue_pairs = 1; | ||||
| /* initialize config space */ | /* initialize config space */ | ||||
| pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_NET); | pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_NET); | ||||
| pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR); | pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR); | ||||
| pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_NETWORK); | pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_NETWORK); | ||||
| pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_TYPE_NET); | pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_TYPE_NET); | ||||
| pci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR); | pci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR); | ||||
| /* Link is up if we managed to open backend device. */ | /* Link is always up. */ | ||||
| sc->vsc_config.status = (opts == NULL || sc->vsc_be); | sc->vsc_config.status = 1; | ||||
| vi_softc_linkup(&sc->vsc_vs, &sc->vsc_consts, sc, pi, sc->vsc_queues); | vi_softc_linkup(&sc->vsc_vs, &sc->vsc_consts, sc, pi, sc->vsc_queues); | ||||
| sc->vsc_vs.vs_mtx = &sc->vsc_mtx; | sc->vsc_vs.vs_mtx = &sc->vsc_mtx; | ||||
| /* use BAR 1 to map MSI-X table and PBA, if we're using MSI-X */ | /* use BAR 1 to map MSI-X table and PBA, if we're using MSI-X */ | ||||
| if (vi_intr_init(&sc->vsc_vs, 1, fbsdrun_virtio_msix())) { | if (vi_intr_init(&sc->vsc_vs, 1, fbsdrun_virtio_msix())) { | ||||
| free(sc); | free(sc); | ||||
| return (1); | return (1); | ||||
| ▲ Show 20 Lines • Show All 148 Lines • ▼ Show 20 Lines | |||||
| done: | done: | ||||
| return (ret); | return (ret); | ||||
| } | } | ||||
| #endif | #endif | ||||
| static struct pci_devemu pci_de_vnet = { | static struct pci_devemu pci_de_vnet = { | ||||
| .pe_emu = "virtio-net", | .pe_emu = "virtio-net", | ||||
| .pe_init = pci_vtnet_init, | .pe_init = pci_vtnet_init, | ||||
| .pe_legacy_config = netbe_legacy_config, | |||||
| .pe_barwrite = vi_pci_write, | .pe_barwrite = vi_pci_write, | ||||
| .pe_barread = vi_pci_read, | .pe_barread = vi_pci_read, | ||||
| #ifdef BHYVE_SNAPSHOT | #ifdef BHYVE_SNAPSHOT | ||||
| .pe_snapshot = vi_pci_snapshot, | .pe_snapshot = vi_pci_snapshot, | ||||
| .pe_pause = vi_pci_pause, | .pe_pause = vi_pci_pause, | ||||
| .pe_resume = vi_pci_resume, | .pe_resume = vi_pci_resume, | ||||
| #endif | #endif | ||||
| }; | }; | ||||
| PCI_EMUL_SET(pci_de_vnet); | PCI_EMUL_SET(pci_de_vnet); | ||||