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> 60*2c2b37adSJustin Hibbits #include <net/if_private.h> 6182f39c91SKip Macy #include <net/route.h> 62da187ddbSAlexander V. Chernikov #include <net/route/route_ctl.h> 6363f7f392SAlexander V. Chernikov #include <net/route/route_debug.h> 64530c0060SRobert Watson #include <net/vnet.h> 6582f39c91SKip Macy #include <netinet/if_ether.h> 6682f39c91SKip Macy #include <netinet6/in6_var.h> 6782f39c91SKip Macy #include <netinet6/nd6.h> 6882f39c91SKip Macy 6982f39c91SKip Macy MALLOC_DEFINE(M_LLTABLE, "lltable", "link level address tables"); 7082f39c91SKip Macy 715f901c92SAndrew Turner VNET_DEFINE_STATIC(SLIST_HEAD(, lltable), lltables) = 7276d68eccSBjoern A. Zeeb SLIST_HEAD_INITIALIZER(lltables); 73989e0411SMarko Zec #define V_lltables VNET(lltables) 7482f39c91SKip Macy 75199511bcSAndrey V. Elsukov static struct rwlock lltable_list_lock; 76199511bcSAndrey V. Elsukov RW_SYSINIT(lltable_list_lock, &lltable_list_lock, "lltable_list_lock"); 77199511bcSAndrey V. Elsukov #define LLTABLE_LIST_RLOCK() rw_rlock(&lltable_list_lock) 78199511bcSAndrey V. Elsukov #define LLTABLE_LIST_RUNLOCK() rw_runlock(&lltable_list_lock) 79199511bcSAndrey V. Elsukov #define LLTABLE_LIST_WLOCK() rw_wlock(&lltable_list_lock) 80199511bcSAndrey V. Elsukov #define LLTABLE_LIST_WUNLOCK() rw_wunlock(&lltable_list_lock) 81199511bcSAndrey V. Elsukov #define LLTABLE_LIST_LOCK_ASSERT() rw_assert(&lltable_list_lock, RA_LOCKED) 82dc56e98fSRobert Watson 83721cd2e0SAlexander V. Chernikov static void lltable_unlink(struct lltable *llt); 8411cdad98SAlexander V. Chernikov static void llentries_unlink(struct lltable *llt, struct llentries *head); 8511cdad98SAlexander V. Chernikov 8611cdad98SAlexander V. Chernikov /* 8711cdad98SAlexander V. Chernikov * Dump lle state for a specific address family. 8811cdad98SAlexander V. Chernikov */ 8911cdad98SAlexander V. Chernikov static int 9011cdad98SAlexander V. Chernikov lltable_dump_af(struct lltable *llt, struct sysctl_req *wr) 9111cdad98SAlexander V. Chernikov { 92a68cc388SGleb Smirnoff struct epoch_tracker et; 9311cdad98SAlexander V. Chernikov int error; 9411cdad98SAlexander V. Chernikov 95199511bcSAndrey V. Elsukov LLTABLE_LIST_LOCK_ASSERT(); 9611cdad98SAlexander V. Chernikov 9711cdad98SAlexander V. Chernikov if (llt->llt_ifp->if_flags & IFF_LOOPBACK) 9811cdad98SAlexander V. Chernikov return (0); 9911cdad98SAlexander V. Chernikov error = 0; 10011cdad98SAlexander V. Chernikov 101a68cc388SGleb Smirnoff NET_EPOCH_ENTER(et); 10211cdad98SAlexander V. Chernikov error = lltable_foreach_lle(llt, 10311cdad98SAlexander V. Chernikov (llt_foreach_cb_t *)llt->llt_dump_entry, wr); 104a68cc388SGleb Smirnoff NET_EPOCH_EXIT(et); 10511cdad98SAlexander V. Chernikov 10611cdad98SAlexander V. Chernikov return (error); 10711cdad98SAlexander V. Chernikov } 10811cdad98SAlexander V. Chernikov 10982f39c91SKip Macy /* 11082f39c91SKip Macy * Dump arp state for a specific address family. 11182f39c91SKip Macy */ 11282f39c91SKip Macy int 11382f39c91SKip Macy lltable_sysctl_dumparp(int af, struct sysctl_req *wr) 11482f39c91SKip Macy { 11582f39c91SKip Macy struct lltable *llt; 11682f39c91SKip Macy int error = 0; 11782f39c91SKip Macy 118199511bcSAndrey V. Elsukov LLTABLE_LIST_RLOCK(); 119989e0411SMarko Zec SLIST_FOREACH(llt, &V_lltables, llt_link) { 12082f39c91SKip Macy if (llt->llt_af == af) { 12111cdad98SAlexander V. Chernikov error = lltable_dump_af(llt, wr); 12282f39c91SKip Macy if (error != 0) 12382f39c91SKip Macy goto done; 12482f39c91SKip Macy } 12582f39c91SKip Macy } 12682f39c91SKip Macy done: 127199511bcSAndrey V. Elsukov LLTABLE_LIST_RUNLOCK(); 12882f39c91SKip Macy return (error); 12982f39c91SKip Macy } 13082f39c91SKip Macy 13182f39c91SKip Macy /* 132d18b4becSArseny Smalyuk * Adds a mbuf to hold queue. Drops old packets if the queue is full. 133d18b4becSArseny Smalyuk * 134d18b4becSArseny Smalyuk * Returns the number of held packets that were dropped. 135d18b4becSArseny Smalyuk */ 136d18b4becSArseny Smalyuk size_t 137d18b4becSArseny Smalyuk lltable_append_entry_queue(struct llentry *lle, struct mbuf *m, 138d18b4becSArseny Smalyuk size_t maxheld) 139d18b4becSArseny Smalyuk { 140d18b4becSArseny Smalyuk size_t pkts_dropped = 0; 141d18b4becSArseny Smalyuk 142d18b4becSArseny Smalyuk LLE_WLOCK_ASSERT(lle); 143d18b4becSArseny Smalyuk 144d18b4becSArseny Smalyuk while (lle->la_numheld >= maxheld && lle->la_hold != NULL) { 145d18b4becSArseny Smalyuk struct mbuf *next = lle->la_hold->m_nextpkt; 146d18b4becSArseny Smalyuk m_freem(lle->la_hold); 147d18b4becSArseny Smalyuk lle->la_hold = next; 148d18b4becSArseny Smalyuk lle->la_numheld--; 149d18b4becSArseny Smalyuk pkts_dropped++; 150d18b4becSArseny Smalyuk } 151d18b4becSArseny Smalyuk 152d18b4becSArseny Smalyuk if (lle->la_hold != NULL) { 153d18b4becSArseny Smalyuk struct mbuf *curr = lle->la_hold; 154d18b4becSArseny Smalyuk while (curr->m_nextpkt != NULL) 155d18b4becSArseny Smalyuk curr = curr->m_nextpkt; 156d18b4becSArseny Smalyuk curr->m_nextpkt = m; 157d18b4becSArseny Smalyuk } else 158d18b4becSArseny Smalyuk lle->la_hold = m; 159d18b4becSArseny Smalyuk 160d18b4becSArseny Smalyuk lle->la_numheld++; 161d18b4becSArseny Smalyuk 162d18b4becSArseny Smalyuk return pkts_dropped; 163d18b4becSArseny Smalyuk } 164d18b4becSArseny Smalyuk 165d18b4becSArseny Smalyuk 166d18b4becSArseny Smalyuk /* 16711cdad98SAlexander V. Chernikov * Common function helpers for chained hash table. 16811cdad98SAlexander V. Chernikov */ 16911cdad98SAlexander V. Chernikov 17011cdad98SAlexander V. Chernikov /* 17111cdad98SAlexander V. Chernikov * Runs specified callback for each entry in @llt. 17211cdad98SAlexander V. Chernikov * Caller does the locking. 17311cdad98SAlexander V. Chernikov * 17411cdad98SAlexander V. Chernikov */ 17511cdad98SAlexander V. Chernikov static int 17611cdad98SAlexander V. Chernikov htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg) 17711cdad98SAlexander V. Chernikov { 17811cdad98SAlexander V. Chernikov struct llentry *lle, *next; 17911cdad98SAlexander V. Chernikov int i, error; 18011cdad98SAlexander V. Chernikov 18111cdad98SAlexander V. Chernikov error = 0; 18211cdad98SAlexander V. Chernikov 18341cb42a6SAlexander V. Chernikov for (i = 0; i < llt->llt_hsize; i++) { 1844f6c66ccSMatt Macy CK_LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) { 18511cdad98SAlexander V. Chernikov error = f(llt, lle, farg); 18611cdad98SAlexander V. Chernikov if (error != 0) 18711cdad98SAlexander V. Chernikov break; 18811cdad98SAlexander V. Chernikov } 18911cdad98SAlexander V. Chernikov } 19011cdad98SAlexander V. Chernikov 19111cdad98SAlexander V. Chernikov return (error); 19211cdad98SAlexander V. Chernikov } 19311cdad98SAlexander V. Chernikov 1943818c25aSBjoern A. Zeeb /* 1953818c25aSBjoern A. Zeeb * The htable_[un]link_entry() functions return: 1963818c25aSBjoern A. Zeeb * 0 if the entry was (un)linked already and nothing changed, 1973818c25aSBjoern A. Zeeb * 1 if the entry was added/removed to/from the table, and 1983818c25aSBjoern A. Zeeb * -1 on error (e.g., not being able to add the entry due to limits reached). 1993818c25aSBjoern A. Zeeb * While the "unlink" operation should never error, callers of 2003818c25aSBjoern A. Zeeb * lltable_link_entry() need to check for errors and handle them. 2013818c25aSBjoern A. Zeeb */ 2023818c25aSBjoern A. Zeeb static int 20311cdad98SAlexander V. Chernikov htable_link_entry(struct lltable *llt, struct llentry *lle) 20411cdad98SAlexander V. Chernikov { 20511cdad98SAlexander V. Chernikov struct llentries *lleh; 20611cdad98SAlexander V. Chernikov uint32_t hashidx; 20711cdad98SAlexander V. Chernikov 20811cdad98SAlexander V. Chernikov if ((lle->la_flags & LLE_LINKED) != 0) 2093818c25aSBjoern A. Zeeb return (0); 21011cdad98SAlexander V. Chernikov 21111cdad98SAlexander V. Chernikov IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp); 21211cdad98SAlexander V. Chernikov 2133818c25aSBjoern A. Zeeb if (llt->llt_maxentries > 0 && 2143818c25aSBjoern A. Zeeb llt->llt_entries >= llt->llt_maxentries) 2153818c25aSBjoern A. Zeeb return (-1); 2163818c25aSBjoern A. Zeeb 2173a749863SAlexander V. Chernikov hashidx = llt->llt_hash(lle, llt->llt_hsize); 21811cdad98SAlexander V. Chernikov lleh = &llt->lle_head[hashidx]; 21911cdad98SAlexander V. Chernikov 22011cdad98SAlexander V. Chernikov lle->lle_tbl = llt; 22111cdad98SAlexander V. Chernikov lle->lle_head = lleh; 22211cdad98SAlexander V. Chernikov lle->la_flags |= LLE_LINKED; 2234f6c66ccSMatt Macy CK_LIST_INSERT_HEAD(lleh, lle, lle_next); 2243818c25aSBjoern A. Zeeb llt->llt_entries++; 2253818c25aSBjoern A. Zeeb 2263818c25aSBjoern A. Zeeb return (1); 22711cdad98SAlexander V. Chernikov } 22811cdad98SAlexander V. Chernikov 2293818c25aSBjoern A. Zeeb static int 23011cdad98SAlexander V. Chernikov htable_unlink_entry(struct llentry *lle) 23111cdad98SAlexander V. Chernikov { 2323818c25aSBjoern A. Zeeb struct lltable *llt; 23311cdad98SAlexander V. Chernikov 234d9a61c96SBjoern A. Zeeb if ((lle->la_flags & LLE_LINKED) == 0) 2353818c25aSBjoern A. Zeeb return (0); 236d9a61c96SBjoern A. Zeeb 2373818c25aSBjoern A. Zeeb llt = lle->lle_tbl; 2383818c25aSBjoern A. Zeeb IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp); 2393818c25aSBjoern A. Zeeb KASSERT(llt->llt_entries > 0, ("%s: lltable %p (%s) entries %d <= 0", 2403818c25aSBjoern A. Zeeb __func__, llt, if_name(llt->llt_ifp), llt->llt_entries)); 2413818c25aSBjoern A. Zeeb 2424f6c66ccSMatt Macy CK_LIST_REMOVE(lle, lle_next); 24311cdad98SAlexander V. Chernikov lle->la_flags &= ~(LLE_VALID | LLE_LINKED); 24411cdad98SAlexander V. Chernikov #if 0 24511cdad98SAlexander V. Chernikov lle->lle_tbl = NULL; 24611cdad98SAlexander V. Chernikov lle->lle_head = NULL; 24711cdad98SAlexander V. Chernikov #endif 2483818c25aSBjoern A. Zeeb llt->llt_entries--; 2493818c25aSBjoern A. Zeeb 2503818c25aSBjoern A. Zeeb return (1); 25111cdad98SAlexander V. Chernikov } 25211cdad98SAlexander V. Chernikov 25311cdad98SAlexander V. Chernikov struct prefix_match_data { 2543e7a2321SAlexander V. Chernikov const struct sockaddr *addr; 25511cdad98SAlexander V. Chernikov const struct sockaddr *mask; 25611cdad98SAlexander V. Chernikov struct llentries dchain; 25711cdad98SAlexander V. Chernikov u_int flags; 25811cdad98SAlexander V. Chernikov }; 25911cdad98SAlexander V. Chernikov 26011cdad98SAlexander V. Chernikov static int 26111cdad98SAlexander V. Chernikov htable_prefix_free_cb(struct lltable *llt, struct llentry *lle, void *farg) 26211cdad98SAlexander V. Chernikov { 26311cdad98SAlexander V. Chernikov struct prefix_match_data *pmd; 26411cdad98SAlexander V. Chernikov 26511cdad98SAlexander V. Chernikov pmd = (struct prefix_match_data *)farg; 26611cdad98SAlexander V. Chernikov 2673e7a2321SAlexander V. Chernikov if (llt->llt_match_prefix(pmd->addr, pmd->mask, pmd->flags, lle)) { 26811cdad98SAlexander V. Chernikov LLE_WLOCK(lle); 2690f8d79d9SMatt Macy CK_LIST_INSERT_HEAD(&pmd->dchain, lle, lle_chain); 27011cdad98SAlexander V. Chernikov } 27111cdad98SAlexander V. Chernikov 27211cdad98SAlexander V. Chernikov return (0); 27311cdad98SAlexander V. Chernikov } 27411cdad98SAlexander V. Chernikov 27511cdad98SAlexander V. Chernikov static void 2763e7a2321SAlexander V. Chernikov htable_prefix_free(struct lltable *llt, const struct sockaddr *addr, 27711cdad98SAlexander V. Chernikov const struct sockaddr *mask, u_int flags) 27811cdad98SAlexander V. Chernikov { 27911cdad98SAlexander V. Chernikov struct llentry *lle, *next; 28011cdad98SAlexander V. Chernikov struct prefix_match_data pmd; 28111cdad98SAlexander V. Chernikov 28211cdad98SAlexander V. Chernikov bzero(&pmd, sizeof(pmd)); 2833e7a2321SAlexander V. Chernikov pmd.addr = addr; 28411cdad98SAlexander V. Chernikov pmd.mask = mask; 28511cdad98SAlexander V. Chernikov pmd.flags = flags; 2864f6c66ccSMatt Macy CK_LIST_INIT(&pmd.dchain); 28711cdad98SAlexander V. Chernikov 28811cdad98SAlexander V. Chernikov IF_AFDATA_WLOCK(llt->llt_ifp); 28911cdad98SAlexander V. Chernikov /* Push matching lles to chain */ 29011cdad98SAlexander V. Chernikov lltable_foreach_lle(llt, htable_prefix_free_cb, &pmd); 29111cdad98SAlexander V. Chernikov 29211cdad98SAlexander V. Chernikov llentries_unlink(llt, &pmd.dchain); 29311cdad98SAlexander V. Chernikov IF_AFDATA_WUNLOCK(llt->llt_ifp); 29411cdad98SAlexander V. Chernikov 2950f8d79d9SMatt Macy CK_LIST_FOREACH_SAFE(lle, &pmd.dchain, lle_chain, next) 2965a255516SAlexander V. Chernikov lltable_free_entry(llt, lle); 29711cdad98SAlexander V. Chernikov } 29811cdad98SAlexander V. Chernikov 29911cdad98SAlexander V. Chernikov static void 30041cb42a6SAlexander V. Chernikov htable_free_tbl(struct lltable *llt) 30141cb42a6SAlexander V. Chernikov { 30241cb42a6SAlexander V. Chernikov 30341cb42a6SAlexander V. Chernikov free(llt->lle_head, M_LLTABLE); 30441cb42a6SAlexander V. Chernikov free(llt, M_LLTABLE); 30541cb42a6SAlexander V. Chernikov } 30641cb42a6SAlexander V. Chernikov 307721cd2e0SAlexander V. Chernikov static void 30811cdad98SAlexander V. Chernikov llentries_unlink(struct lltable *llt, struct llentries *head) 30911cdad98SAlexander V. Chernikov { 31011cdad98SAlexander V. Chernikov struct llentry *lle, *next; 31111cdad98SAlexander V. Chernikov 3120f8d79d9SMatt Macy CK_LIST_FOREACH_SAFE(lle, head, lle_chain, next) 31311cdad98SAlexander V. Chernikov llt->llt_unlink_entry(lle); 31411cdad98SAlexander V. Chernikov } 31511cdad98SAlexander V. Chernikov 31611cdad98SAlexander V. Chernikov /* 31711cdad98SAlexander V. Chernikov * Helper function used to drop all mbufs in hold queue. 318e162ea60SGeorge V. Neville-Neil * 319e162ea60SGeorge V. Neville-Neil * Returns the number of held packets, if any, that were dropped. 32082f39c91SKip Macy */ 321e162ea60SGeorge V. Neville-Neil size_t 32211cdad98SAlexander V. Chernikov lltable_drop_entry_queue(struct llentry *lle) 32382f39c91SKip Macy { 324d18b4becSArseny Smalyuk size_t pkts_dropped = 0; 32582f39c91SKip Macy 32682f39c91SKip Macy LLE_WLOCK_ASSERT(lle); 32782f39c91SKip Macy 328d18b4becSArseny Smalyuk while (lle->la_hold != NULL) { 329d18b4becSArseny Smalyuk struct mbuf *next = lle->la_hold->m_nextpkt; 33082f39c91SKip Macy m_freem(lle->la_hold); 331e162ea60SGeorge V. Neville-Neil lle->la_hold = next; 332e162ea60SGeorge V. Neville-Neil lle->la_numheld--; 333e162ea60SGeorge V. Neville-Neil pkts_dropped++; 334e162ea60SGeorge V. Neville-Neil } 335e162ea60SGeorge V. Neville-Neil 336e162ea60SGeorge V. Neville-Neil KASSERT(lle->la_numheld == 0, 3374f493559SGordon Bergling ("%s: la_numheld %d > 0, pkts_dropped %zd", __func__, 338e162ea60SGeorge V. Neville-Neil lle->la_numheld, pkts_dropped)); 33982f39c91SKip Macy 34011cdad98SAlexander V. Chernikov return (pkts_dropped); 34111cdad98SAlexander V. Chernikov } 34211cdad98SAlexander V. Chernikov 343ddd208f7SAlexander V. Chernikov void 344ddd208f7SAlexander V. Chernikov lltable_set_entry_addr(struct ifnet *ifp, struct llentry *lle, 3454fb3a820SAlexander V. Chernikov const char *linkhdr, size_t linkhdrsize, int lladdr_off) 346ddd208f7SAlexander V. Chernikov { 347ddd208f7SAlexander V. Chernikov 3484fb3a820SAlexander V. Chernikov memcpy(lle->r_linkdata, linkhdr, linkhdrsize); 3494fb3a820SAlexander V. Chernikov lle->r_hdrlen = linkhdrsize; 3504fb3a820SAlexander V. Chernikov lle->ll_addr = &lle->r_linkdata[lladdr_off]; 351ddd208f7SAlexander V. Chernikov lle->la_flags |= LLE_VALID; 352f8aee88fSAlexander V. Chernikov lle->r_flags |= RLLE_VALID; 353ddd208f7SAlexander V. Chernikov } 354ddd208f7SAlexander V. Chernikov 35511cdad98SAlexander V. Chernikov /* 3560b79b007SAlexander V. Chernikov * Acquires lltable write lock. 3570b79b007SAlexander V. Chernikov * 3580b79b007SAlexander V. Chernikov * Returns true on success, with both lltable and lle lock held. 3590b79b007SAlexander V. Chernikov * On failure, false is returned and lle wlock is still held. 3600b79b007SAlexander V. Chernikov */ 3610b79b007SAlexander V. Chernikov bool 3620b79b007SAlexander V. Chernikov lltable_acquire_wlock(struct ifnet *ifp, struct llentry *lle) 3630b79b007SAlexander V. Chernikov { 3640b79b007SAlexander V. Chernikov NET_EPOCH_ASSERT(); 3650b79b007SAlexander V. Chernikov 3660b79b007SAlexander V. Chernikov /* Perform real LLE update */ 3670b79b007SAlexander V. Chernikov /* use afdata WLOCK to update fields */ 3680b79b007SAlexander V. Chernikov LLE_WUNLOCK(lle); 3690b79b007SAlexander V. Chernikov IF_AFDATA_WLOCK(ifp); 3700b79b007SAlexander V. Chernikov LLE_WLOCK(lle); 3710b79b007SAlexander V. Chernikov 3720b79b007SAlexander V. Chernikov /* 3730b79b007SAlexander V. Chernikov * Since we droppped LLE lock, other thread might have deleted 3740b79b007SAlexander V. Chernikov * this lle. Check and return 3750b79b007SAlexander V. Chernikov */ 3760b79b007SAlexander V. Chernikov if ((lle->la_flags & LLE_DELETED) != 0) { 3770b79b007SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 3780b79b007SAlexander V. Chernikov return (false); 3790b79b007SAlexander V. Chernikov } 3800b79b007SAlexander V. Chernikov 3810b79b007SAlexander V. Chernikov return (true); 3820b79b007SAlexander V. Chernikov } 3830b79b007SAlexander V. Chernikov 3840b79b007SAlexander V. Chernikov /* 38512cb7521SAlexander V. Chernikov * Tries to update @lle link-level address. 38612cb7521SAlexander V. Chernikov * Since update requires AFDATA WLOCK, function 38712cb7521SAlexander V. Chernikov * drops @lle lock, acquires AFDATA lock and then acquires 38812cb7521SAlexander V. Chernikov * @lle lock to maintain lock order. 38912cb7521SAlexander V. Chernikov * 39012cb7521SAlexander V. Chernikov * Returns 1 on success. 39112cb7521SAlexander V. Chernikov */ 39212cb7521SAlexander V. Chernikov int 39312cb7521SAlexander V. Chernikov lltable_try_set_entry_addr(struct ifnet *ifp, struct llentry *lle, 3944fb3a820SAlexander V. Chernikov const char *linkhdr, size_t linkhdrsize, int lladdr_off) 39512cb7521SAlexander V. Chernikov { 39612cb7521SAlexander V. Chernikov 3970b79b007SAlexander V. Chernikov if (!lltable_acquire_wlock(ifp, lle)) 39812cb7521SAlexander V. Chernikov return (0); 39912cb7521SAlexander V. Chernikov 40012cb7521SAlexander V. Chernikov /* Update data */ 4014fb3a820SAlexander V. Chernikov lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize, lladdr_off); 40212cb7521SAlexander V. Chernikov 40312cb7521SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 40412cb7521SAlexander V. Chernikov 40512cb7521SAlexander V. Chernikov return (1); 40612cb7521SAlexander V. Chernikov } 40712cb7521SAlexander V. Chernikov 40812cb7521SAlexander V. Chernikov /* 4094fb3a820SAlexander V. Chernikov * Helper function used to pre-compute full/partial link-layer 4104fb3a820SAlexander V. Chernikov * header data suitable for feeding into if_output(). 4114fb3a820SAlexander V. Chernikov */ 4124fb3a820SAlexander V. Chernikov int 4134fb3a820SAlexander V. Chernikov lltable_calc_llheader(struct ifnet *ifp, int family, char *lladdr, 4144fb3a820SAlexander V. Chernikov char *buf, size_t *bufsize, int *lladdr_off) 4154fb3a820SAlexander V. Chernikov { 4164fb3a820SAlexander V. Chernikov struct if_encap_req ereq; 4174fb3a820SAlexander V. Chernikov int error; 4184fb3a820SAlexander V. Chernikov 4194fb3a820SAlexander V. Chernikov bzero(buf, *bufsize); 4204fb3a820SAlexander V. Chernikov bzero(&ereq, sizeof(ereq)); 4214fb3a820SAlexander V. Chernikov ereq.buf = buf; 4224fb3a820SAlexander V. Chernikov ereq.bufsize = *bufsize; 4234fb3a820SAlexander V. Chernikov ereq.rtype = IFENCAP_LL; 4244fb3a820SAlexander V. Chernikov ereq.family = family; 4254fb3a820SAlexander V. Chernikov ereq.lladdr = lladdr; 4264fb3a820SAlexander V. Chernikov ereq.lladdr_len = ifp->if_addrlen; 4274fb3a820SAlexander V. Chernikov error = ifp->if_requestencap(ifp, &ereq); 4284fb3a820SAlexander V. Chernikov if (error == 0) { 4294fb3a820SAlexander V. Chernikov *bufsize = ereq.bufsize; 4304fb3a820SAlexander V. Chernikov *lladdr_off = ereq.lladdr_off; 4314fb3a820SAlexander V. Chernikov } 4324fb3a820SAlexander V. Chernikov 4334fb3a820SAlexander V. Chernikov return (error); 4344fb3a820SAlexander V. Chernikov } 4354fb3a820SAlexander V. Chernikov 4364fb3a820SAlexander V. Chernikov /* 437c541bd36SAlexander V. Chernikov * Searches for the child entry matching @family inside @lle. 438c541bd36SAlexander V. Chernikov * Returns the entry or NULL. 439c541bd36SAlexander V. Chernikov */ 440c541bd36SAlexander V. Chernikov struct llentry * 441c541bd36SAlexander V. Chernikov llentry_lookup_family(struct llentry *lle, int family) 442c541bd36SAlexander V. Chernikov { 443c541bd36SAlexander V. Chernikov struct llentry *child_lle; 444c541bd36SAlexander V. Chernikov 445c541bd36SAlexander V. Chernikov if (lle == NULL) 446c541bd36SAlexander V. Chernikov return (NULL); 447c541bd36SAlexander V. Chernikov 448c541bd36SAlexander V. Chernikov CK_SLIST_FOREACH(child_lle, &lle->lle_children, lle_child_next) { 449c541bd36SAlexander V. Chernikov if (child_lle->r_family == family) 450c541bd36SAlexander V. Chernikov return (child_lle); 451c541bd36SAlexander V. Chernikov } 452c541bd36SAlexander V. Chernikov 453c541bd36SAlexander V. Chernikov return (NULL); 454c541bd36SAlexander V. Chernikov } 455c541bd36SAlexander V. Chernikov 456c541bd36SAlexander V. Chernikov /* 45763f7f392SAlexander V. Chernikov * Retrieves upper protocol family for the llentry. 45863f7f392SAlexander V. Chernikov * By default, all "normal" (e.g. upper_family == transport_family) 45963f7f392SAlexander V. Chernikov * llentries have r_family set to 0. 46063f7f392SAlexander V. Chernikov * Thus, use @default_family in that regard, otherwise use r_family. 46163f7f392SAlexander V. Chernikov * 46263f7f392SAlexander V. Chernikov * Returns upper protocol family 46363f7f392SAlexander V. Chernikov */ 46463f7f392SAlexander V. Chernikov int 46563f7f392SAlexander V. Chernikov llentry_get_upper_family(const struct llentry *lle, int default_family) 46663f7f392SAlexander V. Chernikov { 46763f7f392SAlexander V. Chernikov return (lle->r_family == 0 ? default_family : lle->r_family); 46863f7f392SAlexander V. Chernikov } 46963f7f392SAlexander V. Chernikov 47063f7f392SAlexander V. Chernikov /* 47163f7f392SAlexander V. Chernikov * Prints llentry @lle data into provided buffer. 47263f7f392SAlexander V. Chernikov * Example: lle/inet/valid/em0/1.2.3.4 47363f7f392SAlexander V. Chernikov * 47463f7f392SAlexander V. Chernikov * Returns @buf. 47563f7f392SAlexander V. Chernikov */ 47663f7f392SAlexander V. Chernikov char * 47763f7f392SAlexander V. Chernikov llentry_print_buf(const struct llentry *lle, struct ifnet *ifp, int family, 47863f7f392SAlexander V. Chernikov char *buf, size_t bufsize) 47963f7f392SAlexander V. Chernikov { 480a6668e31SEd Maste #if defined(INET) || defined(INET6) 48163f7f392SAlexander V. Chernikov char abuf[INET6_ADDRSTRLEN]; 482a6668e31SEd Maste #endif 48363f7f392SAlexander V. Chernikov 48463f7f392SAlexander V. Chernikov const char *valid = (lle->r_flags & RLLE_VALID) ? "valid" : "no_l2"; 48563f7f392SAlexander V. Chernikov const char *upper_str = rib_print_family(llentry_get_upper_family(lle, family)); 48663f7f392SAlexander V. Chernikov 48763f7f392SAlexander V. Chernikov switch (family) { 48863f7f392SAlexander V. Chernikov #ifdef INET 48963f7f392SAlexander V. Chernikov case AF_INET: 49063f7f392SAlexander V. Chernikov inet_ntop(AF_INET, &lle->r_l3addr.addr4, abuf, sizeof(abuf)); 49163f7f392SAlexander V. Chernikov snprintf(buf, bufsize, "lle/%s/%s/%s/%s", upper_str, 49263f7f392SAlexander V. Chernikov valid, if_name(ifp), abuf); 49363f7f392SAlexander V. Chernikov break; 49463f7f392SAlexander V. Chernikov #endif 49563f7f392SAlexander V. Chernikov #ifdef INET6 49663f7f392SAlexander V. Chernikov case AF_INET6: 49763f7f392SAlexander V. Chernikov inet_ntop(AF_INET6, &lle->r_l3addr.addr6, abuf, sizeof(abuf)); 49863f7f392SAlexander V. Chernikov snprintf(buf, bufsize, "lle/%s/%s/%s/%s", upper_str, 49963f7f392SAlexander V. Chernikov valid, if_name(ifp), abuf); 50063f7f392SAlexander V. Chernikov break; 50163f7f392SAlexander V. Chernikov #endif 50263f7f392SAlexander V. Chernikov default: 50363f7f392SAlexander V. Chernikov snprintf(buf, bufsize, "lle/%s/%s/%s/????", upper_str, 50463f7f392SAlexander V. Chernikov valid, if_name(ifp)); 50563f7f392SAlexander V. Chernikov break; 50663f7f392SAlexander V. Chernikov } 50763f7f392SAlexander V. Chernikov 50863f7f392SAlexander V. Chernikov return (buf); 50963f7f392SAlexander V. Chernikov } 51063f7f392SAlexander V. Chernikov 51163f7f392SAlexander V. Chernikov char * 51263f7f392SAlexander V. Chernikov llentry_print_buf_lltable(const struct llentry *lle, char *buf, size_t bufsize) 51363f7f392SAlexander V. Chernikov { 51463f7f392SAlexander V. Chernikov struct lltable *tbl = lle->lle_tbl; 51563f7f392SAlexander V. Chernikov 51663f7f392SAlexander V. Chernikov return (llentry_print_buf(lle, lltable_get_ifp(tbl), lltable_get_af(tbl), buf, bufsize)); 51763f7f392SAlexander V. Chernikov } 51863f7f392SAlexander V. Chernikov 51963f7f392SAlexander V. Chernikov /* 520f3a3b061SAlexander V. Chernikov * Requests feedback from the datapath. 521f3a3b061SAlexander V. Chernikov * First packet using @lle should result in 522f3a3b061SAlexander V. Chernikov * setting r_skip_req back to 0 and updating 523f3a3b061SAlexander V. Chernikov * lle_hittime to the current time_uptime. 524f3a3b061SAlexander V. Chernikov */ 525f3a3b061SAlexander V. Chernikov void 526f3a3b061SAlexander V. Chernikov llentry_request_feedback(struct llentry *lle) 527f3a3b061SAlexander V. Chernikov { 528c541bd36SAlexander V. Chernikov struct llentry *child_lle; 529c541bd36SAlexander V. Chernikov 530f3a3b061SAlexander V. Chernikov LLE_REQ_LOCK(lle); 531f3a3b061SAlexander V. Chernikov lle->r_skip_req = 1; 532f3a3b061SAlexander V. Chernikov LLE_REQ_UNLOCK(lle); 533c541bd36SAlexander V. Chernikov 534c541bd36SAlexander V. Chernikov CK_SLIST_FOREACH(child_lle, &lle->lle_children, lle_child_next) { 535c541bd36SAlexander V. Chernikov LLE_REQ_LOCK(child_lle); 536c541bd36SAlexander V. Chernikov child_lle->r_skip_req = 1; 537c541bd36SAlexander V. Chernikov LLE_REQ_UNLOCK(child_lle); 538c541bd36SAlexander V. Chernikov } 539f3a3b061SAlexander V. Chernikov } 540f3a3b061SAlexander V. Chernikov 541f3a3b061SAlexander V. Chernikov /* 542f3a3b061SAlexander V. Chernikov * Updates the lle state to mark it has been used 543f3a3b061SAlexander V. Chernikov * and record the time. 544f3a3b061SAlexander V. Chernikov * Used by the llentry_provide_feedback() wrapper. 545f3a3b061SAlexander V. Chernikov */ 546f3a3b061SAlexander V. Chernikov void 547f3a3b061SAlexander V. Chernikov llentry_mark_used(struct llentry *lle) 548f3a3b061SAlexander V. Chernikov { 549f3a3b061SAlexander V. Chernikov LLE_REQ_LOCK(lle); 550f3a3b061SAlexander V. Chernikov lle->r_skip_req = 0; 551f3a3b061SAlexander V. Chernikov lle->lle_hittime = time_uptime; 552f3a3b061SAlexander V. Chernikov LLE_REQ_UNLOCK(lle); 553f3a3b061SAlexander V. Chernikov } 554f3a3b061SAlexander V. Chernikov 555f3a3b061SAlexander V. Chernikov /* 556f3a3b061SAlexander V. Chernikov * Fetches the time when lle was used. 557f3a3b061SAlexander V. Chernikov * Return 0 if the entry was not used, relevant time_uptime 558f3a3b061SAlexander V. Chernikov * otherwise. 559f3a3b061SAlexander V. Chernikov */ 560c541bd36SAlexander V. Chernikov static time_t 561c541bd36SAlexander V. Chernikov llentry_get_hittime_raw(struct llentry *lle) 562f3a3b061SAlexander V. Chernikov { 563f3a3b061SAlexander V. Chernikov time_t lle_hittime = 0; 564f3a3b061SAlexander V. Chernikov 565f3a3b061SAlexander V. Chernikov LLE_REQ_LOCK(lle); 566f3a3b061SAlexander V. Chernikov if ((lle->r_skip_req == 0) && (lle_hittime < lle->lle_hittime)) 567f3a3b061SAlexander V. Chernikov lle_hittime = lle->lle_hittime; 568f3a3b061SAlexander V. Chernikov LLE_REQ_UNLOCK(lle); 569f3a3b061SAlexander V. Chernikov 570f3a3b061SAlexander V. Chernikov return (lle_hittime); 571f3a3b061SAlexander V. Chernikov } 572f3a3b061SAlexander V. Chernikov 573c541bd36SAlexander V. Chernikov time_t 574c541bd36SAlexander V. Chernikov llentry_get_hittime(struct llentry *lle) 575c541bd36SAlexander V. Chernikov { 576c541bd36SAlexander V. Chernikov time_t lle_hittime = 0; 577c541bd36SAlexander V. Chernikov struct llentry *child_lle; 578c541bd36SAlexander V. Chernikov 579c541bd36SAlexander V. Chernikov lle_hittime = llentry_get_hittime_raw(lle); 580c541bd36SAlexander V. Chernikov 581c541bd36SAlexander V. Chernikov CK_SLIST_FOREACH(child_lle, &lle->lle_children, lle_child_next) { 582c541bd36SAlexander V. Chernikov time_t hittime = llentry_get_hittime_raw(child_lle); 583c541bd36SAlexander V. Chernikov if (hittime > lle_hittime) 584c541bd36SAlexander V. Chernikov lle_hittime = hittime; 585c541bd36SAlexander V. Chernikov } 586c541bd36SAlexander V. Chernikov 587c541bd36SAlexander V. Chernikov return (lle_hittime); 588c541bd36SAlexander V. Chernikov } 589c541bd36SAlexander V. Chernikov 590f3a3b061SAlexander V. Chernikov /* 5914fb3a820SAlexander V. Chernikov * Update link-layer header for given @lle after 5924fb3a820SAlexander V. Chernikov * interface lladdr was changed. 5934fb3a820SAlexander V. Chernikov */ 5944fb3a820SAlexander V. Chernikov static int 5954fb3a820SAlexander V. Chernikov llentry_update_ifaddr(struct lltable *llt, struct llentry *lle, void *farg) 5964fb3a820SAlexander V. Chernikov { 5974fb3a820SAlexander V. Chernikov struct ifnet *ifp; 5984fb3a820SAlexander V. Chernikov u_char linkhdr[LLE_MAX_LINKHDR]; 5994fb3a820SAlexander V. Chernikov size_t linkhdrsize; 6004fb3a820SAlexander V. Chernikov u_char *lladdr; 6014fb3a820SAlexander V. Chernikov int lladdr_off; 6024fb3a820SAlexander V. Chernikov 6034fb3a820SAlexander V. Chernikov ifp = (struct ifnet *)farg; 6044fb3a820SAlexander V. Chernikov 6054fb3a820SAlexander V. Chernikov lladdr = lle->ll_addr; 6064fb3a820SAlexander V. Chernikov 6074fb3a820SAlexander V. Chernikov LLE_WLOCK(lle); 6084fb3a820SAlexander V. Chernikov if ((lle->la_flags & LLE_VALID) == 0) { 6094fb3a820SAlexander V. Chernikov LLE_WUNLOCK(lle); 6104fb3a820SAlexander V. Chernikov return (0); 6114fb3a820SAlexander V. Chernikov } 6124fb3a820SAlexander V. Chernikov 6134fb3a820SAlexander V. Chernikov if ((lle->la_flags & LLE_IFADDR) != 0) 6144fb3a820SAlexander V. Chernikov lladdr = IF_LLADDR(ifp); 6154fb3a820SAlexander V. Chernikov 6164fb3a820SAlexander V. Chernikov linkhdrsize = sizeof(linkhdr); 6174fb3a820SAlexander V. Chernikov lltable_calc_llheader(ifp, llt->llt_af, lladdr, linkhdr, &linkhdrsize, 6184fb3a820SAlexander V. Chernikov &lladdr_off); 6194fb3a820SAlexander V. Chernikov memcpy(lle->r_linkdata, linkhdr, linkhdrsize); 6204fb3a820SAlexander V. Chernikov LLE_WUNLOCK(lle); 6214fb3a820SAlexander V. Chernikov 6224fb3a820SAlexander V. Chernikov return (0); 6234fb3a820SAlexander V. Chernikov } 6244fb3a820SAlexander V. Chernikov 6254fb3a820SAlexander V. Chernikov /* 6264fb3a820SAlexander V. Chernikov * Update all calculated headers for given @llt 6274fb3a820SAlexander V. Chernikov */ 6284fb3a820SAlexander V. Chernikov void 6294fb3a820SAlexander V. Chernikov lltable_update_ifaddr(struct lltable *llt) 6304fb3a820SAlexander V. Chernikov { 6314fb3a820SAlexander V. Chernikov 6324fb3a820SAlexander V. Chernikov if (llt->llt_ifp->if_flags & IFF_LOOPBACK) 6334fb3a820SAlexander V. Chernikov return; 6344fb3a820SAlexander V. Chernikov 6354fb3a820SAlexander V. Chernikov IF_AFDATA_WLOCK(llt->llt_ifp); 6364fb3a820SAlexander V. Chernikov lltable_foreach_lle(llt, llentry_update_ifaddr, llt->llt_ifp); 6374fb3a820SAlexander V. Chernikov IF_AFDATA_WUNLOCK(llt->llt_ifp); 6384fb3a820SAlexander V. Chernikov } 6394fb3a820SAlexander V. Chernikov 6404fb3a820SAlexander V. Chernikov /* 6415a255516SAlexander V. Chernikov * 642a4641f4eSPedro F. Giffuni * Performs generic cleanup routines and frees lle. 6435a255516SAlexander V. Chernikov * 6445a255516SAlexander V. Chernikov * Called for non-linked entries, with callouts and 6455a255516SAlexander V. Chernikov * other AF-specific cleanups performed. 6465a255516SAlexander V. Chernikov * 6475a255516SAlexander V. Chernikov * @lle must be passed WLOCK'ed 64811cdad98SAlexander V. Chernikov * 64911cdad98SAlexander V. Chernikov * Returns the number of held packets, if any, that were dropped. 65011cdad98SAlexander V. Chernikov */ 65111cdad98SAlexander V. Chernikov size_t 65211cdad98SAlexander V. Chernikov llentry_free(struct llentry *lle) 65311cdad98SAlexander V. Chernikov { 65411cdad98SAlexander V. Chernikov size_t pkts_dropped; 65511cdad98SAlexander V. Chernikov 65611cdad98SAlexander V. Chernikov LLE_WLOCK_ASSERT(lle); 65711cdad98SAlexander V. Chernikov 658d3cdb716SAlexander V. Chernikov KASSERT((lle->la_flags & LLE_LINKED) == 0, ("freeing linked lle")); 65911cdad98SAlexander V. Chernikov 66011cdad98SAlexander V. Chernikov pkts_dropped = lltable_drop_entry_queue(lle); 66111cdad98SAlexander V. Chernikov 662acf673edSAndrey V. Elsukov /* cancel timer */ 663acf673edSAndrey V. Elsukov if (callout_stop(&lle->lle_timer) > 0) 664acf673edSAndrey V. Elsukov LLE_REMREF(lle); 66582f39c91SKip Macy LLE_FREE_LOCKED(lle); 666e162ea60SGeorge V. Neville-Neil 667e162ea60SGeorge V. Neville-Neil return (pkts_dropped); 66882f39c91SKip Macy } 66982f39c91SKip Macy 670adfc35ffSKip Macy /* 67182f39c91SKip Macy * Free all entries from given table and free itself. 67282f39c91SKip Macy */ 67311cdad98SAlexander V. Chernikov 67411cdad98SAlexander V. Chernikov static int 67511cdad98SAlexander V. Chernikov lltable_free_cb(struct lltable *llt, struct llentry *lle, void *farg) 67611cdad98SAlexander V. Chernikov { 67711cdad98SAlexander V. Chernikov struct llentries *dchain; 67811cdad98SAlexander V. Chernikov 67911cdad98SAlexander V. Chernikov dchain = (struct llentries *)farg; 68011cdad98SAlexander V. Chernikov 68111cdad98SAlexander V. Chernikov LLE_WLOCK(lle); 6820f8d79d9SMatt Macy CK_LIST_INSERT_HEAD(dchain, lle, lle_chain); 68311cdad98SAlexander V. Chernikov 68411cdad98SAlexander V. Chernikov return (0); 68511cdad98SAlexander V. Chernikov } 68611cdad98SAlexander V. Chernikov 68711cdad98SAlexander V. Chernikov /* 68811cdad98SAlexander V. Chernikov * Free all entries from given table and free itself. 68911cdad98SAlexander V. Chernikov */ 69082f39c91SKip Macy void 69182f39c91SKip Macy lltable_free(struct lltable *llt) 69282f39c91SKip Macy { 69382f39c91SKip Macy struct llentry *lle, *next; 69411cdad98SAlexander V. Chernikov struct llentries dchain; 69582f39c91SKip Macy 69682f39c91SKip Macy KASSERT(llt != NULL, ("%s: llt is NULL", __func__)); 69782f39c91SKip Macy 698721cd2e0SAlexander V. Chernikov lltable_unlink(llt); 69982f39c91SKip Macy 7004f6c66ccSMatt Macy CK_LIST_INIT(&dchain); 701ea537929SGleb Smirnoff IF_AFDATA_WLOCK(llt->llt_ifp); 70211cdad98SAlexander V. Chernikov /* Push all lles to @dchain */ 70311cdad98SAlexander V. Chernikov lltable_foreach_lle(llt, lltable_free_cb, &dchain); 70411cdad98SAlexander V. Chernikov llentries_unlink(llt, &dchain); 70511cdad98SAlexander V. Chernikov IF_AFDATA_WUNLOCK(llt->llt_ifp); 70611cdad98SAlexander V. Chernikov 7070f8d79d9SMatt Macy CK_LIST_FOREACH_SAFE(lle, &dchain, lle_chain, next) { 70882f39c91SKip Macy llentry_free(lle); 70982f39c91SKip Macy } 71082f39c91SKip Macy 7113818c25aSBjoern A. Zeeb KASSERT(llt->llt_entries == 0, ("%s: lltable %p (%s) entires not 0: %d", 7123818c25aSBjoern A. Zeeb __func__, llt, llt->llt_ifp->if_xname, llt->llt_entries)); 7133818c25aSBjoern A. Zeeb 714721cd2e0SAlexander V. Chernikov llt->llt_free_tbl(llt); 71582f39c91SKip Macy } 71682f39c91SKip Macy 7173e7a2321SAlexander V. Chernikov /* 7183e7a2321SAlexander V. Chernikov * Deletes an address from given lltable. 7193e7a2321SAlexander V. Chernikov * Used for userland interaction to remove 7203e7a2321SAlexander V. Chernikov * individual entries. Skips entries added by OS. 7213e7a2321SAlexander V. Chernikov */ 7223e7a2321SAlexander V. Chernikov int 7233e7a2321SAlexander V. Chernikov lltable_delete_addr(struct lltable *llt, u_int flags, 7243e7a2321SAlexander V. Chernikov const struct sockaddr *l3addr) 7253e7a2321SAlexander V. Chernikov { 7263e7a2321SAlexander V. Chernikov struct llentry *lle; 7273e7a2321SAlexander V. Chernikov struct ifnet *ifp; 7283e7a2321SAlexander V. Chernikov 7293e7a2321SAlexander V. Chernikov ifp = llt->llt_ifp; 7303e7a2321SAlexander V. Chernikov IF_AFDATA_WLOCK(ifp); 731c541bd36SAlexander V. Chernikov lle = lla_lookup(llt, LLE_SF(l3addr->sa_family, LLE_EXCLUSIVE), l3addr); 7323e7a2321SAlexander V. Chernikov 7333e7a2321SAlexander V. Chernikov if (lle == NULL) { 7343e7a2321SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 7353e7a2321SAlexander V. Chernikov return (ENOENT); 7363e7a2321SAlexander V. Chernikov } 7373e7a2321SAlexander V. Chernikov if ((lle->la_flags & LLE_IFADDR) != 0 && (flags & LLE_IFADDR) == 0) { 7383e7a2321SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 7393e7a2321SAlexander V. Chernikov LLE_WUNLOCK(lle); 7403e7a2321SAlexander V. Chernikov return (EPERM); 7413e7a2321SAlexander V. Chernikov } 7423e7a2321SAlexander V. Chernikov 7433e7a2321SAlexander V. Chernikov lltable_unlink_entry(llt, lle); 7443e7a2321SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 7453e7a2321SAlexander V. Chernikov 7463e7a2321SAlexander V. Chernikov llt->llt_delete_entry(llt, lle); 7473e7a2321SAlexander V. Chernikov 7483e7a2321SAlexander V. Chernikov return (0); 7493e7a2321SAlexander V. Chernikov } 7503e7a2321SAlexander V. Chernikov 751c9d763bfSQing Li void 7523e7a2321SAlexander V. Chernikov lltable_prefix_free(int af, struct sockaddr *addr, struct sockaddr *mask, 7535b84dc78SQing Li u_int flags) 754c9d763bfSQing Li { 755c9d763bfSQing Li struct lltable *llt; 756c9d763bfSQing Li 757199511bcSAndrey V. Elsukov LLTABLE_LIST_RLOCK(); 758989e0411SMarko Zec SLIST_FOREACH(llt, &V_lltables, llt_link) { 759c9d763bfSQing Li if (llt->llt_af != af) 760c9d763bfSQing Li continue; 761c9d763bfSQing Li 7623e7a2321SAlexander V. Chernikov llt->llt_prefix_free(llt, addr, mask, flags); 763c9d763bfSQing Li } 764199511bcSAndrey V. Elsukov LLTABLE_LIST_RUNLOCK(); 765c9d763bfSQing Li } 766c9d763bfSQing Li 767d6cd20ccSKUROSAWA Takahiro /* 768d6cd20ccSKUROSAWA Takahiro * Delete llentries that func() returns true. 769d6cd20ccSKUROSAWA Takahiro */ 770d6cd20ccSKUROSAWA Takahiro struct lle_match_data { 771d6cd20ccSKUROSAWA Takahiro struct llentries dchain; 772d6cd20ccSKUROSAWA Takahiro llt_match_cb_t *func; 773d6cd20ccSKUROSAWA Takahiro void *farg; 774d6cd20ccSKUROSAWA Takahiro }; 775d6cd20ccSKUROSAWA Takahiro 776d6cd20ccSKUROSAWA Takahiro static int 777d6cd20ccSKUROSAWA Takahiro lltable_delete_conditional_cb(struct lltable *llt, struct llentry *lle, 778d6cd20ccSKUROSAWA Takahiro void *farg) 779d6cd20ccSKUROSAWA Takahiro { 780d6cd20ccSKUROSAWA Takahiro struct lle_match_data *lmd; 781d6cd20ccSKUROSAWA Takahiro 782d6cd20ccSKUROSAWA Takahiro lmd = (struct lle_match_data *)farg; 783d6cd20ccSKUROSAWA Takahiro if (lmd->func(llt, lle, lmd->farg)) { 784d6cd20ccSKUROSAWA Takahiro LLE_WLOCK(lle); 785d6cd20ccSKUROSAWA Takahiro CK_LIST_INSERT_HEAD(&lmd->dchain, lle, lle_chain); 786d6cd20ccSKUROSAWA Takahiro } 787d6cd20ccSKUROSAWA Takahiro 788d6cd20ccSKUROSAWA Takahiro return (0); 789d6cd20ccSKUROSAWA Takahiro } 790d6cd20ccSKUROSAWA Takahiro 791d6cd20ccSKUROSAWA Takahiro void 792d6cd20ccSKUROSAWA Takahiro lltable_delete_conditional(struct lltable *llt, llt_match_cb_t *func, 793d6cd20ccSKUROSAWA Takahiro void *farg) 794d6cd20ccSKUROSAWA Takahiro { 795d6cd20ccSKUROSAWA Takahiro struct llentry *lle, *next; 796d6cd20ccSKUROSAWA Takahiro struct lle_match_data lmd; 797d6cd20ccSKUROSAWA Takahiro 798d6cd20ccSKUROSAWA Takahiro bzero(&lmd, sizeof(lmd)); 799d6cd20ccSKUROSAWA Takahiro CK_LIST_INIT(&lmd.dchain); 800d6cd20ccSKUROSAWA Takahiro lmd.func = func; 801d6cd20ccSKUROSAWA Takahiro lmd.farg = farg; 802d6cd20ccSKUROSAWA Takahiro 803d6cd20ccSKUROSAWA Takahiro IF_AFDATA_WLOCK(llt->llt_ifp); 804d6cd20ccSKUROSAWA Takahiro lltable_foreach_lle(llt, lltable_delete_conditional_cb, &lmd); 805d6cd20ccSKUROSAWA Takahiro llentries_unlink(llt, &lmd.dchain); 806d6cd20ccSKUROSAWA Takahiro IF_AFDATA_WUNLOCK(llt->llt_ifp); 807d6cd20ccSKUROSAWA Takahiro 808d6cd20ccSKUROSAWA Takahiro CK_LIST_FOREACH_SAFE(lle, &lmd.dchain, lle_chain, next) 809d6cd20ccSKUROSAWA Takahiro llt->llt_delete_entry(llt, lle); 810d6cd20ccSKUROSAWA Takahiro } 811d6cd20ccSKUROSAWA Takahiro 81282f39c91SKip Macy struct lltable * 81341cb42a6SAlexander V. Chernikov lltable_allocate_htbl(uint32_t hsize) 81482f39c91SKip Macy { 81582f39c91SKip Macy struct lltable *llt; 81641cb42a6SAlexander V. Chernikov int i; 81782f39c91SKip Macy 81841cb42a6SAlexander V. Chernikov llt = malloc(sizeof(struct lltable), M_LLTABLE, M_WAITOK | M_ZERO); 81941cb42a6SAlexander V. Chernikov llt->llt_hsize = hsize; 82041cb42a6SAlexander V. Chernikov llt->lle_head = malloc(sizeof(struct llentries) * hsize, 82141cb42a6SAlexander V. Chernikov M_LLTABLE, M_WAITOK | M_ZERO); 82282f39c91SKip Macy 82341cb42a6SAlexander V. Chernikov for (i = 0; i < llt->llt_hsize; i++) 8244f6c66ccSMatt Macy CK_LIST_INIT(&llt->lle_head[i]); 82582f39c91SKip Macy 82611cdad98SAlexander V. Chernikov /* Set some default callbacks */ 82711cdad98SAlexander V. Chernikov llt->llt_link_entry = htable_link_entry; 82811cdad98SAlexander V. Chernikov llt->llt_unlink_entry = htable_unlink_entry; 82911cdad98SAlexander V. Chernikov llt->llt_prefix_free = htable_prefix_free; 83011cdad98SAlexander V. Chernikov llt->llt_foreach_entry = htable_foreach_lle; 83141cb42a6SAlexander V. Chernikov llt->llt_free_tbl = htable_free_tbl; 83241cb42a6SAlexander V. Chernikov 83341cb42a6SAlexander V. Chernikov return (llt); 83441cb42a6SAlexander V. Chernikov } 83541cb42a6SAlexander V. Chernikov 83682f39c91SKip Macy /* 837721cd2e0SAlexander V. Chernikov * Links lltable to global llt list. 83882f39c91SKip Macy */ 839721cd2e0SAlexander V. Chernikov void 840721cd2e0SAlexander V. Chernikov lltable_link(struct lltable *llt) 84182f39c91SKip Macy { 84211cdad98SAlexander V. Chernikov 843199511bcSAndrey V. Elsukov LLTABLE_LIST_WLOCK(); 844989e0411SMarko Zec SLIST_INSERT_HEAD(&V_lltables, llt, llt_link); 845199511bcSAndrey V. Elsukov LLTABLE_LIST_WUNLOCK(); 846721cd2e0SAlexander V. Chernikov } 84782f39c91SKip Macy 848721cd2e0SAlexander V. Chernikov static void 849721cd2e0SAlexander V. Chernikov lltable_unlink(struct lltable *llt) 850721cd2e0SAlexander V. Chernikov { 851721cd2e0SAlexander V. Chernikov 852199511bcSAndrey V. Elsukov LLTABLE_LIST_WLOCK(); 853721cd2e0SAlexander V. Chernikov SLIST_REMOVE(&V_lltables, llt, lltable, llt_link); 854199511bcSAndrey V. Elsukov LLTABLE_LIST_WUNLOCK(); 855721cd2e0SAlexander V. Chernikov 85682f39c91SKip Macy } 85782f39c91SKip Macy 85882f39c91SKip Macy /* 859ff3a85d3SAlexander V. Chernikov * Gets interface @ifp lltable for the specified @family 860ff3a85d3SAlexander V. Chernikov */ 861ff3a85d3SAlexander V. Chernikov struct lltable * 862ff3a85d3SAlexander V. Chernikov lltable_get(struct ifnet *ifp, int family) 863ff3a85d3SAlexander V. Chernikov { 864ff3a85d3SAlexander V. Chernikov switch (family) { 865818952c6SEd Maste #ifdef INET 866ff3a85d3SAlexander V. Chernikov case AF_INET: 867ff3a85d3SAlexander V. Chernikov return (in_lltable_get(ifp)); 868818952c6SEd Maste #endif 869818952c6SEd Maste #ifdef INET6 870ff3a85d3SAlexander V. Chernikov case AF_INET6: 871ff3a85d3SAlexander V. Chernikov return (in6_lltable_get(ifp)); 872818952c6SEd Maste #endif 873ff3a85d3SAlexander V. Chernikov } 874ff3a85d3SAlexander V. Chernikov 875ff3a85d3SAlexander V. Chernikov return (NULL); 876ff3a85d3SAlexander V. Chernikov } 877ff3a85d3SAlexander V. Chernikov 878ff3a85d3SAlexander V. Chernikov /* 87911cdad98SAlexander V. Chernikov * External methods used by lltable consumers 88011cdad98SAlexander V. Chernikov */ 88111cdad98SAlexander V. Chernikov 88211cdad98SAlexander V. Chernikov int 88311cdad98SAlexander V. Chernikov lltable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg) 88411cdad98SAlexander V. Chernikov { 88511cdad98SAlexander V. Chernikov 88611cdad98SAlexander V. Chernikov return (llt->llt_foreach_entry(llt, f, farg)); 88711cdad98SAlexander V. Chernikov } 88811cdad98SAlexander V. Chernikov 8895a255516SAlexander V. Chernikov struct llentry * 8905a255516SAlexander V. Chernikov lltable_alloc_entry(struct lltable *llt, u_int flags, 8915a255516SAlexander V. Chernikov const struct sockaddr *l3addr) 8925a255516SAlexander V. Chernikov { 8935a255516SAlexander V. Chernikov 8945a255516SAlexander V. Chernikov return (llt->llt_alloc_entry(llt, flags, l3addr)); 8955a255516SAlexander V. Chernikov } 8965a255516SAlexander V. Chernikov 8975a255516SAlexander V. Chernikov void 8985a255516SAlexander V. Chernikov lltable_free_entry(struct lltable *llt, struct llentry *lle) 8995a255516SAlexander V. Chernikov { 9005a255516SAlexander V. Chernikov 9015a255516SAlexander V. Chernikov llt->llt_free_entry(llt, lle); 9025a255516SAlexander V. Chernikov } 9035a255516SAlexander V. Chernikov 9043818c25aSBjoern A. Zeeb int 90511cdad98SAlexander V. Chernikov lltable_link_entry(struct lltable *llt, struct llentry *lle) 90611cdad98SAlexander V. Chernikov { 90711cdad98SAlexander V. Chernikov 9083818c25aSBjoern A. Zeeb return (llt->llt_link_entry(llt, lle)); 90911cdad98SAlexander V. Chernikov } 91011cdad98SAlexander V. Chernikov 911c541bd36SAlexander V. Chernikov void 912c541bd36SAlexander V. Chernikov lltable_link_child_entry(struct llentry *lle, struct llentry *child_lle) 913c541bd36SAlexander V. Chernikov { 914c541bd36SAlexander V. Chernikov child_lle->lle_parent = lle; 915c541bd36SAlexander V. Chernikov child_lle->lle_tbl = lle->lle_tbl; 916c541bd36SAlexander V. Chernikov child_lle->la_flags |= LLE_LINKED; 917c541bd36SAlexander V. Chernikov CK_SLIST_INSERT_HEAD(&lle->lle_children, child_lle, lle_child_next); 918c541bd36SAlexander V. Chernikov } 919c541bd36SAlexander V. Chernikov 920c541bd36SAlexander V. Chernikov void 921c541bd36SAlexander V. Chernikov lltable_unlink_child_entry(struct llentry *child_lle) 922c541bd36SAlexander V. Chernikov { 923c541bd36SAlexander V. Chernikov struct llentry *lle = child_lle->lle_parent; 924c541bd36SAlexander V. Chernikov 925c541bd36SAlexander V. Chernikov child_lle->la_flags &= ~LLE_LINKED; 926c541bd36SAlexander V. Chernikov child_lle->lle_parent = NULL; 927c541bd36SAlexander V. Chernikov CK_SLIST_REMOVE(&lle->lle_children, child_lle, llentry, lle_child_next); 928c541bd36SAlexander V. Chernikov } 929c541bd36SAlexander V. Chernikov 9303818c25aSBjoern A. Zeeb int 93111cdad98SAlexander V. Chernikov lltable_unlink_entry(struct lltable *llt, struct llentry *lle) 93211cdad98SAlexander V. Chernikov { 93311cdad98SAlexander V. Chernikov 9343818c25aSBjoern A. Zeeb return (llt->llt_unlink_entry(lle)); 93511cdad98SAlexander V. Chernikov } 93611cdad98SAlexander V. Chernikov 93711cdad98SAlexander V. Chernikov void 93811cdad98SAlexander V. Chernikov lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa) 93911cdad98SAlexander V. Chernikov { 94011cdad98SAlexander V. Chernikov struct lltable *llt; 94111cdad98SAlexander V. Chernikov 94211cdad98SAlexander V. Chernikov llt = lle->lle_tbl; 94311cdad98SAlexander V. Chernikov llt->llt_fill_sa_entry(lle, sa); 94411cdad98SAlexander V. Chernikov } 94511cdad98SAlexander V. Chernikov 94611cdad98SAlexander V. Chernikov struct ifnet * 94711cdad98SAlexander V. Chernikov lltable_get_ifp(const struct lltable *llt) 94811cdad98SAlexander V. Chernikov { 94911cdad98SAlexander V. Chernikov 95011cdad98SAlexander V. Chernikov return (llt->llt_ifp); 95111cdad98SAlexander V. Chernikov } 95211cdad98SAlexander V. Chernikov 95311cdad98SAlexander V. Chernikov int 95411cdad98SAlexander V. Chernikov lltable_get_af(const struct lltable *llt) 95511cdad98SAlexander V. Chernikov { 95611cdad98SAlexander V. Chernikov 95711cdad98SAlexander V. Chernikov return (llt->llt_af); 95811cdad98SAlexander V. Chernikov } 95911cdad98SAlexander V. Chernikov 96011cdad98SAlexander V. Chernikov /* 961b4b1367aSAlexander V. Chernikov * Called in route_output when rtm_flags contains RTF_LLDATA. 96282f39c91SKip Macy */ 96382f39c91SKip Macy int 96482f39c91SKip Macy lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info) 96582f39c91SKip Macy { 96682f39c91SKip Macy struct sockaddr_dl *dl = 96782f39c91SKip Macy (struct sockaddr_dl *)info->rti_info[RTAX_GATEWAY]; 96882f39c91SKip Macy struct sockaddr *dst = (struct sockaddr *)info->rti_info[RTAX_DST]; 96982f39c91SKip Macy struct ifnet *ifp; 97082f39c91SKip Macy struct lltable *llt; 9715a255516SAlexander V. Chernikov struct llentry *lle, *lle_tmp; 9724fb3a820SAlexander V. Chernikov uint8_t linkhdr[LLE_MAX_LINKHDR]; 9734fb3a820SAlexander V. Chernikov size_t linkhdrsize; 9744fb3a820SAlexander V. Chernikov int lladdr_off; 975b4b1367aSAlexander V. Chernikov u_int laflags = 0; 976b4b1367aSAlexander V. Chernikov int error; 97782f39c91SKip Macy 978c83dda36SAlexander V. Chernikov if (dl == NULL || dl->sdl_family != AF_LINK) 979c83dda36SAlexander V. Chernikov return (EINVAL); 9801910bfcbSGleb Smirnoff 981e5b394f2SAlexander V. Chernikov /* XXX: should be ntohs() */ 98282f39c91SKip Macy ifp = ifnet_byindex(dl->sdl_index); 98382f39c91SKip Macy if (ifp == NULL) { 98482f39c91SKip Macy log(LOG_INFO, "%s: invalid ifp (sdl_index %d)\n", 98582f39c91SKip Macy __func__, dl->sdl_index); 98682f39c91SKip Macy return EINVAL; 98782f39c91SKip Macy } 98882f39c91SKip Macy 989ff3a85d3SAlexander V. Chernikov llt = lltable_get(ifp, dst->sa_family); 990ff3a85d3SAlexander V. Chernikov 991c83dda36SAlexander V. Chernikov if (llt == NULL) 992c83dda36SAlexander V. Chernikov return (ESRCH); 99382f39c91SKip Macy 994b4b1367aSAlexander V. Chernikov error = 0; 99582f39c91SKip Macy 996b4b1367aSAlexander V. Chernikov switch (rtm->rtm_type) { 997b4b1367aSAlexander V. Chernikov case RTM_ADD: 998b4b1367aSAlexander V. Chernikov /* Add static LLE */ 9993b0fd911SAlexander V. Chernikov laflags = 0; 10003b0fd911SAlexander V. Chernikov if (rtm->rtm_rmx.rmx_expire == 0) 10013b0fd911SAlexander V. Chernikov laflags = LLE_STATIC; 10023b0fd911SAlexander V. Chernikov lle = lltable_alloc_entry(llt, laflags, dst); 10035a255516SAlexander V. Chernikov if (lle == NULL) 1004b4b1367aSAlexander V. Chernikov return (ENOMEM); 1005b4b1367aSAlexander V. Chernikov 10064fb3a820SAlexander V. Chernikov linkhdrsize = sizeof(linkhdr); 10074fb3a820SAlexander V. Chernikov if (lltable_calc_llheader(ifp, dst->sa_family, LLADDR(dl), 1008990a6d18SMark Johnston linkhdr, &linkhdrsize, &lladdr_off) != 0) { 1009990a6d18SMark Johnston lltable_free_entry(llt, lle); 10104fb3a820SAlexander V. Chernikov return (EINVAL); 1011990a6d18SMark Johnston } 10124fb3a820SAlexander V. Chernikov lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize, 10134fb3a820SAlexander V. Chernikov lladdr_off); 1014b4b1367aSAlexander V. Chernikov if ((rtm->rtm_flags & RTF_ANNOUNCE)) 1015b4b1367aSAlexander V. Chernikov lle->la_flags |= LLE_PUB; 101682f39c91SKip Macy lle->la_expire = rtm->rtm_rmx.rmx_expire; 10173b0fd911SAlexander V. Chernikov 101882f39c91SKip Macy laflags = lle->la_flags; 10195a255516SAlexander V. Chernikov 10205a255516SAlexander V. Chernikov /* Try to link new entry */ 10215a255516SAlexander V. Chernikov lle_tmp = NULL; 10225a255516SAlexander V. Chernikov IF_AFDATA_WLOCK(ifp); 10235a255516SAlexander V. Chernikov LLE_WLOCK(lle); 10245a255516SAlexander V. Chernikov lle_tmp = lla_lookup(llt, LLE_EXCLUSIVE, dst); 10255a255516SAlexander V. Chernikov if (lle_tmp != NULL) { 10265a255516SAlexander V. Chernikov /* Check if we are trying to replace immutable entry */ 10275a255516SAlexander V. Chernikov if ((lle_tmp->la_flags & LLE_IFADDR) != 0) { 1028b4b1367aSAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 10295a255516SAlexander V. Chernikov LLE_WUNLOCK(lle_tmp); 10305a255516SAlexander V. Chernikov lltable_free_entry(llt, lle); 10315a255516SAlexander V. Chernikov return (EPERM); 10325a255516SAlexander V. Chernikov } 10335a255516SAlexander V. Chernikov /* Unlink existing entry from table */ 10345a255516SAlexander V. Chernikov lltable_unlink_entry(llt, lle_tmp); 10355a255516SAlexander V. Chernikov } 10365a255516SAlexander V. Chernikov lltable_link_entry(llt, lle); 1037d6cd20ccSKUROSAWA Takahiro if ((lle->la_flags & LLE_PUB) != 0 && 1038d6cd20ccSKUROSAWA Takahiro (llt->llt_flags & LLT_ADDEDPROXY) == 0) 1039d6cd20ccSKUROSAWA Takahiro llt->llt_flags |= LLT_ADDEDPROXY; 10405a255516SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 10415a255516SAlexander V. Chernikov 10425a255516SAlexander V. Chernikov if (lle_tmp != NULL) { 10435a255516SAlexander V. Chernikov EVENTHANDLER_INVOKE(lle_event, lle_tmp,LLENTRY_EXPIRED); 10445a255516SAlexander V. Chernikov lltable_free_entry(llt, lle_tmp); 10455a255516SAlexander V. Chernikov } 10465a255516SAlexander V. Chernikov 10475a255516SAlexander V. Chernikov /* 10485a255516SAlexander V. Chernikov * By invoking LLE handler here we might get 10495a255516SAlexander V. Chernikov * two events on static LLE entry insertion 10505a255516SAlexander V. Chernikov * in routing socket. However, since we might have 10515a255516SAlexander V. Chernikov * other subscribers we need to generate this event. 10525a255516SAlexander V. Chernikov */ 10535a255516SAlexander V. Chernikov EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_RESOLVED); 10545a255516SAlexander V. Chernikov LLE_WUNLOCK(lle); 105577001f9bSKUROSAWA Takahiro llt->llt_post_resolved(llt, lle); 1056b4b1367aSAlexander V. Chernikov break; 1057b4b1367aSAlexander V. Chernikov 1058b4b1367aSAlexander V. Chernikov case RTM_DELETE: 10593e7a2321SAlexander V. Chernikov return (lltable_delete_addr(llt, 0, dst)); 1060b4b1367aSAlexander V. Chernikov 1061b4b1367aSAlexander V. Chernikov default: 1062b4b1367aSAlexander V. Chernikov error = EINVAL; 1063b4b1367aSAlexander V. Chernikov } 106482f39c91SKip Macy 106582f39c91SKip Macy return (error); 106682f39c91SKip Macy } 1067989e0411SMarko Zec 1068335b943fSBjoern A. Zeeb #ifdef DDB 1069335b943fSBjoern A. Zeeb struct llentry_sa { 1070335b943fSBjoern A. Zeeb struct llentry base; 1071335b943fSBjoern A. Zeeb struct sockaddr l3_addr; 1072335b943fSBjoern A. Zeeb }; 1073335b943fSBjoern A. Zeeb 1074335b943fSBjoern A. Zeeb static void 1075335b943fSBjoern A. Zeeb llatbl_lle_show(struct llentry_sa *la) 1076335b943fSBjoern A. Zeeb { 1077335b943fSBjoern A. Zeeb struct llentry *lle; 1078335b943fSBjoern A. Zeeb uint8_t octet[6]; 1079335b943fSBjoern A. Zeeb 1080335b943fSBjoern A. Zeeb lle = &la->base; 1081335b943fSBjoern A. Zeeb db_printf("lle=%p\n", lle); 10820f8d79d9SMatt Macy db_printf(" lle_next=%p\n", lle->lle_next.cle_next); 1083335b943fSBjoern A. Zeeb db_printf(" lle_lock=%p\n", &lle->lle_lock); 1084335b943fSBjoern A. Zeeb db_printf(" lle_tbl=%p\n", lle->lle_tbl); 1085335b943fSBjoern A. Zeeb db_printf(" lle_head=%p\n", lle->lle_head); 1086335b943fSBjoern A. Zeeb db_printf(" la_hold=%p\n", lle->la_hold); 1087e162ea60SGeorge V. Neville-Neil db_printf(" la_numheld=%d\n", lle->la_numheld); 1088335b943fSBjoern A. Zeeb db_printf(" la_expire=%ju\n", (uintmax_t)lle->la_expire); 1089335b943fSBjoern A. Zeeb db_printf(" la_flags=0x%04x\n", lle->la_flags); 1090335b943fSBjoern A. Zeeb db_printf(" la_asked=%u\n", lle->la_asked); 1091335b943fSBjoern A. Zeeb db_printf(" la_preempt=%u\n", lle->la_preempt); 1092335b943fSBjoern A. Zeeb db_printf(" ln_state=%d\n", lle->ln_state); 1093335b943fSBjoern A. Zeeb db_printf(" ln_router=%u\n", lle->ln_router); 1094335b943fSBjoern A. Zeeb db_printf(" ln_ntick=%ju\n", (uintmax_t)lle->ln_ntick); 1095335b943fSBjoern A. Zeeb db_printf(" lle_refcnt=%d\n", lle->lle_refcnt); 10964fb3a820SAlexander V. Chernikov bcopy(lle->ll_addr, octet, sizeof(octet)); 1097335b943fSBjoern A. Zeeb db_printf(" ll_addr=%02x:%02x:%02x:%02x:%02x:%02x\n", 1098335b943fSBjoern A. Zeeb octet[0], octet[1], octet[2], octet[3], octet[4], octet[5]); 10990447c136SAlexander V. Chernikov db_printf(" lle_timer=%p\n", &lle->lle_timer); 1100335b943fSBjoern A. Zeeb 1101335b943fSBjoern A. Zeeb switch (la->l3_addr.sa_family) { 1102335b943fSBjoern A. Zeeb #ifdef INET 1103335b943fSBjoern A. Zeeb case AF_INET: 1104335b943fSBjoern A. Zeeb { 1105335b943fSBjoern A. Zeeb struct sockaddr_in *sin; 1106335b943fSBjoern A. Zeeb char l3s[INET_ADDRSTRLEN]; 1107335b943fSBjoern A. Zeeb 1108335b943fSBjoern A. Zeeb sin = (struct sockaddr_in *)&la->l3_addr; 1109335b943fSBjoern A. Zeeb inet_ntoa_r(sin->sin_addr, l3s); 1110335b943fSBjoern A. Zeeb db_printf(" l3_addr=%s\n", l3s); 1111335b943fSBjoern A. Zeeb break; 1112335b943fSBjoern A. Zeeb } 1113335b943fSBjoern A. Zeeb #endif 1114335b943fSBjoern A. Zeeb #ifdef INET6 1115335b943fSBjoern A. Zeeb case AF_INET6: 1116335b943fSBjoern A. Zeeb { 1117335b943fSBjoern A. Zeeb struct sockaddr_in6 *sin6; 1118335b943fSBjoern A. Zeeb char l3s[INET6_ADDRSTRLEN]; 1119335b943fSBjoern A. Zeeb 1120335b943fSBjoern A. Zeeb sin6 = (struct sockaddr_in6 *)&la->l3_addr; 1121335b943fSBjoern A. Zeeb ip6_sprintf(l3s, &sin6->sin6_addr); 1122335b943fSBjoern A. Zeeb db_printf(" l3_addr=%s\n", l3s); 1123335b943fSBjoern A. Zeeb break; 1124335b943fSBjoern A. Zeeb } 1125335b943fSBjoern A. Zeeb #endif 1126335b943fSBjoern A. Zeeb default: 1127335b943fSBjoern A. Zeeb db_printf(" l3_addr=N/A (af=%d)\n", la->l3_addr.sa_family); 1128335b943fSBjoern A. Zeeb break; 1129335b943fSBjoern A. Zeeb } 1130335b943fSBjoern A. Zeeb } 1131335b943fSBjoern A. Zeeb 1132335b943fSBjoern A. Zeeb DB_SHOW_COMMAND(llentry, db_show_llentry) 1133335b943fSBjoern A. Zeeb { 1134335b943fSBjoern A. Zeeb 1135335b943fSBjoern A. Zeeb if (!have_addr) { 1136335b943fSBjoern A. Zeeb db_printf("usage: show llentry <struct llentry *>\n"); 1137335b943fSBjoern A. Zeeb return; 1138335b943fSBjoern A. Zeeb } 1139335b943fSBjoern A. Zeeb 1140335b943fSBjoern A. Zeeb llatbl_lle_show((struct llentry_sa *)addr); 1141335b943fSBjoern A. Zeeb } 1142335b943fSBjoern A. Zeeb 1143335b943fSBjoern A. Zeeb static void 1144335b943fSBjoern A. Zeeb llatbl_llt_show(struct lltable *llt) 1145335b943fSBjoern A. Zeeb { 1146335b943fSBjoern A. Zeeb int i; 1147335b943fSBjoern A. Zeeb struct llentry *lle; 1148335b943fSBjoern A. Zeeb 1149335b943fSBjoern A. Zeeb db_printf("llt=%p llt_af=%d llt_ifp=%p\n", 1150335b943fSBjoern A. Zeeb llt, llt->llt_af, llt->llt_ifp); 1151335b943fSBjoern A. Zeeb 11523a749863SAlexander V. Chernikov for (i = 0; i < llt->llt_hsize; i++) { 11534f6c66ccSMatt Macy CK_LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { 1154335b943fSBjoern A. Zeeb llatbl_lle_show((struct llentry_sa *)lle); 1155335b943fSBjoern A. Zeeb if (db_pager_quit) 1156335b943fSBjoern A. Zeeb return; 1157335b943fSBjoern A. Zeeb } 1158335b943fSBjoern A. Zeeb } 1159335b943fSBjoern A. Zeeb } 1160335b943fSBjoern A. Zeeb 1161335b943fSBjoern A. Zeeb DB_SHOW_COMMAND(lltable, db_show_lltable) 1162335b943fSBjoern A. Zeeb { 1163335b943fSBjoern A. Zeeb 1164335b943fSBjoern A. Zeeb if (!have_addr) { 1165335b943fSBjoern A. Zeeb db_printf("usage: show lltable <struct lltable *>\n"); 1166335b943fSBjoern A. Zeeb return; 1167335b943fSBjoern A. Zeeb } 1168335b943fSBjoern A. Zeeb 1169335b943fSBjoern A. Zeeb llatbl_llt_show((struct lltable *)addr); 1170335b943fSBjoern A. Zeeb } 1171335b943fSBjoern A. Zeeb 1172335b943fSBjoern A. Zeeb DB_SHOW_ALL_COMMAND(lltables, db_show_all_lltables) 1173335b943fSBjoern A. Zeeb { 1174335b943fSBjoern A. Zeeb VNET_ITERATOR_DECL(vnet_iter); 1175335b943fSBjoern A. Zeeb struct lltable *llt; 1176335b943fSBjoern A. Zeeb 1177335b943fSBjoern A. Zeeb VNET_FOREACH(vnet_iter) { 1178335b943fSBjoern A. Zeeb CURVNET_SET_QUIET(vnet_iter); 1179335b943fSBjoern A. Zeeb #ifdef VIMAGE 1180335b943fSBjoern A. Zeeb db_printf("vnet=%p\n", curvnet); 1181335b943fSBjoern A. Zeeb #endif 1182335b943fSBjoern A. Zeeb SLIST_FOREACH(llt, &V_lltables, llt_link) { 1183335b943fSBjoern A. Zeeb db_printf("llt=%p llt_af=%d llt_ifp=%p(%s)\n", 1184335b943fSBjoern A. Zeeb llt, llt->llt_af, llt->llt_ifp, 1185335b943fSBjoern A. Zeeb (llt->llt_ifp != NULL) ? 1186335b943fSBjoern A. Zeeb llt->llt_ifp->if_xname : "?"); 1187335b943fSBjoern A. Zeeb if (have_addr && addr != 0) /* verbose */ 1188335b943fSBjoern A. Zeeb llatbl_llt_show(llt); 1189335b943fSBjoern A. Zeeb if (db_pager_quit) { 1190335b943fSBjoern A. Zeeb CURVNET_RESTORE(); 1191335b943fSBjoern A. Zeeb return; 1192335b943fSBjoern A. Zeeb } 1193335b943fSBjoern A. Zeeb } 1194335b943fSBjoern A. Zeeb CURVNET_RESTORE(); 1195335b943fSBjoern A. Zeeb } 1196335b943fSBjoern A. Zeeb } 1197335b943fSBjoern A. Zeeb #endif 1198