route.c (97168be809a33a1e85556765b458692afddfe690) route.c (34a5582c47c7ec24a6bf7de8af32b1334a79f58e)
1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1980, 1986, 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions

--- 173 unchanged lines hidden (view full) ---

182SYSCTL_PROC(_net, OID_AUTO, my_fibnum, CTLTYPE_INT|CTLFLAG_RD,
183 NULL, 0, &sysctl_my_fibnum, "I", "default FIB of caller");
184
185static __inline struct rib_head **
186rt_tables_get_rnh_ptr(int table, int fam)
187{
188 struct rib_head **rnh;
189
1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1980, 1986, 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions

--- 173 unchanged lines hidden (view full) ---

182SYSCTL_PROC(_net, OID_AUTO, my_fibnum, CTLTYPE_INT|CTLFLAG_RD,
183 NULL, 0, &sysctl_my_fibnum, "I", "default FIB of caller");
184
185static __inline struct rib_head **
186rt_tables_get_rnh_ptr(int table, int fam)
187{
188 struct rib_head **rnh;
189
190 KASSERT(table >= 0 && table < rt_numfibs, ("%s: table out of bounds.",
191 __func__));
192 KASSERT(fam >= 0 && fam < (AF_MAX+1), ("%s: fam out of bounds.",
193 __func__));
190 KASSERT(table >= 0 && table < rt_numfibs,
191 ("%s: table out of bounds (0 <= %d < %d)", __func__, table,
192 rt_numfibs));
193 KASSERT(fam >= 0 && fam < (AF_MAX + 1),
194 ("%s: fam out of bounds (0 <= %d < %d)", __func__, fam, AF_MAX+1));
194
195 /* rnh is [fib=0][af=0]. */
196 rnh = (struct rib_head **)V_rt_tables;
197 /* Get the offset to the requested table and fam. */
198 rnh += table * (AF_MAX+1) + fam;
199
200 return (rnh);
201}

--- 157 unchanged lines hidden (view full) ---

359
360 /* Save metadata associated with this routing table. */
361 rh->rib_family = family;
362 rh->rib_fibnum = fibnum;
363#ifdef VIMAGE
364 rh->rib_vnet = curvnet;
365#endif
366
195
196 /* rnh is [fib=0][af=0]. */
197 rnh = (struct rib_head **)V_rt_tables;
198 /* Get the offset to the requested table and fam. */
199 rnh += table * (AF_MAX+1) + fam;
200
201 return (rnh);
202}

--- 157 unchanged lines hidden (view full) ---

360
361 /* Save metadata associated with this routing table. */
362 rh->rib_family = family;
363 rh->rib_fibnum = fibnum;
364#ifdef VIMAGE
365 rh->rib_vnet = curvnet;
366#endif
367
368 tmproutes_init(rh);
369
367 /* Init locks */
368 RIB_LOCK_INIT(rh);
369
370 /* Finally, set base callbacks */
371 rh->rnh_addaddr = rn_addroute;
372 rh->rnh_deladdr = rn_delete;
373 rh->rnh_matchaddr = rn_match;
374 rh->rnh_lookup = rn_lookup;

--- 14 unchanged lines hidden (view full) ---

389 R_Free(x);
390 return (0);
391}
392
393void
394rt_table_destroy(struct rib_head *rh)
395{
396
370 /* Init locks */
371 RIB_LOCK_INIT(rh);
372
373 /* Finally, set base callbacks */
374 rh->rnh_addaddr = rn_addroute;
375 rh->rnh_deladdr = rn_delete;
376 rh->rnh_matchaddr = rn_match;
377 rh->rnh_lookup = rn_lookup;

--- 14 unchanged lines hidden (view full) ---

392 R_Free(x);
393 return (0);
394}
395
396void
397rt_table_destroy(struct rib_head *rh)
398{
399
400 tmproutes_destroy(rh);
401
397 rn_walktree(&rh->rmhead.head, rt_freeentry, &rh->rmhead.head);
398
399 /* Assume table is already empty */
400 RIB_LOCK_DESTROY(rh);
401 free(rh, M_RTABLE);
402}
403
404

