So I started to play with the routine table and I'm slowly trying to unify the various code paths to add and delete route entries. The diff below is a first step, it splits rtinit() into rt_add() and rt_delete() there should be no functional change.
ok? Index: net/if.c =================================================================== RCS file: /cvs/src/sys/net/if.c,v retrieving revision 1.262 diff -u -p -r1.262 if.c --- net/if.c 20 Aug 2013 09:14:22 -0000 1.262 +++ net/if.c 27 Aug 2013 13:33:03 -0000 @@ -353,7 +353,7 @@ if_free_sadl(struct ifnet *ifp) return; s = splnet(); - rtinit(ifa, RTM_DELETE, 0); + rt_del(ifa, 0); #if 0 ifa_del(ifp, ifa); ifp->if_lladdr = NULL; Index: net/route.c =================================================================== RCS file: /cvs/src/sys/net/route.c,v retrieving revision 1.144 diff -u -p -r1.144 route.c --- net/route.c 28 Mar 2013 23:10:05 -0000 1.144 +++ net/route.c 27 Aug 2013 13:33:03 -0000 @@ -1069,11 +1069,10 @@ rt_maskedcopy(struct sockaddr *src, stru * for an interface. */ int -rtinit(struct ifaddr *ifa, int cmd, int flags) +rt_add(struct ifaddr *ifa, int flags) { struct rtentry *rt; - struct sockaddr *dst, *deldst; - struct mbuf *m = NULL; + struct sockaddr *dst; struct rtentry *nrt = NULL; int error; struct rt_addrinfo info; @@ -1081,35 +1080,11 @@ rtinit(struct ifaddr *ifa, int cmd, int u_short rtableid = ifa->ifa_ifp->if_rdomain; dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr; - if (cmd == RTM_DELETE) { - if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) { - m = m_get(M_DONTWAIT, MT_SONAME); - if (m == NULL) - return (ENOBUFS); - deldst = mtod(m, struct sockaddr *); - rt_maskedcopy(dst, deldst, ifa->ifa_netmask); - dst = deldst; - } - if ((rt = rtalloc1(dst, 0, rtableid)) != NULL) { - rt->rt_refcnt--; - /* try to find the right route */ - while (rt && rt->rt_ifa != ifa) - rt = (struct rtentry *) - ((struct radix_node *)rt)->rn_dupedkey; - if (!rt) { - if (m != NULL) - (void) m_free(m); - return (flags & RTF_HOST ? EHOSTUNREACH - : ENETUNREACH); - } - } - } bzero(&info, sizeof(info)); info.rti_ifa = ifa; info.rti_flags = flags | ifa->ifa_flags; info.rti_info[RTAX_DST] = dst; - if (cmd == RTM_ADD) - info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr; + info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr; info.rti_info[RTAX_LABEL] = rtlabel_id2sa(ifa->ifa_ifp->if_rtlabelid, &sa_rl); @@ -1120,22 +1095,11 @@ rtinit(struct ifaddr *ifa, int cmd, int * change it to meet bsdi4 behavior. */ info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask; - error = rtrequest1(cmd, &info, RTP_CONNECTED, &nrt, rtableid); - if (cmd == RTM_DELETE) { - if (error == 0 && (rt = nrt) != NULL) { - rt_newaddrmsg(cmd, ifa, error, nrt); - if (rt->rt_refcnt <= 0) { - rt->rt_refcnt++; - rtfree(rt); - } - } - if (m != NULL) - (void) m_free(m); - } - if (cmd == RTM_ADD && error == 0 && (rt = nrt) != NULL) { + error = rtrequest1(RTM_ADD, &info, RTP_CONNECTED, &nrt, rtableid); + if (error == 0 && (rt = nrt) != NULL) { rt->rt_refcnt--; if (rt->rt_ifa != ifa) { - printf("rtinit: wrong ifa (%p) was (%p)\n", + printf("%s: wrong ifa (%p) was (%p)\n", __func__, ifa, rt->rt_ifa); if (rt->rt_ifa->ifa_rtrequest) rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, NULL); @@ -1146,8 +1110,68 @@ rtinit(struct ifaddr *ifa, int cmd, int if (ifa->ifa_rtrequest) ifa->ifa_rtrequest(RTM_ADD, rt, NULL); } - rt_newaddrmsg(cmd, ifa, error, nrt); + rt_newaddrmsg(RTM_ADD, ifa, error, nrt); + } + + return (error); +} + +int +rt_del(struct ifaddr *ifa, int flags) +{ + struct rtentry *rt; + struct sockaddr *dst, *deldst; + struct mbuf *m = NULL; + struct rtentry *nrt = NULL; + int error; + struct rt_addrinfo info; + u_short rtableid = ifa->ifa_ifp->if_rdomain; + + dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr; + if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) { + m = m_get(M_DONTWAIT, MT_SONAME); + if (m == NULL) + return (ENOBUFS); + deldst = mtod(m, struct sockaddr *); + rt_maskedcopy(dst, deldst, ifa->ifa_netmask); + dst = deldst; } + if ((rt = rtalloc1(dst, 0, rtableid)) != NULL) { + rt->rt_refcnt--; + /* try to find the right route */ + while (rt && rt->rt_ifa != ifa) + rt = (struct rtentry *) + ((struct radix_node *)rt)->rn_dupedkey; + if (!rt) { + if (m != NULL) + m_free(m); + return (flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); + } + } + + bzero(&info, sizeof(info)); + info.rti_ifa = ifa; + info.rti_flags = flags | ifa->ifa_flags; + info.rti_info[RTAX_DST] = dst; + + /* + * XXX here, it seems that we are assuming that ifa_netmask is NULL + * for RTF_HOST. bsdi4 passes NULL explicitly (via intermediate + * variable) when RTF_HOST is 1. still not sure if i can safely + * change it to meet bsdi4 behavior. + */ + info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask; + error = rtrequest1(RTM_DELETE, &info, RTP_CONNECTED, &nrt, rtableid); + if (error == 0 && (rt = nrt) != NULL) { + rt_newaddrmsg(RTM_DELETE, ifa, error, nrt); + if (rt->rt_refcnt <= 0) { + rt->rt_refcnt++; + rtfree(rt); + } + } + if (m != NULL) + (void) m_free(m); + return (error); } Index: net/route.h =================================================================== RCS file: /cvs/src/sys/net/route.h,v retrieving revision 1.78 diff -u -p -r1.78 route.h --- net/route.h 19 Sep 2012 16:14:01 -0000 1.78 +++ net/route.h 27 Aug 2013 13:33:03 -0000 @@ -396,7 +396,8 @@ struct rtentry * rtalloc1(struct sockaddr *, int, u_int); void rtfree(struct rtentry *); int rt_getifa(struct rt_addrinfo *, u_int); -int rtinit(struct ifaddr *, int, int); +int rt_add(struct ifaddr *, int); +int rt_del(struct ifaddr *, int); int rtioctl(u_long, caddr_t, struct proc *); void rtredirect(struct sockaddr *, struct sockaddr *, struct sockaddr *, int, struct sockaddr *, Index: netinet/in.c =================================================================== RCS file: /cvs/src/sys/netinet/in.c,v retrieving revision 1.83 diff -u -p -r1.83 in.c --- netinet/in.c 19 Aug 2013 08:45:34 -0000 1.83 +++ netinet/in.c 27 Aug 2013 13:33:04 -0000 @@ -323,9 +323,9 @@ in_control(struct socket *so, u_long cmd } if (ia->ia_flags & IFA_ROUTE) { ia->ia_ifa.ifa_dstaddr = sintosa(&oldaddr); - rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); + rt_del(&ia->ia_ifa, RTF_HOST); ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr); - rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP); + rt_add(&ia->ia_ifa, RTF_HOST | RTF_UP); } splx(s); break; @@ -777,8 +777,7 @@ in_addprefix(struct in_ifaddr *target, i /* move to a real interface instead of carp interface */ if (ia->ia_ifp->if_type == IFT_CARP && target->ia_ifp->if_type != IFT_CARP) { - rtinit(&(ia->ia_ifa), (int)RTM_DELETE, - rtinitflags(ia)); + rt_del(&ia->ia_ifa, rtinitflags(ia)); ia->ia_flags &= ~IFA_ROUTE; break; } @@ -793,7 +792,7 @@ in_addprefix(struct in_ifaddr *target, i /* * noone seem to have prefix route. insert it. */ - error = rtinit(&target->ia_ifa, (int)RTM_ADD, flags); + error = rt_add(&target->ia_ifa, flags); if (!error) target->ia_flags |= IFA_ROUTE; return error; @@ -842,12 +841,10 @@ in_scrubprefix(struct in_ifaddr *target) * if we got a matching prefix route, move IFA_ROUTE to him */ if ((ia->ia_flags & IFA_ROUTE) == 0) { - rtinit(&(target->ia_ifa), (int)RTM_DELETE, - rtinitflags(target)); + rt_del(&target->ia_ifa, rtinitflags(target)); target->ia_flags &= ~IFA_ROUTE; - error = rtinit(&ia->ia_ifa, (int)RTM_ADD, - rtinitflags(ia) | RTF_UP); + error = rt_add(&ia->ia_ifa, rtinitflags(ia) | RTF_UP); if (error == 0) ia->ia_flags |= IFA_ROUTE; return error; @@ -857,7 +854,7 @@ in_scrubprefix(struct in_ifaddr *target) /* * noone seem to have prefix route. remove it. */ - rtinit(&(target->ia_ifa), (int)RTM_DELETE, rtinitflags(target)); + rt_del(&target->ia_ifa, rtinitflags(target)); target->ia_flags &= ~IFA_ROUTE; return 0; } Index: netinet6/in6.c =================================================================== RCS file: /cvs/src/sys/netinet6/in6.c,v retrieving revision 1.118 diff -u -p -r1.118 in6.c --- netinet6/in6.c 26 Aug 2013 07:15:58 -0000 1.118 +++ netinet6/in6.c 27 Aug 2013 13:33:04 -0000 @@ -200,7 +200,7 @@ in6_ifloop_request(int cmd, struct ifadd /* * Report the addition/removal of the address to the routing socket. - * XXX: since we called rtinit for a p2p interface with a destination, + * XXX: since we called rt_add for a p2p interface with a destination, * we end up reporting twice in such a case. Should we rather * omit the second report? */ @@ -932,7 +932,7 @@ in6_update_ifa(struct ifnet *ifp, struct int e; if ((ia->ia_flags & IFA_ROUTE) != 0 && - (e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST)) != 0) { + (e = rt_del(&ia->ia_ifa, RTF_HOST)) != 0) { nd6log((LOG_ERR, "in6_update_ifa: failed to remove " "a route to the old destination: %s\n", ip6_sprintf(&ia->ia_addr.sin6_addr))); @@ -1193,8 +1193,7 @@ in6_purgeaddr(struct ifaddr *ifa) if ((ia->ia_flags & IFA_ROUTE) != 0 && ia->ia_dstaddr.sin6_len != 0) { int e; - if ((e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST)) - != 0) { + if ((e = rt_del(&ia->ia_ifa, RTF_HOST)) != 0) { log(LOG_ERR, "in6_purgeaddr: failed to remove " "a route to the p2p destination: %s on %s, " "errno=%d\n", @@ -1535,8 +1534,7 @@ in6_ifinit(struct ifnet *ifp, struct in6 */ plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */ if (plen == 128 && ia->ia_dstaddr.sin6_family == AF_INET6) { - if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, - RTF_UP | RTF_HOST)) != 0) + if ((error = rt_add(&ia->ia_ifa, RTF_UP | RTF_HOST)) != 0) return (error); ia->ia_flags |= IFA_ROUTE; }