1fe267a55SPedro F. Giffuni /*- 2fe267a55SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3fe267a55SPedro F. Giffuni * 482f39c91SKip Macy * Copyright (c) 2004 Luigi Rizzo, Alessandro Cerri. All rights reserved. 582f39c91SKip Macy * Copyright (c) 2004-2008 Qing Li. All rights reserved. 682f39c91SKip Macy * Copyright (c) 2008 Kip Macy. All rights reserved. 782f39c91SKip Macy * 882f39c91SKip Macy * Redistribution and use in source and binary forms, with or without 982f39c91SKip Macy * modification, are permitted provided that the following conditions 1082f39c91SKip Macy * are met: 1182f39c91SKip Macy * 1. Redistributions of source code must retain the above copyright 1282f39c91SKip Macy * notice, this list of conditions and the following disclaimer. 1382f39c91SKip Macy * 2. Redistributions in binary form must reproduce the above copyright 1482f39c91SKip Macy * notice, this list of conditions and the following disclaimer in the 1582f39c91SKip Macy * documentation and/or other materials provided with the distribution. 1682f39c91SKip Macy * 1782f39c91SKip Macy * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1882f39c91SKip Macy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1982f39c91SKip Macy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2082f39c91SKip Macy * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 2182f39c91SKip Macy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2282f39c91SKip Macy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2382f39c91SKip Macy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2482f39c91SKip Macy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2582f39c91SKip Macy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2682f39c91SKip Macy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2782f39c91SKip Macy * SUCH DAMAGE. 2882f39c91SKip Macy */ 2982f39c91SKip Macy #include <sys/cdefs.h> 3082f39c91SKip Macy __FBSDID("$FreeBSD$"); 3182f39c91SKip Macy 32335b943fSBjoern A. Zeeb #include "opt_ddb.h" 3382f39c91SKip Macy #include "opt_inet.h" 3482f39c91SKip Macy #include "opt_inet6.h" 3582f39c91SKip Macy 3682f39c91SKip Macy #include <sys/param.h> 3782f39c91SKip Macy #include <sys/systm.h> 38e2e050c8SConrad Meyer #include <sys/eventhandler.h> 3982f39c91SKip Macy #include <sys/malloc.h> 4082f39c91SKip Macy #include <sys/mbuf.h> 4182f39c91SKip Macy #include <sys/syslog.h> 4282f39c91SKip Macy #include <sys/sysctl.h> 4382f39c91SKip Macy #include <sys/socket.h> 4482f39c91SKip Macy #include <sys/kernel.h> 4582f39c91SKip Macy #include <sys/lock.h> 4682f39c91SKip Macy #include <sys/mutex.h> 4782f39c91SKip Macy #include <sys/rwlock.h> 4882f39c91SKip Macy 49335b943fSBjoern A. Zeeb #ifdef DDB 50335b943fSBjoern A. Zeeb #include <ddb/ddb.h> 51335b943fSBjoern A. Zeeb #endif 52335b943fSBjoern A. Zeeb 5382f39c91SKip Macy #include <vm/uma.h> 5482f39c91SKip Macy 5582f39c91SKip Macy #include <netinet/in.h> 5682f39c91SKip Macy #include <net/if_llatbl.h> 5782f39c91SKip Macy #include <net/if.h> 5882f39c91SKip Macy #include <net/if_dl.h> 5982f39c91SKip Macy #include <net/if_var.h> 6082f39c91SKip Macy #include <net/route.h> 61da187ddbSAlexander V. Chernikov #include <net/route/route_ctl.h> 6263f7f392SAlexander V. Chernikov #include <net/route/route_debug.h> 63530c0060SRobert Watson #include <net/vnet.h> 6482f39c91SKip Macy #include <netinet/if_ether.h> 6582f39c91SKip Macy #include <netinet6/in6_var.h> 6682f39c91SKip Macy #include <netinet6/nd6.h> 6782f39c91SKip Macy 6882f39c91SKip Macy MALLOC_DEFINE(M_LLTABLE, "lltable", "link level address tables"); 6982f39c91SKip Macy 705f901c92SAndrew Turner VNET_DEFINE_STATIC(SLIST_HEAD(, lltable), lltables) = 7176d68eccSBjoern A. Zeeb SLIST_HEAD_INITIALIZER(lltables); 72989e0411SMarko Zec #define V_lltables VNET(lltables) 7382f39c91SKip Macy 74199511bcSAndrey V. Elsukov static struct rwlock lltable_list_lock; 75199511bcSAndrey V. Elsukov RW_SYSINIT(lltable_list_lock, &lltable_list_lock, "lltable_list_lock"); 76199511bcSAndrey V. Elsukov #define LLTABLE_LIST_RLOCK() rw_rlock(&lltable_list_lock) 77199511bcSAndrey V. Elsukov #define LLTABLE_LIST_RUNLOCK() rw_runlock(&lltable_list_lock) 78199511bcSAndrey V. Elsukov #define LLTABLE_LIST_WLOCK() rw_wlock(&lltable_list_lock) 79199511bcSAndrey V. Elsukov #define LLTABLE_LIST_WUNLOCK() rw_wunlock(&lltable_list_lock) 80199511bcSAndrey V. Elsukov #define LLTABLE_LIST_LOCK_ASSERT() rw_assert(&lltable_list_lock, RA_LOCKED) 81dc56e98fSRobert Watson 82721cd2e0SAlexander V. Chernikov static void lltable_unlink(struct lltable *llt); 8311cdad98SAlexander V. Chernikov static void llentries_unlink(struct lltable *llt, struct llentries *head); 8411cdad98SAlexander V. Chernikov 8511cdad98SAlexander V. Chernikov /* 8611cdad98SAlexander V. Chernikov * Dump lle state for a specific address family. 8711cdad98SAlexander V. Chernikov */ 8811cdad98SAlexander V. Chernikov static int 8911cdad98SAlexander V. Chernikov lltable_dump_af(struct lltable *llt, struct sysctl_req *wr) 9011cdad98SAlexander V. Chernikov { 91a68cc388SGleb Smirnoff struct epoch_tracker et; 9211cdad98SAlexander V. Chernikov int error; 9311cdad98SAlexander V. Chernikov 94199511bcSAndrey V. Elsukov LLTABLE_LIST_LOCK_ASSERT(); 9511cdad98SAlexander V. Chernikov 9611cdad98SAlexander V. Chernikov if (llt->llt_ifp->if_flags & IFF_LOOPBACK) 9711cdad98SAlexander V. Chernikov return (0); 9811cdad98SAlexander V. Chernikov error = 0; 9911cdad98SAlexander V. Chernikov 100a68cc388SGleb Smirnoff NET_EPOCH_ENTER(et); 10111cdad98SAlexander V. Chernikov error = lltable_foreach_lle(llt, 10211cdad98SAlexander V. Chernikov (llt_foreach_cb_t *)llt->llt_dump_entry, wr); 103a68cc388SGleb Smirnoff NET_EPOCH_EXIT(et); 10411cdad98SAlexander V. Chernikov 10511cdad98SAlexander V. Chernikov return (error); 10611cdad98SAlexander V. Chernikov } 10711cdad98SAlexander V. Chernikov 10882f39c91SKip Macy /* 10982f39c91SKip Macy * Dump arp state for a specific address family. 11082f39c91SKip Macy */ 11182f39c91SKip Macy int 11282f39c91SKip Macy lltable_sysctl_dumparp(int af, struct sysctl_req *wr) 11382f39c91SKip Macy { 11482f39c91SKip Macy struct lltable *llt; 11582f39c91SKip Macy int error = 0; 11682f39c91SKip Macy 117199511bcSAndrey V. Elsukov LLTABLE_LIST_RLOCK(); 118989e0411SMarko Zec SLIST_FOREACH(llt, &V_lltables, llt_link) { 11982f39c91SKip Macy if (llt->llt_af == af) { 12011cdad98SAlexander V. Chernikov error = lltable_dump_af(llt, wr); 12182f39c91SKip Macy if (error != 0) 12282f39c91SKip Macy goto done; 12382f39c91SKip Macy } 12482f39c91SKip Macy } 12582f39c91SKip Macy done: 126199511bcSAndrey V. Elsukov LLTABLE_LIST_RUNLOCK(); 12782f39c91SKip Macy return (error); 12882f39c91SKip Macy } 12982f39c91SKip Macy 13082f39c91SKip Macy /* 13111cdad98SAlexander V. Chernikov * Common function helpers for chained hash table. 13211cdad98SAlexander V. Chernikov */ 13311cdad98SAlexander V. Chernikov 13411cdad98SAlexander V. Chernikov /* 13511cdad98SAlexander V. Chernikov * Runs specified callback for each entry in @llt. 13611cdad98SAlexander V. Chernikov * Caller does the locking. 13711cdad98SAlexander V. Chernikov * 13811cdad98SAlexander V. Chernikov */ 13911cdad98SAlexander V. Chernikov static int 14011cdad98SAlexander V. Chernikov htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg) 14111cdad98SAlexander V. Chernikov { 14211cdad98SAlexander V. Chernikov struct llentry *lle, *next; 14311cdad98SAlexander V. Chernikov int i, error; 14411cdad98SAlexander V. Chernikov 14511cdad98SAlexander V. Chernikov error = 0; 14611cdad98SAlexander V. Chernikov 14741cb42a6SAlexander V. Chernikov for (i = 0; i < llt->llt_hsize; i++) { 1484f6c66ccSMatt Macy CK_LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) { 14911cdad98SAlexander V. Chernikov error = f(llt, lle, farg); 15011cdad98SAlexander V. Chernikov if (error != 0) 15111cdad98SAlexander V. Chernikov break; 15211cdad98SAlexander V. Chernikov } 15311cdad98SAlexander V. Chernikov } 15411cdad98SAlexander V. Chernikov 15511cdad98SAlexander V. Chernikov return (error); 15611cdad98SAlexander V. Chernikov } 15711cdad98SAlexander V. Chernikov 1583818c25aSBjoern A. Zeeb /* 1593818c25aSBjoern A. Zeeb * The htable_[un]link_entry() functions return: 1603818c25aSBjoern A. Zeeb * 0 if the entry was (un)linked already and nothing changed, 1613818c25aSBjoern A. Zeeb * 1 if the entry was added/removed to/from the table, and 1623818c25aSBjoern A. Zeeb * -1 on error (e.g., not being able to add the entry due to limits reached). 1633818c25aSBjoern A. Zeeb * While the "unlink" operation should never error, callers of 1643818c25aSBjoern A. Zeeb * lltable_link_entry() need to check for errors and handle them. 1653818c25aSBjoern A. Zeeb */ 1663818c25aSBjoern A. Zeeb static int 16711cdad98SAlexander V. Chernikov htable_link_entry(struct lltable *llt, struct llentry *lle) 16811cdad98SAlexander V. Chernikov { 16911cdad98SAlexander V. Chernikov struct llentries *lleh; 17011cdad98SAlexander V. Chernikov uint32_t hashidx; 17111cdad98SAlexander V. Chernikov 17211cdad98SAlexander V. Chernikov if ((lle->la_flags & LLE_LINKED) != 0) 1733818c25aSBjoern A. Zeeb return (0); 17411cdad98SAlexander V. Chernikov 17511cdad98SAlexander V. Chernikov IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp); 17611cdad98SAlexander V. Chernikov 1773818c25aSBjoern A. Zeeb if (llt->llt_maxentries > 0 && 1783818c25aSBjoern A. Zeeb llt->llt_entries >= llt->llt_maxentries) 1793818c25aSBjoern A. Zeeb return (-1); 1803818c25aSBjoern A. Zeeb 1813a749863SAlexander V. Chernikov hashidx = llt->llt_hash(lle, llt->llt_hsize); 18211cdad98SAlexander V. Chernikov lleh = &llt->lle_head[hashidx]; 18311cdad98SAlexander V. Chernikov 18411cdad98SAlexander V. Chernikov lle->lle_tbl = llt; 18511cdad98SAlexander V. Chernikov lle->lle_head = lleh; 18611cdad98SAlexander V. Chernikov lle->la_flags |= LLE_LINKED; 1874f6c66ccSMatt Macy CK_LIST_INSERT_HEAD(lleh, lle, lle_next); 1883818c25aSBjoern A. Zeeb llt->llt_entries++; 1893818c25aSBjoern A. Zeeb 1903818c25aSBjoern A. Zeeb return (1); 19111cdad98SAlexander V. Chernikov } 19211cdad98SAlexander V. Chernikov 1933818c25aSBjoern A. Zeeb static int 19411cdad98SAlexander V. Chernikov htable_unlink_entry(struct llentry *lle) 19511cdad98SAlexander V. Chernikov { 1963818c25aSBjoern A. Zeeb struct lltable *llt; 19711cdad98SAlexander V. Chernikov 198d9a61c96SBjoern A. Zeeb if ((lle->la_flags & LLE_LINKED) == 0) 1993818c25aSBjoern A. Zeeb return (0); 200d9a61c96SBjoern A. Zeeb 2013818c25aSBjoern A. Zeeb llt = lle->lle_tbl; 2023818c25aSBjoern A. Zeeb IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp); 2033818c25aSBjoern A. Zeeb KASSERT(llt->llt_entries > 0, ("%s: lltable %p (%s) entries %d <= 0", 2043818c25aSBjoern A. Zeeb __func__, llt, if_name(llt->llt_ifp), llt->llt_entries)); 2053818c25aSBjoern A. Zeeb 2064f6c66ccSMatt Macy CK_LIST_REMOVE(lle, lle_next); 20711cdad98SAlexander V. Chernikov lle->la_flags &= ~(LLE_VALID | LLE_LINKED); 20811cdad98SAlexander V. Chernikov #if 0 20911cdad98SAlexander V. Chernikov lle->lle_tbl = NULL; 21011cdad98SAlexander V. Chernikov lle->lle_head = NULL; 21111cdad98SAlexander V. Chernikov #endif 2123818c25aSBjoern A. Zeeb llt->llt_entries--; 2133818c25aSBjoern A. Zeeb 2143818c25aSBjoern A. Zeeb return (1); 21511cdad98SAlexander V. Chernikov } 21611cdad98SAlexander V. Chernikov 21711cdad98SAlexander V. Chernikov struct prefix_match_data { 2183e7a2321SAlexander V. Chernikov const struct sockaddr *addr; 21911cdad98SAlexander V. Chernikov const struct sockaddr *mask; 22011cdad98SAlexander V. Chernikov struct llentries dchain; 22111cdad98SAlexander V. Chernikov u_int flags; 22211cdad98SAlexander V. Chernikov }; 22311cdad98SAlexander V. Chernikov 22411cdad98SAlexander V. Chernikov static int 22511cdad98SAlexander V. Chernikov htable_prefix_free_cb(struct lltable *llt, struct llentry *lle, void *farg) 22611cdad98SAlexander V. Chernikov { 22711cdad98SAlexander V. Chernikov struct prefix_match_data *pmd; 22811cdad98SAlexander V. Chernikov 22911cdad98SAlexander V. Chernikov pmd = (struct prefix_match_data *)farg; 23011cdad98SAlexander V. Chernikov 2313e7a2321SAlexander V. Chernikov if (llt->llt_match_prefix(pmd->addr, pmd->mask, pmd->flags, lle)) { 23211cdad98SAlexander V. Chernikov LLE_WLOCK(lle); 2330f8d79d9SMatt Macy CK_LIST_INSERT_HEAD(&pmd->dchain, lle, lle_chain); 23411cdad98SAlexander V. Chernikov } 23511cdad98SAlexander V. Chernikov 23611cdad98SAlexander V. Chernikov return (0); 23711cdad98SAlexander V. Chernikov } 23811cdad98SAlexander V. Chernikov 23911cdad98SAlexander V. Chernikov static void 2403e7a2321SAlexander V. Chernikov htable_prefix_free(struct lltable *llt, const struct sockaddr *addr, 24111cdad98SAlexander V. Chernikov const struct sockaddr *mask, u_int flags) 24211cdad98SAlexander V. Chernikov { 24311cdad98SAlexander V. Chernikov struct llentry *lle, *next; 24411cdad98SAlexander V. Chernikov struct prefix_match_data pmd; 24511cdad98SAlexander V. Chernikov 24611cdad98SAlexander V. Chernikov bzero(&pmd, sizeof(pmd)); 2473e7a2321SAlexander V. Chernikov pmd.addr = addr; 24811cdad98SAlexander V. Chernikov pmd.mask = mask; 24911cdad98SAlexander V. Chernikov pmd.flags = flags; 2504f6c66ccSMatt Macy CK_LIST_INIT(&pmd.dchain); 25111cdad98SAlexander V. Chernikov 25211cdad98SAlexander V. Chernikov IF_AFDATA_WLOCK(llt->llt_ifp); 25311cdad98SAlexander V. Chernikov /* Push matching lles to chain */ 25411cdad98SAlexander V. Chernikov lltable_foreach_lle(llt, htable_prefix_free_cb, &pmd); 25511cdad98SAlexander V. Chernikov 25611cdad98SAlexander V. Chernikov llentries_unlink(llt, &pmd.dchain); 25711cdad98SAlexander V. Chernikov IF_AFDATA_WUNLOCK(llt->llt_ifp); 25811cdad98SAlexander V. Chernikov 2590f8d79d9SMatt Macy CK_LIST_FOREACH_SAFE(lle, &pmd.dchain, lle_chain, next) 2605a255516SAlexander V. Chernikov lltable_free_entry(llt, lle); 26111cdad98SAlexander V. Chernikov } 26211cdad98SAlexander V. Chernikov 26311cdad98SAlexander V. Chernikov static void 26441cb42a6SAlexander V. Chernikov htable_free_tbl(struct lltable *llt) 26541cb42a6SAlexander V. Chernikov { 26641cb42a6SAlexander V. Chernikov 26741cb42a6SAlexander V. Chernikov free(llt->lle_head, M_LLTABLE); 26841cb42a6SAlexander V. Chernikov free(llt, M_LLTABLE); 26941cb42a6SAlexander V. Chernikov } 27041cb42a6SAlexander V. Chernikov 271721cd2e0SAlexander V. Chernikov static void 27211cdad98SAlexander V. Chernikov llentries_unlink(struct lltable *llt, struct llentries *head) 27311cdad98SAlexander V. Chernikov { 27411cdad98SAlexander V. Chernikov struct llentry *lle, *next; 27511cdad98SAlexander V. Chernikov 2760f8d79d9SMatt Macy CK_LIST_FOREACH_SAFE(lle, head, lle_chain, next) 27711cdad98SAlexander V. Chernikov llt->llt_unlink_entry(lle); 27811cdad98SAlexander V. Chernikov } 27911cdad98SAlexander V. Chernikov 28011cdad98SAlexander V. Chernikov /* 28111cdad98SAlexander V. Chernikov * Helper function used to drop all mbufs in hold queue. 282e162ea60SGeorge V. Neville-Neil * 283e162ea60SGeorge V. Neville-Neil * Returns the number of held packets, if any, that were dropped. 28482f39c91SKip Macy */ 285e162ea60SGeorge V. Neville-Neil size_t 28611cdad98SAlexander V. Chernikov lltable_drop_entry_queue(struct llentry *lle) 28782f39c91SKip Macy { 288e162ea60SGeorge V. Neville-Neil size_t pkts_dropped; 289e162ea60SGeorge V. Neville-Neil struct mbuf *next; 29082f39c91SKip Macy 29182f39c91SKip Macy LLE_WLOCK_ASSERT(lle); 29282f39c91SKip Macy 293ea537929SGleb Smirnoff pkts_dropped = 0; 294e162ea60SGeorge V. Neville-Neil while ((lle->la_numheld > 0) && (lle->la_hold != NULL)) { 295e162ea60SGeorge V. Neville-Neil next = lle->la_hold->m_nextpkt; 29682f39c91SKip Macy m_freem(lle->la_hold); 297e162ea60SGeorge V. Neville-Neil lle->la_hold = next; 298e162ea60SGeorge V. Neville-Neil lle->la_numheld--; 299e162ea60SGeorge V. Neville-Neil pkts_dropped++; 300e162ea60SGeorge V. Neville-Neil } 301e162ea60SGeorge V. Neville-Neil 302e162ea60SGeorge V. Neville-Neil KASSERT(lle->la_numheld == 0, 3037b3b099eSKonstantin Belousov ("%s: la_numheld %d > 0, pkts_droped %zd", __func__, 304e162ea60SGeorge V. Neville-Neil lle->la_numheld, pkts_dropped)); 30582f39c91SKip Macy 30611cdad98SAlexander V. Chernikov return (pkts_dropped); 30711cdad98SAlexander V. Chernikov } 30811cdad98SAlexander V. Chernikov 309ddd208f7SAlexander V. Chernikov void 310ddd208f7SAlexander V. Chernikov lltable_set_entry_addr(struct ifnet *ifp, struct llentry *lle, 3114fb3a820SAlexander V. Chernikov const char *linkhdr, size_t linkhdrsize, int lladdr_off) 312ddd208f7SAlexander V. Chernikov { 313ddd208f7SAlexander V. Chernikov 3144fb3a820SAlexander V. Chernikov memcpy(lle->r_linkdata, linkhdr, linkhdrsize); 3154fb3a820SAlexander V. Chernikov lle->r_hdrlen = linkhdrsize; 3164fb3a820SAlexander V. Chernikov lle->ll_addr = &lle->r_linkdata[lladdr_off]; 317ddd208f7SAlexander V. Chernikov lle->la_flags |= LLE_VALID; 318f8aee88fSAlexander V. Chernikov lle->r_flags |= RLLE_VALID; 319ddd208f7SAlexander V. Chernikov } 320ddd208f7SAlexander V. Chernikov 32111cdad98SAlexander V. Chernikov /* 3220b79b007SAlexander V. Chernikov * Acquires lltable write lock. 3230b79b007SAlexander V. Chernikov * 3240b79b007SAlexander V. Chernikov * Returns true on success, with both lltable and lle lock held. 3250b79b007SAlexander V. Chernikov * On failure, false is returned and lle wlock is still held. 3260b79b007SAlexander V. Chernikov */ 3270b79b007SAlexander V. Chernikov bool 3280b79b007SAlexander V. Chernikov lltable_acquire_wlock(struct ifnet *ifp, struct llentry *lle) 3290b79b007SAlexander V. Chernikov { 3300b79b007SAlexander V. Chernikov NET_EPOCH_ASSERT(); 3310b79b007SAlexander V. Chernikov 3320b79b007SAlexander V. Chernikov /* Perform real LLE update */ 3330b79b007SAlexander V. Chernikov /* use afdata WLOCK to update fields */ 3340b79b007SAlexander V. Chernikov LLE_WUNLOCK(lle); 3350b79b007SAlexander V. Chernikov IF_AFDATA_WLOCK(ifp); 3360b79b007SAlexander V. Chernikov LLE_WLOCK(lle); 3370b79b007SAlexander V. Chernikov 3380b79b007SAlexander V. Chernikov /* 3390b79b007SAlexander V. Chernikov * Since we droppped LLE lock, other thread might have deleted 3400b79b007SAlexander V. Chernikov * this lle. Check and return 3410b79b007SAlexander V. Chernikov */ 3420b79b007SAlexander V. Chernikov if ((lle->la_flags & LLE_DELETED) != 0) { 3430b79b007SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 3440b79b007SAlexander V. Chernikov return (false); 3450b79b007SAlexander V. Chernikov } 3460b79b007SAlexander V. Chernikov 3470b79b007SAlexander V. Chernikov return (true); 3480b79b007SAlexander V. Chernikov } 3490b79b007SAlexander V. Chernikov 3500b79b007SAlexander V. Chernikov /* 35112cb7521SAlexander V. Chernikov * Tries to update @lle link-level address. 35212cb7521SAlexander V. Chernikov * Since update requires AFDATA WLOCK, function 35312cb7521SAlexander V. Chernikov * drops @lle lock, acquires AFDATA lock and then acquires 35412cb7521SAlexander V. Chernikov * @lle lock to maintain lock order. 35512cb7521SAlexander V. Chernikov * 35612cb7521SAlexander V. Chernikov * Returns 1 on success. 35712cb7521SAlexander V. Chernikov */ 35812cb7521SAlexander V. Chernikov int 35912cb7521SAlexander V. Chernikov lltable_try_set_entry_addr(struct ifnet *ifp, struct llentry *lle, 3604fb3a820SAlexander V. Chernikov const char *linkhdr, size_t linkhdrsize, int lladdr_off) 36112cb7521SAlexander V. Chernikov { 36212cb7521SAlexander V. Chernikov 3630b79b007SAlexander V. Chernikov if (!lltable_acquire_wlock(ifp, lle)) 36412cb7521SAlexander V. Chernikov return (0); 36512cb7521SAlexander V. Chernikov 36612cb7521SAlexander V. Chernikov /* Update data */ 3674fb3a820SAlexander V. Chernikov lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize, lladdr_off); 36812cb7521SAlexander V. Chernikov 36912cb7521SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 37012cb7521SAlexander V. Chernikov 37112cb7521SAlexander V. Chernikov return (1); 37212cb7521SAlexander V. Chernikov } 37312cb7521SAlexander V. Chernikov 37412cb7521SAlexander V. Chernikov /* 3754fb3a820SAlexander V. Chernikov * Helper function used to pre-compute full/partial link-layer 3764fb3a820SAlexander V. Chernikov * header data suitable for feeding into if_output(). 3774fb3a820SAlexander V. Chernikov */ 3784fb3a820SAlexander V. Chernikov int 3794fb3a820SAlexander V. Chernikov lltable_calc_llheader(struct ifnet *ifp, int family, char *lladdr, 3804fb3a820SAlexander V. Chernikov char *buf, size_t *bufsize, int *lladdr_off) 3814fb3a820SAlexander V. Chernikov { 3824fb3a820SAlexander V. Chernikov struct if_encap_req ereq; 3834fb3a820SAlexander V. Chernikov int error; 3844fb3a820SAlexander V. Chernikov 3854fb3a820SAlexander V. Chernikov bzero(buf, *bufsize); 3864fb3a820SAlexander V. Chernikov bzero(&ereq, sizeof(ereq)); 3874fb3a820SAlexander V. Chernikov ereq.buf = buf; 3884fb3a820SAlexander V. Chernikov ereq.bufsize = *bufsize; 3894fb3a820SAlexander V. Chernikov ereq.rtype = IFENCAP_LL; 3904fb3a820SAlexander V. Chernikov ereq.family = family; 3914fb3a820SAlexander V. Chernikov ereq.lladdr = lladdr; 3924fb3a820SAlexander V. Chernikov ereq.lladdr_len = ifp->if_addrlen; 3934fb3a820SAlexander V. Chernikov error = ifp->if_requestencap(ifp, &ereq); 3944fb3a820SAlexander V. Chernikov if (error == 0) { 3954fb3a820SAlexander V. Chernikov *bufsize = ereq.bufsize; 3964fb3a820SAlexander V. Chernikov *lladdr_off = ereq.lladdr_off; 3974fb3a820SAlexander V. Chernikov } 3984fb3a820SAlexander V. Chernikov 3994fb3a820SAlexander V. Chernikov return (error); 4004fb3a820SAlexander V. Chernikov } 4014fb3a820SAlexander V. Chernikov 4024fb3a820SAlexander V. Chernikov /* 403c541bd36SAlexander V. Chernikov * Searches for the child entry matching @family inside @lle. 404c541bd36SAlexander V. Chernikov * Returns the entry or NULL. 405c541bd36SAlexander V. Chernikov */ 406c541bd36SAlexander V. Chernikov struct llentry * 407c541bd36SAlexander V. Chernikov llentry_lookup_family(struct llentry *lle, int family) 408c541bd36SAlexander V. Chernikov { 409c541bd36SAlexander V. Chernikov struct llentry *child_lle; 410c541bd36SAlexander V. Chernikov 411c541bd36SAlexander V. Chernikov if (lle == NULL) 412c541bd36SAlexander V. Chernikov return (NULL); 413c541bd36SAlexander V. Chernikov 414c541bd36SAlexander V. Chernikov CK_SLIST_FOREACH(child_lle, &lle->lle_children, lle_child_next) { 415c541bd36SAlexander V. Chernikov if (child_lle->r_family == family) 416c541bd36SAlexander V. Chernikov return (child_lle); 417c541bd36SAlexander V. Chernikov } 418c541bd36SAlexander V. Chernikov 419c541bd36SAlexander V. Chernikov return (NULL); 420c541bd36SAlexander V. Chernikov } 421c541bd36SAlexander V. Chernikov 422c541bd36SAlexander V. Chernikov /* 42363f7f392SAlexander V. Chernikov * Retrieves upper protocol family for the llentry. 42463f7f392SAlexander V. Chernikov * By default, all "normal" (e.g. upper_family == transport_family) 42563f7f392SAlexander V. Chernikov * llentries have r_family set to 0. 42663f7f392SAlexander V. Chernikov * Thus, use @default_family in that regard, otherwise use r_family. 42763f7f392SAlexander V. Chernikov * 42863f7f392SAlexander V. Chernikov * Returns upper protocol family 42963f7f392SAlexander V. Chernikov */ 43063f7f392SAlexander V. Chernikov int 43163f7f392SAlexander V. Chernikov llentry_get_upper_family(const struct llentry *lle, int default_family) 43263f7f392SAlexander V. Chernikov { 43363f7f392SAlexander V. Chernikov return (lle->r_family == 0 ? default_family : lle->r_family); 43463f7f392SAlexander V. Chernikov } 43563f7f392SAlexander V. Chernikov 43663f7f392SAlexander V. Chernikov /* 43763f7f392SAlexander V. Chernikov * Prints llentry @lle data into provided buffer. 43863f7f392SAlexander V. Chernikov * Example: lle/inet/valid/em0/1.2.3.4 43963f7f392SAlexander V. Chernikov * 44063f7f392SAlexander V. Chernikov * Returns @buf. 44163f7f392SAlexander V. Chernikov */ 44263f7f392SAlexander V. Chernikov char * 44363f7f392SAlexander V. Chernikov llentry_print_buf(const struct llentry *lle, struct ifnet *ifp, int family, 44463f7f392SAlexander V. Chernikov char *buf, size_t bufsize) 44563f7f392SAlexander V. Chernikov { 446a6668e31SEd Maste #if defined(INET) || defined(INET6) 44763f7f392SAlexander V. Chernikov char abuf[INET6_ADDRSTRLEN]; 448a6668e31SEd Maste #endif 44963f7f392SAlexander V. Chernikov 45063f7f392SAlexander V. Chernikov const char *valid = (lle->r_flags & RLLE_VALID) ? "valid" : "no_l2"; 45163f7f392SAlexander V. Chernikov const char *upper_str = rib_print_family(llentry_get_upper_family(lle, family)); 45263f7f392SAlexander V. Chernikov 45363f7f392SAlexander V. Chernikov switch (family) { 45463f7f392SAlexander V. Chernikov #ifdef INET 45563f7f392SAlexander V. Chernikov case AF_INET: 45663f7f392SAlexander V. Chernikov inet_ntop(AF_INET, &lle->r_l3addr.addr4, abuf, sizeof(abuf)); 45763f7f392SAlexander V. Chernikov snprintf(buf, bufsize, "lle/%s/%s/%s/%s", upper_str, 45863f7f392SAlexander V. Chernikov valid, if_name(ifp), abuf); 45963f7f392SAlexander V. Chernikov break; 46063f7f392SAlexander V. Chernikov #endif 46163f7f392SAlexander V. Chernikov #ifdef INET6 46263f7f392SAlexander V. Chernikov case AF_INET6: 46363f7f392SAlexander V. Chernikov inet_ntop(AF_INET6, &lle->r_l3addr.addr6, abuf, sizeof(abuf)); 46463f7f392SAlexander V. Chernikov snprintf(buf, bufsize, "lle/%s/%s/%s/%s", upper_str, 46563f7f392SAlexander V. Chernikov valid, if_name(ifp), abuf); 46663f7f392SAlexander V. Chernikov break; 46763f7f392SAlexander V. Chernikov #endif 46863f7f392SAlexander V. Chernikov default: 46963f7f392SAlexander V. Chernikov snprintf(buf, bufsize, "lle/%s/%s/%s/????", upper_str, 47063f7f392SAlexander V. Chernikov valid, if_name(ifp)); 47163f7f392SAlexander V. Chernikov break; 47263f7f392SAlexander V. Chernikov } 47363f7f392SAlexander V. Chernikov 47463f7f392SAlexander V. Chernikov return (buf); 47563f7f392SAlexander V. Chernikov } 47663f7f392SAlexander V. Chernikov 47763f7f392SAlexander V. Chernikov char * 47863f7f392SAlexander V. Chernikov llentry_print_buf_lltable(const struct llentry *lle, char *buf, size_t bufsize) 47963f7f392SAlexander V. Chernikov { 48063f7f392SAlexander V. Chernikov struct lltable *tbl = lle->lle_tbl; 48163f7f392SAlexander V. Chernikov 48263f7f392SAlexander V. Chernikov return (llentry_print_buf(lle, lltable_get_ifp(tbl), lltable_get_af(tbl), buf, bufsize)); 48363f7f392SAlexander V. Chernikov } 48463f7f392SAlexander V. Chernikov 48563f7f392SAlexander V. Chernikov /* 486f3a3b061SAlexander V. Chernikov * Requests feedback from the datapath. 487f3a3b061SAlexander V. Chernikov * First packet using @lle should result in 488f3a3b061SAlexander V. Chernikov * setting r_skip_req back to 0 and updating 489f3a3b061SAlexander V. Chernikov * lle_hittime to the current time_uptime. 490f3a3b061SAlexander V. Chernikov */ 491f3a3b061SAlexander V. Chernikov void 492f3a3b061SAlexander V. Chernikov llentry_request_feedback(struct llentry *lle) 493f3a3b061SAlexander V. Chernikov { 494c541bd36SAlexander V. Chernikov struct llentry *child_lle; 495c541bd36SAlexander V. Chernikov 496f3a3b061SAlexander V. Chernikov LLE_REQ_LOCK(lle); 497f3a3b061SAlexander V. Chernikov lle->r_skip_req = 1; 498f3a3b061SAlexander V. Chernikov LLE_REQ_UNLOCK(lle); 499c541bd36SAlexander V. Chernikov 500c541bd36SAlexander V. Chernikov CK_SLIST_FOREACH(child_lle, &lle->lle_children, lle_child_next) { 501c541bd36SAlexander V. Chernikov LLE_REQ_LOCK(child_lle); 502c541bd36SAlexander V. Chernikov child_lle->r_skip_req = 1; 503c541bd36SAlexander V. Chernikov LLE_REQ_UNLOCK(child_lle); 504c541bd36SAlexander V. Chernikov } 505f3a3b061SAlexander V. Chernikov } 506f3a3b061SAlexander V. Chernikov 507f3a3b061SAlexander V. Chernikov /* 508f3a3b061SAlexander V. Chernikov * Updates the lle state to mark it has been used 509f3a3b061SAlexander V. Chernikov * and record the time. 510f3a3b061SAlexander V. Chernikov * Used by the llentry_provide_feedback() wrapper. 511f3a3b061SAlexander V. Chernikov */ 512f3a3b061SAlexander V. Chernikov void 513f3a3b061SAlexander V. Chernikov llentry_mark_used(struct llentry *lle) 514f3a3b061SAlexander V. Chernikov { 515f3a3b061SAlexander V. Chernikov LLE_REQ_LOCK(lle); 516f3a3b061SAlexander V. Chernikov lle->r_skip_req = 0; 517f3a3b061SAlexander V. Chernikov lle->lle_hittime = time_uptime; 518f3a3b061SAlexander V. Chernikov LLE_REQ_UNLOCK(lle); 519f3a3b061SAlexander V. Chernikov } 520f3a3b061SAlexander V. Chernikov 521f3a3b061SAlexander V. Chernikov /* 522f3a3b061SAlexander V. Chernikov * Fetches the time when lle was used. 523f3a3b061SAlexander V. Chernikov * Return 0 if the entry was not used, relevant time_uptime 524f3a3b061SAlexander V. Chernikov * otherwise. 525f3a3b061SAlexander V. Chernikov */ 526c541bd36SAlexander V. Chernikov static time_t 527c541bd36SAlexander V. Chernikov llentry_get_hittime_raw(struct llentry *lle) 528f3a3b061SAlexander V. Chernikov { 529f3a3b061SAlexander V. Chernikov time_t lle_hittime = 0; 530f3a3b061SAlexander V. Chernikov 531f3a3b061SAlexander V. Chernikov LLE_REQ_LOCK(lle); 532f3a3b061SAlexander V. Chernikov if ((lle->r_skip_req == 0) && (lle_hittime < lle->lle_hittime)) 533f3a3b061SAlexander V. Chernikov lle_hittime = lle->lle_hittime; 534f3a3b061SAlexander V. Chernikov LLE_REQ_UNLOCK(lle); 535f3a3b061SAlexander V. Chernikov 536f3a3b061SAlexander V. Chernikov return (lle_hittime); 537f3a3b061SAlexander V. Chernikov } 538f3a3b061SAlexander V. Chernikov 539c541bd36SAlexander V. Chernikov time_t 540c541bd36SAlexander V. Chernikov llentry_get_hittime(struct llentry *lle) 541c541bd36SAlexander V. Chernikov { 542c541bd36SAlexander V. Chernikov time_t lle_hittime = 0; 543c541bd36SAlexander V. Chernikov struct llentry *child_lle; 544c541bd36SAlexander V. Chernikov 545c541bd36SAlexander V. Chernikov lle_hittime = llentry_get_hittime_raw(lle); 546c541bd36SAlexander V. Chernikov 547c541bd36SAlexander V. Chernikov CK_SLIST_FOREACH(child_lle, &lle->lle_children, lle_child_next) { 548c541bd36SAlexander V. Chernikov time_t hittime = llentry_get_hittime_raw(child_lle); 549c541bd36SAlexander V. Chernikov if (hittime > lle_hittime) 550c541bd36SAlexander V. Chernikov lle_hittime = hittime; 551c541bd36SAlexander V. Chernikov } 552c541bd36SAlexander V. Chernikov 553c541bd36SAlexander V. Chernikov return (lle_hittime); 554c541bd36SAlexander V. Chernikov } 555c541bd36SAlexander V. Chernikov 556f3a3b061SAlexander V. Chernikov /* 5574fb3a820SAlexander V. Chernikov * Update link-layer header for given @lle after 5584fb3a820SAlexander V. Chernikov * interface lladdr was changed. 5594fb3a820SAlexander V. Chernikov */ 5604fb3a820SAlexander V. Chernikov static int 5614fb3a820SAlexander V. Chernikov llentry_update_ifaddr(struct lltable *llt, struct llentry *lle, void *farg) 5624fb3a820SAlexander V. Chernikov { 5634fb3a820SAlexander V. Chernikov struct ifnet *ifp; 5644fb3a820SAlexander V. Chernikov u_char linkhdr[LLE_MAX_LINKHDR]; 5654fb3a820SAlexander V. Chernikov size_t linkhdrsize; 5664fb3a820SAlexander V. Chernikov u_char *lladdr; 5674fb3a820SAlexander V. Chernikov int lladdr_off; 5684fb3a820SAlexander V. Chernikov 5694fb3a820SAlexander V. Chernikov ifp = (struct ifnet *)farg; 5704fb3a820SAlexander V. Chernikov 5714fb3a820SAlexander V. Chernikov lladdr = lle->ll_addr; 5724fb3a820SAlexander V. Chernikov 5734fb3a820SAlexander V. Chernikov LLE_WLOCK(lle); 5744fb3a820SAlexander V. Chernikov if ((lle->la_flags & LLE_VALID) == 0) { 5754fb3a820SAlexander V. Chernikov LLE_WUNLOCK(lle); 5764fb3a820SAlexander V. Chernikov return (0); 5774fb3a820SAlexander V. Chernikov } 5784fb3a820SAlexander V. Chernikov 5794fb3a820SAlexander V. Chernikov if ((lle->la_flags & LLE_IFADDR) != 0) 5804fb3a820SAlexander V. Chernikov lladdr = IF_LLADDR(ifp); 5814fb3a820SAlexander V. Chernikov 5824fb3a820SAlexander V. Chernikov linkhdrsize = sizeof(linkhdr); 5834fb3a820SAlexander V. Chernikov lltable_calc_llheader(ifp, llt->llt_af, lladdr, linkhdr, &linkhdrsize, 5844fb3a820SAlexander V. Chernikov &lladdr_off); 5854fb3a820SAlexander V. Chernikov memcpy(lle->r_linkdata, linkhdr, linkhdrsize); 5864fb3a820SAlexander V. Chernikov LLE_WUNLOCK(lle); 5874fb3a820SAlexander V. Chernikov 5884fb3a820SAlexander V. Chernikov return (0); 5894fb3a820SAlexander V. Chernikov } 5904fb3a820SAlexander V. Chernikov 5914fb3a820SAlexander V. Chernikov /* 5924fb3a820SAlexander V. Chernikov * Update all calculated headers for given @llt 5934fb3a820SAlexander V. Chernikov */ 5944fb3a820SAlexander V. Chernikov void 5954fb3a820SAlexander V. Chernikov lltable_update_ifaddr(struct lltable *llt) 5964fb3a820SAlexander V. Chernikov { 5974fb3a820SAlexander V. Chernikov 5984fb3a820SAlexander V. Chernikov if (llt->llt_ifp->if_flags & IFF_LOOPBACK) 5994fb3a820SAlexander V. Chernikov return; 6004fb3a820SAlexander V. Chernikov 6014fb3a820SAlexander V. Chernikov IF_AFDATA_WLOCK(llt->llt_ifp); 6024fb3a820SAlexander V. Chernikov lltable_foreach_lle(llt, llentry_update_ifaddr, llt->llt_ifp); 6034fb3a820SAlexander V. Chernikov IF_AFDATA_WUNLOCK(llt->llt_ifp); 6044fb3a820SAlexander V. Chernikov } 6054fb3a820SAlexander V. Chernikov 6064fb3a820SAlexander V. Chernikov /* 6075a255516SAlexander V. Chernikov * 608a4641f4eSPedro F. Giffuni * Performs generic cleanup routines and frees lle. 6095a255516SAlexander V. Chernikov * 6105a255516SAlexander V. Chernikov * Called for non-linked entries, with callouts and 6115a255516SAlexander V. Chernikov * other AF-specific cleanups performed. 6125a255516SAlexander V. Chernikov * 6135a255516SAlexander V. Chernikov * @lle must be passed WLOCK'ed 61411cdad98SAlexander V. Chernikov * 61511cdad98SAlexander V. Chernikov * Returns the number of held packets, if any, that were dropped. 61611cdad98SAlexander V. Chernikov */ 61711cdad98SAlexander V. Chernikov size_t 61811cdad98SAlexander V. Chernikov llentry_free(struct llentry *lle) 61911cdad98SAlexander V. Chernikov { 62011cdad98SAlexander V. Chernikov size_t pkts_dropped; 62111cdad98SAlexander V. Chernikov 62211cdad98SAlexander V. Chernikov LLE_WLOCK_ASSERT(lle); 62311cdad98SAlexander V. Chernikov 624d3cdb716SAlexander V. Chernikov KASSERT((lle->la_flags & LLE_LINKED) == 0, ("freeing linked lle")); 62511cdad98SAlexander V. Chernikov 62611cdad98SAlexander V. Chernikov pkts_dropped = lltable_drop_entry_queue(lle); 62711cdad98SAlexander V. Chernikov 628acf673edSAndrey V. Elsukov /* cancel timer */ 629acf673edSAndrey V. Elsukov if (callout_stop(&lle->lle_timer) > 0) 630acf673edSAndrey V. Elsukov LLE_REMREF(lle); 63182f39c91SKip Macy LLE_FREE_LOCKED(lle); 632e162ea60SGeorge V. Neville-Neil 633e162ea60SGeorge V. Neville-Neil return (pkts_dropped); 63482f39c91SKip Macy } 63582f39c91SKip Macy 636adfc35ffSKip Macy /* 63782f39c91SKip Macy * Free all entries from given table and free itself. 63882f39c91SKip Macy */ 63911cdad98SAlexander V. Chernikov 64011cdad98SAlexander V. Chernikov static int 64111cdad98SAlexander V. Chernikov lltable_free_cb(struct lltable *llt, struct llentry *lle, void *farg) 64211cdad98SAlexander V. Chernikov { 64311cdad98SAlexander V. Chernikov struct llentries *dchain; 64411cdad98SAlexander V. Chernikov 64511cdad98SAlexander V. Chernikov dchain = (struct llentries *)farg; 64611cdad98SAlexander V. Chernikov 64711cdad98SAlexander V. Chernikov LLE_WLOCK(lle); 6480f8d79d9SMatt Macy CK_LIST_INSERT_HEAD(dchain, lle, lle_chain); 64911cdad98SAlexander V. Chernikov 65011cdad98SAlexander V. Chernikov return (0); 65111cdad98SAlexander V. Chernikov } 65211cdad98SAlexander V. Chernikov 65311cdad98SAlexander V. Chernikov /* 65411cdad98SAlexander V. Chernikov * Free all entries from given table and free itself. 65511cdad98SAlexander V. Chernikov */ 65682f39c91SKip Macy void 65782f39c91SKip Macy lltable_free(struct lltable *llt) 65882f39c91SKip Macy { 65982f39c91SKip Macy struct llentry *lle, *next; 66011cdad98SAlexander V. Chernikov struct llentries dchain; 66182f39c91SKip Macy 66282f39c91SKip Macy KASSERT(llt != NULL, ("%s: llt is NULL", __func__)); 66382f39c91SKip Macy 664721cd2e0SAlexander V. Chernikov lltable_unlink(llt); 66582f39c91SKip Macy 6664f6c66ccSMatt Macy CK_LIST_INIT(&dchain); 667ea537929SGleb Smirnoff IF_AFDATA_WLOCK(llt->llt_ifp); 66811cdad98SAlexander V. Chernikov /* Push all lles to @dchain */ 66911cdad98SAlexander V. Chernikov lltable_foreach_lle(llt, lltable_free_cb, &dchain); 67011cdad98SAlexander V. Chernikov llentries_unlink(llt, &dchain); 67111cdad98SAlexander V. Chernikov IF_AFDATA_WUNLOCK(llt->llt_ifp); 67211cdad98SAlexander V. Chernikov 6730f8d79d9SMatt Macy CK_LIST_FOREACH_SAFE(lle, &dchain, lle_chain, next) { 67482f39c91SKip Macy llentry_free(lle); 67582f39c91SKip Macy } 67682f39c91SKip Macy 6773818c25aSBjoern A. Zeeb KASSERT(llt->llt_entries == 0, ("%s: lltable %p (%s) entires not 0: %d", 6783818c25aSBjoern A. Zeeb __func__, llt, llt->llt_ifp->if_xname, llt->llt_entries)); 6793818c25aSBjoern A. Zeeb 680721cd2e0SAlexander V. Chernikov llt->llt_free_tbl(llt); 68182f39c91SKip Macy } 68282f39c91SKip Macy 6833e7a2321SAlexander V. Chernikov /* 6843e7a2321SAlexander V. Chernikov * Deletes an address from given lltable. 6853e7a2321SAlexander V. Chernikov * Used for userland interaction to remove 6863e7a2321SAlexander V. Chernikov * individual entries. Skips entries added by OS. 6873e7a2321SAlexander V. Chernikov */ 6883e7a2321SAlexander V. Chernikov int 6893e7a2321SAlexander V. Chernikov lltable_delete_addr(struct lltable *llt, u_int flags, 6903e7a2321SAlexander V. Chernikov const struct sockaddr *l3addr) 6913e7a2321SAlexander V. Chernikov { 6923e7a2321SAlexander V. Chernikov struct llentry *lle; 6933e7a2321SAlexander V. Chernikov struct ifnet *ifp; 6943e7a2321SAlexander V. Chernikov 6953e7a2321SAlexander V. Chernikov ifp = llt->llt_ifp; 6963e7a2321SAlexander V. Chernikov IF_AFDATA_WLOCK(ifp); 697c541bd36SAlexander V. Chernikov lle = lla_lookup(llt, LLE_SF(l3addr->sa_family, LLE_EXCLUSIVE), l3addr); 6983e7a2321SAlexander V. Chernikov 6993e7a2321SAlexander V. Chernikov if (lle == NULL) { 7003e7a2321SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 7013e7a2321SAlexander V. Chernikov return (ENOENT); 7023e7a2321SAlexander V. Chernikov } 7033e7a2321SAlexander V. Chernikov if ((lle->la_flags & LLE_IFADDR) != 0 && (flags & LLE_IFADDR) == 0) { 7043e7a2321SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 7053e7a2321SAlexander V. Chernikov LLE_WUNLOCK(lle); 7063e7a2321SAlexander V. Chernikov return (EPERM); 7073e7a2321SAlexander V. Chernikov } 7083e7a2321SAlexander V. Chernikov 7093e7a2321SAlexander V. Chernikov lltable_unlink_entry(llt, lle); 7103e7a2321SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 7113e7a2321SAlexander V. Chernikov 7123e7a2321SAlexander V. Chernikov llt->llt_delete_entry(llt, lle); 7133e7a2321SAlexander V. Chernikov 7143e7a2321SAlexander V. Chernikov return (0); 7153e7a2321SAlexander V. Chernikov } 7163e7a2321SAlexander V. Chernikov 717c9d763bfSQing Li void 7183e7a2321SAlexander V. Chernikov lltable_prefix_free(int af, struct sockaddr *addr, struct sockaddr *mask, 7195b84dc78SQing Li u_int flags) 720c9d763bfSQing Li { 721c9d763bfSQing Li struct lltable *llt; 722c9d763bfSQing Li 723199511bcSAndrey V. Elsukov LLTABLE_LIST_RLOCK(); 724989e0411SMarko Zec SLIST_FOREACH(llt, &V_lltables, llt_link) { 725c9d763bfSQing Li if (llt->llt_af != af) 726c9d763bfSQing Li continue; 727c9d763bfSQing Li 7283e7a2321SAlexander V. Chernikov llt->llt_prefix_free(llt, addr, mask, flags); 729c9d763bfSQing Li } 730199511bcSAndrey V. Elsukov LLTABLE_LIST_RUNLOCK(); 731c9d763bfSQing Li } 732c9d763bfSQing Li 73382f39c91SKip Macy struct lltable * 73441cb42a6SAlexander V. Chernikov lltable_allocate_htbl(uint32_t hsize) 73582f39c91SKip Macy { 73682f39c91SKip Macy struct lltable *llt; 73741cb42a6SAlexander V. Chernikov int i; 73882f39c91SKip Macy 73941cb42a6SAlexander V. Chernikov llt = malloc(sizeof(struct lltable), M_LLTABLE, M_WAITOK | M_ZERO); 74041cb42a6SAlexander V. Chernikov llt->llt_hsize = hsize; 74141cb42a6SAlexander V. Chernikov llt->lle_head = malloc(sizeof(struct llentries) * hsize, 74241cb42a6SAlexander V. Chernikov M_LLTABLE, M_WAITOK | M_ZERO); 74382f39c91SKip Macy 74441cb42a6SAlexander V. Chernikov for (i = 0; i < llt->llt_hsize; i++) 7454f6c66ccSMatt Macy CK_LIST_INIT(&llt->lle_head[i]); 74682f39c91SKip Macy 74711cdad98SAlexander V. Chernikov /* Set some default callbacks */ 74811cdad98SAlexander V. Chernikov llt->llt_link_entry = htable_link_entry; 74911cdad98SAlexander V. Chernikov llt->llt_unlink_entry = htable_unlink_entry; 75011cdad98SAlexander V. Chernikov llt->llt_prefix_free = htable_prefix_free; 75111cdad98SAlexander V. Chernikov llt->llt_foreach_entry = htable_foreach_lle; 75241cb42a6SAlexander V. Chernikov llt->llt_free_tbl = htable_free_tbl; 75341cb42a6SAlexander V. Chernikov 75441cb42a6SAlexander V. Chernikov return (llt); 75541cb42a6SAlexander V. Chernikov } 75641cb42a6SAlexander V. Chernikov 75782f39c91SKip Macy /* 758721cd2e0SAlexander V. Chernikov * Links lltable to global llt list. 75982f39c91SKip Macy */ 760721cd2e0SAlexander V. Chernikov void 761721cd2e0SAlexander V. Chernikov lltable_link(struct lltable *llt) 76282f39c91SKip Macy { 76311cdad98SAlexander V. Chernikov 764199511bcSAndrey V. Elsukov LLTABLE_LIST_WLOCK(); 765989e0411SMarko Zec SLIST_INSERT_HEAD(&V_lltables, llt, llt_link); 766199511bcSAndrey V. Elsukov LLTABLE_LIST_WUNLOCK(); 767721cd2e0SAlexander V. Chernikov } 76882f39c91SKip Macy 769721cd2e0SAlexander V. Chernikov static void 770721cd2e0SAlexander V. Chernikov lltable_unlink(struct lltable *llt) 771721cd2e0SAlexander V. Chernikov { 772721cd2e0SAlexander V. Chernikov 773199511bcSAndrey V. Elsukov LLTABLE_LIST_WLOCK(); 774721cd2e0SAlexander V. Chernikov SLIST_REMOVE(&V_lltables, llt, lltable, llt_link); 775199511bcSAndrey V. Elsukov LLTABLE_LIST_WUNLOCK(); 776721cd2e0SAlexander V. Chernikov 77782f39c91SKip Macy } 77882f39c91SKip Macy 77982f39c91SKip Macy /* 780ff3a85d3SAlexander V. Chernikov * Gets interface @ifp lltable for the specified @family 781ff3a85d3SAlexander V. Chernikov */ 782ff3a85d3SAlexander V. Chernikov struct lltable * 783ff3a85d3SAlexander V. Chernikov lltable_get(struct ifnet *ifp, int family) 784ff3a85d3SAlexander V. Chernikov { 785ff3a85d3SAlexander V. Chernikov switch (family) { 786818952c6SEd Maste #ifdef INET 787ff3a85d3SAlexander V. Chernikov case AF_INET: 788ff3a85d3SAlexander V. Chernikov return (in_lltable_get(ifp)); 789818952c6SEd Maste #endif 790818952c6SEd Maste #ifdef INET6 791ff3a85d3SAlexander V. Chernikov case AF_INET6: 792ff3a85d3SAlexander V. Chernikov return (in6_lltable_get(ifp)); 793818952c6SEd Maste #endif 794ff3a85d3SAlexander V. Chernikov } 795ff3a85d3SAlexander V. Chernikov 796ff3a85d3SAlexander V. Chernikov return (NULL); 797ff3a85d3SAlexander V. Chernikov } 798ff3a85d3SAlexander V. Chernikov 799ff3a85d3SAlexander V. Chernikov /* 80011cdad98SAlexander V. Chernikov * External methods used by lltable consumers 80111cdad98SAlexander V. Chernikov */ 80211cdad98SAlexander V. Chernikov 80311cdad98SAlexander V. Chernikov int 80411cdad98SAlexander V. Chernikov lltable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg) 80511cdad98SAlexander V. Chernikov { 80611cdad98SAlexander V. Chernikov 80711cdad98SAlexander V. Chernikov return (llt->llt_foreach_entry(llt, f, farg)); 80811cdad98SAlexander V. Chernikov } 80911cdad98SAlexander V. Chernikov 8105a255516SAlexander V. Chernikov struct llentry * 8115a255516SAlexander V. Chernikov lltable_alloc_entry(struct lltable *llt, u_int flags, 8125a255516SAlexander V. Chernikov const struct sockaddr *l3addr) 8135a255516SAlexander V. Chernikov { 8145a255516SAlexander V. Chernikov 8155a255516SAlexander V. Chernikov return (llt->llt_alloc_entry(llt, flags, l3addr)); 8165a255516SAlexander V. Chernikov } 8175a255516SAlexander V. Chernikov 8185a255516SAlexander V. Chernikov void 8195a255516SAlexander V. Chernikov lltable_free_entry(struct lltable *llt, struct llentry *lle) 8205a255516SAlexander V. Chernikov { 8215a255516SAlexander V. Chernikov 8225a255516SAlexander V. Chernikov llt->llt_free_entry(llt, lle); 8235a255516SAlexander V. Chernikov } 8245a255516SAlexander V. Chernikov 8253818c25aSBjoern A. Zeeb int 82611cdad98SAlexander V. Chernikov lltable_link_entry(struct lltable *llt, struct llentry *lle) 82711cdad98SAlexander V. Chernikov { 82811cdad98SAlexander V. Chernikov 8293818c25aSBjoern A. Zeeb return (llt->llt_link_entry(llt, lle)); 83011cdad98SAlexander V. Chernikov } 83111cdad98SAlexander V. Chernikov 832c541bd36SAlexander V. Chernikov void 833c541bd36SAlexander V. Chernikov lltable_link_child_entry(struct llentry *lle, struct llentry *child_lle) 834c541bd36SAlexander V. Chernikov { 835c541bd36SAlexander V. Chernikov child_lle->lle_parent = lle; 836c541bd36SAlexander V. Chernikov child_lle->lle_tbl = lle->lle_tbl; 837c541bd36SAlexander V. Chernikov child_lle->la_flags |= LLE_LINKED; 838c541bd36SAlexander V. Chernikov CK_SLIST_INSERT_HEAD(&lle->lle_children, child_lle, lle_child_next); 839c541bd36SAlexander V. Chernikov } 840c541bd36SAlexander V. Chernikov 841c541bd36SAlexander V. Chernikov void 842c541bd36SAlexander V. Chernikov lltable_unlink_child_entry(struct llentry *child_lle) 843c541bd36SAlexander V. Chernikov { 844c541bd36SAlexander V. Chernikov struct llentry *lle = child_lle->lle_parent; 845c541bd36SAlexander V. Chernikov 846c541bd36SAlexander V. Chernikov child_lle->la_flags &= ~LLE_LINKED; 847c541bd36SAlexander V. Chernikov child_lle->lle_parent = NULL; 848c541bd36SAlexander V. Chernikov CK_SLIST_REMOVE(&lle->lle_children, child_lle, llentry, lle_child_next); 849c541bd36SAlexander V. Chernikov } 850c541bd36SAlexander V. Chernikov 8513818c25aSBjoern A. Zeeb int 85211cdad98SAlexander V. Chernikov lltable_unlink_entry(struct lltable *llt, struct llentry *lle) 85311cdad98SAlexander V. Chernikov { 85411cdad98SAlexander V. Chernikov 8553818c25aSBjoern A. Zeeb return (llt->llt_unlink_entry(lle)); 85611cdad98SAlexander V. Chernikov } 85711cdad98SAlexander V. Chernikov 85811cdad98SAlexander V. Chernikov void 85911cdad98SAlexander V. Chernikov lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa) 86011cdad98SAlexander V. Chernikov { 86111cdad98SAlexander V. Chernikov struct lltable *llt; 86211cdad98SAlexander V. Chernikov 86311cdad98SAlexander V. Chernikov llt = lle->lle_tbl; 86411cdad98SAlexander V. Chernikov llt->llt_fill_sa_entry(lle, sa); 86511cdad98SAlexander V. Chernikov } 86611cdad98SAlexander V. Chernikov 86711cdad98SAlexander V. Chernikov struct ifnet * 86811cdad98SAlexander V. Chernikov lltable_get_ifp(const struct lltable *llt) 86911cdad98SAlexander V. Chernikov { 87011cdad98SAlexander V. Chernikov 87111cdad98SAlexander V. Chernikov return (llt->llt_ifp); 87211cdad98SAlexander V. Chernikov } 87311cdad98SAlexander V. Chernikov 87411cdad98SAlexander V. Chernikov int 87511cdad98SAlexander V. Chernikov lltable_get_af(const struct lltable *llt) 87611cdad98SAlexander V. Chernikov { 87711cdad98SAlexander V. Chernikov 87811cdad98SAlexander V. Chernikov return (llt->llt_af); 87911cdad98SAlexander V. Chernikov } 88011cdad98SAlexander V. Chernikov 88111cdad98SAlexander V. Chernikov /* 882b4b1367aSAlexander V. Chernikov * Called in route_output when rtm_flags contains RTF_LLDATA. 88382f39c91SKip Macy */ 88482f39c91SKip Macy int 88582f39c91SKip Macy lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info) 88682f39c91SKip Macy { 88782f39c91SKip Macy struct sockaddr_dl *dl = 88882f39c91SKip Macy (struct sockaddr_dl *)info->rti_info[RTAX_GATEWAY]; 88982f39c91SKip Macy struct sockaddr *dst = (struct sockaddr *)info->rti_info[RTAX_DST]; 89082f39c91SKip Macy struct ifnet *ifp; 89182f39c91SKip Macy struct lltable *llt; 8925a255516SAlexander V. Chernikov struct llentry *lle, *lle_tmp; 8934fb3a820SAlexander V. Chernikov uint8_t linkhdr[LLE_MAX_LINKHDR]; 8944fb3a820SAlexander V. Chernikov size_t linkhdrsize; 8954fb3a820SAlexander V. Chernikov int lladdr_off; 896b4b1367aSAlexander V. Chernikov u_int laflags = 0; 897b4b1367aSAlexander V. Chernikov int error; 89882f39c91SKip Macy 899c83dda36SAlexander V. Chernikov if (dl == NULL || dl->sdl_family != AF_LINK) 900c83dda36SAlexander V. Chernikov return (EINVAL); 9011910bfcbSGleb Smirnoff 902e5b394f2SAlexander V. Chernikov /* XXX: should be ntohs() */ 90382f39c91SKip Macy ifp = ifnet_byindex(dl->sdl_index); 90482f39c91SKip Macy if (ifp == NULL) { 90582f39c91SKip Macy log(LOG_INFO, "%s: invalid ifp (sdl_index %d)\n", 90682f39c91SKip Macy __func__, dl->sdl_index); 90782f39c91SKip Macy return EINVAL; 90882f39c91SKip Macy } 90982f39c91SKip Macy 910ff3a85d3SAlexander V. Chernikov llt = lltable_get(ifp, dst->sa_family); 911ff3a85d3SAlexander V. Chernikov 912c83dda36SAlexander V. Chernikov if (llt == NULL) 913c83dda36SAlexander V. Chernikov return (ESRCH); 91482f39c91SKip Macy 915b4b1367aSAlexander V. Chernikov error = 0; 91682f39c91SKip Macy 917b4b1367aSAlexander V. Chernikov switch (rtm->rtm_type) { 918b4b1367aSAlexander V. Chernikov case RTM_ADD: 919b4b1367aSAlexander V. Chernikov /* Add static LLE */ 9203b0fd911SAlexander V. Chernikov laflags = 0; 9213b0fd911SAlexander V. Chernikov if (rtm->rtm_rmx.rmx_expire == 0) 9223b0fd911SAlexander V. Chernikov laflags = LLE_STATIC; 9233b0fd911SAlexander V. Chernikov lle = lltable_alloc_entry(llt, laflags, dst); 9245a255516SAlexander V. Chernikov if (lle == NULL) 925b4b1367aSAlexander V. Chernikov return (ENOMEM); 926b4b1367aSAlexander V. Chernikov 9274fb3a820SAlexander V. Chernikov linkhdrsize = sizeof(linkhdr); 9284fb3a820SAlexander V. Chernikov if (lltable_calc_llheader(ifp, dst->sa_family, LLADDR(dl), 929*990a6d18SMark Johnston linkhdr, &linkhdrsize, &lladdr_off) != 0) { 930*990a6d18SMark Johnston lltable_free_entry(llt, lle); 9314fb3a820SAlexander V. Chernikov return (EINVAL); 932*990a6d18SMark Johnston } 9334fb3a820SAlexander V. Chernikov lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize, 9344fb3a820SAlexander V. Chernikov lladdr_off); 935b4b1367aSAlexander V. Chernikov if ((rtm->rtm_flags & RTF_ANNOUNCE)) 936b4b1367aSAlexander V. Chernikov lle->la_flags |= LLE_PUB; 93782f39c91SKip Macy lle->la_expire = rtm->rtm_rmx.rmx_expire; 9383b0fd911SAlexander V. Chernikov 93982f39c91SKip Macy laflags = lle->la_flags; 9405a255516SAlexander V. Chernikov 9415a255516SAlexander V. Chernikov /* Try to link new entry */ 9425a255516SAlexander V. Chernikov lle_tmp = NULL; 9435a255516SAlexander V. Chernikov IF_AFDATA_WLOCK(ifp); 9445a255516SAlexander V. Chernikov LLE_WLOCK(lle); 9455a255516SAlexander V. Chernikov lle_tmp = lla_lookup(llt, LLE_EXCLUSIVE, dst); 9465a255516SAlexander V. Chernikov if (lle_tmp != NULL) { 9475a255516SAlexander V. Chernikov /* Check if we are trying to replace immutable entry */ 9485a255516SAlexander V. Chernikov if ((lle_tmp->la_flags & LLE_IFADDR) != 0) { 949b4b1367aSAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 9505a255516SAlexander V. Chernikov LLE_WUNLOCK(lle_tmp); 9515a255516SAlexander V. Chernikov lltable_free_entry(llt, lle); 9525a255516SAlexander V. Chernikov return (EPERM); 9535a255516SAlexander V. Chernikov } 9545a255516SAlexander V. Chernikov /* Unlink existing entry from table */ 9555a255516SAlexander V. Chernikov lltable_unlink_entry(llt, lle_tmp); 9565a255516SAlexander V. Chernikov } 9575a255516SAlexander V. Chernikov lltable_link_entry(llt, lle); 9585a255516SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 9595a255516SAlexander V. Chernikov 9605a255516SAlexander V. Chernikov if (lle_tmp != NULL) { 9615a255516SAlexander V. Chernikov EVENTHANDLER_INVOKE(lle_event, lle_tmp,LLENTRY_EXPIRED); 9625a255516SAlexander V. Chernikov lltable_free_entry(llt, lle_tmp); 9635a255516SAlexander V. Chernikov } 9645a255516SAlexander V. Chernikov 9655a255516SAlexander V. Chernikov /* 9665a255516SAlexander V. Chernikov * By invoking LLE handler here we might get 9675a255516SAlexander V. Chernikov * two events on static LLE entry insertion 9685a255516SAlexander V. Chernikov * in routing socket. However, since we might have 9695a255516SAlexander V. Chernikov * other subscribers we need to generate this event. 9705a255516SAlexander V. Chernikov */ 9715a255516SAlexander V. Chernikov EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_RESOLVED); 9725a255516SAlexander V. Chernikov LLE_WUNLOCK(lle); 97382f39c91SKip Macy #ifdef INET 9747b4d716bSKip Macy /* gratuitous ARP */ 9759711a168SGleb Smirnoff if ((laflags & LLE_PUB) && dst->sa_family == AF_INET) 97682f39c91SKip Macy arprequest(ifp, 97782f39c91SKip Macy &((struct sockaddr_in *)dst)->sin_addr, 97882f39c91SKip Macy &((struct sockaddr_in *)dst)->sin_addr, 9799711a168SGleb Smirnoff (u_char *)LLADDR(dl)); 98082f39c91SKip Macy #endif 98182f39c91SKip Macy 982b4b1367aSAlexander V. Chernikov break; 983b4b1367aSAlexander V. Chernikov 984b4b1367aSAlexander V. Chernikov case RTM_DELETE: 9853e7a2321SAlexander V. Chernikov return (lltable_delete_addr(llt, 0, dst)); 986b4b1367aSAlexander V. Chernikov 987b4b1367aSAlexander V. Chernikov default: 988b4b1367aSAlexander V. Chernikov error = EINVAL; 989b4b1367aSAlexander V. Chernikov } 99082f39c91SKip Macy 99182f39c91SKip Macy return (error); 99282f39c91SKip Macy } 993989e0411SMarko Zec 994335b943fSBjoern A. Zeeb #ifdef DDB 995335b943fSBjoern A. Zeeb struct llentry_sa { 996335b943fSBjoern A. Zeeb struct llentry base; 997335b943fSBjoern A. Zeeb struct sockaddr l3_addr; 998335b943fSBjoern A. Zeeb }; 999335b943fSBjoern A. Zeeb 1000335b943fSBjoern A. Zeeb static void 1001335b943fSBjoern A. Zeeb llatbl_lle_show(struct llentry_sa *la) 1002335b943fSBjoern A. Zeeb { 1003335b943fSBjoern A. Zeeb struct llentry *lle; 1004335b943fSBjoern A. Zeeb uint8_t octet[6]; 1005335b943fSBjoern A. Zeeb 1006335b943fSBjoern A. Zeeb lle = &la->base; 1007335b943fSBjoern A. Zeeb db_printf("lle=%p\n", lle); 10080f8d79d9SMatt Macy db_printf(" lle_next=%p\n", lle->lle_next.cle_next); 1009335b943fSBjoern A. Zeeb db_printf(" lle_lock=%p\n", &lle->lle_lock); 1010335b943fSBjoern A. Zeeb db_printf(" lle_tbl=%p\n", lle->lle_tbl); 1011335b943fSBjoern A. Zeeb db_printf(" lle_head=%p\n", lle->lle_head); 1012335b943fSBjoern A. Zeeb db_printf(" la_hold=%p\n", lle->la_hold); 1013e162ea60SGeorge V. Neville-Neil db_printf(" la_numheld=%d\n", lle->la_numheld); 1014335b943fSBjoern A. Zeeb db_printf(" la_expire=%ju\n", (uintmax_t)lle->la_expire); 1015335b943fSBjoern A. Zeeb db_printf(" la_flags=0x%04x\n", lle->la_flags); 1016335b943fSBjoern A. Zeeb db_printf(" la_asked=%u\n", lle->la_asked); 1017335b943fSBjoern A. Zeeb db_printf(" la_preempt=%u\n", lle->la_preempt); 1018335b943fSBjoern A. Zeeb db_printf(" ln_state=%d\n", lle->ln_state); 1019335b943fSBjoern A. Zeeb db_printf(" ln_router=%u\n", lle->ln_router); 1020335b943fSBjoern A. Zeeb db_printf(" ln_ntick=%ju\n", (uintmax_t)lle->ln_ntick); 1021335b943fSBjoern A. Zeeb db_printf(" lle_refcnt=%d\n", lle->lle_refcnt); 10224fb3a820SAlexander V. Chernikov bcopy(lle->ll_addr, octet, sizeof(octet)); 1023335b943fSBjoern A. Zeeb db_printf(" ll_addr=%02x:%02x:%02x:%02x:%02x:%02x\n", 1024335b943fSBjoern A. Zeeb octet[0], octet[1], octet[2], octet[3], octet[4], octet[5]); 10250447c136SAlexander V. Chernikov db_printf(" lle_timer=%p\n", &lle->lle_timer); 1026335b943fSBjoern A. Zeeb 1027335b943fSBjoern A. Zeeb switch (la->l3_addr.sa_family) { 1028335b943fSBjoern A. Zeeb #ifdef INET 1029335b943fSBjoern A. Zeeb case AF_INET: 1030335b943fSBjoern A. Zeeb { 1031335b943fSBjoern A. Zeeb struct sockaddr_in *sin; 1032335b943fSBjoern A. Zeeb char l3s[INET_ADDRSTRLEN]; 1033335b943fSBjoern A. Zeeb 1034335b943fSBjoern A. Zeeb sin = (struct sockaddr_in *)&la->l3_addr; 1035335b943fSBjoern A. Zeeb inet_ntoa_r(sin->sin_addr, l3s); 1036335b943fSBjoern A. Zeeb db_printf(" l3_addr=%s\n", l3s); 1037335b943fSBjoern A. Zeeb break; 1038335b943fSBjoern A. Zeeb } 1039335b943fSBjoern A. Zeeb #endif 1040335b943fSBjoern A. Zeeb #ifdef INET6 1041335b943fSBjoern A. Zeeb case AF_INET6: 1042335b943fSBjoern A. Zeeb { 1043335b943fSBjoern A. Zeeb struct sockaddr_in6 *sin6; 1044335b943fSBjoern A. Zeeb char l3s[INET6_ADDRSTRLEN]; 1045335b943fSBjoern A. Zeeb 1046335b943fSBjoern A. Zeeb sin6 = (struct sockaddr_in6 *)&la->l3_addr; 1047335b943fSBjoern A. Zeeb ip6_sprintf(l3s, &sin6->sin6_addr); 1048335b943fSBjoern A. Zeeb db_printf(" l3_addr=%s\n", l3s); 1049335b943fSBjoern A. Zeeb break; 1050335b943fSBjoern A. Zeeb } 1051335b943fSBjoern A. Zeeb #endif 1052335b943fSBjoern A. Zeeb default: 1053335b943fSBjoern A. Zeeb db_printf(" l3_addr=N/A (af=%d)\n", la->l3_addr.sa_family); 1054335b943fSBjoern A. Zeeb break; 1055335b943fSBjoern A. Zeeb } 1056335b943fSBjoern A. Zeeb } 1057335b943fSBjoern A. Zeeb 1058335b943fSBjoern A. Zeeb DB_SHOW_COMMAND(llentry, db_show_llentry) 1059335b943fSBjoern A. Zeeb { 1060335b943fSBjoern A. Zeeb 1061335b943fSBjoern A. Zeeb if (!have_addr) { 1062335b943fSBjoern A. Zeeb db_printf("usage: show llentry <struct llentry *>\n"); 1063335b943fSBjoern A. Zeeb return; 1064335b943fSBjoern A. Zeeb } 1065335b943fSBjoern A. Zeeb 1066335b943fSBjoern A. Zeeb llatbl_lle_show((struct llentry_sa *)addr); 1067335b943fSBjoern A. Zeeb } 1068335b943fSBjoern A. Zeeb 1069335b943fSBjoern A. Zeeb static void 1070335b943fSBjoern A. Zeeb llatbl_llt_show(struct lltable *llt) 1071335b943fSBjoern A. Zeeb { 1072335b943fSBjoern A. Zeeb int i; 1073335b943fSBjoern A. Zeeb struct llentry *lle; 1074335b943fSBjoern A. Zeeb 1075335b943fSBjoern A. Zeeb db_printf("llt=%p llt_af=%d llt_ifp=%p\n", 1076335b943fSBjoern A. Zeeb llt, llt->llt_af, llt->llt_ifp); 1077335b943fSBjoern A. Zeeb 10783a749863SAlexander V. Chernikov for (i = 0; i < llt->llt_hsize; i++) { 10794f6c66ccSMatt Macy CK_LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { 1080335b943fSBjoern A. Zeeb llatbl_lle_show((struct llentry_sa *)lle); 1081335b943fSBjoern A. Zeeb if (db_pager_quit) 1082335b943fSBjoern A. Zeeb return; 1083335b943fSBjoern A. Zeeb } 1084335b943fSBjoern A. Zeeb } 1085335b943fSBjoern A. Zeeb } 1086335b943fSBjoern A. Zeeb 1087335b943fSBjoern A. Zeeb DB_SHOW_COMMAND(lltable, db_show_lltable) 1088335b943fSBjoern A. Zeeb { 1089335b943fSBjoern A. Zeeb 1090335b943fSBjoern A. Zeeb if (!have_addr) { 1091335b943fSBjoern A. Zeeb db_printf("usage: show lltable <struct lltable *>\n"); 1092335b943fSBjoern A. Zeeb return; 1093335b943fSBjoern A. Zeeb } 1094335b943fSBjoern A. Zeeb 1095335b943fSBjoern A. Zeeb llatbl_llt_show((struct lltable *)addr); 1096335b943fSBjoern A. Zeeb } 1097335b943fSBjoern A. Zeeb 1098335b943fSBjoern A. Zeeb DB_SHOW_ALL_COMMAND(lltables, db_show_all_lltables) 1099335b943fSBjoern A. Zeeb { 1100335b943fSBjoern A. Zeeb VNET_ITERATOR_DECL(vnet_iter); 1101335b943fSBjoern A. Zeeb struct lltable *llt; 1102335b943fSBjoern A. Zeeb 1103335b943fSBjoern A. Zeeb VNET_FOREACH(vnet_iter) { 1104335b943fSBjoern A. Zeeb CURVNET_SET_QUIET(vnet_iter); 1105335b943fSBjoern A. Zeeb #ifdef VIMAGE 1106335b943fSBjoern A. Zeeb db_printf("vnet=%p\n", curvnet); 1107335b943fSBjoern A. Zeeb #endif 1108335b943fSBjoern A. Zeeb SLIST_FOREACH(llt, &V_lltables, llt_link) { 1109335b943fSBjoern A. Zeeb db_printf("llt=%p llt_af=%d llt_ifp=%p(%s)\n", 1110335b943fSBjoern A. Zeeb llt, llt->llt_af, llt->llt_ifp, 1111335b943fSBjoern A. Zeeb (llt->llt_ifp != NULL) ? 1112335b943fSBjoern A. Zeeb llt->llt_ifp->if_xname : "?"); 1113335b943fSBjoern A. Zeeb if (have_addr && addr != 0) /* verbose */ 1114335b943fSBjoern A. Zeeb llatbl_llt_show(llt); 1115335b943fSBjoern A. Zeeb if (db_pager_quit) { 1116335b943fSBjoern A. Zeeb CURVNET_RESTORE(); 1117335b943fSBjoern A. Zeeb return; 1118335b943fSBjoern A. Zeeb } 1119335b943fSBjoern A. Zeeb } 1120335b943fSBjoern A. Zeeb CURVNET_RESTORE(); 1121335b943fSBjoern A. Zeeb } 1122335b943fSBjoern A. Zeeb } 1123335b943fSBjoern A. Zeeb #endif 1124