Changeset View
Changeset View
Standalone View
Standalone View
sys/net/if_epair.c
Show First 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | |||||
* epairs on multiple stacks/machines, we may need this. | * epairs on multiple stacks/machines, we may need this. | ||||
* For now let the user handle that case. | * For now let the user handle that case. | ||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/jail.h> | |||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/mbuf.h> | #include <sys/mbuf.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/refcount.h> | #include <sys/refcount.h> | ||||
#include <sys/queue.h> | #include <sys/queue.h> | ||||
#include <sys/smp.h> | #include <sys/smp.h> | ||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
#include <sys/sockio.h> | #include <sys/sockio.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/types.h> | #include <sys/types.h> | ||||
#include <sys/ucred.h> | |||||
#include <sys/systm.h> | |||||
#include <sys/counter.h> | |||||
#include <net/bpf.h> | #include <net/bpf.h> | ||||
#include <net/ethernet.h> | #include <net/ethernet.h> | ||||
#include <net/if.h> | #include <net/if.h> | ||||
#include <net/if_var.h> | #include <net/if_var.h> | ||||
#include <net/if_clone.h> | #include <net/if_clone.h> | ||||
#include <net/if_media.h> | #include <net/if_media.h> | ||||
#include <net/if_var.h> | #include <net/if_var.h> | ||||
▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | struct epair_softc { | ||||
struct ifnet *oifp; /* other ifp of pair. */ | struct ifnet *oifp; /* other ifp of pair. */ | ||||
struct ifmedia media; /* Media config (fake). */ | struct ifmedia media; /* Media config (fake). */ | ||||
u_int refcount; /* # of mbufs in flight. */ | u_int refcount; /* # of mbufs in flight. */ | ||||
u_int cpuid; /* CPU ID assigned upon creation. */ | u_int cpuid; /* CPU ID assigned upon creation. */ | ||||
void (*if_qflush)(struct ifnet *); | void (*if_qflush)(struct ifnet *); | ||||
/* Original if_qflush routine. */ | /* Original if_qflush routine. */ | ||||
}; | }; | ||||
/* A system-wide conter for the number of epair interfaces. */ | |||||
static counter_u64_t epair_cnt; | |||||
/* | /* | ||||
* Per-CPU list of ifps with data in the ifq that needs to be flushed | * Per-CPU list of ifps with data in the ifq that needs to be flushed | ||||
* to the netisr ``hw'' queue before we allow any further direct queuing | * to the netisr ``hw'' queue before we allow any further direct queuing | ||||
* to the ``hw'' queue. | * to the ``hw'' queue. | ||||
*/ | */ | ||||
struct epair_ifp_drain { | struct epair_ifp_drain { | ||||
STAILQ_ENTRY(epair_ifp_drain) ifp_next; | STAILQ_ENTRY(epair_ifp_drain) ifp_next; | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
▲ Show 20 Lines • Show All 555 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static int | static int | ||||
epair_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params) | epair_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params) | ||||
{ | { | ||||
struct epair_softc *sca, *scb; | struct epair_softc *sca, *scb; | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
char *dp; | char *dp; | ||||
int error, unit, wildcard; | int error, unit, wildcard, jid; | ||||
uint8_t eaddr[ETHER_ADDR_LEN]; /* 00:00:00:00:00:00 */ | uint8_t eaddr[ETHER_ADDR_LEN]; /* 00:00:00:00:00:00 */ | ||||
/* | /* | ||||
* We are abusing params to create our second interface. | * We are abusing params to create our second interface. | ||||
* Actually we already created it and called if_clone_create() | * Actually we already created it and called if_clone_create() | ||||
* for it to do the official insertion procedure the moment we knew | * for it to do the official insertion procedure the moment we knew | ||||
* it cannot fail anymore. So just do attach it here. | * it cannot fail anymore. So just do attach it here. | ||||
*/ | */ | ||||
bzero(eaddr, sizeof(eaddr)); | |||||
jid = curthread->td_ucred->cr_prison->pr_id; | |||||
if (params) { | if (params) { | ||||
scb = (struct epair_softc *)params; | scb = (struct epair_softc *)params; | ||||
ifp = scb->ifp; | ifp = scb->ifp; | ||||
/* Assign a hopefully unique, locally administered etheraddr. */ | /* Assign a hopefully unique, locally administered etheraddr. */ | ||||
eaddr[0] = 0x02; | eaddr[0] = 0x02; | ||||
eaddr[3] = (ifp->if_index >> 8) & 0xff; | eaddr[1] = (jid >> 8) & 0xff; | ||||
eaddr[4] = ifp->if_index & 0xff; | eaddr[2] = jid & 0xff; | ||||
eaddr[3] = (counter_u64_fetch(epair_cnt) >> 8) & 0xff; | |||||
eaddr[4] = counter_u64_fetch(epair_cnt) & 0xff; | |||||
eaddr[5] = 0x0b; | eaddr[5] = 0x0b; | ||||
ether_ifattach(ifp, eaddr); | ether_ifattach(ifp, eaddr); | ||||
counter_u64_add(epair_cnt, 1); | |||||
/* Correctly set the name for the cloner list. */ | /* Correctly set the name for the cloner list. */ | ||||
strlcpy(name, scb->ifp->if_xname, len); | strlcpy(name, scb->ifp->if_xname, len); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* Try to see if a special unit was requested. */ | /* Try to see if a special unit was requested. */ | ||||
error = ifc_name2unit(name, &unit); | error = ifc_name2unit(name, &unit); | ||||
if (error != 0) | if (error != 0) | ||||
▲ Show 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | epair_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params) | ||||
ifp->if_capabilities = IFCAP_VLAN_MTU; | ifp->if_capabilities = IFCAP_VLAN_MTU; | ||||
ifp->if_capenable = IFCAP_VLAN_MTU; | ifp->if_capenable = IFCAP_VLAN_MTU; | ||||
ifp->if_start = epair_start; | ifp->if_start = epair_start; | ||||
ifp->if_ioctl = epair_ioctl; | ifp->if_ioctl = epair_ioctl; | ||||
ifp->if_init = epair_init; | ifp->if_init = epair_init; | ||||
ifp->if_snd.ifq_maxlen = ifqmaxlen; | ifp->if_snd.ifq_maxlen = ifqmaxlen; | ||||
/* Assign a hopefully unique, locally administered etheraddr. */ | /* Assign a hopefully unique, locally administered etheraddr. */ | ||||
eaddr[0] = 0x02; | eaddr[0] = 0x02; | ||||
eaddr[3] = (ifp->if_index >> 8) & 0xff; | eaddr[1] = (jid >> 8) & 0xff; | ||||
eaddr[4] = ifp->if_index & 0xff; | eaddr[2] = jid & 0xff; | ||||
eaddr[3] = (counter_u64_fetch(epair_cnt) >> 8) & 0xff; | |||||
eaddr[4] = counter_u64_fetch(epair_cnt) & 0xff; | |||||
eaddr[5] = 0x0a; | eaddr[5] = 0x0a; | ||||
ether_ifattach(ifp, eaddr); | ether_ifattach(ifp, eaddr); | ||||
counter_u64_add(epair_cnt, 1); | |||||
sca->if_qflush = ifp->if_qflush; | sca->if_qflush = ifp->if_qflush; | ||||
ifp->if_qflush = epair_qflush; | ifp->if_qflush = epair_qflush; | ||||
ifp->if_transmit = epair_transmit; | ifp->if_transmit = epair_transmit; | ||||
ifp->if_baudrate = IF_Gbps(10); /* arbitrary maximum */ | ifp->if_baudrate = IF_Gbps(10); /* arbitrary maximum */ | ||||
/* Swap the name and finish initialization of interface <n>b. */ | /* Swap the name and finish initialization of interface <n>b. */ | ||||
*dp = 'b'; | *dp = 'b'; | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | epair_clone_destroy(struct if_clone *ifc, struct ifnet *ifp) | ||||
/* | /* | ||||
* Get rid of our second half. As the other of the two | * Get rid of our second half. As the other of the two | ||||
* interfaces may reside in a different vnet, we need to | * interfaces may reside in a different vnet, we need to | ||||
* switch before freeing them. | * switch before freeing them. | ||||
*/ | */ | ||||
CURVNET_SET_QUIET(oifp->if_vnet); | CURVNET_SET_QUIET(oifp->if_vnet); | ||||
ether_ifdetach(oifp); | ether_ifdetach(oifp); | ||||
counter_u64_add(epair_cnt, -1); | |||||
/* | /* | ||||
* Wait for all packets to be dispatched to if_input. | * Wait for all packets to be dispatched to if_input. | ||||
* The numbers can only go down as the interface is | * The numbers can only go down as the interface is | ||||
* detached so there is no need to use atomics. | * detached so there is no need to use atomics. | ||||
*/ | */ | ||||
DPRINTF("scb refcnt=%u\n", scb->refcount); | DPRINTF("scb refcnt=%u\n", scb->refcount); | ||||
EPAIR_REFCOUNT_ASSERT(scb->refcount == 1, | EPAIR_REFCOUNT_ASSERT(scb->refcount == 1, | ||||
("%s: ifp=%p scb->refcount!=1: %d", __func__, oifp, scb->refcount)); | ("%s: ifp=%p scb->refcount!=1: %d", __func__, oifp, scb->refcount)); | ||||
oifp->if_softc = NULL; | oifp->if_softc = NULL; | ||||
error = if_clone_destroyif(ifc, oifp); | error = if_clone_destroyif(ifc, oifp); | ||||
if (error) | if (error) | ||||
panic("%s: if_clone_destroyif() for our 2nd iface failed: %d", | panic("%s: if_clone_destroyif() for our 2nd iface failed: %d", | ||||
__func__, error); | __func__, error); | ||||
if_free(oifp); | if_free(oifp); | ||||
ifmedia_removeall(&scb->media); | ifmedia_removeall(&scb->media); | ||||
free(scb, M_EPAIR); | free(scb, M_EPAIR); | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
ether_ifdetach(ifp); | ether_ifdetach(ifp); | ||||
counter_u64_add(epair_cnt, -1); | |||||
/* | /* | ||||
* Wait for all packets to be dispatched to if_input. | * Wait for all packets to be dispatched to if_input. | ||||
*/ | */ | ||||
DPRINTF("sca refcnt=%u\n", sca->refcount); | DPRINTF("sca refcnt=%u\n", sca->refcount); | ||||
EPAIR_REFCOUNT_ASSERT(sca->refcount == 1, | EPAIR_REFCOUNT_ASSERT(sca->refcount == 1, | ||||
("%s: ifp=%p sca->refcount!=1: %d", __func__, ifp, sca->refcount)); | ("%s: ifp=%p sca->refcount!=1: %d", __func__, ifp, sca->refcount)); | ||||
if_free(ifp); | if_free(ifp); | ||||
ifmedia_removeall(&sca->media); | ifmedia_removeall(&sca->media); | ||||
Show All 24 Lines | |||||
static int | static int | ||||
epair_modevent(module_t mod, int type, void *data) | epair_modevent(module_t mod, int type, void *data) | ||||
{ | { | ||||
int qlimit; | int qlimit; | ||||
switch (type) { | switch (type) { | ||||
case MOD_LOAD: | case MOD_LOAD: | ||||
epair_cnt = counter_u64_alloc(M_WAITOK); | |||||
/* For now limit us to one global mutex and one inq. */ | /* For now limit us to one global mutex and one inq. */ | ||||
epair_dpcpu_init(); | epair_dpcpu_init(); | ||||
epair_nh.nh_qlimit = 42 * ifqmaxlen; /* 42 shall be the number. */ | epair_nh.nh_qlimit = 42 * ifqmaxlen; /* 42 shall be the number. */ | ||||
if (TUNABLE_INT_FETCH("net.link.epair.netisr_maxqlen", &qlimit)) | if (TUNABLE_INT_FETCH("net.link.epair.netisr_maxqlen", &qlimit)) | ||||
epair_nh.nh_qlimit = qlimit; | epair_nh.nh_qlimit = qlimit; | ||||
netisr_register(&epair_nh); | netisr_register(&epair_nh); | ||||
if (bootverbose) | if (bootverbose) | ||||
printf("%s initialized.\n", epairname); | printf("%s initialized.\n", epairname); | ||||
break; | break; | ||||
case MOD_UNLOAD: | case MOD_UNLOAD: | ||||
netisr_unregister(&epair_nh); | netisr_unregister(&epair_nh); | ||||
epair_dpcpu_detach(); | epair_dpcpu_detach(); | ||||
counter_u64_free(epair_cnt); | |||||
if (bootverbose) | if (bootverbose) | ||||
printf("%s unloaded.\n", epairname); | printf("%s unloaded.\n", epairname); | ||||
break; | break; | ||||
default: | default: | ||||
return (EOPNOTSUPP); | return (EOPNOTSUPP); | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
Show All 9 Lines |