The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netlink/route/iface.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    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 __FBSDID("$FreeBSD$");
   30 #include "opt_inet.h"
   31 #include "opt_inet6.h"
   32 #include <sys/types.h>
   33 #include <sys/eventhandler.h>
   34 #include <sys/kernel.h>
   35 #include <sys/malloc.h>
   36 #include <sys/socket.h>
   37 #include <sys/sockio.h>
   38 #include <sys/syslog.h>
   39 
   40 #include <net/if.h>
   41 #include <net/if_dl.h>
   42 #include <net/if_media.h>
   43 #include <net/if_var.h>
   44 #include <net/if_clone.h>
   45 #include <net/route.h>
   46 #include <net/route/nhop.h>
   47 #include <net/route/route_ctl.h>
   48 #include <netlink/netlink.h>
   49 #include <netlink/netlink_ctl.h>
   50 #include <netlink/netlink_route.h>
   51 #include <netlink/route/route_var.h>
   52 
   53 #include <netinet6/scope6_var.h> /* scope deembedding */
   54 
   55 #define DEBUG_MOD_NAME  nl_iface
   56 #define DEBUG_MAX_LEVEL LOG_DEBUG3
   57 #include <netlink/netlink_debug.h>
   58 _DECLARE_DEBUG(LOG_DEBUG);
   59 
   60 struct netlink_walkargs {
   61         struct nl_writer *nw;
   62         struct nlmsghdr hdr;
   63         struct nlpcb *so;
   64         uint32_t fibnum;
   65         int family;
   66         int error;
   67         int count;
   68         int dumped;
   69 };
   70 
   71 static eventhandler_tag ifdetach_event, ifattach_event, iflink_event, ifaddr_event;
   72 
   73 static SLIST_HEAD(, nl_cloner) nl_cloners = SLIST_HEAD_INITIALIZER(nl_cloners);
   74 
   75 static struct sx rtnl_cloner_lock;
   76 SX_SYSINIT(rtnl_cloner_lock, &rtnl_cloner_lock, "rtnl cloner lock");
   77 
   78 static struct nl_cloner *rtnl_iface_find_cloner_locked(const char *name);
   79 
   80 /*
   81  * RTM_GETLINK request
   82  * sendto(3, {{len=32, type=RTM_GETLINK, flags=NLM_F_REQUEST|NLM_F_DUMP, seq=1641940952, pid=0},
   83  *  {ifi_family=AF_INET, ifi_type=ARPHRD_NETROM, ifi_index=0, ifi_flags=0, ifi_change=0}}, 32, 0, NULL, 0) = 32
   84  *
   85  * Reply:
   86  * {ifi_family=AF_UNSPEC, ifi_type=ARPHRD_ETHER, ifi_index=if_nametoindex("enp0s31f6"), ifi_flags=IFF_UP|IFF_BROADCAST|IFF_RUNNING|IFF_MULTICAST|IFF_LOWER_UP, ifi_change=0},
   87 {{nla_len=10, nla_type=IFLA_ADDRESS}, "\xfe\x54\x00\x52\x3e\x90"}
   88 
   89 [
   90 {{nla_len=14, nla_type=IFLA_IFNAME}, "enp0s31f6"},
   91 {{nla_len=8, nla_type=IFLA_TXQLEN}, 1000},
   92 {{nla_len=5, nla_type=IFLA_OPERSTATE}, 6},
   93 {{nla_len=5, nla_type=IFLA_LINKMODE}, 0},
   94 {{nla_len=8, nla_type=IFLA_MTU}, 1500},
   95 {{nla_len=8, nla_type=IFLA_MIN_MTU}, 68},
   96  {{nla_len=8, nla_type=IFLA_MAX_MTU}, 9000},
   97 {{nla_len=8, nla_type=IFLA_GROUP}, 0},
   98 {{nla_len=8, nla_type=IFLA_PROMISCUITY}, 0},
   99 {{nla_len=8, nla_type=IFLA_NUM_TX_QUEUES}, 1},
  100 {{nla_len=8, nla_type=IFLA_GSO_MAX_SEGS}, 65535},
  101 {{nla_len=8, nla_type=IFLA_GSO_MAX_SIZE}, 65536},
  102 {{nla_len=8, nla_type=IFLA_NUM_RX_QUEUES}, 1},
  103 {{nla_len=5, nla_type=IFLA_CARRIER}, 1},
  104 {{nla_len=13, nla_type=IFLA_QDISC}, "fq_codel"},
  105 {{nla_len=8, nla_type=IFLA_CARRIER_CHANGES}, 2},
  106 {{nla_len=5, nla_type=IFLA_PROTO_DOWN}, 0},
  107 {{nla_len=8, nla_type=IFLA_CARRIER_UP_COUNT}, 1},
  108 {{nla_len=8, nla_type=IFLA_CARRIER_DOWN_COUNT}, 1},
  109  */
  110 
  111 struct if_state {
  112         uint8_t         ifla_operstate;
  113         uint8_t         ifla_carrier;
  114 };
  115 
  116 static void
  117 get_operstate_ether(struct ifnet *ifp, struct if_state *pstate)
  118 {
  119         struct ifmediareq ifmr = {};
  120         int error;
  121         error = (*ifp->if_ioctl)(ifp, SIOCGIFMEDIA, (void *)&ifmr);
  122 
  123         if (error != 0) {
  124                 NL_LOG(LOG_DEBUG, "error calling SIOCGIFMEDIA on %s: %d",
  125                     if_name(ifp), error);
  126                 return;
  127         }
  128 
  129         switch (IFM_TYPE(ifmr.ifm_active)) {
  130         case IFM_ETHER:
  131                 if (ifmr.ifm_status & IFM_ACTIVE) {
  132                         pstate->ifla_carrier = 1;
  133                         if (ifp->if_flags & IFF_MONITOR)
  134                                 pstate->ifla_operstate = IF_OPER_DORMANT;
  135                         else
  136                                 pstate->ifla_operstate = IF_OPER_UP;
  137                 } else
  138                         pstate->ifla_operstate = IF_OPER_DOWN;
  139         }
  140 }
  141 
  142 static bool
  143 get_stats(struct nl_writer *nw, struct ifnet *ifp)
  144 {
  145         struct rtnl_link_stats64 *stats;
  146 
  147         int nla_len = sizeof(struct nlattr) + sizeof(*stats);
  148         struct nlattr *nla = nlmsg_reserve_data(nw, nla_len, struct nlattr);
  149         if (nla == NULL)
  150                 return (false);
  151         nla->nla_type = IFLA_STATS64;
  152         nla->nla_len = nla_len;
  153         stats = (struct rtnl_link_stats64 *)(nla + 1);
  154 
  155         stats->rx_packets = ifp->if_get_counter(ifp, IFCOUNTER_IPACKETS);
  156         stats->tx_packets = ifp->if_get_counter(ifp, IFCOUNTER_OPACKETS);
  157         stats->rx_bytes = ifp->if_get_counter(ifp, IFCOUNTER_IBYTES);
  158         stats->tx_bytes = ifp->if_get_counter(ifp, IFCOUNTER_OBYTES);
  159         stats->rx_errors = ifp->if_get_counter(ifp, IFCOUNTER_IERRORS);
  160         stats->tx_errors = ifp->if_get_counter(ifp, IFCOUNTER_OERRORS);
  161         stats->rx_dropped = ifp->if_get_counter(ifp, IFCOUNTER_IQDROPS);
  162         stats->tx_dropped = ifp->if_get_counter(ifp, IFCOUNTER_OQDROPS);
  163         stats->multicast = ifp->if_get_counter(ifp, IFCOUNTER_IMCASTS);
  164         stats->rx_nohandler = ifp->if_get_counter(ifp, IFCOUNTER_NOPROTO);
  165 
  166         return (true);
  167 }
  168 
  169 static void
  170 get_operstate(struct ifnet *ifp, struct if_state *pstate)
  171 {
  172         pstate->ifla_operstate = IF_OPER_UNKNOWN;
  173         pstate->ifla_carrier = 0; /* no carrier */
  174 
  175         switch (ifp->if_type) {
  176         case IFT_ETHER:
  177                 get_operstate_ether(ifp, pstate);
  178                 break;
  179         case IFT_LOOP:
  180                 if (ifp->if_flags & IFF_UP) {
  181                         pstate->ifla_operstate = IF_OPER_UP;
  182                         pstate->ifla_carrier = 1;
  183                 } else
  184                         pstate->ifla_operstate = IF_OPER_DOWN;
  185                 break;
  186         }
  187 }
  188 
  189 static unsigned
  190 ifp_flags_to_netlink(const struct ifnet *ifp)
  191 {
  192         return (ifp->if_flags | ifp->if_drv_flags);
  193 }
  194 
  195 #define LLADDR_CONST(s) ((const void *)((s)->sdl_data + (s)->sdl_nlen))
  196 static bool
  197 dump_sa(struct nl_writer *nw, int attr, const struct sockaddr *sa)
  198 {
  199         uint32_t addr_len = 0;
  200         const void *addr_data = NULL;
  201 #ifdef INET6
  202         struct in6_addr addr6;
  203 #endif
  204 
  205         if (sa == NULL)
  206                 return (true);
  207 
  208         switch (sa->sa_family) {
  209 #ifdef INET
  210         case AF_INET:
  211                 addr_len = sizeof(struct in_addr);
  212                 addr_data = &((const struct sockaddr_in *)sa)->sin_addr;
  213                 break;
  214 #endif
  215 #ifdef INET6
  216         case AF_INET6:
  217                 in6_splitscope(&((const struct sockaddr_in6 *)sa)->sin6_addr, &addr6, &addr_len);
  218                 addr_len = sizeof(struct in6_addr);
  219                 addr_data = &addr6;
  220                 break;
  221 #endif
  222         case AF_LINK:
  223                 addr_len = ((const struct sockaddr_dl *)sa)->sdl_alen;
  224                 addr_data = LLADDR_CONST((const struct sockaddr_dl *)sa);
  225                 break;
  226         default:
  227                 NL_LOG(LOG_DEBUG, "unsupported family: %d, skipping", sa->sa_family);
  228                 return (true);
  229         }
  230 
  231         return (nlattr_add(nw, attr, addr_len, addr_data));
  232 }
  233 
  234 /*
  235  * Dumps interface state, properties and metrics.
  236  * @nw: message writer
  237  * @ifp: target interface
  238  * @hdr: template header
  239  * @if_flags_mask: changed if_[drv]_flags bitmask
  240  *
  241  * This function is called without epoch and MAY sleep.
  242  */
  243 static bool
  244 dump_iface(struct nl_writer *nw, struct ifnet *ifp, const struct nlmsghdr *hdr,
  245     int if_flags_mask)
  246 {
  247         struct ifinfomsg *ifinfo;
  248 
  249         NL_LOG(LOG_DEBUG3, "dumping interface %s data", if_name(ifp));
  250 
  251         if (!nlmsg_reply(nw, hdr, sizeof(struct ifinfomsg)))
  252                 goto enomem;
  253 
  254         ifinfo = nlmsg_reserve_object(nw, struct ifinfomsg);
  255         ifinfo->ifi_family = AF_UNSPEC;
  256         ifinfo->__ifi_pad = 0;
  257         ifinfo->ifi_type = ifp->if_type;
  258         ifinfo->ifi_index = ifp->if_index;
  259         ifinfo->ifi_flags = ifp_flags_to_netlink(ifp);
  260         ifinfo->ifi_change = if_flags_mask;
  261 
  262         struct if_state ifs = {};
  263         get_operstate(ifp, &ifs);
  264 
  265         if (ifs.ifla_operstate == IF_OPER_UP)
  266                 ifinfo->ifi_flags |= IFF_LOWER_UP;
  267 
  268         nlattr_add_string(nw, IFLA_IFNAME, if_name(ifp));
  269         nlattr_add_u8(nw, IFLA_OPERSTATE, ifs.ifla_operstate);
  270         nlattr_add_u8(nw, IFLA_CARRIER, ifs.ifla_carrier);
  271 
  272 /*
  273         nlattr_add_u8(nw, IFLA_PROTO_DOWN, val);
  274         nlattr_add_u8(nw, IFLA_LINKMODE, val);
  275 */
  276         if ((ifp->if_addr != NULL)) {
  277                 dump_sa(nw, IFLA_ADDRESS, ifp->if_addr->ifa_addr);
  278         }
  279 
  280         if ((ifp->if_broadcastaddr != NULL)) {
  281                 nlattr_add(nw, IFLA_BROADCAST, ifp->if_addrlen,
  282                     ifp->if_broadcastaddr);
  283         }
  284 
  285         nlattr_add_u32(nw, IFLA_MTU, ifp->if_mtu);
  286 /*
  287         nlattr_add_u32(nw, IFLA_MIN_MTU, 60);
  288         nlattr_add_u32(nw, IFLA_MAX_MTU, 9000);
  289         nlattr_add_u32(nw, IFLA_GROUP, 0);
  290 */
  291 
  292         if (ifp->if_description != NULL)
  293                 nlattr_add_string(nw, IFLA_IFALIAS, ifp->if_description);
  294 
  295         get_stats(nw, ifp);
  296 
  297         uint32_t val = (ifp->if_flags & IFF_PROMISC) != 0;
  298         nlattr_add_u32(nw, IFLA_PROMISCUITY, val);
  299 
  300         sx_slock(&rtnl_cloner_lock);
  301         struct nl_cloner *cloner = rtnl_iface_find_cloner_locked(ifp->if_dname);
  302         if (cloner != NULL && cloner->dump_f != NULL) {
  303                 /* Ignore any dump error */
  304                 cloner->dump_f(ifp, nw);
  305         }
  306         sx_sunlock(&rtnl_cloner_lock);
  307 
  308         if (nlmsg_end(nw))
  309                 return (true);
  310 
  311 enomem:
  312         NL_LOG(LOG_DEBUG, "unable to dump interface %s state (ENOMEM)", if_name(ifp));
  313         nlmsg_abort(nw);
  314         return (false);
  315 }
  316 
  317 static bool
  318 check_ifmsg(void *hdr, struct nl_pstate *npt)
  319 {
  320         struct ifinfomsg *ifm = hdr;
  321 
  322         if (ifm->__ifi_pad != 0 || ifm->ifi_type != 0 ||
  323             ifm->ifi_flags != 0 || ifm->ifi_change != 0) {
  324                 nlmsg_report_err_msg(npt,
  325                     "strict checking: non-zero values in ifinfomsg header");
  326                 return (false);
  327         }
  328 
  329         return (true);
  330 }
  331 
  332 #define _IN(_field)     offsetof(struct ifinfomsg, _field)
  333 #define _OUT(_field)    offsetof(struct nl_parsed_link, _field)
  334 static const struct nlfield_parser nlf_p_if[] = {
  335         { .off_in = _IN(ifi_type), .off_out = _OUT(ifi_type), .cb = nlf_get_u16 },
  336         { .off_in = _IN(ifi_index), .off_out = _OUT(ifi_index), .cb = nlf_get_u32 },
  337         { .off_in = _IN(ifi_flags), .off_out = _OUT(ifi_flags), .cb = nlf_get_u32 },
  338         { .off_in = _IN(ifi_change), .off_out = _OUT(ifi_change), .cb = nlf_get_u32 },
  339 };
  340 
  341 static const struct nlattr_parser nla_p_linfo[] = {
  342         { .type = IFLA_INFO_KIND, .off = _OUT(ifla_cloner), .cb = nlattr_get_stringn },
  343         { .type = IFLA_INFO_DATA, .off = _OUT(ifla_idata), .cb = nlattr_get_nla },
  344 };
  345 NL_DECLARE_ATTR_PARSER(linfo_parser, nla_p_linfo);
  346 
  347 static const struct nlattr_parser nla_p_if[] = {
  348         { .type = IFLA_IFNAME, .off = _OUT(ifla_ifname), .cb = nlattr_get_string },
  349         { .type = IFLA_MTU, .off = _OUT(ifla_mtu), .cb = nlattr_get_uint32 },
  350         { .type = IFLA_LINK, .off = _OUT(ifi_index), .cb = nlattr_get_uint32 },
  351         { .type = IFLA_LINKINFO, .arg = &linfo_parser, .cb = nlattr_get_nested },
  352         { .type = IFLA_IFALIAS, .off = _OUT(ifla_ifalias), .cb = nlattr_get_string },
  353         { .type = IFLA_GROUP, .off = _OUT(ifla_group), .cb = nlattr_get_string },
  354         { .type = IFLA_ALT_IFNAME, .off = _OUT(ifla_ifname), .cb = nlattr_get_string },
  355 };
  356 #undef _IN
  357 #undef _OUT
  358 NL_DECLARE_STRICT_PARSER(ifmsg_parser, struct ifinfomsg, check_ifmsg, nlf_p_if, nla_p_if);
  359 
  360 static bool
  361 match_iface(struct nl_parsed_link *attrs, struct ifnet *ifp)
  362 {
  363         if (attrs->ifi_index != 0 && attrs->ifi_index != ifp->if_index)
  364                 return (false);
  365         if (attrs->ifi_type != 0 && attrs->ifi_index != ifp->if_type)
  366                 return (false);
  367         if (attrs->ifla_ifname != NULL && strcmp(attrs->ifla_ifname, if_name(ifp)))
  368                 return (false);
  369         /* TODO: add group match */
  370 
  371         return (true);
  372 }
  373 
  374 /*
  375  * {nlmsg_len=52, nlmsg_type=RTM_GETLINK, nlmsg_flags=NLM_F_REQUEST, nlmsg_seq=1662842818, nlmsg_pid=0},
  376  *  {ifi_family=AF_PACKET, ifi_type=ARPHRD_NETROM, ifi_index=0, ifi_flags=0, ifi_change=0},
  377  *   [
  378  *    [{nla_len=10, nla_type=IFLA_IFNAME}, "vnet9"],
  379  *    [{nla_len=8, nla_type=IFLA_EXT_MASK}, RTEXT_FILTER_VF]
  380  *   ]
  381  */
  382 static int
  383 rtnl_handle_getlink(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_pstate *npt)
  384 {
  385         struct epoch_tracker et;
  386         struct ifnet *ifp;
  387         int error = 0;
  388 
  389         struct nl_parsed_link attrs = {};
  390         error = nl_parse_nlmsg(hdr, &ifmsg_parser, npt, &attrs);
  391         if (error != 0)
  392                 return (error);
  393 
  394         struct netlink_walkargs wa = {
  395                 .so = nlp,
  396                 .nw = npt->nw,
  397                 .hdr.nlmsg_pid = hdr->nlmsg_pid,
  398                 .hdr.nlmsg_seq = hdr->nlmsg_seq,
  399                 .hdr.nlmsg_flags = hdr->nlmsg_flags,
  400                 .hdr.nlmsg_type = NL_RTM_NEWLINK,
  401         };
  402 
  403         /* Fast track for an interface w/ explicit name or index match */
  404         if ((attrs.ifi_index != 0) || (attrs.ifla_ifname != NULL)) {
  405                 if (attrs.ifi_index != 0) {
  406                         NLP_LOG(LOG_DEBUG3, nlp, "fast track -> searching index %u",
  407                             attrs.ifi_index);
  408                         NET_EPOCH_ENTER(et);
  409                         ifp = ifnet_byindex_ref(attrs.ifi_index);
  410                         NET_EPOCH_EXIT(et);
  411                 } else {
  412                         NLP_LOG(LOG_DEBUG3, nlp, "fast track -> searching name %s",
  413                             attrs.ifla_ifname);
  414                         ifp = ifunit_ref(attrs.ifla_ifname);
  415                 }
  416 
  417                 if (ifp != NULL) {
  418                         if (match_iface(&attrs, ifp)) {
  419                                 if (!dump_iface(wa.nw, ifp, &wa.hdr, 0))
  420                                         error = ENOMEM;
  421                         } else
  422                                 error = ENODEV;
  423                         if_rele(ifp);
  424                 } else
  425                         error = ENODEV;
  426                 return (error);
  427         }
  428 
  429         /* Always treat non-direct-match as a multipart message */
  430         wa.hdr.nlmsg_flags |= NLM_F_MULTI;
  431 
  432         /*
  433          * Fetching some link properties require performing ioctl's that may be blocking.
  434          * Address it by saving referenced pointers of the matching links,
  435          * exiting from epoch and going through the list one-by-one.
  436          */
  437 
  438         NL_LOG(LOG_DEBUG2, "Start dump");
  439 
  440         struct ifnet **match_array;
  441         int offset = 0, base_count = 16; /* start with 128 bytes */
  442         match_array = malloc(base_count * sizeof(void *), M_TEMP, M_NOWAIT);
  443 
  444         NLP_LOG(LOG_DEBUG3, nlp, "MATCHING: index=%u type=%d name=%s",
  445             attrs.ifi_index, attrs.ifi_type, attrs.ifla_ifname);
  446         NET_EPOCH_ENTER(et);
  447         CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
  448                 wa.count++;
  449                 if (match_iface(&attrs, ifp)) {
  450                         if (offset < base_count) {
  451                                 if (!if_try_ref(ifp))
  452                                         continue;
  453                                 match_array[offset++] = ifp;
  454                                 continue;
  455                         }
  456                         /* Too many matches, need to reallocate */
  457                         struct ifnet **new_array;
  458                         int sz = base_count * sizeof(void *);
  459                         base_count *= 2;
  460                         new_array = malloc(sz * 2, M_TEMP, M_NOWAIT);
  461                         if (new_array == NULL) {
  462                                 error = ENOMEM;
  463                                 break;
  464                         }
  465                         memcpy(new_array, match_array, sz);
  466                         free(match_array, M_TEMP);
  467                         match_array = new_array;
  468                 }
  469         }
  470         NET_EPOCH_EXIT(et);
  471 
  472         NL_LOG(LOG_DEBUG2, "Matched %d interface(s), dumping", offset);
  473         for (int i = 0; error == 0 && i < offset; i++) {
  474                 if (!dump_iface(wa.nw, match_array[i], &wa.hdr, 0))
  475                         error = ENOMEM;
  476         }
  477         for (int i = 0; i < offset; i++)
  478                 if_rele(match_array[i]);
  479         free(match_array, M_TEMP);
  480 
  481         NL_LOG(LOG_DEBUG2, "End dump, iterated %d dumped %d", wa.count, wa.dumped);
  482 
  483         if (!nlmsg_end_dump(wa.nw, error, &wa.hdr)) {
  484                 NL_LOG(LOG_DEBUG, "Unable to finalize the dump");
  485                 return (ENOMEM);
  486         }
  487 
  488         return (error);
  489 }
  490 
  491 /*
  492  * sendmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base=[
  493  * {nlmsg_len=60, nlmsg_type=RTM_NEWLINK, nlmsg_flags=NLM_F_REQUEST|NLM_F_ACK|NLM_F_EXCL|NLM_F_CREATE, nlmsg_seq=1662715618, nlmsg_pid=0},
  494  *  {ifi_family=AF_UNSPEC, ifi_type=ARPHRD_NETROM, ifi_index=0, ifi_flags=0, ifi_change=0},
  495  *   {nla_len=11, nla_type=IFLA_IFNAME}, "dummy0"],
  496  *   [
  497  *    {nla_len=16, nla_type=IFLA_LINKINFO},
  498  *     [
  499  *      {nla_len=9, nla_type=IFLA_INFO_KIND}, "dummy"...
  500  *     ]
  501  *    ]
  502  */
  503 
  504 static int
  505 rtnl_handle_dellink(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_pstate *npt)
  506 {
  507         struct epoch_tracker et;
  508         struct ifnet *ifp;
  509         int error;
  510 
  511         struct nl_parsed_link attrs = {};
  512         error = nl_parse_nlmsg(hdr, &ifmsg_parser, npt, &attrs);
  513         if (error != 0)
  514                 return (error);
  515 
  516         NET_EPOCH_ENTER(et);
  517         ifp = ifnet_byindex_ref(attrs.ifi_index);
  518         NET_EPOCH_EXIT(et);
  519         if (ifp == NULL) {
  520                 NLP_LOG(LOG_DEBUG, nlp, "unable to find interface %u", attrs.ifi_index);
  521                 return (ENOENT);
  522         }
  523         NLP_LOG(LOG_DEBUG3, nlp, "mapped ifindex %u to %s", attrs.ifi_index, if_name(ifp));
  524 
  525         sx_xlock(&ifnet_detach_sxlock);
  526         error = if_clone_destroy(if_name(ifp));
  527         sx_xunlock(&ifnet_detach_sxlock);
  528 
  529         NLP_LOG(LOG_DEBUG2, nlp, "deleting interface %s returned %d", if_name(ifp), error);
  530 
  531         if_rele(ifp);
  532         return (error);
  533 }
  534 
  535 /*
  536  * New link:
  537  * type=RTM_NEWLINK, flags=NLM_F_REQUEST|NLM_F_ACK|NLM_F_EXCL|NLM_F_CREATE, seq=1668185590, pid=0},
  538  *   {ifi_family=AF_UNSPEC, ifi_type=ARPHRD_NETROM, ifi_index=0, ifi_flags=0, ifi_change=0}
  539  *    [
  540  *     {{nla_len=8, nla_type=IFLA_MTU}, 123},
  541  *     {{nla_len=10, nla_type=IFLA_IFNAME}, "vlan1"},
  542  *     {{nla_len=24, nla_type=IFLA_LINKINFO},
  543  *      [
  544  *       {{nla_len=8, nla_type=IFLA_INFO_KIND}, "vlan"...},
  545  *       {{nla_len=12, nla_type=IFLA_INFO_DATA}, "\x06\x00\x01\x00\x7b\x00\x00\x00"}]}]}
  546  *
  547  * Update link:
  548  * type=RTM_NEWLINK, flags=NLM_F_REQUEST|NLM_F_ACK, seq=1668185923, pid=0},
  549  * {ifi_family=AF_UNSPEC, ifi_type=ARPHRD_NETROM, ifi_index=if_nametoindex("lo"), ifi_flags=0, ifi_change=0},
  550  * {{nla_len=8, nla_type=IFLA_MTU}, 123}}
  551  *
  552  *
  553  * Check command availability:
  554  * type=RTM_NEWLINK, flags=NLM_F_REQUEST|NLM_F_ACK, seq=0, pid=0},
  555  *  {ifi_family=AF_UNSPEC, ifi_type=ARPHRD_NETROM, ifi_index=0, ifi_flags=0, ifi_change=0}
  556  */
  557 
  558 
  559 static int
  560 create_link(struct nlmsghdr *hdr, struct nl_parsed_link *lattrs,
  561     struct nlattr_bmask *bm, struct nlpcb *nlp, struct nl_pstate *npt)
  562 {
  563         if (lattrs->ifla_ifname == NULL || strlen(lattrs->ifla_ifname) == 0) {
  564                 NLMSG_REPORT_ERR_MSG(npt, "empty IFLA_IFNAME attribute");
  565                 return (EINVAL);
  566         }
  567         if (lattrs->ifla_cloner == NULL || strlen(lattrs->ifla_cloner) == 0) {
  568                 NLMSG_REPORT_ERR_MSG(npt, "empty IFLA_INFO_KIND attribute");
  569                 return (EINVAL);
  570         }
  571 
  572         bool found = false;
  573         int error = 0;
  574 
  575         sx_slock(&rtnl_cloner_lock);
  576         struct nl_cloner *cloner = rtnl_iface_find_cloner_locked(lattrs->ifla_cloner);
  577         if (cloner != NULL) {
  578                 found = true;
  579                 error = cloner->create_f(lattrs, bm, nlp, npt);
  580         }
  581         sx_sunlock(&rtnl_cloner_lock);
  582 
  583         if (!found)
  584                 error = generic_cloner.create_f(lattrs, bm, nlp, npt);
  585 
  586         return (error);
  587 }
  588 
  589 static int
  590 modify_link(struct nlmsghdr *hdr, struct nl_parsed_link *lattrs,
  591     struct nlattr_bmask *bm, struct nlpcb *nlp, struct nl_pstate *npt)
  592 {
  593         struct ifnet *ifp = NULL;
  594         struct epoch_tracker et;
  595 
  596         if (lattrs->ifi_index == 0 && lattrs->ifla_ifname == NULL) {
  597                 /*
  598                  * Applications like ip(8) verify RTM_NEWLINK command
  599                  * existence by calling it with empty arguments. Always
  600                  * return "innocent" error in that case.
  601                  */
  602                 NLMSG_REPORT_ERR_MSG(npt, "empty ifi_index field");
  603                 return (EPERM);
  604         }
  605 
  606         if (lattrs->ifi_index != 0) {
  607                 NET_EPOCH_ENTER(et);
  608                 ifp = ifnet_byindex_ref(lattrs->ifi_index);
  609                 NET_EPOCH_EXIT(et);
  610                 if (ifp == NULL) {
  611                         NLMSG_REPORT_ERR_MSG(npt, "unable to find interface #%u",
  612                             lattrs->ifi_index);
  613                         return (ENOENT);
  614                 }
  615         }
  616 
  617         if (ifp == NULL && lattrs->ifla_ifname != NULL) {
  618                 ifp = ifunit_ref(lattrs->ifla_ifname);
  619                 if (ifp == NULL) {
  620                         NLMSG_REPORT_ERR_MSG(npt, "unable to find interface %s",
  621                             lattrs->ifla_ifname);
  622                         return (ENOENT);
  623                 }
  624         }
  625 
  626         MPASS(ifp != NULL);
  627 
  628         /*
  629          * There can be multiple kinds of interfaces:
  630          * 1) cloned, with additional options
  631          * 2) cloned, but w/o additional options
  632          * 3) non-cloned (e.g. "physical).
  633          *
  634          * Thus, try to find cloner-specific callback and fallback to the
  635          * "default" handler if not found.
  636          */
  637         bool found = false;
  638         int error = 0;
  639 
  640         sx_slock(&rtnl_cloner_lock);
  641         struct nl_cloner *cloner = rtnl_iface_find_cloner_locked(ifp->if_dname);
  642         if (cloner != NULL) {
  643                 found = true;
  644                 error = cloner->modify_f(ifp, lattrs, bm, nlp, npt);
  645         }
  646         sx_sunlock(&rtnl_cloner_lock);
  647 
  648         if (!found)
  649                 error = generic_cloner.modify_f(ifp, lattrs, bm, nlp, npt);
  650 
  651         if_rele(ifp);
  652 
  653         return (error);
  654 }
  655 
  656 
  657 static int
  658 rtnl_handle_newlink(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_pstate *npt)
  659 {
  660         struct nlattr_bmask bm;
  661         int error;
  662 
  663         struct nl_parsed_link attrs = {};
  664         error = nl_parse_nlmsg(hdr, &ifmsg_parser, npt, &attrs);
  665         if (error != 0)
  666                 return (error);
  667         nl_get_attrs_bmask_nlmsg(hdr, &ifmsg_parser, &bm);
  668 
  669         if (hdr->nlmsg_flags & NLM_F_CREATE)
  670                 return (create_link(hdr, &attrs, &bm, nlp, npt));
  671         else
  672                 return (modify_link(hdr, &attrs, &bm, nlp, npt));
  673 }
  674 
  675 struct nl_parsed_ifa {
  676         uint8_t         ifa_family;
  677         uint8_t         ifa_prefixlen;
  678         uint8_t         ifa_scope;
  679         uint32_t        ifa_index;
  680         uint32_t        ifa_flags;
  681         struct sockaddr *ifa_address;
  682         struct sockaddr *ifa_local;
  683 };
  684 
  685 #define _IN(_field)     offsetof(struct ifaddrmsg, _field)
  686 #define _OUT(_field)    offsetof(struct nl_parsed_ifa, _field)
  687 static const struct nlfield_parser nlf_p_ifa[] = {
  688         { .off_in = _IN(ifa_family), .off_out = _OUT(ifa_family), .cb = nlf_get_u8 },
  689         { .off_in = _IN(ifa_prefixlen), .off_out = _OUT(ifa_prefixlen), .cb = nlf_get_u8 },
  690         { .off_in = _IN(ifa_scope), .off_out = _OUT(ifa_scope), .cb = nlf_get_u8 },
  691         { .off_in = _IN(ifa_flags), .off_out = _OUT(ifa_flags), .cb = nlf_get_u8_u32 },
  692         { .off_in = _IN(ifa_index), .off_out = _OUT(ifa_index), .cb = nlf_get_u32 },
  693 };
  694 
  695 static const struct nlattr_parser nla_p_ifa[] = {
  696         { .type = IFA_ADDRESS, .off = _OUT(ifa_address), .cb = nlattr_get_ip },
  697         { .type = IFA_LOCAL, .off = _OUT(ifa_local), .cb = nlattr_get_ip },
  698         { .type = IFA_FLAGS, .off = _OUT(ifa_flags), .cb = nlattr_get_uint32 },
  699 };
  700 #undef _IN
  701 #undef _OUT
  702 NL_DECLARE_PARSER(ifaddrmsg_parser, struct ifaddrmsg, nlf_p_ifa, nla_p_ifa);
  703 
  704 
  705 /*
  706 
  707 {ifa_family=AF_INET, ifa_prefixlen=8, ifa_flags=IFA_F_PERMANENT, ifa_scope=RT_SCOPE_HOST, ifa_index=if_nametoindex("lo")},
  708  [
  709         {{nla_len=8, nla_type=IFA_ADDRESS}, inet_addr("127.0.0.1")},
  710         {{nla_len=8, nla_type=IFA_LOCAL}, inet_addr("127.0.0.1")},
  711         {{nla_len=7, nla_type=IFA_LABEL}, "lo"},
  712         {{nla_len=8, nla_type=IFA_FLAGS}, IFA_F_PERMANENT},
  713         {{nla_len=20, nla_type=IFA_CACHEINFO}, {ifa_prefered=4294967295, ifa_valid=4294967295, cstamp=3619, tstamp=3619}}]},
  714 ---
  715 
  716 {{len=72, type=RTM_NEWADDR, flags=NLM_F_MULTI, seq=1642191126, pid=566735},
  717  {ifa_family=AF_INET6, ifa_prefixlen=96, ifa_flags=IFA_F_PERMANENT, ifa_scope=RT_SCOPE_UNIVERSE, ifa_index=if_nametoindex("virbr0")},
  718    [
  719     {{nla_len=20, nla_type=IFA_ADDRESS}, inet_pton(AF_INET6, "2a01:4f8:13a:70c:ffff::1")},
  720    {{nla_len=20, nla_type=IFA_CACHEINFO}, {ifa_prefered=4294967295, ifa_valid=4294967295, cstamp=4283, tstamp=4283}},
  721    {{nla_len=8, nla_type=IFA_FLAGS}, IFA_F_PERMANENT}]},
  722 */
  723 
  724 static uint8_t
  725 ifa_get_scope(const struct ifaddr *ifa)
  726 {
  727         const struct sockaddr *sa;
  728         uint8_t addr_scope = RT_SCOPE_UNIVERSE;
  729 
  730         sa = ifa->ifa_addr;
  731         switch (sa->sa_family) {
  732 #ifdef INET
  733         case AF_INET:
  734                 {
  735                         struct in_addr addr;
  736                         addr = ((const struct sockaddr_in *)sa)->sin_addr;
  737                         if (IN_LOOPBACK(addr.s_addr))
  738                                 addr_scope = RT_SCOPE_HOST;
  739                         else if (IN_LINKLOCAL(addr.s_addr))
  740                                 addr_scope = RT_SCOPE_LINK;
  741                         break;
  742                 }
  743 #endif
  744 #ifdef INET6
  745         case AF_INET6:
  746                 {
  747                         const struct in6_addr *addr;
  748                         addr = &((const struct sockaddr_in6 *)sa)->sin6_addr;
  749                         if (IN6_IS_ADDR_LOOPBACK(addr))
  750                                 addr_scope = RT_SCOPE_HOST;
  751                         else if (IN6_IS_ADDR_LINKLOCAL(addr))
  752                                 addr_scope = RT_SCOPE_LINK;
  753                         break;
  754                 }
  755 #endif
  756         }
  757 
  758         return (addr_scope);
  759 }
  760 
  761 static uint8_t
  762 inet6_get_plen(const struct in6_addr *addr)
  763 {
  764 
  765         return (bitcount32(addr->s6_addr32[0]) + bitcount32(addr->s6_addr32[1]) +
  766             bitcount32(addr->s6_addr32[2]) + bitcount32(addr->s6_addr32[3]));
  767 }
  768 
  769 static uint8_t
  770 get_sa_plen(const struct sockaddr *sa)
  771 {
  772 #ifdef INET
  773         const struct in_addr *paddr;
  774 #endif
  775 #ifdef INET6
  776         const struct in6_addr *paddr6;
  777 #endif
  778 
  779         switch (sa->sa_family) {
  780 #ifdef INET
  781         case AF_INET:
  782                 if (sa == NULL)
  783                         return (32);
  784                 paddr = &(((const struct sockaddr_in *)sa)->sin_addr);
  785                 return bitcount32(paddr->s_addr);;
  786 #endif
  787 #ifdef INET6
  788         case AF_INET6:
  789                 if (sa == NULL)
  790                         return (128);
  791                 paddr6 = &(((const struct sockaddr_in6 *)sa)->sin6_addr);
  792                 return inet6_get_plen(paddr6);
  793 #endif
  794         }
  795 
  796         return (0);
  797 }
  798 
  799 
  800 /*
  801  * {'attrs': [('IFA_ADDRESS', '12.0.0.1'),
  802            ('IFA_LOCAL', '12.0.0.1'),
  803            ('IFA_LABEL', 'eth10'),
  804            ('IFA_FLAGS', 128),
  805            ('IFA_CACHEINFO', {'ifa_preferred': 4294967295, 'ifa_valid': 4294967295, 'cstamp': 63745746, 'tstamp': 63745746})],
  806  */
  807 static bool
  808 dump_iface_addr(struct nl_writer *nw, struct ifnet *ifp, struct ifaddr *ifa,
  809     const struct nlmsghdr *hdr)
  810 {
  811         struct ifaddrmsg *ifamsg;
  812         struct sockaddr *sa = ifa->ifa_addr;
  813 
  814         NL_LOG(LOG_DEBUG3, "dumping ifa %p type %s(%d) for interface %s",
  815             ifa, rib_print_family(sa->sa_family), sa->sa_family, if_name(ifp));
  816 
  817         if (!nlmsg_reply(nw, hdr, sizeof(struct ifaddrmsg)))
  818                 goto enomem;
  819 
  820         ifamsg = nlmsg_reserve_object(nw, struct ifaddrmsg);
  821         ifamsg->ifa_family = sa->sa_family;
  822         ifamsg->ifa_prefixlen = get_sa_plen(ifa->ifa_netmask);
  823         ifamsg->ifa_flags = 0; // ifa_flags is useless
  824         ifamsg->ifa_scope = ifa_get_scope(ifa);
  825         ifamsg->ifa_index = ifp->if_index;
  826 
  827         if (ifp->if_flags & IFF_POINTOPOINT) {
  828                 dump_sa(nw, IFA_ADDRESS, ifa->ifa_dstaddr);
  829                 dump_sa(nw, IFA_LOCAL, sa);
  830         } else {
  831                 dump_sa(nw, IFA_ADDRESS, sa);
  832 #ifdef INET
  833                 /*
  834                  * In most cases, IFA_ADDRESS == IFA_LOCAL
  835                  * Skip IFA_LOCAL for anything except INET
  836                  */
  837                 if (sa->sa_family == AF_INET)
  838                         dump_sa(nw, IFA_LOCAL, sa);
  839 #endif
  840         }
  841         if (ifp->if_flags & IFF_BROADCAST)
  842                 dump_sa(nw, IFA_BROADCAST, ifa->ifa_broadaddr);
  843 
  844         nlattr_add_string(nw, IFA_LABEL, if_name(ifp));
  845 
  846         uint32_t val = 0; // ifa->ifa_flags;
  847         nlattr_add_u32(nw, IFA_FLAGS, val);
  848 
  849         if (nlmsg_end(nw))
  850                 return (true);
  851 enomem:
  852         NL_LOG(LOG_DEBUG, "Failed to dump ifa type %s(%d) for interface %s",
  853             rib_print_family(sa->sa_family), sa->sa_family, if_name(ifp));
  854         nlmsg_abort(nw);
  855         return (false);
  856 }
  857 
  858 static int
  859 dump_iface_addrs(struct netlink_walkargs *wa, struct ifnet *ifp)
  860 {
  861         struct ifaddr *ifa;
  862 
  863         CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
  864                 if (wa->family != 0 && wa->family != ifa->ifa_addr->sa_family)
  865                         continue;
  866                 if (ifa->ifa_addr->sa_family == AF_LINK)
  867                         continue;
  868                 wa->count++;
  869                 if (!dump_iface_addr(wa->nw, ifp, ifa, &wa->hdr))
  870                         return (ENOMEM);
  871                 wa->dumped++;
  872         }
  873 
  874         return (0);
  875 }
  876 
  877 static int
  878 rtnl_handle_getaddr(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_pstate *npt)
  879 {
  880         struct ifnet *ifp;
  881         int error = 0;
  882 
  883         struct nl_parsed_ifa attrs = {};
  884         error = nl_parse_nlmsg(hdr, &ifaddrmsg_parser, npt, &attrs);
  885         if (error != 0)
  886                 return (error);
  887 
  888         struct netlink_walkargs wa = {
  889                 .so = nlp,
  890                 .nw = npt->nw,
  891                 .family = attrs.ifa_family,
  892                 .hdr.nlmsg_pid = hdr->nlmsg_pid,
  893                 .hdr.nlmsg_seq = hdr->nlmsg_seq,
  894                 .hdr.nlmsg_flags = hdr->nlmsg_flags | NLM_F_MULTI,
  895                 .hdr.nlmsg_type = NL_RTM_NEWADDR,
  896         };
  897 
  898         NL_LOG(LOG_DEBUG2, "Start dump");
  899 
  900         if (attrs.ifa_index != 0) {
  901                 ifp = ifnet_byindex(attrs.ifa_index);
  902                 if (ifp == NULL)
  903                         error = ENOENT;
  904                 else
  905                         error = dump_iface_addrs(&wa, ifp);
  906         } else {
  907                 CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
  908                         error = dump_iface_addrs(&wa, ifp);
  909                         if (error != 0)
  910                                 break;
  911                 }
  912         }
  913 
  914         NL_LOG(LOG_DEBUG2, "End dump, iterated %d dumped %d", wa.count, wa.dumped);
  915 
  916         if (!nlmsg_end_dump(wa.nw, error, &wa.hdr)) {
  917                 NL_LOG(LOG_DEBUG, "Unable to finalize the dump");
  918                 return (ENOMEM);
  919         }
  920 
  921         return (error);
  922 }
  923 
  924 static void
  925 rtnl_handle_ifaddr(void *arg __unused, struct ifaddr *ifa, int cmd)
  926 {
  927         struct nlmsghdr hdr = {};
  928         struct nl_writer nw = {};
  929         uint32_t group = 0;
  930 
  931         switch (ifa->ifa_addr->sa_family) {
  932 #ifdef INET
  933         case AF_INET:
  934                 group = RTNLGRP_IPV4_IFADDR;
  935                 break;
  936 #endif
  937 #ifdef INET6
  938         case AF_INET6:
  939                 group = RTNLGRP_IPV6_IFADDR;
  940                 break;
  941 #endif
  942         default:
  943                 NL_LOG(LOG_DEBUG2, "ifa notification for unknown AF: %d",
  944                     ifa->ifa_addr->sa_family);
  945                 return;
  946         }
  947 
  948         if (!nl_has_listeners(NETLINK_ROUTE, group))
  949                 return;
  950 
  951         if (!nlmsg_get_group_writer(&nw, NLMSG_LARGE, NETLINK_ROUTE, group)) {
  952                 NL_LOG(LOG_DEBUG, "error allocating group writer");
  953                 return;
  954         }
  955 
  956         hdr.nlmsg_type = (cmd == RTM_DELETE) ? NL_RTM_DELADDR : NL_RTM_NEWADDR;
  957 
  958         dump_iface_addr(&nw, ifa->ifa_ifp, ifa, &hdr);
  959         nlmsg_flush(&nw);
  960 }
  961 
  962 static void
  963 rtnl_handle_ifevent(struct ifnet *ifp, int nlmsg_type, int if_flags_mask)
  964 {
  965         struct nlmsghdr hdr = { .nlmsg_type = nlmsg_type };
  966         struct nl_writer nw = {};
  967 
  968         if (!nl_has_listeners(NETLINK_ROUTE, RTNLGRP_LINK))
  969                 return;
  970 
  971         if (!nlmsg_get_group_writer(&nw, NLMSG_LARGE, NETLINK_ROUTE, RTNLGRP_LINK)) {
  972                 NL_LOG(LOG_DEBUG, "error allocating mbuf");
  973                 return;
  974         }
  975         dump_iface(&nw, ifp, &hdr, if_flags_mask);
  976         nlmsg_flush(&nw);
  977 }
  978 
  979 static void
  980 rtnl_handle_ifattach(void *arg, struct ifnet *ifp)
  981 {
  982         NL_LOG(LOG_DEBUG2, "ifnet %s", if_name(ifp));
  983         rtnl_handle_ifevent(ifp, NL_RTM_NEWLINK, 0);
  984 }
  985 
  986 static void
  987 rtnl_handle_ifdetach(void *arg, struct ifnet *ifp)
  988 {
  989         NL_LOG(LOG_DEBUG2, "ifnet %s", if_name(ifp));
  990         rtnl_handle_ifevent(ifp, NL_RTM_DELLINK, 0);
  991 }
  992 
  993 static void
  994 rtnl_handle_iflink(void *arg, struct ifnet *ifp)
  995 {
  996         NL_LOG(LOG_DEBUG2, "ifnet %s", if_name(ifp));
  997         rtnl_handle_ifevent(ifp, NL_RTM_NEWLINK, 0);
  998 }
  999 
 1000 void
 1001 rtnl_handle_ifnet_event(struct ifnet *ifp, int if_flags_mask)
 1002 {
 1003         NL_LOG(LOG_DEBUG2, "ifnet %s", if_name(ifp));
 1004         rtnl_handle_ifevent(ifp, NL_RTM_NEWLINK, if_flags_mask);
 1005 }
 1006 
 1007 static const struct rtnl_cmd_handler cmd_handlers[] = {
 1008         {
 1009                 .cmd = NL_RTM_GETLINK,
 1010                 .name = "RTM_GETLINK",
 1011                 .cb = &rtnl_handle_getlink,
 1012                 .flags = RTNL_F_NOEPOCH,
 1013         },
 1014         {
 1015                 .cmd = NL_RTM_DELLINK,
 1016                 .name = "RTM_DELLINK",
 1017                 .cb = &rtnl_handle_dellink,
 1018                 .priv = PRIV_NET_IFDESTROY,
 1019                 .flags = RTNL_F_NOEPOCH,
 1020         },
 1021         {
 1022                 .cmd = NL_RTM_NEWLINK,
 1023                 .name = "RTM_NEWLINK",
 1024                 .cb = &rtnl_handle_newlink,
 1025                 .priv = PRIV_NET_IFCREATE,
 1026                 .flags = RTNL_F_NOEPOCH,
 1027         },
 1028         {
 1029                 .cmd = NL_RTM_GETADDR,
 1030                 .name = "RTM_GETADDR",
 1031                 .cb = &rtnl_handle_getaddr,
 1032         },
 1033         {
 1034                 .cmd = NL_RTM_NEWADDR,
 1035                 .name = "RTM_NEWADDR",
 1036                 .cb = &rtnl_handle_getaddr,
 1037         },
 1038         {
 1039                 .cmd = NL_RTM_DELADDR,
 1040                 .name = "RTM_DELADDR",
 1041                 .cb = &rtnl_handle_getaddr,
 1042         },
 1043 };
 1044 
 1045 static const struct nlhdr_parser *all_parsers[] = { &ifmsg_parser, &ifaddrmsg_parser };
 1046 
 1047 void
 1048 rtnl_iface_add_cloner(struct nl_cloner *cloner)
 1049 {
 1050         sx_xlock(&rtnl_cloner_lock);
 1051         SLIST_INSERT_HEAD(&nl_cloners, cloner, next);
 1052         sx_xunlock(&rtnl_cloner_lock);
 1053 }
 1054 
 1055 void
 1056 rtnl_iface_del_cloner(struct nl_cloner *cloner)
 1057 {
 1058         sx_xlock(&rtnl_cloner_lock);
 1059         SLIST_REMOVE(&nl_cloners, cloner, nl_cloner, next);
 1060         sx_xunlock(&rtnl_cloner_lock);
 1061 }
 1062 
 1063 static struct nl_cloner *
 1064 rtnl_iface_find_cloner_locked(const char *name)
 1065 {
 1066         struct nl_cloner *cloner;
 1067 
 1068         SLIST_FOREACH(cloner, &nl_cloners, next) {
 1069                 if (!strcmp(name, cloner->name))
 1070                         return (cloner);
 1071         }
 1072 
 1073         return (NULL);
 1074 }
 1075 
 1076 void
 1077 rtnl_ifaces_init(void)
 1078 {
 1079         ifattach_event = EVENTHANDLER_REGISTER(
 1080             ifnet_arrival_event, rtnl_handle_ifattach, NULL,
 1081             EVENTHANDLER_PRI_ANY);
 1082         ifdetach_event = EVENTHANDLER_REGISTER(
 1083             ifnet_departure_event, rtnl_handle_ifdetach, NULL,
 1084             EVENTHANDLER_PRI_ANY);
 1085         ifaddr_event = EVENTHANDLER_REGISTER(
 1086             rt_addrmsg, rtnl_handle_ifaddr, NULL,
 1087             EVENTHANDLER_PRI_ANY);
 1088         iflink_event = EVENTHANDLER_REGISTER(
 1089             ifnet_link_event, rtnl_handle_iflink, NULL,
 1090             EVENTHANDLER_PRI_ANY);
 1091         NL_VERIFY_PARSERS(all_parsers);
 1092         rtnl_iface_drivers_register();
 1093         rtnl_register_messages(cmd_handlers, NL_ARRAY_LEN(cmd_handlers));
 1094 }
 1095 
 1096 void
 1097 rtnl_ifaces_destroy(void)
 1098 {
 1099         EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ifattach_event);
 1100         EVENTHANDLER_DEREGISTER(ifnet_departure_event, ifdetach_event);
 1101         EVENTHANDLER_DEREGISTER(rt_addrmsg, ifaddr_event);
 1102         EVENTHANDLER_DEREGISTER(ifnet_link_event, iflink_event);
 1103 }

Cache object: ab221290af4b5a893af59d10ca46749a


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.