Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/net_backends.c
| Show First 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | |||||
| #include <assert.h> | #include <assert.h> | ||||
| #ifdef NETGRAPH | #ifdef NETGRAPH | ||||
| #include <sys/param.h> | #include <sys/param.h> | ||||
| #include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
| #include <netgraph.h> | #include <netgraph.h> | ||||
| #endif | #endif | ||||
| #include "config.h" | |||||
| #include "debug.h" | #include "debug.h" | ||||
| #include "iov.h" | #include "iov.h" | ||||
| #include "mevent.h" | #include "mevent.h" | ||||
| #include "net_backends.h" | #include "net_backends.h" | ||||
| #include "pci_emul.h" | |||||
| #include <sys/linker_set.h> | #include <sys/linker_set.h> | ||||
| /* | /* | ||||
| * Each network backend registers a set of function pointers that are | * Each network backend registers a set of function pointers that are | ||||
| * used to implement the net backends API. | * used to implement the net backends API. | ||||
| * This might need to be exposed if we implement backends in separate files. | * This might need to be exposed if we implement backends in separate files. | ||||
| */ | */ | ||||
| struct net_backend { | struct net_backend { | ||||
| const char *prefix; /* prefix matching this backend */ | const char *prefix; /* prefix matching this backend */ | ||||
| /* | /* | ||||
| * Routines used to initialize and cleanup the resources needed | * Routines used to initialize and cleanup the resources needed | ||||
| * by a backend. The cleanup function is used internally, | * by a backend. The cleanup function is used internally, | ||||
| * and should not be called by the frontend. | * and should not be called by the frontend. | ||||
| */ | */ | ||||
| int (*init)(struct net_backend *be, const char *devname, | int (*init)(struct net_backend *be, const char *devname, | ||||
| const char *opts, net_be_rxeof_t cb, void *param); | nvlist_t *nvl, net_be_rxeof_t cb, void *param); | ||||
| void (*cleanup)(struct net_backend *be); | void (*cleanup)(struct net_backend *be); | ||||
| /* | /* | ||||
| * Called to serve a guest transmit request. The scatter-gather | * Called to serve a guest transmit request. The scatter-gather | ||||
| * vector provided by the caller has 'iovcnt' elements and contains | * vector provided by the caller has 'iovcnt' elements and contains | ||||
| * the packet to send. | * the packet to send. | ||||
| */ | */ | ||||
| ssize_t (*send)(struct net_backend *be, const struct iovec *iov, | ssize_t (*send)(struct net_backend *be, const struct iovec *iov, | ||||
| ▲ Show 20 Lines • Show All 91 Lines • ▼ Show 20 Lines | tap_cleanup(struct net_backend *be) | ||||
| if (be->fd != -1) { | if (be->fd != -1) { | ||||
| close(be->fd); | close(be->fd); | ||||
| be->fd = -1; | be->fd = -1; | ||||
| } | } | ||||
| } | } | ||||
| static int | static int | ||||
| tap_init(struct net_backend *be, const char *devname, | tap_init(struct net_backend *be, const char *devname, | ||||
| const char *opts, net_be_rxeof_t cb, void *param) | nvlist_t *nvl, net_be_rxeof_t cb, void *param) | ||||
| { | { | ||||
| struct tap_priv *priv = (struct tap_priv *)be->opaque; | struct tap_priv *priv = (struct tap_priv *)be->opaque; | ||||
| char tbuf[80]; | char tbuf[80]; | ||||
| int opt = 1; | int opt = 1; | ||||
| #ifndef WITHOUT_CAPSICUM | #ifndef WITHOUT_CAPSICUM | ||||
| cap_rights_t rights; | cap_rights_t rights; | ||||
| #endif | #endif | ||||
| ▲ Show 20 Lines • Show All 177 Lines • ▼ Show 20 Lines | |||||
| /* | /* | ||||
| * Netgraph backend | * Netgraph backend | ||||
| */ | */ | ||||
| #define NG_SBUF_MAX_SIZE (4 * 1024 * 1024) | #define NG_SBUF_MAX_SIZE (4 * 1024 * 1024) | ||||
| static int | static int | ||||
| ng_init(struct net_backend *be, const char *devname, | ng_init(struct net_backend *be, const char *devname, | ||||
| const char *opts, net_be_rxeof_t cb, void *param) | nvlist_t *nvl, net_be_rxeof_t cb, void *param) | ||||
| { | { | ||||
| struct tap_priv *p = (struct tap_priv *)be->opaque; | struct tap_priv *p = (struct tap_priv *)be->opaque; | ||||
| struct ngm_connect ngc; | struct ngm_connect ngc; | ||||
| char *ngopts, *tofree; | const char *value, *nodename; | ||||
| char nodename[NG_NODESIZ]; | |||||
| int sbsz; | int sbsz; | ||||
| int ctrl_sock; | int ctrl_sock; | ||||
| int flags; | int flags; | ||||
| int path_provided; | |||||
| int peerhook_provided; | |||||
| int socket_provided; | |||||
| unsigned long maxsbsz; | unsigned long maxsbsz; | ||||
| size_t msbsz; | size_t msbsz; | ||||
| #ifndef WITHOUT_CAPSICUM | #ifndef WITHOUT_CAPSICUM | ||||
| cap_rights_t rights; | cap_rights_t rights; | ||||
| #endif | #endif | ||||
| if (cb == NULL) { | if (cb == NULL) { | ||||
| WPRINTF(("Netgraph backend requires non-NULL callback")); | WPRINTF(("Netgraph backend requires non-NULL callback")); | ||||
| return (-1); | return (-1); | ||||
| } | } | ||||
| be->fd = -1; | be->fd = -1; | ||||
| memset(&ngc, 0, sizeof(ngc)); | memset(&ngc, 0, sizeof(ngc)); | ||||
| strncpy(ngc.ourhook, "vmlink", NG_HOOKSIZ - 1); | value = get_config_value_node(nvl, "path"); | ||||
| if (value == NULL) { | |||||
| tofree = ngopts = strdup(opts); | WPRINTF(("path must be provided")); | ||||
| if (ngopts == NULL) { | |||||
| WPRINTF(("strdup error")); | |||||
| return (-1); | return (-1); | ||||
| } | } | ||||
| strncpy(ngc.path, value, NG_PATHSIZ - 1); | |||||
| socket_provided = 0; | value = get_config_value_node(nvl, "hook"); | ||||
| path_provided = 0; | |||||
| peerhook_provided = 0; | |||||
| while (ngopts != NULL) { | |||||
| char *value = ngopts; | |||||
| char *key; | |||||
| key = strsep(&value, "="); | |||||
| if (value == NULL) | if (value == NULL) | ||||
| break; | value = "vmlink"; | ||||
| ngopts = value; | |||||
| (void) strsep(&ngopts, ","); | |||||
| if (strcmp(key, "socket") == 0) { | |||||
| strncpy(nodename, value, NG_NODESIZ - 1); | |||||
| socket_provided = 1; | |||||
| } else if (strcmp(key, "path") == 0) { | |||||
| strncpy(ngc.path, value, NG_PATHSIZ - 1); | |||||
| path_provided = 1; | |||||
| } else if (strcmp(key, "hook") == 0) { | |||||
| strncpy(ngc.ourhook, value, NG_HOOKSIZ - 1); | strncpy(ngc.ourhook, value, NG_HOOKSIZ - 1); | ||||
| } else if (strcmp(key, "peerhook") == 0) { | |||||
| strncpy(ngc.peerhook, value, NG_HOOKSIZ - 1); | |||||
| peerhook_provided = 1; | |||||
| } | |||||
| } | |||||
| free(tofree); | value = get_config_value_node(nvl, "peerhook"); | ||||
| if (value == NULL) { | |||||
| if (!path_provided) { | |||||
| WPRINTF(("path must be provided")); | |||||
| return (-1); | |||||
| } | |||||
| if (!peerhook_provided) { | |||||
| WPRINTF(("peer hook must be provided")); | WPRINTF(("peer hook must be provided")); | ||||
| return (-1); | return (-1); | ||||
| } | } | ||||
| strncpy(ngc.peerhook, value, NG_HOOKSIZ - 1); | |||||
| if (NgMkSockNode(socket_provided ? nodename : NULL, | nodename = get_config_value_node(nvl, "socket"); | ||||
| if (NgMkSockNode(nodename, | |||||
| &ctrl_sock, &be->fd) < 0) { | &ctrl_sock, &be->fd) < 0) { | ||||
| WPRINTF(("can't get Netgraph sockets")); | WPRINTF(("can't get Netgraph sockets")); | ||||
| return (-1); | return (-1); | ||||
| } | } | ||||
| if (NgSendMsg(ctrl_sock, ".", | if (NgSendMsg(ctrl_sock, ".", | ||||
| NGM_GENERIC_COOKIE, | NGM_GENERIC_COOKIE, | ||||
| NGM_CONNECT, &ngc, sizeof(ngc)) < 0) { | NGM_CONNECT, &ngc, sizeof(ngc)) < 0) { | ||||
| ▲ Show 20 Lines • Show All 173 Lines • ▼ Show 20 Lines | netmap_set_cap(struct net_backend *be, uint64_t features, | ||||
| unsigned vnet_hdr_len) | unsigned vnet_hdr_len) | ||||
| { | { | ||||
| return (netmap_set_vnet_hdr_len(be, vnet_hdr_len)); | return (netmap_set_vnet_hdr_len(be, vnet_hdr_len)); | ||||
| } | } | ||||
| static int | static int | ||||
| netmap_init(struct net_backend *be, const char *devname, | netmap_init(struct net_backend *be, const char *devname, | ||||
| const char *opts, net_be_rxeof_t cb, void *param) | nvlist_t *nvl, net_be_rxeof_t cb, void *param) | ||||
| { | { | ||||
| struct netmap_priv *priv = (struct netmap_priv *)be->opaque; | struct netmap_priv *priv = (struct netmap_priv *)be->opaque; | ||||
| strlcpy(priv->ifname, devname, sizeof(priv->ifname)); | strlcpy(priv->ifname, devname, sizeof(priv->ifname)); | ||||
| priv->ifname[sizeof(priv->ifname) - 1] = '\0'; | priv->ifname[sizeof(priv->ifname) - 1] = '\0'; | ||||
| priv->nmd = nm_open(priv->ifname, NULL, NETMAP_NO_TX_POLL, NULL); | priv->nmd = nm_open(priv->ifname, NULL, NETMAP_NO_TX_POLL, NULL); | ||||
| if (priv->nmd == NULL) { | if (priv->nmd == NULL) { | ||||
| ▲ Show 20 Lines • Show All 243 Lines • ▼ Show 20 Lines | static struct net_backend vale_backend = { | ||||
| .recv_disable = netmap_recv_disable, | .recv_disable = netmap_recv_disable, | ||||
| .get_cap = netmap_get_cap, | .get_cap = netmap_get_cap, | ||||
| .set_cap = netmap_set_cap, | .set_cap = netmap_set_cap, | ||||
| }; | }; | ||||
| DATA_SET(net_backend_set, netmap_backend); | DATA_SET(net_backend_set, netmap_backend); | ||||
| DATA_SET(net_backend_set, vale_backend); | DATA_SET(net_backend_set, vale_backend); | ||||
| int | |||||
| netbe_legacy_config(nvlist_t *nvl, const char *opts) | |||||
| { | |||||
| char *backend, *cp; | |||||
| if (opts == NULL) | |||||
| return (0); | |||||
| cp = strchr(opts, ','); | |||||
| if (cp == NULL) { | |||||
| set_config_value_node(nvl, "backend", opts); | |||||
| return (0); | |||||
| } | |||||
| backend = strndup(opts, cp - opts); | |||||
| set_config_value_node(nvl, "backend", backend); | |||||
| free(backend); | |||||
| return (pci_parse_legacy_config(nvl, cp + 1)); | |||||
| } | |||||
| /* | /* | ||||
| * Initialize a backend and attach to the frontend. | * Initialize a backend and attach to the frontend. | ||||
| * This is called during frontend initialization. | * This is called during frontend initialization. | ||||
| * @pbe is a pointer to the backend to be initialized | * @ret is a pointer to the backend to be initialized | ||||
| * @devname is the backend-name as supplied on the command line, | * @devname is the backend-name as supplied on the command line, | ||||
| * e.g. -s 2:0,frontend-name,backend-name[,other-args] | * e.g. -s 2:0,frontend-name,backend-name[,other-args] | ||||
| * @cb is the receive callback supplied by the frontend, | * @cb is the receive callback supplied by the frontend, | ||||
| * and it is invoked in the event loop when a receive | * and it is invoked in the event loop when a receive | ||||
| * event is generated in the hypervisor, | * event is generated in the hypervisor, | ||||
| * @param is a pointer to the frontend, and normally used as | * @param is a pointer to the frontend, and normally used as | ||||
| * the argument for the callback. | * the argument for the callback. | ||||
| */ | */ | ||||
| int | int | ||||
| netbe_init(struct net_backend **ret, const char *opts, net_be_rxeof_t cb, | netbe_init(struct net_backend **ret, nvlist_t *nvl, net_be_rxeof_t cb, | ||||
| void *param) | void *param) | ||||
| { | { | ||||
| struct net_backend **pbe, *nbe, *tbe = NULL; | struct net_backend **pbe, *nbe, *tbe = NULL; | ||||
| const char *value; | |||||
| char *devname; | char *devname; | ||||
| char *options; | |||||
| int err; | int err; | ||||
| devname = options = strdup(opts); | value = get_config_value_node(nvl, "backend"); | ||||
| if (value == NULL) { | |||||
grehan: Should be `if (value == NULL)` | |||||
| if (devname == NULL) { | |||||
| return (-1); | return (-1); | ||||
| } | } | ||||
| devname = strdup(value); | |||||
| devname = strsep(&options, ","); | |||||
| /* | /* | ||||
| * Find the network backend that matches the user-provided | * Find the network backend that matches the user-provided | ||||
| * device name. net_backend_set is built using a linker set. | * device name. net_backend_set is built using a linker set. | ||||
| */ | */ | ||||
| SET_FOREACH(pbe, net_backend_set) { | SET_FOREACH(pbe, net_backend_set) { | ||||
| if (strncmp(devname, (*pbe)->prefix, | if (strncmp(devname, (*pbe)->prefix, | ||||
| strlen((*pbe)->prefix)) == 0) { | strlen((*pbe)->prefix)) == 0) { | ||||
| tbe = *pbe; | tbe = *pbe; | ||||
| Show All 16 Lines | netbe_init(struct net_backend **ret, nvlist_t *nvl, net_be_rxeof_t cb, | ||||
| nbe = calloc(1, sizeof(*nbe) + tbe->priv_size); | nbe = calloc(1, sizeof(*nbe) + tbe->priv_size); | ||||
| *nbe = *tbe; /* copy the template */ | *nbe = *tbe; /* copy the template */ | ||||
| nbe->fd = -1; | nbe->fd = -1; | ||||
| nbe->sc = param; | nbe->sc = param; | ||||
| nbe->be_vnet_hdr_len = 0; | nbe->be_vnet_hdr_len = 0; | ||||
| nbe->fe_vnet_hdr_len = 0; | nbe->fe_vnet_hdr_len = 0; | ||||
| /* Initialize the backend. */ | /* Initialize the backend. */ | ||||
| err = nbe->init(nbe, devname, options, cb, param); | err = nbe->init(nbe, devname, nvl, cb, param); | ||||
| if (err) { | if (err) { | ||||
| free(devname); | free(devname); | ||||
| free(nbe); | free(nbe); | ||||
| return (err); | return (err); | ||||
| } | } | ||||
| *ret = nbe; | *ret = nbe; | ||||
| free(devname); | free(devname); | ||||
| ▲ Show 20 Lines • Show All 112 Lines • Show Last 20 Lines | |||||
Should be if (value == NULL)