On Sat, Jul 16, 2022 at 10:28:56AM +0000, Visa Hankala wrote: > The index of a network interface is assigned in if_idxmap_insert(). > ifq_init() and ifiq_init() use if_index before it has its final value. > As a consequence, interfaces tend to use net_tq(0) as their first > softnet task queue even though the other softnet task queues could be > used as well. To fix this, allocate if_index before queue setup. > > The patch tracks index allocations using a separate bitmap so that > if_get() does not need extra logic. > > Because the memory allocation of the map array can sleep, replace the > kernel lock with an rwlock to serialize idxmap updates more robustly. > > Also, correct the "too many interfaces" condition because the valid > index range is from 1 to USHRT_MAX. > > OK?
OK bluhm@ > Index: net/if.c > =================================================================== > RCS file: src/sys/net/if.c,v > retrieving revision 1.659 > diff -u -p -r1.659 if.c > --- net/if.c 14 Jul 2022 11:03:15 -0000 1.659 > +++ net/if.c 16 Jul 2022 10:07:14 -0000 > @@ -217,9 +217,12 @@ struct if_idxmap { > unsigned int serial; > unsigned int count; > struct srp map; > + struct rwlock lock; > + unsigned char *usedidx; /* bitmap of indices in use */ > }; > > void if_idxmap_init(unsigned int); > +void if_idxmap_alloc(struct ifnet *); > void if_idxmap_insert(struct ifnet *); > void if_idxmap_remove(struct ifnet *); > > @@ -273,7 +276,9 @@ ifinit(void) > static struct if_idxmap if_idxmap = { > 0, > 0, > - SRP_INITIALIZER() > + SRP_INITIALIZER(), > + RWLOCK_INITIALIZER("idxmaplk"), > + NULL, > }; > > struct srp_gc if_ifp_gc = SRP_GC_INITIALIZER(if_ifp_dtor, NULL); > @@ -298,12 +303,15 @@ if_idxmap_init(unsigned int limit) > for (i = 0; i < limit; i++) > srp_init(&map[i]); > > + if_idxmap.usedidx = malloc(howmany(limit, NBBY), > + M_IFADDR, M_WAITOK | M_ZERO); > + > /* this is called early so there's nothing to race with */ > srp_update_locked(&if_map_gc, &if_idxmap.map, if_map); > } > > void > -if_idxmap_insert(struct ifnet *ifp) > +if_idxmap_alloc(struct ifnet *ifp) > { > struct if_map *if_map; > struct srp *map; > @@ -311,10 +319,9 @@ if_idxmap_insert(struct ifnet *ifp) > > refcnt_init(&ifp->if_refcnt); > > - /* the kernel lock guarantees serialised modifications to if_idxmap */ > - KERNEL_ASSERT_LOCKED(); > + rw_enter_write(&if_idxmap.lock); > > - if (++if_idxmap.count > USHRT_MAX) > + if (++if_idxmap.count >= USHRT_MAX) > panic("too many interfaces"); > > if_map = srp_get_locked(&if_idxmap.map); > @@ -327,6 +334,7 @@ if_idxmap_insert(struct ifnet *ifp) > struct srp *nmap; > unsigned int nlimit; > struct ifnet *nifp; > + unsigned char *nusedidx; > > nlimit = if_map->limit * 2; > nif_map = malloc(sizeof(*nif_map) + nlimit * sizeof(*nmap), > @@ -348,6 +356,14 @@ if_idxmap_insert(struct ifnet *ifp) > i++; > } > > + nusedidx = malloc(howmany(nlimit, NBBY), > + M_IFADDR, M_WAITOK | M_ZERO); > + memcpy(nusedidx, if_idxmap.usedidx, > + howmany(if_map->limit, NBBY)); > + free(if_idxmap.usedidx, M_IFADDR, > + howmany(if_map->limit, NBBY)); > + if_idxmap.usedidx = nusedidx; > + > srp_update_locked(&if_map_gc, &if_idxmap.map, nif_map); > if_map = nif_map; > map = nmap; > @@ -355,15 +371,39 @@ if_idxmap_insert(struct ifnet *ifp) > > /* pick the next free index */ > for (i = 0; i < USHRT_MAX; i++) { > - if (index != 0 && srp_get_locked(&map[index]) == NULL) > + if (index != 0 && isclr(if_idxmap.usedidx, index)) > break; > > index = if_idxmap.serial++ & USHRT_MAX; > } > + KASSERT(index != 0 && index < if_map->limit); > + KASSERT(isclr(if_idxmap.usedidx, index)); > > - /* commit */ > + setbit(if_idxmap.usedidx, index); > ifp->if_index = index; > + > + rw_exit_write(&if_idxmap.lock); > +} > + > +void > +if_idxmap_insert(struct ifnet *ifp) > +{ > + struct if_map *if_map; > + struct srp *map; > + unsigned int index = ifp->if_index; > + > + rw_enter_write(&if_idxmap.lock); > + > + if_map = srp_get_locked(&if_idxmap.map); > + map = (struct srp *)(if_map + 1); > + > + KASSERT(index != 0 && index < if_map->limit); > + KASSERT(isset(if_idxmap.usedidx, index)); > + > + /* commit */ > srp_update_locked(&if_ifp_gc, &map[index], if_ref(ifp)); > + > + rw_exit_write(&if_idxmap.lock); > } > > void > @@ -375,8 +415,7 @@ if_idxmap_remove(struct ifnet *ifp) > > index = ifp->if_index; > > - /* the kernel lock guarantees serialised modifications to if_idxmap */ > - KERNEL_ASSERT_LOCKED(); > + rw_enter_write(&if_idxmap.lock); > > if_map = srp_get_locked(&if_idxmap.map); > KASSERT(index < if_map->limit); > @@ -386,7 +425,12 @@ if_idxmap_remove(struct ifnet *ifp) > > srp_update_locked(&if_ifp_gc, &map[index], NULL); > if_idxmap.count--; > + > + KASSERT(isset(if_idxmap.usedidx, index)); > + clrbit(if_idxmap.usedidx, index); > /* end of if_idxmap modifications */ > + > + rw_exit_write(&if_idxmap.lock); > } > > void > @@ -606,6 +650,8 @@ if_attach_common(struct ifnet *ifp) > KASSERTMSG(ifp->if_qstart != NULL, > "%s: if_qstart not set with MPSAFE set", ifp->if_xname); > } > + > + if_idxmap_alloc(ifp); > > ifq_init(&ifp->if_snd, ifp, 0); >