Index: share/man/man4/epair.4 =================================================================== --- share/man/man4/epair.4 +++ share/man/man4/epair.4 @@ -28,7 +28,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 18, 2015 +.Dd March 11, 2020 .Dt EPAIR 4 .Os .Sh NAME @@ -99,6 +99,48 @@ can have a .Xr vlan 4 configured on top of it. +.Sh LOADER TUNABLES +Tunables can be set at the +.Xr loader 8 +prompt before booting the kernel, or stored in +.Xr loader.conf 5 . +.Bl -tag -width indent +.It Va net.isr.bindthreads Pq Defaults to 0 +If running multi-CPU configurations is is advised to turn this to +.Ql 1 +along with the next option adjusted as well. +.It Va net.isr.maxthreads Pq Defaults to 1 +If running a multi-CPU configration with a lot of +.Nm +interfaces it is advisable to set this number to the current number of +CPUs or a high number (as +.Xr netisr 9 +will automatically reduce it to the maximum number). +.It Va net.link.epair.netisr_maxqlen Pq Defaults to 256 +If running a high number of +.Nm +interfaces it is advisable to adjust this value to the +.Xr netisr 9 +maximum queue length of +.Ql 10240 . +This allows interfaces to queue more packets per CPU and with that +usually avoids queue drops. +.El +.Pp +All tunables are related to the +.Xr netisr 9 +functionality used by +.Nm +and should help scaling to larger systems. +.Sh BUGS +.Nm +interfaces used to stall once the hardware queue was overflown. +The functionality of draining per-interfaces queues is currently +disabled. +.Pp +.Nm +has scaling problems on modern systems with mass-deployment and +needs to be reworked. .Sh SEE ALSO .Xr ioctl 2 , .Xr altq 4 , @@ -107,7 +149,8 @@ .Xr vlan 4 , .Xr loader.conf 5 , .Xr rc.conf 5 , -.Xr ifconfig 8 +.Xr ifconfig 8 , +.Xr netisr 9 .Sh HISTORY The .Nm Index: sys/net/if_epair.c =================================================================== --- sys/net/if_epair.c +++ sys/net/if_epair.c @@ -97,7 +97,9 @@ static void epair_nh_sintr(struct mbuf *); static struct mbuf *epair_nh_m2cpuid(struct mbuf *, uintptr_t, u_int *); +#ifdef EPAIR_DRAIN static void epair_nh_drainedcpu(u_int); +#endif static void epair_start_locked(struct ifnet *); static int epair_media_change(struct ifnet *); @@ -117,7 +119,9 @@ .nh_policy = NETISR_POLICY_CPU, .nh_handler = epair_nh_sintr, .nh_m2cpuid = epair_nh_m2cpuid, +#ifdef EPAIR_DRAIN .nh_drainedcpu = epair_nh_drainedcpu, +#endif }; static int @@ -148,6 +152,7 @@ /* Original if_qflush routine. */ }; +#ifdef EPAIR_DRAIN /* * 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 @@ -158,6 +163,7 @@ struct ifnet *ifp; }; STAILQ_HEAD(eid_list, epair_ifp_drain); +#endif #define EPAIR_LOCK_INIT(dpcpu) mtx_init(&(dpcpu)->if_epair_mtx, \ "if_epair", NULL, MTX_DEF) @@ -191,8 +197,10 @@ struct epair_dpcpu { struct mtx if_epair_mtx; /* Per-CPU locking. */ int epair_drv_flags; /* Per-CPU ``hw'' drv flags. */ +#ifdef EPAIR_DRAIN struct eid_list epair_ifp_drain_list; /* Per-CPU list of ifps with * data in the ifq. */ +#endif }; DPCPU_DEFINE(struct epair_dpcpu, epair_dpcpu); @@ -200,7 +208,9 @@ epair_dpcpu_init(void) { struct epair_dpcpu *epair_dpcpu; +#ifdef EPAIR_DRAIN struct eid_list *s; +#endif u_int cpuid; CPU_FOREACH(cpuid) { @@ -212,6 +222,7 @@ /* Driver flags are per-cpu as are our netisr "hw" queues. */ epair_dpcpu->epair_drv_flags = 0; +#ifdef EPAIR_DRAIN /* * Initialize per-cpu drain list. * Manually do what STAILQ_HEAD_INITIALIZER would do. @@ -219,6 +230,7 @@ s = &epair_dpcpu->epair_ifp_drain_list; s->stqh_first = NULL; s->stqh_last = &s->stqh_first; +#endif } } @@ -279,6 +291,7 @@ return (m); } +#ifdef EPAIR_DRAIN static void epair_nh_drainedcpu(u_int cpuid) { @@ -327,10 +340,12 @@ } EPAIR_UNLOCK(epair_dpcpu); } +#endif /* * Network interface (`if') related functions. */ +#ifdef EPAIR_DRAIN static void epair_remove_ifp_from_draining(struct ifnet *ifp) { @@ -390,6 +405,7 @@ return (0); } +#endif static void epair_start_locked(struct ifnet *ifp) @@ -450,14 +466,16 @@ if_inc_counter(oifp, IFCOUNTER_IPACKETS, 1); } else { /* The packet was freed already. */ + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); +#ifdef EPAIR_DRAIN epair_dpcpu->epair_drv_flags |= IFF_DRV_OACTIVE; ifp->if_drv_flags |= IFF_DRV_OACTIVE; (void) epair_add_ifp_for_draining(ifp); - if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); EPAIR_REFCOUNT_RELEASE(&sc->refcount); EPAIR_REFCOUNT_ASSERT((int)sc->refcount >= 1, ("%s: ifp=%p sc->refcount not >= 1: %d", __func__, oifp, sc->refcount)); +#endif } } } @@ -535,16 +553,21 @@ if (mflags & (M_BCAST|M_MCAST)) if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1); +#ifdef EPAIR_DRAIN if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) +#endif epair_start_locked(ifp); +#ifdef EPAIR_DRAIN else (void)epair_add_ifp_for_draining(ifp); +#endif } return (error); } IF_UNLOCK(&ifp->if_snd); #endif +#ifdef EPAIR_DRAIN if ((epair_dpcpu->epair_drv_flags & IFF_DRV_OACTIVE) != 0) { /* * Our hardware queue is full, try to fall back @@ -556,6 +579,7 @@ (void)epair_add_ifp_for_draining(ifp); return (error); } +#endif sc = oifp->if_softc; /* * Add a reference so the interface cannot go while the @@ -580,13 +604,15 @@ if_inc_counter(oifp, IFCOUNTER_IPACKETS, 1); } else { /* The packet was freed already. */ + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); +#ifdef EPAIR_DRAIN epair_dpcpu->epair_drv_flags |= IFF_DRV_OACTIVE; ifp->if_drv_flags |= IFF_DRV_OACTIVE; - if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); EPAIR_REFCOUNT_RELEASE(&sc->refcount); EPAIR_REFCOUNT_ASSERT((int)sc->refcount >= 1, ("%s: ifp=%p sc->refcount not >= 1: %d", __func__, oifp, sc->refcount)); +#endif } return (error); @@ -613,12 +639,14 @@ sc = ifp->if_softc; KASSERT(sc != NULL, ("%s: ifp=%p, epair_softc gone? sc=%p\n", __func__, ifp, sc)); +#ifdef EPAIR_DRAIN /* * Remove this ifp from all backpointer lists. The interface will not * usable for flushing anyway nor should it have anything to flush * after if_qflush(). */ epair_remove_ifp_from_draining(ifp); +#endif if (sc->if_qflush) sc->if_qflush(ifp);