182f39c91SKip Macy /* 282f39c91SKip Macy * Copyright (c) 2004 Luigi Rizzo, Alessandro Cerri. All rights reserved. 382f39c91SKip Macy * Copyright (c) 2004-2008 Qing Li. All rights reserved. 482f39c91SKip Macy * Copyright (c) 2008 Kip Macy. All rights reserved. 582f39c91SKip Macy * 682f39c91SKip Macy * Redistribution and use in source and binary forms, with or without 782f39c91SKip Macy * modification, are permitted provided that the following conditions 882f39c91SKip Macy * are met: 982f39c91SKip Macy * 1. Redistributions of source code must retain the above copyright 1082f39c91SKip Macy * notice, this list of conditions and the following disclaimer. 1182f39c91SKip Macy * 2. Redistributions in binary form must reproduce the above copyright 1282f39c91SKip Macy * notice, this list of conditions and the following disclaimer in the 1382f39c91SKip Macy * documentation and/or other materials provided with the distribution. 1482f39c91SKip Macy * 1582f39c91SKip Macy * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1682f39c91SKip Macy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1782f39c91SKip Macy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1882f39c91SKip Macy * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 1982f39c91SKip Macy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2082f39c91SKip Macy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2182f39c91SKip Macy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2282f39c91SKip Macy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2382f39c91SKip Macy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2482f39c91SKip Macy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2582f39c91SKip Macy * SUCH DAMAGE. 2682f39c91SKip Macy */ 2782f39c91SKip Macy #include <sys/cdefs.h> 2882f39c91SKip Macy __FBSDID("$FreeBSD$"); 2982f39c91SKip Macy 30335b943fSBjoern A. Zeeb #include "opt_ddb.h" 3182f39c91SKip Macy #include "opt_inet.h" 3282f39c91SKip Macy #include "opt_inet6.h" 3382f39c91SKip Macy 3482f39c91SKip Macy #include <sys/param.h> 3582f39c91SKip Macy #include <sys/systm.h> 3682f39c91SKip Macy #include <sys/malloc.h> 3782f39c91SKip Macy #include <sys/mbuf.h> 3882f39c91SKip Macy #include <sys/syslog.h> 3982f39c91SKip Macy #include <sys/sysctl.h> 4082f39c91SKip Macy #include <sys/socket.h> 4182f39c91SKip Macy #include <sys/kernel.h> 4282f39c91SKip Macy #include <sys/lock.h> 4382f39c91SKip Macy #include <sys/mutex.h> 4482f39c91SKip Macy #include <sys/rwlock.h> 4582f39c91SKip Macy 46335b943fSBjoern A. Zeeb #ifdef DDB 47335b943fSBjoern A. Zeeb #include <ddb/ddb.h> 48335b943fSBjoern A. Zeeb #endif 49335b943fSBjoern A. Zeeb 5082f39c91SKip Macy #include <vm/uma.h> 5182f39c91SKip Macy 5282f39c91SKip Macy #include <netinet/in.h> 5382f39c91SKip Macy #include <net/if_llatbl.h> 5482f39c91SKip Macy #include <net/if.h> 5582f39c91SKip Macy #include <net/if_dl.h> 5682f39c91SKip Macy #include <net/if_var.h> 5782f39c91SKip Macy #include <net/route.h> 58530c0060SRobert Watson #include <net/vnet.h> 5982f39c91SKip Macy #include <netinet/if_ether.h> 6082f39c91SKip Macy #include <netinet6/in6_var.h> 6182f39c91SKip Macy #include <netinet6/nd6.h> 6282f39c91SKip Macy 6382f39c91SKip Macy MALLOC_DEFINE(M_LLTABLE, "lltable", "link level address tables"); 6482f39c91SKip Macy 653e288e62SDimitry Andric static VNET_DEFINE(SLIST_HEAD(, lltable), lltables); 66989e0411SMarko Zec #define V_lltables VNET(lltables) 6782f39c91SKip Macy 68989e0411SMarko Zec static void vnet_lltable_init(void); 69989e0411SMarko Zec 70f89d4c3aSAndre Oppermann struct rwlock lltable_rwlock; 71dc56e98fSRobert Watson RW_SYSINIT(lltable_rwlock, &lltable_rwlock, "lltable_rwlock"); 72dc56e98fSRobert Watson 73721cd2e0SAlexander V. Chernikov static void lltable_unlink(struct lltable *llt); 7411cdad98SAlexander V. Chernikov static void llentries_unlink(struct lltable *llt, struct llentries *head); 7511cdad98SAlexander V. Chernikov 7611cdad98SAlexander V. Chernikov static void htable_unlink_entry(struct llentry *lle); 7711cdad98SAlexander V. Chernikov static void htable_link_entry(struct lltable *llt, struct llentry *lle); 7811cdad98SAlexander V. Chernikov static int htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, 7911cdad98SAlexander V. Chernikov void *farg); 8011cdad98SAlexander V. Chernikov 8111cdad98SAlexander V. Chernikov /* 8211cdad98SAlexander V. Chernikov * Dump lle state for a specific address family. 8311cdad98SAlexander V. Chernikov */ 8411cdad98SAlexander V. Chernikov static int 8511cdad98SAlexander V. Chernikov lltable_dump_af(struct lltable *llt, struct sysctl_req *wr) 8611cdad98SAlexander V. Chernikov { 8711cdad98SAlexander V. Chernikov int error; 8811cdad98SAlexander V. Chernikov 8911cdad98SAlexander V. Chernikov LLTABLE_LOCK_ASSERT(); 9011cdad98SAlexander V. Chernikov 9111cdad98SAlexander V. Chernikov if (llt->llt_ifp->if_flags & IFF_LOOPBACK) 9211cdad98SAlexander V. Chernikov return (0); 9311cdad98SAlexander V. Chernikov error = 0; 9411cdad98SAlexander V. Chernikov 9511cdad98SAlexander V. Chernikov IF_AFDATA_RLOCK(llt->llt_ifp); 9611cdad98SAlexander V. Chernikov error = lltable_foreach_lle(llt, 9711cdad98SAlexander V. Chernikov (llt_foreach_cb_t *)llt->llt_dump_entry, wr); 9811cdad98SAlexander V. Chernikov IF_AFDATA_RUNLOCK(llt->llt_ifp); 9911cdad98SAlexander V. Chernikov 10011cdad98SAlexander V. Chernikov return (error); 10111cdad98SAlexander V. Chernikov } 10211cdad98SAlexander V. Chernikov 10382f39c91SKip Macy /* 10482f39c91SKip Macy * Dump arp state for a specific address family. 10582f39c91SKip Macy */ 10682f39c91SKip Macy int 10782f39c91SKip Macy lltable_sysctl_dumparp(int af, struct sysctl_req *wr) 10882f39c91SKip Macy { 10982f39c91SKip Macy struct lltable *llt; 11082f39c91SKip Macy int error = 0; 11182f39c91SKip Macy 112dc56e98fSRobert Watson LLTABLE_RLOCK(); 113989e0411SMarko Zec SLIST_FOREACH(llt, &V_lltables, llt_link) { 11482f39c91SKip Macy if (llt->llt_af == af) { 11511cdad98SAlexander V. Chernikov error = lltable_dump_af(llt, wr); 11682f39c91SKip Macy if (error != 0) 11782f39c91SKip Macy goto done; 11882f39c91SKip Macy } 11982f39c91SKip Macy } 12082f39c91SKip Macy done: 121dc56e98fSRobert Watson LLTABLE_RUNLOCK(); 12282f39c91SKip Macy return (error); 12382f39c91SKip Macy } 12482f39c91SKip Macy 12582f39c91SKip Macy /* 12611cdad98SAlexander V. Chernikov * Common function helpers for chained hash table. 12711cdad98SAlexander V. Chernikov */ 12811cdad98SAlexander V. Chernikov 12911cdad98SAlexander V. Chernikov /* 13011cdad98SAlexander V. Chernikov * Runs specified callback for each entry in @llt. 13111cdad98SAlexander V. Chernikov * Caller does the locking. 13211cdad98SAlexander V. Chernikov * 13311cdad98SAlexander V. Chernikov */ 13411cdad98SAlexander V. Chernikov static int 13511cdad98SAlexander V. Chernikov htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg) 13611cdad98SAlexander V. Chernikov { 13711cdad98SAlexander V. Chernikov struct llentry *lle, *next; 13811cdad98SAlexander V. Chernikov int i, error; 13911cdad98SAlexander V. Chernikov 14011cdad98SAlexander V. Chernikov error = 0; 14111cdad98SAlexander V. Chernikov 14241cb42a6SAlexander V. Chernikov for (i = 0; i < llt->llt_hsize; i++) { 14311cdad98SAlexander V. Chernikov LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) { 14411cdad98SAlexander V. Chernikov error = f(llt, lle, farg); 14511cdad98SAlexander V. Chernikov if (error != 0) 14611cdad98SAlexander V. Chernikov break; 14711cdad98SAlexander V. Chernikov } 14811cdad98SAlexander V. Chernikov } 14911cdad98SAlexander V. Chernikov 15011cdad98SAlexander V. Chernikov return (error); 15111cdad98SAlexander V. Chernikov } 15211cdad98SAlexander V. Chernikov 15311cdad98SAlexander V. Chernikov static void 15411cdad98SAlexander V. Chernikov htable_link_entry(struct lltable *llt, struct llentry *lle) 15511cdad98SAlexander V. Chernikov { 15611cdad98SAlexander V. Chernikov struct llentries *lleh; 15711cdad98SAlexander V. Chernikov uint32_t hashidx; 15811cdad98SAlexander V. Chernikov 15911cdad98SAlexander V. Chernikov if ((lle->la_flags & LLE_LINKED) != 0) 16011cdad98SAlexander V. Chernikov return; 16111cdad98SAlexander V. Chernikov 16211cdad98SAlexander V. Chernikov IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp); 16311cdad98SAlexander V. Chernikov 1643a749863SAlexander V. Chernikov hashidx = llt->llt_hash(lle, llt->llt_hsize); 16511cdad98SAlexander V. Chernikov lleh = &llt->lle_head[hashidx]; 16611cdad98SAlexander V. Chernikov 16711cdad98SAlexander V. Chernikov lle->lle_tbl = llt; 16811cdad98SAlexander V. Chernikov lle->lle_head = lleh; 16911cdad98SAlexander V. Chernikov lle->la_flags |= LLE_LINKED; 17011cdad98SAlexander V. Chernikov LIST_INSERT_HEAD(lleh, lle, lle_next); 17111cdad98SAlexander V. Chernikov } 17211cdad98SAlexander V. Chernikov 17311cdad98SAlexander V. Chernikov static void 17411cdad98SAlexander V. Chernikov htable_unlink_entry(struct llentry *lle) 17511cdad98SAlexander V. Chernikov { 17611cdad98SAlexander V. Chernikov 17711cdad98SAlexander V. Chernikov if ((lle->la_flags & LLE_LINKED) != 0) { 17811cdad98SAlexander V. Chernikov IF_AFDATA_WLOCK_ASSERT(lle->lle_tbl->llt_ifp); 17911cdad98SAlexander V. Chernikov LIST_REMOVE(lle, lle_next); 18011cdad98SAlexander V. Chernikov lle->la_flags &= ~(LLE_VALID | LLE_LINKED); 18111cdad98SAlexander V. Chernikov #if 0 18211cdad98SAlexander V. Chernikov lle->lle_tbl = NULL; 18311cdad98SAlexander V. Chernikov lle->lle_head = NULL; 18411cdad98SAlexander V. Chernikov #endif 18511cdad98SAlexander V. Chernikov } 18611cdad98SAlexander V. Chernikov } 18711cdad98SAlexander V. Chernikov 18811cdad98SAlexander V. Chernikov struct prefix_match_data { 1893e7a2321SAlexander V. Chernikov const struct sockaddr *addr; 19011cdad98SAlexander V. Chernikov const struct sockaddr *mask; 19111cdad98SAlexander V. Chernikov struct llentries dchain; 19211cdad98SAlexander V. Chernikov u_int flags; 19311cdad98SAlexander V. Chernikov }; 19411cdad98SAlexander V. Chernikov 19511cdad98SAlexander V. Chernikov static int 19611cdad98SAlexander V. Chernikov htable_prefix_free_cb(struct lltable *llt, struct llentry *lle, void *farg) 19711cdad98SAlexander V. Chernikov { 19811cdad98SAlexander V. Chernikov struct prefix_match_data *pmd; 19911cdad98SAlexander V. Chernikov 20011cdad98SAlexander V. Chernikov pmd = (struct prefix_match_data *)farg; 20111cdad98SAlexander V. Chernikov 2023e7a2321SAlexander V. Chernikov if (llt->llt_match_prefix(pmd->addr, pmd->mask, pmd->flags, lle)) { 20311cdad98SAlexander V. Chernikov LLE_WLOCK(lle); 20411cdad98SAlexander V. Chernikov LIST_INSERT_HEAD(&pmd->dchain, lle, lle_chain); 20511cdad98SAlexander V. Chernikov } 20611cdad98SAlexander V. Chernikov 20711cdad98SAlexander V. Chernikov return (0); 20811cdad98SAlexander V. Chernikov } 20911cdad98SAlexander V. Chernikov 21011cdad98SAlexander V. Chernikov static void 2113e7a2321SAlexander V. Chernikov htable_prefix_free(struct lltable *llt, const struct sockaddr *addr, 21211cdad98SAlexander V. Chernikov const struct sockaddr *mask, u_int flags) 21311cdad98SAlexander V. Chernikov { 21411cdad98SAlexander V. Chernikov struct llentry *lle, *next; 21511cdad98SAlexander V. Chernikov struct prefix_match_data pmd; 21611cdad98SAlexander V. Chernikov 21711cdad98SAlexander V. Chernikov bzero(&pmd, sizeof(pmd)); 2183e7a2321SAlexander V. Chernikov pmd.addr = addr; 21911cdad98SAlexander V. Chernikov pmd.mask = mask; 22011cdad98SAlexander V. Chernikov pmd.flags = flags; 22111cdad98SAlexander V. Chernikov LIST_INIT(&pmd.dchain); 22211cdad98SAlexander V. Chernikov 22311cdad98SAlexander V. Chernikov IF_AFDATA_WLOCK(llt->llt_ifp); 22411cdad98SAlexander V. Chernikov /* Push matching lles to chain */ 22511cdad98SAlexander V. Chernikov lltable_foreach_lle(llt, htable_prefix_free_cb, &pmd); 22611cdad98SAlexander V. Chernikov 22711cdad98SAlexander V. Chernikov llentries_unlink(llt, &pmd.dchain); 22811cdad98SAlexander V. Chernikov IF_AFDATA_WUNLOCK(llt->llt_ifp); 22911cdad98SAlexander V. Chernikov 23011cdad98SAlexander V. Chernikov LIST_FOREACH_SAFE(lle, &pmd.dchain, lle_chain, next) 2315a255516SAlexander V. Chernikov lltable_free_entry(llt, lle); 23211cdad98SAlexander V. Chernikov } 23311cdad98SAlexander V. Chernikov 23411cdad98SAlexander V. Chernikov static void 23541cb42a6SAlexander V. Chernikov htable_free_tbl(struct lltable *llt) 23641cb42a6SAlexander V. Chernikov { 23741cb42a6SAlexander V. Chernikov 23841cb42a6SAlexander V. Chernikov free(llt->lle_head, M_LLTABLE); 23941cb42a6SAlexander V. Chernikov free(llt, M_LLTABLE); 24041cb42a6SAlexander V. Chernikov } 24141cb42a6SAlexander V. Chernikov 242721cd2e0SAlexander V. Chernikov static void 24311cdad98SAlexander V. Chernikov llentries_unlink(struct lltable *llt, struct llentries *head) 24411cdad98SAlexander V. Chernikov { 24511cdad98SAlexander V. Chernikov struct llentry *lle, *next; 24611cdad98SAlexander V. Chernikov 24711cdad98SAlexander V. Chernikov LIST_FOREACH_SAFE(lle, head, lle_chain, next) 24811cdad98SAlexander V. Chernikov llt->llt_unlink_entry(lle); 24911cdad98SAlexander V. Chernikov } 25011cdad98SAlexander V. Chernikov 25111cdad98SAlexander V. Chernikov /* 25211cdad98SAlexander V. Chernikov * Helper function used to drop all mbufs in hold queue. 253e162ea60SGeorge V. Neville-Neil * 254e162ea60SGeorge V. Neville-Neil * Returns the number of held packets, if any, that were dropped. 25582f39c91SKip Macy */ 256e162ea60SGeorge V. Neville-Neil size_t 25711cdad98SAlexander V. Chernikov lltable_drop_entry_queue(struct llentry *lle) 25882f39c91SKip Macy { 259e162ea60SGeorge V. Neville-Neil size_t pkts_dropped; 260e162ea60SGeorge V. Neville-Neil struct mbuf *next; 26182f39c91SKip Macy 26282f39c91SKip Macy LLE_WLOCK_ASSERT(lle); 26382f39c91SKip Macy 264ea537929SGleb Smirnoff pkts_dropped = 0; 265e162ea60SGeorge V. Neville-Neil while ((lle->la_numheld > 0) && (lle->la_hold != NULL)) { 266e162ea60SGeorge V. Neville-Neil next = lle->la_hold->m_nextpkt; 26782f39c91SKip Macy m_freem(lle->la_hold); 268e162ea60SGeorge V. Neville-Neil lle->la_hold = next; 269e162ea60SGeorge V. Neville-Neil lle->la_numheld--; 270e162ea60SGeorge V. Neville-Neil pkts_dropped++; 271e162ea60SGeorge V. Neville-Neil } 272e162ea60SGeorge V. Neville-Neil 273e162ea60SGeorge V. Neville-Neil KASSERT(lle->la_numheld == 0, 2747b3b099eSKonstantin Belousov ("%s: la_numheld %d > 0, pkts_droped %zd", __func__, 275e162ea60SGeorge V. Neville-Neil lle->la_numheld, pkts_dropped)); 27682f39c91SKip Macy 27711cdad98SAlexander V. Chernikov return (pkts_dropped); 27811cdad98SAlexander V. Chernikov } 27911cdad98SAlexander V. Chernikov 28011cdad98SAlexander V. Chernikov /* 2815a255516SAlexander V. Chernikov * 2825a255516SAlexander V. Chernikov * Performes generic cleanup routines and frees lle. 2835a255516SAlexander V. Chernikov * 2845a255516SAlexander V. Chernikov * Called for non-linked entries, with callouts and 2855a255516SAlexander V. Chernikov * other AF-specific cleanups performed. 2865a255516SAlexander V. Chernikov * 2875a255516SAlexander V. Chernikov * @lle must be passed WLOCK'ed 28811cdad98SAlexander V. Chernikov * 28911cdad98SAlexander V. Chernikov * Returns the number of held packets, if any, that were dropped. 29011cdad98SAlexander V. Chernikov */ 29111cdad98SAlexander V. Chernikov size_t 29211cdad98SAlexander V. Chernikov llentry_free(struct llentry *lle) 29311cdad98SAlexander V. Chernikov { 29411cdad98SAlexander V. Chernikov size_t pkts_dropped; 29511cdad98SAlexander V. Chernikov 29611cdad98SAlexander V. Chernikov LLE_WLOCK_ASSERT(lle); 29711cdad98SAlexander V. Chernikov 298*d3cdb716SAlexander V. Chernikov KASSERT((lle->la_flags & LLE_LINKED) == 0, ("freeing linked lle")); 29911cdad98SAlexander V. Chernikov 30011cdad98SAlexander V. Chernikov pkts_dropped = lltable_drop_entry_queue(lle); 30111cdad98SAlexander V. Chernikov 30282f39c91SKip Macy LLE_FREE_LOCKED(lle); 303e162ea60SGeorge V. Neville-Neil 304e162ea60SGeorge V. Neville-Neil return (pkts_dropped); 30582f39c91SKip Macy } 30682f39c91SKip Macy 307adfc35ffSKip Macy /* 308b1d86af7SGleb Smirnoff * (al)locate an llentry for address dst (equivalent to rtalloc for new-arp). 309e94ba2ceSKip Macy * 310b1d86af7SGleb Smirnoff * If found the llentry * is returned referenced and unlocked. 311adfc35ffSKip Macy */ 312b1d86af7SGleb Smirnoff struct llentry * 313b1d86af7SGleb Smirnoff llentry_alloc(struct ifnet *ifp, struct lltable *lt, 314b1d86af7SGleb Smirnoff struct sockaddr_storage *dst) 315c8da95acSKip Macy { 3165a255516SAlexander V. Chernikov struct llentry *la, *la_tmp; 317c8da95acSKip Macy 318c8da95acSKip Macy IF_AFDATA_RLOCK(ifp); 319b1d86af7SGleb Smirnoff la = lla_lookup(lt, LLE_EXCLUSIVE, (struct sockaddr *)dst); 320c8da95acSKip Macy IF_AFDATA_RUNLOCK(ifp); 321b1d86af7SGleb Smirnoff 322b1d86af7SGleb Smirnoff if (la != NULL) { 323c8da95acSKip Macy LLE_ADDREF(la); 324c8da95acSKip Macy LLE_WUNLOCK(la); 3255a255516SAlexander V. Chernikov return (la); 3265a255516SAlexander V. Chernikov } 3275a255516SAlexander V. Chernikov 3285a255516SAlexander V. Chernikov if ((ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0) { 3295a255516SAlexander V. Chernikov la = lltable_alloc_entry(lt, 0, (struct sockaddr *)dst); 3305a255516SAlexander V. Chernikov if (la == NULL) 3315a255516SAlexander V. Chernikov return (NULL); 3325a255516SAlexander V. Chernikov IF_AFDATA_WLOCK(ifp); 3335a255516SAlexander V. Chernikov LLE_WLOCK(la); 3345a255516SAlexander V. Chernikov /* Prefer any existing LLE over newly-created one */ 3355a255516SAlexander V. Chernikov la_tmp = lla_lookup(lt, LLE_EXCLUSIVE, (struct sockaddr *)dst); 3365a255516SAlexander V. Chernikov if (la_tmp == NULL) 3375a255516SAlexander V. Chernikov lltable_link_entry(lt, la); 3385a255516SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 3395a255516SAlexander V. Chernikov if (la_tmp != NULL) { 3405a255516SAlexander V. Chernikov lltable_free_entry(lt, la); 3415a255516SAlexander V. Chernikov la = la_tmp; 3425a255516SAlexander V. Chernikov } 3435a255516SAlexander V. Chernikov LLE_ADDREF(la); 3445a255516SAlexander V. Chernikov LLE_WUNLOCK(la); 345b1d86af7SGleb Smirnoff } 346c8da95acSKip Macy 347b1d86af7SGleb Smirnoff return (la); 348c8da95acSKip Macy } 349c8da95acSKip Macy 35082f39c91SKip Macy /* 35182f39c91SKip Macy * Free all entries from given table and free itself. 35282f39c91SKip Macy */ 35311cdad98SAlexander V. Chernikov 35411cdad98SAlexander V. Chernikov static int 35511cdad98SAlexander V. Chernikov lltable_free_cb(struct lltable *llt, struct llentry *lle, void *farg) 35611cdad98SAlexander V. Chernikov { 35711cdad98SAlexander V. Chernikov struct llentries *dchain; 35811cdad98SAlexander V. Chernikov 35911cdad98SAlexander V. Chernikov dchain = (struct llentries *)farg; 36011cdad98SAlexander V. Chernikov 36111cdad98SAlexander V. Chernikov LLE_WLOCK(lle); 36211cdad98SAlexander V. Chernikov LIST_INSERT_HEAD(dchain, lle, lle_chain); 36311cdad98SAlexander V. Chernikov 36411cdad98SAlexander V. Chernikov return (0); 36511cdad98SAlexander V. Chernikov } 36611cdad98SAlexander V. Chernikov 36711cdad98SAlexander V. Chernikov /* 36811cdad98SAlexander V. Chernikov * Free all entries from given table and free itself. 36911cdad98SAlexander V. Chernikov */ 37082f39c91SKip Macy void 37182f39c91SKip Macy lltable_free(struct lltable *llt) 37282f39c91SKip Macy { 37382f39c91SKip Macy struct llentry *lle, *next; 37411cdad98SAlexander V. Chernikov struct llentries dchain; 37582f39c91SKip Macy 37682f39c91SKip Macy KASSERT(llt != NULL, ("%s: llt is NULL", __func__)); 37782f39c91SKip Macy 378721cd2e0SAlexander V. Chernikov lltable_unlink(llt); 37982f39c91SKip Macy 38011cdad98SAlexander V. Chernikov LIST_INIT(&dchain); 381ea537929SGleb Smirnoff IF_AFDATA_WLOCK(llt->llt_ifp); 38211cdad98SAlexander V. Chernikov /* Push all lles to @dchain */ 38311cdad98SAlexander V. Chernikov lltable_foreach_lle(llt, lltable_free_cb, &dchain); 38411cdad98SAlexander V. Chernikov llentries_unlink(llt, &dchain); 38511cdad98SAlexander V. Chernikov IF_AFDATA_WUNLOCK(llt->llt_ifp); 38611cdad98SAlexander V. Chernikov 38711cdad98SAlexander V. Chernikov LIST_FOREACH_SAFE(lle, &dchain, lle_chain, next) { 3880447c136SAlexander V. Chernikov if (callout_stop(&lle->lle_timer)) 389becba438SBjoern A. Zeeb LLE_REMREF(lle); 39082f39c91SKip Macy llentry_free(lle); 39182f39c91SKip Macy } 39282f39c91SKip Macy 393721cd2e0SAlexander V. Chernikov llt->llt_free_tbl(llt); 39482f39c91SKip Macy } 39582f39c91SKip Macy 396fc2bfb32SBjoern A. Zeeb #if 0 39782f39c91SKip Macy void 39882f39c91SKip Macy lltable_drain(int af) 39982f39c91SKip Macy { 40082f39c91SKip Macy struct lltable *llt; 40182f39c91SKip Macy struct llentry *lle; 40282f39c91SKip Macy register int i; 40382f39c91SKip Macy 404dc56e98fSRobert Watson LLTABLE_RLOCK(); 405989e0411SMarko Zec SLIST_FOREACH(llt, &V_lltables, llt_link) { 40682f39c91SKip Macy if (llt->llt_af != af) 40782f39c91SKip Macy continue; 40882f39c91SKip Macy 4093a749863SAlexander V. Chernikov for (i=0; i < llt->llt_hsize; i++) { 41082f39c91SKip Macy LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { 411fc2bfb32SBjoern A. Zeeb LLE_WLOCK(lle); 41282f39c91SKip Macy if (lle->la_hold) { 41382f39c91SKip Macy m_freem(lle->la_hold); 41482f39c91SKip Macy lle->la_hold = NULL; 41582f39c91SKip Macy } 416fc2bfb32SBjoern A. Zeeb LLE_WUNLOCK(lle); 41782f39c91SKip Macy } 41882f39c91SKip Macy } 41982f39c91SKip Macy } 420dc56e98fSRobert Watson LLTABLE_RUNLOCK(); 42182f39c91SKip Macy } 422fc2bfb32SBjoern A. Zeeb #endif 42382f39c91SKip Macy 4243e7a2321SAlexander V. Chernikov /* 4253e7a2321SAlexander V. Chernikov * Deletes an address from given lltable. 4263e7a2321SAlexander V. Chernikov * Used for userland interaction to remove 4273e7a2321SAlexander V. Chernikov * individual entries. Skips entries added by OS. 4283e7a2321SAlexander V. Chernikov */ 4293e7a2321SAlexander V. Chernikov int 4303e7a2321SAlexander V. Chernikov lltable_delete_addr(struct lltable *llt, u_int flags, 4313e7a2321SAlexander V. Chernikov const struct sockaddr *l3addr) 4323e7a2321SAlexander V. Chernikov { 4333e7a2321SAlexander V. Chernikov struct llentry *lle; 4343e7a2321SAlexander V. Chernikov struct ifnet *ifp; 4353e7a2321SAlexander V. Chernikov 4363e7a2321SAlexander V. Chernikov ifp = llt->llt_ifp; 4373e7a2321SAlexander V. Chernikov IF_AFDATA_WLOCK(ifp); 4383e7a2321SAlexander V. Chernikov lle = lla_lookup(llt, LLE_EXCLUSIVE, l3addr); 4393e7a2321SAlexander V. Chernikov 4403e7a2321SAlexander V. Chernikov if (lle == NULL) { 4413e7a2321SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 4423e7a2321SAlexander V. Chernikov return (ENOENT); 4433e7a2321SAlexander V. Chernikov } 4443e7a2321SAlexander V. Chernikov if ((lle->la_flags & LLE_IFADDR) != 0 && (flags & LLE_IFADDR) == 0) { 4453e7a2321SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 4463e7a2321SAlexander V. Chernikov LLE_WUNLOCK(lle); 4473e7a2321SAlexander V. Chernikov return (EPERM); 4483e7a2321SAlexander V. Chernikov } 4493e7a2321SAlexander V. Chernikov 4503e7a2321SAlexander V. Chernikov lltable_unlink_entry(llt, lle); 4513e7a2321SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 4523e7a2321SAlexander V. Chernikov 4533e7a2321SAlexander V. Chernikov llt->llt_delete_entry(llt, lle); 4543e7a2321SAlexander V. Chernikov 4553e7a2321SAlexander V. Chernikov return (0); 4563e7a2321SAlexander V. Chernikov } 4573e7a2321SAlexander V. Chernikov 458c9d763bfSQing Li void 4593e7a2321SAlexander V. Chernikov lltable_prefix_free(int af, struct sockaddr *addr, struct sockaddr *mask, 4605b84dc78SQing Li u_int flags) 461c9d763bfSQing Li { 462c9d763bfSQing Li struct lltable *llt; 463c9d763bfSQing Li 464dc56e98fSRobert Watson LLTABLE_RLOCK(); 465989e0411SMarko Zec SLIST_FOREACH(llt, &V_lltables, llt_link) { 466c9d763bfSQing Li if (llt->llt_af != af) 467c9d763bfSQing Li continue; 468c9d763bfSQing Li 4693e7a2321SAlexander V. Chernikov llt->llt_prefix_free(llt, addr, mask, flags); 470c9d763bfSQing Li } 471dc56e98fSRobert Watson LLTABLE_RUNLOCK(); 472c9d763bfSQing Li } 473c9d763bfSQing Li 47482f39c91SKip Macy struct lltable * 47541cb42a6SAlexander V. Chernikov lltable_allocate_htbl(uint32_t hsize) 47682f39c91SKip Macy { 47782f39c91SKip Macy struct lltable *llt; 47841cb42a6SAlexander V. Chernikov int i; 47982f39c91SKip Macy 48041cb42a6SAlexander V. Chernikov llt = malloc(sizeof(struct lltable), M_LLTABLE, M_WAITOK | M_ZERO); 48141cb42a6SAlexander V. Chernikov llt->llt_hsize = hsize; 48241cb42a6SAlexander V. Chernikov llt->lle_head = malloc(sizeof(struct llentries) * hsize, 48341cb42a6SAlexander V. Chernikov M_LLTABLE, M_WAITOK | M_ZERO); 48482f39c91SKip Macy 48541cb42a6SAlexander V. Chernikov for (i = 0; i < llt->llt_hsize; i++) 48682f39c91SKip Macy LIST_INIT(&llt->lle_head[i]); 48782f39c91SKip Macy 48811cdad98SAlexander V. Chernikov /* Set some default callbacks */ 48911cdad98SAlexander V. Chernikov llt->llt_link_entry = htable_link_entry; 49011cdad98SAlexander V. Chernikov llt->llt_unlink_entry = htable_unlink_entry; 49111cdad98SAlexander V. Chernikov llt->llt_prefix_free = htable_prefix_free; 49211cdad98SAlexander V. Chernikov llt->llt_foreach_entry = htable_foreach_lle; 49341cb42a6SAlexander V. Chernikov llt->llt_free_tbl = htable_free_tbl; 49441cb42a6SAlexander V. Chernikov 49541cb42a6SAlexander V. Chernikov return (llt); 49641cb42a6SAlexander V. Chernikov } 49741cb42a6SAlexander V. Chernikov 49882f39c91SKip Macy /* 499721cd2e0SAlexander V. Chernikov * Links lltable to global llt list. 50082f39c91SKip Macy */ 501721cd2e0SAlexander V. Chernikov void 502721cd2e0SAlexander V. Chernikov lltable_link(struct lltable *llt) 50382f39c91SKip Macy { 50411cdad98SAlexander V. Chernikov 505dc56e98fSRobert Watson LLTABLE_WLOCK(); 506989e0411SMarko Zec SLIST_INSERT_HEAD(&V_lltables, llt, llt_link); 507dc56e98fSRobert Watson LLTABLE_WUNLOCK(); 508721cd2e0SAlexander V. Chernikov } 50982f39c91SKip Macy 510721cd2e0SAlexander V. Chernikov static void 511721cd2e0SAlexander V. Chernikov lltable_unlink(struct lltable *llt) 512721cd2e0SAlexander V. Chernikov { 513721cd2e0SAlexander V. Chernikov 514721cd2e0SAlexander V. Chernikov LLTABLE_WLOCK(); 515721cd2e0SAlexander V. Chernikov SLIST_REMOVE(&V_lltables, llt, lltable, llt_link); 516721cd2e0SAlexander V. Chernikov LLTABLE_WUNLOCK(); 517721cd2e0SAlexander V. Chernikov 51882f39c91SKip Macy } 51982f39c91SKip Macy 52082f39c91SKip Macy /* 52111cdad98SAlexander V. Chernikov * External methods used by lltable consumers 52211cdad98SAlexander V. Chernikov */ 52311cdad98SAlexander V. Chernikov 52411cdad98SAlexander V. Chernikov int 52511cdad98SAlexander V. Chernikov lltable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg) 52611cdad98SAlexander V. Chernikov { 52711cdad98SAlexander V. Chernikov 52811cdad98SAlexander V. Chernikov return (llt->llt_foreach_entry(llt, f, farg)); 52911cdad98SAlexander V. Chernikov } 53011cdad98SAlexander V. Chernikov 5315a255516SAlexander V. Chernikov struct llentry * 5325a255516SAlexander V. Chernikov lltable_alloc_entry(struct lltable *llt, u_int flags, 5335a255516SAlexander V. Chernikov const struct sockaddr *l3addr) 5345a255516SAlexander V. Chernikov { 5355a255516SAlexander V. Chernikov 5365a255516SAlexander V. Chernikov return (llt->llt_alloc_entry(llt, flags, l3addr)); 5375a255516SAlexander V. Chernikov } 5385a255516SAlexander V. Chernikov 5395a255516SAlexander V. Chernikov void 5405a255516SAlexander V. Chernikov lltable_free_entry(struct lltable *llt, struct llentry *lle) 5415a255516SAlexander V. Chernikov { 5425a255516SAlexander V. Chernikov 5435a255516SAlexander V. Chernikov llt->llt_free_entry(llt, lle); 5445a255516SAlexander V. Chernikov } 5455a255516SAlexander V. Chernikov 54611cdad98SAlexander V. Chernikov void 54711cdad98SAlexander V. Chernikov lltable_link_entry(struct lltable *llt, struct llentry *lle) 54811cdad98SAlexander V. Chernikov { 54911cdad98SAlexander V. Chernikov 55011cdad98SAlexander V. Chernikov llt->llt_link_entry(llt, lle); 55111cdad98SAlexander V. Chernikov } 55211cdad98SAlexander V. Chernikov 55311cdad98SAlexander V. Chernikov void 55411cdad98SAlexander V. Chernikov lltable_unlink_entry(struct lltable *llt, struct llentry *lle) 55511cdad98SAlexander V. Chernikov { 55611cdad98SAlexander V. Chernikov 55711cdad98SAlexander V. Chernikov llt->llt_unlink_entry(lle); 55811cdad98SAlexander V. Chernikov } 55911cdad98SAlexander V. Chernikov 56011cdad98SAlexander V. Chernikov void 56111cdad98SAlexander V. Chernikov lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa) 56211cdad98SAlexander V. Chernikov { 56311cdad98SAlexander V. Chernikov struct lltable *llt; 56411cdad98SAlexander V. Chernikov 56511cdad98SAlexander V. Chernikov llt = lle->lle_tbl; 56611cdad98SAlexander V. Chernikov llt->llt_fill_sa_entry(lle, sa); 56711cdad98SAlexander V. Chernikov } 56811cdad98SAlexander V. Chernikov 56911cdad98SAlexander V. Chernikov struct ifnet * 57011cdad98SAlexander V. Chernikov lltable_get_ifp(const struct lltable *llt) 57111cdad98SAlexander V. Chernikov { 57211cdad98SAlexander V. Chernikov 57311cdad98SAlexander V. Chernikov return (llt->llt_ifp); 57411cdad98SAlexander V. Chernikov } 57511cdad98SAlexander V. Chernikov 57611cdad98SAlexander V. Chernikov int 57711cdad98SAlexander V. Chernikov lltable_get_af(const struct lltable *llt) 57811cdad98SAlexander V. Chernikov { 57911cdad98SAlexander V. Chernikov 58011cdad98SAlexander V. Chernikov return (llt->llt_af); 58111cdad98SAlexander V. Chernikov } 58211cdad98SAlexander V. Chernikov 58311cdad98SAlexander V. Chernikov /* 584b4b1367aSAlexander V. Chernikov * Called in route_output when rtm_flags contains RTF_LLDATA. 58582f39c91SKip Macy */ 58682f39c91SKip Macy int 58782f39c91SKip Macy lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info) 58882f39c91SKip Macy { 58982f39c91SKip Macy struct sockaddr_dl *dl = 59082f39c91SKip Macy (struct sockaddr_dl *)info->rti_info[RTAX_GATEWAY]; 59182f39c91SKip Macy struct sockaddr *dst = (struct sockaddr *)info->rti_info[RTAX_DST]; 59282f39c91SKip Macy struct ifnet *ifp; 59382f39c91SKip Macy struct lltable *llt; 5945a255516SAlexander V. Chernikov struct llentry *lle, *lle_tmp; 595b4b1367aSAlexander V. Chernikov u_int laflags = 0; 596b4b1367aSAlexander V. Chernikov int error; 59782f39c91SKip Macy 5981910bfcbSGleb Smirnoff KASSERT(dl != NULL && dl->sdl_family == AF_LINK, 5991910bfcbSGleb Smirnoff ("%s: invalid dl\n", __func__)); 6001910bfcbSGleb Smirnoff 60182f39c91SKip Macy ifp = ifnet_byindex(dl->sdl_index); 60282f39c91SKip Macy if (ifp == NULL) { 60382f39c91SKip Macy log(LOG_INFO, "%s: invalid ifp (sdl_index %d)\n", 60482f39c91SKip Macy __func__, dl->sdl_index); 60582f39c91SKip Macy return EINVAL; 60682f39c91SKip Macy } 60782f39c91SKip Macy 60882f39c91SKip Macy /* XXX linked list may be too expensive */ 609dc56e98fSRobert Watson LLTABLE_RLOCK(); 610989e0411SMarko Zec SLIST_FOREACH(llt, &V_lltables, llt_link) { 61182f39c91SKip Macy if (llt->llt_af == dst->sa_family && 61282f39c91SKip Macy llt->llt_ifp == ifp) 61382f39c91SKip Macy break; 61482f39c91SKip Macy } 615dc56e98fSRobert Watson LLTABLE_RUNLOCK(); 61682f39c91SKip Macy KASSERT(llt != NULL, ("Yep, ugly hacks are bad\n")); 61782f39c91SKip Macy 618b4b1367aSAlexander V. Chernikov error = 0; 61982f39c91SKip Macy 620b4b1367aSAlexander V. Chernikov switch (rtm->rtm_type) { 621b4b1367aSAlexander V. Chernikov case RTM_ADD: 622b4b1367aSAlexander V. Chernikov /* Add static LLE */ 6233b0fd911SAlexander V. Chernikov laflags = 0; 6243b0fd911SAlexander V. Chernikov if (rtm->rtm_rmx.rmx_expire == 0) 6253b0fd911SAlexander V. Chernikov laflags = LLE_STATIC; 6263b0fd911SAlexander V. Chernikov lle = lltable_alloc_entry(llt, laflags, dst); 6275a255516SAlexander V. Chernikov if (lle == NULL) 628b4b1367aSAlexander V. Chernikov return (ENOMEM); 629b4b1367aSAlexander V. Chernikov 63082f39c91SKip Macy bcopy(LLADDR(dl), &lle->ll_addr, ifp->if_addrlen); 631b4b1367aSAlexander V. Chernikov if ((rtm->rtm_flags & RTF_ANNOUNCE)) 632b4b1367aSAlexander V. Chernikov lle->la_flags |= LLE_PUB; 63382f39c91SKip Macy lle->la_flags |= LLE_VALID; 63482f39c91SKip Macy lle->la_expire = rtm->rtm_rmx.rmx_expire; 6353b0fd911SAlexander V. Chernikov 63682f39c91SKip Macy laflags = lle->la_flags; 6375a255516SAlexander V. Chernikov 6385a255516SAlexander V. Chernikov /* Try to link new entry */ 6395a255516SAlexander V. Chernikov lle_tmp = NULL; 6405a255516SAlexander V. Chernikov IF_AFDATA_WLOCK(ifp); 6415a255516SAlexander V. Chernikov LLE_WLOCK(lle); 6425a255516SAlexander V. Chernikov lle_tmp = lla_lookup(llt, LLE_EXCLUSIVE, dst); 6435a255516SAlexander V. Chernikov if (lle_tmp != NULL) { 6445a255516SAlexander V. Chernikov /* Check if we are trying to replace immutable entry */ 6455a255516SAlexander V. Chernikov if ((lle_tmp->la_flags & LLE_IFADDR) != 0) { 646b4b1367aSAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 6475a255516SAlexander V. Chernikov LLE_WUNLOCK(lle_tmp); 6485a255516SAlexander V. Chernikov lltable_free_entry(llt, lle); 6495a255516SAlexander V. Chernikov return (EPERM); 6505a255516SAlexander V. Chernikov } 6515a255516SAlexander V. Chernikov /* Unlink existing entry from table */ 6525a255516SAlexander V. Chernikov lltable_unlink_entry(llt, lle_tmp); 6535a255516SAlexander V. Chernikov } 6545a255516SAlexander V. Chernikov lltable_link_entry(llt, lle); 6555a255516SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 6565a255516SAlexander V. Chernikov 6575a255516SAlexander V. Chernikov if (lle_tmp != NULL) { 6585a255516SAlexander V. Chernikov EVENTHANDLER_INVOKE(lle_event, lle_tmp,LLENTRY_EXPIRED); 6595a255516SAlexander V. Chernikov lltable_free_entry(llt, lle_tmp); 6605a255516SAlexander V. Chernikov } 6615a255516SAlexander V. Chernikov 6625a255516SAlexander V. Chernikov /* 6635a255516SAlexander V. Chernikov * By invoking LLE handler here we might get 6645a255516SAlexander V. Chernikov * two events on static LLE entry insertion 6655a255516SAlexander V. Chernikov * in routing socket. However, since we might have 6665a255516SAlexander V. Chernikov * other subscribers we need to generate this event. 6675a255516SAlexander V. Chernikov */ 6685a255516SAlexander V. Chernikov EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_RESOLVED); 6695a255516SAlexander V. Chernikov LLE_WUNLOCK(lle); 67082f39c91SKip Macy #ifdef INET 6717b4d716bSKip Macy /* gratuitous ARP */ 6729711a168SGleb Smirnoff if ((laflags & LLE_PUB) && dst->sa_family == AF_INET) 67382f39c91SKip Macy arprequest(ifp, 67482f39c91SKip Macy &((struct sockaddr_in *)dst)->sin_addr, 67582f39c91SKip Macy &((struct sockaddr_in *)dst)->sin_addr, 6769711a168SGleb Smirnoff (u_char *)LLADDR(dl)); 67782f39c91SKip Macy #endif 67882f39c91SKip Macy 679b4b1367aSAlexander V. Chernikov break; 680b4b1367aSAlexander V. Chernikov 681b4b1367aSAlexander V. Chernikov case RTM_DELETE: 6823e7a2321SAlexander V. Chernikov return (lltable_delete_addr(llt, 0, dst)); 683b4b1367aSAlexander V. Chernikov 684b4b1367aSAlexander V. Chernikov default: 685b4b1367aSAlexander V. Chernikov error = EINVAL; 686b4b1367aSAlexander V. Chernikov } 68782f39c91SKip Macy 68882f39c91SKip Macy return (error); 68982f39c91SKip Macy } 690989e0411SMarko Zec 691989e0411SMarko Zec static void 692989e0411SMarko Zec vnet_lltable_init() 693989e0411SMarko Zec { 694989e0411SMarko Zec 695989e0411SMarko Zec SLIST_INIT(&V_lltables); 696989e0411SMarko Zec } 69738d61195SMarko Zec VNET_SYSINIT(vnet_lltable_init, SI_SUB_PSEUDO, SI_ORDER_FIRST, 69838d61195SMarko Zec vnet_lltable_init, NULL); 699989e0411SMarko Zec 700335b943fSBjoern A. Zeeb #ifdef DDB 701335b943fSBjoern A. Zeeb struct llentry_sa { 702335b943fSBjoern A. Zeeb struct llentry base; 703335b943fSBjoern A. Zeeb struct sockaddr l3_addr; 704335b943fSBjoern A. Zeeb }; 705335b943fSBjoern A. Zeeb 706335b943fSBjoern A. Zeeb static void 707335b943fSBjoern A. Zeeb llatbl_lle_show(struct llentry_sa *la) 708335b943fSBjoern A. Zeeb { 709335b943fSBjoern A. Zeeb struct llentry *lle; 710335b943fSBjoern A. Zeeb uint8_t octet[6]; 711335b943fSBjoern A. Zeeb 712335b943fSBjoern A. Zeeb lle = &la->base; 713335b943fSBjoern A. Zeeb db_printf("lle=%p\n", lle); 714335b943fSBjoern A. Zeeb db_printf(" lle_next=%p\n", lle->lle_next.le_next); 715335b943fSBjoern A. Zeeb db_printf(" lle_lock=%p\n", &lle->lle_lock); 716335b943fSBjoern A. Zeeb db_printf(" lle_tbl=%p\n", lle->lle_tbl); 717335b943fSBjoern A. Zeeb db_printf(" lle_head=%p\n", lle->lle_head); 718335b943fSBjoern A. Zeeb db_printf(" la_hold=%p\n", lle->la_hold); 719e162ea60SGeorge V. Neville-Neil db_printf(" la_numheld=%d\n", lle->la_numheld); 720335b943fSBjoern A. Zeeb db_printf(" la_expire=%ju\n", (uintmax_t)lle->la_expire); 721335b943fSBjoern A. Zeeb db_printf(" la_flags=0x%04x\n", lle->la_flags); 722335b943fSBjoern A. Zeeb db_printf(" la_asked=%u\n", lle->la_asked); 723335b943fSBjoern A. Zeeb db_printf(" la_preempt=%u\n", lle->la_preempt); 724335b943fSBjoern A. Zeeb db_printf(" ln_byhint=%u\n", lle->ln_byhint); 725335b943fSBjoern A. Zeeb db_printf(" ln_state=%d\n", lle->ln_state); 726335b943fSBjoern A. Zeeb db_printf(" ln_router=%u\n", lle->ln_router); 727335b943fSBjoern A. Zeeb db_printf(" ln_ntick=%ju\n", (uintmax_t)lle->ln_ntick); 728335b943fSBjoern A. Zeeb db_printf(" lle_refcnt=%d\n", lle->lle_refcnt); 729335b943fSBjoern A. Zeeb bcopy(&lle->ll_addr.mac16, octet, sizeof(octet)); 730335b943fSBjoern A. Zeeb db_printf(" ll_addr=%02x:%02x:%02x:%02x:%02x:%02x\n", 731335b943fSBjoern A. Zeeb octet[0], octet[1], octet[2], octet[3], octet[4], octet[5]); 7320447c136SAlexander V. Chernikov db_printf(" lle_timer=%p\n", &lle->lle_timer); 733335b943fSBjoern A. Zeeb 734335b943fSBjoern A. Zeeb switch (la->l3_addr.sa_family) { 735335b943fSBjoern A. Zeeb #ifdef INET 736335b943fSBjoern A. Zeeb case AF_INET: 737335b943fSBjoern A. Zeeb { 738335b943fSBjoern A. Zeeb struct sockaddr_in *sin; 739335b943fSBjoern A. Zeeb char l3s[INET_ADDRSTRLEN]; 740335b943fSBjoern A. Zeeb 741335b943fSBjoern A. Zeeb sin = (struct sockaddr_in *)&la->l3_addr; 742335b943fSBjoern A. Zeeb inet_ntoa_r(sin->sin_addr, l3s); 743335b943fSBjoern A. Zeeb db_printf(" l3_addr=%s\n", l3s); 744335b943fSBjoern A. Zeeb break; 745335b943fSBjoern A. Zeeb } 746335b943fSBjoern A. Zeeb #endif 747335b943fSBjoern A. Zeeb #ifdef INET6 748335b943fSBjoern A. Zeeb case AF_INET6: 749335b943fSBjoern A. Zeeb { 750335b943fSBjoern A. Zeeb struct sockaddr_in6 *sin6; 751335b943fSBjoern A. Zeeb char l3s[INET6_ADDRSTRLEN]; 752335b943fSBjoern A. Zeeb 753335b943fSBjoern A. Zeeb sin6 = (struct sockaddr_in6 *)&la->l3_addr; 754335b943fSBjoern A. Zeeb ip6_sprintf(l3s, &sin6->sin6_addr); 755335b943fSBjoern A. Zeeb db_printf(" l3_addr=%s\n", l3s); 756335b943fSBjoern A. Zeeb break; 757335b943fSBjoern A. Zeeb } 758335b943fSBjoern A. Zeeb #endif 759335b943fSBjoern A. Zeeb default: 760335b943fSBjoern A. Zeeb db_printf(" l3_addr=N/A (af=%d)\n", la->l3_addr.sa_family); 761335b943fSBjoern A. Zeeb break; 762335b943fSBjoern A. Zeeb } 763335b943fSBjoern A. Zeeb } 764335b943fSBjoern A. Zeeb 765335b943fSBjoern A. Zeeb DB_SHOW_COMMAND(llentry, db_show_llentry) 766335b943fSBjoern A. Zeeb { 767335b943fSBjoern A. Zeeb 768335b943fSBjoern A. Zeeb if (!have_addr) { 769335b943fSBjoern A. Zeeb db_printf("usage: show llentry <struct llentry *>\n"); 770335b943fSBjoern A. Zeeb return; 771335b943fSBjoern A. Zeeb } 772335b943fSBjoern A. Zeeb 773335b943fSBjoern A. Zeeb llatbl_lle_show((struct llentry_sa *)addr); 774335b943fSBjoern A. Zeeb } 775335b943fSBjoern A. Zeeb 776335b943fSBjoern A. Zeeb static void 777335b943fSBjoern A. Zeeb llatbl_llt_show(struct lltable *llt) 778335b943fSBjoern A. Zeeb { 779335b943fSBjoern A. Zeeb int i; 780335b943fSBjoern A. Zeeb struct llentry *lle; 781335b943fSBjoern A. Zeeb 782335b943fSBjoern A. Zeeb db_printf("llt=%p llt_af=%d llt_ifp=%p\n", 783335b943fSBjoern A. Zeeb llt, llt->llt_af, llt->llt_ifp); 784335b943fSBjoern A. Zeeb 7853a749863SAlexander V. Chernikov for (i = 0; i < llt->llt_hsize; i++) { 786335b943fSBjoern A. Zeeb LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { 787335b943fSBjoern A. Zeeb 788335b943fSBjoern A. Zeeb llatbl_lle_show((struct llentry_sa *)lle); 789335b943fSBjoern A. Zeeb if (db_pager_quit) 790335b943fSBjoern A. Zeeb return; 791335b943fSBjoern A. Zeeb } 792335b943fSBjoern A. Zeeb } 793335b943fSBjoern A. Zeeb } 794335b943fSBjoern A. Zeeb 795335b943fSBjoern A. Zeeb DB_SHOW_COMMAND(lltable, db_show_lltable) 796335b943fSBjoern A. Zeeb { 797335b943fSBjoern A. Zeeb 798335b943fSBjoern A. Zeeb if (!have_addr) { 799335b943fSBjoern A. Zeeb db_printf("usage: show lltable <struct lltable *>\n"); 800335b943fSBjoern A. Zeeb return; 801335b943fSBjoern A. Zeeb } 802335b943fSBjoern A. Zeeb 803335b943fSBjoern A. Zeeb llatbl_llt_show((struct lltable *)addr); 804335b943fSBjoern A. Zeeb } 805335b943fSBjoern A. Zeeb 806335b943fSBjoern A. Zeeb DB_SHOW_ALL_COMMAND(lltables, db_show_all_lltables) 807335b943fSBjoern A. Zeeb { 808335b943fSBjoern A. Zeeb VNET_ITERATOR_DECL(vnet_iter); 809335b943fSBjoern A. Zeeb struct lltable *llt; 810335b943fSBjoern A. Zeeb 811335b943fSBjoern A. Zeeb VNET_FOREACH(vnet_iter) { 812335b943fSBjoern A. Zeeb CURVNET_SET_QUIET(vnet_iter); 813335b943fSBjoern A. Zeeb #ifdef VIMAGE 814335b943fSBjoern A. Zeeb db_printf("vnet=%p\n", curvnet); 815335b943fSBjoern A. Zeeb #endif 816335b943fSBjoern A. Zeeb SLIST_FOREACH(llt, &V_lltables, llt_link) { 817335b943fSBjoern A. Zeeb db_printf("llt=%p llt_af=%d llt_ifp=%p(%s)\n", 818335b943fSBjoern A. Zeeb llt, llt->llt_af, llt->llt_ifp, 819335b943fSBjoern A. Zeeb (llt->llt_ifp != NULL) ? 820335b943fSBjoern A. Zeeb llt->llt_ifp->if_xname : "?"); 821335b943fSBjoern A. Zeeb if (have_addr && addr != 0) /* verbose */ 822335b943fSBjoern A. Zeeb llatbl_llt_show(llt); 823335b943fSBjoern A. Zeeb if (db_pager_quit) { 824335b943fSBjoern A. Zeeb CURVNET_RESTORE(); 825335b943fSBjoern A. Zeeb return; 826335b943fSBjoern A. Zeeb } 827335b943fSBjoern A. Zeeb } 828335b943fSBjoern A. Zeeb CURVNET_RESTORE(); 829335b943fSBjoern A. Zeeb } 830335b943fSBjoern A. Zeeb } 831335b943fSBjoern A. Zeeb #endif 832