Changeset View
Changeset View
Standalone View
Standalone View
sys/net/route.c
Show First 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | |||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#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/nhop.h> | |||||
#include <net/route_var.h> | #include <net/route_var.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 All 14 Lines | |||||
*/ | */ | ||||
#define RNTORT(p) ((struct rtentry *)(p)) | #define RNTORT(p) ((struct rtentry *)(p)) | ||||
VNET_DEFINE_STATIC(uma_zone_t, rtzone); /* Routing table UMA zone. */ | VNET_DEFINE_STATIC(uma_zone_t, rtzone); /* Routing table UMA zone. */ | ||||
#define V_rtzone VNET(rtzone) | #define V_rtzone VNET(rtzone) | ||||
EVENTHANDLER_LIST_DEFINE(rt_addrmsg); | EVENTHANDLER_LIST_DEFINE(rt_addrmsg); | ||||
static int rt_getifa_fib(struct rt_addrinfo *, u_int); | |||||
static int rtrequest1_fib_change(struct rib_head *, struct rt_addrinfo *, | static int rtrequest1_fib_change(struct rib_head *, struct rt_addrinfo *, | ||||
struct rtentry **, u_int); | struct rtentry **, u_int); | ||||
static void rt_setmetrics(const struct rt_addrinfo *, struct rtentry *); | static void rt_setmetrics(const struct rt_addrinfo *, struct rtentry *); | ||||
static int rt_ifdelroute(const struct rtentry *rt, void *arg); | static int rt_ifdelroute(const struct rtentry *rt, void *arg); | ||||
static struct rtentry *rt_unlinkrte(struct rib_head *rnh, | static struct rtentry *rt_unlinkrte(struct rib_head *rnh, | ||||
struct rt_addrinfo *info, int *perror); | struct rt_addrinfo *info, int *perror); | ||||
static void rt_notifydelete(struct rtentry *rt, struct rt_addrinfo *info); | static void rt_notifydelete(struct rtentry *rt, struct rt_addrinfo *info); | ||||
#ifdef RADIX_MPATH | #ifdef RADIX_MPATH | ||||
▲ Show 20 Lines • Show All 76 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_object(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 127 Lines • ▼ Show 20 Lines | rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt, | ||||
u_int fibnum) | u_int fibnum) | ||||
{ | { | ||||
int error = 0; | int error = 0; | ||||
struct rtentry *rt, *rt_old; | struct rtentry *rt, *rt_old; | ||||
struct radix_node *rn; | struct radix_node *rn; | ||||
struct rib_head *rnh; | struct rib_head *rnh; | ||||
struct ifaddr *ifa; | struct ifaddr *ifa; | ||||
struct sockaddr *ndst; | struct sockaddr *ndst; | ||||
struct nhop_object *nh; | |||||
struct sockaddr_storage mdst; | struct sockaddr_storage mdst; | ||||
struct epoch_tracker et; | |||||
KASSERT((fibnum < rt_numfibs), ("rtrequest1_fib: bad fibnum")); | KASSERT((fibnum < rt_numfibs), ("rtrequest1_fib: bad fibnum")); | ||||
KASSERT((flags & RTF_RNH_LOCKED) == 0, ("rtrequest1_fib: locked")); | KASSERT((flags & RTF_RNH_LOCKED) == 0, ("rtrequest1_fib: locked")); | ||||
switch (dst->sa_family) { | switch (dst->sa_family) { | ||||
case AF_INET6: | case AF_INET6: | ||||
case AF_INET: | case AF_INET: | ||||
/* We support multiple FIBs. */ | /* We support multiple FIBs. */ | ||||
break; | break; | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | case RTM_ADD: | ||||
if (info->rti_ifa == NULL) { | if (info->rti_ifa == NULL) { | ||||
error = rt_getifa_fib(info, fibnum); | error = rt_getifa_fib(info, 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); | |||||
nh = nhop_create_from_info_wrapper(rnh, info); | |||||
NET_EPOCH_EXIT(et); | |||||
if (nh == NULL) { | |||||
ifa_free(info->rti_ifa); | |||||
return (ENOBUFS); | |||||
} | |||||
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_object(nh); | |||||
return (ENOBUFS); | return (ENOBUFS); | ||||
} | } | ||||
rt->rt_nhop = nh; | |||||
rt->rt_flags = RTF_UP | flags; | rt->rt_flags = RTF_UP | flags; | ||||
rt->rt_fibnum = fibnum; | rt->rt_fibnum = fibnum; | ||||
/* | /* | ||||
* 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_object(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 22 Lines | case RTM_ADD: | ||||
RT_LOCK(rt); | RT_LOCK(rt); | ||||
#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); | ||||
nhop_free_object(nh); | |||||
R_Free(rt_key(rt)); | R_Free(rt_key(rt)); | ||||
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 | if (rt_old != NULL) | ||||
RT_UNLOCK(rt_old); | RT_UNLOCK(rt_old); | ||||
/* | /* | ||||
* 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)); | ||||
ae: It seems there is another exit point, but you didn't add nhop_free_object(nh) here. Is it ok? | |||||
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 All 12 Lines | #endif | ||||
if (ret_nrt) { | if (ret_nrt) { | ||||
*ret_nrt = rt; | *ret_nrt = rt; | ||||
RT_ADDREF(rt); | RT_ADDREF(rt); | ||||
} | } | ||||
rnh->rnh_gen++; /* Routing table updated */ | rnh->rnh_gen++; /* Routing table updated */ | ||||
RT_UNLOCK(rt); | RT_UNLOCK(rt); | ||||
break; | break; | ||||
case RTM_CHANGE: | case RTM_CHANGE: | ||||
NET_EPOCH_ENTER(et); | |||||
RIB_WLOCK(rnh); | RIB_WLOCK(rnh); | ||||
error = rtrequest1_fib_change(rnh, info, ret_nrt, fibnum); | error = rtrequest1_fib_change(rnh, info, ret_nrt, fibnum); | ||||
RIB_WUNLOCK(rnh); | RIB_WUNLOCK(rnh); | ||||
NET_EPOCH_EXIT(et); | |||||
break; | break; | ||||
default: | default: | ||||
error = EOPNOTSUPP; | error = EOPNOTSUPP; | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
#undef dst | #undef dst | ||||
#undef gateway | #undef gateway | ||||
#undef netmask | #undef netmask | ||||
#undef ifaaddr | #undef ifaaddr | ||||
#undef ifpaddr | #undef ifpaddr | ||||
#undef flags | #undef flags | ||||
static int | static int | ||||
rtrequest1_fib_change(struct rib_head *rnh, struct rt_addrinfo *info, | rtrequest1_fib_change(struct rib_head *rnh, struct rt_addrinfo *info, | ||||
struct rtentry **ret_nrt, u_int fibnum) | struct rtentry **ret_nrt, u_int fibnum) | ||||
{ | { | ||||
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 | ||||
RT_LOCK(rt); | RT_LOCK(rt); | ||||
nh = nhop_create_from_nhop_wrapper(rnh, rt->rt_nhop, info); | |||||
if (nh == NULL) { | |||||
RT_UNLOCK(rt); | |||||
return (ENOBUFS); | |||||
} | |||||
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 | ||||
*/ | */ | ||||
if (((rt->rt_flags & RTF_GATEWAY) && | if (((rt->rt_flags & RTF_GATEWAY) && | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | if (rt->rt_mtu == 0) | ||||
rt->rt_mtu = mtu; | rt->rt_mtu = mtu; | ||||
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_object(rt->rt_nhop); | |||||
rt->rt_nhop = nh; | |||||
/* | /* | ||||
* 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); | ||||
aeUnsubmitted Done Inline ActionsProbably the "goto bad" case needs nhop_free_object(). Isn't it? ae: Probably the "goto bad" case needs nhop_free_object(). Isn't it? | |||||
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 |
It seems there is another exit point, but you didn't add nhop_free_object(nh) here. Is it ok?