1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2022 Alexander V. Chernikov <melifaro@FreeBSD.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 #include <sys/types.h> 30 #include <sys/ck.h> 31 #include <sys/epoch.h> 32 #include <sys/kernel.h> 33 #include <sys/malloc.h> 34 #include <sys/socket.h> 35 36 #include <net/route.h> 37 #include <net/route/route_ctl.h> 38 #include <netlink/netlink.h> 39 #include <netlink/netlink_ctl.h> 40 #include <netlink/netlink_route.h> 41 #include <netlink/route/route_var.h> 42 43 #define DEBUG_MOD_NAME nl_route_core 44 #define DEBUG_MAX_LEVEL LOG_DEBUG3 45 #include <netlink/netlink_debug.h> 46 _DECLARE_DEBUG(LOG_INFO); 47 48 #define HANDLER_MAX_NUM (NL_RTM_MAX + 10) 49 static const struct rtnl_cmd_handler *rtnl_handler[HANDLER_MAX_NUM] = {}; 50 51 bool 52 rtnl_register_messages(const struct rtnl_cmd_handler *handlers, int count) 53 { 54 for (int i = 0; i < count; i++) { 55 if (handlers[i].cmd >= HANDLER_MAX_NUM) 56 return (false); 57 MPASS(rtnl_handler[handlers[i].cmd] == NULL); 58 } 59 for (int i = 0; i < count; i++) 60 rtnl_handler[handlers[i].cmd] = &handlers[i]; 61 return (true); 62 } 63 64 /* 65 * Handler called by netlink subsystem when matching netlink message is received 66 */ 67 static int 68 rtnl_handle_message(struct nlmsghdr *hdr, struct nl_pstate *npt) 69 { 70 const struct rtnl_cmd_handler *cmd; 71 struct epoch_tracker et; 72 struct nlpcb *nlp = npt->nlp; 73 int error = 0; 74 75 if (__predict_false(hdr->nlmsg_type >= HANDLER_MAX_NUM)) { 76 NLMSG_REPORT_ERR_MSG(npt, "unknown message type: %d", hdr->nlmsg_type); 77 return (ENOTSUP); 78 } 79 80 cmd = rtnl_handler[hdr->nlmsg_type]; 81 if (__predict_false(cmd == NULL)) { 82 NLMSG_REPORT_ERR_MSG(npt, "unknown message type: %d", hdr->nlmsg_type); 83 return (ENOTSUP); 84 } 85 86 NLP_LOG(LOG_DEBUG2, nlp, "received msg %s(%d) len %d", cmd->name, 87 hdr->nlmsg_type, hdr->nlmsg_len); 88 89 if (cmd->priv != 0 && !nlp_has_priv(nlp, cmd->priv)) { 90 NLP_LOG(LOG_DEBUG2, nlp, "priv %d check failed for msg %s", cmd->priv, cmd->name); 91 return (EPERM); 92 } else if (cmd->priv != 0) 93 NLP_LOG(LOG_DEBUG3, nlp, "priv %d check passed for msg %s", cmd->priv, cmd->name); 94 95 if (!nlp_unconstrained_vnet(nlp) && (cmd->flags & RTNL_F_ALLOW_NONVNET_JAIL) == 0) { 96 NLP_LOG(LOG_DEBUG2, nlp, "jail check failed for msg %s", cmd->name); 97 return (EPERM); 98 } 99 100 bool need_epoch = !(cmd->flags & RTNL_F_NOEPOCH); 101 102 if (need_epoch) 103 NET_EPOCH_ENTER(et); 104 error = cmd->cb(hdr, nlp, npt); 105 if (need_epoch) 106 NET_EPOCH_EXIT(et); 107 108 NLP_LOG(LOG_DEBUG3, nlp, "message %s -> error %d", cmd->name, error); 109 110 return (error); 111 } 112 113 static struct rtbridge nlbridge = { 114 .route_f = rtnl_handle_route_event, 115 .ifmsg_f = rtnl_handle_ifnet_event, 116 }; 117 static struct rtbridge *nlbridge_orig_p; 118 119 static void 120 rtnl_load(void *u __unused) 121 { 122 NL_LOG(LOG_DEBUG2, "rtnl loading"); 123 nlbridge_orig_p = netlink_callback_p; 124 netlink_callback_p = &nlbridge; 125 rtnl_neighs_init(); 126 rtnl_ifaces_init(); 127 rtnl_nexthops_init(); 128 rtnl_routes_init(); 129 netlink_register_proto(NETLINK_ROUTE, "NETLINK_ROUTE", rtnl_handle_message); 130 } 131 SYSINIT(rtnl_load, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, rtnl_load, NULL); 132 133 static void 134 rtnl_unload(void *u __unused) 135 { 136 netlink_callback_p = nlbridge_orig_p; 137 netlink_unregister_proto(NETLINK_ROUTE); 138 rtnl_ifaces_destroy(); 139 rtnl_neighs_destroy(); 140 141 /* Wait till all consumers read nlbridge data */ 142 NET_EPOCH_WAIT(); 143 } 144 SYSUNINIT(rtnl_unload, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, rtnl_unload, NULL); 145