--- 174 unchanged lines hidden (view full) ---

579 */
580 uma_zfree(V_rtzone, rt);
581 return;
582 }
583done:
584 RT_UNLOCK(rt);
585}
586
402 rn_walktree(&rh->rmhead.head, rt_freeentry, &rh->rmhead.head);
403
404 /* Assume table is already empty */
405 RIB_LOCK_DESTROY(rh);
406 free(rh, M_RTABLE);
407}
408
409

--- 174 unchanged lines hidden (view full) ---

584 */
585 uma_zfree(V_rtzone, rt);
586 return;
587 }
588done:
589 RT_UNLOCK(rt);
590}
591
587
588/*
592/*
589 * Force a routing table entry to the specified
590 * destination to go through the given gateway.
591 * Normally called as a result of a routing redirect
592 * message from the network layer.
593 * Adds a temporal redirect entry to the routing table.
594 * @fibnum: fib number
595 * @dst: destination to install redirect to
596 * @gateway: gateway to go via
597 * @author: sockaddr of originating router, can be NULL
598 * @ifp: interface to use for the redirected route
599 * @flags: set of flags to add. Allowed: RTF_GATEWAY
600 * @lifetime_sec: time in seconds to expire this redirect.
601 *
602 * Retuns 0 on success, errno otherwise.
593 */
603 */
594void
595rtredirect_fib(struct sockaddr *dst,
596 struct sockaddr *gateway,
597 struct sockaddr *netmask,
598 int flags,
599 struct sockaddr *src,
600 u_int fibnum)
604int
605rib_add_redirect(u_int fibnum, struct sockaddr *dst, struct sockaddr *gateway,
606 struct sockaddr *author, struct ifnet *ifp, int flags, int lifetime_sec)
601{
602 struct rtentry *rt;
607{
608 struct rtentry *rt;
603 int error = 0;
609 int error;
604 struct rt_addrinfo info;
610 struct rt_addrinfo info;
611 struct rt_metrics rti_rmx;
605 struct ifaddr *ifa;
612 struct ifaddr *ifa;
606 struct rib_head *rnh;
607
608 NET_EPOCH_ASSERT();
609
613
614 NET_EPOCH_ASSERT();
615
610 ifa = NULL;
611 rnh = rt_tables_get_rnh(fibnum, dst->sa_family);
612 if (rnh == NULL) {
613 error = EAFNOSUPPORT;
614 goto out;
616 if (rt_tables_get_rnh(fibnum, dst->sa_family) == NULL)
617 return (EAFNOSUPPORT);
618
619 /* Verify the allowed flag mask. */
620 KASSERT(((flags & ~(RTF_GATEWAY)) == 0),
621 ("invalid redirect flags: %x", flags));
622
623 /* Get the best ifa for the given interface and gateway. */
624 if ((ifa = ifaof_ifpforaddr(gateway, ifp)) == NULL)
625 return (ENETUNREACH);
626 ifa_ref(ifa);
627
628 bzero(&info, sizeof(info));
629 info.rti_info[RTAX_DST] = dst;
630 info.rti_info[RTAX_GATEWAY] = gateway;
631 info.rti_ifa = ifa;
632 info.rti_ifp = ifp;
633 info.rti_flags = flags | RTF_DYNAMIC;
634
635 /* Setup route metrics to define expire time. */
636 bzero(&rti_rmx, sizeof(rti_rmx));
637 /* Set expire time as absolute. */
638 rti_rmx.rmx_expire = lifetime_sec + time_second;
639 info.rti_mflags |= RTV_EXPIRE;
640 info.rti_rmx = &rti_rmx;
641
642 error = rtrequest1_fib(RTM_ADD, &info, &rt, fibnum);
643 ifa_free(ifa);
644
645 if (error != 0) {
646 /* TODO: add per-fib redirect stats. */
647 return (error);
615 }
648 }
616 /* verify the gateway is directly reachable */
617 if ((ifa = ifa_ifwithnet(gateway, 0, fibnum)) == NULL) {
618 error = ENETUNREACH;
619 goto out;
620 }
621 rt = rtalloc1_fib(dst, 0, 0UL, fibnum); /* NB: rt is locked */
622 /*
623 * If the redirect isn't from our current router for this dst,
624 * it's either old or wrong. If it redirects us to ourselves,
625 * we have a routing loop, perhaps as a result of an interface
626 * going down recently.
627 */
628 if (!(flags & RTF_DONE) && rt) {
629 if (!sa_equal(src, rt->rt_gateway)) {
630 error = EINVAL;
631 goto done;
632 }
633 if (rt->rt_ifa != ifa && ifa->ifa_addr->sa_family != AF_LINK) {
634 error = EINVAL;
635 goto done;
636 }
637 }
638 if ((flags & RTF_GATEWAY) && ifa_ifwithaddr_check(gateway)) {
639 error = EHOSTUNREACH;
640 goto done;
641 }
642 /*
643 * Create a new entry if we just got back a wildcard entry
644 * or the lookup failed. This is necessary for hosts
645 * which use routing redirects generated by smart gateways
646 * to dynamically build the routing tables.
647 */
648 if (rt == NULL || (rt_mask(rt) && rt_mask(rt)->sa_len < 2))
649 goto create;
650 /*
651 * Don't listen to the redirect if it's
652 * for a route to an interface.
653 */
654 if (rt->rt_flags & RTF_GATEWAY) {
655 if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
656 /*
657 * Changing from route to net => route to host.
658 * Create new route, rather than smashing route to net.
659 */
660 create:
661 if (rt != NULL)
662 RTFREE_LOCKED(rt);
663
664 flags |= RTF_DYNAMIC;
665 bzero((caddr_t)&info, sizeof(info));
666 info.rti_info[RTAX_DST] = dst;
667 info.rti_info[RTAX_GATEWAY] = gateway;
668 info.rti_info[RTAX_NETMASK] = netmask;
669 ifa_ref(ifa);
670 info.rti_ifa = ifa;
671 info.rti_flags = flags;
672 error = rtrequest1_fib(RTM_ADD, &info, &rt, fibnum);
673 if (rt != NULL) {
674 RT_LOCK(rt);
675 flags = rt->rt_flags;
676 }
677 if (error == 0)
678 RTSTAT_INC(rts_dynamic);
679 } else {
680
649
681 /*
682 * Smash the current notion of the gateway to
683 * this destination. Should check about netmask!!!
684 */
685 if ((flags & RTF_GATEWAY) == 0)
686 rt->rt_flags &= ~RTF_GATEWAY;
687 rt->rt_flags |= RTF_MODIFIED;
688 flags |= RTF_MODIFIED;
689 RTSTAT_INC(rts_newgateway);
690 /*
691 * add the key and gateway (in one malloc'd chunk).
692 */
693 RT_UNLOCK(rt);
694 RIB_WLOCK(rnh);
695 RT_LOCK(rt);
696 rt_setgate(rt, rt_key(rt), gateway);
697 RIB_WUNLOCK(rnh);
698 }
699 } else
700 error = EHOSTUNREACH;
701done:
702 if (rt)
703 RTFREE_LOCKED(rt);
704 out:
705 if (error)
706 RTSTAT_INC(rts_badredirect);
707 bzero((caddr_t)&info, sizeof(info));
650 RT_LOCK(rt);
651 flags = rt->rt_flags;
652 RTFREE_LOCKED(rt);
653
654 RTSTAT_INC(rts_dynamic);
655
656 /* Send notification of a route addition to userland. */
657 bzero(&info, sizeof(info));
708 info.rti_info[RTAX_DST] = dst;
709 info.rti_info[RTAX_GATEWAY] = gateway;
658 info.rti_info[RTAX_DST] = dst;
659 info.rti_info[RTAX_GATEWAY] = gateway;
710 info.rti_info[RTAX_NETMASK] = netmask;
711 info.rti_info[RTAX_AUTHOR] = src;
660 info.rti_info[RTAX_AUTHOR] = author;
712 rt_missmsg_fib(RTM_REDIRECT, &info, flags, error, fibnum);
661 rt_missmsg_fib(RTM_REDIRECT, &info, flags, error, fibnum);
662
663 return (0);
713}
714
715/*
716 * Routing table ioctl interface.
717 */
718int
719rtioctl_fib(u_long req, caddr_t data, u_int fibnum)
720{

--- 333 unchanged lines hidden (view full) ---

1054 /* Entry was unlinked. Add to the list and return */
1055 rt->rt_chain = di->head;
1056 di->head = rt;
1057
1058 return (0);
1059}
1060
1061/*
664}
665
666/*
667 * Routing table ioctl interface.
668 */
669int
670rtioctl_fib(u_long req, caddr_t data, u_int fibnum)
671{

--- 333 unchanged lines hidden (view full) ---

1005 /* Entry was unlinked. Add to the list and return */
1006 rt->rt_chain = di->head;
1007 di->head = rt;
1008
1009 return (0);
1010}
1011
1012/*
1062 * Iterates over all existing fibs in system.
1063 * Deletes each element for which @filter_f function returned
1064 * non-zero value.
1065 * If @af is not AF_UNSPEC, iterates over fibs in particular
1066 * address family.
1013 * Iterates over a routing table specified by @fibnum and @family and
1014 * deletes elements marked by @filter_f.
1015 * @fibnum: rtable id
1016 * @family: AF_ address family
1017 * @filter_f: function returning non-zero value for items to delete
1018 * @arg: data to pass to the @filter_f function
1019 * @report: true if rtsock notification is needed.
1067 */
1068void
1020 */
1021void
1069rt_foreach_fib_walk_del(int af, rt_filter_f_t *filter_f, void *arg)
1022rib_walk_del(u_int fibnum, int family, rt_filter_f_t *filter_f, void *arg, bool report)
1070{
1071 struct rib_head *rnh;
1072 struct rt_delinfo di;
1073 struct rtentry *rt;
1023{
1024 struct rib_head *rnh;
1025 struct rt_delinfo di;
1026 struct rtentry *rt;
1074 uint32_t fibnum;
1075 int i, start, end;
1076
1027
1028 rnh = rt_tables_get_rnh(fibnum, family);
1029 if (rnh == NULL)
1030 return;
1031
1077 bzero(&di, sizeof(di));
1078 di.info.rti_filter = filter_f;
1079 di.info.rti_filterdata = arg;
1032 bzero(&di, sizeof(di));
1033 di.info.rti_filter = filter_f;
1034 di.info.rti_filterdata = arg;
1035 di.rnh = rnh;
1080
1036
1037 RIB_WLOCK(rnh);
1038 rnh->rnh_walktree(&rnh->head, rt_checkdelroute, &di);
1039 RIB_WUNLOCK(rnh);
1040
1041 if (di.head == NULL)
1042 return;
1043
1044 /* We might have something to reclaim. */
1045 while (di.head != NULL) {
1046 rt = di.head;
1047 di.head = rt->rt_chain;
1048 rt->rt_chain = NULL;
1049
1050 /* TODO std rt -> rt_addrinfo export */
1051 di.info.rti_info[RTAX_DST] = rt_key(rt);
1052 di.info.rti_info[RTAX_NETMASK] = rt_mask(rt);
1053
1054 rt_notifydelete(rt, &di.info);
1055
1056 if (report)
1057 rt_routemsg(RTM_DELETE, rt, rt->rt_ifp, 0, fibnum);
1058 RTFREE_LOCKED(rt);
1059 }
1060}
1061
1062/*
1063 * Iterates over all existing fibs in system and deletes each element
1064 * for which @filter_f function returns non-zero value.
1065 * If @family is not AF_UNSPEC, iterates over fibs in particular
1066 * address family.
1067 */
1068void
1069rt_foreach_fib_walk_del(int family, rt_filter_f_t *filter_f, void *arg)
1070{
1071 u_int fibnum;
1072 int i, start, end;
1073
1081 for (fibnum = 0; fibnum < rt_numfibs; fibnum++) {
1082 /* Do we want some specific family? */
1074 for (fibnum = 0; fibnum < rt_numfibs; fibnum++) {
1075 /* Do we want some specific family? */
1083 if (af != AF_UNSPEC) {
1084 start = af;
1085 end = af;
1076 if (family != AF_UNSPEC) {
1077 start = family;
1078 end = family;
1086 } else {
1087 start = 1;
1088 end = AF_MAX;
1089 }
1090
1091 for (i = start; i <= end; i++) {
1079 } else {
1080 start = 1;
1081 end = AF_MAX;
1082 }
1083
1084 for (i = start; i <= end; i++) {
1092 rnh = rt_tables_get_rnh(fibnum, i);
1093 if (rnh == NULL)
1085 if (rt_tables_get_rnh(fibnum, i) == NULL)
1094 continue;
1086 continue;
1095 di.rnh = rnh;
1096
1087
1097 RIB_WLOCK(rnh);
1098 rnh->rnh_walktree(&rnh->head, rt_checkdelroute, &di);
1099 RIB_WUNLOCK(rnh);
1100
1101 if (di.head == NULL)
1102 continue;
1103
1104 /* We might have something to reclaim */
1105 while (di.head != NULL) {
1106 rt = di.head;
1107 di.head = rt->rt_chain;
1108 rt->rt_chain = NULL;
1109
1110 /* TODO std rt -> rt_addrinfo export */
1111 di.info.rti_info[RTAX_DST] = rt_key(rt);
1112 di.info.rti_info[RTAX_NETMASK] = rt_mask(rt);
1113
1114 rt_notifydelete(rt, &di.info);
1115 RTFREE_LOCKED(rt);
1116 }
1117
1088 rib_walk_del(fibnum, i, filter_f, arg, 0);
1118 }
1119 }
1120}
1121
1122/*
1123 * Delete Routes for a Network Interface
1124 *
1125 * Called for each routing entry via the rnh->rnh_walktree() call above

--- 569 unchanged lines hidden (view full) ---

1695 uma_zfree(V_rtzone, rt);
1696 return (EEXIST);
1697 }
1698#endif
1699
1700 /* XXX mtu manipulation will be done in rnh_addaddr -- itojun */
1701 rn = rnh->rnh_addaddr(ndst, netmask, &rnh->head, rt->rt_nodes);
1702
1089 }
1090 }
1091}
1092
1093/*
1094 * Delete Routes for a Network Interface
1095 *
1096 * Called for each routing entry via the rnh->rnh_walktree() call above

--- 569 unchanged lines hidden (view full) ---

1666 uma_zfree(V_rtzone, rt);
1667 return (EEXIST);
1668 }
1669#endif
1670
1671 /* XXX mtu manipulation will be done in rnh_addaddr -- itojun */
1672 rn = rnh->rnh_addaddr(ndst, netmask, &rnh->head, rt->rt_nodes);
1673
1674 if (rn != NULL && rt->rt_expire > 0)
1675 tmproutes_update(rnh, rt);
1676
1703 rt_old = NULL;
1704 if (rn == NULL && (info->rti_flags & RTF_PINNED) != 0) {
1705
1706 /*
1707 * Force removal and re-try addition
1708 * TODO: better multipath&pinned support
1709 */
1710 struct sockaddr *info_dst = info->rti_info[RTAX_DST];

--- 604 unchanged lines hidden ---
1677 rt_old = NULL;
1678 if (rn == NULL && (info->rti_flags & RTF_PINNED) != 0) {
1679
1680 /*
1681 * Force removal and re-try addition
1682 * TODO: better multipath&pinned support
1683 */
1684 struct sockaddr *info_dst = info->rti_info[RTAX_DST];

--- 604 unchanged lines hidden ---