2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 1980, 1986, 1991, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * @(#)route.c 8.3.1.1 (Berkeley) 2/23/95
34 /************************************************************************
35 * Note: In this file a 'fib' is a "forwarding information base" *
36 * Which is the new name for an in kernel routing (next hop) table. *
37 ***********************************************************************/
40 #include "opt_inet6.h"
41 #include "opt_mrouting.h"
42 #include "opt_route.h"
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/malloc.h>
48 #include <sys/socket.h>
49 #include <sys/sysctl.h>
50 #include <sys/syslog.h>
51 #include <sys/sysproto.h>
53 #include <sys/domain.h>
54 #include <sys/eventhandler.h>
55 #include <sys/kernel.h>
57 #include <sys/rmlock.h>
60 #include <net/if_var.h>
61 #include <net/if_dl.h>
62 #include <net/route.h>
63 #include <net/route/route_ctl.h>
64 #include <net/route/route_var.h>
65 #include <net/route/nhop.h>
69 #include <net/radix_mpath.h>
72 #include <netinet/in.h>
73 #include <netinet/ip_mroute.h>
75 VNET_PCPUSTAT_DEFINE(struct rtstat, rtstat);
77 VNET_PCPUSTAT_SYSINIT(rtstat);
79 VNET_PCPUSTAT_SYSUNINIT(rtstat);
82 EVENTHANDLER_LIST_DEFINE(rt_addrmsg);
84 static int rt_ifdelroute(const struct rtentry *rt, const struct nhop_object *,
86 static int rt_exportinfo(struct rtentry *rt, struct rt_addrinfo *info,
90 * route initialization must occur before ip6_init2(), which happenas at
99 SYSINIT(route_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, route_init, NULL);
102 rt_table_init(int offset, int family, u_int fibnum)
106 rh = malloc(sizeof(struct rib_head), M_RTABLE, M_WAITOK | M_ZERO);
108 /* TODO: These details should be hidded inside radix.c */
109 /* Init masks tree */
110 rn_inithead_internal(&rh->head, rh->rnh_nodes, offset);
111 rn_inithead_internal(&rh->rmhead.head, rh->rmhead.mask_nodes, 0);
112 rh->head.rnh_masks = &rh->rmhead;
114 /* Save metadata associated with this routing table. */
115 rh->rib_family = family;
116 rh->rib_fibnum = fibnum;
118 rh->rib_vnet = curvnet;
128 /* Init subscription system */
129 rib_init_subscriptions(rh);
131 /* Finally, set base callbacks */
132 rh->rnh_addaddr = rn_addroute;
133 rh->rnh_deladdr = rn_delete;
134 rh->rnh_matchaddr = rn_match;
135 rh->rnh_lookup = rn_lookup;
136 rh->rnh_walktree = rn_walktree;
137 rh->rnh_walktree_from = rn_walktree_from;
143 rt_freeentry(struct radix_node *rn, void *arg)
145 struct radix_head * const rnh = arg;
146 struct radix_node *x;
148 x = (struct radix_node *)rn_delete(rn + 2, NULL, rnh);
155 rt_table_destroy(struct rib_head *rh)
158 tmproutes_destroy(rh);
160 rn_walktree(&rh->rmhead.head, rt_freeentry, &rh->rmhead.head);
162 nhops_destroy_rib(rh);
164 rib_destroy_subscriptions(rh);
166 /* Assume table is already empty */
167 RIB_LOCK_DESTROY(rh);
172 * Adds a temporal redirect entry to the routing table.
173 * @fibnum: fib number
174 * @dst: destination to install redirect to
175 * @gateway: gateway to go via
176 * @author: sockaddr of originating router, can be NULL
177 * @ifp: interface to use for the redirected route
178 * @flags: set of flags to add. Allowed: RTF_GATEWAY
179 * @lifetime_sec: time in seconds to expire this redirect.
181 * Retuns 0 on success, errno otherwise.
184 rib_add_redirect(u_int fibnum, struct sockaddr *dst, struct sockaddr *gateway,
185 struct sockaddr *author, struct ifnet *ifp, int flags, int lifetime_sec)
187 struct rib_cmd_info rc;
189 struct rt_addrinfo info;
190 struct rt_metrics rti_rmx;
195 if (rt_tables_get_rnh(fibnum, dst->sa_family) == NULL)
196 return (EAFNOSUPPORT);
198 /* Verify the allowed flag mask. */
199 KASSERT(((flags & ~(RTF_GATEWAY)) == 0),
200 ("invalid redirect flags: %x", flags));
201 flags |= RTF_HOST | RTF_DYNAMIC;
203 /* Get the best ifa for the given interface and gateway. */
204 if ((ifa = ifaof_ifpforaddr(gateway, ifp)) == NULL)
205 return (ENETUNREACH);
208 bzero(&info, sizeof(info));
209 info.rti_info[RTAX_DST] = dst;
210 info.rti_info[RTAX_GATEWAY] = gateway;
213 info.rti_flags = flags;
215 /* Setup route metrics to define expire time. */
216 bzero(&rti_rmx, sizeof(rti_rmx));
217 /* Set expire time as absolute. */
218 rti_rmx.rmx_expire = lifetime_sec + time_second;
219 info.rti_mflags |= RTV_EXPIRE;
220 info.rti_rmx = &rti_rmx;
222 error = rib_action(fibnum, RTM_ADD, &info, &rc);
226 /* TODO: add per-fib redirect stats. */
230 RTSTAT_INC(rts_dynamic);
232 /* Send notification of a route addition to userland. */
233 bzero(&info, sizeof(info));
234 info.rti_info[RTAX_DST] = dst;
235 info.rti_info[RTAX_GATEWAY] = gateway;
236 info.rti_info[RTAX_AUTHOR] = author;
237 rt_missmsg_fib(RTM_REDIRECT, &info, flags | RTF_UP, error, fibnum);
243 * Routing table ioctl interface.
246 rtioctl_fib(u_long req, caddr_t data, u_int fibnum)
250 * If more ioctl commands are added here, make sure the proper
251 * super-user checks are being performed because it is possible for
252 * prison-root to make it this far if raw sockets have been enabled
256 /* Multicast goop, grrr... */
257 return mrt_ioctl ? mrt_ioctl(req, data, fibnum) : EOPNOTSUPP;
264 ifa_ifwithroute(int flags, const struct sockaddr *dst,
265 const struct sockaddr *gateway, u_int fibnum)
270 if ((flags & RTF_GATEWAY) == 0) {
272 * If we are adding a route to an interface,
273 * and the interface is a pt to pt link
274 * we should search for the destination
275 * as our clue to the interface. Otherwise
276 * we can use the local address.
279 if (flags & RTF_HOST)
280 ifa = ifa_ifwithdstaddr(dst, fibnum);
282 ifa = ifa_ifwithaddr(gateway);
285 * If we are adding a route to a remote net
286 * or host, the gateway may still be on the
287 * other end of a pt to pt link.
289 ifa = ifa_ifwithdstaddr(gateway, fibnum);
292 ifa = ifa_ifwithnet(gateway, 0, fibnum);
294 struct nhop_object *nh;
296 nh = rib_lookup(fibnum, gateway, NHR_NONE, 0);
299 * dismiss a gateway that is reachable only
300 * through the default router
302 if ((nh == NULL) || (nh->nh_flags & NHF_DEFAULT))
306 if (ifa->ifa_addr->sa_family != dst->sa_family) {
307 struct ifaddr *oifa = ifa;
308 ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp);
317 * Copy most of @rt data into @info.
319 * If @flags contains NHR_COPY, copies dst,netmask and gw to the
320 * pointers specified by @info structure. Assume such pointers
321 * are zeroed sockaddr-like structures with sa_len field initialized
322 * to reflect size of the provided buffer. if no NHR_COPY is specified,
323 * point dst,netmask and gw @info fields to appropriate @rt values.
325 * if @flags contains NHR_REF, do refcouting on rt_ifp and rt_ifa.
327 * Returns 0 on success.
330 rt_exportinfo(struct rtentry *rt, struct rt_addrinfo *info, int flags)
332 struct rt_metrics *rmx;
333 struct sockaddr *src, *dst;
334 struct nhop_object *nh;
338 if (flags & NHR_COPY) {
339 /* Copy destination if dst is non-zero */
341 dst = info->rti_info[RTAX_DST];
342 sa_len = src->sa_len;
344 if (src->sa_len > dst->sa_len)
346 memcpy(dst, src, src->sa_len);
347 info->rti_addrs |= RTA_DST;
350 /* Copy mask if set && dst is non-zero */
352 dst = info->rti_info[RTAX_NETMASK];
353 if (src != NULL && dst != NULL) {
355 * Radix stores different value in sa_len,
356 * assume rt_mask() to have the same length
359 if (sa_len > dst->sa_len)
361 memcpy(dst, src, src->sa_len);
362 info->rti_addrs |= RTA_NETMASK;
365 /* Copy gateway is set && dst is non-zero */
367 dst = info->rti_info[RTAX_GATEWAY];
368 if ((nhop_get_rtflags(nh) & RTF_GATEWAY) &&
369 src != NULL && dst != NULL) {
370 if (src->sa_len > dst->sa_len)
372 memcpy(dst, src, src->sa_len);
373 info->rti_addrs |= RTA_GATEWAY;
376 info->rti_info[RTAX_DST] = rt_key(rt);
377 info->rti_addrs |= RTA_DST;
378 if (rt_mask(rt) != NULL) {
379 info->rti_info[RTAX_NETMASK] = rt_mask(rt);
380 info->rti_addrs |= RTA_NETMASK;
382 if (nhop_get_rtflags(nh) & RTF_GATEWAY) {
383 info->rti_info[RTAX_GATEWAY] = &nh->gw_sa;
384 info->rti_addrs |= RTA_GATEWAY;
390 info->rti_mflags |= RTV_MTU;
391 rmx->rmx_mtu = nh->nh_mtu;
394 info->rti_flags = rt->rte_flags | nhop_get_rtflags(nh);
395 info->rti_ifp = nh->nh_ifp;
396 info->rti_ifa = nh->nh_ifa;
397 if (flags & NHR_REF) {
398 if_ref(info->rti_ifp);
399 ifa_ref(info->rti_ifa);
406 * Lookups up route entry for @dst in RIB database for fib @fibnum.
407 * Exports entry data to @info using rt_exportinfo().
409 * If @flags contains NHR_REF, refcouting is performed on rt_ifp and rt_ifa.
410 * All references can be released later by calling rib_free_info().
412 * Returns 0 on success.
413 * Returns ENOENT for lookup failure, ENOMEM for export failure.
416 rib_lookup_info(uint32_t fibnum, const struct sockaddr *dst, uint32_t flags,
417 uint32_t flowid, struct rt_addrinfo *info)
421 struct radix_node *rn;
425 KASSERT((fibnum < rt_numfibs), ("rib_lookup_rte: bad fibnum"));
426 rh = rt_tables_get_rnh(fibnum, dst->sa_family);
431 rn = rh->rnh_matchaddr(__DECONST(void *, dst), &rh->head);
432 if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) {
434 /* Ensure route & ifp is UP */
435 if (RT_LINK_IS_UP(rt->rt_nhop->nh_ifp)) {
436 flags = (flags & NHR_REF) | NHR_COPY;
437 error = rt_exportinfo(rt, info, flags);
449 * Releases all references acquired by rib_lookup_info() when
450 * called with NHR_REF flags.
453 rib_free_info(struct rt_addrinfo *info)
456 ifa_free(info->rti_ifa);
457 if_rele(info->rti_ifp);
461 * Iterates over all existing fibs in system calling
462 * @setwa_f function prior to traversing each fib.
463 * Calls @wa_f function for each element in current fib.
464 * If af is not AF_UNSPEC, iterates over fibs in particular
468 rt_foreach_fib_walk(int af, rt_setwarg_t *setwa_f, rt_walktree_f_t *wa_f,
471 struct rib_head *rnh;
475 for (fibnum = 0; fibnum < rt_numfibs; fibnum++) {
476 /* Do we want some specific family? */
477 if (af != AF_UNSPEC) {
478 rnh = rt_tables_get_rnh(fibnum, af);
482 setwa_f(rnh, fibnum, af, arg);
485 rnh->rnh_walktree(&rnh->head, (walktree_f_t *)wa_f,arg);
490 for (i = 1; i <= AF_MAX; i++) {
491 rnh = rt_tables_get_rnh(fibnum, i);
495 setwa_f(rnh, fibnum, i, arg);
498 rnh->rnh_walktree(&rnh->head, (walktree_f_t *)wa_f,arg);
505 * Iterates over all existing fibs in system and deletes each element
506 * for which @filter_f function returns non-zero value.
507 * If @family is not AF_UNSPEC, iterates over fibs in particular
511 rt_foreach_fib_walk_del(int family, rt_filter_f_t *filter_f, void *arg)
516 for (fibnum = 0; fibnum < rt_numfibs; fibnum++) {
517 /* Do we want some specific family? */
518 if (family != AF_UNSPEC) {
526 for (i = start; i <= end; i++) {
527 if (rt_tables_get_rnh(fibnum, i) == NULL)
530 rib_walk_del(fibnum, i, filter_f, arg, 0);
536 * Delete Routes for a Network Interface
538 * Called for each routing entry via the rnh->rnh_walktree() call above
539 * to delete all route entries referencing a detaching network interface.
542 * rt pointer to rtentry
544 * arg argument passed to rnh->rnh_walktree() - detaching interface
548 * errno failed - reason indicated
551 rt_ifdelroute(const struct rtentry *rt, const struct nhop_object *nh, void *arg)
553 struct ifnet *ifp = arg;
555 if (nh->nh_ifp != ifp)
559 * Protect (sorta) against walktree recursion problems
562 if ((rt->rte_flags & RTF_UP) == 0)
569 * Delete all remaining routes using this interface
570 * Unfortuneatly the only way to do this is to slog through
571 * the entire routing table looking for routes which point
572 * to this interface...oh well...
575 rt_flushifroutes_af(struct ifnet *ifp, int af)
577 KASSERT((af >= 1 && af <= AF_MAX), ("%s: af %d not >= 1 and <= %d",
578 __func__, af, AF_MAX));
580 rt_foreach_fib_walk_del(af, rt_ifdelroute, ifp);
584 rt_flushifroutes(struct ifnet *ifp)
587 rt_foreach_fib_walk_del(AF_UNSPEC, rt_ifdelroute, ifp);
591 * Look up rt_addrinfo for a specific fib. Note that if rti_ifa is defined,
592 * it will be referenced so the caller must free it.
594 * Assume basic consistency checks are executed by callers:
595 * RTAX_DST exists, if RTF_GATEWAY is set, RTAX_GATEWAY exists as well.
598 rt_getifa_fib(struct rt_addrinfo *info, u_int fibnum)
600 const struct sockaddr *dst, *gateway, *ifpaddr, *ifaaddr;
601 struct epoch_tracker et;
602 int needref, error, flags;
604 dst = info->rti_info[RTAX_DST];
605 gateway = info->rti_info[RTAX_GATEWAY];
606 ifpaddr = info->rti_info[RTAX_IFP];
607 ifaaddr = info->rti_info[RTAX_IFA];
608 flags = info->rti_flags;
611 * ifp may be specified by sockaddr_dl
612 * when protocol address is ambiguous.
615 needref = (info->rti_ifa == NULL);
618 /* If we have interface specified by the ifindex in the address, use it */
619 if (info->rti_ifp == NULL && ifpaddr != NULL &&
620 ifpaddr->sa_family == AF_LINK) {
621 const struct sockaddr_dl *sdl = (const struct sockaddr_dl *)ifpaddr;
622 if (sdl->sdl_index != 0)
623 info->rti_ifp = ifnet_byindex(sdl->sdl_index);
626 * If we have source address specified, try to find it
627 * TODO: avoid enumerating all ifas on all interfaces.
629 if (info->rti_ifa == NULL && ifaaddr != NULL)
630 info->rti_ifa = ifa_ifwithaddr(ifaaddr);
631 if (info->rti_ifa == NULL) {
632 const struct sockaddr *sa;
635 * Most common use case for the userland-supplied routes.
637 * Choose sockaddr to select ifa.
638 * -- if ifp is set --
639 * Order of preference:
642 * Note: for interface routes link-level gateway address
643 * is specified to indicate the interface index without
644 * specifying RTF_GATEWAY. In this case, ignore gateway
645 * Note: gateway AF may be different from dst AF. In this case,
647 * 3) final destination.
648 * 4) if all of these fails, try to get at least link-level ifa.
650 * try to lookup gateway or dst in the routing table to get ifa
652 if (info->rti_info[RTAX_IFA] != NULL)
653 sa = info->rti_info[RTAX_IFA];
654 else if ((info->rti_flags & RTF_GATEWAY) != 0 &&
655 gateway->sa_family == dst->sa_family)
659 if (info->rti_ifp != NULL) {
660 info->rti_ifa = ifaof_ifpforaddr(sa, info->rti_ifp);
662 if (info->rti_ifa == NULL && gateway != NULL)
663 info->rti_ifa = ifaof_ifpforaddr(gateway, info->rti_ifp);
664 } else if (dst != NULL && gateway != NULL)
665 info->rti_ifa = ifa_ifwithroute(flags, dst, gateway,
668 info->rti_ifa = ifa_ifwithroute(flags, sa, sa,
671 if (needref && info->rti_ifa != NULL) {
672 if (info->rti_ifp == NULL)
673 info->rti_ifp = info->rti_ifa->ifa_ifp;
674 ifa_ref(info->rti_ifa);
682 rt_updatemtu(struct ifnet *ifp)
684 struct rib_head *rnh;
689 * Try to update rt_mtu for all routes using this interface
690 * Unfortunately the only way to do this is to traverse all
691 * routing tables in all fibs/domains.
693 for (i = 1; i <= AF_MAX; i++) {
694 mtu = if_getmtu_family(ifp, i);
695 for (j = 0; j < rt_numfibs; j++) {
696 rnh = rt_tables_get_rnh(j, i);
699 nhops_update_ifmtu(rnh, ifp, mtu);
705 int p_sockaddr(char *buf, int buflen, struct sockaddr *s);
706 int rt_print(char *buf, int buflen, struct rtentry *rt);
709 p_sockaddr(char *buf, int buflen, struct sockaddr *s)
713 switch (s->sa_family) {
715 paddr = &((struct sockaddr_in *)s)->sin_addr;
718 paddr = &((struct sockaddr_in6 *)s)->sin6_addr;
725 if (inet_ntop(s->sa_family, paddr, buf, buflen) == NULL)
728 return (strlen(buf));
732 rt_print(char *buf, int buflen, struct rtentry *rt)
734 struct sockaddr *addr, *mask;
740 i = p_sockaddr(buf, buflen, addr);
741 if (!(rt->rt_flags & RTF_HOST)) {
743 i += p_sockaddr(buf + i, buflen - i, mask);
746 if (rt->rt_flags & RTF_GATEWAY) {
748 i += p_sockaddr(buf + i, buflen - i, &rt->rt_nhop->gw_sa);
757 * Deletes key for single-path routes, unlinks rtentry with
758 * gateway specified in @info from multi-path routes.
760 * Returnes unlinked entry. In case of failure, returns NULL
761 * and sets @perror to ESRCH.
764 rt_mpath_unlink(struct rib_head *rnh, struct rt_addrinfo *info,
765 struct rtentry *rto, int *perror)
768 * if we got multipath routes, we require users to specify
769 * a matching RTAX_GATEWAY.
771 struct rtentry *rt; // *rto = NULL;
772 struct radix_node *rn;
775 gw = info->rti_info[RTAX_GATEWAY];
776 rt = rt_mpath_matchgate(rto, gw);
783 * this is the first entry in the chain
786 rn = rn_mpath_next((struct radix_node *)rt);
788 * there is another entry, now it's active
792 rto->rte_flags |= RTF_UP;
793 } else if (rt->rte_flags & RTF_GATEWAY) {
795 * For gateway routes, we need to
796 * make sure that we we are deleting
797 * the correct gateway.
798 * rt_mpath_matchgate() does not
799 * check the case when there is only
800 * one route in the chain.
803 (rt->rt_nhop->gw_sa.sa_len != gw->sa_len ||
804 memcmp(&rt->rt_nhop->gw_sa, gw, gw->sa_len))) {
811 * use the normal delete code to remove
814 rn = rnh->rnh_deladdr(info->rti_info[RTAX_DST],
815 info->rti_info[RTAX_NETMASK],
826 * if the entry is 2nd and on up
828 if (rt_mpath_deldup(rto, rt) == 0)
829 panic ("rtrequest1: rt_mpath_deldup");
831 rn = (struct radix_node *)rt;
837 rt_maskedcopy(struct sockaddr *src, struct sockaddr *dst, struct sockaddr *netmask)
839 u_char *cp1 = (u_char *)src;
840 u_char *cp2 = (u_char *)dst;
841 u_char *cp3 = (u_char *)netmask;
842 u_char *cplim = cp2 + *cp3;
843 u_char *cplim2 = cp2 + *cp1;
845 *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */
850 *cp2++ = *cp1++ & *cp3++;
852 bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2));
856 * Announce interface address arrival/withdraw
857 * Returns 0 on success.
860 rt_addrmsg(int cmd, struct ifaddr *ifa, int fibnum)
863 KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE,
864 ("unexpected cmd %d", cmd));
865 KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs),
866 ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs));
868 EVENTHANDLER_DIRECT_INVOKE(rt_addrmsg, ifa, cmd);
869 return (rtsock_addrmsg(cmd, ifa, fibnum));
873 * Announce kernel-originated route addition/removal to rtsock based on @rt data.
876 * @ifp: target route interface
877 * @fibnum: fib id or RT_ALL_FIBS
879 * Returns 0 on success.
882 rt_routemsg(int cmd, struct rtentry *rt, struct ifnet *ifp, int rti_addrs,
886 KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE,
887 ("unexpected cmd %d", cmd));
889 KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs),
890 ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs));
892 KASSERT(rt_key(rt) != NULL, (":%s: rt_key must be supplied", __func__));
894 return (rtsock_routemsg(cmd, rt, ifp, 0, fibnum));
898 * Announce kernel-originated route addition/removal to rtsock based on @rt data.
900 * @info: addrinfo structure with valid data.
901 * @fibnum: fib id or RT_ALL_FIBS
903 * Returns 0 on success.
906 rt_routemsg_info(int cmd, struct rt_addrinfo *info, int fibnum)
909 KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE || cmd == RTM_CHANGE,
910 ("unexpected cmd %d", cmd));
912 KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs),
913 ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs));
915 KASSERT(info->rti_info[RTAX_DST] != NULL, (":%s: RTAX_DST must be supplied", __func__));
917 return (rtsock_routemsg_info(cmd, info, fibnum));
921 * This is called to generate messages from the routing socket
922 * indicating a network interface has had addresses associated with it.
925 rt_newaddrmsg_fib(int cmd, struct ifaddr *ifa, struct rtentry *rt, int fibnum)
928 KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE,
929 ("unexpected cmd %u", cmd));
930 KASSERT(fibnum == RT_ALL_FIBS || (fibnum >= 0 && fibnum < rt_numfibs),
931 ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs));
933 if (cmd == RTM_ADD) {
934 rt_addrmsg(cmd, ifa, fibnum);
936 rt_routemsg(cmd, rt, ifa->ifa_ifp, 0, fibnum);
939 rt_routemsg(cmd, rt, ifa->ifa_ifp, 0, fibnum);
940 rt_addrmsg(cmd, ifa, fibnum);