Changeset View
Changeset View
Standalone View
Standalone View
sys/net/route/nhop_ctl.c
Show First 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | |||||
* | * | ||||
* Conventions: | * Conventions: | ||||
* 1) non-exported functions start with verb | * 1) non-exported functions start with verb | ||||
* 2) exported function starts with the subsystem prefix: "nhop" | * 2) exported function starts with the subsystem prefix: "nhop" | ||||
*/ | */ | ||||
static int dump_nhop_entry(struct rib_head *rh, struct nhop_object *nh, struct sysctl_req *w); | 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 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 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_epoch(epoch_context_t ctx); | ||||
static void destroy_nhop(struct nhop_object *nh); | 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, | _Static_assert(__offsetof(struct nhop_object, nh_ifp) == 32, | ||||
"nhop_object: wrong nh_ifp offset"); | "nhop_object: wrong nh_ifp offset"); | ||||
_Static_assert(sizeof(struct nhop_object) <= 128, | _Static_assert(sizeof(struct nhop_object) <= 128, | ||||
"nhop_object: size exceeds 128 bytes"); | "nhop_object: size exceeds 128 bytes"); | ||||
static uma_zone_t nhops_zone; /* Global zone for each and every nexthop */ | static uma_zone_t nhops_zone; /* Global zone for each and every nexthop */ | ||||
▲ Show 20 Lines • Show All 207 Lines • ▼ Show 20 Lines | |||||
* Returns 0 on success, storing referenced nexthop in @pnh. | * Returns 0 on success, storing referenced nexthop in @pnh. | ||||
* Otherwise, errno is returned. | * Otherwise, errno is returned. | ||||
*/ | */ | ||||
struct nhop_object * | struct nhop_object * | ||||
nhop_get_nhop(struct nhop_object *nh, int *perror) | nhop_get_nhop(struct nhop_object *nh, int *perror) | ||||
{ | { | ||||
struct rib_head *rnh = nhop_get_rh(nh); | 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)); | return (nhop_get_nhop_internal(rnh, nh, perror)); | ||||
} | } | ||||
struct nhop_object * | struct nhop_object * | ||||
nhop_get_nhop_internal(struct rib_head *rnh, struct nhop_object *nh, int *perror) | nhop_get_nhop_internal(struct rib_head *rnh, struct nhop_object *nh, int *perror) | ||||
{ | { | ||||
struct nhop_priv *tmp_priv; | struct nhop_priv *tmp_priv; | ||||
int error; | int error; | ||||
Show All 18 Lines | nhop_get_nhop_internal(struct rib_head *rnh, struct nhop_object *nh, int *perror) | ||||
/* | /* | ||||
* Existing nexthop not found, need to create new one. | * Existing nexthop not found, need to create new one. | ||||
* Note: multiple simultaneous requests | * Note: multiple simultaneous requests | ||||
* can result in multiple equal nexhops existing in the | * can result in multiple equal nexhops existing in the | ||||
* nexthop table. This is not a not a problem until the | * nexthop table. This is not a not a problem until the | ||||
* relative number of such nexthops is significant, which | * relative number of such nexthops is significant, which | ||||
* is extremely unlikely. | * is extremely unlikely. | ||||
*/ | */ | ||||
*perror = finalize_nhop(rnh->nh_control, nh); | *perror = finalize_nhop(rnh->nh_control, nh, true); | ||||
return (*perror == 0 ? nh : NULL); | return (*perror == 0 ? nh : NULL); | ||||
} | } | ||||
/* | /* | ||||
* Alocates/references the remaining bits of nexthop data. | |||||
*/ | |||||
int | |||||
nhop_finalize(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. | * Update @nh with data supplied in @info. | ||||
* This is a helper function to support route changes. | * This is a helper function to support route changes. | ||||
* | * | ||||
* It limits the changes that can be done to the route to the following: | * It limits the changes that can be done to the route to the following: | ||||
* 1) all combination of gateway changes | * 1) all combination of gateway changes | ||||
* 2) route flags (FLAG[123],STATIC) | * 2) route flags (FLAG[123],STATIC) | ||||
* 3) route MTU | * 3) route MTU | ||||
* | * | ||||
▲ Show 20 Lines • Show All 88 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Alocates/references the remaining bits of nexthop data and links | * Alocates/references the remaining bits of nexthop data and links | ||||
* it to the hash table. | * it to the hash table. | ||||
* Returns 0 if successful, | * Returns 0 if successful, | ||||
* errno otherwise. @nh_priv is freed in case of error. | * errno otherwise. @nh_priv is freed in case of error. | ||||
*/ | */ | ||||
static int | 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 */ | /* Allocate per-cpu packet counter */ | ||||
nh->nh_pksent = counter_u64_alloc(M_NOWAIT); | nh->nh_pksent = counter_u64_alloc(M_NOWAIT); | ||||
if (nh->nh_pksent == NULL) { | if (nh->nh_pksent == NULL) { | ||||
nhop_free(nh); | nhop_free(nh); | ||||
RTSTAT_INC(rts_nh_alloc_failure); | RTSTAT_INC(rts_nh_alloc_failure); | ||||
FIB_NH_LOG(LOG_WARNING, nh, "counter_u64_alloc() failed"); | FIB_NH_LOG(LOG_WARNING, nh, "counter_u64_alloc() failed"); | ||||
Show All 9 Lines | finalize_nhop(struct nh_control *ctl, struct nhop_object *nh, bool link) | ||||
} | } | ||||
/* Save vnet to ease destruction */ | /* Save vnet to ease destruction */ | ||||
nh->nh_priv->nh_vnet = curvnet; | nh->nh_priv->nh_vnet = curvnet; | ||||
/* Please see nhop_free() comments on the initial value */ | /* Please see nhop_free() comments on the initial value */ | ||||
refcount_init(&nh->nh_priv->nh_linked, 2); | 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 | * Adding nexthop to the datastructures | ||||
* failed. Call destructor w/o waiting for | * failed. Call destructor w/o waiting for | ||||
* the epoch end, as nexthop is not used | * the epoch end, as nexthop is not used | ||||
* and return. | * and return. | ||||
*/ | */ | ||||
char nhbuf[NHOP_PRINT_BUFSIZE]; | char nhbuf[NHOP_PRINT_BUFSIZE]; | ||||
FIB_NH_LOG(LOG_WARNING, nh, "failed to link %s", | FIB_NH_LOG(LOG_WARNING, nh, "failed to link %s", | ||||
▲ Show 20 Lines • Show All 190 Lines • ▼ Show 20 Lines | nhop_set_direct_gw(struct nhop_object *nh, struct ifnet *ifp) | ||||
nh->nh_flags &= ~NHF_GATEWAY; | nh->nh_flags &= ~NHF_GATEWAY; | ||||
nh->nh_priv->rt_flags &= ~RTF_GATEWAY; | nh->nh_priv->rt_flags &= ~RTF_GATEWAY; | ||||
nh->nh_priv->nh_neigh_family = nh->nh_priv->nh_upper_family; | nh->nh_priv->nh_neigh_family = nh->nh_priv->nh_upper_family; | ||||
fill_sdl_from_ifp(&nh->gwl_sa, ifp); | fill_sdl_from_ifp(&nh->gwl_sa, ifp); | ||||
memset(&nh->gw_buf[nh->gw_sa.sa_len], 0, sizeof(nh->gw_buf) - nh->gw_sa.sa_len); | 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. | * Sets gateway for the nexthop. | ||||
* It can be "normal" gateway with is_gw set or a special form of | * It can be "normal" gateway with is_gw set or a special form of | ||||
* adding interface route, refering to it by specifying local interface | * adding interface route, refering to it by specifying local interface | ||||
* address. In that case is_gw is set to false. | * address. In that case is_gw is set to false. | ||||
*/ | */ | ||||
bool | bool | ||||
nhop_set_gw(struct nhop_object *nh, const struct sockaddr *gw, bool is_gw) | nhop_set_gw(struct nhop_object *nh, const struct sockaddr *gw, bool is_gw) | ||||
{ | { | ||||
if (gw->sa_len > sizeof(nh->gw_buf)) { | if (gw->sa_len > sizeof(nh->gw_buf)) { | ||||
FIB_NH_LOG(LOG_DEBUG, nh, "nhop SA size too big: AF %d len %u", | FIB_NH_LOG(LOG_DEBUG, nh, "nhop SA size too big: AF %d len %u", | ||||
gw->sa_family, gw->sa_len); | gw->sa_family, gw->sa_len); | ||||
return (false); | 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); | memcpy(&nh->gw_sa, gw, gw->sa_len); | ||||
memset(&nh->gw_buf[gw->sa_len], 0, sizeof(nh->gw_buf) - gw->sa_len); | memset(&nh->gw_buf[gw->sa_len], 0, sizeof(nh->gw_buf) - gw->sa_len); | ||||
if (is_gw) { | if (is_gw) { | ||||
nh->nh_flags |= NHF_GATEWAY; | nh->nh_flags |= NHF_GATEWAY; | ||||
nh->nh_priv->rt_flags |= RTF_GATEWAY; | nh->nh_priv->rt_flags |= RTF_GATEWAY; | ||||
nh->nh_priv->nh_neigh_family = gw->sa_family; | nh->nh_priv->nh_neigh_family = gw->sa_family; | ||||
} else { | } else { | ||||
nh->nh_flags &= ~NHF_GATEWAY; | nh->nh_flags &= ~NHF_GATEWAY; | ||||
nh->nh_priv->rt_flags &= ~RTF_GATEWAY; | nh->nh_priv->rt_flags &= ~RTF_GATEWAY; | ||||
nh->nh_priv->nh_neigh_family = nh->nh_priv->nh_upper_family; | nh->nh_priv->nh_neigh_family = nh->nh_priv->nh_upper_family; | ||||
} | } | ||||
return (true); | 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 | void | ||||
nhop_set_broadcast(struct nhop_object *nh, bool is_broadcast) | nhop_set_broadcast(struct nhop_object *nh, bool is_broadcast) | ||||
{ | { | ||||
if (is_broadcast) { | if (is_broadcast) { | ||||
nh->nh_flags |= NHF_BROADCAST; | nh->nh_flags |= NHF_BROADCAST; | ||||
nh->nh_priv->rt_flags |= RTF_BROADCAST; | nh->nh_priv->rt_flags |= RTF_BROADCAST; | ||||
} else { | } else { | ||||
nh->nh_flags &= ~NHF_BROADCAST; | nh->nh_flags &= ~NHF_BROADCAST; | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | |||||
uint32_t | uint32_t | ||||
nhop_get_idx(const struct nhop_object *nh) | nhop_get_idx(const struct nhop_object *nh) | ||||
{ | { | ||||
return (nh->nh_priv->nh_idx); | return (nh->nh_priv->nh_idx); | ||||
} | } | ||||
uint32_t | |||||
nhop_get_uidx(const struct nhop_object *nh) | |||||
{ | |||||
return (nh->nh_priv->nh_uidx); | |||||
} | |||||
void | |||||
nhop_set_uidx(struct nhop_object *nh, uint32_t uidx) | |||||
{ | |||||
nh->nh_priv->nh_uidx = uidx; | |||||
} | |||||
enum nhop_type | enum nhop_type | ||||
nhop_get_type(const struct nhop_object *nh) | nhop_get_type(const struct nhop_object *nh) | ||||
{ | { | ||||
return (nh->nh_priv->nh_type); | return (nh->nh_priv->nh_type); | ||||
} | } | ||||
void | void | ||||
▲ Show 20 Lines • Show All 122 Lines • ▼ Show 20 Lines | |||||
void | void | ||||
nhop_set_expire(struct nhop_object *nh, uint32_t expire) | nhop_set_expire(struct nhop_object *nh, uint32_t expire) | ||||
{ | { | ||||
MPASS(!NH_IS_LINKED(nh)); | MPASS(!NH_IS_LINKED(nh)); | ||||
nh->nh_priv->nh_expire = expire; | nh->nh_priv->nh_expire = expire; | ||||
} | } | ||||
static struct rib_head * | struct rib_head * | ||||
nhop_get_rh(const struct nhop_object *nh) | nhop_get_rh(const struct nhop_object *nh) | ||||
{ | { | ||||
uint32_t fibnum = nhop_get_fibnum(nh); | uint32_t fibnum = nhop_get_fibnum(nh); | ||||
int family = nhop_get_neigh_family(nh); | int family = nhop_get_neigh_family(nh); | ||||
return (rt_tables_get_rnh(fibnum, family)); | return (rt_tables_get_rnh(fibnum, family)); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 194 Lines • Show Last 20 Lines |