svn commit: r361708 - head/sys/net/route

Alexander V. Chernikov melifaro at FreeBSD.org
Mon Jun 1 21:52:25 UTC 2020


Author: melifaro
Date: Mon Jun  1 21:52:24 2020
New Revision: 361708
URL: https://svnweb.freebsd.org/changeset/base/361708

Log:
  Add rib subscription API.
  
  Currently there is no easy way of subscribing for the routing table changes.
  The only existing way is to set ifa_rtrequest callback in the each protocol
   ifaddr, which is not convenient or extandable.
  
  This change provides generic notification subscription mechanism, that will
   replace current ifa_rtrequest one and allow other applications such as
   accelerated routing lookup modules subscribe for the changes.
  
  In particular, this change provides 2 hooks: 1) synchronous one
   (RIB_NOTIFY_IMMEDIATE), called under RIB_WLOCK, which ensures exact
   ordering of the changes and 2) async one, (RIB_NOTIFY_DELAYED)
   that is called after the change w/o holding locks. The latter one does not
   provide any notification ordering guarantee.
  
  Differential Revision:  https://reviews.freebsd.org/D25070

Modified:
  head/sys/net/route/route_ctl.c
  head/sys/net/route/route_ctl.h

Modified: head/sys/net/route/route_ctl.c
==============================================================================
--- head/sys/net/route/route_ctl.c	Mon Jun  1 21:51:20 2020	(r361707)
+++ head/sys/net/route/route_ctl.c	Mon Jun  1 21:52:24 2020	(r361708)
@@ -68,10 +68,19 @@ __FBSDID("$FreeBSD$");
  * All functions assumes they are called in net epoch.
  */
 
+struct rib_subscription {
+	CK_STAILQ_ENTRY(rib_subscription)	next;
+	rib_subscription_cb_t			*func;
+	void					*arg;
+	enum rib_subscription_type		type;
+	struct epoch_context			epoch_ctx;
+};
+
 static void rib_notify(struct rib_head *rnh, enum rib_subscription_type type,
     struct rib_cmd_info *rc);
 
 static void rt_notifydelete(struct rtentry *rt, struct rt_addrinfo *info);
+static void destroy_subscription_epoch(epoch_context_t ctx);
 
 static struct rib_head *
 get_rnh(uint32_t fibnum, const struct rt_addrinfo *info)
@@ -263,6 +272,9 @@ add_route(struct rib_head *rnh, struct rt_addrinfo *in
 	}
 	RIB_WUNLOCK(rnh);
 
