I just committed a diff to reuse the logic of rtinit() to manipulate routes to loopback used in our IPv6 stack.
Since this diff turned rtinit() into a wrapper around rt_ifa_add() and rt_ifa_del(), here's a diff to get completely rid of it. These new functions come with a man page which is far from being perfect but at least explains which routes are automatically managed by the kernel. This diff has another advantage, since the new API requires the caller to specify a `dst' argument, it allows us to remove some "save and restore" logic in in.c I totally agree that this API might be improved, but I believe it's a good step and this diff should not introduce any change in behavior. As you can see it's mostly IPv4 centric, since the IPv6 stack reroll its own functions to manipulate "connected routes". Hopefully somebody can try to replace the remaining rtrequest1(9) call with a priority of RTP_CONNECTED by this new API. Ok? Index: share/man/man9/Makefile =================================================================== RCS file: /cvs/src/share/man/man9/Makefile,v retrieving revision 1.206 diff -u -p -r1.206 Makefile --- share/man/man9/Makefile 2 Apr 2014 13:10:48 -0000 1.206 +++ share/man/man9/Makefile 3 Apr 2014 08:24:48 -0000 @@ -25,8 +25,8 @@ MAN= altq.9 aml_evalnode.9 atomic_add_in panic.9 pci_conf_read.9 pci_intr_map.9 pfind.9 physio.9 pmap.9 \ pool.9 powerhook_establish.9 ppsratecheck.9 printf.9 psignal.9 \ radio.9 arc4random.9 rasops.9 ratecheck.9 resettodr.9 rssadapt.9 \ - route.9 rt_timer_add.9 rtable_add.9 rtlabel_id2name.9 rtrequest1.9 \ - rwlock.9 sensor_attach.9 \ + rt_ifa_add.9 rt_timer_add.9 route.9 rtable_add.9 rtlabel_id2name.9 \ + rtrequest1.9 rwlock.9 sensor_attach.9 \ shutdownhook_establish.9 tsleep.9 spl.9 startuphook_establish.9 \ socreate.9 sosplice.9 style.9 syscall.9 systrace.9 sysctl_int.9 \ task_add.9 tc_init.9 time.9 timeout.9 tvtohz.9 uiomove.9 uvm.9 \ @@ -313,13 +313,15 @@ MLINKS+=rssadapt.9 ieee80211_rssadapt_ch MLINKS+=route.9 rt_lookup.9 route.9 rtalloc.9 route.9 rtalloc_noclone.9 \ route.9 rtalloc1.9 route.9 rtfree.9 route.9 rt_setgate.9 \ route.9 rtredirect.9 route.9 rtdeletemsg.9 -MLINKS+=rtable_add.9 rtable_exists.9 rtable_add.9 rtable_get.9 \ - rtable_add.9 rtable_l2.9 rtable_add.9 rtable_l2set.9 +MLINKS+=rt_ifa_add.9 rt_ifa_del.9 rt_ifa_add.9 rt_ifa_addloop.9 \ + rt_ifa_add.9 rt_ifa_delloop.9 MLINKS+=rt_timer_add.9 rt_timer_queue_create.9 \ rt_timer_add.9 rt_timer_queue_count.9 \ rt_timer_add.9 rt_timer_queue_change.9 \ rt_timer_add.9 rt_timer_queue_destroy.9 \ rt_timer_add.9 rt_timer_remove_all.9 +MLINKS+=rtable_add.9 rtable_exists.9 rtable_add.9 rtable_get.9 \ + rtable_add.9 rtable_l2.9 rtable_add.9 rtable_l2set.9 MLINKS+=rtlabel_id2name.9 rtlabel_name2id.9 \ rtlabel_id2name.9 rtlabel_id2sa.9 rtlabel_id2name.9 rtlabel_unref.9 MLINKS+=rwlock.9 rw_init.9 rwlock.9 rw_enter.9 rwlock.9 rw_exit.9 \ Index: share/man/man9/rt_ifa_add.9 =================================================================== RCS file: share/man/man9/rt_ifa_add.9 diff -N share/man/man9/rt_ifa_add.9 --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ share/man/man9/rt_ifa_add.9 3 Apr 2014 08:24:48 -0000 @@ -0,0 +1,104 @@ +.\" $OpenBSD$ +.\" +.\" Copyright (c) 2014 Martin Pieuchot +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate$ +.Dt RT_IFA_ADD 9 +.Os +.Sh NAME +.Nm rt_ifa_add , +.Nm rt_ifa_del , +.Nm rt_ifa_addloop , +.Nm rt_ifa_delloop +.Nd add or delete routes associated with an address +.Sh SYNOPSIS +.In sys/socket.h +.In net/if.h +.In net/route.h +.Ft int +.Fn rt_ifa_add "struct ifaddr *ifa" "int flags" "struct sockaddr *dst" +.Ft int +.Fn rt_ifa_del "struct ifaddr *ifa" "int flags" "struct sockaddr *dst" +.Ft void +.Fn rt_ifa_addloop "struct ifaddr *ifa" +.Ft void +.Fn rt_ifa_delloop "struct ifaddr *ifa" +.Sh DESCRIPTION +These functions create and delete routes required by the network stack +and managed by the kernel. +.Bl -tag -width rt_ifa_addloopxx +.It Fn rt_ifa_add +Creates and associates a connected route with +.Fa ifa . +.Pp +Connected routes are most of the time routes to prefix and should be created +with +.Dv RTF_CLONING +in +.Fa flags +and the address of +.Fa ifa +in +.Fa dst . +But for Point-to-Point interfaces, connected routes are routes to host and +should be created +with +.Dv RTF_HOST +in +.Fa flags +and the destination address in +.Fa dst . +Connected routes have a priority of +.Dv RTP_CONNECTED . +.It Fn rt_ifa_del +Removes the connected route associated with +.Fa ifa . +.It Fn rt_ifa_addloop +Creates and associates a local route +with +.Fa ifa . +.Pp +Local routes are used to not send packets destined to a local address on the +wire and instead redirect them to +.Xr lo 4 . +They have the lowest priority available, +.Dv RTP_LOCAL , +and contain a special flag, +.Dv RTF_LOCAL , +that can be checked to determine if the address is configured on the system. +.It Fn rt_ifa_delloop +Removes the local route associated with +.Fa ifa . +.El +.Sh CONTEXT +.Fn rt_ifa_add , +.Fn rt_ifa_del , +.Fn rt_ifa_addloop , +and +.Fn rt_ifa_delloop +can be called during autoconf, from process context, or from interrupt context. +.Sh RETURN VALUES +.Fn rt_ifa_add +and +.Fn rt_ifa_del +will return +.Dv 0 +on success and the return value of +.Xr rtrequest1 9 +otherwise. +.Sh SEE ALSO +.Xr lo 4 , +.Xr route 4 , +.Xr rtrequest1 9 Index: sys/net/if.c =================================================================== RCS file: /cvs/src/sys/net/if.c,v retrieving revision 1.282 diff -u -p -r1.282 if.c --- sys/net/if.c 20 Mar 2014 13:19:06 -0000 1.282 +++ sys/net/if.c 3 Apr 2014 08:24:58 -0000 @@ -368,7 +368,7 @@ if_free_sadl(struct ifnet *ifp) return; s = splnet(); - rtinit(ifa, RTM_DELETE, 0); + rt_ifa_del(ifa, 0, ifa->ifa_addr); ifa_del(ifp, ifa); ifafree(ifp->if_lladdr); ifp->if_lladdr = NULL; Index: sys/net/route.c =================================================================== RCS file: /cvs/src/sys/net/route.c,v retrieving revision 1.158 diff -u -p -r1.158 route.c --- sys/net/route.c 3 Apr 2014 08:22:10 -0000 1.158 +++ sys/net/route.c 3 Apr 2014 08:25:02 -0000 @@ -150,9 +150,6 @@ int rtflushclone1(struct radix_node *, v void rtflushclone(struct radix_node_head *, struct rtentry *); int rt_if_remove_rtdelete(struct radix_node *, void *, u_int); -int rt_ifa_add(struct ifaddr *, int, struct sockaddr *); -int rt_ifa_del(struct ifaddr *, int, struct sockaddr *); - #define LABELID_MAX 50000 struct rt_label { @@ -1077,28 +1074,6 @@ rt_maskedcopy(struct sockaddr *src, stru *cp2++ = *cp1++ & *cp3++; if (cp2 < cplim2) bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2)); -} - -/* - * Set up a routing table entry, normally - * for an interface. - */ -int -rtinit(struct ifaddr *ifa, int cmd, int flags) -{ - struct sockaddr *dst; - int error; - - KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE); - - dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr; - - if (cmd == RTM_ADD) - error = rt_ifa_add(ifa, flags, dst); - else - error = rt_ifa_del(ifa, flags, dst); - - return (error); } int Index: sys/net/route.h =================================================================== RCS file: /cvs/src/sys/net/route.h,v retrieving revision 1.90 diff -u -p -r1.90 route.h --- sys/net/route.h 3 Apr 2014 08:22:10 -0000 1.90 +++ sys/net/route.h 3 Apr 2014 08:25:04 -0000 @@ -401,7 +401,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_ifa_add(struct ifaddr *, int, struct sockaddr *); +int rt_ifa_del(struct ifaddr *, int, struct sockaddr *); void rt_ifa_addloop(struct ifaddr *); void rt_ifa_delloop(struct ifaddr *); int rtioctl(u_long, caddr_t, struct proc *); Index: sys/netinet/in.c =================================================================== RCS file: /cvs/src/sys/netinet/in.c,v retrieving revision 1.94 diff -u -p -r1.94 in.c --- sys/netinet/in.c 27 Mar 2014 10:39:23 -0000 1.94 +++ sys/netinet/in.c 3 Apr 2014 08:25:08 -0000 @@ -328,10 +328,9 @@ in_control(struct socket *so, u_long cmd return (error); } if (ia->ia_flags & IFA_ROUTE) { - ia->ia_ifa.ifa_dstaddr = sintosa(&oldaddr); - rtinit(&ia->ia_ifa, RTM_DELETE, RTF_UP | RTF_HOST); - ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr); - rtinit(&ia->ia_ifa, RTM_ADD, RTF_UP | RTF_HOST); + rt_ifa_del(&ia->ia_ifa, RTF_HOST, sintosa(&oldaddr)); + rt_ifa_add(&ia->ia_ifa, RTF_HOST, + ia->ia_ifa.ifa_dstaddr); } splx(s); break; @@ -773,7 +772,7 @@ in_addhost(struct in_ifaddr *ia0) return (0); } - error = rtinit(&ia0->ia_ifa, RTM_ADD, RTF_UP | RTF_HOST); + error = rt_ifa_add(&ia0->ia_ifa, RTF_HOST, ia0->ia_ifa.ifa_dstaddr); if (!error) ia0->ia_flags |= IFA_ROUTE; @@ -807,16 +806,17 @@ in_scrubhost(struct in_ifaddr *ia0) if ((ia->ia_flags & IFA_ROUTE) != 0) continue; - rtinit(&ia0->ia_ifa, RTM_DELETE, RTF_UP | RTF_HOST); + rt_ifa_del(&ia0->ia_ifa, RTF_HOST, ia0->ia_ifa.ifa_dstaddr); ia0->ia_flags &= ~IFA_ROUTE; - error = rtinit(&ia->ia_ifa, RTM_ADD, RTF_UP | RTF_HOST); + error = rt_ifa_add(&ia->ia_ifa, RTF_HOST, + ia->ia_ifa.ifa_dstaddr); if (!error) ia->ia_flags |= IFA_ROUTE; return (error); } - rtinit(&ia0->ia_ifa, RTM_DELETE, RTF_UP | RTF_HOST); + rt_ifa_del(&ia0->ia_ifa, RTF_HOST, ia0->ia_ifa.ifa_dstaddr); ia0->ia_flags &= ~IFA_ROUTE; return (0); @@ -858,7 +858,7 @@ in_addprefix(struct in_ifaddr *ia0) /* move to a real interface instead of carp interface */ if (ia->ia_ifp->if_type == IFT_CARP && ia0->ia_ifp->if_type != IFT_CARP) { - rtinit(&ia->ia_ifa, RTM_DELETE, RTF_UP | RTF_CLONING); + rt_ifa_del(&ia->ia_ifa, 0, ia->ia_ifa.ifa_addr); ia->ia_flags &= ~IFA_ROUTE; break; } @@ -873,7 +873,7 @@ in_addprefix(struct in_ifaddr *ia0) /* * noone seem to have prefix route. insert it. */ - error = rtinit(&ia0->ia_ifa, RTM_ADD, RTF_UP | RTF_CLONING); + error = rt_ifa_add(&ia0->ia_ifa, RTF_CLONING, ia0->ia_ifa.ifa_addr); if (!error) ia0->ia_flags |= IFA_ROUTE; return error; @@ -918,9 +918,10 @@ in_scrubprefix(struct in_ifaddr *ia0) /* * if we got a matching prefix route, move IFA_ROUTE to him */ - rtinit(&ia0->ia_ifa, RTM_DELETE, RTF_UP | RTF_CLONING); + rt_ifa_del(&ia0->ia_ifa, 0, ia0->ia_ifa.ifa_addr); ia0->ia_flags &= ~IFA_ROUTE; - error = rtinit(&ia->ia_ifa, RTM_ADD, RTF_UP | RTF_CLONING); + error = rt_ifa_add(&ia->ia_ifa, RTF_CLONING, + ia->ia_ifa.ifa_addr); if (error == 0) ia->ia_flags |= IFA_ROUTE; return error; @@ -929,7 +930,7 @@ in_scrubprefix(struct in_ifaddr *ia0) /* * noone seem to have prefix route. remove it. */ - rtinit(&ia0->ia_ifa, RTM_DELETE, RTF_UP | RTF_CLONING); + rt_ifa_del(&ia0->ia_ifa, 0, ia0->ia_ifa.ifa_addr); ia0->ia_flags &= ~IFA_ROUTE; return 0; } Index: sys/netinet6/in6.c =================================================================== RCS file: /cvs/src/sys/netinet6/in6.c,v retrieving revision 1.134 diff -u -p -r1.134 in6.c --- sys/netinet6/in6.c 3 Apr 2014 08:22:10 -0000 1.134 +++ sys/netinet6/in6.c 3 Apr 2014 08:25:09 -0000 @@ -750,9 +750,11 @@ in6_update_ifa(struct ifnet *ifp, struct */ if (dst6.sin6_family == AF_INET6 && !IN6_ARE_ADDR_EQUAL(&dst6.sin6_addr, &ia6->ia_dstaddr.sin6_addr)) { + struct ifaddr *ifa = &ia6->ia_ifa; + int e; - if ((ia6->ia_flags & IFA_ROUTE) != 0 && - rtinit(&ia6->ia_ifa, RTM_DELETE, RTF_UP | RTF_HOST)) { + if (((ia6->ia_flags & IFA_ROUTE) != 0) && + (e = rt_ifa_del(ifa, RTF_HOST, ifa->ifa_dstaddr) != 0)) { nd6log((LOG_ERR, "in6_update_ifa: failed to remove " "a route to the old destination: %s\n", inet_ntop(AF_INET6, &ia6->ia_addr.sin6_addr, @@ -1020,8 +1022,7 @@ in6_purgeaddr(struct ifaddr *ifa) if ((ia6->ia_flags & IFA_ROUTE) != 0 && ia6->ia_dstaddr.sin6_len != 0) { int e; - if ((e = rtinit(&ia6->ia_ifa, RTM_DELETE, - RTF_UP | RTF_HOST)) != 0) { + if ((e = rt_ifa_del(ifa, RTF_HOST, ifa->ifa_dstaddr)) != 0) { char addr[INET6_ADDRSTRLEN]; log(LOG_ERR, "in6_purgeaddr: failed to remove " "a route to the p2p destination: %s on %s, " @@ -1388,7 +1389,9 @@ in6_ifinit(struct ifnet *ifp, struct in6 */ plen = in6_mask2len(&ia6->ia_prefixmask.sin6_addr, NULL); /* XXX */ if (plen == 128 && ia6->ia_dstaddr.sin6_family == AF_INET6) { - if ((error = rtinit(&ia6->ia_ifa, RTM_ADD, RTF_UP | RTF_HOST))) + ifa = &ia6->ia_ifa; + error = rt_ifa_add(ifa, RTF_HOST, ifa->ifa_dstaddr); + if (error != 0) return (error); ia6->ia_flags |= IFA_ROUTE; }