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> 62530c0060SRobert Watson #include <net/vnet.h> 6382f39c91SKip Macy #include <netinet/if_ether.h> 6482f39c91SKip Macy #include <netinet6/in6_var.h> 6582f39c91SKip Macy #include <netinet6/nd6.h> 6682f39c91SKip Macy 6782f39c91SKip Macy MALLOC_DEFINE(M_LLTABLE, "lltable", "link level address tables"); 6882f39c91SKip Macy 695f901c92SAndrew Turner VNET_DEFINE_STATIC(SLIST_HEAD(, lltable), lltables) = 7076d68eccSBjoern A. Zeeb SLIST_HEAD_INITIALIZER(lltables); 71989e0411SMarko Zec #define V_lltables VNET(lltables) 7282f39c91SKip Macy 73199511bcSAndrey V. Elsukov static struct rwlock lltable_list_lock; 74199511bcSAndrey V. Elsukov RW_SYSINIT(lltable_list_lock, &lltable_list_lock, "lltable_list_lock"); 75199511bcSAndrey V. Elsukov #define LLTABLE_LIST_RLOCK() rw_rlock(&lltable_list_lock) 76199511bcSAndrey V. Elsukov #define LLTABLE_LIST_RUNLOCK() rw_runlock(&lltable_list_lock) 77199511bcSAndrey V. Elsukov #define LLTABLE_LIST_WLOCK() rw_wlock(&lltable_list_lock) 78199511bcSAndrey V. Elsukov #define LLTABLE_LIST_WUNLOCK() rw_wunlock(&lltable_list_lock) 79199511bcSAndrey V. Elsukov #define LLTABLE_LIST_LOCK_ASSERT() rw_assert(&lltable_list_lock, RA_LOCKED) 80dc56e98fSRobert Watson 81721cd2e0SAlexander V. Chernikov static void lltable_unlink(struct lltable *llt); 8211cdad98SAlexander V. Chernikov static void llentries_unlink(struct lltable *llt, struct llentries *head); 8311cdad98SAlexander V. Chernikov 8411cdad98SAlexander V. Chernikov /* 8511cdad98SAlexander V. Chernikov * Dump lle state for a specific address family. 8611cdad98SAlexander V. Chernikov */ 8711cdad98SAlexander V. Chernikov static int 8811cdad98SAlexander V. Chernikov lltable_dump_af(struct lltable *llt, struct sysctl_req *wr) 8911cdad98SAlexander V. Chernikov { 90a68cc388SGleb Smirnoff struct epoch_tracker et; 9111cdad98SAlexander V. Chernikov int error; 9211cdad98SAlexander V. Chernikov 93199511bcSAndrey V. Elsukov LLTABLE_LIST_LOCK_ASSERT(); 9411cdad98SAlexander V. Chernikov 9511cdad98SAlexander V. Chernikov if (llt->llt_ifp->if_flags & IFF_LOOPBACK) 9611cdad98SAlexander V. Chernikov return (0); 9711cdad98SAlexander V. Chernikov error = 0; 9811cdad98SAlexander V. Chernikov 99a68cc388SGleb Smirnoff NET_EPOCH_ENTER(et); 10011cdad98SAlexander V. Chernikov error = lltable_foreach_lle(llt, 10111cdad98SAlexander V. Chernikov (llt_foreach_cb_t *)llt->llt_dump_entry, wr); 102a68cc388SGleb Smirnoff NET_EPOCH_EXIT(et); 10311cdad98SAlexander V. Chernikov 10411cdad98SAlexander V. Chernikov return (error); 10511cdad98SAlexander V. Chernikov } 10611cdad98SAlexander V. Chernikov 10782f39c91SKip Macy /* 10882f39c91SKip Macy * Dump arp state for a specific address family. 10982f39c91SKip Macy */ 11082f39c91SKip Macy int 11182f39c91SKip Macy lltable_sysctl_dumparp(int af, struct sysctl_req *wr) 11282f39c91SKip Macy { 11382f39c91SKip Macy struct lltable *llt; 11482f39c91SKip Macy int error = 0; 11582f39c91SKip Macy 116199511bcSAndrey V. Elsukov LLTABLE_LIST_RLOCK(); 117989e0411SMarko Zec SLIST_FOREACH(llt, &V_lltables, llt_link) { 11882f39c91SKip Macy if (llt->llt_af == af) { 11911cdad98SAlexander V. Chernikov error = lltable_dump_af(llt, wr); 12082f39c91SKip Macy if (error != 0) 12182f39c91SKip Macy goto done; 12282f39c91SKip Macy } 12382f39c91SKip Macy } 12482f39c91SKip Macy done: 125199511bcSAndrey V. Elsukov LLTABLE_LIST_RUNLOCK(); 12682f39c91SKip Macy return (error); 12782f39c91SKip Macy } 12882f39c91SKip Macy 12982f39c91SKip Macy /* 13011cdad98SAlexander V. Chernikov * Common function helpers for chained hash table. 13111cdad98SAlexander V. Chernikov */ 13211cdad98SAlexander V. Chernikov 13311cdad98SAlexander V. Chernikov /* 13411cdad98SAlexander V. Chernikov * Runs specified callback for each entry in @llt. 13511cdad98SAlexander V. Chernikov * Caller does the locking. 13611cdad98SAlexander V. Chernikov * 13711cdad98SAlexander V. Chernikov */ 13811cdad98SAlexander V. Chernikov static int 13911cdad98SAlexander V. Chernikov htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg) 14011cdad98SAlexander V. Chernikov { 14111cdad98SAlexander V. Chernikov struct llentry *lle, *next; 14211cdad98SAlexander V. Chernikov int i, error; 14311cdad98SAlexander V. Chernikov 14411cdad98SAlexander V. Chernikov error = 0; 14511cdad98SAlexander V. Chernikov 14641cb42a6SAlexander V. Chernikov for (i = 0; i < llt->llt_hsize; i++) { 1474f6c66ccSMatt Macy CK_LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) { 14811cdad98SAlexander V. Chernikov error = f(llt, lle, farg); 14911cdad98SAlexander V. Chernikov if (error != 0) 15011cdad98SAlexander V. Chernikov break; 15111cdad98SAlexander V. Chernikov } 15211cdad98SAlexander V. Chernikov } 15311cdad98SAlexander V. Chernikov 15411cdad98SAlexander V. Chernikov return (error); 15511cdad98SAlexander V. Chernikov } 15611cdad98SAlexander V. Chernikov 1573818c25aSBjoern A. Zeeb /* 1583818c25aSBjoern A. Zeeb * The htable_[un]link_entry() functions return: 1593818c25aSBjoern A. Zeeb * 0 if the entry was (un)linked already and nothing changed, 1603818c25aSBjoern A. Zeeb * 1 if the entry was added/removed to/from the table, and 1613818c25aSBjoern A. Zeeb * -1 on error (e.g., not being able to add the entry due to limits reached). 1623818c25aSBjoern A. Zeeb * While the "unlink" operation should never error, callers of 1633818c25aSBjoern A. Zeeb * lltable_link_entry() need to check for errors and handle them. 1643818c25aSBjoern A. Zeeb */ 1653818c25aSBjoern A. Zeeb static int 16611cdad98SAlexander V. Chernikov htable_link_entry(struct lltable *llt, struct llentry *lle) 16711cdad98SAlexander V. Chernikov { 16811cdad98SAlexander V. Chernikov struct llentries *lleh; 16911cdad98SAlexander V. Chernikov uint32_t hashidx; 17011cdad98SAlexander V. Chernikov 17111cdad98SAlexander V. Chernikov if ((lle->la_flags & LLE_LINKED) != 0) 1723818c25aSBjoern A. Zeeb return (0); 17311cdad98SAlexander V. Chernikov 17411cdad98SAlexander V. Chernikov IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp); 17511cdad98SAlexander V. Chernikov 1763818c25aSBjoern A. Zeeb if (llt->llt_maxentries > 0 && 1773818c25aSBjoern A. Zeeb llt->llt_entries >= llt->llt_maxentries) 1783818c25aSBjoern A. Zeeb return (-1); 1793818c25aSBjoern A. Zeeb 1803a749863SAlexander V. Chernikov hashidx = llt->llt_hash(lle, llt->llt_hsize); 18111cdad98SAlexander V. Chernikov lleh = &llt->lle_head[hashidx]; 18211cdad98SAlexander V. Chernikov 18311cdad98SAlexander V. Chernikov lle->lle_tbl = llt; 18411cdad98SAlexander V. Chernikov lle->lle_head = lleh; 18511cdad98SAlexander V. Chernikov lle->la_flags |= LLE_LINKED; 1864f6c66ccSMatt Macy CK_LIST_INSERT_HEAD(lleh, lle, lle_next); 1873818c25aSBjoern A. Zeeb llt->llt_entries++; 1883818c25aSBjoern A. Zeeb 1893818c25aSBjoern A. Zeeb return (1); 19011cdad98SAlexander V. Chernikov } 19111cdad98SAlexander V. Chernikov 1923818c25aSBjoern A. Zeeb static int 19311cdad98SAlexander V. Chernikov htable_unlink_entry(struct llentry *lle) 19411cdad98SAlexander V. Chernikov { 1953818c25aSBjoern A. Zeeb struct lltable *llt; 19611cdad98SAlexander V. Chernikov 197d9a61c96SBjoern A. Zeeb if ((lle->la_flags & LLE_LINKED) == 0) 1983818c25aSBjoern A. Zeeb return (0); 199d9a61c96SBjoern A. Zeeb 2003818c25aSBjoern A. Zeeb llt = lle->lle_tbl; 2013818c25aSBjoern A. Zeeb IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp); 2023818c25aSBjoern A. Zeeb KASSERT(llt->llt_entries > 0, ("%s: lltable %p (%s) entries %d <= 0", 2033818c25aSBjoern A. Zeeb __func__, llt, if_name(llt->llt_ifp), llt->llt_entries)); 2043818c25aSBjoern A. Zeeb 2054f6c66ccSMatt Macy CK_LIST_REMOVE(lle, lle_next); 20611cdad98SAlexander V. Chernikov lle->la_flags &= ~(LLE_VALID | LLE_LINKED); 20711cdad98SAlexander V. Chernikov #if 0 20811cdad98SAlexander V. Chernikov lle->lle_tbl = NULL; 20911cdad98SAlexander V. Chernikov lle->lle_head = NULL; 21011cdad98SAlexander V. Chernikov #endif 2113818c25aSBjoern A. Zeeb llt->llt_entries--; 2123818c25aSBjoern A. Zeeb 2133818c25aSBjoern A. Zeeb return (1); 21411cdad98SAlexander V. Chernikov } 21511cdad98SAlexander V. Chernikov 21611cdad98SAlexander V. Chernikov struct prefix_match_data { 2173e7a2321SAlexander V. Chernikov const struct sockaddr *addr; 21811cdad98SAlexander V. Chernikov const struct sockaddr *mask; 21911cdad98SAlexander V. Chernikov struct llentries dchain; 22011cdad98SAlexander V. Chernikov u_int flags; 22111cdad98SAlexander V. Chernikov }; 22211cdad98SAlexander V. Chernikov 22311cdad98SAlexander V. Chernikov static int 22411cdad98SAlexander V. Chernikov htable_prefix_free_cb(struct lltable *llt, struct llentry *lle, void *farg) 22511cdad98SAlexander V. Chernikov { 22611cdad98SAlexander V. Chernikov struct prefix_match_data *pmd; 22711cdad98SAlexander V. Chernikov 22811cdad98SAlexander V. Chernikov pmd = (struct prefix_match_data *)farg; 22911cdad98SAlexander V. Chernikov 2303e7a2321SAlexander V. Chernikov if (llt->llt_match_prefix(pmd->addr, pmd->mask, pmd->flags, lle)) { 23111cdad98SAlexander V. Chernikov LLE_WLOCK(lle); 2320f8d79d9SMatt Macy CK_LIST_INSERT_HEAD(&pmd->dchain, lle, lle_chain); 23311cdad98SAlexander V. Chernikov } 23411cdad98SAlexander V. Chernikov 23511cdad98SAlexander V. Chernikov return (0); 23611cdad98SAlexander V. Chernikov } 23711cdad98SAlexander V. Chernikov 23811cdad98SAlexander V. Chernikov static void 2393e7a2321SAlexander V. Chernikov htable_prefix_free(struct lltable *llt, const struct sockaddr *addr, 24011cdad98SAlexander V. Chernikov const struct sockaddr *mask, u_int flags) 24111cdad98SAlexander V. Chernikov { 24211cdad98SAlexander V. Chernikov struct llentry *lle, *next; 24311cdad98SAlexander V. Chernikov struct prefix_match_data pmd; 24411cdad98SAlexander V. Chernikov 24511cdad98SAlexander V. Chernikov bzero(&pmd, sizeof(pmd)); 2463e7a2321SAlexander V. Chernikov pmd.addr = addr; 24711cdad98SAlexander V. Chernikov pmd.mask = mask; 24811cdad98SAlexander V. Chernikov pmd.flags = flags; 2494f6c66ccSMatt Macy CK_LIST_INIT(&pmd.dchain); 25011cdad98SAlexander V. Chernikov 25111cdad98SAlexander V. Chernikov IF_AFDATA_WLOCK(llt->llt_ifp); 25211cdad98SAlexander V. Chernikov /* Push matching lles to chain */ 25311cdad98SAlexander V. Chernikov lltable_foreach_lle(llt, htable_prefix_free_cb, &pmd); 25411cdad98SAlexander V. Chernikov 25511cdad98SAlexander V. Chernikov llentries_unlink(llt, &pmd.dchain); 25611cdad98SAlexander V. Chernikov IF_AFDATA_WUNLOCK(llt->llt_ifp); 25711cdad98SAlexander V. Chernikov 2580f8d79d9SMatt Macy CK_LIST_FOREACH_SAFE(lle, &pmd.dchain, lle_chain, next) 2595a255516SAlexander V. Chernikov lltable_free_entry(llt, lle); 26011cdad98SAlexander V. Chernikov } 26111cdad98SAlexander V. Chernikov 26211cdad98SAlexander V. Chernikov static void 26341cb42a6SAlexander V. Chernikov htable_free_tbl(struct lltable *llt) 26441cb42a6SAlexander V. Chernikov { 26541cb42a6SAlexander V. Chernikov 26641cb42a6SAlexander V. Chernikov free(llt->lle_head, M_LLTABLE); 26741cb42a6SAlexander V. Chernikov free(llt, M_LLTABLE); 26841cb42a6SAlexander V. Chernikov } 26941cb42a6SAlexander V. Chernikov 270721cd2e0SAlexander V. Chernikov static void 27111cdad98SAlexander V. Chernikov llentries_unlink(struct lltable *llt, struct llentries *head) 27211cdad98SAlexander V. Chernikov { 27311cdad98SAlexander V. Chernikov struct llentry *lle, *next; 27411cdad98SAlexander V. Chernikov 2750f8d79d9SMatt Macy CK_LIST_FOREACH_SAFE(lle, head, lle_chain, next) 27611cdad98SAlexander V. Chernikov llt->llt_unlink_entry(lle); 27711cdad98SAlexander V. Chernikov } 27811cdad98SAlexander V. Chernikov 27911cdad98SAlexander V. Chernikov /* 28011cdad98SAlexander V. Chernikov * Helper function used to drop all mbufs in hold queue. 281e162ea60SGeorge V. Neville-Neil * 282e162ea60SGeorge V. Neville-Neil * Returns the number of held packets, if any, that were dropped. 28382f39c91SKip Macy */ 284e162ea60SGeorge V. Neville-Neil size_t 28511cdad98SAlexander V. Chernikov lltable_drop_entry_queue(struct llentry *lle) 28682f39c91SKip Macy { 287e162ea60SGeorge V. Neville-Neil size_t pkts_dropped; 288e162ea60SGeorge V. Neville-Neil struct mbuf *next; 28982f39c91SKip Macy 29082f39c91SKip Macy LLE_WLOCK_ASSERT(lle); 29182f39c91SKip Macy 292ea537929SGleb Smirnoff pkts_dropped = 0; 293e162ea60SGeorge V. Neville-Neil while ((lle->la_numheld > 0) && (lle->la_hold != NULL)) { 294e162ea60SGeorge V. Neville-Neil next = lle->la_hold->m_nextpkt; 29582f39c91SKip Macy m_freem(lle->la_hold); 296e162ea60SGeorge V. Neville-Neil lle->la_hold = next; 297e162ea60SGeorge V. Neville-Neil lle->la_numheld--; 298e162ea60SGeorge V. Neville-Neil pkts_dropped++; 299e162ea60SGeorge V. Neville-Neil } 300e162ea60SGeorge V. Neville-Neil 301e162ea60SGeorge V. Neville-Neil KASSERT(lle->la_numheld == 0, 3027b3b099eSKonstantin Belousov ("%s: la_numheld %d > 0, pkts_droped %zd", __func__, 303e162ea60SGeorge V. Neville-Neil lle->la_numheld, pkts_dropped)); 30482f39c91SKip Macy 30511cdad98SAlexander V. Chernikov return (pkts_dropped); 30611cdad98SAlexander V. Chernikov } 30711cdad98SAlexander V. Chernikov 308ddd208f7SAlexander V. Chernikov void 309ddd208f7SAlexander V. Chernikov lltable_set_entry_addr(struct ifnet *ifp, struct llentry *lle, 3104fb3a820SAlexander V. Chernikov const char *linkhdr, size_t linkhdrsize, int lladdr_off) 311ddd208f7SAlexander V. Chernikov { 312ddd208f7SAlexander V. Chernikov 3134fb3a820SAlexander V. Chernikov memcpy(lle->r_linkdata, linkhdr, linkhdrsize); 3144fb3a820SAlexander V. Chernikov lle->r_hdrlen = linkhdrsize; 3154fb3a820SAlexander V. Chernikov lle->ll_addr = &lle->r_linkdata[lladdr_off]; 316ddd208f7SAlexander V. Chernikov lle->la_flags |= LLE_VALID; 317f8aee88fSAlexander V. Chernikov lle->r_flags |= RLLE_VALID; 318ddd208f7SAlexander V. Chernikov } 319ddd208f7SAlexander V. Chernikov 32011cdad98SAlexander V. Chernikov /* 3210b79b007SAlexander V. Chernikov * Acquires lltable write lock. 3220b79b007SAlexander V. Chernikov * 3230b79b007SAlexander V. Chernikov * Returns true on success, with both lltable and lle lock held. 3240b79b007SAlexander V. Chernikov * On failure, false is returned and lle wlock is still held. 3250b79b007SAlexander V. Chernikov */ 3260b79b007SAlexander V. Chernikov bool 3270b79b007SAlexander V. Chernikov lltable_acquire_wlock(struct ifnet *ifp, struct llentry *lle) 3280b79b007SAlexander V. Chernikov { 3290b79b007SAlexander V. Chernikov NET_EPOCH_ASSERT(); 3300b79b007SAlexander V. Chernikov 3310b79b007SAlexander V. Chernikov /* Perform real LLE update */ 3320b79b007SAlexander V. Chernikov /* use afdata WLOCK to update fields */ 3330b79b007SAlexander V. Chernikov LLE_WUNLOCK(lle); 3340b79b007SAlexander V. Chernikov IF_AFDATA_WLOCK(ifp); 3350b79b007SAlexander V. Chernikov LLE_WLOCK(lle); 3360b79b007SAlexander V. Chernikov 3370b79b007SAlexander V. Chernikov /* 3380b79b007SAlexander V. Chernikov * Since we droppped LLE lock, other thread might have deleted 3390b79b007SAlexander V. Chernikov * this lle. Check and return 3400b79b007SAlexander V. Chernikov */ 3410b79b007SAlexander V. Chernikov if ((lle->la_flags & LLE_DELETED) != 0) { 3420b79b007SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 3430b79b007SAlexander V. Chernikov return (false); 3440b79b007SAlexander V. Chernikov } 3450b79b007SAlexander V. Chernikov 3460b79b007SAlexander V. Chernikov return (true); 3470b79b007SAlexander V. Chernikov } 3480b79b007SAlexander V. Chernikov 3490b79b007SAlexander V. Chernikov /* 35012cb7521SAlexander V. Chernikov * Tries to update @lle link-level address. 35112cb7521SAlexander V. Chernikov * Since update requires AFDATA WLOCK, function 35212cb7521SAlexander V. Chernikov * drops @lle lock, acquires AFDATA lock and then acquires 35312cb7521SAlexander V. Chernikov * @lle lock to maintain lock order. 35412cb7521SAlexander V. Chernikov * 35512cb7521SAlexander V. Chernikov * Returns 1 on success. 35612cb7521SAlexander V. Chernikov */ 35712cb7521SAlexander V. Chernikov int 35812cb7521SAlexander V. Chernikov lltable_try_set_entry_addr(struct ifnet *ifp, struct llentry *lle, 3594fb3a820SAlexander V. Chernikov const char *linkhdr, size_t linkhdrsize, int lladdr_off) 36012cb7521SAlexander V. Chernikov { 36112cb7521SAlexander V. Chernikov 3620b79b007SAlexander V. Chernikov if (!lltable_acquire_wlock(ifp, lle)) 36312cb7521SAlexander V. Chernikov return (0); 36412cb7521SAlexander V. Chernikov 36512cb7521SAlexander V. Chernikov /* Update data */ 3664fb3a820SAlexander V. Chernikov lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize, lladdr_off); 36712cb7521SAlexander V. Chernikov 36812cb7521SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 36912cb7521SAlexander V. Chernikov 37012cb7521SAlexander V. Chernikov return (1); 37112cb7521SAlexander V. Chernikov } 37212cb7521SAlexander V. Chernikov 37312cb7521SAlexander V. Chernikov /* 3744fb3a820SAlexander V. Chernikov * Helper function used to pre-compute full/partial link-layer 3754fb3a820SAlexander V. Chernikov * header data suitable for feeding into if_output(). 3764fb3a820SAlexander V. Chernikov */ 3774fb3a820SAlexander V. Chernikov int 3784fb3a820SAlexander V. Chernikov lltable_calc_llheader(struct ifnet *ifp, int family, char *lladdr, 3794fb3a820SAlexander V. Chernikov char *buf, size_t *bufsize, int *lladdr_off) 3804fb3a820SAlexander V. Chernikov { 3814fb3a820SAlexander V. Chernikov struct if_encap_req ereq; 3824fb3a820SAlexander V. Chernikov int error; 3834fb3a820SAlexander V. Chernikov 3844fb3a820SAlexander V. Chernikov bzero(buf, *bufsize); 3854fb3a820SAlexander V. Chernikov bzero(&ereq, sizeof(ereq)); 3864fb3a820SAlexander V. Chernikov ereq.buf = buf; 3874fb3a820SAlexander V. Chernikov ereq.bufsize = *bufsize; 3884fb3a820SAlexander V. Chernikov ereq.rtype = IFENCAP_LL; 3894fb3a820SAlexander V. Chernikov ereq.family = family; 3904fb3a820SAlexander V. Chernikov ereq.lladdr = lladdr; 3914fb3a820SAlexander V. Chernikov ereq.lladdr_len = ifp->if_addrlen; 3924fb3a820SAlexander V. Chernikov error = ifp->if_requestencap(ifp, &ereq); 3934fb3a820SAlexander V. Chernikov if (error == 0) { 3944fb3a820SAlexander V. Chernikov *bufsize = ereq.bufsize; 3954fb3a820SAlexander V. Chernikov *lladdr_off = ereq.lladdr_off; 3964fb3a820SAlexander V. Chernikov } 3974fb3a820SAlexander V. Chernikov 3984fb3a820SAlexander V. Chernikov return (error); 3994fb3a820SAlexander V. Chernikov } 4004fb3a820SAlexander V. Chernikov 4014fb3a820SAlexander V. Chernikov /* 402c541bd36SAlexander V. Chernikov * Searches for the child entry matching @family inside @lle. 403c541bd36SAlexander V. Chernikov * Returns the entry or NULL. 404c541bd36SAlexander V. Chernikov */ 405c541bd36SAlexander V. Chernikov struct llentry * 406c541bd36SAlexander V. Chernikov llentry_lookup_family(struct llentry *lle, int family) 407c541bd36SAlexander V. Chernikov { 408c541bd36SAlexander V. Chernikov struct llentry *child_lle; 409c541bd36SAlexander V. Chernikov 410c541bd36SAlexander V. Chernikov if (lle == NULL) 411c541bd36SAlexander V. Chernikov return (NULL); 412c541bd36SAlexander V. Chernikov 413c541bd36SAlexander V. Chernikov CK_SLIST_FOREACH(child_lle, &lle->lle_children, lle_child_next) { 414c541bd36SAlexander V. Chernikov if (child_lle->r_family == family) 415c541bd36SAlexander V. Chernikov return (child_lle); 416c541bd36SAlexander V. Chernikov } 417c541bd36SAlexander V. Chernikov 418c541bd36SAlexander V. Chernikov return (NULL); 419c541bd36SAlexander V. Chernikov } 420c541bd36SAlexander V. Chernikov 421c541bd36SAlexander V. Chernikov /* 422f3a3b061SAlexander V. Chernikov * Requests feedback from the datapath. 423f3a3b061SAlexander V. Chernikov * First packet using @lle should result in 424f3a3b061SAlexander V. Chernikov * setting r_skip_req back to 0 and updating 425f3a3b061SAlexander V. Chernikov * lle_hittime to the current time_uptime. 426f3a3b061SAlexander V. Chernikov */ 427f3a3b061SAlexander V. Chernikov void 428f3a3b061SAlexander V. Chernikov llentry_request_feedback(struct llentry *lle) 429f3a3b061SAlexander V. Chernikov { 430c541bd36SAlexander V. Chernikov struct llentry *child_lle; 431c541bd36SAlexander V. Chernikov 432f3a3b061SAlexander V. Chernikov LLE_REQ_LOCK(lle); 433f3a3b061SAlexander V. Chernikov lle->r_skip_req = 1; 434f3a3b061SAlexander V. Chernikov LLE_REQ_UNLOCK(lle); 435c541bd36SAlexander V. Chernikov 436c541bd36SAlexander V. Chernikov CK_SLIST_FOREACH(child_lle, &lle->lle_children, lle_child_next) { 437c541bd36SAlexander V. Chernikov LLE_REQ_LOCK(child_lle); 438c541bd36SAlexander V. Chernikov child_lle->r_skip_req = 1; 439c541bd36SAlexander V. Chernikov LLE_REQ_UNLOCK(child_lle); 440c541bd36SAlexander V. Chernikov } 441f3a3b061SAlexander V. Chernikov } 442f3a3b061SAlexander V. Chernikov 443f3a3b061SAlexander V. Chernikov /* 444f3a3b061SAlexander V. Chernikov * Updates the lle state to mark it has been used 445f3a3b061SAlexander V. Chernikov * and record the time. 446f3a3b061SAlexander V. Chernikov * Used by the llentry_provide_feedback() wrapper. 447f3a3b061SAlexander V. Chernikov */ 448f3a3b061SAlexander V. Chernikov void 449f3a3b061SAlexander V. Chernikov llentry_mark_used(struct llentry *lle) 450f3a3b061SAlexander V. Chernikov { 451f3a3b061SAlexander V. Chernikov LLE_REQ_LOCK(lle); 452f3a3b061SAlexander V. Chernikov lle->r_skip_req = 0; 453f3a3b061SAlexander V. Chernikov lle->lle_hittime = time_uptime; 454f3a3b061SAlexander V. Chernikov LLE_REQ_UNLOCK(lle); 455f3a3b061SAlexander V. Chernikov } 456f3a3b061SAlexander V. Chernikov 457f3a3b061SAlexander V. Chernikov /* 458f3a3b061SAlexander V. Chernikov * Fetches the time when lle was used. 459f3a3b061SAlexander V. Chernikov * Return 0 if the entry was not used, relevant time_uptime 460f3a3b061SAlexander V. Chernikov * otherwise. 461f3a3b061SAlexander V. Chernikov */ 462c541bd36SAlexander V. Chernikov static time_t 463c541bd36SAlexander V. Chernikov llentry_get_hittime_raw(struct llentry *lle) 464f3a3b061SAlexander V. Chernikov { 465f3a3b061SAlexander V. Chernikov time_t lle_hittime = 0; 466f3a3b061SAlexander V. Chernikov 467f3a3b061SAlexander V. Chernikov LLE_REQ_LOCK(lle); 468f3a3b061SAlexander V. Chernikov if ((lle->r_skip_req == 0) && (lle_hittime < lle->lle_hittime)) 469f3a3b061SAlexander V. Chernikov lle_hittime = lle->lle_hittime; 470f3a3b061SAlexander V. Chernikov LLE_REQ_UNLOCK(lle); 471f3a3b061SAlexander V. Chernikov 472f3a3b061SAlexander V. Chernikov return (lle_hittime); 473f3a3b061SAlexander V. Chernikov } 474f3a3b061SAlexander V. Chernikov 475c541bd36SAlexander V. Chernikov time_t 476c541bd36SAlexander V. Chernikov llentry_get_hittime(struct llentry *lle) 477c541bd36SAlexander V. Chernikov { 478c541bd36SAlexander V. Chernikov time_t lle_hittime = 0; 479c541bd36SAlexander V. Chernikov struct llentry *child_lle; 480c541bd36SAlexander V. Chernikov 481c541bd36SAlexander V. Chernikov lle_hittime = llentry_get_hittime_raw(lle); 482c541bd36SAlexander V. Chernikov 483c541bd36SAlexander V. Chernikov CK_SLIST_FOREACH(child_lle, &lle->lle_children, lle_child_next) { 484c541bd36SAlexander V. Chernikov time_t hittime = llentry_get_hittime_raw(child_lle); 485c541bd36SAlexander V. Chernikov if (hittime > lle_hittime) 486c541bd36SAlexander V. Chernikov lle_hittime = hittime; 487c541bd36SAlexander V. Chernikov } 488c541bd36SAlexander V. Chernikov 489c541bd36SAlexander V. Chernikov return (lle_hittime); 490c541bd36SAlexander V. Chernikov } 491c541bd36SAlexander V. Chernikov 492f3a3b061SAlexander V. Chernikov /* 4934fb3a820SAlexander V. Chernikov * Update link-layer header for given @lle after 4944fb3a820SAlexander V. Chernikov * interface lladdr was changed. 4954fb3a820SAlexander V. Chernikov */ 4964fb3a820SAlexander V. Chernikov static int 4974fb3a820SAlexander V. Chernikov llentry_update_ifaddr(struct lltable *llt, struct llentry *lle, void *farg) 4984fb3a820SAlexander V. Chernikov { 4994fb3a820SAlexander V. Chernikov struct ifnet *ifp; 5004fb3a820SAlexander V. Chernikov u_char linkhdr[LLE_MAX_LINKHDR]; 5014fb3a820SAlexander V. Chernikov size_t linkhdrsize; 5024fb3a820SAlexander V. Chernikov u_char *lladdr; 5034fb3a820SAlexander V. Chernikov int lladdr_off; 5044fb3a820SAlexander V. Chernikov 5054fb3a820SAlexander V. Chernikov ifp = (struct ifnet *)farg; 5064fb3a820SAlexander V. Chernikov 5074fb3a820SAlexander V. Chernikov lladdr = lle->ll_addr; 5084fb3a820SAlexander V. Chernikov 5094fb3a820SAlexander V. Chernikov LLE_WLOCK(lle); 5104fb3a820SAlexander V. Chernikov if ((lle->la_flags & LLE_VALID) == 0) { 5114fb3a820SAlexander V. Chernikov LLE_WUNLOCK(lle); 5124fb3a820SAlexander V. Chernikov return (0); 5134fb3a820SAlexander V. Chernikov } 5144fb3a820SAlexander V. Chernikov 5154fb3a820SAlexander V. Chernikov if ((lle->la_flags & LLE_IFADDR) != 0) 5164fb3a820SAlexander V. Chernikov lladdr = IF_LLADDR(ifp); 5174fb3a820SAlexander V. Chernikov 5184fb3a820SAlexander V. Chernikov linkhdrsize = sizeof(linkhdr); 5194fb3a820SAlexander V. Chernikov lltable_calc_llheader(ifp, llt->llt_af, lladdr, linkhdr, &linkhdrsize, 5204fb3a820SAlexander V. Chernikov &lladdr_off); 5214fb3a820SAlexander V. Chernikov memcpy(lle->r_linkdata, linkhdr, linkhdrsize); 5224fb3a820SAlexander V. Chernikov LLE_WUNLOCK(lle); 5234fb3a820SAlexander V. Chernikov 5244fb3a820SAlexander V. Chernikov return (0); 5254fb3a820SAlexander V. Chernikov } 5264fb3a820SAlexander V. Chernikov 5274fb3a820SAlexander V. Chernikov /* 5284fb3a820SAlexander V. Chernikov * Update all calculated headers for given @llt 5294fb3a820SAlexander V. Chernikov */ 5304fb3a820SAlexander V. Chernikov void 5314fb3a820SAlexander V. Chernikov lltable_update_ifaddr(struct lltable *llt) 5324fb3a820SAlexander V. Chernikov { 5334fb3a820SAlexander V. Chernikov 5344fb3a820SAlexander V. Chernikov if (llt->llt_ifp->if_flags & IFF_LOOPBACK) 5354fb3a820SAlexander V. Chernikov return; 5364fb3a820SAlexander V. Chernikov 5374fb3a820SAlexander V. Chernikov IF_AFDATA_WLOCK(llt->llt_ifp); 5384fb3a820SAlexander V. Chernikov lltable_foreach_lle(llt, llentry_update_ifaddr, llt->llt_ifp); 5394fb3a820SAlexander V. Chernikov IF_AFDATA_WUNLOCK(llt->llt_ifp); 5404fb3a820SAlexander V. Chernikov } 5414fb3a820SAlexander V. Chernikov 5424fb3a820SAlexander V. Chernikov /* 5435a255516SAlexander V. Chernikov * 544a4641f4eSPedro F. Giffuni * Performs generic cleanup routines and frees lle. 5455a255516SAlexander V. Chernikov * 5465a255516SAlexander V. Chernikov * Called for non-linked entries, with callouts and 5475a255516SAlexander V. Chernikov * other AF-specific cleanups performed. 5485a255516SAlexander V. Chernikov * 5495a255516SAlexander V. Chernikov * @lle must be passed WLOCK'ed 55011cdad98SAlexander V. Chernikov * 55111cdad98SAlexander V. Chernikov * Returns the number of held packets, if any, that were dropped. 55211cdad98SAlexander V. Chernikov */ 55311cdad98SAlexander V. Chernikov size_t 55411cdad98SAlexander V. Chernikov llentry_free(struct llentry *lle) 55511cdad98SAlexander V. Chernikov { 55611cdad98SAlexander V. Chernikov size_t pkts_dropped; 55711cdad98SAlexander V. Chernikov 55811cdad98SAlexander V. Chernikov LLE_WLOCK_ASSERT(lle); 55911cdad98SAlexander V. Chernikov 560d3cdb716SAlexander V. Chernikov KASSERT((lle->la_flags & LLE_LINKED) == 0, ("freeing linked lle")); 56111cdad98SAlexander V. Chernikov 56211cdad98SAlexander V. Chernikov pkts_dropped = lltable_drop_entry_queue(lle); 56311cdad98SAlexander V. Chernikov 564acf673edSAndrey V. Elsukov /* cancel timer */ 565acf673edSAndrey V. Elsukov if (callout_stop(&lle->lle_timer) > 0) 566acf673edSAndrey V. Elsukov LLE_REMREF(lle); 56782f39c91SKip Macy LLE_FREE_LOCKED(lle); 568e162ea60SGeorge V. Neville-Neil 569e162ea60SGeorge V. Neville-Neil return (pkts_dropped); 57082f39c91SKip Macy } 57182f39c91SKip Macy 572adfc35ffSKip Macy /* 57382f39c91SKip Macy * Free all entries from given table and free itself. 57482f39c91SKip Macy */ 57511cdad98SAlexander V. Chernikov 57611cdad98SAlexander V. Chernikov static int 57711cdad98SAlexander V. Chernikov lltable_free_cb(struct lltable *llt, struct llentry *lle, void *farg) 57811cdad98SAlexander V. Chernikov { 57911cdad98SAlexander V. Chernikov struct llentries *dchain; 58011cdad98SAlexander V. Chernikov 58111cdad98SAlexander V. Chernikov dchain = (struct llentries *)farg; 58211cdad98SAlexander V. Chernikov 58311cdad98SAlexander V. Chernikov LLE_WLOCK(lle); 5840f8d79d9SMatt Macy CK_LIST_INSERT_HEAD(dchain, lle, lle_chain); 58511cdad98SAlexander V. Chernikov 58611cdad98SAlexander V. Chernikov return (0); 58711cdad98SAlexander V. Chernikov } 58811cdad98SAlexander V. Chernikov 58911cdad98SAlexander V. Chernikov /* 59011cdad98SAlexander V. Chernikov * Free all entries from given table and free itself. 59111cdad98SAlexander V. Chernikov */ 59282f39c91SKip Macy void 59382f39c91SKip Macy lltable_free(struct lltable *llt) 59482f39c91SKip Macy { 59582f39c91SKip Macy struct llentry *lle, *next; 59611cdad98SAlexander V. Chernikov struct llentries dchain; 59782f39c91SKip Macy 59882f39c91SKip Macy KASSERT(llt != NULL, ("%s: llt is NULL", __func__)); 59982f39c91SKip Macy 600721cd2e0SAlexander V. Chernikov lltable_unlink(llt); 60182f39c91SKip Macy 6024f6c66ccSMatt Macy CK_LIST_INIT(&dchain); 603ea537929SGleb Smirnoff IF_AFDATA_WLOCK(llt->llt_ifp); 60411cdad98SAlexander V. Chernikov /* Push all lles to @dchain */ 60511cdad98SAlexander V. Chernikov lltable_foreach_lle(llt, lltable_free_cb, &dchain); 60611cdad98SAlexander V. Chernikov llentries_unlink(llt, &dchain); 60711cdad98SAlexander V. Chernikov IF_AFDATA_WUNLOCK(llt->llt_ifp); 60811cdad98SAlexander V. Chernikov 6090f8d79d9SMatt Macy CK_LIST_FOREACH_SAFE(lle, &dchain, lle_chain, next) { 61082f39c91SKip Macy llentry_free(lle); 61182f39c91SKip Macy } 61282f39c91SKip Macy 6133818c25aSBjoern A. Zeeb KASSERT(llt->llt_entries == 0, ("%s: lltable %p (%s) entires not 0: %d", 6143818c25aSBjoern A. Zeeb __func__, llt, llt->llt_ifp->if_xname, llt->llt_entries)); 6153818c25aSBjoern A. Zeeb 616721cd2e0SAlexander V. Chernikov llt->llt_free_tbl(llt); 61782f39c91SKip Macy } 61882f39c91SKip Macy 6193e7a2321SAlexander V. Chernikov /* 6203e7a2321SAlexander V. Chernikov * Deletes an address from given lltable. 6213e7a2321SAlexander V. Chernikov * Used for userland interaction to remove 6223e7a2321SAlexander V. Chernikov * individual entries. Skips entries added by OS. 6233e7a2321SAlexander V. Chernikov */ 6243e7a2321SAlexander V. Chernikov int 6253e7a2321SAlexander V. Chernikov lltable_delete_addr(struct lltable *llt, u_int flags, 6263e7a2321SAlexander V. Chernikov const struct sockaddr *l3addr) 6273e7a2321SAlexander V. Chernikov { 6283e7a2321SAlexander V. Chernikov struct llentry *lle; 6293e7a2321SAlexander V. Chernikov struct ifnet *ifp; 6303e7a2321SAlexander V. Chernikov 6313e7a2321SAlexander V. Chernikov ifp = llt->llt_ifp; 6323e7a2321SAlexander V. Chernikov IF_AFDATA_WLOCK(ifp); 633c541bd36SAlexander V. Chernikov lle = lla_lookup(llt, LLE_SF(l3addr->sa_family, LLE_EXCLUSIVE), l3addr); 6343e7a2321SAlexander V. Chernikov 6353e7a2321SAlexander V. Chernikov if (lle == NULL) { 6363e7a2321SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 6373e7a2321SAlexander V. Chernikov return (ENOENT); 6383e7a2321SAlexander V. Chernikov } 6393e7a2321SAlexander V. Chernikov if ((lle->la_flags & LLE_IFADDR) != 0 && (flags & LLE_IFADDR) == 0) { 6403e7a2321SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 6413e7a2321SAlexander V. Chernikov LLE_WUNLOCK(lle); 6423e7a2321SAlexander V. Chernikov return (EPERM); 6433e7a2321SAlexander V. Chernikov } 6443e7a2321SAlexander V. Chernikov 6453e7a2321SAlexander V. Chernikov lltable_unlink_entry(llt, lle); 6463e7a2321SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 6473e7a2321SAlexander V. Chernikov 6483e7a2321SAlexander V. Chernikov llt->llt_delete_entry(llt, lle); 6493e7a2321SAlexander V. Chernikov 6503e7a2321SAlexander V. Chernikov return (0); 6513e7a2321SAlexander V. Chernikov } 6523e7a2321SAlexander V. Chernikov 653c9d763bfSQing Li void 6543e7a2321SAlexander V. Chernikov lltable_prefix_free(int af, struct sockaddr *addr, struct sockaddr *mask, 6555b84dc78SQing Li u_int flags) 656c9d763bfSQing Li { 657c9d763bfSQing Li struct lltable *llt; 658c9d763bfSQing Li 659199511bcSAndrey V. Elsukov LLTABLE_LIST_RLOCK(); 660989e0411SMarko Zec SLIST_FOREACH(llt, &V_lltables, llt_link) { 661c9d763bfSQing Li if (llt->llt_af != af) 662c9d763bfSQing Li continue; 663c9d763bfSQing Li 6643e7a2321SAlexander V. Chernikov llt->llt_prefix_free(llt, addr, mask, flags); 665c9d763bfSQing Li } 666199511bcSAndrey V. Elsukov LLTABLE_LIST_RUNLOCK(); 667c9d763bfSQing Li } 668c9d763bfSQing Li 66982f39c91SKip Macy struct lltable * 67041cb42a6SAlexander V. Chernikov lltable_allocate_htbl(uint32_t hsize) 67182f39c91SKip Macy { 67282f39c91SKip Macy struct lltable *llt; 67341cb42a6SAlexander V. Chernikov int i; 67482f39c91SKip Macy 67541cb42a6SAlexander V. Chernikov llt = malloc(sizeof(struct lltable), M_LLTABLE, M_WAITOK | M_ZERO); 67641cb42a6SAlexander V. Chernikov llt->llt_hsize = hsize; 67741cb42a6SAlexander V. Chernikov llt->lle_head = malloc(sizeof(struct llentries) * hsize, 67841cb42a6SAlexander V. Chernikov M_LLTABLE, M_WAITOK | M_ZERO); 67982f39c91SKip Macy 68041cb42a6SAlexander V. Chernikov for (i = 0; i < llt->llt_hsize; i++) 6814f6c66ccSMatt Macy CK_LIST_INIT(&llt->lle_head[i]); 68282f39c91SKip Macy 68311cdad98SAlexander V. Chernikov /* Set some default callbacks */ 68411cdad98SAlexander V. Chernikov llt->llt_link_entry = htable_link_entry; 68511cdad98SAlexander V. Chernikov llt->llt_unlink_entry = htable_unlink_entry; 68611cdad98SAlexander V. Chernikov llt->llt_prefix_free = htable_prefix_free; 68711cdad98SAlexander V. Chernikov llt->llt_foreach_entry = htable_foreach_lle; 68841cb42a6SAlexander V. Chernikov llt->llt_free_tbl = htable_free_tbl; 68941cb42a6SAlexander V. Chernikov 69041cb42a6SAlexander V. Chernikov return (llt); 69141cb42a6SAlexander V. Chernikov } 69241cb42a6SAlexander V. Chernikov 69382f39c91SKip Macy /* 694721cd2e0SAlexander V. Chernikov * Links lltable to global llt list. 69582f39c91SKip Macy */ 696721cd2e0SAlexander V. Chernikov void 697721cd2e0SAlexander V. Chernikov lltable_link(struct lltable *llt) 69882f39c91SKip Macy { 69911cdad98SAlexander V. Chernikov 700199511bcSAndrey V. Elsukov LLTABLE_LIST_WLOCK(); 701989e0411SMarko Zec SLIST_INSERT_HEAD(&V_lltables, llt, llt_link); 702199511bcSAndrey V. Elsukov LLTABLE_LIST_WUNLOCK(); 703721cd2e0SAlexander V. Chernikov } 70482f39c91SKip Macy 705721cd2e0SAlexander V. Chernikov static void 706721cd2e0SAlexander V. Chernikov lltable_unlink(struct lltable *llt) 707721cd2e0SAlexander V. Chernikov { 708721cd2e0SAlexander V. Chernikov 709199511bcSAndrey V. Elsukov LLTABLE_LIST_WLOCK(); 710721cd2e0SAlexander V. Chernikov SLIST_REMOVE(&V_lltables, llt, lltable, llt_link); 711199511bcSAndrey V. Elsukov LLTABLE_LIST_WUNLOCK(); 712721cd2e0SAlexander V. Chernikov 71382f39c91SKip Macy } 71482f39c91SKip Macy 71582f39c91SKip Macy /* 716*ff3a85d3SAlexander V. Chernikov * Gets interface @ifp lltable for the specified @family 717*ff3a85d3SAlexander V. Chernikov */ 718*ff3a85d3SAlexander V. Chernikov struct lltable * 719*ff3a85d3SAlexander V. Chernikov lltable_get(struct ifnet *ifp, int family) 720*ff3a85d3SAlexander V. Chernikov { 721*ff3a85d3SAlexander V. Chernikov switch (family) { 722*ff3a85d3SAlexander V. Chernikov case AF_INET: 723*ff3a85d3SAlexander V. Chernikov return (in_lltable_get(ifp)); 724*ff3a85d3SAlexander V. Chernikov case AF_INET6: 725*ff3a85d3SAlexander V. Chernikov return (in6_lltable_get(ifp)); 726*ff3a85d3SAlexander V. Chernikov } 727*ff3a85d3SAlexander V. Chernikov 728*ff3a85d3SAlexander V. Chernikov return (NULL); 729*ff3a85d3SAlexander V. Chernikov } 730*ff3a85d3SAlexander V. Chernikov 731*ff3a85d3SAlexander V. Chernikov /* 73211cdad98SAlexander V. Chernikov * External methods used by lltable consumers 73311cdad98SAlexander V. Chernikov */ 73411cdad98SAlexander V. Chernikov 73511cdad98SAlexander V. Chernikov int 73611cdad98SAlexander V. Chernikov lltable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg) 73711cdad98SAlexander V. Chernikov { 73811cdad98SAlexander V. Chernikov 73911cdad98SAlexander V. Chernikov return (llt->llt_foreach_entry(llt, f, farg)); 74011cdad98SAlexander V. Chernikov } 74111cdad98SAlexander V. Chernikov 7425a255516SAlexander V. Chernikov struct llentry * 7435a255516SAlexander V. Chernikov lltable_alloc_entry(struct lltable *llt, u_int flags, 7445a255516SAlexander V. Chernikov const struct sockaddr *l3addr) 7455a255516SAlexander V. Chernikov { 7465a255516SAlexander V. Chernikov 7475a255516SAlexander V. Chernikov return (llt->llt_alloc_entry(llt, flags, l3addr)); 7485a255516SAlexander V. Chernikov } 7495a255516SAlexander V. Chernikov 7505a255516SAlexander V. Chernikov void 7515a255516SAlexander V. Chernikov lltable_free_entry(struct lltable *llt, struct llentry *lle) 7525a255516SAlexander V. Chernikov { 7535a255516SAlexander V. Chernikov 7545a255516SAlexander V. Chernikov llt->llt_free_entry(llt, lle); 7555a255516SAlexander V. Chernikov } 7565a255516SAlexander V. Chernikov 7573818c25aSBjoern A. Zeeb int 75811cdad98SAlexander V. Chernikov lltable_link_entry(struct lltable *llt, struct llentry *lle) 75911cdad98SAlexander V. Chernikov { 76011cdad98SAlexander V. Chernikov 7613818c25aSBjoern A. Zeeb return (llt->llt_link_entry(llt, lle)); 76211cdad98SAlexander V. Chernikov } 76311cdad98SAlexander V. Chernikov 764c541bd36SAlexander V. Chernikov void 765c541bd36SAlexander V. Chernikov lltable_link_child_entry(struct llentry *lle, struct llentry *child_lle) 766c541bd36SAlexander V. Chernikov { 767c541bd36SAlexander V. Chernikov child_lle->lle_parent = lle; 768c541bd36SAlexander V. Chernikov child_lle->lle_tbl = lle->lle_tbl; 769c541bd36SAlexander V. Chernikov child_lle->la_flags |= LLE_LINKED; 770c541bd36SAlexander V. Chernikov CK_SLIST_INSERT_HEAD(&lle->lle_children, child_lle, lle_child_next); 771c541bd36SAlexander V. Chernikov } 772c541bd36SAlexander V. Chernikov 773c541bd36SAlexander V. Chernikov void 774c541bd36SAlexander V. Chernikov lltable_unlink_child_entry(struct llentry *child_lle) 775c541bd36SAlexander V. Chernikov { 776c541bd36SAlexander V. Chernikov struct llentry *lle = child_lle->lle_parent; 777c541bd36SAlexander V. Chernikov 778c541bd36SAlexander V. Chernikov child_lle->la_flags &= ~LLE_LINKED; 779c541bd36SAlexander V. Chernikov child_lle->lle_parent = NULL; 780c541bd36SAlexander V. Chernikov CK_SLIST_REMOVE(&lle->lle_children, child_lle, llentry, lle_child_next); 781c541bd36SAlexander V. Chernikov } 782c541bd36SAlexander V. Chernikov 7833818c25aSBjoern A. Zeeb int 78411cdad98SAlexander V. Chernikov lltable_unlink_entry(struct lltable *llt, struct llentry *lle) 78511cdad98SAlexander V. Chernikov { 78611cdad98SAlexander V. Chernikov 7873818c25aSBjoern A. Zeeb return (llt->llt_unlink_entry(lle)); 78811cdad98SAlexander V. Chernikov } 78911cdad98SAlexander V. Chernikov 79011cdad98SAlexander V. Chernikov void 79111cdad98SAlexander V. Chernikov lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa) 79211cdad98SAlexander V. Chernikov { 79311cdad98SAlexander V. Chernikov struct lltable *llt; 79411cdad98SAlexander V. Chernikov 79511cdad98SAlexander V. Chernikov llt = lle->lle_tbl; 79611cdad98SAlexander V. Chernikov llt->llt_fill_sa_entry(lle, sa); 79711cdad98SAlexander V. Chernikov } 79811cdad98SAlexander V. Chernikov 79911cdad98SAlexander V. Chernikov struct ifnet * 80011cdad98SAlexander V. Chernikov lltable_get_ifp(const struct lltable *llt) 80111cdad98SAlexander V. Chernikov { 80211cdad98SAlexander V. Chernikov 80311cdad98SAlexander V. Chernikov return (llt->llt_ifp); 80411cdad98SAlexander V. Chernikov } 80511cdad98SAlexander V. Chernikov 80611cdad98SAlexander V. Chernikov int 80711cdad98SAlexander V. Chernikov lltable_get_af(const struct lltable *llt) 80811cdad98SAlexander V. Chernikov { 80911cdad98SAlexander V. Chernikov 81011cdad98SAlexander V. Chernikov return (llt->llt_af); 81111cdad98SAlexander V. Chernikov } 81211cdad98SAlexander V. Chernikov 81311cdad98SAlexander V. Chernikov /* 814b4b1367aSAlexander V. Chernikov * Called in route_output when rtm_flags contains RTF_LLDATA. 81582f39c91SKip Macy */ 81682f39c91SKip Macy int 81782f39c91SKip Macy lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info) 81882f39c91SKip Macy { 81982f39c91SKip Macy struct sockaddr_dl *dl = 82082f39c91SKip Macy (struct sockaddr_dl *)info->rti_info[RTAX_GATEWAY]; 82182f39c91SKip Macy struct sockaddr *dst = (struct sockaddr *)info->rti_info[RTAX_DST]; 82282f39c91SKip Macy struct ifnet *ifp; 82382f39c91SKip Macy struct lltable *llt; 8245a255516SAlexander V. Chernikov struct llentry *lle, *lle_tmp; 8254fb3a820SAlexander V. Chernikov uint8_t linkhdr[LLE_MAX_LINKHDR]; 8264fb3a820SAlexander V. Chernikov size_t linkhdrsize; 8274fb3a820SAlexander V. Chernikov int lladdr_off; 828b4b1367aSAlexander V. Chernikov u_int laflags = 0; 829b4b1367aSAlexander V. Chernikov int error; 83082f39c91SKip Macy 831c83dda36SAlexander V. Chernikov if (dl == NULL || dl->sdl_family != AF_LINK) 832c83dda36SAlexander V. Chernikov return (EINVAL); 8331910bfcbSGleb Smirnoff 834e5b394f2SAlexander V. Chernikov /* XXX: should be ntohs() */ 83582f39c91SKip Macy ifp = ifnet_byindex(dl->sdl_index); 83682f39c91SKip Macy if (ifp == NULL) { 83782f39c91SKip Macy log(LOG_INFO, "%s: invalid ifp (sdl_index %d)\n", 83882f39c91SKip Macy __func__, dl->sdl_index); 83982f39c91SKip Macy return EINVAL; 84082f39c91SKip Macy } 84182f39c91SKip Macy 842*ff3a85d3SAlexander V. Chernikov llt = lltable_get(ifp, dst->sa_family); 843*ff3a85d3SAlexander V. Chernikov 844c83dda36SAlexander V. Chernikov if (llt == NULL) 845c83dda36SAlexander V. Chernikov return (ESRCH); 84682f39c91SKip Macy 847b4b1367aSAlexander V. Chernikov error = 0; 84882f39c91SKip Macy 849b4b1367aSAlexander V. Chernikov switch (rtm->rtm_type) { 850b4b1367aSAlexander V. Chernikov case RTM_ADD: 851b4b1367aSAlexander V. Chernikov /* Add static LLE */ 8523b0fd911SAlexander V. Chernikov laflags = 0; 8533b0fd911SAlexander V. Chernikov if (rtm->rtm_rmx.rmx_expire == 0) 8543b0fd911SAlexander V. Chernikov laflags = LLE_STATIC; 8553b0fd911SAlexander V. Chernikov lle = lltable_alloc_entry(llt, laflags, dst); 8565a255516SAlexander V. Chernikov if (lle == NULL) 857b4b1367aSAlexander V. Chernikov return (ENOMEM); 858b4b1367aSAlexander V. Chernikov 8594fb3a820SAlexander V. Chernikov linkhdrsize = sizeof(linkhdr); 8604fb3a820SAlexander V. Chernikov if (lltable_calc_llheader(ifp, dst->sa_family, LLADDR(dl), 8614fb3a820SAlexander V. Chernikov linkhdr, &linkhdrsize, &lladdr_off) != 0) 8624fb3a820SAlexander V. Chernikov return (EINVAL); 8634fb3a820SAlexander V. Chernikov lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize, 8644fb3a820SAlexander V. Chernikov lladdr_off); 865b4b1367aSAlexander V. Chernikov if ((rtm->rtm_flags & RTF_ANNOUNCE)) 866b4b1367aSAlexander V. Chernikov lle->la_flags |= LLE_PUB; 86782f39c91SKip Macy lle->la_expire = rtm->rtm_rmx.rmx_expire; 8683b0fd911SAlexander V. Chernikov 86982f39c91SKip Macy laflags = lle->la_flags; 8705a255516SAlexander V. Chernikov 8715a255516SAlexander V. Chernikov /* Try to link new entry */ 8725a255516SAlexander V. Chernikov lle_tmp = NULL; 8735a255516SAlexander V. Chernikov IF_AFDATA_WLOCK(ifp); 8745a255516SAlexander V. Chernikov LLE_WLOCK(lle); 8755a255516SAlexander V. Chernikov lle_tmp = lla_lookup(llt, LLE_EXCLUSIVE, dst); 8765a255516SAlexander V. Chernikov if (lle_tmp != NULL) { 8775a255516SAlexander V. Chernikov /* Check if we are trying to replace immutable entry */ 8785a255516SAlexander V. Chernikov if ((lle_tmp->la_flags & LLE_IFADDR) != 0) { 879b4b1367aSAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 8805a255516SAlexander V. Chernikov LLE_WUNLOCK(lle_tmp); 8815a255516SAlexander V. Chernikov lltable_free_entry(llt, lle); 8825a255516SAlexander V. Chernikov return (EPERM); 8835a255516SAlexander V. Chernikov } 8845a255516SAlexander V. Chernikov /* Unlink existing entry from table */ 8855a255516SAlexander V. Chernikov lltable_unlink_entry(llt, lle_tmp); 8865a255516SAlexander V. Chernikov } 8875a255516SAlexander V. Chernikov lltable_link_entry(llt, lle); 8885a255516SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 8895a255516SAlexander V. Chernikov 8905a255516SAlexander V. Chernikov if (lle_tmp != NULL) { 8915a255516SAlexander V. Chernikov EVENTHANDLER_INVOKE(lle_event, lle_tmp,LLENTRY_EXPIRED); 8925a255516SAlexander V. Chernikov lltable_free_entry(llt, lle_tmp); 8935a255516SAlexander V. Chernikov } 8945a255516SAlexander V. Chernikov 8955a255516SAlexander V. Chernikov /* 8965a255516SAlexander V. Chernikov * By invoking LLE handler here we might get 8975a255516SAlexander V. Chernikov * two events on static LLE entry insertion 8985a255516SAlexander V. Chernikov * in routing socket. However, since we might have 8995a255516SAlexander V. Chernikov * other subscribers we need to generate this event. 9005a255516SAlexander V. Chernikov */ 9015a255516SAlexander V. Chernikov EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_RESOLVED); 9025a255516SAlexander V. Chernikov LLE_WUNLOCK(lle); 90382f39c91SKip Macy #ifdef INET 9047b4d716bSKip Macy /* gratuitous ARP */ 9059711a168SGleb Smirnoff if ((laflags & LLE_PUB) && dst->sa_family == AF_INET) 90682f39c91SKip Macy arprequest(ifp, 90782f39c91SKip Macy &((struct sockaddr_in *)dst)->sin_addr, 90882f39c91SKip Macy &((struct sockaddr_in *)dst)->sin_addr, 9099711a168SGleb Smirnoff (u_char *)LLADDR(dl)); 91082f39c91SKip Macy #endif 91182f39c91SKip Macy 912b4b1367aSAlexander V. Chernikov break; 913b4b1367aSAlexander V. Chernikov 914b4b1367aSAlexander V. Chernikov case RTM_DELETE: 9153e7a2321SAlexander V. Chernikov return (lltable_delete_addr(llt, 0, dst)); 916b4b1367aSAlexander V. Chernikov 917b4b1367aSAlexander V. Chernikov default: 918b4b1367aSAlexander V. Chernikov error = EINVAL; 919b4b1367aSAlexander V. Chernikov } 92082f39c91SKip Macy 92182f39c91SKip Macy return (error); 92282f39c91SKip Macy } 923989e0411SMarko Zec 924335b943fSBjoern A. Zeeb #ifdef DDB 925335b943fSBjoern A. Zeeb struct llentry_sa { 926335b943fSBjoern A. Zeeb struct llentry base; 927335b943fSBjoern A. Zeeb struct sockaddr l3_addr; 928335b943fSBjoern A. Zeeb }; 929335b943fSBjoern A. Zeeb 930335b943fSBjoern A. Zeeb static void 931335b943fSBjoern A. Zeeb llatbl_lle_show(struct llentry_sa *la) 932335b943fSBjoern A. Zeeb { 933335b943fSBjoern A. Zeeb struct llentry *lle; 934335b943fSBjoern A. Zeeb uint8_t octet[6]; 935335b943fSBjoern A. Zeeb 936335b943fSBjoern A. Zeeb lle = &la->base; 937335b943fSBjoern A. Zeeb db_printf("lle=%p\n", lle); 9380f8d79d9SMatt Macy db_printf(" lle_next=%p\n", lle->lle_next.cle_next); 939335b943fSBjoern A. Zeeb db_printf(" lle_lock=%p\n", &lle->lle_lock); 940335b943fSBjoern A. Zeeb db_printf(" lle_tbl=%p\n", lle->lle_tbl); 941335b943fSBjoern A. Zeeb db_printf(" lle_head=%p\n", lle->lle_head); 942335b943fSBjoern A. Zeeb db_printf(" la_hold=%p\n", lle->la_hold); 943e162ea60SGeorge V. Neville-Neil db_printf(" la_numheld=%d\n", lle->la_numheld); 944335b943fSBjoern A. Zeeb db_printf(" la_expire=%ju\n", (uintmax_t)lle->la_expire); 945335b943fSBjoern A. Zeeb db_printf(" la_flags=0x%04x\n", lle->la_flags); 946335b943fSBjoern A. Zeeb db_printf(" la_asked=%u\n", lle->la_asked); 947335b943fSBjoern A. Zeeb db_printf(" la_preempt=%u\n", lle->la_preempt); 948335b943fSBjoern A. Zeeb db_printf(" ln_state=%d\n", lle->ln_state); 949335b943fSBjoern A. Zeeb db_printf(" ln_router=%u\n", lle->ln_router); 950335b943fSBjoern A. Zeeb db_printf(" ln_ntick=%ju\n", (uintmax_t)lle->ln_ntick); 951335b943fSBjoern A. Zeeb db_printf(" lle_refcnt=%d\n", lle->lle_refcnt); 9524fb3a820SAlexander V. Chernikov bcopy(lle->ll_addr, octet, sizeof(octet)); 953335b943fSBjoern A. Zeeb db_printf(" ll_addr=%02x:%02x:%02x:%02x:%02x:%02x\n", 954335b943fSBjoern A. Zeeb octet[0], octet[1], octet[2], octet[3], octet[4], octet[5]); 9550447c136SAlexander V. Chernikov db_printf(" lle_timer=%p\n", &lle->lle_timer); 956335b943fSBjoern A. Zeeb 957335b943fSBjoern A. Zeeb switch (la->l3_addr.sa_family) { 958335b943fSBjoern A. Zeeb #ifdef INET 959335b943fSBjoern A. Zeeb case AF_INET: 960335b943fSBjoern A. Zeeb { 961335b943fSBjoern A. Zeeb struct sockaddr_in *sin; 962335b943fSBjoern A. Zeeb char l3s[INET_ADDRSTRLEN]; 963335b943fSBjoern A. Zeeb 964335b943fSBjoern A. Zeeb sin = (struct sockaddr_in *)&la->l3_addr; 965335b943fSBjoern A. Zeeb inet_ntoa_r(sin->sin_addr, l3s); 966335b943fSBjoern A. Zeeb db_printf(" l3_addr=%s\n", l3s); 967335b943fSBjoern A. Zeeb break; 968335b943fSBjoern A. Zeeb } 969335b943fSBjoern A. Zeeb #endif 970335b943fSBjoern A. Zeeb #ifdef INET6 971335b943fSBjoern A. Zeeb case AF_INET6: 972335b943fSBjoern A. Zeeb { 973335b943fSBjoern A. Zeeb struct sockaddr_in6 *sin6; 974335b943fSBjoern A. Zeeb char l3s[INET6_ADDRSTRLEN]; 975335b943fSBjoern A. Zeeb 976335b943fSBjoern A. Zeeb sin6 = (struct sockaddr_in6 *)&la->l3_addr; 977335b943fSBjoern A. Zeeb ip6_sprintf(l3s, &sin6->sin6_addr); 978335b943fSBjoern A. Zeeb db_printf(" l3_addr=%s\n", l3s); 979335b943fSBjoern A. Zeeb break; 980335b943fSBjoern A. Zeeb } 981335b943fSBjoern A. Zeeb #endif 982335b943fSBjoern A. Zeeb default: 983335b943fSBjoern A. Zeeb db_printf(" l3_addr=N/A (af=%d)\n", la->l3_addr.sa_family); 984335b943fSBjoern A. Zeeb break; 985335b943fSBjoern A. Zeeb } 986335b943fSBjoern A. Zeeb } 987335b943fSBjoern A. Zeeb 988335b943fSBjoern A. Zeeb DB_SHOW_COMMAND(llentry, db_show_llentry) 989335b943fSBjoern A. Zeeb { 990335b943fSBjoern A. Zeeb 991335b943fSBjoern A. Zeeb if (!have_addr) { 992335b943fSBjoern A. Zeeb db_printf("usage: show llentry <struct llentry *>\n"); 993335b943fSBjoern A. Zeeb return; 994335b943fSBjoern A. Zeeb } 995335b943fSBjoern A. Zeeb 996335b943fSBjoern A. Zeeb llatbl_lle_show((struct llentry_sa *)addr); 997335b943fSBjoern A. Zeeb } 998335b943fSBjoern A. Zeeb 999335b943fSBjoern A. Zeeb static void 1000335b943fSBjoern A. Zeeb llatbl_llt_show(struct lltable *llt) 1001335b943fSBjoern A. Zeeb { 1002335b943fSBjoern A. Zeeb int i; 1003335b943fSBjoern A. Zeeb struct llentry *lle; 1004335b943fSBjoern A. Zeeb 1005335b943fSBjoern A. Zeeb db_printf("llt=%p llt_af=%d llt_ifp=%p\n", 1006335b943fSBjoern A. Zeeb llt, llt->llt_af, llt->llt_ifp); 1007335b943fSBjoern A. Zeeb 10083a749863SAlexander V. Chernikov for (i = 0; i < llt->llt_hsize; i++) { 10094f6c66ccSMatt Macy CK_LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { 1010335b943fSBjoern A. Zeeb llatbl_lle_show((struct llentry_sa *)lle); 1011335b943fSBjoern A. Zeeb if (db_pager_quit) 1012335b943fSBjoern A. Zeeb return; 1013335b943fSBjoern A. Zeeb } 1014335b943fSBjoern A. Zeeb } 1015335b943fSBjoern A. Zeeb } 1016335b943fSBjoern A. Zeeb 1017335b943fSBjoern A. Zeeb DB_SHOW_COMMAND(lltable, db_show_lltable) 1018335b943fSBjoern A. Zeeb { 1019335b943fSBjoern A. Zeeb 1020335b943fSBjoern A. Zeeb if (!have_addr) { 1021335b943fSBjoern A. Zeeb db_printf("usage: show lltable <struct lltable *>\n"); 1022335b943fSBjoern A. Zeeb return; 1023335b943fSBjoern A. Zeeb } 1024335b943fSBjoern A. Zeeb 1025335b943fSBjoern A. Zeeb llatbl_llt_show((struct lltable *)addr); 1026335b943fSBjoern A. Zeeb } 1027335b943fSBjoern A. Zeeb 1028335b943fSBjoern A. Zeeb DB_SHOW_ALL_COMMAND(lltables, db_show_all_lltables) 1029335b943fSBjoern A. Zeeb { 1030335b943fSBjoern A. Zeeb VNET_ITERATOR_DECL(vnet_iter); 1031335b943fSBjoern A. Zeeb struct lltable *llt; 1032335b943fSBjoern A. Zeeb 1033335b943fSBjoern A. Zeeb VNET_FOREACH(vnet_iter) { 1034335b943fSBjoern A. Zeeb CURVNET_SET_QUIET(vnet_iter); 1035335b943fSBjoern A. Zeeb #ifdef VIMAGE 1036335b943fSBjoern A. Zeeb db_printf("vnet=%p\n", curvnet); 1037335b943fSBjoern A. Zeeb #endif 1038335b943fSBjoern A. Zeeb SLIST_FOREACH(llt, &V_lltables, llt_link) { 1039335b943fSBjoern A. Zeeb db_printf("llt=%p llt_af=%d llt_ifp=%p(%s)\n", 1040335b943fSBjoern A. Zeeb llt, llt->llt_af, llt->llt_ifp, 1041335b943fSBjoern A. Zeeb (llt->llt_ifp != NULL) ? 1042335b943fSBjoern A. Zeeb llt->llt_ifp->if_xname : "?"); 1043335b943fSBjoern A. Zeeb if (have_addr && addr != 0) /* verbose */ 1044335b943fSBjoern A. Zeeb llatbl_llt_show(llt); 1045335b943fSBjoern A. Zeeb if (db_pager_quit) { 1046335b943fSBjoern A. Zeeb CURVNET_RESTORE(); 1047335b943fSBjoern A. Zeeb return; 1048335b943fSBjoern A. Zeeb } 1049335b943fSBjoern A. Zeeb } 1050335b943fSBjoern A. Zeeb CURVNET_RESTORE(); 1051335b943fSBjoern A. Zeeb } 1052335b943fSBjoern A. Zeeb } 1053335b943fSBjoern A. Zeeb #endif 1054