On Wed, Jun 29, 2022 at 10:17:26PM +0200, Martin Pieuchot wrote:
> On 29/06/22(Wed) 19:40, Alexander Bluhm wrote:
> Note that some times the code checks for the RTF_LLINFO flags and some
> time for rt_llinfo != NULL. This is inconsistent and a bit confusing
> now that we use a mutex to protect those states.
Now I check for RTF_LLINFO and that assert rt_llinfo is consistent.
Always call arpinvalidate(rt). Checking flag or asserting pointer
gives only valid ressult when holding mutex.
> PS: What about ND6?
Haha. It has a big kernel lock.
Follow up diff below.
bluhm
Index: net/route.h
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/net/route.h,v
retrieving revision 1.196
diff -u -p -r1.196 route.h
--- net/route.h 28 Jun 2022 10:01:13 -0000 1.196
+++ net/route.h 16 Jul 2022 17:09:05 -0000
@@ -37,6 +37,7 @@
/*
* Locks used to protect struct members in this file:
+ * A arp_mtx mutex for arp list and route llinfo
* I immutable after creation
* T rttimer_mtx route timer lists
*/
@@ -109,7 +110,8 @@ struct rtentry {
struct sockaddr *rt_gateway; /* value */
struct ifaddr *rt_ifa; /* the answer: interface addr to use */
caddr_t rt_llinfo; /* pointer to link level info cache or
- to an MPLS structure */
+ to an MPLS structure
+ [A] for ARP llinfo_arp */
union {
struct rtentry *_nh; /* implied entry for gatewayed routes */
unsigned int _ref; /* # gatewayed caching this route */
@@ -120,7 +122,8 @@ struct rtentry {
LIST_HEAD(, rttimer) rt_timer; /* queue of timeouts for misc funcs */
struct rt_kmetrics rt_rmx; /* metrics used by rx'ing protocols */
unsigned int rt_ifidx; /* the answer: interface to use */
- unsigned int rt_flags; /* up/down?, host/net */
+ unsigned int rt_flags; /* up/down?, host/net
+ [A] for ARP RTF_LLINFO */
struct refcnt rt_refcnt; /* # held references */
int rt_plen; /* prefix length */
uint16_t rt_labelid; /* route label ID */
Index: netinet/if_ether.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/if_ether.c,v
retrieving revision 1.251
diff -u -p -r1.251 if_ether.c
--- netinet/if_ether.c 16 Jul 2022 15:25:30 -0000 1.251
+++ netinet/if_ether.c 16 Jul 2022 17:10:48 -0000
@@ -67,15 +67,15 @@
/*
* Locks used to protect struct members in this file:
+ * A arp_mtx mutex for arp list and route llinfo
* a atomic operations
* I immutable after creation
* K kernel lock
- * m arp mutex, needed when net lock is shared
* N net lock
*/
struct llinfo_arp {
- LIST_ENTRY(llinfo_arp) la_list; /* [mN] global arp_list */
+ LIST_ENTRY(llinfo_arp) la_list; /* [AN] global arp_list */
struct rtentry *la_rt; /* [I] backpointer to rtentry */
struct mbuf_queue la_mq; /* packet hold queue */
time_t la_refreshed; /* when was refresh sent */
@@ -105,7 +105,7 @@ struct niqueue arpinq = NIQUEUE_INITIALI
/* llinfo_arp live time, rt_llinfo and RTF_LLINFO are protected by arp_mtx */
struct mutex arp_mtx = MUTEX_INITIALIZER(IPL_SOFTNET);
-LIST_HEAD(, llinfo_arp) arp_list; /* [mN] list of all llinfo_arp structures */
+LIST_HEAD(, llinfo_arp) arp_list; /* [AN] list of all llinfo_arp structures */
struct pool arp_pool; /* [I] pool for llinfo_arp structures */
int arp_maxtries = 5; /* [I] arp requests before set to rejected */
int la_hold_total; /* [a] packets currently in the arp queue */
@@ -169,21 +169,24 @@ arp_rtrequest(struct ifnet *ifp, int req
uptime = getuptime();
switch (req) {
case RTM_ADD:
- if (rt->rt_flags & RTF_CLONING) {
+ if (ISSET(rt->rt_flags, RTF_CLONING)) {
rt->rt_expire = 0;
break;
}
- if ((rt->rt_flags & RTF_LOCAL) && rt->rt_llinfo == NULL)
+ if (ISSET(rt->rt_flags, RTF_LOCAL) &&
+ !ISSET(rt->rt_flags, RTF_LLINFO)) {
rt->rt_expire = 0;
+ }
/*
* Announce a new entry if requested or warn the user
* if another station has this IP address.
*/
- if (rt->rt_flags & (RTF_ANNOUNCE|RTF_LOCAL))
+ if (ISSET(rt->rt_flags, RTF_ANNOUNCE|RTF_LOCAL)) {
arprequest(ifp,
&satosin(rt_key(rt))->sin_addr.s_addr,
&satosin(rt_key(rt))->sin_addr.s_addr,
(u_char *)LLADDR(satosdl(gate)));
+ }
/*FALLTHROUGH*/
case RTM_RESOLVE:
if (gate->sa_family != AF_LINK ||
@@ -205,18 +208,19 @@ arp_rtrequest(struct ifnet *ifp, int req
}
mtx_enter(&arp_mtx);
- if (rt->rt_llinfo != NULL) {
+ if (ISSET(rt->rt_flags, RTF_LLINFO)) {
/* we lost the race, another thread has entered it */
mtx_leave(&arp_mtx);
pool_put(&arp_pool, la);
break;
}
+ KASSERT(rt->rt_llinfo == NULL);
mq_init(&la->la_mq, LA_HOLD_QUEUE, IPL_SOFTNET);
+ SET(rt->rt_flags, RTF_LLINFO);
rt->rt_llinfo = (caddr_t)la;
la->la_rt = rt;
- rt->rt_flags |= RTF_LLINFO;
LIST_INSERT_HEAD(&arp_list, la, la_list);
- if ((rt->rt_flags & RTF_LOCAL) == 0)
+ if (!ISSET(rt->rt_flags, RTF_LOCAL))
rt->rt_expire = uptime;
mtx_leave(&arp_mtx);
@@ -224,15 +228,16 @@ arp_rtrequest(struct ifnet *ifp, int req
case RTM_DELETE:
mtx_enter(&arp_mtx);
- la = (struct llinfo_arp *)rt->rt_llinfo;
- if (la == NULL) {
+ if (!ISSET(rt->rt_flags, RTF_LLINFO)) {
/* we lost the race, another thread has removed it */
mtx_leave(&arp_mtx);
break;
}
+ la = (struct llinfo_arp *)rt->rt_llinfo;
+ KASSERT(la != NULL);
LIST_REMOVE(la, la_list);
rt->rt_llinfo = NULL;
- rt->rt_flags &= ~RTF_LLINFO;
+ CLR(rt->rt_flags, RTF_LLINFO);
atomic_sub_int(&la_hold_total, mq_purge(&la->la_mq));
mtx_leave(&arp_mtx);
@@ -240,8 +245,7 @@ arp_rtrequest(struct ifnet *ifp, int req
break;
case RTM_INVALIDATE:
- if (!ISSET(rt->rt_flags, RTF_LOCAL))
- arpinvalidate(rt);
+ arpinvalidate(rt);
break;
}
}
@@ -750,11 +754,12 @@ arpinvalidate(struct rtentry *rt)
struct sockaddr_dl *sdl = satosdl(rt->rt_gateway);
mtx_enter(&arp_mtx);
- la = (struct llinfo_arp *)rt->rt_llinfo;
- if (la == NULL) {
+ if (!ISSET(rt->rt_flags, RTF_LLINFO)) {
mtx_leave(&arp_mtx);
return;
}
+ la = (struct llinfo_arp *)rt->rt_llinfo;
+ KASSERT(la != NULL);
atomic_sub_int(&la_hold_total, mq_purge(&la->la_mq));
sdl->sdl_alen = 0;
la->la_asked = 0;
@@ -769,7 +774,6 @@ arptfree(struct rtentry *rt)
{
struct ifnet *ifp;
- KASSERT(!ISSET(rt->rt_flags, RTF_LOCAL));
arpinvalidate(rt);
ifp = if_get(rt->rt_ifidx);