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/net/if_llatbl.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2004 Luigi Rizzo, Alessandro Cerri. All rights reserved.
    3  * Copyright (c) 2004-2008 Qing Li. All rights reserved.
    4  * Copyright (c) 2008 Kip Macy. All rights reserved.
    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 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 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 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: releng/10.1/sys/net/if_llatbl.c 250300 2013-05-06 16:42:18Z andre $");
   29 
   30 #include "opt_ddb.h"
   31 #include "opt_inet.h"
   32 #include "opt_inet6.h"
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/malloc.h>
   37 #include <sys/mbuf.h>
   38 #include <sys/syslog.h>
   39 #include <sys/sysctl.h>
   40 #include <sys/socket.h>
   41 #include <sys/kernel.h>
   42 #include <sys/lock.h>
   43 #include <sys/mutex.h>
   44 #include <sys/rwlock.h>
   45 
   46 #ifdef DDB
   47 #include <ddb/ddb.h>
   48 #endif
   49 
   50 #include <vm/uma.h>
   51 
   52 #include <netinet/in.h>
   53 #include <net/if_llatbl.h>
   54 #include <net/if.h>
   55 #include <net/if_dl.h>
   56 #include <net/if_var.h>
   57 #include <net/route.h>
   58 #include <net/vnet.h>
   59 #include <netinet/if_ether.h>
   60 #include <netinet6/in6_var.h>
   61 #include <netinet6/nd6.h>
   62 
   63 MALLOC_DEFINE(M_LLTABLE, "lltable", "link level address tables");
   64 
   65 static VNET_DEFINE(SLIST_HEAD(, lltable), lltables);
   66 #define V_lltables      VNET(lltables)
   67 
   68 static void vnet_lltable_init(void);
   69 
   70 struct rwlock lltable_rwlock;
   71 RW_SYSINIT(lltable_rwlock, &lltable_rwlock, "lltable_rwlock");
   72 
   73 /*
   74  * Dump arp state for a specific address family.
   75  */
   76 int
   77 lltable_sysctl_dumparp(int af, struct sysctl_req *wr)
   78 {
   79         struct lltable *llt;
   80         int error = 0;
   81 
   82         LLTABLE_RLOCK();
   83         SLIST_FOREACH(llt, &V_lltables, llt_link) {
   84                 if (llt->llt_af == af) {
   85                         error = llt->llt_dump(llt, wr);
   86                         if (error != 0)
   87                                 goto done;
   88                 }
   89         }
   90 done:
   91         LLTABLE_RUNLOCK();
   92         return (error);
   93 }
   94 
   95 /*
   96  * Deletes an address from the address table.
   97  * This function is called by the timer functions
   98  * such as arptimer() and nd6_llinfo_timer(), and
   99  * the caller does the locking.
  100  *
  101  * Returns the number of held packets, if any, that were dropped.
  102  */
  103 size_t
  104 llentry_free(struct llentry *lle)
  105 {
  106         size_t pkts_dropped;
  107         struct mbuf *next;
  108 
  109         IF_AFDATA_WLOCK_ASSERT(lle->lle_tbl->llt_ifp);
  110         LLE_WLOCK_ASSERT(lle);
  111 
  112         LIST_REMOVE(lle, lle_next);
  113         lle->la_flags &= ~(LLE_VALID | LLE_LINKED);
  114 
  115         pkts_dropped = 0;
  116         while ((lle->la_numheld > 0) && (lle->la_hold != NULL)) {
  117                 next = lle->la_hold->m_nextpkt;
  118                 m_freem(lle->la_hold);
  119                 lle->la_hold = next;
  120                 lle->la_numheld--;
  121                 pkts_dropped++;
  122         }
  123 
  124         KASSERT(lle->la_numheld == 0,
  125                 ("%s: la_numheld %d > 0, pkts_droped %zd", __func__,
  126                  lle->la_numheld, pkts_dropped));
  127 
  128         LLE_FREE_LOCKED(lle);
  129 
  130         return (pkts_dropped);
  131 }
  132 
  133 /*
  134  * (al)locate an llentry for address dst (equivalent to rtalloc for new-arp).
  135  *
  136  * If found the llentry * is returned referenced and unlocked.
  137  */
  138 struct llentry *
  139 llentry_alloc(struct ifnet *ifp, struct lltable *lt,
  140     struct sockaddr_storage *dst)
  141 {
  142         struct llentry *la;
  143 
  144         IF_AFDATA_RLOCK(ifp);
  145         la = lla_lookup(lt, LLE_EXCLUSIVE, (struct sockaddr *)dst);
  146         IF_AFDATA_RUNLOCK(ifp);
  147         if ((la == NULL) &&
  148             (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0) {
  149                 IF_AFDATA_WLOCK(ifp);
  150                 la = lla_lookup(lt, (LLE_CREATE | LLE_EXCLUSIVE),
  151                     (struct sockaddr *)dst);
  152                 IF_AFDATA_WUNLOCK(ifp);
  153         }
  154 
  155         if (la != NULL) {
  156                 LLE_ADDREF(la);
  157                 LLE_WUNLOCK(la);
  158         }
  159 
  160         return (la);
  161 }
  162 
  163 /*
  164  * Free all entries from given table and free itself.
  165  */
  166 void
  167 lltable_free(struct lltable *llt)
  168 {
  169         struct llentry *lle, *next;
  170         int i;
  171 
  172         KASSERT(llt != NULL, ("%s: llt is NULL", __func__));
  173 
  174         LLTABLE_WLOCK();
  175         SLIST_REMOVE(&V_lltables, llt, lltable, llt_link);
  176         LLTABLE_WUNLOCK();
  177 
  178         IF_AFDATA_WLOCK(llt->llt_ifp);
  179         for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) {
  180                 LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
  181                         LLE_WLOCK(lle);
  182                         if (callout_stop(&lle->la_timer))
  183                                 LLE_REMREF(lle);
  184                         llentry_free(lle);
  185                 }
  186         }
  187         IF_AFDATA_WUNLOCK(llt->llt_ifp);
  188 
  189         free(llt, M_LLTABLE);
  190 }
  191 
  192 #if 0
  193 void
  194 lltable_drain(int af)
  195 {
  196         struct lltable  *llt;
  197         struct llentry  *lle;
  198         register int i;
  199 
  200         LLTABLE_RLOCK();
  201         SLIST_FOREACH(llt, &V_lltables, llt_link) {
  202                 if (llt->llt_af != af)
  203                         continue;
  204 
  205                 for (i=0; i < LLTBL_HASHTBL_SIZE; i++) {
  206                         LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
  207                                 LLE_WLOCK(lle);
  208                                 if (lle->la_hold) {
  209                                         m_freem(lle->la_hold);
  210                                         lle->la_hold = NULL;
  211                                 }
  212                                 LLE_WUNLOCK(lle);
  213                         }
  214                 }
  215         }
  216         LLTABLE_RUNLOCK();
  217 }
  218 #endif
  219 
  220 void
  221 lltable_prefix_free(int af, struct sockaddr *prefix, struct sockaddr *mask,
  222     u_int flags)
  223 {
  224         struct lltable *llt;
  225 
  226         LLTABLE_RLOCK();
  227         SLIST_FOREACH(llt, &V_lltables, llt_link) {
  228                 if (llt->llt_af != af)
  229                         continue;
  230 
  231                 llt->llt_prefix_free(llt, prefix, mask, flags);
  232         }
  233         LLTABLE_RUNLOCK();
  234 }
  235 
  236 
  237 
  238 /*
  239  * Create a new lltable.
  240  */
  241 struct lltable *
  242 lltable_init(struct ifnet *ifp, int af)
  243 {
  244         struct lltable *llt;
  245         register int i;
  246 
  247         llt = malloc(sizeof(struct lltable), M_LLTABLE, M_WAITOK);
  248 
  249         llt->llt_af = af;
  250         llt->llt_ifp = ifp;
  251         for (i = 0; i < LLTBL_HASHTBL_SIZE; i++)
  252                 LIST_INIT(&llt->lle_head[i]);
  253 
  254         LLTABLE_WLOCK();
  255         SLIST_INSERT_HEAD(&V_lltables, llt, llt_link);
  256         LLTABLE_WUNLOCK();
  257 
  258         return (llt);
  259 }
  260 
  261 /*
  262  * Called in route_output when adding/deleting a route to an interface.
  263  */
  264 int
  265 lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info)
  266 {
  267         struct sockaddr_dl *dl =
  268             (struct sockaddr_dl *)info->rti_info[RTAX_GATEWAY];
  269         struct sockaddr *dst = (struct sockaddr *)info->rti_info[RTAX_DST];
  270         struct ifnet *ifp;
  271         struct lltable *llt;
  272         struct llentry *lle;
  273         u_int laflags = 0, flags = 0;
  274         int error = 0;
  275 
  276         KASSERT(dl != NULL && dl->sdl_family == AF_LINK,
  277             ("%s: invalid dl\n", __func__));
  278 
  279         ifp = ifnet_byindex(dl->sdl_index);
  280         if (ifp == NULL) {
  281                 log(LOG_INFO, "%s: invalid ifp (sdl_index %d)\n",
  282                     __func__, dl->sdl_index);
  283                 return EINVAL;
  284         }
  285 
  286         switch (rtm->rtm_type) {
  287         case RTM_ADD:
  288                 if (rtm->rtm_flags & RTF_ANNOUNCE)
  289                         flags |= LLE_PUB;
  290                 flags |= LLE_CREATE;
  291                 break;
  292 
  293         case RTM_DELETE:
  294                 flags |= LLE_DELETE;
  295                 break;
  296 
  297         case RTM_CHANGE:
  298                 break;
  299 
  300         default:
  301                 return EINVAL; /* XXX not implemented yet */
  302         }
  303 
  304         /* XXX linked list may be too expensive */
  305         LLTABLE_RLOCK();
  306         SLIST_FOREACH(llt, &V_lltables, llt_link) {
  307                 if (llt->llt_af == dst->sa_family &&
  308                     llt->llt_ifp == ifp)
  309                         break;
  310         }
  311         LLTABLE_RUNLOCK();
  312         KASSERT(llt != NULL, ("Yep, ugly hacks are bad\n"));
  313 
  314         if (flags & LLE_CREATE)
  315                 flags |= LLE_EXCLUSIVE;
  316 
  317         IF_AFDATA_LOCK(ifp);
  318         lle = lla_lookup(llt, flags, dst);
  319         IF_AFDATA_UNLOCK(ifp);
  320         if (LLE_IS_VALID(lle)) {
  321                 if (flags & LLE_CREATE) {
  322                         /*
  323                          * If we delay the delete, then a subsequent
  324                          * "arp add" should look up this entry, reset the
  325                          * LLE_DELETED flag, and reset the expiration timer
  326                          */
  327                         bcopy(LLADDR(dl), &lle->ll_addr, ifp->if_addrlen);
  328                         lle->la_flags |= (flags & LLE_PUB);
  329                         lle->la_flags |= LLE_VALID;
  330                         lle->la_flags &= ~LLE_DELETED;
  331 #ifdef INET6
  332                         /*
  333                          * ND6
  334                          */
  335                         if (dst->sa_family == AF_INET6)
  336                                 lle->ln_state = ND6_LLINFO_REACHABLE;
  337 #endif
  338                         /*
  339                          * NB: arp and ndp always set (RTF_STATIC | RTF_HOST)
  340                          */
  341 
  342                         if (rtm->rtm_rmx.rmx_expire == 0) {
  343                                 lle->la_flags |= LLE_STATIC;
  344                                 lle->la_expire = 0;
  345                         } else
  346                                 lle->la_expire = rtm->rtm_rmx.rmx_expire;
  347                         laflags = lle->la_flags;
  348                         LLE_WUNLOCK(lle);
  349 #ifdef INET
  350                         /* gratuitous ARP */
  351                         if ((laflags & LLE_PUB) && dst->sa_family == AF_INET)
  352                                 arprequest(ifp,
  353                                     &((struct sockaddr_in *)dst)->sin_addr,
  354                                     &((struct sockaddr_in *)dst)->sin_addr,
  355                                     (u_char *)LLADDR(dl));
  356 #endif
  357                 } else {
  358                         if (flags & LLE_EXCLUSIVE)
  359                                 LLE_WUNLOCK(lle);
  360                         else
  361                                 LLE_RUNLOCK(lle);
  362                 }
  363         } else if ((lle == NULL) && (flags & LLE_DELETE))
  364                 error = EINVAL;
  365 
  366 
  367         return (error);
  368 }
  369 
  370 static void
  371 vnet_lltable_init()
  372 {
  373 
  374         SLIST_INIT(&V_lltables);
  375 }
  376 VNET_SYSINIT(vnet_lltable_init, SI_SUB_PSEUDO, SI_ORDER_FIRST,
  377     vnet_lltable_init, NULL);
  378 
  379 #ifdef DDB
  380 struct llentry_sa {
  381         struct llentry          base;
  382         struct sockaddr         l3_addr;
  383 };
  384 
  385 static void
  386 llatbl_lle_show(struct llentry_sa *la)
  387 {
  388         struct llentry *lle;
  389         uint8_t octet[6];
  390 
  391         lle = &la->base;
  392         db_printf("lle=%p\n", lle);
  393         db_printf(" lle_next=%p\n", lle->lle_next.le_next);
  394         db_printf(" lle_lock=%p\n", &lle->lle_lock);
  395         db_printf(" lle_tbl=%p\n", lle->lle_tbl);
  396         db_printf(" lle_head=%p\n", lle->lle_head);
  397         db_printf(" la_hold=%p\n", lle->la_hold);
  398         db_printf(" la_numheld=%d\n", lle->la_numheld);
  399         db_printf(" la_expire=%ju\n", (uintmax_t)lle->la_expire);
  400         db_printf(" la_flags=0x%04x\n", lle->la_flags);
  401         db_printf(" la_asked=%u\n", lle->la_asked);
  402         db_printf(" la_preempt=%u\n", lle->la_preempt);
  403         db_printf(" ln_byhint=%u\n", lle->ln_byhint);
  404         db_printf(" ln_state=%d\n", lle->ln_state);
  405         db_printf(" ln_router=%u\n", lle->ln_router);
  406         db_printf(" ln_ntick=%ju\n", (uintmax_t)lle->ln_ntick);
  407         db_printf(" lle_refcnt=%d\n", lle->lle_refcnt);
  408         bcopy(&lle->ll_addr.mac16, octet, sizeof(octet));
  409         db_printf(" ll_addr=%02x:%02x:%02x:%02x:%02x:%02x\n",
  410             octet[0], octet[1], octet[2], octet[3], octet[4], octet[5]);
  411         db_printf(" la_timer=%p\n", &lle->la_timer);
  412 
  413         switch (la->l3_addr.sa_family) {
  414 #ifdef INET
  415         case AF_INET:
  416         {
  417                 struct sockaddr_in *sin;
  418                 char l3s[INET_ADDRSTRLEN];
  419 
  420                 sin = (struct sockaddr_in *)&la->l3_addr;
  421                 inet_ntoa_r(sin->sin_addr, l3s);
  422                 db_printf(" l3_addr=%s\n", l3s);
  423                 break;
  424         }
  425 #endif
  426 #ifdef INET6
  427         case AF_INET6:
  428         {
  429                 struct sockaddr_in6 *sin6;
  430                 char l3s[INET6_ADDRSTRLEN];
  431 
  432                 sin6 = (struct sockaddr_in6 *)&la->l3_addr;
  433                 ip6_sprintf(l3s, &sin6->sin6_addr);
  434                 db_printf(" l3_addr=%s\n", l3s);
  435                 break;
  436         }
  437 #endif
  438         default:
  439                 db_printf(" l3_addr=N/A (af=%d)\n", la->l3_addr.sa_family);
  440                 break;
  441         }
  442 }
  443 
  444 DB_SHOW_COMMAND(llentry, db_show_llentry)
  445 {
  446 
  447         if (!have_addr) {
  448                 db_printf("usage: show llentry <struct llentry *>\n");
  449                 return;
  450         }
  451 
  452         llatbl_lle_show((struct llentry_sa *)addr);
  453 }
  454 
  455 static void
  456 llatbl_llt_show(struct lltable *llt)
  457 {
  458         int i;
  459         struct llentry *lle;
  460 
  461         db_printf("llt=%p llt_af=%d llt_ifp=%p\n",
  462             llt, llt->llt_af, llt->llt_ifp);
  463 
  464         for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) {
  465                 LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
  466 
  467                         llatbl_lle_show((struct llentry_sa *)lle);
  468                         if (db_pager_quit)
  469                                 return;
  470                 }
  471         }
  472 }
  473 
  474 DB_SHOW_COMMAND(lltable, db_show_lltable)
  475 {
  476 
  477         if (!have_addr) {
  478                 db_printf("usage: show lltable <struct lltable *>\n");
  479                 return;
  480         }
  481 
  482         llatbl_llt_show((struct lltable *)addr);
  483 }
  484 
  485 DB_SHOW_ALL_COMMAND(lltables, db_show_all_lltables)
  486 {
  487         VNET_ITERATOR_DECL(vnet_iter);
  488         struct lltable *llt;
  489 
  490         VNET_FOREACH(vnet_iter) {
  491                 CURVNET_SET_QUIET(vnet_iter);
  492 #ifdef VIMAGE
  493                 db_printf("vnet=%p\n", curvnet);
  494 #endif
  495                 SLIST_FOREACH(llt, &V_lltables, llt_link) {
  496                         db_printf("llt=%p llt_af=%d llt_ifp=%p(%s)\n",
  497                             llt, llt->llt_af, llt->llt_ifp,
  498                             (llt->llt_ifp != NULL) ?
  499                                 llt->llt_ifp->if_xname : "?");
  500                         if (have_addr && addr != 0) /* verbose */
  501                                 llatbl_llt_show(llt);
  502                         if (db_pager_quit) {
  503                                 CURVNET_RESTORE();
  504                                 return;
  505                         }
  506                 }
  507                 CURVNET_RESTORE();
  508         }
  509 }
  510 #endif

Cache object: a9676af96f3782f9fe60047dc2aee2bc


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