On Tue, Apr 25, 2023 at 11:44:34AM +0200, Alexander Bluhm wrote: > Hi, > > Mutex arp_mtx protects the llinfo_arp la_... fields. So kernel > lock is only needed for changing the route rt_flags. > > Of course there is a race between checking and setting rt_flags. > But the other checks of the RTF_REJECT flags were without kernel > lock before. This does not cause trouble, the worst thing that may > happen is to wait another exprire time for ARP retry. My diff does > not make it worse, reading rt_flags and rt_expire is done without > lock anyway.
This is progress in the right direction, I think. The XXXSMP comment is incorrect and confusing. > > The kernel lock is needed to change rt_flags. Testing without > KERNEL_LOCK() caused crashes. Still not nice, reducing kernel lock scope helps. With this diff in, we couldn't break the kernel with further unlock diffs. A clearer version of this diff would use two new bools `expired' and `reject' rather than a ternary `reject', but that can be polished and retested later. OK kn > > ok? > > bluhm > > Index: netinet/if_ether.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/if_ether.c,v > retrieving revision 1.262 > diff -u -p -r1.262 if_ether.c > --- netinet/if_ether.c 12 Apr 2023 16:14:42 -0000 1.262 > +++ netinet/if_ether.c 24 Apr 2023 14:44:51 -0000 > @@ -339,7 +339,7 @@ arpresolve(struct ifnet *ifp, struct rte > struct rtentry *rt = NULL; > char addr[INET_ADDRSTRLEN]; > time_t uptime; > - int refresh = 0; > + int refresh = 0, reject = 0; > > if (m->m_flags & M_BCAST) { /* broadcast */ > memcpy(desten, etherbroadcastaddr, sizeof(etherbroadcastaddr)); > @@ -411,16 +411,9 @@ arpresolve(struct ifnet *ifp, struct rte > if (ifp->if_flags & (IFF_NOARP|IFF_STATICARP)) > goto bad; > > - KERNEL_LOCK(); > - /* > - * Re-check since we grab the kernel lock after the first check. > - * rtrequest_delete() can be called with shared netlock. From > - * there arp_rtrequest() is reached which touches RTF_LLINFO > - * and rt_llinfo. As this is called with kernel lock we grab the > - * kernel lock here and are safe. XXXSMP > - */ > + mtx_enter(&arp_mtx); > if (!ISSET(rt->rt_flags, RTF_LLINFO)) { > - KERNEL_UNLOCK(); > + mtx_leave(&arp_mtx); > goto bad; > } > la = (struct llinfo_arp *)rt->rt_llinfo; > @@ -451,13 +444,13 @@ arpresolve(struct ifnet *ifp, struct rte > } > #endif > if (rt->rt_expire) { > - rt->rt_flags &= ~RTF_REJECT; > + reject = ~RTF_REJECT; > if (la->la_asked == 0 || rt->rt_expire != uptime) { > rt->rt_expire = uptime; > if (la->la_asked++ < arp_maxtries) > refresh = 1; > else { > - rt->rt_flags |= RTF_REJECT; > + reject = RTF_REJECT; > rt->rt_expire += arpt_down; > la->la_asked = 0; > la->la_refreshed = 0; > @@ -466,8 +459,18 @@ arpresolve(struct ifnet *ifp, struct rte > } > } > } > + mtx_leave(&arp_mtx); > > - KERNEL_UNLOCK(); > + if (reject == RTF_REJECT && !ISSET(rt->rt_flags, RTF_REJECT)) { > + KERNEL_LOCK(); > + SET(rt->rt_flags, RTF_REJECT); > + KERNEL_UNLOCK(); > + } > + if (reject == ~RTF_REJECT && ISSET(rt->rt_flags, RTF_REJECT)) { > + KERNEL_LOCK(); > + CLR(rt->rt_flags, RTF_REJECT); > + KERNEL_UNLOCK(); > + } > if (refresh) > arprequest(ifp, &satosin(rt->rt_ifa->ifa_addr)->sin_addr.s_addr, > &satosin(dst)->sin_addr.s_addr, ac->ac_enaddr); >