Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F108667380
D35985.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
29 KB
Referenced Files
None
Subscribers
None
D35985.diff
View Options
diff --git a/sys/net/route.c b/sys/net/route.c
--- a/sys/net/route.c
+++ b/sys/net/route.c
@@ -570,7 +570,7 @@
}
/*
- * Look up rt_addrinfo for a specific fib.
+ * Fills in rti_ifp and rti_ifa for the provided fib.
*
* Assume basic consistency checks are executed by callers:
* RTAX_DST exists, if RTF_GATEWAY is set, RTAX_GATEWAY exists as well.
diff --git a/sys/net/route/nhgrp.c b/sys/net/route/nhgrp.c
--- a/sys/net/route/nhgrp.c
+++ b/sys/net/route/nhgrp.c
@@ -179,6 +179,13 @@
NHOPS_WUNLOCK(ctl);
+#if DEBUG_MAX_LEVEL >= LOG_DEBUG2
+ {
+ char nhgrp_buf[NHOP_PRINT_BUFSIZE];
+ nhgrp_print_buf(grp_priv->nhg, nhgrp_buf, sizeof(nhgrp_buf));
+ FIB_RH_LOG(LOG_DEBUG2, ctl->ctl_rh, "linked %s", nhgrp_buf);
+ }
+#endif
consider_resize(ctl, new_num_buckets, new_num_items);
return (1);
@@ -207,6 +214,14 @@
NHOPS_WUNLOCK(ctl);
+#if DEBUG_MAX_LEVEL >= LOG_DEBUG2
+ {
+ char nhgrp_buf[NHOP_PRINT_BUFSIZE];
+ nhgrp_print_buf(nhg_priv_ret->nhg, nhgrp_buf, sizeof(nhgrp_buf));
+ FIB_RH_LOG(LOG_DEBUG2, ctl->ctl_rh, "unlinked idx#%d %s", idx,
+ nhgrp_buf);
+ }
+#endif
return (nhg_priv_ret);
}
diff --git a/sys/net/route/nhop.h b/sys/net/route/nhop.h
--- a/sys/net/route/nhop.h
+++ b/sys/net/route/nhop.h
@@ -175,6 +175,29 @@
struct sockaddr_dl;
struct rib_head;
+/* flags that can be set using nhop_set_rtflags() */
+#define RT_SET_RTFLAGS_MASK (RTF_PROTO1 | RTF_PROTO2 | RTF_PROTO3 | RTF_STATIC)
+#define RT_CHANGE_RTFLAGS_MASK RT_SET_RTFLAGS_MASK
+
+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);
+
+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);
+
+
+void nhop_set_mtu(struct nhop_object *nh, uint32_t mtu, bool from_user);
+void nhop_set_rtflags(struct nhop_object *nh, int rt_flags);
+void nhop_set_pxtype_flag(struct nhop_object *nh, int nh_flag);
+void nhop_set_broadcast(struct nhop_object *nh, bool is_broadcast);
+void nhop_set_blackhole(struct nhop_object *nh, int blackhole_rt_flag);
+void nhop_set_pinned(struct nhop_object *nh, bool is_pinned);
+void nhop_set_redirect(struct nhop_object *nh, bool is_redirect);
+void nhop_set_type(struct nhop_object *nh, enum nhop_type nh_type);
+void nhop_set_src(struct nhop_object *nh, struct ifaddr *ifa);
+void nhop_set_transmit_ifp(struct nhop_object *nh, struct ifnet *ifp);
+
uint32_t nhop_get_idx(const struct nhop_object *nh);
enum nhop_type nhop_get_type(const struct nhop_object *nh);
int nhop_get_rtflags(const struct nhop_object *nh);
diff --git a/sys/net/route/nhop.c b/sys/net/route/nhop.c
--- a/sys/net/route/nhop.c
+++ b/sys/net/route/nhop.c
@@ -304,6 +304,7 @@
nh_priv->nh_idx = idx;
nh_priv->nh_control = ctl;
+ nh_priv->nh_finalized = 1;
CHT_SLIST_INSERT_HEAD(&ctl->nh_head, nhops, nh_priv);
diff --git a/sys/net/route/nhop_ctl.c b/sys/net/route/nhop_ctl.c
--- a/sys/net/route/nhop_ctl.c
+++ b/sys/net/route/nhop_ctl.c
@@ -85,16 +85,13 @@
static int dump_nhop_entry(struct rib_head *rh, struct nhop_object *nh, struct sysctl_req *w);
-static struct nhop_priv *alloc_nhop_structure(void);
-static int get_nhop(struct rib_head *rnh, struct rt_addrinfo *info,
- struct nhop_priv **pnh_priv);
-static int finalize_nhop(struct nh_control *ctl, struct rt_addrinfo *info,
- struct nhop_priv *nh_priv);
+static int finalize_nhop(struct nh_control *ctl, 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 destroy_nhop_epoch(epoch_context_t ctx);
-static void destroy_nhop(struct nhop_priv *nh_priv);
+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");
@@ -172,24 +169,8 @@
static void
set_nhop_mtu_from_info(struct nhop_object *nh, const struct rt_addrinfo *info)
{
-
- if (info->rti_mflags & RTV_MTU) {
- if (info->rti_rmx->rmx_mtu != 0) {
- /*
- * MTU was explicitly provided by user.
- * Keep it.
- */
-
- nh->nh_priv->rt_flags |= RTF_FIXEDMTU;
- } else {
- /*
- * User explicitly sets MTU to 0.
- * Assume rollback to default.
- */
- nh->nh_priv->rt_flags &= ~RTF_FIXEDMTU;
- }
- nh->nh_mtu = info->rti_rmx->rmx_mtu;
- }
+ if (info->rti_mflags & RTV_MTU)
+ nhop_set_mtu(nh, info->rti_rmx->rmx_mtu, true);
}
/*
@@ -213,9 +194,10 @@
struct sockaddr *gw;
gw = info->rti_info[RTAX_GATEWAY];
- KASSERT(gw != NULL, ("gw is NULL"));
+ MPASS(gw != NULL);
+ bool is_gw = info->rti_flags & RTF_GATEWAY;
- if ((gw->sa_family == AF_LINK) && !(info->rti_flags & RTF_GATEWAY)) {
+ if ((gw->sa_family == AF_LINK) && !is_gw) {
/*
* Interface route with interface specified by the interface
@@ -233,7 +215,7 @@
sdl->sdl_index);
return (EINVAL);
}
- fill_sdl_from_ifp(&nh->gwl_sa, ifp);
+ nhop_set_direct_gw(nh, ifp);
} else {
/*
@@ -247,31 +229,12 @@
* In both cases, save the original nexthop to make the callers
* happy.
*/
- if (gw->sa_len > sizeof(struct sockaddr_in6)) {
- FIB_NH_LOG(LOG_DEBUG, nh, "nhop SA size too big: AF %d len %u",
- gw->sa_family, gw->sa_len);
+ if (!nhop_set_gw(nh, gw, is_gw))
return (EINVAL);
- }
- memcpy(&nh->gw_sa, gw, gw->sa_len);
}
return (0);
}
-static uint16_t
-convert_rt_to_nh_flags(int rt_flags)
-{
- uint16_t res;
-
- res = (rt_flags & RTF_REJECT) ? NHF_REJECT : 0;
- res |= (rt_flags & RTF_HOST) ? NHF_HOST : 0;
- res |= (rt_flags & RTF_BLACKHOLE) ? NHF_BLACKHOLE : 0;
- res |= (rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) ? NHF_REDIRECT : 0;
- res |= (rt_flags & RTF_BROADCAST) ? NHF_BROADCAST : 0;
- res |= (rt_flags & RTF_GATEWAY) ? NHF_GATEWAY : 0;
-
- return (res);
-}
-
static void
set_nhop_expire_from_info(struct nhop_object *nh, const struct rt_addrinfo *info)
{
@@ -283,43 +246,6 @@
nhop_set_expire(nh, nh_expire);
}
-static int
-fill_nhop_from_info(struct nhop_priv *nh_priv, struct rt_addrinfo *info)
-{
- int error, rt_flags;
- struct nhop_object *nh;
-
- nh = nh_priv->nh;
-
- rt_flags = info->rti_flags & NHOP_RT_FLAG_MASK;
-
- nh->nh_priv->rt_flags = rt_flags;
- nh_priv->nh_upper_family = info->rti_info[RTAX_DST]->sa_family;
- nh_priv->nh_type = 0; // hook responsibility to set nhop type
- nh->nh_flags = convert_rt_to_nh_flags(rt_flags);
-
- set_nhop_mtu_from_info(nh, info);
- if ((error = set_nhop_gw_from_info(nh, info)) != 0)
- return (error);
- if (nh->gw_sa.sa_family == AF_LINK)
- nh_priv->nh_neigh_family = nh_priv->nh_upper_family;
- else
- nh_priv->nh_neigh_family = nh->gw_sa.sa_family;
- set_nhop_expire_from_info(nh, info);
-
- nh->nh_ifp = (info->rti_ifp != NULL) ? info->rti_ifp : info->rti_ifa->ifa_ifp;
- nh->nh_ifa = info->rti_ifa;
- /* depends on the gateway */
- nh->nh_aifp = get_aifp(nh);
-
- /*
- * Note some of the remaining data is set by the
- * per-address-family pre-add hook.
- */
-
- return (0);
-}
-
/*
* Creates a new nexthop based on the information in @info.
*
@@ -331,81 +257,94 @@
nhop_create_from_info(struct rib_head *rnh, struct rt_addrinfo *info,
struct nhop_object **nh_ret)
{
- struct nhop_priv *nh_priv;
int error;
NET_EPOCH_ASSERT();
+ MPASS(info->rti_ifa != NULL);
+ MPASS(info->rti_ifp != NULL);
+
if (info->rti_info[RTAX_GATEWAY] == NULL) {
FIB_RH_LOG(LOG_DEBUG, rnh, "error: empty gateway");
return (EINVAL);
}
- nh_priv = alloc_nhop_structure();
+ struct nhop_object *nh = nhop_alloc(rnh->rib_fibnum, rnh->rib_family);
+ if (nh == NULL)
+ return (ENOMEM);
- error = fill_nhop_from_info(nh_priv, info);
- if (error != 0) {
- uma_zfree(nhops_zone, nh_priv->nh);
+ if ((error = set_nhop_gw_from_info(nh, info)) != 0) {
+ nhop_free(nh);
return (error);
}
+ nhop_set_transmit_ifp(nh, info->rti_ifp);
- error = get_nhop(rnh, info, &nh_priv);
- if (error == 0)
- *nh_ret = nh_priv->nh;
+ nhop_set_blackhole(nh, info->rti_flags & (RTF_BLACKHOLE | RTF_REJECT));
+
+ error = rnh->rnh_set_nh_pfxflags(rnh->rib_fibnum, info->rti_info[RTAX_DST],
+ info->rti_info[RTAX_NETMASK], nh);
+
+ nhop_set_redirect(nh, info->rti_flags & RTF_DYNAMIC);
+ nhop_set_pinned(nh, info->rti_flags & RTF_PINNED);
+ set_nhop_expire_from_info(nh, info);
+ nhop_set_rtflags(nh, info->rti_flags);
+
+ set_nhop_mtu_from_info(nh, info);
+ nhop_set_src(nh, info->rti_ifa);
+
+ /*
+ * The remaining fields are either set from nh_preadd hook
+ * or are computed from the provided data
+ */
+ *nh_ret = nhop_get_nhop(nh, &error);
return (error);
}
/*
- * Gets linked nhop using the provided @pnh_priv nexhop data.
+ * Gets linked nhop using the provided @nh nexhop data.
* If linked nhop is found, returns it, freeing the provided one.
* If there is no such nexthop, attaches the remaining data to the
* provided nexthop and links it.
*
- * Returns 0 on success, storing referenced nexthop in @pnh_priv.
+ * Returns 0 on success, storing referenced nexthop in @pnh.
* Otherwise, errno is returned.
*/
-static int
-get_nhop(struct rib_head *rnh, struct rt_addrinfo *info,
- struct nhop_priv **pnh_priv)
+struct nhop_object *
+nhop_get_nhop(struct nhop_object *nh, int *perror)
{
- const struct sockaddr *dst, *netmask;
- struct nhop_priv *nh_priv, *tmp_priv;
+ struct nhop_priv *tmp_priv;
int error;
- nh_priv = *pnh_priv;
+ nh->nh_aifp = get_aifp(nh);
- /* Give the protocols chance to augment the request data */
- dst = info->rti_info[RTAX_DST];
- netmask = info->rti_info[RTAX_NETMASK];
+ struct rib_head *rnh = nhop_get_rh(nh);
- error = rnh->rnh_preadd(rnh->rib_fibnum, dst, netmask, nh_priv->nh);
+ /* Give the protocols chance to augment nexthop properties */
+ error = rnh->rnh_augment_nh(rnh->rib_fibnum, nh);
if (error != 0) {
- uma_zfree(nhops_zone, nh_priv->nh);
- return (error);
+ nhop_free(nh);
+ *perror = error;
+ return (NULL);
}
- tmp_priv = find_nhop(rnh->nh_control, nh_priv);
+ tmp_priv = find_nhop(rnh->nh_control, nh->nh_priv);
if (tmp_priv != NULL) {
- uma_zfree(nhops_zone, nh_priv->nh);
- *pnh_priv = tmp_priv;
- return (0);
+ nhop_free(nh);
+ *perror = 0;
+ return (tmp_priv->nh);
}
/*
* Existing nexthop not found, need to create new one.
- * Note: multiple simultaneous get_nhop() requests
+ * Note: multiple simultaneous requests
* can result in multiple equal nexhops existing in the
* nexthop table. This is not a not a problem until the
* relative number of such nexthops is significant, which
* is extremely unlikely.
*/
-
- error = finalize_nhop(rnh->nh_control, info, nh_priv);
- if (error != 0)
- return (error);
-
- return (0);
+ *perror = finalize_nhop(rnh->nh_control, nh);
+ return (*perror == 0 ? nh : NULL);
}
/*
@@ -413,28 +352,26 @@
* This is a helper function to support route changes.
*
* It limits the changes that can be done to the route to the following:
- * 1) all combination of gateway changes (gw, interface, blackhole/reject)
- * 2) route flags (FLAG[123],STATIC,BLACKHOLE,REJECT)
+ * 1) all combination of gateway changes
+ * 2) route flags (FLAG[123],STATIC)
* 3) route MTU
*
* Returns:
- * 0 on success
+ * 0 on success, errno otherwise
*/
static int
alter_nhop_from_info(struct nhop_object *nh, struct rt_addrinfo *info)
{
- struct nhop_priv *nh_priv = nh->nh_priv;
struct sockaddr *info_gw;
int error;
/* Update MTU if set in the request*/
set_nhop_mtu_from_info(nh, info);
- /* XXX: allow only one of BLACKHOLE,REJECT,GATEWAY */
-
- /* Allow some flags (FLAG1,STATIC,BLACKHOLE,REJECT) to be toggled on change. */
- nh_priv->rt_flags &= ~RTF_FMASK;
- nh_priv->rt_flags |= info->rti_flags & RTF_FMASK;
+ /* Only RTF_FLAG[123] and RTF_STATIC */
+ uint32_t rt_flags = nhop_get_rtflags(nh) & ~RT_CHANGE_RTFLAGS_MASK;
+ rt_flags |= info->rti_flags & RT_CHANGE_RTFLAGS_MASK;
+ nhop_set_rtflags(nh, rt_flags);
/* Consider gateway change */
info_gw = info->rti_info[RTAX_GATEWAY];
@@ -442,22 +379,12 @@
error = set_nhop_gw_from_info(nh, info);
if (error != 0)
return (error);
- if (nh->gw_sa.sa_family == AF_LINK)
- nh_priv->nh_neigh_family = nh_priv->nh_upper_family;
- else
- nh_priv->nh_neigh_family = nh->gw_sa.sa_family;
- /* Update RTF_GATEWAY flag status */
- nh_priv->rt_flags &= ~RTF_GATEWAY;
- nh_priv->rt_flags |= (RTF_GATEWAY & info->rti_flags);
}
- /* Update datapath flags */
- nh->nh_flags = convert_rt_to_nh_flags(nh_priv->rt_flags);
if (info->rti_ifa != NULL)
- nh->nh_ifa = info->rti_ifa;
+ nhop_set_src(nh, info->rti_ifa);
if (info->rti_ifp != NULL)
- nh->nh_ifp = info->rti_ifp;
- nh->nh_aifp = get_aifp(nh);
+ nhop_set_transmit_ifp(nh, info->rti_ifp);
return (0);
}
@@ -475,64 +402,28 @@
nhop_create_from_nhop(struct rib_head *rnh, const struct nhop_object *nh_orig,
struct rt_addrinfo *info, struct nhop_object **pnh)
{
- struct nhop_priv *nh_priv;
struct nhop_object *nh;
int error;
NET_EPOCH_ASSERT();
- nh_priv = alloc_nhop_structure();
- nh = nh_priv->nh;
-
- /* Start with copying data from original nexthop */
- nh_priv->nh_upper_family = nh_orig->nh_priv->nh_upper_family;
- nh_priv->nh_neigh_family = nh_orig->nh_priv->nh_neigh_family;
- nh_priv->rt_flags = nh_orig->nh_priv->rt_flags;
- nh_priv->nh_type = nh_orig->nh_priv->nh_type;
- nh_priv->nh_fibnum = nh_orig->nh_priv->nh_fibnum;
+ nh = nhop_alloc(rnh->rib_fibnum, rnh->rib_family);
+ if (nh == NULL)
+ return (ENOMEM);
- nh->nh_ifp = nh_orig->nh_ifp;
- nh->nh_ifa = nh_orig->nh_ifa;
- nh->nh_aifp = nh_orig->nh_aifp;
- nh->nh_mtu = nh_orig->nh_mtu;
- nh->nh_flags = nh_orig->nh_flags;
- memcpy(&nh->gw_sa, &nh_orig->gw_sa, nh_orig->gw_sa.sa_len);
+ nhop_copy(nh, nh_orig);
error = alter_nhop_from_info(nh, info);
if (error != 0) {
- uma_zfree(nhops_zone, nh_priv->nh);
+ nhop_free(nh);
return (error);
}
- error = get_nhop(rnh, info, &nh_priv);
- if (error == 0)
- *pnh = nh_priv->nh;
+ *pnh = nhop_get_nhop(nh, &error);
return (error);
}
-/*
- * Allocates memory for public/private nexthop structures.
- *
- * Returns pointer to nhop_priv or NULL.
- */
-static struct nhop_priv *
-alloc_nhop_structure(void)
-{
- struct nhop_object *nh;
- struct nhop_priv *nh_priv;
-
- nh = (struct nhop_object *)uma_zalloc(nhops_zone, M_NOWAIT | M_ZERO);
- if (nh == NULL)
- return (NULL);
- nh_priv = (struct nhop_priv *)((char *)nh + NHOP_OBJECT_ALIGNED_SIZE);
-
- nh->nh_priv = nh_priv;
- nh_priv->nh = nh;
-
- return (nh_priv);
-}
-
static bool
reference_nhop_deps(struct nhop_object *nh)
{
@@ -543,7 +434,8 @@
ifa_free(nh->nh_ifa);
return (false);
}
- FIB_NH_LOG(LOG_DEBUG, nh, "AIFP: %p nh_ifp %p", nh->nh_aifp, nh->nh_ifp);
+ FIB_NH_LOG(LOG_DEBUG2, nh, "nh_aifp: %s nh_ifp %s",
+ if_name(nh->nh_aifp), if_name(nh->nh_ifp));
if (!if_try_ref(nh->nh_ifp)) {
ifa_free(nh->nh_ifa);
if_rele(nh->nh_aifp);
@@ -560,15 +452,13 @@
* errno otherwise. @nh_priv is freed in case of error.
*/
static int
-finalize_nhop(struct nh_control *ctl, struct rt_addrinfo *info,
- struct nhop_priv *nh_priv)
+finalize_nhop(struct nh_control *ctl, struct nhop_object *nh)
{
- struct nhop_object *nh = nh_priv->nh;
/* Allocate per-cpu packet counter */
nh->nh_pksent = counter_u64_alloc(M_NOWAIT);
if (nh->nh_pksent == NULL) {
- uma_zfree(nhops_zone, nh);
+ nhop_free(nh);
RTSTAT_INC(rts_nh_alloc_failure);
FIB_NH_LOG(LOG_WARNING, nh, "counter_u64_alloc() failed");
return (ENOMEM);
@@ -576,23 +466,21 @@
if (!reference_nhop_deps(nh)) {
counter_u64_free(nh->nh_pksent);
- uma_zfree(nhops_zone, nh);
+ nhop_free(nh);
RTSTAT_INC(rts_nh_alloc_failure);
FIB_NH_LOG(LOG_WARNING, nh, "interface reference failed");
return (EAGAIN);
}
/* Save vnet to ease destruction */
- nh_priv->nh_vnet = curvnet;
-
- refcount_init(&nh_priv->nh_refcnt, 1);
+ nh->nh_priv->nh_vnet = curvnet;
/* Please see nhop_free() comments on the initial value */
- refcount_init(&nh_priv->nh_linked, 2);
+ refcount_init(&nh->nh_priv->nh_linked, 2);
- nh_priv->nh_fibnum = ctl->ctl_rh->rib_fibnum;
+ nh->nh_priv->nh_fibnum = ctl->ctl_rh->rib_fibnum;
- if (link_nhop(ctl, nh_priv) == 0) {
+ if (link_nhop(ctl, nh->nh_priv) == 0) {
/*
* Adding nexthop to the datastructures
* failed. Call destructor w/o waiting for
@@ -602,7 +490,7 @@
char nhbuf[NHOP_PRINT_BUFSIZE];
FIB_NH_LOG(LOG_WARNING, nh, "failed to link %s",
nhop_print_buf(nh, nhbuf, sizeof(nhbuf)));
- destroy_nhop(nh_priv);
+ destroy_nhop(nh);
return (ENOBUFS);
}
@@ -616,12 +504,8 @@
}
static void
-destroy_nhop(struct nhop_priv *nh_priv)
+destroy_nhop(struct nhop_object *nh)
{
- struct nhop_object *nh;
-
- nh = nh_priv->nh;
-
if_rele(nh->nh_ifp);
if_rele(nh->nh_aifp);
ifa_free(nh->nh_ifa);
@@ -640,7 +524,7 @@
nh_priv = __containerof(ctx, struct nhop_priv, nh_epoch_ctx);
- destroy_nhop(nh_priv);
+ destroy_nhop(nh_priv->nh);
}
void
@@ -669,6 +553,12 @@
if (!refcount_release(&nh_priv->nh_refcnt))
return;
+ /* allows to use nhop_free() during nhop init */
+ if (__predict_false(nh_priv->nh_finalized == 0)) {
+ uma_zfree(nhops_zone, nh);
+ return;
+ }
+
#if DEBUG_MAX_LEVEL >= LOG_DEBUG
char nhbuf[NHOP_PRINT_BUFSIZE];
FIB_NH_LOG(LOG_DEBUG, nh, "deleting %s", nhop_print_buf(nh, nhbuf, sizeof(nhbuf)));
@@ -738,7 +628,144 @@
#endif
}
-/* Helper functions */
+/* Nhop-related methods */
+
+/*
+ * Allocates an empty unlinked nhop object.
+ * Returns object pointer or NULL on failure
+ */
+struct nhop_object *
+nhop_alloc(uint32_t fibnum, int family)
+{
+ struct nhop_object *nh;
+ struct nhop_priv *nh_priv;
+
+ nh = (struct nhop_object *)uma_zalloc(nhops_zone, M_NOWAIT | M_ZERO);
+ if (__predict_false(nh == NULL))
+ return (NULL);
+
+ nh_priv = (struct nhop_priv *)((char *)nh + NHOP_OBJECT_ALIGNED_SIZE);
+ nh->nh_priv = nh_priv;
+ nh_priv->nh = nh;
+
+ nh_priv->nh_upper_family = family;
+ nh_priv->nh_fibnum = fibnum;
+
+ /* Setup refcount early to allow nhop_free() to work */
+ refcount_init(&nh_priv->nh_refcnt, 1);
+
+ return (nh);
+}
+
+void
+nhop_copy(struct nhop_object *nh, const struct nhop_object *nh_orig)
+{
+ struct nhop_priv *nh_priv = nh->nh_priv;
+
+ nh->nh_flags = nh_orig->nh_flags;
+ nh->nh_mtu = nh_orig->nh_mtu;
+ memcpy(&nh->gw_sa, &nh_orig->gw_sa, nh_orig->gw_sa.sa_len);
+ nh->nh_ifp = nh_orig->nh_ifp;
+ nh->nh_ifa = nh_orig->nh_ifa;
+ nh->nh_aifp = nh_orig->nh_aifp;
+
+ nh_priv->nh_upper_family = nh_orig->nh_priv->nh_upper_family;
+ nh_priv->nh_neigh_family = nh_orig->nh_priv->nh_neigh_family;
+ nh_priv->nh_type = nh_orig->nh_priv->nh_type;
+ nh_priv->rt_flags = nh_orig->nh_priv->rt_flags;
+ nh_priv->nh_fibnum = nh_orig->nh_priv->nh_fibnum;
+}
+
+void
+nhop_set_direct_gw(struct nhop_object *nh, struct ifnet *ifp)
+{
+ nh->nh_flags &= ~NHF_GATEWAY;
+ nh->nh_priv->rt_flags &= ~RTF_GATEWAY;
+ nh->nh_priv->nh_neigh_family = nh->nh_priv->nh_upper_family;
+
+ 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);
+}
+
+/*
+ * Sets gateway for the nexthop.
+ * It can be "normal" gateway with is_gw set or a special form of
+ * adding interface route, refering to it by specifying local interface
+ * address. In that case is_gw is set to false.
+ */
+bool
+nhop_set_gw(struct nhop_object *nh, const struct sockaddr *gw, bool is_gw)
+{
+ if (gw->sa_len > sizeof(nh->gw_buf)) {
+ FIB_NH_LOG(LOG_DEBUG, nh, "nhop SA size too big: AF %d len %u",
+ gw->sa_family, gw->sa_len);
+ 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);
+
+ if (is_gw) {
+ nh->nh_flags |= NHF_GATEWAY;
+ nh->nh_priv->rt_flags |= RTF_GATEWAY;
+ nh->nh_priv->nh_neigh_family = gw->sa_family;
+ } else {
+ nh->nh_flags &= ~NHF_GATEWAY;
+ nh->nh_priv->rt_flags &= ~RTF_GATEWAY;
+ nh->nh_priv->nh_neigh_family = nh->nh_priv->nh_upper_family;
+ }
+
+ return (true);
+}
+
+void
+nhop_set_broadcast(struct nhop_object *nh, bool is_broadcast)
+{
+ if (is_broadcast) {
+ nh->nh_flags |= NHF_BROADCAST;
+ nh->nh_priv->rt_flags |= RTF_BROADCAST;
+ } else {
+ nh->nh_flags &= ~NHF_BROADCAST;
+ nh->nh_priv->rt_flags &= ~RTF_BROADCAST;
+ }
+}
+
+void
+nhop_set_blackhole(struct nhop_object *nh, int blackhole_rt_flag)
+{
+ nh->nh_flags &= ~(NHF_BLACKHOLE | NHF_REJECT);
+ nh->nh_priv->rt_flags &= ~(RTF_BLACKHOLE | RTF_REJECT);
+ switch (blackhole_rt_flag) {
+ case RTF_BLACKHOLE:
+ nh->nh_flags |= NHF_BLACKHOLE;
+ nh->nh_priv->rt_flags |= RTF_BLACKHOLE;
+ break;
+ case RTF_REJECT:
+ nh->nh_flags |= NHF_REJECT;
+ nh->nh_priv->rt_flags |= RTF_REJECT;
+ break;
+ }
+}
+
+void
+nhop_set_redirect(struct nhop_object *nh, bool is_redirect)
+{
+ if (is_redirect) {
+ nh->nh_priv->rt_flags |= RTF_DYNAMIC;
+ nh->nh_flags |= NHF_REDIRECT;
+ } else {
+ nh->nh_priv->rt_flags &= ~RTF_DYNAMIC;
+ nh->nh_flags &= ~NHF_REDIRECT;
+ }
+}
+
+void
+nhop_set_pinned(struct nhop_object *nh, bool is_pinned)
+{
+ if (is_pinned)
+ nh->nh_priv->rt_flags |= RTF_PINNED;
+ else
+ nh->nh_priv->rt_flags &= ~RTF_PINNED;
+}
uint32_t
nhop_get_idx(const struct nhop_object *nh)
@@ -768,13 +795,65 @@
return (nh->nh_priv->rt_flags);
}
+/*
+ * Sets generic rtflags that are not covered by other functions.
+ */
void
nhop_set_rtflags(struct nhop_object *nh, int rt_flags)
{
+ nh->nh_priv->rt_flags &= ~RT_SET_RTFLAGS_MASK;
+ nh->nh_priv->rt_flags |= (rt_flags & RT_SET_RTFLAGS_MASK);
+}
- nh->nh_priv->rt_flags = rt_flags;
+/*
+ * Sets flags that are specific to the prefix (NHF_HOST or NHF_DEFAULT).
+ */
+void
+nhop_set_pxtype_flag(struct nhop_object *nh, int nh_flag)
+{
+ if (nh_flag == NHF_HOST) {
+ nh->nh_flags |= NHF_HOST;
+ nh->nh_flags &= ~NHF_DEFAULT;
+ nh->nh_priv->rt_flags |= RTF_HOST;
+ } else if (nh_flag == NHF_DEFAULT) {
+ nh->nh_flags |= NHF_DEFAULT;
+ nh->nh_flags &= ~NHF_HOST;
+ nh->nh_priv->rt_flags &= ~RTF_HOST;
+ } else {
+ nh->nh_flags &= ~(NHF_HOST | NHF_DEFAULT);
+ nh->nh_priv->rt_flags &= ~RTF_HOST;
+ }
+}
+
+/*
+ * Sets nhop MTU. Sets RTF_FIXEDMTU if mtu is explicitly
+ * specified by userland.
+ */
+void
+nhop_set_mtu(struct nhop_object *nh, uint32_t mtu, bool from_user)
+{
+ if (from_user) {
+ if (mtu != 0)
+ nh->nh_priv->rt_flags |= RTF_FIXEDMTU;
+ else
+ nh->nh_priv->rt_flags &= ~RTF_FIXEDMTU;
+ }
+ nh->nh_mtu = mtu;
}
+void
+nhop_set_src(struct nhop_object *nh, struct ifaddr *ifa)
+{
+ nh->nh_ifa = ifa;
+}
+
+void
+nhop_set_transmit_ifp(struct nhop_object *nh, struct ifnet *ifp)
+{
+ nh->nh_ifp = ifp;
+}
+
+
struct vnet *
nhop_get_vnet(const struct nhop_object *nh)
{
@@ -827,6 +906,15 @@
nh->nh_priv->nh_expire = expire;
}
+static struct rib_head *
+nhop_get_rh(const struct nhop_object *nh)
+{
+ uint32_t fibnum = nhop_get_fibnum(nh);
+ int family = nhop_get_neigh_family(nh);
+
+ return (rt_tables_get_rnh(fibnum, family));
+}
+
void
nhops_update_ifmtu(struct rib_head *rh, struct ifnet *ifp, uint32_t mtu)
{
diff --git a/sys/net/route/nhop_var.h b/sys/net/route/nhop_var.h
--- a/sys/net/route/nhop_var.h
+++ b/sys/net/route/nhop_var.h
@@ -85,6 +85,7 @@
void *cb_func; /* function handling additional rewrite caps */
u_int nh_refcnt; /* number of references, refcount(9) */
u_int nh_linked; /* refcount(9), == 2 if linked to the list */
+ int nh_finalized; /* non-zero if finalized() was called */
struct nhop_object *nh; /* backreference to the dataplane nhop */
struct nh_control *nh_control; /* backreference to the rnh */
struct nhop_priv *nh_next; /* hash table membership */
diff --git a/sys/net/route/route_var.h b/sys/net/route/route_var.h
--- a/sys/net/route/route_var.h
+++ b/sys/net/route/route_var.h
@@ -48,8 +48,11 @@
#endif
struct nh_control;
-typedef int rnh_preadd_entry_f_t(u_int fibnum, const struct sockaddr *addr,
+/* Sets prefix-specific nexthop flags (NHF_DEFAULT, RTF/NHF_HOST, RTF_BROADCAST,..) */
+typedef int rnh_set_nh_pfxflags_f_t(u_int fibnum, const struct sockaddr *addr,
const struct sockaddr *mask, struct nhop_object *nh);
+/* Fills in family-specific details that are not yet set up (mtu, nhop type, ..) */
+typedef int rnh_augment_nh_f_t(u_int fibnum, struct nhop_object *nh);
struct rib_head {
struct radix_head head;
@@ -59,7 +62,7 @@
rn_lookup_f_t *rnh_lookup; /* exact match for sockaddr */
rn_walktree_t *rnh_walktree; /* traverse tree */
rn_walktree_from_t *rnh_walktree_from; /* traverse tree below a */
- rnh_preadd_entry_f_t *rnh_preadd; /* hook to alter record prior to insertion */
+ rnh_set_nh_pfxflags_f_t *rnh_set_nh_pfxflags; /* hook to alter record prior to insertion */
rt_gen_t rnh_gen; /* datapath generation counter */
int rnh_multipath; /* multipath capable ? */
struct radix_node rnh_nodes[3]; /* empty tree for common case */
@@ -76,6 +79,7 @@
uint32_t rib_algo_fixed:1;/* fixed algorithm */
uint32_t rib_algo_init:1;/* algo init done */
struct nh_control *nh_control; /* nexthop subsystem data */
+ rnh_augment_nh_f_t *rnh_augment_nh;/* hook to alter nexthop prior to insertion */
CK_STAILQ_HEAD(, rib_subscription) rnh_subscribers;/* notification subscribers */
};
@@ -204,11 +208,6 @@
* RTF_PINNED, RTF_REJECT, RTF_BLACKHOLE, RTF_BROADCAST
*/
-/* Nexthop rt flags mask */
-#define NHOP_RT_FLAG_MASK (RTF_GATEWAY | RTF_HOST | RTF_REJECT | RTF_DYNAMIC | \
- RTF_MODIFIED | RTF_STATIC | RTF_BLACKHOLE | RTF_PROTO1 | RTF_PROTO2 | \
- RTF_PROTO3 | RTF_FIXEDMTU | RTF_PINNED | RTF_BROADCAST)
-
/* rtentry rt flag mask */
#define RTE_RT_FLAG_MASK (RTF_UP | RTF_HOST)
@@ -250,8 +249,6 @@
void nhop_ref_any(struct nhop_object *nh);
void nhop_free_any(struct nhop_object *nh);
-void nhop_set_type(struct nhop_object *nh, enum nhop_type nh_type);
-void nhop_set_rtflags(struct nhop_object *nh, int rt_flags);
int nhop_create_from_info(struct rib_head *rnh, struct rt_addrinfo *info,
struct nhop_object **nh_ret);
diff --git a/sys/netinet/in_rmx.c b/sys/netinet/in_rmx.c
--- a/sys/netinet/in_rmx.c
+++ b/sys/netinet/in_rmx.c
@@ -52,18 +52,15 @@
#include <netinet/ip_var.h>
static int
-rib4_preadd(u_int fibnum, const struct sockaddr *addr, const struct sockaddr *mask,
+rib4_set_nh_pfxflags(u_int fibnum, const struct sockaddr *addr, const struct sockaddr *mask,
struct nhop_object *nh)
{
const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr;
- uint16_t nh_type;
- int rt_flags;
-
- /* XXX: RTF_LOCAL && RTF_MULTICAST */
-
- rt_flags = nhop_get_rtflags(nh);
+ const struct sockaddr_in *mask4 = (const struct sockaddr_in *)mask;
+ bool is_broadcast = false;
- if (rt_flags & RTF_HOST) {
+ if (mask == NULL) {
+ nhop_set_pxtype_flag(nh, NHF_HOST);
/*
* Backward compatibility:
* if the destination is broadcast,
@@ -76,13 +73,21 @@
* add these routes to support some cases with active-active
* load balancing. Given that, retain this support.
*/
- if (in_broadcast(addr4->sin_addr, nh->nh_ifp)) {
- rt_flags |= RTF_BROADCAST;
- nhop_set_rtflags(nh, rt_flags);
- nh->nh_flags |= NHF_BROADCAST;
- }
- }
+ if (in_broadcast(addr4->sin_addr, nh->nh_ifp))
+ is_broadcast = true;
+ } else if (mask4->sin_addr.s_addr == 0)
+ nhop_set_pxtype_flag(nh, NHF_DEFAULT);
+ else
+ nhop_set_pxtype_flag(nh, 0);
+
+ nhop_set_broadcast(nh, is_broadcast);
+
+ return (0);
+}
+static int
+rib4_augment_nh(u_int fibnum, struct nhop_object *nh)
+{
/*
* Check route MTU:
* inherit interface MTU if not set or
@@ -93,14 +98,9 @@
} else if (nh->nh_mtu > nh->nh_ifp->if_mtu)
nh->nh_mtu = nh->nh_ifp->if_mtu;
- /* Ensure that default route nhop has special flag */
- const struct sockaddr_in *mask4 = (const struct sockaddr_in *)mask;
- if ((rt_flags & RTF_HOST) == 0 && mask4 != NULL &&
- mask4->sin_addr.s_addr == 0)
- nh->nh_flags |= NHF_DEFAULT;
-
/* Set nhop type to basic per-AF nhop */
if (nhop_get_type(nh) == 0) {
+ uint16_t nh_type;
if (nh->nh_flags & NHF_GATEWAY)
nh_type = NH_TYPE_IPV4_ETHER_NHOP;
else
@@ -124,7 +124,8 @@
if (rh == NULL)
return (NULL);
- rh->rnh_preadd = rib4_preadd;
+ rh->rnh_set_nh_pfxflags = rib4_set_nh_pfxflags;
+ rh->rnh_augment_nh = rib4_augment_nh;
return (rh);
}
diff --git a/sys/netinet6/in6_rmx.c b/sys/netinet6/in6_rmx.c
--- a/sys/netinet6/in6_rmx.c
+++ b/sys/netinet6/in6_rmx.c
@@ -94,13 +94,24 @@
#include <netinet6/nd6.h>
static int
-rib6_preadd(u_int fibnum, const struct sockaddr *addr, const struct sockaddr *mask,
+rib6_set_nh_pfxflags(u_int fibnum, const struct sockaddr *addr, const struct sockaddr *mask,
struct nhop_object *nh)
{
- uint16_t nh_type;
+ const struct sockaddr_in6 *mask6 = (const struct sockaddr_in6 *)mask;
+
+ if (mask6 == NULL)
+ nhop_set_pxtype_flag(nh, NHF_HOST);
+ else if (IN6_IS_ADDR_UNSPECIFIED(&mask6->sin6_addr))
+ nhop_set_pxtype_flag(nh, NHF_DEFAULT);
+ else
+ nhop_set_pxtype_flag(nh, 0);
- /* XXX: RTF_LOCAL */
+ return (0);
+}
+static int
+rib6_augment_nh(u_int fibnum, struct nhop_object *nh)
+{
/*
* Check route MTU:
* inherit interface MTU if not set or
@@ -111,14 +122,9 @@
} else if (nh->nh_mtu > IN6_LINKMTU(nh->nh_ifp))
nh->nh_mtu = IN6_LINKMTU(nh->nh_ifp);
- /* Ensure that default route nhop has special flag */
- const struct sockaddr_in6 *mask6 = (const struct sockaddr_in6 *)mask;
- if ((nhop_get_rtflags(nh) & RTF_HOST) == 0 && mask6 != NULL &&
- IN6_IS_ADDR_UNSPECIFIED(&mask6->sin6_addr))
- nh->nh_flags |= NHF_DEFAULT;
-
/* Set nexthop type */
if (nhop_get_type(nh) == 0) {
+ uint16_t nh_type;
if (nh->nh_flags & NHF_GATEWAY)
nh_type = NH_TYPE_IPV6_ETHER_NHOP;
else
@@ -145,7 +151,8 @@
if (rh == NULL)
return (NULL);
- rh->rnh_preadd = rib6_preadd;
+ rh->rnh_set_nh_pfxflags = rib6_set_nh_pfxflags;
+ rh->rnh_augment_nh = rib6_augment_nh;
rs = rib_subscribe_internal(rh, nd6_subscription_cb, NULL,
RIB_NOTIFY_IMMEDIATE, true);
diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c
--- a/sys/netinet6/nd6_rtr.c
+++ b/sys/netinet6/nd6_rtr.c
@@ -2042,6 +2042,7 @@
struct rt_addrinfo info = {
.rti_ifa = ifa,
+ .rti_ifp = ifp,
.rti_flags = RTF_PINNED | ((netmask != NULL) ? 0 : RTF_HOST),
.rti_info = {
[RTAX_DST] = (struct sockaddr *)dst,
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Jan 28, 4:39 AM (9 h, 27 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16248838
Default Alt Text
D35985.diff (29 KB)
Attached To
Mode
D35985: routing: add nhop(9) kpi.
Attached
Detach File
Event Timeline
Log In to Comment