routing: extend nhop(9) kpi
* add nhop_get_unlinked() used to prepare referenced but not linked nexthop, that can later be used as a clone source. * add nhop_check_gateway() to check for allowed address family combinations between the rib family and neighbor family (useful for 4o6 or direct routes) * add nhop_set_upper_family() to allow copying IPv6 nexthops to IPv4 rib. * add rt_get_rnd() wrapper, returning both nexthop/group and its weight attached to the rtentry. * Add CHT_SLIST_FOREACH_SAFE(), allowing to delete items during iteration. MFC after: 2 weeks
This commit is contained in:
parent
c24a8f19c5
commit
fe05d1dd0f
@ -182,6 +182,7 @@ struct rib_head;
|
||||
struct nhop_object *nhop_alloc(uint32_t fibnum, int family);
|
||||
void nhop_copy(struct nhop_object *nh, const struct nhop_object *nh_orig);
|
||||
struct nhop_object *nhop_get_nhop(struct nhop_object *nh, int *perror);
|
||||
int nhop_get_unlinked(struct nhop_object *nh);
|
||||
|
||||
void nhop_set_direct_gw(struct nhop_object *nh, struct ifnet *ifp);
|
||||
bool nhop_set_gw(struct nhop_object *nh, const struct sockaddr *sa, bool is_gw);
|
||||
@ -206,11 +207,13 @@ int nhop_get_rtflags(const struct nhop_object *nh);
|
||||
struct vnet *nhop_get_vnet(const struct nhop_object *nh);
|
||||
struct nhop_object *nhop_select_func(struct nhop_object *nh, uint32_t flowid);
|
||||
int nhop_get_upper_family(const struct nhop_object *nh);
|
||||
bool nhop_set_upper_family(struct nhop_object *nh, int family);
|
||||
int nhop_get_neigh_family(const struct nhop_object *nh);
|
||||
uint32_t nhop_get_fibnum(const struct nhop_object *nh);
|
||||
void nhop_set_fibnum(struct nhop_object *nh, uint32_t fibnum);
|
||||
uint32_t nhop_get_expire(const struct nhop_object *nh);
|
||||
void nhop_set_expire(struct nhop_object *nh, uint32_t expire);
|
||||
struct rib_head *nhop_get_rh(const struct nhop_object *nh);
|
||||
|
||||
struct nhgrp_object;
|
||||
uint32_t nhgrp_get_uidx(const struct nhgrp_object *nhg);
|
||||
|
@ -85,13 +85,12 @@ _DECLARE_DEBUG(LOG_INFO);
|
||||
|
||||
static int dump_nhop_entry(struct rib_head *rh, struct nhop_object *nh, struct sysctl_req *w);
|
||||
|
||||
static int finalize_nhop(struct nh_control *ctl, struct nhop_object *nh);
|
||||
static int finalize_nhop(struct nh_control *ctl, struct nhop_object *nh, bool link);
|
||||
static struct ifnet *get_aifp(const struct nhop_object *nh);
|
||||
static void fill_sdl_from_ifp(struct sockaddr_dl_short *sdl, const struct ifnet *ifp);
|
||||
|
||||
static void destroy_nhop_epoch(epoch_context_t ctx);
|
||||
static void destroy_nhop(struct nhop_object *nh);
|
||||
static struct rib_head *nhop_get_rh(const struct nhop_object *nh);
|
||||
|
||||
_Static_assert(__offsetof(struct nhop_object, nh_ifp) == 32,
|
||||
"nhop_object: wrong nh_ifp offset");
|
||||
@ -315,6 +314,12 @@ nhop_get_nhop(struct nhop_object *nh, int *perror)
|
||||
{
|
||||
struct rib_head *rnh = nhop_get_rh(nh);
|
||||
|
||||
if (__predict_false(rnh == NULL)) {
|
||||
*perror = EAFNOSUPPORT;
|
||||
nhop_free(nh);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (nhop_get_nhop_internal(rnh, nh, perror));
|
||||
}
|
||||
|
||||
@ -349,10 +354,33 @@ nhop_get_nhop_internal(struct rib_head *rnh, struct nhop_object *nh, int *perror
|
||||
* relative number of such nexthops is significant, which
|
||||
* is extremely unlikely.
|
||||
*/
|
||||
*perror = finalize_nhop(rnh->nh_control, nh);
|
||||
*perror = finalize_nhop(rnh->nh_control, nh, true);
|
||||
return (*perror == 0 ? nh : NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets referenced but unlinked nhop.
|
||||
* Alocates/references the remaining bits of the nexthop data, so
|
||||
* it can be safely linked later or used as a clone source.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
*/
|
||||
int
|
||||
nhop_get_unlinked(struct nhop_object *nh)
|
||||
{
|
||||
struct rib_head *rnh = nhop_get_rh(nh);
|
||||
|
||||
if (__predict_false(rnh == NULL)) {
|
||||
nhop_free(nh);
|
||||
return (EAFNOSUPPORT);
|
||||
}
|
||||
|
||||
nh->nh_aifp = get_aifp(nh);
|
||||
|
||||
return (finalize_nhop(rnh->nh_control, nh, false));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Update @nh with data supplied in @info.
|
||||
* This is a helper function to support route changes.
|
||||
@ -458,7 +486,7 @@ reference_nhop_deps(struct nhop_object *nh)
|
||||
* errno otherwise. @nh_priv is freed in case of error.
|
||||
*/
|
||||
static int
|
||||
finalize_nhop(struct nh_control *ctl, struct nhop_object *nh)
|
||||
finalize_nhop(struct nh_control *ctl, struct nhop_object *nh, bool link)
|
||||
{
|
||||
|
||||
/* Allocate per-cpu packet counter */
|
||||
@ -484,9 +512,14 @@ finalize_nhop(struct nh_control *ctl, struct nhop_object *nh)
|
||||
/* Please see nhop_free() comments on the initial value */
|
||||
refcount_init(&nh->nh_priv->nh_linked, 2);
|
||||
|
||||
nh->nh_priv->nh_fibnum = ctl->ctl_rh->rib_fibnum;
|
||||
MPASS(nh->nh_priv->nh_fibnum == ctl->ctl_rh->rib_fibnum);
|
||||
|
||||
if (link_nhop(ctl, nh->nh_priv) == 0) {
|
||||
if (!link) {
|
||||
refcount_release(&nh->nh_priv->nh_linked);
|
||||
NHOPS_WLOCK(ctl);
|
||||
nh->nh_priv->nh_finalized = 1;
|
||||
NHOPS_WUNLOCK(ctl);
|
||||
} else if (link_nhop(ctl, nh->nh_priv) == 0) {
|
||||
/*
|
||||
* Adding nexthop to the datastructures
|
||||
* failed. Call destructor w/o waiting for
|
||||
@ -693,6 +726,22 @@ nhop_set_direct_gw(struct nhop_object *nh, struct ifnet *ifp)
|
||||
memset(&nh->gw_buf[nh->gw_sa.sa_len], 0, sizeof(nh->gw_buf) - nh->gw_sa.sa_len);
|
||||
}
|
||||
|
||||
bool
|
||||
nhop_check_gateway(int upper_family, int neigh_family)
|
||||
{
|
||||
if (upper_family == neigh_family)
|
||||
return (true);
|
||||
else if (neigh_family == AF_UNSPEC || neigh_family == AF_LINK)
|
||||
return (true);
|
||||
#if defined(INET) && defined(INET6)
|
||||
else if (upper_family == AF_INET && neigh_family == AF_INET6 &&
|
||||
rib_can_4o6_nhop())
|
||||
return (true);
|
||||
#endif
|
||||
else
|
||||
return (false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets gateway for the nexthop.
|
||||
* It can be "normal" gateway with is_gw set or a special form of
|
||||
@ -707,6 +756,14 @@ nhop_set_gw(struct nhop_object *nh, const struct sockaddr *gw, bool is_gw)
|
||||
gw->sa_family, gw->sa_len);
|
||||
return (false);
|
||||
}
|
||||
|
||||
if (!nhop_check_gateway(nh->nh_priv->nh_upper_family, gw->sa_family)) {
|
||||
FIB_NH_LOG(LOG_DEBUG, nh,
|
||||
"error: invalid dst/gateway family combination (%d, %d)",
|
||||
nh->nh_priv->nh_upper_family, gw->sa_family);
|
||||
return (false);
|
||||
}
|
||||
|
||||
memcpy(&nh->gw_sa, gw, gw->sa_len);
|
||||
memset(&nh->gw_buf[gw->sa_len], 0, sizeof(nh->gw_buf) - gw->sa_len);
|
||||
|
||||
@ -723,6 +780,20 @@ nhop_set_gw(struct nhop_object *nh, const struct sockaddr *gw, bool is_gw)
|
||||
return (true);
|
||||
}
|
||||
|
||||
bool
|
||||
nhop_set_upper_family(struct nhop_object *nh, int family)
|
||||
{
|
||||
if (!nhop_check_gateway(nh->nh_priv->nh_upper_family, family)) {
|
||||
FIB_NH_LOG(LOG_DEBUG, nh,
|
||||
"error: invalid upper/neigh family combination (%d, %d)",
|
||||
nh->nh_priv->nh_upper_family, family);
|
||||
return (false);
|
||||
}
|
||||
|
||||
nh->nh_priv->nh_upper_family = family;
|
||||
return (true);
|
||||
}
|
||||
|
||||
void
|
||||
nhop_set_broadcast(struct nhop_object *nh, bool is_broadcast)
|
||||
{
|
||||
@ -930,7 +1001,7 @@ nhop_set_expire(struct nhop_object *nh, uint32_t expire)
|
||||
nh->nh_priv->nh_expire = expire;
|
||||
}
|
||||
|
||||
static struct rib_head *
|
||||
struct rib_head *
|
||||
nhop_get_rh(const struct nhop_object *nh)
|
||||
{
|
||||
uint32_t fibnum = nhop_get_fibnum(nh);
|
||||
|
@ -139,6 +139,11 @@ struct _HNAME##_head { \
|
||||
for (_x = CHT_FIRST(_head, _i); _x; _x = _PX##_next(_x))
|
||||
#define CHT_SLIST_FOREACH_END }
|
||||
|
||||
#define CHT_SLIST_FOREACH_SAFE(_head, _PX, _x, _tmp) \
|
||||
for (uint32_t _i = 0; _i < (_head)->hash_size; _i++) { \
|
||||
for (_x = CHT_FIRST(_head, _i); (_tmp = _PX##_next(_x), _x); _x = _tmp)
|
||||
#define CHT_SLIST_FOREACH_SAFE_END }
|
||||
|
||||
#define CHT_SLIST_RESIZE(_head, _PX, _new_void_ptr, _new_hsize) \
|
||||
uint32_t _new_idx; \
|
||||
typeof((_head)->ptr) _new_ptr = (void *)_new_void_ptr; \
|
||||
|
@ -134,7 +134,7 @@ uint8_t mpath_entropy_key[MPATH_ENTROPY_KEY_LEN] = {
|
||||
#if defined(INET) && defined(INET6)
|
||||
FEATURE(ipv4_rfc5549_support, "Route IPv4 packets via IPv6 nexthops");
|
||||
#define V_rib_route_ipv6_nexthop VNET(rib_route_ipv6_nexthop)
|
||||
VNET_DEFINE(u_int, rib_route_ipv6_nexthop) = 1;
|
||||
VNET_DEFINE_STATIC(u_int, rib_route_ipv6_nexthop) = 1;
|
||||
SYSCTL_UINT(_net_route, OID_AUTO, ipv6_nexthop, CTLFLAG_RW | CTLFLAG_VNET,
|
||||
&VNET_NAME(rib_route_ipv6_nexthop), 0, "Enable IPv4 route via IPv6 Next Hop address");
|
||||
#endif
|
||||
@ -157,16 +157,10 @@ get_rnh(uint32_t fibnum, const struct rt_addrinfo *info)
|
||||
}
|
||||
|
||||
#if defined(INET) && defined(INET6)
|
||||
static bool
|
||||
rib_can_ipv6_nexthop_address(struct rib_head *rh)
|
||||
bool
|
||||
rib_can_4o6_nhop(void)
|
||||
{
|
||||
int result;
|
||||
|
||||
CURVNET_SET(rh->rib_vnet);
|
||||
result = !!V_rib_route_ipv6_nexthop;
|
||||
CURVNET_RESTORE();
|
||||
|
||||
return (result);
|
||||
return (!!V_rib_route_ipv6_nexthop);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -702,30 +696,6 @@ rib_add_route(uint32_t fibnum, struct rt_addrinfo *info,
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if @dst and @gateway is valid combination.
|
||||
*
|
||||
* Returns true if is valid, false otherwise.
|
||||
*/
|
||||
static bool
|
||||
check_gateway(struct rib_head *rnh, struct sockaddr *dst,
|
||||
struct sockaddr *gateway)
|
||||
{
|
||||
if (dst->sa_family == gateway->sa_family)
|
||||
return (true);
|
||||
else if (gateway->sa_family == AF_UNSPEC)
|
||||
return (true);
|
||||
else if (gateway->sa_family == AF_LINK)
|
||||
return (true);
|
||||
#if defined(INET) && defined(INET6)
|
||||
else if (dst->sa_family == AF_INET && gateway->sa_family == AF_INET6 &&
|
||||
rib_can_ipv6_nexthop_address(rnh))
|
||||
return (true);
|
||||
#endif
|
||||
else
|
||||
return (false);
|
||||
}
|
||||
|
||||
static int
|
||||
add_route_byinfo(struct rib_head *rnh, struct rt_addrinfo *info,
|
||||
struct rib_cmd_info *rc)
|
||||
@ -744,7 +714,7 @@ add_route_byinfo(struct rib_head *rnh, struct rt_addrinfo *info,
|
||||
FIB_RH_LOG(LOG_DEBUG, rnh, "error: RTF_GATEWAY set with empty gw");
|
||||
return (EINVAL);
|
||||
}
|
||||
if (dst && gateway && !check_gateway(rnh, dst, gateway)) {
|
||||
if (dst && gateway && !nhop_check_gateway(dst->sa_family, gateway->sa_family)) {
|
||||
FIB_RH_LOG(LOG_DEBUG, rnh,
|
||||
"error: invalid dst/gateway family combination (%d, %d)",
|
||||
dst->sa_family, gateway->sa_family);
|
||||
@ -1578,3 +1548,4 @@ rib_print_family(int family)
|
||||
}
|
||||
return ("unknown");
|
||||
}
|
||||
|
||||
|
@ -136,6 +136,7 @@ const struct rtentry *rib_lookup_lpm(uint32_t fibnum, int family,
|
||||
bool rt_is_host(const struct rtentry *rt);
|
||||
sa_family_t rt_get_family(const struct rtentry *);
|
||||
struct nhop_object *rt_get_raw_nhop(const struct rtentry *rt);
|
||||
void rt_get_rnd(const struct rtentry *rt, struct route_nhop_data *rnd);
|
||||
#ifdef INET
|
||||
struct in_addr;
|
||||
void rt_get_inet_prefix_plen(const struct rtentry *rt, struct in_addr *paddr,
|
||||
|
@ -192,6 +192,13 @@ rt_get_raw_nhop(const struct rtentry *rt)
|
||||
return (rt->rt_nhop);
|
||||
}
|
||||
|
||||
void
|
||||
rt_get_rnd(const struct rtentry *rt, struct route_nhop_data *rnd)
|
||||
{
|
||||
rnd->rnd_nhop = rt->rt_nhop;
|
||||
rnd->rnd_weight = rt->rt_weight;
|
||||
}
|
||||
|
||||
#ifdef INET
|
||||
/*
|
||||
* Stores IPv4 address and prefix length of @rt inside
|
||||
|
@ -228,6 +228,7 @@ bool nhop_can_multipath(const struct nhop_object *nh);
|
||||
bool match_nhop_gw(const struct nhop_object *nh, const struct sockaddr *gw);
|
||||
int check_info_match_nhop(const struct rt_addrinfo *info,
|
||||
const struct rtentry *rt, const struct nhop_object *nh);
|
||||
bool rib_can_4o6_nhop(void);
|
||||
|
||||
/* route_rtentry.c */
|
||||
void vnet_rtzone_init(void);
|
||||
@ -255,6 +256,7 @@ void nhop_free_any(struct nhop_object *nh);
|
||||
struct nhop_object *nhop_get_nhop_internal(struct rib_head *rnh,
|
||||
struct nhop_object *nh, int *perror);
|
||||
|
||||
bool nhop_check_gateway(int upper_family, int neigh_family);
|
||||
|
||||
int nhop_create_from_info(struct rib_head *rnh, struct rt_addrinfo *info,
|
||||
struct nhop_object **nh_ret);
|
||||
|
Loading…
Reference in New Issue
Block a user