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/neigh.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/malloc.h>
   35 #include <sys/socket.h>
   36 #include <sys/syslog.h>
   37 
   38 #include <net/if.h>
   39 #include <net/if_llatbl.h>
   40 #include <netlink/netlink.h>
   41 #include <netlink/netlink_ctl.h>
   42 #include <netlink/netlink_route.h>
   43 #include <netlink/route/route_var.h>
   44 
   45 #include <netinet6/in6_var.h>           /* nd6.h requires this */
   46 #include <netinet6/nd6.h>               /* nd6 state machine */
   47 #include <netinet6/scope6_var.h>        /* scope deembedding */
   48 
   49 #define DEBUG_MOD_NAME  nl_neigh
   50 #define DEBUG_MAX_LEVEL LOG_DEBUG3
   51 #include <netlink/netlink_debug.h>
   52 _DECLARE_DEBUG(LOG_DEBUG);
   53 
   54 static int lle_families[] = { AF_INET, AF_INET6 };
   55 
   56 static eventhandler_tag lle_event_p;
   57 
   58 struct netlink_walkargs {
   59         struct nl_writer *nw;
   60         struct nlmsghdr hdr;
   61         struct nlpcb *so;
   62         struct ifnet *ifp;
   63         int family;
   64         int error;
   65         int count;
   66         int dumped;
   67 };
   68 
   69 static int
   70 lle_state_to_nl_state(int family, struct llentry *lle)
   71 {
   72         int state = lle->ln_state;
   73 
   74         switch (family) {
   75         case AF_INET:
   76                 if (lle->la_flags & (LLE_STATIC | LLE_IFADDR))
   77                         state = 1;
   78                 switch (state) {
   79                 case 0: /* ARP_LLINFO_INCOMPLETE */
   80                         return (NUD_INCOMPLETE);
   81                 case 1: /* ARP_LLINFO_REACHABLE  */
   82                         return (NUD_REACHABLE);
   83                 case 2: /* ARP_LLINFO_VERIFY */
   84                         return (NUD_PROBE);
   85                 }
   86                 break;
   87         case AF_INET6:
   88                 switch (state) {
   89                 case ND6_LLINFO_INCOMPLETE:
   90                         return (NUD_INCOMPLETE);
   91                 case ND6_LLINFO_REACHABLE:
   92                         return (NUD_REACHABLE);
   93                 case ND6_LLINFO_STALE:
   94                         return (NUD_STALE);
   95                 case ND6_LLINFO_DELAY:
   96                         return (NUD_DELAY);
   97                 case ND6_LLINFO_PROBE:
   98                         return (NUD_PROBE);
   99                 }
  100                 break;
  101         }
  102 
  103         return (NUD_NONE);
  104 }
  105 
  106 static uint32_t
  107 lle_flags_to_nl_flags(const struct llentry *lle)
  108 {
  109         uint32_t nl_flags = 0;
  110 
  111         if (lle->la_flags & LLE_IFADDR)
  112                 nl_flags |= NTF_SELF;
  113         if (lle->la_flags & LLE_PUB)
  114                 nl_flags |= NTF_PROXY;
  115         if (lle->la_flags & LLE_STATIC)
  116                 nl_flags |= NTF_STICKY;
  117         if (lle->ln_router != 0)
  118                 nl_flags |= NTF_ROUTER;
  119 
  120         return (nl_flags);
  121 }
  122 
  123 static int
  124 dump_lle_locked(struct llentry *lle, void *arg)
  125 {
  126         struct netlink_walkargs *wa = (struct netlink_walkargs *)arg;
  127         struct nlmsghdr *hdr = &wa->hdr;
  128         struct nl_writer *nw = wa->nw;
  129         struct ndmsg *ndm;
  130 #if defined(INET) || defined(INET6)
  131         union {
  132                 struct in_addr  in;
  133                 struct in6_addr in6;
  134         } addr;
  135 #endif
  136 
  137         IF_DEBUG_LEVEL(LOG_DEBUG2) {
  138                 char llebuf[NHOP_PRINT_BUFSIZE];
  139                 llentry_print_buf_lltable(lle, llebuf, sizeof(llebuf));
  140                 NL_LOG(LOG_DEBUG2, "dumping %s", llebuf);
  141         }
  142 
  143         if (!nlmsg_reply(nw, hdr, sizeof(struct ndmsg)))
  144                 goto enomem;
  145 
  146         ndm = nlmsg_reserve_object(nw, struct ndmsg);
  147         ndm->ndm_family = wa->family;
  148         ndm->ndm_ifindex = wa->ifp->if_index;
  149         ndm->ndm_state = lle_state_to_nl_state(wa->family, lle);
  150         ndm->ndm_flags = lle_flags_to_nl_flags(lle);
  151 
  152         switch (wa->family) {
  153 #ifdef INET
  154         case AF_INET:
  155                 addr.in = lle->r_l3addr.addr4;
  156                 nlattr_add(nw, NDA_DST, 4, &addr);
  157                 break;
  158 #endif
  159 #ifdef INET6
  160         case AF_INET6:
  161                 addr.in6 = lle->r_l3addr.addr6;
  162                 in6_clearscope(&addr.in6);
  163                 nlattr_add(nw, NDA_DST, 16, &addr);
  164                 break;
  165 #endif
  166         }
  167 
  168         if (lle->r_flags & RLLE_VALID) {
  169                 /* Has L2 */
  170                 int addrlen = wa->ifp->if_addrlen;
  171                 nlattr_add(nw, NDA_LLADDR, addrlen, lle->ll_addr);
  172         }
  173 
  174         nlattr_add_u32(nw, NDA_PROBES, lle->la_asked);
  175 
  176         struct nda_cacheinfo *cache;
  177         cache = nlmsg_reserve_attr(nw, NDA_CACHEINFO, struct nda_cacheinfo);
  178         if (cache == NULL)
  179                 goto enomem;
  180         /* TODO: provide confirmed/updated */
  181         cache->ndm_refcnt = lle->lle_refcnt;
  182 
  183         if (nlmsg_end(nw))
  184                 return (0);
  185 enomem:
  186         NL_LOG(LOG_DEBUG, "unable to dump lle state (ENOMEM)");
  187         nlmsg_abort(nw);
  188         return (ENOMEM);
  189 }
  190 
  191 static int
  192 dump_lle(struct lltable *llt, struct llentry *lle, void *arg)
  193 {
  194         int error;
  195 
  196         LLE_RLOCK(lle);
  197         error = dump_lle_locked(lle, arg);
  198         LLE_RUNLOCK(lle);
  199         return (error);
  200 }
  201 
  202 static bool
  203 dump_llt(struct lltable *llt, struct netlink_walkargs *wa)
  204 {
  205         lltable_foreach_lle(llt, dump_lle, wa);
  206 
  207         return (true);
  208 }
  209 
  210 static int
  211 dump_llts_iface(struct netlink_walkargs *wa, struct ifnet *ifp, int family)
  212 {
  213         int error = 0;
  214 
  215         wa->ifp = ifp;
  216         for (int i = 0; i < sizeof(lle_families) / sizeof(int); i++) {
  217                 int fam = lle_families[i];
  218                 struct lltable *llt = lltable_get(ifp, fam);
  219                 if (llt != NULL && (family == 0 || family == fam)) {
  220                         wa->count++;
  221                         wa->family = fam;
  222                         if (!dump_llt(llt, wa)) {
  223                                 error = ENOMEM;
  224                                 break;
  225                         }
  226                         wa->dumped++;
  227                 }
  228         }
  229         return (error);
  230 }
  231 
  232 static int
  233 dump_llts(struct netlink_walkargs *wa, struct ifnet *ifp, int family)
  234 {
  235         NL_LOG(LOG_DEBUG, "Start dump ifp=%s family=%d", ifp ? if_name(ifp) : "NULL", family);
  236 
  237         wa->hdr.nlmsg_flags |= NLM_F_MULTI;
  238 
  239         if (ifp != NULL) {
  240                 dump_llts_iface(wa, ifp, family);
  241         } else {
  242                 CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
  243                         dump_llts_iface(wa, ifp, family);
  244                 }
  245         }
  246 
  247         NL_LOG(LOG_DEBUG, "End dump, iterated %d dumped %d", wa->count, wa->dumped);
  248 
  249         if (!nlmsg_end_dump(wa->nw, wa->error, &wa->hdr)) {
  250                 NL_LOG(LOG_DEBUG, "Unable to add new message");
  251                 return (ENOMEM);
  252         }
  253 
  254         return (0);
  255 }
  256 
  257 static int
  258 get_lle(struct netlink_walkargs *wa, struct ifnet *ifp, int family, struct sockaddr *dst)
  259 {
  260         struct lltable *llt = lltable_get(ifp, family);
  261         if (llt == NULL)
  262                 return (ESRCH);
  263 
  264 #ifdef INET6
  265         if (dst->sa_family == AF_INET6) {
  266                 struct sockaddr_in6 *dst6 = (struct sockaddr_in6 *)dst;
  267 
  268                 if (IN6_IS_SCOPE_LINKLOCAL(&dst6->sin6_addr))
  269                         in6_set_unicast_scopeid(&dst6->sin6_addr, ifp->if_index);
  270         }
  271 #endif
  272         struct llentry *lle = lla_lookup(llt, LLE_UNLOCKED, dst);
  273         if (lle == NULL)
  274                 return (ESRCH);
  275 
  276         wa->ifp = ifp;
  277         wa->family = family;
  278 
  279         return (dump_lle(llt, lle, wa));
  280 }
  281 
  282 struct nl_parsed_neigh {
  283         struct sockaddr *nda_dst;
  284         struct ifnet    *nda_ifp;
  285         struct nlattr   *nda_lladdr;
  286         uint32_t        ndm_flags;
  287         uint16_t        ndm_state;
  288         uint8_t         ndm_family;
  289 };
  290 
  291 #define _IN(_field)     offsetof(struct ndmsg, _field)
  292 #define _OUT(_field)    offsetof(struct nl_parsed_neigh, _field)
  293 static struct nlfield_parser nlf_p_neigh[] = {
  294         { .off_in = _IN(ndm_family), .off_out = _OUT(ndm_family), .cb = nlf_get_u8 },
  295         { .off_in = _IN(ndm_flags), .off_out = _OUT(ndm_flags), .cb = nlf_get_u8_u32 },
  296         { .off_in = _IN(ndm_state), .off_out = _OUT(ndm_state), .cb = nlf_get_u16 },
  297         { .off_in = _IN(ndm_ifindex), .off_out = _OUT(nda_ifp), .cb = nlf_get_ifpz },
  298 };
  299 
  300 static struct nlattr_parser nla_p_neigh[] = {
  301         { .type = NDA_DST, .off = _OUT(nda_dst), .cb = nlattr_get_ip },
  302         { .type = NDA_LLADDR, .off = _OUT(nda_lladdr), .cb = nlattr_get_nla },
  303         { .type = NDA_IFINDEX, .off = _OUT(nda_ifp), .cb = nlattr_get_ifp },
  304         { .type = NDA_FLAGS_EXT, .off = _OUT(ndm_flags), .cb = nlattr_get_uint32 },
  305 };
  306 #undef _IN
  307 #undef _OUT
  308 NL_DECLARE_PARSER(ndmsg_parser, struct ndmsg, nlf_p_neigh, nla_p_neigh);
  309 
  310 
  311 /*
  312  * type=RTM_NEWNEIGH, flags=NLM_F_REQUEST|NLM_F_ACK|NLM_F_EXCL|NLM_F_CREATE, seq=1661941473, pid=0},
  313  * {ndm_family=AF_INET6, ndm_ifindex=if_nametoindex("enp0s31f6"), ndm_state=NUD_PERMANENT, ndm_flags=0, ndm_type=RTN_UNSPEC},
  314  * [
  315  *  {{nla_len=20, nla_type=NDA_DST}, inet_pton(AF_INET6, "2a01:4f8:13a:70c::3")},
  316  *  {{nla_len=10, nla_type=NDA_LLADDR}, 20:4e:71:62:ae:f2}]}, iov_len=60}
  317  */
  318 
  319 static int
  320 rtnl_handle_newneigh(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_pstate *npt)
  321 {
  322         int error;
  323 
  324         struct nl_parsed_neigh attrs = {};
  325         error = nl_parse_nlmsg(hdr, &ndmsg_parser, npt, &attrs);
  326         if (error != 0)
  327                 return (error);
  328 
  329         if (attrs.nda_ifp == NULL || attrs.nda_dst == NULL || attrs.nda_lladdr == NULL) {
  330                 if (attrs.nda_ifp == NULL)
  331                         NLMSG_REPORT_ERR_MSG(npt, "NDA_IFINDEX / ndm_ifindex not set");
  332                 if (attrs.nda_dst == NULL)
  333                         NLMSG_REPORT_ERR_MSG(npt, "NDA_DST not set");
  334                 if (attrs.nda_lladdr == NULL)
  335                         NLMSG_REPORT_ERR_MSG(npt, "NDA_LLADDR not set");
  336                 return (EINVAL);
  337         }
  338 
  339         if (attrs.nda_dst->sa_family != attrs.ndm_family) {
  340                 NLMSG_REPORT_ERR_MSG(npt,
  341                     "NDA_DST family (%d) is different from ndm_family (%d)",
  342                     attrs.nda_dst->sa_family, attrs.ndm_family);
  343                 return (EINVAL);
  344         }
  345 
  346         int addrlen = attrs.nda_ifp->if_addrlen;
  347         if (attrs.nda_lladdr->nla_len != sizeof(struct nlattr) + addrlen) {
  348                 NLMSG_REPORT_ERR_MSG(npt,
  349                     "NDA_LLADDR address length (%d) is different from expected (%d)",
  350                     (int)attrs.nda_lladdr->nla_len - (int)sizeof(struct nlattr), addrlen);
  351                 return (EINVAL);
  352         }
  353 
  354         if (attrs.ndm_state != NUD_PERMANENT) {
  355                 NLMSG_REPORT_ERR_MSG(npt, "ndm_state %d not supported", attrs.ndm_state);
  356                 return (ENOTSUP);
  357         }
  358 
  359         const uint16_t supported_flags = NTF_PROXY | NTF_STICKY;
  360         if ((attrs.ndm_flags & supported_flags) != attrs.ndm_flags) {
  361                 NLMSG_REPORT_ERR_MSG(npt, "ndm_flags %X not supported",
  362                     attrs.ndm_flags &~ supported_flags);
  363                 return (ENOTSUP);
  364         }
  365 
  366         /* Replacement requires new entry creation anyway */
  367         if ((hdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_REPLACE)) == 0)
  368                 return (ENOTSUP);
  369 
  370         struct lltable *llt = lltable_get(attrs.nda_ifp, attrs.ndm_family);
  371         if (llt == NULL)
  372                 return (EAFNOSUPPORT);
  373 
  374 
  375         uint8_t linkhdr[LLE_MAX_LINKHDR];
  376         size_t linkhdrsize = sizeof(linkhdr);
  377         int lladdr_off = 0;
  378         if (lltable_calc_llheader(attrs.nda_ifp, attrs.ndm_family,
  379             (char *)(attrs.nda_lladdr + 1), linkhdr, &linkhdrsize, &lladdr_off) != 0) {
  380                 NLMSG_REPORT_ERR_MSG(npt, "unable to calculate lle prepend data");
  381                 return (EINVAL);
  382         }
  383 
  384         int lle_flags = LLE_STATIC | ((attrs.ndm_flags & NTF_PROXY) ? LLE_PUB : 0);
  385         struct llentry *lle = lltable_alloc_entry(llt, lle_flags, attrs.nda_dst);
  386         if (lle == NULL)
  387                 return (ENOMEM);
  388         lltable_set_entry_addr(attrs.nda_ifp, lle, linkhdr, linkhdrsize, lladdr_off);
  389 
  390         /* llentry created, try to insert or update :*/
  391         IF_AFDATA_WLOCK(attrs.nda_ifp);
  392         LLE_WLOCK(lle);
  393         struct llentry *lle_tmp = lla_lookup(llt, LLE_EXCLUSIVE, attrs.nda_dst);
  394         if (lle_tmp != NULL) {
  395                 if (hdr->nlmsg_flags & NLM_F_EXCL) {
  396                         LLE_WUNLOCK(lle_tmp);
  397                         lle_tmp = NULL;
  398                         error = EEXIST;
  399                 } else if (hdr->nlmsg_flags & NLM_F_REPLACE) {
  400                         lltable_unlink_entry(llt, lle_tmp);
  401                         lltable_link_entry(llt, lle);
  402                 } else
  403                         error = EEXIST;
  404         } else {
  405                 if (hdr->nlmsg_flags & NLM_F_CREATE)
  406                         lltable_link_entry(llt, lle);
  407                 else
  408                         error = ENOENT;
  409         }
  410         IF_AFDATA_WUNLOCK(attrs.nda_ifp);
  411 
  412         if (error != 0) {
  413                 if (lle != NULL)
  414                         llentry_free(lle);
  415                 return (error);
  416         }
  417 
  418         if (lle_tmp != NULL)
  419                 llentry_free(lle_tmp);
  420 
  421         /* XXX: We're inside epoch */
  422         EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_RESOLVED);
  423         LLE_WUNLOCK(lle);
  424 
  425         return (0);
  426 }
  427 
  428 static int
  429 rtnl_handle_delneigh(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_pstate *npt)
  430 {
  431         int error;
  432 
  433         struct nl_parsed_neigh attrs = {};
  434         error = nl_parse_nlmsg(hdr, &ndmsg_parser, npt, &attrs);
  435         if (error != 0)
  436                 return (error);
  437 
  438         if (attrs.nda_dst == NULL) {
  439                 NLMSG_REPORT_ERR_MSG(npt, "NDA_DST not set");
  440                 return (EINVAL);
  441         }
  442 
  443         if (attrs.nda_ifp == NULL) {
  444                 NLMSG_REPORT_ERR_MSG(npt, "no ifindex provided");
  445                 return (EINVAL);
  446         }
  447 
  448         struct lltable *llt = lltable_get(attrs.nda_ifp, attrs.ndm_family);
  449         if (llt == NULL)
  450                 return (EAFNOSUPPORT);
  451 
  452         IF_AFDATA_WLOCK(attrs.nda_ifp);
  453         struct llentry *lle = lla_lookup(llt, LLE_EXCLUSIVE, attrs.nda_dst);
  454         if (lle != NULL) {
  455                 if ((lle->la_flags & LLE_IFADDR) != 0) {
  456                         LLE_WUNLOCK(lle);
  457                         lle = NULL;
  458                         error = EPERM;
  459                 } else
  460                         lltable_unlink_entry(llt, lle);
  461         } else
  462                 error = ENOENT;
  463         IF_AFDATA_WUNLOCK(attrs.nda_ifp);
  464 
  465         if (error == 0 && lle != NULL)
  466                 EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED);
  467 
  468         if (lle != NULL)
  469                 llentry_free(lle);
  470 
  471         return (error);
  472 }
  473 
  474 static int
  475 rtnl_handle_getneigh(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_pstate *npt)
  476 {
  477         int error;
  478 
  479         struct nl_parsed_neigh attrs = {};
  480         error = nl_parse_nlmsg(hdr, &ndmsg_parser, npt, &attrs);
  481         if (error != 0)
  482                 return (error);
  483 
  484         if (attrs.nda_dst != NULL && attrs.nda_ifp == NULL) {
  485                 NLMSG_REPORT_ERR_MSG(npt, "has NDA_DST but no ifindex provided");
  486                 return (EINVAL);
  487         }
  488 
  489         struct netlink_walkargs wa = {
  490                 .so = nlp,
  491                 .nw = npt->nw,
  492                 .hdr.nlmsg_pid = hdr->nlmsg_pid,
  493                 .hdr.nlmsg_seq = hdr->nlmsg_seq,
  494                 .hdr.nlmsg_flags = hdr->nlmsg_flags,
  495                 .hdr.nlmsg_type = NL_RTM_NEWNEIGH,
  496         };
  497 
  498         if (attrs.nda_dst == NULL)
  499                 error = dump_llts(&wa, attrs.nda_ifp, attrs.ndm_family);
  500         else
  501                 error = get_lle(&wa, attrs.nda_ifp, attrs.ndm_family, attrs.nda_dst);
  502 
  503         return (error);
  504 }
  505 
  506 static const struct rtnl_cmd_handler cmd_handlers[] = {
  507         {
  508                 .cmd = NL_RTM_NEWNEIGH,
  509                 .name = "RTM_NEWNEIGH",
  510                 .cb = &rtnl_handle_newneigh,
  511         },
  512         {
  513                 .cmd = NL_RTM_DELNEIGH,
  514                 .name = "RTM_DELNEIGH",
  515                 .cb = &rtnl_handle_delneigh,
  516                 .priv = PRIV_NET_ROUTE,
  517         },
  518         {
  519                 .cmd = NL_RTM_GETNEIGH,
  520                 .name = "RTM_GETNEIGH",
  521                 .cb = &rtnl_handle_getneigh,
  522                 .priv = PRIV_NET_ROUTE,
  523         }
  524 };
  525 
  526 static void
  527 rtnl_lle_event(void *arg __unused, struct llentry *lle, int evt)
  528 {
  529         struct ifnet *ifp;
  530         int family;
  531 
  532         LLE_WLOCK_ASSERT(lle);
  533 
  534         ifp = lltable_get_ifp(lle->lle_tbl);
  535         family = lltable_get_af(lle->lle_tbl);
  536 
  537         if (family != AF_INET && family != AF_INET6)
  538                 return;
  539 
  540         int nlmsgs_type = evt == LLENTRY_RESOLVED ? NL_RTM_NEWNEIGH : NL_RTM_DELNEIGH;
  541 
  542         struct nl_writer nw = {};
  543         if (!nlmsg_get_group_writer(&nw, NLMSG_SMALL, NETLINK_ROUTE, RTNLGRP_NEIGH)) {
  544                 NL_LOG(LOG_DEBUG, "error allocating group writer");
  545                 return;
  546         }
  547 
  548         struct netlink_walkargs wa = {
  549                 .hdr.nlmsg_type = nlmsgs_type,
  550                 .nw = &nw,
  551                 .ifp = ifp,
  552                 .family = family,
  553         };
  554 
  555         dump_lle_locked(lle, &wa);
  556         nlmsg_flush(&nw);
  557 }
  558 
  559 static const struct nlhdr_parser *all_parsers[] = { &ndmsg_parser };
  560 
  561 void
  562 rtnl_neighs_init(void)
  563 {
  564         NL_VERIFY_PARSERS(all_parsers);
  565         rtnl_register_messages(cmd_handlers, NL_ARRAY_LEN(cmd_handlers));
  566         lle_event_p = EVENTHANDLER_REGISTER(lle_event, rtnl_lle_event, NULL,
  567             EVENTHANDLER_PRI_ANY);
  568 }
  569 
  570 void
  571 rtnl_neighs_destroy(void)
  572 {
  573         EVENTHANDLER_DEREGISTER(lle_event, lle_event_p);
  574 }

Cache object: cf7e6a3f00d6954d6f644dc59aefba28


[ 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.