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)