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_ID_NETWORK); | pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_ID_NETWORK); | ||||
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); |