15c4d2252SAlexander V. Chernikov /*- 2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 35c4d2252SAlexander V. Chernikov * 45c4d2252SAlexander V. Chernikov * Copyright (c) 2021-2022 Alexander V. Chernikov 55c4d2252SAlexander V. Chernikov * 65c4d2252SAlexander V. Chernikov * Redistribution and use in source and binary forms, with or without 75c4d2252SAlexander V. Chernikov * modification, are permitted provided that the following conditions 85c4d2252SAlexander V. Chernikov * are met: 95c4d2252SAlexander V. Chernikov * 1. Redistributions of source code must retain the above copyright 105c4d2252SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer. 115c4d2252SAlexander V. Chernikov * 2. Redistributions in binary form must reproduce the above copyright 125c4d2252SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer in the 135c4d2252SAlexander V. Chernikov * documentation and/or other materials provided with the distribution. 145c4d2252SAlexander V. Chernikov * 155c4d2252SAlexander V. Chernikov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 165c4d2252SAlexander V. Chernikov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 175c4d2252SAlexander V. Chernikov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 185c4d2252SAlexander V. Chernikov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 195c4d2252SAlexander V. Chernikov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 205c4d2252SAlexander V. Chernikov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 215c4d2252SAlexander V. Chernikov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 225c4d2252SAlexander V. Chernikov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 235c4d2252SAlexander V. Chernikov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 245c4d2252SAlexander V. Chernikov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 255c4d2252SAlexander V. Chernikov * SUCH DAMAGE. 265c4d2252SAlexander V. Chernikov */ 275c4d2252SAlexander V. Chernikov 285c4d2252SAlexander V. Chernikov #include <sys/cdefs.h> 295c4d2252SAlexander V. Chernikov __FBSDID("$FreeBSD$"); 305c4d2252SAlexander V. Chernikov #include "opt_route.h" 315c4d2252SAlexander V. Chernikov 325c4d2252SAlexander V. Chernikov #include <sys/param.h> 335c4d2252SAlexander V. Chernikov #include <sys/systm.h> 345c4d2252SAlexander V. Chernikov #include <sys/malloc.h> 355c4d2252SAlexander V. Chernikov #include <sys/socket.h> 365c4d2252SAlexander V. Chernikov #include <sys/kernel.h> 375c4d2252SAlexander V. Chernikov #include <sys/lock.h> 385c4d2252SAlexander V. Chernikov #include <sys/rmlock.h> 395c4d2252SAlexander V. Chernikov 405c4d2252SAlexander V. Chernikov #include <net/route.h> 415c4d2252SAlexander V. Chernikov #include <net/route/route_ctl.h> 425c4d2252SAlexander V. Chernikov #include <net/route/route_var.h> 435c4d2252SAlexander V. Chernikov #include <net/route/nhop.h> 445c4d2252SAlexander V. Chernikov 455c4d2252SAlexander V. Chernikov struct rib_subscription { 465c4d2252SAlexander V. Chernikov CK_STAILQ_ENTRY(rib_subscription) next; 475c4d2252SAlexander V. Chernikov rib_subscription_cb_t *func; 485c4d2252SAlexander V. Chernikov void *arg; 495c4d2252SAlexander V. Chernikov struct rib_head *rnh; 505c4d2252SAlexander V. Chernikov enum rib_subscription_type type; 515c4d2252SAlexander V. Chernikov struct epoch_context epoch_ctx; 525c4d2252SAlexander V. Chernikov }; 535c4d2252SAlexander V. Chernikov 545c4d2252SAlexander V. Chernikov static void destroy_subscription_epoch(epoch_context_t ctx); 555c4d2252SAlexander V. Chernikov 565c4d2252SAlexander V. Chernikov void 575c4d2252SAlexander V. Chernikov rib_notify(struct rib_head *rnh, enum rib_subscription_type type, 585c4d2252SAlexander V. Chernikov struct rib_cmd_info *rc) 595c4d2252SAlexander V. Chernikov { 605c4d2252SAlexander V. Chernikov struct rib_subscription *rs; 615c4d2252SAlexander V. Chernikov 625c4d2252SAlexander V. Chernikov CK_STAILQ_FOREACH(rs, &rnh->rnh_subscribers, next) { 635c4d2252SAlexander V. Chernikov if (rs->type == type) 645c4d2252SAlexander V. Chernikov rs->func(rnh, rc, rs->arg); 655c4d2252SAlexander V. Chernikov } 665c4d2252SAlexander V. Chernikov } 675c4d2252SAlexander V. Chernikov 685c4d2252SAlexander V. Chernikov static struct rib_subscription * 695c4d2252SAlexander V. Chernikov allocate_subscription(rib_subscription_cb_t *f, void *arg, 705c4d2252SAlexander V. Chernikov enum rib_subscription_type type, bool waitok) 715c4d2252SAlexander V. Chernikov { 725c4d2252SAlexander V. Chernikov struct rib_subscription *rs; 735c4d2252SAlexander V. Chernikov int flags = M_ZERO | (waitok ? M_WAITOK : M_NOWAIT); 745c4d2252SAlexander V. Chernikov 755c4d2252SAlexander V. Chernikov rs = malloc(sizeof(struct rib_subscription), M_RTABLE, flags); 765c4d2252SAlexander V. Chernikov if (rs == NULL) 775c4d2252SAlexander V. Chernikov return (NULL); 785c4d2252SAlexander V. Chernikov 795c4d2252SAlexander V. Chernikov rs->func = f; 805c4d2252SAlexander V. Chernikov rs->arg = arg; 815c4d2252SAlexander V. Chernikov rs->type = type; 825c4d2252SAlexander V. Chernikov 835c4d2252SAlexander V. Chernikov return (rs); 845c4d2252SAlexander V. Chernikov } 855c4d2252SAlexander V. Chernikov 865c4d2252SAlexander V. Chernikov /* 875c4d2252SAlexander V. Chernikov * Subscribe for the changes in the routing table specified by @fibnum and 885c4d2252SAlexander V. Chernikov * @family. 895c4d2252SAlexander V. Chernikov * 905c4d2252SAlexander V. Chernikov * Returns pointer to the subscription structure on success. 915c4d2252SAlexander V. Chernikov */ 925c4d2252SAlexander V. Chernikov struct rib_subscription * 935c4d2252SAlexander V. Chernikov rib_subscribe(uint32_t fibnum, int family, rib_subscription_cb_t *f, void *arg, 945c4d2252SAlexander V. Chernikov enum rib_subscription_type type, bool waitok) 955c4d2252SAlexander V. Chernikov { 965c4d2252SAlexander V. Chernikov struct rib_head *rnh; 975c4d2252SAlexander V. Chernikov struct epoch_tracker et; 985c4d2252SAlexander V. Chernikov 995c4d2252SAlexander V. Chernikov NET_EPOCH_ENTER(et); 1005c4d2252SAlexander V. Chernikov KASSERT((fibnum < rt_numfibs), ("%s: bad fibnum", __func__)); 1015c4d2252SAlexander V. Chernikov rnh = rt_tables_get_rnh(fibnum, family); 1025c4d2252SAlexander V. Chernikov NET_EPOCH_EXIT(et); 1035c4d2252SAlexander V. Chernikov 1045c4d2252SAlexander V. Chernikov return (rib_subscribe_internal(rnh, f, arg, type, waitok)); 1055c4d2252SAlexander V. Chernikov } 1065c4d2252SAlexander V. Chernikov 1075c4d2252SAlexander V. Chernikov struct rib_subscription * 1085c4d2252SAlexander V. Chernikov rib_subscribe_internal(struct rib_head *rnh, rib_subscription_cb_t *f, void *arg, 1095c4d2252SAlexander V. Chernikov enum rib_subscription_type type, bool waitok) 1105c4d2252SAlexander V. Chernikov { 1115c4d2252SAlexander V. Chernikov struct rib_subscription *rs; 1125c4d2252SAlexander V. Chernikov struct epoch_tracker et; 1135c4d2252SAlexander V. Chernikov 1145c4d2252SAlexander V. Chernikov if ((rs = allocate_subscription(f, arg, type, waitok)) == NULL) 1155c4d2252SAlexander V. Chernikov return (NULL); 1165c4d2252SAlexander V. Chernikov rs->rnh = rnh; 1175c4d2252SAlexander V. Chernikov 1185c4d2252SAlexander V. Chernikov NET_EPOCH_ENTER(et); 1195c4d2252SAlexander V. Chernikov RIB_WLOCK(rnh); 1205c4d2252SAlexander V. Chernikov CK_STAILQ_INSERT_HEAD(&rnh->rnh_subscribers, rs, next); 1215c4d2252SAlexander V. Chernikov RIB_WUNLOCK(rnh); 1225c4d2252SAlexander V. Chernikov NET_EPOCH_EXIT(et); 1235c4d2252SAlexander V. Chernikov 1245c4d2252SAlexander V. Chernikov return (rs); 1255c4d2252SAlexander V. Chernikov } 1265c4d2252SAlexander V. Chernikov 1275c4d2252SAlexander V. Chernikov struct rib_subscription * 1285c4d2252SAlexander V. Chernikov rib_subscribe_locked(struct rib_head *rnh, rib_subscription_cb_t *f, void *arg, 1295c4d2252SAlexander V. Chernikov enum rib_subscription_type type) 1305c4d2252SAlexander V. Chernikov { 1315c4d2252SAlexander V. Chernikov struct rib_subscription *rs; 1325c4d2252SAlexander V. Chernikov 1335c4d2252SAlexander V. Chernikov NET_EPOCH_ASSERT(); 1345c4d2252SAlexander V. Chernikov RIB_WLOCK_ASSERT(rnh); 1355c4d2252SAlexander V. Chernikov 1365c4d2252SAlexander V. Chernikov if ((rs = allocate_subscription(f, arg, type, false)) == NULL) 1375c4d2252SAlexander V. Chernikov return (NULL); 1385c4d2252SAlexander V. Chernikov rs->rnh = rnh; 1395c4d2252SAlexander V. Chernikov 1405c4d2252SAlexander V. Chernikov CK_STAILQ_INSERT_HEAD(&rnh->rnh_subscribers, rs, next); 1415c4d2252SAlexander V. Chernikov 1425c4d2252SAlexander V. Chernikov return (rs); 1435c4d2252SAlexander V. Chernikov } 1445c4d2252SAlexander V. Chernikov 1455c4d2252SAlexander V. Chernikov /* 1465c4d2252SAlexander V. Chernikov * Remove rtable subscription @rs from the routing table. 1475c4d2252SAlexander V. Chernikov * Needs to be run in network epoch. 1485c4d2252SAlexander V. Chernikov */ 1495c4d2252SAlexander V. Chernikov void 1505c4d2252SAlexander V. Chernikov rib_unsubscribe(struct rib_subscription *rs) 1515c4d2252SAlexander V. Chernikov { 1525c4d2252SAlexander V. Chernikov struct rib_head *rnh = rs->rnh; 1535c4d2252SAlexander V. Chernikov 1545c4d2252SAlexander V. Chernikov NET_EPOCH_ASSERT(); 1555c4d2252SAlexander V. Chernikov 1565c4d2252SAlexander V. Chernikov RIB_WLOCK(rnh); 1575c4d2252SAlexander V. Chernikov CK_STAILQ_REMOVE(&rnh->rnh_subscribers, rs, rib_subscription, next); 1585c4d2252SAlexander V. Chernikov RIB_WUNLOCK(rnh); 1595c4d2252SAlexander V. Chernikov 16073336a6fSZhenlei Huang NET_EPOCH_CALL(destroy_subscription_epoch, &rs->epoch_ctx); 1615c4d2252SAlexander V. Chernikov } 1625c4d2252SAlexander V. Chernikov 1635c4d2252SAlexander V. Chernikov void 1645c4d2252SAlexander V. Chernikov rib_unsubscribe_locked(struct rib_subscription *rs) 1655c4d2252SAlexander V. Chernikov { 1665c4d2252SAlexander V. Chernikov struct rib_head *rnh = rs->rnh; 1675c4d2252SAlexander V. Chernikov 1685c4d2252SAlexander V. Chernikov NET_EPOCH_ASSERT(); 1695c4d2252SAlexander V. Chernikov RIB_WLOCK_ASSERT(rnh); 1705c4d2252SAlexander V. Chernikov 1715c4d2252SAlexander V. Chernikov CK_STAILQ_REMOVE(&rnh->rnh_subscribers, rs, rib_subscription, next); 1725c4d2252SAlexander V. Chernikov 17373336a6fSZhenlei Huang NET_EPOCH_CALL(destroy_subscription_epoch, &rs->epoch_ctx); 1745c4d2252SAlexander V. Chernikov } 1755c4d2252SAlexander V. Chernikov 1765c4d2252SAlexander V. Chernikov /* 1775c4d2252SAlexander V. Chernikov * Epoch callback indicating subscription is safe to destroy 1785c4d2252SAlexander V. Chernikov */ 1795c4d2252SAlexander V. Chernikov static void 1805c4d2252SAlexander V. Chernikov destroy_subscription_epoch(epoch_context_t ctx) 1815c4d2252SAlexander V. Chernikov { 1825c4d2252SAlexander V. Chernikov struct rib_subscription *rs; 1835c4d2252SAlexander V. Chernikov 1845c4d2252SAlexander V. Chernikov rs = __containerof(ctx, struct rib_subscription, epoch_ctx); 1855c4d2252SAlexander V. Chernikov 1865c4d2252SAlexander V. Chernikov free(rs, M_RTABLE); 1875c4d2252SAlexander V. Chernikov } 1885c4d2252SAlexander V. Chernikov 1895c4d2252SAlexander V. Chernikov void 1905c4d2252SAlexander V. Chernikov rib_init_subscriptions(struct rib_head *rnh) 1915c4d2252SAlexander V. Chernikov { 1925c4d2252SAlexander V. Chernikov 1935c4d2252SAlexander V. Chernikov CK_STAILQ_INIT(&rnh->rnh_subscribers); 1945c4d2252SAlexander V. Chernikov } 1955c4d2252SAlexander V. Chernikov 1965c4d2252SAlexander V. Chernikov void 1975c4d2252SAlexander V. Chernikov rib_destroy_subscriptions(struct rib_head *rnh) 1985c4d2252SAlexander V. Chernikov { 1995c4d2252SAlexander V. Chernikov struct rib_subscription *rs; 2005c4d2252SAlexander V. Chernikov struct epoch_tracker et; 2015c4d2252SAlexander V. Chernikov 2025c4d2252SAlexander V. Chernikov NET_EPOCH_ENTER(et); 2035c4d2252SAlexander V. Chernikov RIB_WLOCK(rnh); 2045c4d2252SAlexander V. Chernikov while ((rs = CK_STAILQ_FIRST(&rnh->rnh_subscribers)) != NULL) { 2055c4d2252SAlexander V. Chernikov CK_STAILQ_REMOVE_HEAD(&rnh->rnh_subscribers, next); 20673336a6fSZhenlei Huang NET_EPOCH_CALL(destroy_subscription_epoch, &rs->epoch_ctx); 2075c4d2252SAlexander V. Chernikov } 2085c4d2252SAlexander V. Chernikov RIB_WUNLOCK(rnh); 2095c4d2252SAlexander V. Chernikov NET_EPOCH_EXIT(et); 2105c4d2252SAlexander V. Chernikov } 211