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"