git: c9b6853febc5 - stable/13 - routing: move route expiration time to its nexthop

From: Alexander V. Chernikov <melifaro_at_FreeBSD.org>
Date: Fri, 13 Jan 2023 21:24:52 UTC
The branch stable/13 has been updated by melifaro:

URL: https://cgit.FreeBSD.org/src/commit/?id=c9b6853febc5f9f4913786d6d3c9c95a8836eec6

commit c9b6853febc5f9f4913786d6d3c9c95a8836eec6
Author:     Alexander V. Chernikov <melifaro@FreeBSD.org>
AuthorDate: 2022-07-28 12:18:19 +0000
Commit:     Alexander V. Chernikov <melifaro@FreeBSD.org>
CommitDate: 2023-01-13 21:18:25 +0000

    routing: move route expiration time to its nexthop
    
    Expiration time is actually a path property, not a route property.
    Move its storage to nexthop to simplify upcoming nhop(9) KPI changes
     and netlink introduction.
    
    Differential Revision: https://reviews.freebsd.org/D35970
    MFC after:      2 weeks
    
    (cherry picked from commit 2717e958df537b2885fdf42635d7b9dc793719b2)
---
 sys/net/route/nhop.h           |  2 ++
 sys/net/route/nhop_ctl.c       | 25 +++++++++++++++++++++++++
 sys/net/route/nhop_var.h       |  2 ++
 sys/net/route/route_ctl.c      | 23 +++++------------------
 sys/net/route/route_temporal.c | 20 +++++++++++---------
 sys/net/route/route_var.h      |  3 +--
 sys/net/rtsock.c               |  4 ++--
 7 files changed, 48 insertions(+), 31 deletions(-)

diff --git a/sys/net/route/nhop.h b/sys/net/route/nhop.h
index 12bbe163788f..985e4c32ccd3 100644
--- a/sys/net/route/nhop.h
+++ b/sys/net/route/nhop.h
@@ -183,6 +183,8 @@ struct nhop_object *nhop_select_func(struct nhop_object *nh, uint32_t flowid);
 int nhop_get_upper_family(const struct nhop_object *nh);
 int nhop_get_neigh_family(const struct nhop_object *nh);
 uint32_t nhop_get_fibnum(const struct nhop_object *nh);
+uint32_t nhop_get_expire(const struct nhop_object *nh);
+void nhop_set_expire(struct nhop_object *nh, uint32_t expire);
 
 #endif /* _KERNEL */
 
diff --git a/sys/net/route/nhop_ctl.c b/sys/net/route/nhop_ctl.c
index 4bf7bfb1b416..9f612e354fa6 100644
--- a/sys/net/route/nhop_ctl.c
+++ b/sys/net/route/nhop_ctl.c
@@ -272,6 +272,17 @@ convert_rt_to_nh_flags(int rt_flags)
 	return (res);
 }
 
+static void
+set_nhop_expire_from_info(struct nhop_object *nh, const struct rt_addrinfo *info)
+{
+	uint32_t nh_expire = 0;
+
+	/* Kernel -> userland timebase conversion. */
+	if ((info->rti_mflags & RTV_EXPIRE) && (info->rti_rmx->rmx_expire > 0))
+		nh_expire = info->rti_rmx->rmx_expire - time_second + time_uptime;
+	nhop_set_expire(nh, nh_expire);
+}
+
 static int
 fill_nhop_from_info(struct nhop_priv *nh_priv, struct rt_addrinfo *info)
 {
@@ -294,6 +305,7 @@ fill_nhop_from_info(struct nhop_priv *nh_priv, struct rt_addrinfo *info)
 		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;
@@ -802,6 +814,19 @@ nhop_get_fibnum(const struct nhop_object *nh)
 	return (nh->nh_priv->nh_fibnum);
 }
 
+uint32_t
+nhop_get_expire(const struct nhop_object *nh)
+{
+	return (nh->nh_priv->nh_expire);
+}
+
+void
+nhop_set_expire(struct nhop_object *nh, uint32_t expire)
+{
+	MPASS(!NH_IS_LINKED(nh));
+	nh->nh_priv->nh_expire = expire;
+}
+
 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