+	if ((rn != NULL) || (rt_old != NULL))
+		rib_notify(rnh, RIB_NOTIFY_DELAYED, rc);
+
 	if (rt_old != NULL) {
 		rt_notifydelete(rt_old, info);
 		rtfree(rt_old);
@@ -419,6 +431,7 @@ del_route(struct rib_head *rnh, struct rt_addrinfo *in
 	if (error != 0)
 		return (error);
 
+	rib_notify(rnh, RIB_NOTIFY_DELAYED, rc);
 	rt_notifydelete(rt, info);
 
 	/*
@@ -559,11 +572,12 @@ change_route_one(struct rib_head *rnh, struct rt_addri
 
 	/* Update generation id to reflect rtable change */
 	rnh->rnh_gen++;
-
 	rib_notify(rnh, RIB_NOTIFY_IMMEDIATE, rc);
 
 	RIB_WUNLOCK(rnh);
 
+	rib_notify(rnh, RIB_NOTIFY_DELAYED, rc);
+
 	nhop_free(nh_orig);
 
 	return (0);
@@ -614,6 +628,7 @@ struct rt_delinfo
 	struct rt_addrinfo info;
 	struct rib_head *rnh;
 	struct rtentry *head;
+	struct rib_cmd_info rc;
 };
 
 /*
@@ -643,7 +658,13 @@ rt_checkdelroute(struct radix_node *rn, void *arg)
 		return (0);
 	}
 
-	/* Entry was unlinked. Add to the list and return */
+	/* Entry was unlinked. Notify subscribers */
+	di->rnh->rnh_gen++;
+	di->rc.rc_rt = rt;
+	di->rc.rc_nh_old = rt->rt_nhop;
+	rib_notify(di->rnh, RIB_NOTIFY_IMMEDIATE, &di->rc);
+
+	/* Add to the list and return */
 	rt->rt_chain = di->head;
 	di->head = rt;
 
@@ -665,6 +686,7 @@ rib_walk_del(u_int fibnum, int family, rt_filter_f_t *
 	struct rib_head *rnh;
 	struct rt_delinfo di;
 	struct rtentry *rt;
+	struct epoch_tracker et;
 
 	rnh = rt_tables_get_rnh(fibnum, family);
 	if (rnh == NULL)
@@ -674,20 +696,24 @@ rib_walk_del(u_int fibnum, int family, rt_filter_f_t *
 	di.info.rti_filter = filter_f;
 	di.info.rti_filterdata = arg;
 	di.rnh = rnh;
+	di.rc.rc_cmd = RTM_DELETE;
 
+	NET_EPOCH_ENTER(et);
+
 	RIB_WLOCK(rnh);
 	rnh->rnh_walktree(&rnh->head, rt_checkdelroute, &di);
 	RIB_WUNLOCK(rnh);
 
-	if (di.head == NULL)
-		return;
-
 	/* We might have something to reclaim. */
 	while (di.head != NULL) {
 		rt = di.head;
 		di.head = rt->rt_chain;
 		rt->rt_chain = NULL;
 
+		di.rc.rc_rt = rt;
+		di.rc.rc_nh_old = rt->rt_nhop;
+		rib_notify(rnh, RIB_NOTIFY_DELAYED, &di.rc);
+
 		/* TODO std rt -> rt_addrinfo export */
 		di.info.rti_info[RTAX_DST] = rt_key(rt);
 		di.info.rti_info[RTAX_NETMASK] = rt_mask(rt);
@@ -699,6 +725,8 @@ rib_walk_del(u_int fibnum, int family, rt_filter_f_t *
 			    fibnum);
 		rtfree(rt);
 	}
+
+	NET_EPOCH_EXIT(et);
 }
 
 static void
@@ -713,6 +741,13 @@ rib_notify(struct rib_head *rnh, enum rib_subscription
 	}
 }
 
+/*
+ * Subscribe for the changes in the routing table specified by @fibnum and
+ *  @family.
+ * Needs to be run in network epoch.
+ *
+ * Returns pointer to the subscription structure on success.
+ */
 struct rib_subscription *
 rib_subscribe(uint32_t fibnum, int family, rib_subscription_cb_t *f, void *arg,
     enum rib_subscription_type type, int waitok)
@@ -740,6 +775,13 @@ rib_subscribe(uint32_t fibnum, int family, rib_subscri
 	return (rs);
 }
 
+/*
+ * Remove rtable subscription @rs from the table specified by @fibnum
+ *  and @family.
+ * Needs to be run in network epoch.
+ *
+ * Returns 0 on success.
+ */
 int
 rib_unsibscribe(uint32_t fibnum, int family, struct rib_subscription *rs)
 {
@@ -756,7 +798,21 @@ rib_unsibscribe(uint32_t fibnum, int family, struct ri
 	CK_STAILQ_REMOVE(&rnh->rnh_subscribers, rs, rib_subscription, next);
 	RIB_WUNLOCK(rnh);
 
-	free(rs, M_RTABLE);
+	epoch_call(net_epoch_preempt, destroy_subscription_epoch,
+	    &rs->epoch_ctx);
+
 	return (0);
 }
 
+/*
+ * Epoch callback indicating subscription is safe to destroy
+ */
+static void
+destroy_subscription_epoch(epoch_context_t ctx)
+{
+	struct rib_subscription *rs;
+
+	rs = __containerof(ctx, struct rib_subscription, epoch_ctx);
+
+	free(rs, M_RTABLE);
+}

Modified: head/sys/net/route/route_ctl.h
==============================================================================
--- head/sys/net/route/route_ctl.h	Mon Jun  1 21:51:20 2020	(r361707)
+++ head/sys/net/route/route_ctl.h	Mon Jun  1 21:52:24 2020	(r361708)
@@ -64,5 +64,20 @@ void rib_walk_del(u_int fibnum, int family, rt_filter_
 typedef void rt_setwarg_t(struct rib_head *, uint32_t, int, void *);
 void rt_foreach_fib_walk(int af, rt_setwarg_t *, rt_walktree_f_t *, void *);
 void rt_foreach_fib_walk_del(int af, rt_filter_f_t *filter_f, void *arg);
+
+enum rib_subscription_type {
+	RIB_NOTIFY_IMMEDIATE,
+	RIB_NOTIFY_DELAYED
+};
+
+struct rib_subscription;
+typedef void rib_subscription_cb_t(struct rib_head *rnh, struct rib_cmd_info *rc,
+    void *arg);
+
+struct rib_subscription *rib_subscribe(uint32_t fibnum, int family,
+    rib_subscription_cb_t *f, void *arg, enum rib_subscription_type type,
+    int waitok);
+int rib_unsibscribe(uint32_t fibnum, int family, struct rib_subscription *rs);
+
 #endif
 


More information about the svn-src-head mailing list