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 #include "opt_route.h"
305c4d2252SAlexander V. Chernikov
315c4d2252SAlexander V. Chernikov #include <sys/param.h>
325c4d2252SAlexander V. Chernikov #include <sys/systm.h>
335c4d2252SAlexander V. Chernikov #include <sys/malloc.h>
345c4d2252SAlexander V. Chernikov #include <sys/socket.h>
355c4d2252SAlexander V. Chernikov #include <sys/kernel.h>
365c4d2252SAlexander V. Chernikov #include <sys/lock.h>
375c4d2252SAlexander V. Chernikov #include <sys/rmlock.h>
385c4d2252SAlexander V. Chernikov
395c4d2252SAlexander V. Chernikov #include <net/route.h>
405c4d2252SAlexander V. Chernikov #include <net/route/route_ctl.h>
415c4d2252SAlexander V. Chernikov #include <net/route/route_var.h>
425c4d2252SAlexander V. Chernikov #include <net/route/nhop.h>
435c4d2252SAlexander V. Chernikov
445c4d2252SAlexander V. Chernikov struct rib_subscription {
455c4d2252SAlexander V. Chernikov CK_STAILQ_ENTRY(rib_subscription) next;
465c4d2252SAlexander V. Chernikov rib_subscription_cb_t *func;
475c4d2252SAlexander V. Chernikov void *arg;
485c4d2252SAlexander V. Chernikov struct rib_head *rnh;
495c4d2252SAlexander V. Chernikov enum rib_subscription_type type;
505c4d2252SAlexander V. Chernikov struct epoch_context epoch_ctx;
515c4d2252SAlexander V. Chernikov };
525c4d2252SAlexander V. Chernikov
535c4d2252SAlexander V. Chernikov static void destroy_subscription_epoch(epoch_context_t ctx);
545c4d2252SAlexander V. Chernikov
555c4d2252SAlexander V. Chernikov void
rib_notify(struct rib_head * rnh,enum rib_subscription_type type,struct rib_cmd_info * rc)565c4d2252SAlexander V. Chernikov rib_notify(struct rib_head *rnh, enum rib_subscription_type type,
575c4d2252SAlexander V. Chernikov struct rib_cmd_info *rc)
585c4d2252SAlexander V. Chernikov {
595c4d2252SAlexander V. Chernikov struct rib_subscription *rs;
605c4d2252SAlexander V. Chernikov
615c4d2252SAlexander V. Chernikov CK_STAILQ_FOREACH(rs, &rnh->rnh_subscribers, next) {
625c4d2252SAlexander V. Chernikov if (rs->type == type)
635c4d2252SAlexander V. Chernikov rs->func(rnh, rc, rs->arg);
645c4d2252SAlexander V. Chernikov }
655c4d2252SAlexander V. Chernikov }
665c4d2252SAlexander V. Chernikov
675c4d2252SAlexander V. Chernikov static struct rib_subscription *
allocate_subscription(rib_subscription_cb_t * f,void * arg,enum rib_subscription_type type,bool waitok)685c4d2252SAlexander V. Chernikov allocate_subscription(rib_subscription_cb_t *f, void *arg,
695c4d2252SAlexander V. Chernikov enum rib_subscription_type type, bool waitok)
705c4d2252SAlexander V. Chernikov {
715c4d2252SAlexander V. Chernikov struct rib_subscription *rs;
725c4d2252SAlexander V. Chernikov int flags = M_ZERO | (waitok ? M_WAITOK : M_NOWAIT);
735c4d2252SAlexander V. Chernikov
745c4d2252SAlexander V. Chernikov rs = malloc(sizeof(struct rib_subscription), M_RTABLE, flags);
755c4d2252SAlexander V. Chernikov if (rs == NULL)
765c4d2252SAlexander V. Chernikov return (NULL);
775c4d2252SAlexander V. Chernikov
785c4d2252SAlexander V. Chernikov rs->func = f;
795c4d2252SAlexander V. Chernikov rs->arg = arg;
805c4d2252SAlexander V. Chernikov rs->type = type;
815c4d2252SAlexander V. Chernikov
825c4d2252SAlexander V. Chernikov return (rs);
835c4d2252SAlexander V. Chernikov }
845c4d2252SAlexander V. Chernikov
855c4d2252SAlexander V. Chernikov /*
865c4d2252SAlexander V. Chernikov * Subscribe for the changes in the routing table specified by @fibnum and
875c4d2252SAlexander V. Chernikov * @family.
885c4d2252SAlexander V. Chernikov *
895c4d2252SAlexander V. Chernikov * Returns pointer to the subscription structure on success.
905c4d2252SAlexander V. Chernikov */
915c4d2252SAlexander V. Chernikov struct rib_subscription *
rib_subscribe(uint32_t fibnum,int family,rib_subscription_cb_t * f,void * arg,enum rib_subscription_type type,bool waitok)925c4d2252SAlexander V. Chernikov rib_subscribe(uint32_t fibnum, int family, rib_subscription_cb_t *f, void *arg,
935c4d2252SAlexander V. Chernikov enum rib_subscription_type type, bool waitok)
945c4d2252SAlexander V. Chernikov {
955c4d2252SAlexander V. Chernikov struct rib_head *rnh;
965c4d2252SAlexander V. Chernikov struct epoch_tracker et;
975c4d2252SAlexander V. Chernikov
985c4d2252SAlexander V. Chernikov NET_EPOCH_ENTER(et);
995c4d2252SAlexander V. Chernikov KASSERT((fibnum < rt_numfibs), ("%s: bad fibnum", __func__));
1005c4d2252SAlexander V. Chernikov rnh = rt_tables_get_rnh(fibnum, family);
1015c4d2252SAlexander V. Chernikov NET_EPOCH_EXIT(et);
1025c4d2252SAlexander V. Chernikov
1035c4d2252SAlexander V. Chernikov return (rib_subscribe_internal(rnh, f, arg, type, waitok));
1045c4d2252SAlexander V. Chernikov }
1055c4d2252SAlexander V. Chernikov
1065c4d2252SAlexander V. Chernikov struct rib_subscription *
rib_subscribe_internal(struct rib_head * rnh,rib_subscription_cb_t * f,void * arg,enum rib_subscription_type type,bool waitok)1075c4d2252SAlexander V. Chernikov rib_subscribe_internal(struct rib_head *rnh, rib_subscription_cb_t *f, void *arg,
1085c4d2252SAlexander V. Chernikov enum rib_subscription_type type, bool waitok)
1095c4d2252SAlexander V. Chernikov {
1105c4d2252SAlexander V. Chernikov struct rib_subscription *rs;
1115c4d2252SAlexander V. Chernikov struct epoch_tracker et;
1125c4d2252SAlexander V. Chernikov
1135c4d2252SAlexander V. Chernikov if ((rs = allocate_subscription(f, arg, type, waitok)) == NULL)
1145c4d2252SAlexander V. Chernikov return (NULL);
1155c4d2252SAlexander V. Chernikov rs->rnh = rnh;
1165c4d2252SAlexander V. Chernikov
1175c4d2252SAlexander V. Chernikov NET_EPOCH_ENTER(et);
1185c4d2252SAlexander V. Chernikov RIB_WLOCK(rnh);
1195c4d2252SAlexander V. Chernikov CK_STAILQ_INSERT_HEAD(&rnh->rnh_subscribers, rs, next);
1205c4d2252SAlexander V. Chernikov RIB_WUNLOCK(rnh);
1215c4d2252SAlexander V. Chernikov NET_EPOCH_EXIT(et);
1225c4d2252SAlexander V. Chernikov
1235c4d2252SAlexander V. Chernikov return (rs);
1245c4d2252SAlexander V. Chernikov }
1255c4d2252SAlexander V. Chernikov
1265c4d2252SAlexander V. Chernikov struct rib_subscription *
rib_subscribe_locked(struct rib_head * rnh,rib_subscription_cb_t * f,void * arg,enum rib_subscription_type type)1275c4d2252SAlexander V. Chernikov rib_subscribe_locked(struct rib_head *rnh, rib_subscription_cb_t *f, void *arg,
1285c4d2252SAlexander V. Chernikov enum rib_subscription_type type)
1295c4d2252SAlexander V. Chernikov {
1305c4d2252SAlexander V. Chernikov struct rib_subscription *rs;
1315c4d2252SAlexander V. Chernikov
1325c4d2252SAlexander V. Chernikov NET_EPOCH_ASSERT();
1335c4d2252SAlexander V. Chernikov RIB_WLOCK_ASSERT(rnh);
1345c4d2252SAlexander V. Chernikov
1355c4d2252SAlexander V. Chernikov if ((rs = allocate_subscription(f, arg, type, false)) == NULL)
1365c4d2252SAlexander V. Chernikov return (NULL);
1375c4d2252SAlexander V. Chernikov rs->rnh = rnh;
1385c4d2252SAlexander V. Chernikov
1395c4d2252SAlexander V. Chernikov CK_STAILQ_INSERT_HEAD(&rnh->rnh_subscribers, rs, next);
1405c4d2252SAlexander V. Chernikov
1415c4d2252SAlexander V. Chernikov return (rs);
1425c4d2252SAlexander V. Chernikov }
1435c4d2252SAlexander V. Chernikov
1445c4d2252SAlexander V. Chernikov /*
1455c4d2252SAlexander V. Chernikov * Remove rtable subscription @rs from the routing table.
1465c4d2252SAlexander V. Chernikov * Needs to be run in network epoch.
1475c4d2252SAlexander V. Chernikov */
1485c4d2252SAlexander V. Chernikov void
rib_unsubscribe(struct rib_subscription * rs)1495c4d2252SAlexander V. Chernikov rib_unsubscribe(struct rib_subscription *rs)
1505c4d2252SAlexander V. Chernikov {
1515c4d2252SAlexander V. Chernikov struct rib_head *rnh = rs->rnh;
1525c4d2252SAlexander V. Chernikov
1535c4d2252SAlexander V. Chernikov NET_EPOCH_ASSERT();
1545c4d2252SAlexander V. Chernikov
1555c4d2252SAlexander V. Chernikov RIB_WLOCK(rnh);
1565c4d2252SAlexander V. Chernikov CK_STAILQ_REMOVE(&rnh->rnh_subscribers, rs, rib_subscription, next);
1575c4d2252SAlexander V. Chernikov RIB_WUNLOCK(rnh);
1585c4d2252SAlexander V. Chernikov
15973336a6fSZhenlei Huang NET_EPOCH_CALL(destroy_subscription_epoch, &rs->epoch_ctx);
1605c4d2252SAlexander V. Chernikov }
1615c4d2252SAlexander V. Chernikov
1625c4d2252SAlexander V. Chernikov void
rib_unsubscribe_locked(struct rib_subscription * rs)1635c4d2252SAlexander V. Chernikov rib_unsubscribe_locked(struct rib_subscription *rs)
1645c4d2252SAlexander V. Chernikov {
1655c4d2252SAlexander V. Chernikov struct rib_head *rnh = rs->rnh;
1665c4d2252SAlexander V. Chernikov
1675c4d2252SAlexander V. Chernikov NET_EPOCH_ASSERT();
1685c4d2252SAlexander V. Chernikov RIB_WLOCK_ASSERT(rnh);
1695c4d2252SAlexander V. Chernikov
1705c4d2252SAlexander V. Chernikov CK_STAILQ_REMOVE(&rnh->rnh_subscribers, rs, rib_subscription, next);
1715c4d2252SAlexander V. Chernikov
17273336a6fSZhenlei Huang NET_EPOCH_CALL(destroy_subscription_epoch, &rs->epoch_ctx);
1735c4d2252SAlexander V. Chernikov }
1745c4d2252SAlexander V. Chernikov
1755c4d2252SAlexander V. Chernikov /*
1765c4d2252SAlexander V. Chernikov * Epoch callback indicating subscription is safe to destroy
1775c4d2252SAlexander V. Chernikov */
1785c4d2252SAlexander V. Chernikov static void
destroy_subscription_epoch(epoch_context_t ctx)1795c4d2252SAlexander V. Chernikov destroy_subscription_epoch(epoch_context_t ctx)
1805c4d2252SAlexander V. Chernikov {
1815c4d2252SAlexander V. Chernikov struct rib_subscription *rs;
1825c4d2252SAlexander V. Chernikov
1835c4d2252SAlexander V. Chernikov rs = __containerof(ctx, struct rib_subscription, epoch_ctx);
1845c4d2252SAlexander V. Chernikov
1855c4d2252SAlexander V. Chernikov free(rs, M_RTABLE);
1865c4d2252SAlexander V. Chernikov }
1875c4d2252SAlexander V. Chernikov
1885c4d2252SAlexander V. Chernikov void
rib_init_subscriptions(struct rib_head * rnh)1895c4d2252SAlexander V. Chernikov rib_init_subscriptions(struct rib_head *rnh)
1905c4d2252SAlexander V. Chernikov {
1915c4d2252SAlexander V. Chernikov
1925c4d2252SAlexander V. Chernikov CK_STAILQ_INIT(&rnh->rnh_subscribers);
1935c4d2252SAlexander V. Chernikov }
1945c4d2252SAlexander V. Chernikov
1955c4d2252SAlexander V. Chernikov void
rib_destroy_subscriptions(struct rib_head * rnh)1965c4d2252SAlexander V. Chernikov rib_destroy_subscriptions(struct rib_head *rnh)
1975c4d2252SAlexander V. Chernikov {
1985c4d2252SAlexander V. Chernikov struct rib_subscription *rs;
1995c4d2252SAlexander V. Chernikov struct epoch_tracker et;
2005c4d2252SAlexander V. Chernikov
2015c4d2252SAlexander V. Chernikov NET_EPOCH_ENTER(et);
2025c4d2252SAlexander V. Chernikov RIB_WLOCK(rnh);
2035c4d2252SAlexander V. Chernikov while ((rs = CK_STAILQ_FIRST(&rnh->rnh_subscribers)) != NULL) {
2045c4d2252SAlexander V. Chernikov CK_STAILQ_REMOVE_HEAD(&rnh->rnh_subscribers, next);
20573336a6fSZhenlei Huang NET_EPOCH_CALL(destroy_subscription_epoch, &rs->epoch_ctx);
2065c4d2252SAlexander V. Chernikov }
2075c4d2252SAlexander V. Chernikov RIB_WUNLOCK(rnh);
2085c4d2252SAlexander V. Chernikov NET_EPOCH_EXIT(et);
2095c4d2252SAlexander V. Chernikov }
210