Changeset View
Changeset View
Standalone View
Standalone View
head/sys/net/route.c
Show First 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | |||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/rmlock.h> | #include <sys/rmlock.h> | ||||
#include <net/if.h> | #include <net/if.h> | ||||
#include <net/if_var.h> | #include <net/if_var.h> | ||||
#include <net/if_dl.h> | #include <net/if_dl.h> | ||||
#include <net/route.h> | #include <net/route.h> | ||||
#include <net/route_var.h> | #include <net/route_var.h> | ||||
#include <net/route/nhop.h> | |||||
#include <net/route/shared.h> | |||||
#include <net/vnet.h> | #include <net/vnet.h> | ||||
#ifdef RADIX_MPATH | #ifdef RADIX_MPATH | ||||
#include <net/radix_mpath.h> | #include <net/radix_mpath.h> | ||||
#endif | #endif | ||||
#include <netinet/in.h> | #include <netinet/in.h> | ||||
#include <netinet/ip_mroute.h> | #include <netinet/ip_mroute.h> | ||||
Show All 30 Lines | |||||
* XXX also has the problems getting the FIB from curthread which will not | * XXX also has the problems getting the FIB from curthread which will not | ||||
* always work given the fib can be overridden and prefixes can be added | * always work given the fib can be overridden and prefixes can be added | ||||
* from the network stack context. | * from the network stack context. | ||||
*/ | */ | ||||
VNET_DEFINE(u_int, rt_add_addr_allfibs) = 1; | VNET_DEFINE(u_int, rt_add_addr_allfibs) = 1; | ||||
SYSCTL_UINT(_net, OID_AUTO, add_addr_allfibs, CTLFLAG_RWTUN | CTLFLAG_VNET, | SYSCTL_UINT(_net, OID_AUTO, add_addr_allfibs, CTLFLAG_RWTUN | CTLFLAG_VNET, | ||||
&VNET_NAME(rt_add_addr_allfibs), 0, ""); | &VNET_NAME(rt_add_addr_allfibs), 0, ""); | ||||
VNET_PCPUSTAT_DEFINE_STATIC(struct rtstat, rtstat); | VNET_PCPUSTAT_DEFINE(struct rtstat, rtstat); | ||||
#define RTSTAT_ADD(name, val) \ | |||||
VNET_PCPUSTAT_ADD(struct rtstat, rtstat, name, (val)) | |||||
#define RTSTAT_INC(name) RTSTAT_ADD(name, 1) | |||||
VNET_PCPUSTAT_SYSINIT(rtstat); | VNET_PCPUSTAT_SYSINIT(rtstat); | ||||
#ifdef VIMAGE | #ifdef VIMAGE | ||||
VNET_PCPUSTAT_SYSUNINIT(rtstat); | VNET_PCPUSTAT_SYSUNINIT(rtstat); | ||||
#endif | #endif | ||||
VNET_DEFINE(struct rib_head *, rt_tables); | VNET_DEFINE(struct rib_head *, rt_tables); | ||||
#define V_rt_tables VNET(rt_tables) | #define V_rt_tables VNET(rt_tables) | ||||
▲ Show 20 Lines • Show All 112 Lines • ▼ Show 20 Lines | |||||
route_init(void) | route_init(void) | ||||
{ | { | ||||
/* whack the tunable ints into line. */ | /* whack the tunable ints into line. */ | ||||
if (rt_numfibs > RT_MAXFIBS) | if (rt_numfibs > RT_MAXFIBS) | ||||
rt_numfibs = RT_MAXFIBS; | rt_numfibs = RT_MAXFIBS; | ||||
if (rt_numfibs == 0) | if (rt_numfibs == 0) | ||||
rt_numfibs = 1; | rt_numfibs = 1; | ||||
nhops_init(); | |||||
} | } | ||||
SYSINIT(route_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, route_init, NULL); | SYSINIT(route_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, route_init, NULL); | ||||
static int | static int | ||||
rtentry_zinit(void *mem, int size, int how) | rtentry_zinit(void *mem, int size, int how) | ||||
{ | { | ||||
struct rtentry *rt = mem; | struct rtentry *rt = mem; | ||||
▲ Show 20 Lines • Show All 121 Lines • ▼ Show 20 Lines | #ifdef VIMAGE | ||||
rh->rib_vnet = curvnet; | rh->rib_vnet = curvnet; | ||||
#endif | #endif | ||||
tmproutes_init(rh); | tmproutes_init(rh); | ||||
/* Init locks */ | /* Init locks */ | ||||
RIB_LOCK_INIT(rh); | RIB_LOCK_INIT(rh); | ||||
nhops_init_rib(rh); | |||||
/* Finally, set base callbacks */ | /* Finally, set base callbacks */ | ||||
rh->rnh_addaddr = rn_addroute; | rh->rnh_addaddr = rn_addroute; | ||||
rh->rnh_deladdr = rn_delete; | rh->rnh_deladdr = rn_delete; | ||||
rh->rnh_matchaddr = rn_match; | rh->rnh_matchaddr = rn_match; | ||||
rh->rnh_lookup = rn_lookup; | rh->rnh_lookup = rn_lookup; | ||||
rh->rnh_walktree = rn_walktree; | rh->rnh_walktree = rn_walktree; | ||||
rh->rnh_walktree_from = rn_walktree_from; | rh->rnh_walktree_from = rn_walktree_from; | ||||
Show All 15 Lines | |||||
void | void | ||||
rt_table_destroy(struct rib_head *rh) | rt_table_destroy(struct rib_head *rh) | ||||
{ | { | ||||
tmproutes_destroy(rh); | tmproutes_destroy(rh); | ||||
rn_walktree(&rh->rmhead.head, rt_freeentry, &rh->rmhead.head); | rn_walktree(&rh->rmhead.head, rt_freeentry, &rh->rmhead.head); | ||||
nhops_destroy_rib(rh); | |||||
/* Assume table is already empty */ | /* Assume table is already empty */ | ||||
RIB_LOCK_DESTROY(rh); | RIB_LOCK_DESTROY(rh); | ||||
free(rh, M_RTABLE); | free(rh, M_RTABLE); | ||||
} | } | ||||
#ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||
struct setfib_args { | struct setfib_args { | ||||
▲ Show 20 Lines • Show All 162 Lines • ▼ Show 20 Lines | if (rt->rt_ifa) | ||||
ifa_free(rt->rt_ifa); | ifa_free(rt->rt_ifa); | ||||
/* | /* | ||||
* The key is separatly alloc'd so free it (see rt_setgate()). | * The key is separatly alloc'd so free it (see rt_setgate()). | ||||
* This also frees the gateway, as they are always malloc'd | * This also frees the gateway, as they are always malloc'd | ||||
* together. | * together. | ||||
*/ | */ | ||||
R_Free(rt_key(rt)); | R_Free(rt_key(rt)); | ||||
/* Unreference nexthop */ | |||||
nhop_free(rt->rt_nhop); | |||||
/* | /* | ||||
* and the rtentry itself of course | * and the rtentry itself of course | ||||
*/ | */ | ||||
uma_zfree(V_rtzone, rt); | uma_zfree(V_rtzone, rt); | ||||
return; | return; | ||||
} | } | ||||
done: | done: | ||||
RT_UNLOCK(rt); | RT_UNLOCK(rt); | ||||
▲ Show 20 Lines • Show All 798 Lines • ▼ Show 20 Lines | for (i = 1; i <= AF_MAX; i++) { | ||||
ifmtu.mtu = if_getmtu_family(ifp, i); | ifmtu.mtu = if_getmtu_family(ifp, i); | ||||
for (j = 0; j < rt_numfibs; j++) { | for (j = 0; j < rt_numfibs; j++) { | ||||
rnh = rt_tables_get_rnh(j, i); | rnh = rt_tables_get_rnh(j, i); | ||||
if (rnh == NULL) | if (rnh == NULL) | ||||
continue; | continue; | ||||
RIB_WLOCK(rnh); | RIB_WLOCK(rnh); | ||||
rnh->rnh_walktree(&rnh->head, if_updatemtu_cb, &ifmtu); | rnh->rnh_walktree(&rnh->head, if_updatemtu_cb, &ifmtu); | ||||
RIB_WUNLOCK(rnh); | RIB_WUNLOCK(rnh); | ||||
nhops_update_ifmtu(rnh, ifp, ifmtu.mtu); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
#if 0 | #if 0 | ||||
int p_sockaddr(char *buf, int buflen, struct sockaddr *s); | int p_sockaddr(char *buf, int buflen, struct sockaddr *s); | ||||
int rt_print(char *buf, int buflen, struct rtentry *rt); | int rt_print(char *buf, int buflen, struct rtentry *rt); | ||||
▲ Show 20 Lines • Show All 128 Lines • ▼ Show 20 Lines | |||||
#undef ifaaddr | #undef ifaaddr | ||||
#undef ifpaddr | #undef ifpaddr | ||||
#undef flags | #undef flags | ||||
int | int | ||||
rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt, | rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt, | ||||
u_int fibnum) | u_int fibnum) | ||||
{ | { | ||||
struct epoch_tracker et; | |||||
const struct sockaddr *dst; | const struct sockaddr *dst; | ||||
struct rib_head *rnh; | struct rib_head *rnh; | ||||
int error; | int error; | ||||
KASSERT((fibnum < rt_numfibs), ("rtrequest1_fib: bad fibnum")); | KASSERT((fibnum < rt_numfibs), ("rtrequest1_fib: bad fibnum")); | ||||
KASSERT((info->rti_flags & RTF_RNH_LOCKED) == 0, ("rtrequest1_fib: locked")); | KASSERT((info->rti_flags & RTF_RNH_LOCKED) == 0, ("rtrequest1_fib: locked")); | ||||
dst = info->rti_info[RTAX_DST]; | dst = info->rti_info[RTAX_DST]; | ||||
Show All 32 Lines | case RTM_RESOLVE: | ||||
* resolve was only used for route cloning | * resolve was only used for route cloning | ||||
* here for compat | * here for compat | ||||
*/ | */ | ||||
break; | break; | ||||
case RTM_ADD: | case RTM_ADD: | ||||
error = add_route(rnh, info, ret_nrt); | error = add_route(rnh, info, ret_nrt); | ||||
break; | break; | ||||
case RTM_CHANGE: | case RTM_CHANGE: | ||||
NET_EPOCH_ENTER(et); | |||||
RIB_WLOCK(rnh); | RIB_WLOCK(rnh); | ||||
error = change_route(rnh, info, ret_nrt); | error = change_route(rnh, info, ret_nrt); | ||||
RIB_WUNLOCK(rnh); | RIB_WUNLOCK(rnh); | ||||
NET_EPOCH_EXIT(et); | |||||
break; | break; | ||||
default: | default: | ||||
error = EOPNOTSUPP; | error = EOPNOTSUPP; | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
add_route(struct rib_head *rnh, struct rt_addrinfo *info, | add_route(struct rib_head *rnh, struct rt_addrinfo *info, | ||||
struct rtentry **ret_nrt) | struct rtentry **ret_nrt) | ||||
{ | { | ||||
struct sockaddr *dst, *ndst, *gateway, *netmask; | struct sockaddr *dst, *ndst, *gateway, *netmask; | ||||
struct rtentry *rt, *rt_old; | struct rtentry *rt, *rt_old; | ||||
struct nhop_object *nh; | |||||
struct radix_node *rn; | struct radix_node *rn; | ||||
struct ifaddr *ifa; | struct ifaddr *ifa; | ||||
int error, flags; | int error, flags; | ||||
struct epoch_tracker et; | |||||
dst = info->rti_info[RTAX_DST]; | dst = info->rti_info[RTAX_DST]; | ||||
gateway = info->rti_info[RTAX_GATEWAY]; | gateway = info->rti_info[RTAX_GATEWAY]; | ||||
netmask = info->rti_info[RTAX_NETMASK]; | netmask = info->rti_info[RTAX_NETMASK]; | ||||
flags = info->rti_flags; | flags = info->rti_flags; | ||||
if ((flags & RTF_GATEWAY) && !gateway) | if ((flags & RTF_GATEWAY) && !gateway) | ||||
return (EINVAL); | return (EINVAL); | ||||
if (dst && gateway && (dst->sa_family != gateway->sa_family) && | if (dst && gateway && (dst->sa_family != gateway->sa_family) && | ||||
(gateway->sa_family != AF_UNSPEC) && (gateway->sa_family != AF_LINK)) | (gateway->sa_family != AF_UNSPEC) && (gateway->sa_family != AF_LINK)) | ||||
return (EINVAL); | return (EINVAL); | ||||
if (info->rti_ifa == NULL) { | if (info->rti_ifa == NULL) { | ||||
error = rt_getifa_fib(info, rnh->rib_fibnum); | error = rt_getifa_fib(info, rnh->rib_fibnum); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
} else { | } else { | ||||
ifa_ref(info->rti_ifa); | ifa_ref(info->rti_ifa); | ||||
} | } | ||||
NET_EPOCH_ENTER(et); | |||||
error = nhop_create_from_info(rnh, info, &nh); | |||||
NET_EPOCH_EXIT(et); | |||||
if (error != 0) { | |||||
ifa_free(info->rti_ifa); | |||||
return (error); | |||||
} | |||||
rt = uma_zalloc(V_rtzone, M_NOWAIT); | rt = uma_zalloc(V_rtzone, M_NOWAIT); | ||||
if (rt == NULL) { | if (rt == NULL) { | ||||
ifa_free(info->rti_ifa); | ifa_free(info->rti_ifa); | ||||
nhop_free(nh); | |||||
return (ENOBUFS); | return (ENOBUFS); | ||||
} | } | ||||
rt->rt_flags = RTF_UP | flags; | rt->rt_flags = RTF_UP | flags; | ||||
rt->rt_fibnum = rnh->rib_fibnum; | rt->rt_fibnum = rnh->rib_fibnum; | ||||
rt->rt_nhop = nh; | |||||
/* | /* | ||||
* Add the gateway. Possibly re-malloc-ing the storage for it. | * Add the gateway. Possibly re-malloc-ing the storage for it. | ||||
*/ | */ | ||||
if ((error = rt_setgate(rt, dst, gateway)) != 0) { | if ((error = rt_setgate(rt, dst, gateway)) != 0) { | ||||
ifa_free(info->rti_ifa); | ifa_free(info->rti_ifa); | ||||
nhop_free(nh); | |||||
uma_zfree(V_rtzone, rt); | uma_zfree(V_rtzone, rt); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* point to the (possibly newly malloc'd) dest address. | * point to the (possibly newly malloc'd) dest address. | ||||
*/ | */ | ||||
ndst = (struct sockaddr *)rt_key(rt); | ndst = (struct sockaddr *)rt_key(rt); | ||||
Show All 23 Lines | |||||
#ifdef RADIX_MPATH | #ifdef RADIX_MPATH | ||||
/* do not permit exactly the same dst/mask/gw pair */ | /* do not permit exactly the same dst/mask/gw pair */ | ||||
if (rt_mpath_capable(rnh) && | if (rt_mpath_capable(rnh) && | ||||
rt_mpath_conflict(rnh, rt, netmask)) { | rt_mpath_conflict(rnh, rt, netmask)) { | ||||
RIB_WUNLOCK(rnh); | RIB_WUNLOCK(rnh); | ||||
ifa_free(rt->rt_ifa); | ifa_free(rt->rt_ifa); | ||||
R_Free(rt_key(rt)); | R_Free(rt_key(rt)); | ||||
nhop_free(nh); | |||||
uma_zfree(V_rtzone, rt); | uma_zfree(V_rtzone, rt); | ||||
return (EEXIST); | return (EEXIST); | ||||
} | } | ||||
#endif | #endif | ||||
/* XXX mtu manipulation will be done in rnh_addaddr -- itojun */ | /* XXX mtu manipulation will be done in rnh_addaddr -- itojun */ | ||||
rn = rnh->rnh_addaddr(ndst, netmask, &rnh->head, rt->rt_nodes); | rn = rnh->rnh_addaddr(ndst, netmask, &rnh->head, rt->rt_nodes); | ||||
Show All 25 Lines | #endif | ||||
/* | /* | ||||
* If it still failed to go into the tree, | * If it still failed to go into the tree, | ||||
* then un-make it (this should be a function) | * then un-make it (this should be a function) | ||||
*/ | */ | ||||
if (rn == NULL) { | if (rn == NULL) { | ||||
ifa_free(rt->rt_ifa); | ifa_free(rt->rt_ifa); | ||||
R_Free(rt_key(rt)); | R_Free(rt_key(rt)); | ||||
nhop_free(nh); | |||||
uma_zfree(V_rtzone, rt); | uma_zfree(V_rtzone, rt); | ||||
return (EEXIST); | return (EEXIST); | ||||
} | } | ||||
if (rt_old != NULL) { | if (rt_old != NULL) { | ||||
rt_notifydelete(rt_old, info); | rt_notifydelete(rt_old, info); | ||||
RTFREE(rt_old); | RTFREE(rt_old); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | |||||
static int | static int | ||||
change_route(struct rib_head *rnh, struct rt_addrinfo *info, | change_route(struct rib_head *rnh, struct rt_addrinfo *info, | ||||
struct rtentry **ret_nrt) | struct rtentry **ret_nrt) | ||||
{ | { | ||||
struct rtentry *rt = NULL; | struct rtentry *rt = NULL; | ||||
int error = 0; | int error = 0; | ||||
int free_ifa = 0; | int free_ifa = 0; | ||||
int family, mtu; | int family, mtu; | ||||
struct nhop_object *nh; | |||||
struct if_mtuinfo ifmtu; | struct if_mtuinfo ifmtu; | ||||
RIB_WLOCK_ASSERT(rnh); | RIB_WLOCK_ASSERT(rnh); | ||||
rt = (struct rtentry *)rnh->rnh_lookup(info->rti_info[RTAX_DST], | rt = (struct rtentry *)rnh->rnh_lookup(info->rti_info[RTAX_DST], | ||||
info->rti_info[RTAX_NETMASK], &rnh->head); | info->rti_info[RTAX_NETMASK], &rnh->head); | ||||
if (rt == NULL) | if (rt == NULL) | ||||
return (ESRCH); | return (ESRCH); | ||||
#ifdef RADIX_MPATH | #ifdef RADIX_MPATH | ||||
/* | /* | ||||
* If we got multipath routes, | * If we got multipath routes, | ||||
* we require users to specify a matching RTAX_GATEWAY. | * we require users to specify a matching RTAX_GATEWAY. | ||||
*/ | */ | ||||
if (rt_mpath_capable(rnh)) { | if (rt_mpath_capable(rnh)) { | ||||
rt = rt_mpath_matchgate(rt, info->rti_info[RTAX_GATEWAY]); | rt = rt_mpath_matchgate(rt, info->rti_info[RTAX_GATEWAY]); | ||||
if (rt == NULL) | if (rt == NULL) | ||||
return (ESRCH); | return (ESRCH); | ||||
} | } | ||||
#endif | #endif | ||||
nh = NULL; | |||||
RT_LOCK(rt); | RT_LOCK(rt); | ||||
rt_setmetrics(info, rt); | rt_setmetrics(info, rt); | ||||
/* | /* | ||||
* New gateway could require new ifaddr, ifp; | * New gateway could require new ifaddr, ifp; | ||||
* flags may also be different; ifp may be specified | * flags may also be different; ifp may be specified | ||||
* by ll sockaddr when protocol address is ambiguous | * by ll sockaddr when protocol address is ambiguous | ||||
Show All 12 Lines | if (((rt->rt_flags & RTF_GATEWAY) && | ||||
info->rti_flags &= ~RTF_RNH_LOCKED; | info->rti_flags &= ~RTF_RNH_LOCKED; | ||||
if (info->rti_ifa != NULL) | if (info->rti_ifa != NULL) | ||||
free_ifa = 1; | free_ifa = 1; | ||||
if (error != 0) | if (error != 0) | ||||
goto bad; | goto bad; | ||||
} | } | ||||
error = nhop_create_from_nhop(rnh, rt->rt_nhop, info, &nh); | |||||
if (error != 0) | |||||
goto bad; | |||||
/* Check if outgoing interface has changed */ | /* Check if outgoing interface has changed */ | ||||
if (info->rti_ifa != NULL && info->rti_ifa != rt->rt_ifa && | if (info->rti_ifa != NULL && info->rti_ifa != rt->rt_ifa && | ||||
rt->rt_ifa != NULL) { | rt->rt_ifa != NULL) { | ||||
if (rt->rt_ifa->ifa_rtrequest != NULL) | if (rt->rt_ifa->ifa_rtrequest != NULL) | ||||
rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, info); | rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, info); | ||||
ifa_free(rt->rt_ifa); | ifa_free(rt->rt_ifa); | ||||
rt->rt_ifa = NULL; | rt->rt_ifa = NULL; | ||||
} | } | ||||
Show All 29 Lines | if (rt->rt_ifp != NULL) { | ||||
if (rt->rt_mtu != mtu) { | if (rt->rt_mtu != mtu) { | ||||
/* Check if we really need to update */ | /* Check if we really need to update */ | ||||
ifmtu.ifp = rt->rt_ifp; | ifmtu.ifp = rt->rt_ifp; | ||||
ifmtu.mtu = mtu; | ifmtu.mtu = mtu; | ||||
if_updatemtu_cb(rt->rt_nodes, &ifmtu); | if_updatemtu_cb(rt->rt_nodes, &ifmtu); | ||||
} | } | ||||
} | } | ||||
/* Update nexthop */ | |||||
nhop_free(rt->rt_nhop); | |||||
rt->rt_nhop = nh; | |||||
nh = NULL; | |||||
/* | /* | ||||
* This route change may have modified the route's gateway. In that | * This route change may have modified the route's gateway. In that | ||||
* case, any inpcbs that have cached this route need to invalidate their | * case, any inpcbs that have cached this route need to invalidate their | ||||
* llentry cache. | * llentry cache. | ||||
*/ | */ | ||||
rnh->rnh_gen++; | rnh->rnh_gen++; | ||||
if (ret_nrt) { | if (ret_nrt) { | ||||
*ret_nrt = rt; | *ret_nrt = rt; | ||||
RT_ADDREF(rt); | RT_ADDREF(rt); | ||||
} | } | ||||
bad: | bad: | ||||
RT_UNLOCK(rt); | RT_UNLOCK(rt); | ||||
if (nh != NULL) | |||||
nhop_free(nh); | |||||
if (free_ifa != 0) { | if (free_ifa != 0) { | ||||
ifa_free(info->rti_ifa); | ifa_free(info->rti_ifa); | ||||
info->rti_ifa = NULL; | info->rti_ifa = NULL; | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
static void | static void | ||||
▲ Show 20 Lines • Show All 412 Lines • Show Last 20 Lines |