Changeset View
Changeset View
Standalone View
Standalone View
sys/net/route/route_ctl.c
Show All 23 Lines | |||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||||
* SUCH DAMAGE. | * SUCH DAMAGE. | ||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include "opt_inet.h" | #include "opt_inet.h" | ||||
#include "opt_inet6.h" | #include "opt_inet6.h" | ||||
#include "opt_mpath.h" | #include "opt_route.h" | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/mbuf.h> | #include <sys/mbuf.h> | ||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/syslog.h> | #include <sys/syslog.h> | ||||
Show All 37 Lines | static int add_route(struct rib_head *rnh, struct rt_addrinfo *info, | ||||
struct rib_cmd_info *rc); | struct rib_cmd_info *rc); | ||||
static int add_route_nhop(struct rib_head *rnh, struct rtentry *rt, | static int add_route_nhop(struct rib_head *rnh, struct rtentry *rt, | ||||
struct rt_addrinfo *info, struct route_nhop_data *rnd, | struct rt_addrinfo *info, struct route_nhop_data *rnd, | ||||
struct rib_cmd_info *rc); | struct rib_cmd_info *rc); | ||||
static int del_route(struct rib_head *rnh, struct rt_addrinfo *info, | static int del_route(struct rib_head *rnh, struct rt_addrinfo *info, | ||||
struct rib_cmd_info *rc); | struct rib_cmd_info *rc); | ||||
static int change_route(struct rib_head *rnh, struct rt_addrinfo *info, | static int change_route(struct rib_head *rnh, struct rt_addrinfo *info, | ||||
struct route_nhop_data *nhd_orig, struct rib_cmd_info *rc); | struct route_nhop_data *nhd_orig, struct rib_cmd_info *rc); | ||||
static int change_route_nhop(struct rib_head *rnh, struct rtentry *rt, | |||||
struct rt_addrinfo *info, struct route_nhop_data *rnd, | |||||
struct rib_cmd_info *rc); | |||||
static int rt_unlinkrte(struct rib_head *rnh, struct rt_addrinfo *info, | static int rt_unlinkrte(struct rib_head *rnh, struct rt_addrinfo *info, | ||||
struct rib_cmd_info *rc); | struct rib_cmd_info *rc); | ||||
static void rib_notify(struct rib_head *rnh, enum rib_subscription_type type, | static void rib_notify(struct rib_head *rnh, enum rib_subscription_type type, | ||||
struct rib_cmd_info *rc); | struct rib_cmd_info *rc); | ||||
static void destroy_subscription_epoch(epoch_context_t ctx); | static void destroy_subscription_epoch(epoch_context_t ctx); | ||||
static bool rib_can_multipath(struct rib_head *rh); | |||||
/* Per-vnet multipath routing configuration */ | |||||
SYSCTL_DECL(_net_route); | |||||
#define V_rib_route_multipath VNET(rib_route_multipath) | |||||
#ifdef ROUTE_MPATH | |||||
VNET_DEFINE(u_int, rib_route_multipath) = 1; | |||||
#define _MP_FLAGS CTLFLAG_RWTUN | |||||
#else | |||||
VNET_DEFINE(u_int, rib_route_multipath) = 0; | |||||
#define _MP_FLAGS CTLFLAG_RD | |||||
#endif | |||||
SYSCTL_UINT(_net_route, OID_AUTO, multipath, _MP_FLAGS | CTLFLAG_VNET, | |||||
&VNET_NAME(rib_route_multipath), 0, "Enable route multipath"); | |||||
#undef _MP_FLAGS | |||||
/* Routing table UMA zone */ | /* Routing table UMA zone */ | ||||
VNET_DEFINE_STATIC(uma_zone_t, rtzone); | VNET_DEFINE_STATIC(uma_zone_t, rtzone); | ||||
#define V_rtzone VNET(rtzone) | #define V_rtzone VNET(rtzone) | ||||
void | void | ||||
vnet_rtzone_init() | vnet_rtzone_init() | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | get_rnh(uint32_t fibnum, const struct rt_addrinfo *info) | ||||
KASSERT((fibnum < rt_numfibs), ("rib_add_route: bad fibnum")); | KASSERT((fibnum < rt_numfibs), ("rib_add_route: bad fibnum")); | ||||
dst = info->rti_info[RTAX_DST]; | dst = info->rti_info[RTAX_DST]; | ||||
rnh = rt_tables_get_rnh(fibnum, dst->sa_family); | rnh = rt_tables_get_rnh(fibnum, dst->sa_family); | ||||
return (rnh); | return (rnh); | ||||
} | } | ||||
#ifdef ROUTE_MPATH | |||||
static bool | |||||
rib_can_multipath(struct rib_head *rh) | |||||
{ | |||||
int result; | |||||
CURVNET_SET(rh->rib_vnet); | |||||
result = !!V_rib_route_multipath; | |||||
CURVNET_RESTORE(); | |||||
return (result); | |||||
} | |||||
/* | /* | ||||
* Check is nhop is multipath-eligible. | |||||
* Avoid nhops without gateways and redirects. | |||||
* | |||||
* Returns 1 for multipath-eligible nexthop, | |||||
* 0 otherwise. | |||||
*/ | |||||
bool | |||||
nhop_can_multipath(const struct nhop_object *nh) | |||||
{ | |||||
if ((nh->nh_flags & NHF_MULTIPATH) != 0) | |||||
return (1); | |||||
if ((nh->nh_flags & NHF_GATEWAY) == 0) | |||||
return (0); | |||||
if ((nh->nh_flags & NHF_REDIRECT) != 0) | |||||
return (0); | |||||
return (1); | |||||
} | |||||
#endif | |||||
static int | |||||
get_info_weight(const struct rt_addrinfo *info, uint32_t default_weight) | |||||
{ | |||||
uint32_t weight; | |||||
if (info->rti_mflags & RTV_WEIGHT) | |||||
weight = info->rti_rmx->rmx_weight; | |||||
else | |||||
weight = default_weight; | |||||
/* Keep upper 1 byte for adm distance purposes */ | |||||
if (weight > RT_MAX_WEIGHT) | |||||
weight = RT_MAX_WEIGHT; | |||||
return (weight); | |||||
} | |||||
static void | |||||
rt_set_expire_info(struct rtentry *rt, const struct rt_addrinfo *info) | |||||
{ | |||||
/* Kernel -> userland timebase conversion. */ | |||||
if (info->rti_mflags & RTV_EXPIRE) | |||||
rt->rt_expire = info->rti_rmx->rmx_expire ? | |||||
info->rti_rmx->rmx_expire - time_second + time_uptime : 0; | |||||
} | |||||
/* | |||||
* Check if specified @gw matches gw data in the nexthop @nh. | * Check if specified @gw matches gw data in the nexthop @nh. | ||||
* | * | ||||
* Returns true if matches, false otherwise. | * Returns true if matches, false otherwise. | ||||
*/ | */ | ||||
static bool | bool | ||||
match_nhop_gw(const struct nhop_object *nh, const struct sockaddr *gw) | match_nhop_gw(const struct nhop_object *nh, const struct sockaddr *gw) | ||||
{ | { | ||||
if (nh->gw_sa.sa_family != gw->sa_family) | if (nh->gw_sa.sa_family != gw->sa_family) | ||||
return (false); | return (false); | ||||
switch (gw->sa_family) { | switch (gw->sa_family) { | ||||
case AF_INET: | case AF_INET: | ||||
▲ Show 20 Lines • Show All 226 Lines • ▼ Show 20 Lines | if (netmask) { | ||||
bcopy(dst, ndst, dst->sa_len); | bcopy(dst, ndst, dst->sa_len); | ||||
/* | /* | ||||
* We use the ifa reference returned by rt_getifa_fib(). | * We use the ifa reference returned by rt_getifa_fib(). | ||||
* This moved from below so that rnh->rnh_addaddr() can | * This moved from below so that rnh->rnh_addaddr() can | ||||
* examine the ifa and ifa->ifa_ifp if it so desires. | * examine the ifa and ifa->ifa_ifp if it so desires. | ||||
*/ | */ | ||||
ifa = info->rti_ifa; | ifa = info->rti_ifa; | ||||
rt->rt_weight = 1; | rt->rt_weight = get_info_weight(info, RT_DEFAULT_WEIGHT); | ||||
rt_set_expire_info(rt, info); | |||||
rt_setmetrics(info, rt); | |||||
*prt = rt; | *prt = rt; | ||||
return (0); | return (0); | ||||
} | } | ||||
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 rib_cmd_info *rc) | struct rib_cmd_info *rc) | ||||
{ | { | ||||
struct nhop_object *nh_orig; | struct nhop_object *nh_orig; | ||||
struct route_nhop_data rnd; | struct route_nhop_data rnd_orig, rnd_add; | ||||
struct nhop_object *nh; | struct nhop_object *nh; | ||||
struct rtentry *rt, *rt_orig; | struct rtentry *rt, *rt_orig; | ||||
int error; | int error; | ||||
error = create_rtentry(rnh, info, &rt); | error = create_rtentry(rnh, info, &rt); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
rnd.rnd_nhop = rt->rt_nhop; | rnd_add.rnd_nhop = rt->rt_nhop; | ||||
rnd.rnd_weight = rt->rt_weight; | rnd_add.rnd_weight = rt->rt_weight; | ||||
nh = rt->rt_nhop; | nh = rt->rt_nhop; | ||||
RIB_WLOCK(rnh); | RIB_WLOCK(rnh); | ||||
#ifdef RADIX_MPATH | error = add_route_nhop(rnh, rt, info, &rnd_add, rc); | ||||
struct sockaddr *netmask; | |||||
netmask = info->rti_info[RTAX_NETMASK]; | |||||
/* do not permit exactly the same dst/mask/gw pair */ | |||||
if (rt_mpath_capable(rnh) && | |||||
rt_mpath_conflict(rnh, rt, netmask)) { | |||||
RIB_WUNLOCK(rnh); | |||||
nhop_free(nh); | |||||
uma_zfree(V_rtzone, rt); | |||||
return (EEXIST); | |||||
} | |||||
#endif | |||||
error = add_route_nhop(rnh, rt, info, &rnd, rc); | |||||
if (error == 0) { | if (error == 0) { | ||||
RIB_WUNLOCK(rnh); | RIB_WUNLOCK(rnh); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* addition failed. Lookup prefix in the rib to determine the cause */ | /* addition failed. Lookup prefix in the rib to determine the cause */ | ||||
rt_orig = lookup_prefix(rnh, info, &rnd); | rt_orig = lookup_prefix(rnh, info, &rnd_orig); | ||||
if (rt_orig == NULL) { | if (rt_orig == NULL) { | ||||
/* No prefix -> rnh_addaddr() failed to allocate memory */ | /* No prefix -> rnh_addaddr() failed to allocate memory */ | ||||
RIB_WUNLOCK(rnh); | RIB_WUNLOCK(rnh); | ||||
nhop_free(nh); | nhop_free(nh); | ||||
uma_zfree(V_rtzone, rt); | uma_zfree(V_rtzone, rt); | ||||
return (ENOMEM); | return (ENOMEM); | ||||
} | } | ||||
/* We have existing route in the RIB. */ | /* We have existing route in the RIB. */ | ||||
nh_orig = rnd.rnd_nhop; | nh_orig = rnd_orig.rnd_nhop; | ||||
/* Check if new route has higher preference */ | /* Check if new route has higher preference */ | ||||
if (can_override_nhop(info, nh_orig) > 0) { | if (can_override_nhop(info, nh_orig) > 0) { | ||||
/* Update nexthop to the new route */ | /* Update nexthop to the new route */ | ||||
change_route_nhop(rnh, rt_orig, info, &rnd, rc); | change_route_nhop(rnh, rt_orig, info, &rnd_add, rc); | ||||
RIB_WUNLOCK(rnh); | RIB_WUNLOCK(rnh); | ||||
uma_zfree(V_rtzone, rt); | uma_zfree(V_rtzone, rt); | ||||
nhop_free(nh_orig); | nhop_free(nh_orig); | ||||
return (0); | return (0); | ||||
} | } | ||||
RIB_WUNLOCK(rnh); | RIB_WUNLOCK(rnh); | ||||
#ifdef ROUTE_MPATH | |||||
if (rib_can_multipath(rnh) && nhop_can_multipath(rnd_add.rnd_nhop) && | |||||
nhop_can_multipath(rnd_orig.rnd_nhop)) | |||||
error = add_route_mpath(rnh, info, rt, &rnd_add, &rnd_orig, rc); | |||||
else | |||||
#endif | |||||
/* Unable to add - another route with the same preference exists */ | /* Unable to add - another route with the same preference exists */ | ||||
error = EEXIST; | error = EEXIST; | ||||
if (error != 0) { | |||||
nhop_free(nh); | nhop_free(nh); | ||||
uma_zfree(V_rtzone, rt); | uma_zfree(V_rtzone, rt); | ||||
} | |||||
donner: So in the case of ! ROUTE_MPATH, the call to uma_zfree is suppressed now? | |||||
Done Inline ActionsNot exactly. We have error set to EEXIST above, which renders this condition to be true. melifaro: Not exactly. We have error set to EEXIST above, which renders this condition to be true. | |||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Removes route defined by @info from the kernel table specified by @fibnum and | * Removes route defined by @info from the kernel table specified by @fibnum and | ||||
* sa_family in @info->rti_info[RTAX_DST]. | * sa_family in @info->rti_info[RTAX_DST]. | ||||
* | * | ||||
Show All 35 Lines | |||||
/* | /* | ||||
* Conditionally unlinks rtentry matching data inside @info from @rnh. | * Conditionally unlinks rtentry matching data inside @info from @rnh. | ||||
* Returns 0 on success with operation result stored in @rc. | * Returns 0 on success with operation result stored in @rc. | ||||
* On error, returns: | * On error, returns: | ||||
* ESRCH - if prefix was not found, | * ESRCH - if prefix was not found, | ||||
* EADDRINUSE - if trying to delete higher priority route. | * EADDRINUSE - if trying to delete higher priority route. | ||||
* ENOENT - if supplied filter function returned 0 (not matched). | * ENOENT - if supplied filter function returned 0 (not matched). | ||||
*/ | */ | ||||
static int | int | ||||
rt_unlinkrte(struct rib_head *rnh, struct rt_addrinfo *info, struct rib_cmd_info *rc) | rt_unlinkrte(struct rib_head *rnh, struct rt_addrinfo *info, struct rib_cmd_info *rc) | ||||
{ | { | ||||
struct rtentry *rt; | struct rtentry *rt; | ||||
struct nhop_object *nh; | struct nhop_object *nh; | ||||
struct radix_node *rn; | struct radix_node *rn; | ||||
struct route_nhop_data rnd; | struct route_nhop_data rnd; | ||||
int error; | int error; | ||||
rt = lookup_prefix(rnh, info, &rnd); | rt = lookup_prefix(rnh, info, &rnd); | ||||
if (rt == NULL) | if (rt == NULL) | ||||
return (ESRCH); | return (ESRCH); | ||||
nh = rt->rt_nhop; | nh = rt->rt_nhop; | ||||
#ifdef ROUTE_MPATH | |||||
if (NH_IS_NHGRP(nh)) { | |||||
error = del_route_mpath(rnh, info, rt, | |||||
(struct nhgrp_object *)nh, rc); | |||||
return (error); | |||||
} | |||||
#endif | |||||
error = check_info_match_nhop(info, rt, nh); | error = check_info_match_nhop(info, rt, nh); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
if (can_override_nhop(info, nh) < 0) | if (can_override_nhop(info, nh) < 0) | ||||
return (EADDRINUSE); | return (EADDRINUSE); | ||||
/* | /* | ||||
* Remove the item from the tree and return it. | * Remove the item from the tree and return it. | ||||
* Complain if it is not there and do no more processing. | * Complain if it is not there and do no more processing. | ||||
*/ | */ | ||||
#ifdef RADIX_MPATH | |||||
info->rti_info[RTAX_GATEWAY] = &nh->gw_sa; | |||||
if (rt_mpath_capable(rnh)) { | |||||
rn = rt_mpath_unlink(rnh, info, rt, &error); | |||||
if (error != 0) | |||||
return (error); | |||||
} else | |||||
#endif | |||||
rn = rnh->rnh_deladdr(info->rti_info[RTAX_DST], | rn = rnh->rnh_deladdr(info->rti_info[RTAX_DST], | ||||
info->rti_info[RTAX_NETMASK], &rnh->head); | info->rti_info[RTAX_NETMASK], &rnh->head); | ||||
if (rn == NULL) | if (rn == NULL) | ||||
return (ESRCH); | return (ESRCH); | ||||
if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) | if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) | ||||
panic ("rtrequest delete"); | panic ("rtrequest delete"); | ||||
Show All 24 Lines | if (error != 0) | ||||
return (error); | return (error); | ||||
rib_notify(rnh, RIB_NOTIFY_DELAYED, rc); | rib_notify(rnh, RIB_NOTIFY_DELAYED, rc); | ||||
/* | /* | ||||
* If the caller wants it, then it can have it, | * If the caller wants it, then it can have it, | ||||
* the entry will be deleted after the end of the current epoch. | * the entry will be deleted after the end of the current epoch. | ||||
*/ | */ | ||||
if (rc->rc_cmd == RTM_DELETE) | |||||
rtfree(rc->rc_rt); | rtfree(rc->rc_rt); | ||||
return (0); | return (0); | ||||
} | } | ||||
int | int | ||||
rib_change_route(uint32_t fibnum, struct rt_addrinfo *info, | rib_change_route(uint32_t fibnum, struct rt_addrinfo *info, | ||||
struct rib_cmd_info *rc) | struct rib_cmd_info *rc) | ||||
{ | { | ||||
Show All 29 Lines | rib_change_route(uint32_t fibnum, struct rt_addrinfo *info, | ||||
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) { | ||||
RIB_RUNLOCK(rnh); | RIB_RUNLOCK(rnh); | ||||
return (ESRCH); | return (ESRCH); | ||||
} | } | ||||
#ifdef RADIX_MPATH | |||||
/* | |||||
* If we got multipath routes, | |||||
* we require users to specify a matching RTAX_GATEWAY. | |||||
*/ | |||||
if (rt_mpath_capable(rnh)) { | |||||
rt = rt_mpath_matchgate(rt, info->rti_info[RTAX_GATEWAY]); | |||||
if (rt == NULL) { | |||||
RIB_RUNLOCK(rnh); | |||||
return (ESRCH); | |||||
} | |||||
} | |||||
#endif | |||||
rnd_orig.rnd_nhop = rt->rt_nhop; | rnd_orig.rnd_nhop = rt->rt_nhop; | ||||
rnd_orig.rnd_weight = rt->rt_weight; | rnd_orig.rnd_weight = rt->rt_weight; | ||||
RIB_RUNLOCK(rnh); | RIB_RUNLOCK(rnh); | ||||
for (int i = 0; i < RIB_MAX_RETRIES; i++) { | for (int i = 0; i < RIB_MAX_RETRIES; i++) { | ||||
error = change_route(rnh, info, &rnd_orig, rc); | error = change_route(rnh, info, &rnd_orig, rc); | ||||
if (error != EAGAIN) | if (error != EAGAIN) | ||||
break; | break; | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
change_route(struct rib_head *rnh, struct rt_addrinfo *info, | change_nhop(struct rib_head *rnh, struct rt_addrinfo *info, | ||||
struct route_nhop_data *rnd_orig, struct rib_cmd_info *rc) | struct nhop_object *nh_orig, struct nhop_object **nh_new) | ||||
{ | { | ||||
int error = 0; | |||||
int free_ifa = 0; | int free_ifa = 0; | ||||
struct nhop_object *nh, *nh_orig; | int error; | ||||
struct route_nhop_data rnd_new; | |||||
nh = NULL; | |||||
nh_orig = rnd_orig->rnd_nhop; | |||||
if (nh_orig == NULL) | |||||
return (ESRCH); | |||||
/* | /* | ||||
* 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 (((nh_orig->nh_flags & NHF_GATEWAY) && | if (((nh_orig->nh_flags & NHF_GATEWAY) && | ||||
info->rti_info[RTAX_GATEWAY] != NULL) || | info->rti_info[RTAX_GATEWAY] != NULL) || | ||||
info->rti_info[RTAX_IFP] != NULL || | info->rti_info[RTAX_IFP] != NULL || | ||||
(info->rti_info[RTAX_IFA] != NULL && | (info->rti_info[RTAX_IFA] != NULL && | ||||
!sa_equal(info->rti_info[RTAX_IFA], nh_orig->nh_ifa->ifa_addr))) { | !sa_equal(info->rti_info[RTAX_IFA], nh_orig->nh_ifa->ifa_addr))) { | ||||
error = rt_getifa_fib(info, rnh->rib_fibnum); | error = rt_getifa_fib(info, rnh->rib_fibnum); | ||||
if (info->rti_ifa != NULL) | if (info->rti_ifa != NULL) | ||||
free_ifa = 1; | free_ifa = 1; | ||||
if (error != 0) { | if (error != 0) { | ||||
if (free_ifa) { | if (free_ifa) { | ||||
ifa_free(info->rti_ifa); | ifa_free(info->rti_ifa); | ||||
info->rti_ifa = NULL; | info->rti_ifa = NULL; | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
} | } | ||||
error = nhop_create_from_nhop(rnh, nh_orig, info, &nh); | error = nhop_create_from_nhop(rnh, nh_orig, info, nh_new); | ||||
if (free_ifa) { | if (free_ifa) { | ||||
ifa_free(info->rti_ifa); | ifa_free(info->rti_ifa); | ||||
info->rti_ifa = NULL; | info->rti_ifa = NULL; | ||||
} | } | ||||
return (error); | |||||
} | |||||
#ifdef ROUTE_MPATH | |||||
static int | |||||
change_mpath_route(struct rib_head *rnh, struct rt_addrinfo *info, | |||||
struct route_nhop_data *rnd_orig, struct rib_cmd_info *rc) | |||||
{ | |||||
int error = 0; | |||||
struct nhop_object *nh, *nh_orig, *nh_new; | |||||
struct route_nhop_data rnd_new; | |||||
nh = NULL; | |||||
nh_orig = rnd_orig->rnd_nhop; | |||||
struct weightened_nhop *wn = NULL, *wn_new; | |||||
uint32_t num_nhops; | |||||
wn = nhgrp_get_nhops((struct nhgrp_object *)nh_orig, &num_nhops); | |||||
nh_orig = NULL; | |||||
for (int i = 0; i < num_nhops; i++) { | |||||
if (check_info_match_nhop(info, NULL, wn[i].nh)) { | |||||
nh_orig = wn[i].nh; | |||||
break; | |||||
} | |||||
} | |||||
if (nh_orig == NULL) | |||||
return (ESRCH); | |||||
error = change_nhop(rnh, info, nh_orig, &nh_new); | |||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
rnd_new.rnd_nhop = nh; | wn_new = mallocarray(num_nhops, sizeof(struct weightened_nhop), | ||||
if (info->rti_mflags & RTV_WEIGHT) | M_TEMP, M_NOWAIT | M_ZERO); | ||||
rnd_new.rnd_weight = info->rti_rmx->rmx_weight; | if (wn_new == NULL) { | ||||
else | nhop_free(nh_new); | ||||
rnd_new.rnd_weight = rnd_orig->rnd_weight; | return (EAGAIN); | ||||
} | |||||
memcpy(wn_new, wn, num_nhops * sizeof(struct weightened_nhop)); | |||||
for (int i = 0; i < num_nhops; i++) { | |||||
if (wn[i].nh == nh_orig) { | |||||
wn[i].nh = nh_new; | |||||
wn[i].weight = get_info_weight(info, rnd_orig->rnd_weight); | |||||
break; | |||||
} | |||||
} | |||||
error = nhgrp_get_group(rnh, wn_new, num_nhops, &rnd_new); | |||||
nhop_free(nh_new); | |||||
free(wn_new, M_TEMP); | |||||
if (error != 0) | |||||
return (error); | |||||
error = change_route_conditional(rnh, NULL, info, rnd_orig, &rnd_new, rc); | error = change_route_conditional(rnh, NULL, info, rnd_orig, &rnd_new, rc); | ||||
return (error); | return (error); | ||||
} | } | ||||
#endif | |||||
static int | |||||
change_route(struct rib_head *rnh, struct rt_addrinfo *info, | |||||
struct route_nhop_data *rnd_orig, struct rib_cmd_info *rc) | |||||
{ | |||||
int error = 0; | |||||
struct nhop_object *nh, *nh_orig; | |||||
struct route_nhop_data rnd_new; | |||||
nh = NULL; | |||||
nh_orig = rnd_orig->rnd_nhop; | |||||
if (nh_orig == NULL) | |||||
return (ESRCH); | |||||
if (NH_IS_NHGRP(nh_orig)) | |||||
return (change_mpath_route(rnh, info, rnd_orig, rc)); | |||||
rnd_new.rnd_weight = get_info_weight(info, rnd_orig->rnd_weight); | |||||
error = change_nhop(rnh, info, nh_orig, &rnd_new.rnd_nhop); | |||||
if (error != 0) | |||||
return (error); | |||||
error = change_route_conditional(rnh, NULL, info, rnd_orig, &rnd_new, rc); | |||||
return (error); | |||||
} | |||||
/* | /* | ||||
* Insert @rt with nhop data from @rnd_new to @rnh. | * Insert @rt with nhop data from @rnd_new to @rnh. | ||||
* Returns 0 on success and stores operation results in @rc. | * Returns 0 on success and stores operation results in @rc. | ||||
*/ | */ | ||||
static int | static int | ||||
add_route_nhop(struct rib_head *rnh, struct rtentry *rt, | add_route_nhop(struct rib_head *rnh, struct rtentry *rt, | ||||
struct rt_addrinfo *info, struct route_nhop_data *rnd, | struct rt_addrinfo *info, struct route_nhop_data *rnd, | ||||
struct rib_cmd_info *rc) | struct rib_cmd_info *rc) | ||||
Show All 33 Lines | add_route_nhop(struct rib_head *rnh, struct rtentry *rt, | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Switch @rt nhop/weigh to the ones specified in @rnd. | * Switch @rt nhop/weigh to the ones specified in @rnd. | ||||
* Conditionally set rt_expire if set in @info. | * Conditionally set rt_expire if set in @info. | ||||
* Returns 0 on success. | * Returns 0 on success. | ||||
*/ | */ | ||||
static int | int | ||||
change_route_nhop(struct rib_head *rnh, struct rtentry *rt, | change_route_nhop(struct rib_head *rnh, struct rtentry *rt, | ||||
struct rt_addrinfo *info, struct route_nhop_data *rnd, | struct rt_addrinfo *info, struct route_nhop_data *rnd, | ||||
struct rib_cmd_info *rc) | struct rib_cmd_info *rc) | ||||
{ | { | ||||
struct nhop_object *nh_orig; | struct nhop_object *nh_orig; | ||||
RIB_WLOCK_ASSERT(rnh); | RIB_WLOCK_ASSERT(rnh); | ||||
nh_orig = rt->rt_nhop; | nh_orig = rt->rt_nhop; | ||||
if (rnd->rnd_nhop != NULL) { | if (rnd->rnd_nhop != NULL) { | ||||
/* Changing expiration & nexthop & weight to a new one */ | /* Changing expiration & nexthop & weight to a new one */ | ||||
rt_setmetrics(info, rt); | rt_set_expire_info(rt, info); | ||||
rt->rt_nhop = rnd->rnd_nhop; | rt->rt_nhop = rnd->rnd_nhop; | ||||
rt->rt_weight = rnd->rnd_weight; | rt->rt_weight = rnd->rnd_weight; | ||||
if (rt->rt_expire > 0) | if (rt->rt_expire > 0) | ||||
tmproutes_update(rnh, rt); | tmproutes_update(rnh, rt); | ||||
} else { | } else { | ||||
/* Route deletion requested. */ | /* Route deletion requested. */ | ||||
struct sockaddr *ndst, *netmask; | struct sockaddr *ndst, *netmask; | ||||
struct radix_node *rn; | struct radix_node *rn; | ||||
▲ Show 20 Lines • Show All 143 Lines • ▼ Show 20 Lines | rt_checkdelroute(struct radix_node *rn, void *arg) | ||||
/* | /* | ||||
* Add deleted rtentries to the list to GC them | * Add deleted rtentries to the list to GC them | ||||
* after dropping the lock. | * after dropping the lock. | ||||
* | * | ||||
* XXX: Delayed notifications not implemented | * XXX: Delayed notifications not implemented | ||||
* for nexthop updates. | * for nexthop updates. | ||||
*/ | */ | ||||
if (error == 0) { | if ((error == 0) && (di->rc.rc_cmd == RTM_DELETE)) { | ||||
/* Add to the list and return */ | /* Add to the list and return */ | ||||
rt->rt_chain = di->head; | rt->rt_chain = di->head; | ||||
di->head = rt; | di->head = rt; | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 201 Lines • Show Last 20 Lines |
So in the case of ! ROUTE_MPATH, the call to uma_zfree is suppressed now?