On 19/01/15(Mon) 09:35, Todd C. Miller wrote: > On Mon, 19 Jan 2015 11:49:53 +0100, Martin Pieuchot wrote: > > > Instead of rerolling rtrequest1(RTM_DELETE...) code in various places, > > simply use rtdeletemsg() which also notify userland that the route entry > > is going away. > > Since rtdeletemsg() may call rtfree() doesn't this mean that we can > end up calling rtfree() twice? Or is rt->rt_refcnt never going to > be zero in this case?
It is indeed confusing. I tried to check every cases but in the end I think that it might be better to decouple the removal from the routing table and the rtfree(). Updated diff below does that. Another advantage I can see to this approach is to be more strict about the reference counter on a per-rt basic. Index: net/route.c =================================================================== RCS file: /home/ncvs/src/sys/net/route.c,v retrieving revision 1.200 diff -u -p -r1.200 route.c --- net/route.c 18 Jan 2015 14:51:43 -0000 1.200 +++ net/route.c 21 Jan 2015 12:17:21 -0000 @@ -544,11 +544,6 @@ rtdeletemsg(struct rtentry *rt, u_int ta rt_missmsg(RTM_DELETE, &info, info.rti_flags, ifp, error, tableid); - /* Adjust the refcount */ - if (error == 0 && rt->rt_refcnt <= 0) { - rt->rt_refcnt++; - rtfree(rt); - } return (error); } @@ -556,11 +551,19 @@ int rtflushclone1(struct radix_node *rn, void *arg, u_int id) { struct rtentry *rt, *parent; + int error; rt = (struct rtentry *)rn; parent = (struct rtentry *)arg; - if ((rt->rt_flags & RTF_CLONED) != 0 && rt->rt_parent == parent) - rtdeletemsg(rt, id); + if ((rt->rt_flags & RTF_CLONED) != 0 && rt->rt_parent == parent) { + error = rtdeletemsg(rt, id); + + /* Adjust the refcount */ + if (error == 0 && rt->rt_refcnt <= 0) { + rt->rt_refcnt++; + rtfree(rt); + } + } return 0; } @@ -1632,8 +1635,17 @@ rt_if_remove_rtdelete(struct radix_node if (rt->rt_ifp == ifp) { int cloning = (rt->rt_flags & RTF_CLONING); - if (rtdeletemsg(rt, id) == 0 && cloning) - return (EAGAIN); + if (rtdeletemsg(rt, id) == 0) { + + /* Adjust the refcount */ + if (rt->rt_refcnt <= 0) { + rt->rt_refcnt++; + rtfree(rt); + } + + if (cloning) + return (EAGAIN); + } } /* Index: netinet/if_ether.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/if_ether.c,v retrieving revision 1.141 diff -u -p -r1.141 if_ether.c --- netinet/if_ether.c 13 Jan 2015 12:16:18 -0000 1.141 +++ netinet/if_ether.c 21 Jan 2015 12:17:21 -0000 @@ -789,6 +789,7 @@ arptfree(struct llinfo_arp *la) struct rtentry *rt = la->la_rt; struct sockaddr_dl *sdl; u_int tid = 0; + int error; if (rt == NULL) panic("arptfree"); @@ -803,7 +804,13 @@ arptfree(struct llinfo_arp *la) if (rt->rt_ifp) tid = rt->rt_ifp->if_rdomain; - rtdeletemsg(rt, tid); + error = rtdeletemsg(rt, tid); + + /* Adjust the refcount */ + if (error == 0 && rt->rt_refcnt <= 0) { + rt->rt_refcnt++; + rtfree(rt); + } } /* Index: netinet/ip_icmp.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/ip_icmp.c,v retrieving revision 1.129 diff -u -p -r1.129 ip_icmp.c --- netinet/ip_icmp.c 22 Dec 2014 11:05:53 -0000 1.129 +++ netinet/ip_icmp.c 21 Jan 2015 12:17:21 -0000 @@ -1031,20 +1031,12 @@ icmp_mtudisc_timeout(struct rtentry *rt, (RTF_DYNAMIC | RTF_HOST)) { void *(*ctlfunc)(int, struct sockaddr *, u_int, void *); struct sockaddr_in sa; - struct rt_addrinfo info; int s; - memset(&info, 0, sizeof(info)); - info.rti_info[RTAX_DST] = rt_key(rt); - info.rti_info[RTAX_NETMASK] = rt_mask(rt); - info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; - info.rti_flags = rt->rt_flags; - sa = *(struct sockaddr_in *)rt_key(rt); s = splsoftnet(); - rtrequest1(RTM_DELETE, &info, rt->rt_priority, NULL, - r->rtt_tableid); + rtdeletemsg(rt, r->rtt_tableid); /* Notify TCP layer of increased Path MTU estimate */ ctlfunc = inetsw[ip_protox[IPPROTO_TCP]].pr_ctlinput; @@ -1083,18 +1075,10 @@ icmp_redirect_timeout(struct rtentry *rt if ((rt->rt_flags & (RTF_DYNAMIC | RTF_HOST)) == (RTF_DYNAMIC | RTF_HOST)) { - struct rt_addrinfo info; int s; - memset(&info, 0, sizeof(info)); - info.rti_info[RTAX_DST] = rt_key(rt); - info.rti_info[RTAX_NETMASK] = rt_mask(rt); - info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; - info.rti_flags = rt->rt_flags; - s = splsoftnet(); - rtrequest1(RTM_DELETE, &info, rt->rt_priority, NULL, - r->rtt_tableid); + rtdeletemsg(rt, r->rtt_tableid); splx(s); } } Index: netinet6/icmp6.c =================================================================== RCS file: /home/ncvs/src/sys/netinet6/icmp6.c,v retrieving revision 1.153 diff -u -p -r1.153 icmp6.c --- netinet6/icmp6.c 19 Jan 2015 13:53:55 -0000 1.153 +++ netinet6/icmp6.c 21 Jan 2015 12:17:21 -0000 @@ -1983,18 +1983,10 @@ icmp6_mtudisc_timeout(struct rtentry *rt panic("icmp6_mtudisc_timeout: bad route to timeout"); if ((rt->rt_flags & (RTF_DYNAMIC | RTF_HOST)) == (RTF_DYNAMIC | RTF_HOST)) { - struct rt_addrinfo info; int s; - bzero(&info, sizeof(info)); - info.rti_flags = rt->rt_flags; - info.rti_info[RTAX_DST] = rt_key(rt); - info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; - info.rti_info[RTAX_NETMASK] = rt_mask(rt); - s = splsoftnet(); - rtrequest1(RTM_DELETE, &info, rt->rt_priority, NULL, - r->rtt_tableid); + rtdeletemsg(rt, r->rtt_tableid); splx(s); } else { if (!(rt->rt_rmx.rmx_locks & RTV_MTU)) @@ -2009,18 +2001,10 @@ icmp6_redirect_timeout(struct rtentry *r panic("icmp6_redirect_timeout: bad route to timeout"); if ((rt->rt_flags & (RTF_GATEWAY | RTF_DYNAMIC | RTF_HOST)) == (RTF_GATEWAY | RTF_DYNAMIC | RTF_HOST)) { - struct rt_addrinfo info; int s; - bzero(&info, sizeof(info)); - info.rti_flags = rt->rt_flags; - info.rti_info[RTAX_DST] = rt_key(rt); - info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; - info.rti_info[RTAX_NETMASK] = rt_mask(rt); - s = splsoftnet(); - rtrequest1(RTM_DELETE, &info, rt->rt_priority, NULL, - r->rtt_tableid); + rtdeletemsg(rt, r->rtt_tableid); splx(s); } } Index: netinet6/in6_ifattach.c =================================================================== RCS file: /home/ncvs/src/sys/netinet6/in6_ifattach.c,v retrieving revision 1.81 diff -u -p -r1.81 in6_ifattach.c --- netinet6/in6_ifattach.c 10 Jan 2015 11:43:37 -0000 1.81 +++ netinet6/in6_ifattach.c 21 Jan 2015 12:17:21 -0000 @@ -666,15 +666,7 @@ in6_ifdetach(struct ifnet *ifp) sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index); rt = rtalloc(sin6tosa(&sin6), 0, ifp->if_rdomain); if (rt && rt->rt_ifp == ifp) { - struct rt_addrinfo info; - - bzero(&info, sizeof(info)); - info.rti_flags = rt->rt_flags; - info.rti_info[RTAX_DST] = rt_key(rt); - info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; - info.rti_info[RTAX_NETMASK] = rt_mask(rt); - rtrequest1(RTM_DELETE, &info, rt->rt_priority, NULL, - ifp->if_rdomain); + rtdeletemsg(rt, ifp->if_rdomain); rtfree(rt); } @@ -686,15 +678,7 @@ in6_ifdetach(struct ifnet *ifp) sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index); rt = rtalloc(sin6tosa(&sin6), 0, ifp->if_rdomain); if (rt && rt->rt_ifp == ifp) { - struct rt_addrinfo info; - - bzero(&info, sizeof(info)); - info.rti_flags = rt->rt_flags; - info.rti_info[RTAX_DST] = rt_key(rt); - info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; - info.rti_info[RTAX_NETMASK] = rt_mask(rt); - rtrequest1(RTM_DELETE, &info, rt->rt_priority, NULL, - ifp->if_rdomain); + rtdeletemsg(rt, ifp->if_rdomain); rtfree(rt); }