Module Name: src Committed By: snj Date: Fri Nov 17 20:24:05 UTC 2017
Modified Files: src/sys/net [netbsd-8]: if_llatbl.c if_llatbl.h src/sys/netinet [netbsd-8]: if_arp.c in.c src/sys/netinet6 [netbsd-8]: in6.c nd6.c Log Message: Pull up following revision(s) (requested by ozaki-r in ticket #353): sys/net/if_llatbl.c: 1.22 sys/net/if_llatbl.h: 1.13 sys/netinet/if_arp.c: 1.254 sys/netinet/in.c: 1.208-1.209 sys/netinet6/in6.c: 1.249-1.250 sys/netinet6/nd6.c: 1.237 Remove redundant KASSERTMSG The function is static, has just one caller and the caller does the same check. -- Fix a deadlock between a route update and lltable It happens because rtalloc1 is called from lltable with holding IF_AFDATA_WLOCK. If a route update is in action, rtalloc1 would wait for its completion with holding IF_AFDATA_WLOCK. At the same moment, a softint (e.g., arpintr) may try to take IF_AFDATA_WLOCK and get stuck on it. Unfortunately the stuck softint prevents the route update from progressing because the route update calls psref_target_destroy that needs the softint to complete. A resource allocation graph of the senario looks like this: route update =(psref_target_destroy)=> softint => IF_AFDATA_WLOCK =(rt_update_wait)=> route update Fix the deadlock by pulling rtalloc1 out of the lltable codes inside IF_AFDATA_WLOCK. Note that the deadlock happens only if NET_MPSAFE is enabled. To generate a diff of this commit: cvs rdiff -u -r1.18.6.1 -r1.18.6.2 src/sys/net/if_llatbl.c cvs rdiff -u -r1.10.8.1 -r1.10.8.2 src/sys/net/if_llatbl.h cvs rdiff -u -r1.250.2.2 -r1.250.2.3 src/sys/netinet/if_arp.c cvs rdiff -u -r1.203.2.1 -r1.203.2.2 src/sys/netinet/in.c cvs rdiff -u -r1.245.2.1 -r1.245.2.2 src/sys/netinet6/in6.c cvs rdiff -u -r1.232.2.2 -r1.232.2.3 src/sys/netinet6/nd6.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/net/if_llatbl.c diff -u src/sys/net/if_llatbl.c:1.18.6.1 src/sys/net/if_llatbl.c:1.18.6.2 --- src/sys/net/if_llatbl.c:1.18.6.1 Fri Jul 7 13:57:26 2017 +++ src/sys/net/if_llatbl.c Fri Nov 17 20:24:05 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: if_llatbl.c,v 1.18.6.1 2017/07/07 13:57:26 martin Exp $ */ +/* $NetBSD: if_llatbl.c,v 1.18.6.2 2017/11/17 20:24:05 snj Exp $ */ /* * Copyright (c) 2004 Luigi Rizzo, Alessandro Cerri. All rights reserved. * Copyright (c) 2004-2008 Qing Li. All rights reserved. @@ -386,7 +386,7 @@ llentry_alloc(struct ifnet *ifp, struct (ifp->if_flags & IFF_NOARP) == 0) { #endif IF_AFDATA_WLOCK(ifp); - la = lla_create(lt, 0, (struct sockaddr *)dst); + la = lla_create(lt, 0, (struct sockaddr *)dst, NULL /* XXX */); IF_AFDATA_WUNLOCK(ifp); } @@ -656,7 +656,12 @@ lla_rt_output(const u_char rtm_type, con error = 0; switch (rtm_type) { - case RTM_ADD: + case RTM_ADD: { + struct rtentry *rt; + + /* Never call rtalloc1 with IF_AFDATA_WLOCK */ + rt = rtalloc1(dst, 0); + /* Add static LLE */ IF_AFDATA_WLOCK(ifp); lle = lla_lookup(llt, 0, dst); @@ -666,15 +671,19 @@ lla_rt_output(const u_char rtm_type, con (lle->la_flags & LLE_STATIC || lle->la_expire == 0)) { LLE_RUNLOCK(lle); IF_AFDATA_WUNLOCK(ifp); + if (rt != NULL) + rt_unref(rt); error = EEXIST; goto out; } if (lle != NULL) LLE_RUNLOCK(lle); - lle = lla_create(llt, 0, dst); + lle = lla_create(llt, 0, dst, rt); if (lle == NULL) { IF_AFDATA_WUNLOCK(ifp); + if (rt != NULL) + rt_unref(rt); error = ENOMEM; goto out; } @@ -703,6 +712,8 @@ lla_rt_output(const u_char rtm_type, con laflags = lle->la_flags; LLE_WUNLOCK(lle); IF_AFDATA_WUNLOCK(ifp); + if (rt != NULL) + rt_unref(rt); #if defined(INET) && NARP > 0 /* gratuitous ARP */ if ((laflags & LLE_PUB) && dst->sa_family == AF_INET) { @@ -721,8 +732,8 @@ lla_rt_output(const u_char rtm_type, con #else (void)laflags; #endif - break; + } case RTM_DELETE: IF_AFDATA_WLOCK(ifp); Index: src/sys/net/if_llatbl.h diff -u src/sys/net/if_llatbl.h:1.10.8.1 src/sys/net/if_llatbl.h:1.10.8.2 --- src/sys/net/if_llatbl.h:1.10.8.1 Fri Jul 7 13:57:26 2017 +++ src/sys/net/if_llatbl.h Fri Nov 17 20:24:05 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: if_llatbl.h,v 1.10.8.1 2017/07/07 13:57:26 martin Exp $ */ +/* $NetBSD: if_llatbl.h,v 1.10.8.2 2017/11/17 20:24:05 snj Exp $ */ /* * Copyright (c) 2004 Luigi Rizzo, Alessandro Cerri. All rights reserved. * Copyright (c) 2004-2008 Qing Li. All rights reserved. @@ -190,7 +190,7 @@ struct llentry { typedef struct llentry *(llt_lookup_t)(struct lltable *, u_int flags, const struct sockaddr *l3addr); typedef struct llentry *(llt_create_t)(struct lltable *, u_int flags, - const struct sockaddr *l3addr); + const struct sockaddr *l3addr, const struct rtentry *); typedef int (llt_delete_t)(struct lltable *, u_int flags, const struct sockaddr *l3addr); typedef void (llt_prefix_free_t)(struct lltable *, @@ -297,10 +297,11 @@ lla_lookup(struct lltable *llt, u_int fl } static __inline struct llentry * -lla_create(struct lltable *llt, u_int flags, const struct sockaddr *l3addr) +lla_create(struct lltable *llt, u_int flags, const struct sockaddr *l3addr, + const struct rtentry *rt) { - return (llt->llt_create(llt, flags, l3addr)); + return (llt->llt_create(llt, flags, l3addr, rt)); } static __inline int Index: src/sys/netinet/if_arp.c diff -u src/sys/netinet/if_arp.c:1.250.2.2 src/sys/netinet/if_arp.c:1.250.2.3 --- src/sys/netinet/if_arp.c:1.250.2.2 Fri Jul 7 13:57:27 2017 +++ src/sys/netinet/if_arp.c Fri Nov 17 20:24:05 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: if_arp.c,v 1.250.2.2 2017/07/07 13:57:27 martin Exp $ */ +/* $NetBSD: if_arp.c,v 1.250.2.3 2017/11/17 20:24:05 snj Exp $ */ /*- * Copyright (c) 1998, 2000, 2008 The NetBSD Foundation, Inc. @@ -68,7 +68,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.250.2.2 2017/07/07 13:57:27 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.250.2.3 2017/11/17 20:24:05 snj Exp $"); #ifdef _KERNEL_OPT #include "opt_ddb.h" @@ -754,10 +754,15 @@ notfound: } #undef _IFF_NOARP if (la == NULL) { + struct rtentry *_rt; + create_lookup = "create"; + _rt = rtalloc1(dst, 0); IF_AFDATA_WLOCK(ifp); - la = lla_create(LLTABLE(ifp), LLE_EXCLUSIVE, dst); + la = lla_create(LLTABLE(ifp), LLE_EXCLUSIVE, dst, _rt); IF_AFDATA_WUNLOCK(ifp); + if (_rt != NULL) + rt_unref(_rt); if (la == NULL) ARP_STATINC(ARP_STAT_ALLOCFAIL); else { @@ -1452,9 +1457,14 @@ arpcreate(struct ifnet *ifp, struct mbuf la = arplookup(ifp, m, addr, sa, wlock); if (la == NULL) { + struct rtentry *rt; + + rt = rtalloc1(sa, 0); IF_AFDATA_WLOCK(ifp); - la = lla_create(LLTABLE(ifp), flags, sa); + la = lla_create(LLTABLE(ifp), flags, sa, rt); IF_AFDATA_WUNLOCK(ifp); + if (rt != NULL) + rt_unref(rt); if (la != NULL) arp_init_llentry(ifp, la); Index: src/sys/netinet/in.c diff -u src/sys/netinet/in.c:1.203.2.1 src/sys/netinet/in.c:1.203.2.2 --- src/sys/netinet/in.c:1.203.2.1 Fri Jul 7 13:57:27 2017 +++ src/sys/netinet/in.c Fri Nov 17 20:24:05 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: in.c,v 1.203.2.1 2017/07/07 13:57:27 martin Exp $ */ +/* $NetBSD: in.c,v 1.203.2.2 2017/11/17 20:24:05 snj Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -91,7 +91,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: in.c,v 1.203.2.1 2017/07/07 13:57:27 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: in.c,v 1.203.2.2 2017/11/17 20:24:05 snj Exp $"); #include "arp.h" @@ -1938,15 +1938,11 @@ in_lltable_free_entry(struct lltable *ll } static int -in_lltable_rtcheck(struct ifnet *ifp, u_int flags, const struct sockaddr *l3addr) +in_lltable_rtcheck(struct ifnet *ifp, u_int flags, const struct sockaddr *l3addr, + const struct rtentry *rt) { - struct rtentry *rt; int error = EINVAL; - KASSERTMSG(l3addr->sa_family == AF_INET, - "sin_family %d", l3addr->sa_family); - - rt = rtalloc1(l3addr, 0); if (rt == NULL) return error; @@ -2007,7 +2003,6 @@ in_lltable_rtcheck(struct ifnet *ifp, u_ error = 0; error: - rt_unref(rt); return error; } @@ -2098,7 +2093,8 @@ in_lltable_delete(struct lltable *llt, u } static struct llentry * -in_lltable_create(struct lltable *llt, u_int flags, const struct sockaddr *l3addr) +in_lltable_create(struct lltable *llt, u_int flags, const struct sockaddr *l3addr, + const struct rtentry *rt) { const struct sockaddr_in *sin = (const struct sockaddr_in *)l3addr; struct ifnet *ifp = llt->llt_ifp; @@ -2123,7 +2119,7 @@ in_lltable_create(struct lltable *llt, u * verify this. */ if (!(flags & LLE_IFADDR) && - in_lltable_rtcheck(ifp, flags, l3addr) != 0) + in_lltable_rtcheck(ifp, flags, l3addr, rt) != 0) return (NULL); lle = in_lltable_new(sin->sin_addr, flags); Index: src/sys/netinet6/in6.c diff -u src/sys/netinet6/in6.c:1.245.2.1 src/sys/netinet6/in6.c:1.245.2.2 --- src/sys/netinet6/in6.c:1.245.2.1 Fri Jul 7 13:57:26 2017 +++ src/sys/netinet6/in6.c Fri Nov 17 20:24:05 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: in6.c,v 1.245.2.1 2017/07/07 13:57:26 martin Exp $ */ +/* $NetBSD: in6.c,v 1.245.2.2 2017/11/17 20:24:05 snj Exp $ */ /* $KAME: in6.c,v 1.198 2001/07/18 09:12:38 itojun Exp $ */ /* @@ -62,7 +62,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.245.2.1 2017/07/07 13:57:26 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.245.2.2 2017/11/17 20:24:05 snj Exp $"); #ifdef _KERNEL_OPT #include "opt_inet.h" @@ -2458,17 +2458,11 @@ in6_lltable_free_entry(struct lltable *l } static int -in6_lltable_rtcheck(struct ifnet *ifp, - u_int flags, - const struct sockaddr *l3addr) +in6_lltable_rtcheck(struct ifnet *ifp, u_int flags, + const struct sockaddr *l3addr, const struct rtentry *rt) { - struct rtentry *rt; char ip6buf[INET6_ADDRSTRLEN]; - KASSERTMSG(l3addr->sa_family == AF_INET6, - "sin_family %d", l3addr->sa_family); - - rt = rtalloc1(l3addr, 0); if (rt == NULL || (rt->rt_flags & RTF_GATEWAY) || rt->rt_ifp != ifp) { int s; struct ifaddr *ifa; @@ -2481,19 +2475,14 @@ in6_lltable_rtcheck(struct ifnet *ifp, ifa = ifaof_ifpforaddr(l3addr, ifp); if (ifa != NULL) { pserialize_read_exit(s); - if (rt != NULL) - rt_unref(rt); return 0; } pserialize_read_exit(s); log(LOG_INFO, "IPv6 address: \"%s\" is not on the network\n", IN6_PRINT(ip6buf, &((const struct sockaddr_in6 *)l3addr)->sin6_addr)); - if (rt != NULL) - rt_unref(rt); return EINVAL; } - rt_unref(rt); return 0; } @@ -2585,7 +2574,7 @@ in6_lltable_delete(struct lltable *llt, static struct llentry * in6_lltable_create(struct lltable *llt, u_int flags, - const struct sockaddr *l3addr) + const struct sockaddr *l3addr, const struct rtentry *rt) { const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)l3addr; struct ifnet *ifp = llt->llt_ifp; @@ -2608,7 +2597,7 @@ in6_lltable_create(struct lltable *llt, * verify this. */ if (!(flags & LLE_IFADDR) && - in6_lltable_rtcheck(ifp, flags, l3addr) != 0) + in6_lltable_rtcheck(ifp, flags, l3addr, rt) != 0) return NULL; lle = in6_lltable_new(&sin6->sin6_addr, flags); Index: src/sys/netinet6/nd6.c diff -u src/sys/netinet6/nd6.c:1.232.2.2 src/sys/netinet6/nd6.c:1.232.2.3 --- src/sys/netinet6/nd6.c:1.232.2.2 Tue Oct 24 09:00:22 2017 +++ src/sys/netinet6/nd6.c Fri Nov 17 20:24:05 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: nd6.c,v 1.232.2.2 2017/10/24 09:00:22 snj Exp $ */ +/* $NetBSD: nd6.c,v 1.232.2.3 2017/11/17 20:24:05 snj Exp $ */ /* $KAME: nd6.c,v 1.279 2002/06/08 11:16:51 itojun Exp $ */ /* @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.232.2.2 2017/10/24 09:00:22 snj Exp $"); +__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.232.2.3 2017/11/17 20:24:05 snj Exp $"); #ifdef _KERNEL_OPT #include "opt_net_mpsafe.h" @@ -950,14 +950,17 @@ nd6_create(const struct in6_addr *addr6, { struct sockaddr_in6 sin6; struct llentry *ln; + struct rtentry *rt; sockaddr_in6_init(&sin6, addr6, 0, 0, 0); + rt = rtalloc1(sin6tosa(&sin6), 0); IF_AFDATA_WLOCK(ifp); - ln = lla_create(LLTABLE6(ifp), LLE_EXCLUSIVE, - sin6tosa(&sin6)); + ln = lla_create(LLTABLE6(ifp), LLE_EXCLUSIVE, sin6tosa(&sin6), rt); IF_AFDATA_WUNLOCK(ifp); + if (rt != NULL) + rt_unref(rt); if (ln != NULL) ln->ln_state = ND6_LLINFO_NOSTATE;