summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhrs <hrs@FreeBSD.org>2015-09-09 08:52:39 +0000
committerhrs <hrs@FreeBSD.org>2015-09-09 08:52:39 +0000
commit72c1e2950ca7a308f080ed659aa0e0f677d935d8 (patch)
treeda5b34b14c500260f058097118ab6faa9fe63e0c
parentc02639b79471c7dcfd8094a16aff3ef9975fd6f8 (diff)
downloadFreeBSD-src-72c1e2950ca7a308f080ed659aa0e0f677d935d8.zip
FreeBSD-src-72c1e2950ca7a308f080ed659aa0e0f677d935d8.tar.gz
MFC r272889 and r287402:
- Virtualize if_epair(4). An if_xname check for both "a" and "b" interfaces is added to return EEXIST when only "b" interface exists---this can happen when epair<N>b is moved to a vnet jail and then "ifconfig epair<N> create" is invoked there. - Fix a panic which was reproducible by an infinite loop of "ifconfig epair0 create && ifconfig epair0a destroy". This was caused by an uninitialized function pointer in softc->media.
-rw-r--r--sys/net/if_epair.c52
1 files changed, 38 insertions, 14 deletions
diff --git a/sys/net/if_epair.c b/sys/net/if_epair.c
index 42a8a7a..540f06c 100644
--- a/sys/net/if_epair.c
+++ b/sys/net/if_epair.c
@@ -100,7 +100,7 @@ static int epair_clone_destroy(struct if_clone *, struct ifnet *);
static const char epairname[] = "epair";
-/* Netisr realted definitions and sysctl. */
+/* Netisr related definitions and sysctl. */
static struct netisr_handler epair_nh = {
.nh_name = epairname,
.nh_proto = NETISR_EPAIR,
@@ -171,7 +171,8 @@ STAILQ_HEAD(eid_list, epair_ifp_drain);
static MALLOC_DEFINE(M_EPAIR, epairname,
"Pair of virtual cross-over connected Ethernet-like interfaces");
-static struct if_clone *epair_cloner;
+static VNET_DEFINE(struct if_clone *, epair_cloner);
+#define V_epair_cloner VNET(epair_cloner)
/*
* DPCPU area and functions.
@@ -759,10 +760,17 @@ epair_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params)
ifc_free_unit(ifc, unit);
return (ENOSPC);
}
- *dp = 'a';
+ *dp = 'b';
/* Must not change dp so we can replace 'a' by 'b' later. */
*(dp+1) = '\0';
+ /* Check if 'a' and 'b' interfaces already exist. */
+ if (ifunit(name) != NULL)
+ return (EEXIST);
+ *dp = 'a';
+ if (ifunit(name) != NULL)
+ return (EEXIST);
+
/* Allocate memory for both [ab] interfaces */
sca = malloc(sizeof(struct epair_softc), M_EPAIR, M_WAITOK | M_ZERO);
EPAIR_REFCOUNT_INIT(&sca->refcount, 1);
@@ -800,6 +808,14 @@ epair_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params)
netisr_get_cpuid(sca->ifp->if_index % netisr_get_cpucount());
scb->cpuid =
netisr_get_cpuid(scb->ifp->if_index % netisr_get_cpucount());
+
+ /* Initialise pseudo media types. */
+ ifmedia_init(&sca->media, 0, epair_media_change, epair_media_status);
+ ifmedia_add(&sca->media, IFM_ETHER | IFM_10G_T, 0, NULL);
+ ifmedia_set(&sca->media, IFM_ETHER | IFM_10G_T);
+ ifmedia_init(&scb->media, 0, epair_media_change, epair_media_status);
+ ifmedia_add(&scb->media, IFM_ETHER | IFM_10G_T, 0, NULL);
+ ifmedia_set(&scb->media, IFM_ETHER | IFM_10G_T);
/* Finish initialization of interface <n>a. */
ifp = sca->ifp;
@@ -858,14 +874,6 @@ epair_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params)
strlcpy(name, sca->ifp->if_xname, len);
DPRINTF("name='%s/%db' created sca=%p scb=%p\n", name, unit, sca, scb);
- /* Initialise pseudo media types. */
- ifmedia_init(&sca->media, 0, epair_media_change, epair_media_status);
- ifmedia_add(&sca->media, IFM_ETHER | IFM_10G_T, 0, NULL);
- ifmedia_set(&sca->media, IFM_ETHER | IFM_10G_T);
- ifmedia_init(&scb->media, 0, epair_media_change, epair_media_status);
- ifmedia_add(&scb->media, IFM_ETHER | IFM_10G_T, 0, NULL);
- ifmedia_set(&scb->media, IFM_ETHER | IFM_10G_T);
-
/* Tell the world, that we are ready to rock. */
sca->ifp->if_drv_flags |= IFF_DRV_RUNNING;
scb->ifp->if_drv_flags |= IFF_DRV_RUNNING;
@@ -943,6 +951,25 @@ epair_clone_destroy(struct if_clone *ifc, struct ifnet *ifp)
return (0);
}
+static void
+vnet_epair_init(const void *unused __unused)
+{
+
+ V_epair_cloner = if_clone_advanced(epairname, 0,
+ epair_clone_match, epair_clone_create, epair_clone_destroy);
+}
+VNET_SYSINIT(vnet_epair_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
+ vnet_epair_init, NULL);
+
+static void
+vnet_epair_uninit(const void *unused __unused)
+{
+
+ if_clone_detach(V_epair_cloner);
+}
+VNET_SYSUNINIT(vnet_epair_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
+ vnet_epair_uninit, NULL);
+
static int
epair_modevent(module_t mod, int type, void *data)
{
@@ -956,13 +983,10 @@ epair_modevent(module_t mod, int type, void *data)
if (TUNABLE_INT_FETCH("net.link.epair.netisr_maxqlen", &qlimit))
epair_nh.nh_qlimit = qlimit;
netisr_register(&epair_nh);
- epair_cloner = if_clone_advanced(epairname, 0,
- epair_clone_match, epair_clone_create, epair_clone_destroy);
if (bootverbose)
printf("%s initialized.\n", epairname);
break;
case MOD_UNLOAD:
- if_clone_detach(epair_cloner);
netisr_unregister(&epair_nh);
epair_dpcpu_detach();
if (bootverbose)
OpenPOWER on IntegriCloud