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
 
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to