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 --- |