17e5bf684SAlexander V. Chernikov /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 37e5bf684SAlexander V. Chernikov * 47e5bf684SAlexander V. Chernikov * Copyright (c) 2022 Alexander V. Chernikov <melifaro@FreeBSD.org> 57e5bf684SAlexander V. Chernikov * 67e5bf684SAlexander V. Chernikov * Redistribution and use in source and binary forms, with or without 77e5bf684SAlexander V. Chernikov * modification, are permitted provided that the following conditions 87e5bf684SAlexander V. Chernikov * are met: 97e5bf684SAlexander V. Chernikov * 1. Redistributions of source code must retain the above copyright 107e5bf684SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer. 117e5bf684SAlexander V. Chernikov * 2. Redistributions in binary form must reproduce the above copyright 127e5bf684SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer in the 137e5bf684SAlexander V. Chernikov * documentation and/or other materials provided with the distribution. 147e5bf684SAlexander V. Chernikov * 157e5bf684SAlexander V. Chernikov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 167e5bf684SAlexander V. Chernikov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 177e5bf684SAlexander V. Chernikov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 187e5bf684SAlexander V. Chernikov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 197e5bf684SAlexander V. Chernikov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 207e5bf684SAlexander V. Chernikov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 217e5bf684SAlexander V. Chernikov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 227e5bf684SAlexander V. Chernikov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 237e5bf684SAlexander V. Chernikov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 247e5bf684SAlexander V. Chernikov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 257e5bf684SAlexander V. Chernikov * SUCH DAMAGE. 267e5bf684SAlexander V. Chernikov */ 277e5bf684SAlexander V. Chernikov 287e5bf684SAlexander V. Chernikov #include <sys/cdefs.h> 297e5bf684SAlexander V. Chernikov #include <sys/types.h> 30fc083c3eSJung-uk Kim #include <sys/ck.h> 31669d63ebSAlexander V. Chernikov #include <sys/epoch.h> 32fc083c3eSJung-uk Kim #include <sys/kernel.h> 337e5bf684SAlexander V. Chernikov #include <sys/malloc.h> 347e5bf684SAlexander V. Chernikov #include <sys/socket.h> 357e5bf684SAlexander V. Chernikov 367e5bf684SAlexander V. Chernikov #include <net/route.h> 377e5bf684SAlexander V. Chernikov #include <net/route/route_ctl.h> 387e5bf684SAlexander V. Chernikov #include <netlink/netlink.h> 397e5bf684SAlexander V. Chernikov #include <netlink/netlink_ctl.h> 407e5bf684SAlexander V. Chernikov #include <netlink/netlink_route.h> 417e5bf684SAlexander V. Chernikov #include <netlink/route/route_var.h> 427e5bf684SAlexander V. Chernikov 437e5bf684SAlexander V. Chernikov #define DEBUG_MOD_NAME nl_route_core 447e5bf684SAlexander V. Chernikov #define DEBUG_MAX_LEVEL LOG_DEBUG3 457e5bf684SAlexander V. Chernikov #include <netlink/netlink_debug.h> 46fa554de7SKristof Provost _DECLARE_DEBUG(LOG_INFO); 477e5bf684SAlexander V. Chernikov 487e5bf684SAlexander V. Chernikov #define HANDLER_MAX_NUM (NL_RTM_MAX + 10) 497e5bf684SAlexander V. Chernikov static const struct rtnl_cmd_handler *rtnl_handler[HANDLER_MAX_NUM] = {}; 507e5bf684SAlexander V. Chernikov 517e5bf684SAlexander V. Chernikov bool 527e5bf684SAlexander V. Chernikov rtnl_register_messages(const struct rtnl_cmd_handler *handlers, int count) 537e5bf684SAlexander V. Chernikov { 547e5bf684SAlexander V. Chernikov for (int i = 0; i < count; i++) { 557e5bf684SAlexander V. Chernikov if (handlers[i].cmd >= HANDLER_MAX_NUM) 567e5bf684SAlexander V. Chernikov return (false); 577e5bf684SAlexander V. Chernikov MPASS(rtnl_handler[handlers[i].cmd] == NULL); 587e5bf684SAlexander V. Chernikov } 597e5bf684SAlexander V. Chernikov for (int i = 0; i < count; i++) 607e5bf684SAlexander V. Chernikov rtnl_handler[handlers[i].cmd] = &handlers[i]; 617e5bf684SAlexander V. Chernikov return (true); 627e5bf684SAlexander V. Chernikov } 637e5bf684SAlexander V. Chernikov 647e5bf684SAlexander V. Chernikov /* 657e5bf684SAlexander V. Chernikov * Handler called by netlink subsystem when matching netlink message is received 667e5bf684SAlexander V. Chernikov */ 677e5bf684SAlexander V. Chernikov static int 687e5bf684SAlexander V. Chernikov rtnl_handle_message(struct nlmsghdr *hdr, struct nl_pstate *npt) 697e5bf684SAlexander V. Chernikov { 707e5bf684SAlexander V. Chernikov const struct rtnl_cmd_handler *cmd; 717e5bf684SAlexander V. Chernikov struct epoch_tracker et; 727e5bf684SAlexander V. Chernikov struct nlpcb *nlp = npt->nlp; 737e5bf684SAlexander V. Chernikov int error = 0; 747e5bf684SAlexander V. Chernikov 757e5bf684SAlexander V. Chernikov if (__predict_false(hdr->nlmsg_type >= HANDLER_MAX_NUM)) { 767e5bf684SAlexander V. Chernikov NLMSG_REPORT_ERR_MSG(npt, "unknown message type: %d", hdr->nlmsg_type); 777e5bf684SAlexander V. Chernikov return (ENOTSUP); 787e5bf684SAlexander V. Chernikov } 797e5bf684SAlexander V. Chernikov 807e5bf684SAlexander V. Chernikov cmd = rtnl_handler[hdr->nlmsg_type]; 817e5bf684SAlexander V. Chernikov if (__predict_false(cmd == NULL)) { 827e5bf684SAlexander V. Chernikov NLMSG_REPORT_ERR_MSG(npt, "unknown message type: %d", hdr->nlmsg_type); 837e5bf684SAlexander V. Chernikov return (ENOTSUP); 847e5bf684SAlexander V. Chernikov } 857e5bf684SAlexander V. Chernikov 867e5bf684SAlexander V. Chernikov NLP_LOG(LOG_DEBUG2, nlp, "received msg %s(%d) len %d", cmd->name, 877e5bf684SAlexander V. Chernikov hdr->nlmsg_type, hdr->nlmsg_len); 887e5bf684SAlexander V. Chernikov 897e5bf684SAlexander V. Chernikov if (cmd->priv != 0 && !nlp_has_priv(nlp, cmd->priv)) { 907e5bf684SAlexander V. Chernikov NLP_LOG(LOG_DEBUG2, nlp, "priv %d check failed for msg %s", cmd->priv, cmd->name); 917e5bf684SAlexander V. Chernikov return (EPERM); 927e5bf684SAlexander V. Chernikov } else if (cmd->priv != 0) 937e5bf684SAlexander V. Chernikov NLP_LOG(LOG_DEBUG3, nlp, "priv %d check passed for msg %s", cmd->priv, cmd->name); 947e5bf684SAlexander V. Chernikov 9504f75b98SAlexander V. Chernikov if (!nlp_unconstrained_vnet(nlp) && (cmd->flags & RTNL_F_ALLOW_NONVNET_JAIL) == 0) { 9604f75b98SAlexander V. Chernikov NLP_LOG(LOG_DEBUG2, nlp, "jail check failed for msg %s", cmd->name); 9704f75b98SAlexander V. Chernikov return (EPERM); 9804f75b98SAlexander V. Chernikov } 9904f75b98SAlexander V. Chernikov 1007e5bf684SAlexander V. Chernikov bool need_epoch = !(cmd->flags & RTNL_F_NOEPOCH); 1017e5bf684SAlexander V. Chernikov 1027e5bf684SAlexander V. Chernikov if (need_epoch) 1037e5bf684SAlexander V. Chernikov NET_EPOCH_ENTER(et); 1047e5bf684SAlexander V. Chernikov error = cmd->cb(hdr, nlp, npt); 1057e5bf684SAlexander V. Chernikov if (need_epoch) 1067e5bf684SAlexander V. Chernikov NET_EPOCH_EXIT(et); 1077e5bf684SAlexander V. Chernikov 1087e5bf684SAlexander V. Chernikov NLP_LOG(LOG_DEBUG3, nlp, "message %s -> error %d", cmd->name, error); 1097e5bf684SAlexander V. Chernikov 1107e5bf684SAlexander V. Chernikov return (error); 1117e5bf684SAlexander V. Chernikov } 1127e5bf684SAlexander V. Chernikov 1131bcd230fSAlexander V. Chernikov static struct rtbridge nlbridge = { 1141bcd230fSAlexander V. Chernikov .route_f = rtnl_handle_route_event, 1151bcd230fSAlexander V. Chernikov .ifmsg_f = rtnl_handle_ifnet_event, 1161bcd230fSAlexander V. Chernikov }; 1177e5bf684SAlexander V. Chernikov static struct rtbridge *nlbridge_orig_p; 1187e5bf684SAlexander V. Chernikov 1197e5bf684SAlexander V. Chernikov static void 1207e5bf684SAlexander V. Chernikov rtnl_load(void *u __unused) 1217e5bf684SAlexander V. Chernikov { 1227fc9cfa5SAlexander V. Chernikov NL_LOG(LOG_DEBUG2, "rtnl loading"); 1237e5bf684SAlexander V. Chernikov nlbridge_orig_p = netlink_callback_p; 1247e5bf684SAlexander V. Chernikov netlink_callback_p = &nlbridge; 1257e5bf684SAlexander V. Chernikov rtnl_neighs_init(); 1267e5bf684SAlexander V. Chernikov rtnl_ifaces_init(); 1277e5bf684SAlexander V. Chernikov rtnl_nexthops_init(); 1287e5bf684SAlexander V. Chernikov rtnl_routes_init(); 1297e5bf684SAlexander V. Chernikov netlink_register_proto(NETLINK_ROUTE, "NETLINK_ROUTE", rtnl_handle_message); 1307e5bf684SAlexander V. Chernikov } 1317e5bf684SAlexander V. Chernikov SYSINIT(rtnl_load, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, rtnl_load, NULL); 1327e5bf684SAlexander V. Chernikov 1337e5bf684SAlexander V. Chernikov static void 1347e5bf684SAlexander V. Chernikov rtnl_unload(void *u __unused) 1357e5bf684SAlexander V. Chernikov { 1367e5bf684SAlexander V. Chernikov netlink_callback_p = nlbridge_orig_p; 137*4bdf7f69SLin Ma netlink_unregister_proto(NETLINK_ROUTE); 1387e5bf684SAlexander V. Chernikov rtnl_ifaces_destroy(); 1397e5bf684SAlexander V. Chernikov rtnl_neighs_destroy(); 1407e5bf684SAlexander V. Chernikov 1417e5bf684SAlexander V. Chernikov /* Wait till all consumers read nlbridge data */ 142ab591c87SZhenlei Huang NET_EPOCH_WAIT(); 1437e5bf684SAlexander V. Chernikov } 1447e5bf684SAlexander V. Chernikov SYSUNINIT(rtnl_unload, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, rtnl_unload, NULL); 145