From owner-svn-src-all@freebsd.org Mon Jun 1 21:52:25 2020 Return-Path: Delivered-To: svn-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id B0ADC2F401B; Mon, 1 Jun 2020 21:52:25 +0000 (UTC) (envelope-from melifaro@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 49bTRY4FsTz3clK; Mon, 1 Jun 2020 21:52:25 +0000 (UTC) (envelope-from melifaro@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 8CFC512481; Mon, 1 Jun 2020 21:52:25 +0000 (UTC) (envelope-from melifaro@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id 051LqPc9003890; Mon, 1 Jun 2020 21:52:25 GMT (envelope-from melifaro@FreeBSD.org) Received: (from melifaro@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id 051LqPmv003889; Mon, 1 Jun 2020 21:52:25 GMT (envelope-from melifaro@FreeBSD.org) Message-Id: <202006012152.051LqPmv003889@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: melifaro set sender to melifaro@FreeBSD.org using -f From: "Alexander V. Chernikov" Date: Mon, 1 Jun 2020 21:52:25 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r361708 - head/sys/net/route X-SVN-Group: head X-SVN-Commit-Author: melifaro X-SVN-Commit-Paths: head/sys/net/route X-SVN-Commit-Revision: 361708 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.33 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 01 Jun 2020 21:52:25 -0000 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