index facf8a7a546b..516032cd3756 100644
--- a/sys/net/route/nhop_var.h
+++ b/sys/net/route/nhop_var.h
@@ -78,6 +78,7 @@ struct nhop_priv {
 	uint8_t			nh_neigh_family;/* neighbor address family */
 	uint16_t		nh_type;	/* nexthop type */
 	uint32_t		rt_flags;	/* routing flags for the control plane */
+	uint32_t		nh_expire;	/* path expiration time */
 	/* nhop lookup comparison end */
 	uint32_t		nh_idx;		/* nexthop index */
 	uint32_t		nh_fibnum;	/* nexthop fib */
@@ -95,6 +96,7 @@ struct nhop_priv {
 
 #define	NH_IS_PINNED(_nh)	((!NH_IS_NHGRP(_nh)) && \
 				((_nh)->nh_priv->rt_flags & RTF_PINNED))
+#define	NH_IS_LINKED(_nh)	((_nh)->nh_priv->nh_idx != 0)
 
 /* nhop.c */
 struct nhop_priv *find_nhop(struct nh_control *ctl,
diff --git a/sys/net/route/route_ctl.c b/sys/net/route/route_ctl.c
index f8b6a6eb4cd0..1127c504400e 100644
--- a/sys/net/route/route_ctl.c
+++ b/sys/net/route/route_ctl.c
@@ -416,16 +416,6 @@ rt_get_inet6_prefix_pmask(const struct rtentry *rt, struct in6_addr *paddr,
 }
 #endif
 
-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.
  *
@@ -702,7 +692,6 @@ create_rtentry(struct rib_head *rnh, struct rt_addrinfo *info,
 	 * examine the ifa and  ifa->ifa_ifp if it so desires.
 	 */
 	rt->rt_weight = get_info_weight(info, RT_DEFAULT_WEIGHT);
-	rt_set_expire_info(rt, info);
 
 	*prt = rt;
 	return (0);
@@ -1112,8 +1101,8 @@ add_route_nhop(struct rib_head *rnh, struct rtentry *rt,
 	rn = rnh->rnh_addaddr(ndst, netmask, &rnh->head, rt->rt_nodes);
 
 	if (rn != NULL) {
-		if (rt->rt_expire > 0)
-			tmproutes_update(rnh, rt);
+		if (!NH_IS_NHGRP(rnd->rnd_nhop) && nhop_get_expire(rnd->rnd_nhop))
+			tmproutes_update(rnh, rt, rnd->rnd_nhop);
 
 		/* Finalize notification */
 		rib_bump_gen(rnh);
@@ -1136,7 +1125,6 @@ add_route_nhop(struct rib_head *rnh, struct rtentry *rt,
 
 /*
  * Switch @rt nhop/weigh to the ones specified in @rnd.
- *  Conditionally set rt_expire if set in @info.
  * Returns 0 on success.
  */
 int
@@ -1151,12 +1139,11 @@ change_route_nhop(struct rib_head *rnh, struct rtentry *rt,
 	nh_orig = rt->rt_nhop;
 
 	if (rnd->rnd_nhop != NULL) {
-		/* Changing expiration & nexthop & weight to a new one */
-		rt_set_expire_info(rt, info);
+		/* Changing nexthop & weight to a new one */
 		rt->rt_nhop = rnd->rnd_nhop;
 		rt->rt_weight = rnd->rnd_weight;
-		if (rt->rt_expire > 0)
-			tmproutes_update(rnh, rt);
+		if (!NH_IS_NHGRP(rnd->rnd_nhop) && nhop_get_expire(rnd->rnd_nhop))
+			tmproutes_update(rnh, rt, rnd->rnd_nhop);
 	} else {
 		/* Route deletion requested. */
 		struct sockaddr *ndst, *netmask;
diff --git a/sys/net/route/route_temporal.c b/sys/net/route/route_temporal.c
index 935b110db629..edb8ab769bbe 100644
--- a/sys/net/route/route_temporal.c
+++ b/sys/net/route/route_temporal.c
@@ -55,12 +55,13 @@ __FBSDID("$FreeBSD$");
 static int
 expire_route(const struct rtentry *rt, const struct nhop_object *nh, void *arg)
 {
+	uint32_t nh_expire = nhop_get_expire(nh);
 	time_t *next_callout;
 
-	if (rt->rt_expire == 0)
+	if (nh_expire == 0)
 		return (0);
 
-	if (rt->rt_expire <= time_uptime)
+	if (nh_expire <= time_uptime)
 		return (1);
 
 	next_callout = (time_t *)arg;
@@ -69,8 +70,8 @@ expire_route(const struct rtentry *rt, const struct nhop_object *nh, void *arg)
 	 * Update next_callout to determine the next ts to
 	 * run the callback at.
 	 */
-	if (*next_callout == 0 || *next_callout > rt->rt_expire)
-		*next_callout = rt->rt_expire;
+	if (*next_callout == 0 || *next_callout > nh_expire)
+		*next_callout = nh_expire;
 
 	return (0);
 }
@@ -78,7 +79,7 @@ expire_route(const struct rtentry *rt, const struct nhop_object *nh, void *arg)
 /*
  * Per-rnh callout function traversing the tree and deleting
  * expired routes. Calculates next callout run by looking at
- * the rt_expire time for the remaining temporal routes.
+ * the nh_expire time for the remaining temporal routes.
  */
 static void
 expire_callout(void *arg)
@@ -123,26 +124,27 @@ expire_callout(void *arg)
  * to the tree. RIB_WLOCK must be held.
  */
 void
-tmproutes_update(struct rib_head *rnh, struct rtentry *rt)
+tmproutes_update(struct rib_head *rnh, struct rtentry *rt, struct nhop_object *nh)
 {
 	int seconds;
+	uint32_t nh_expire = nhop_get_expire(nh);
 
 	RIB_WLOCK_ASSERT(rnh);
 
-	if (rnh->next_expire == 0 || rnh->next_expire > rt->rt_expire) {
+	if (rnh->next_expire == 0 || rnh->next_expire > nh_expire) {
 		/*
 		 * Callback is not scheduled, is executing,
 		 * or is scheduled for a later time than we need.
 		 *
 		 * Schedule the one for the current @rt expiration time.
 		 */
-		seconds = (rt->rt_expire - time_uptime);
+		seconds = (nh_expire - time_uptime);
 		if (seconds < 0)
 			seconds = 0;
 		callout_reset_sbt(&rnh->expire_callout, SBT_1S * seconds,
 		    SBT_1MS * 500, expire_callout, rnh, 0);
 
-		rnh->next_expire = rt->rt_expire;
+		rnh->next_expire = nh_expire;
 	}
 }
 
diff --git a/sys/net/route/route_var.h b/sys/net/route/route_var.h
index b29b79c88864..60891026c00a 100644
--- a/sys/net/route/route_var.h
+++ b/sys/net/route/route_var.h
@@ -183,7 +183,6 @@ struct rtentry {
 
 	int		rte_flags;	/* up/down?, host/net */
 	u_long		rt_weight;	/* absolute weight */ 
-	u_long		rt_expire;	/* lifetime for route, e.g. redirect */
 	struct rtentry	*rt_chain;	/* pointer to next rtentry to delete */
 	struct epoch_context	rt_epoch_ctx;	/* net epoch tracker */
 };
@@ -214,7 +213,7 @@ struct rtentry {
 #define	RTE_RT_FLAG_MASK	(RTF_UP | RTF_HOST)
 
 /* route_temporal.c */
-void tmproutes_update(struct rib_head *rnh, struct rtentry *rt);
+void tmproutes_update(struct rib_head *rnh, struct rtentry *rt, struct nhop_object *nh);
 void tmproutes_init(struct rib_head *rh);
 void tmproutes_destroy(struct rib_head *rh);
 
diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c
index 5011ab37030e..b116319d96d6 100644
--- a/sys/net/rtsock.c
+++ b/sys/net/rtsock.c
@@ -1293,8 +1293,8 @@ rt_getmetrics(const struct rtentry *rt, const struct nhop_object *nh,
 	out->rmx_weight = rt->rt_weight;
 	out->rmx_nhidx = nhop_get_idx(nh);
 	/* Kernel -> userland timebase conversion. */
-	out->rmx_expire = rt->rt_expire ?
-	    rt->rt_expire - time_uptime + time_second : 0;
+	out->rmx_expire = nhop_get_expire(nh) ?
+	    nhop_get_expire(nh) - time_uptime + time_second : 0;
 }
 
 /*