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> 38*e2e050c8SConrad 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> 61530c0060SRobert Watson #include <net/vnet.h> 6282f39c91SKip Macy #include <netinet/if_ether.h> 6382f39c91SKip Macy #include <netinet6/in6_var.h> 6482f39c91SKip Macy #include <netinet6/nd6.h> 6582f39c91SKip Macy 6682f39c91SKip Macy MALLOC_DEFINE(M_LLTABLE, "lltable", "link level address tables"); 6782f39c91SKip Macy 685f901c92SAndrew Turner VNET_DEFINE_STATIC(SLIST_HEAD(, lltable), lltables) = 6976d68eccSBjoern A. Zeeb SLIST_HEAD_INITIALIZER(lltables); 70989e0411SMarko Zec #define V_lltables VNET(lltables) 7182f39c91SKip Macy 72199511bcSAndrey V. Elsukov static struct rwlock lltable_list_lock; 73199511bcSAndrey V. Elsukov RW_SYSINIT(lltable_list_lock, &lltable_list_lock, "lltable_list_lock"); 74199511bcSAndrey V. Elsukov #define LLTABLE_LIST_RLOCK() rw_rlock(&lltable_list_lock) 75199511bcSAndrey V. Elsukov #define LLTABLE_LIST_RUNLOCK() rw_runlock(&lltable_list_lock) 76199511bcSAndrey V. Elsukov #define LLTABLE_LIST_WLOCK() rw_wlock(&lltable_list_lock) 77199511bcSAndrey V. Elsukov #define LLTABLE_LIST_WUNLOCK() rw_wunlock(&lltable_list_lock) 78199511bcSAndrey V. Elsukov #define LLTABLE_LIST_LOCK_ASSERT() rw_assert(&lltable_list_lock, RA_LOCKED) 79dc56e98fSRobert Watson 80721cd2e0SAlexander V. Chernikov static void lltable_unlink(struct lltable *llt); 8111cdad98SAlexander V. Chernikov static void llentries_unlink(struct lltable *llt, struct llentries *head); 8211cdad98SAlexander V. Chernikov 8311cdad98SAlexander V. Chernikov static void htable_unlink_entry(struct llentry *lle); 8411cdad98SAlexander V. Chernikov static void htable_link_entry(struct lltable *llt, struct llentry *lle); 8511cdad98SAlexander V. Chernikov static int htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, 8611cdad98SAlexander V. Chernikov void *farg); 8711cdad98SAlexander V. Chernikov 8811cdad98SAlexander V. Chernikov /* 8911cdad98SAlexander V. Chernikov * Dump lle state for a specific address family. 9011cdad98SAlexander V. Chernikov */ 9111cdad98SAlexander V. Chernikov static int 9211cdad98SAlexander V. Chernikov lltable_dump_af(struct lltable *llt, struct sysctl_req *wr) 9311cdad98SAlexander V. Chernikov { 94a68cc388SGleb Smirnoff struct epoch_tracker et; 9511cdad98SAlexander V. Chernikov int error; 9611cdad98SAlexander V. Chernikov 97199511bcSAndrey V. Elsukov LLTABLE_LIST_LOCK_ASSERT(); 9811cdad98SAlexander V. Chernikov 9911cdad98SAlexander V. Chernikov if (llt->llt_ifp->if_flags & IFF_LOOPBACK) 10011cdad98SAlexander V. Chernikov return (0); 10111cdad98SAlexander V. Chernikov error = 0; 10211cdad98SAlexander V. Chernikov 103a68cc388SGleb Smirnoff NET_EPOCH_ENTER(et); 10411cdad98SAlexander V. Chernikov error = lltable_foreach_lle(llt, 10511cdad98SAlexander V. Chernikov (llt_foreach_cb_t *)llt->llt_dump_entry, wr); 106a68cc388SGleb Smirnoff NET_EPOCH_EXIT(et); 10711cdad98SAlexander V. Chernikov 10811cdad98SAlexander V. Chernikov return (error); 10911cdad98SAlexander V. Chernikov } 11011cdad98SAlexander V. Chernikov 11182f39c91SKip Macy /* 11282f39c91SKip Macy * Dump arp state for a specific address family. 11382f39c91SKip Macy */ 11482f39c91SKip Macy int 11582f39c91SKip Macy lltable_sysctl_dumparp(int af, struct sysctl_req *wr) 11682f39c91SKip Macy { 11782f39c91SKip Macy struct lltable *llt; 11882f39c91SKip Macy int error = 0; 11982f39c91SKip Macy 120199511bcSAndrey V. Elsukov LLTABLE_LIST_RLOCK(); 121989e0411SMarko Zec SLIST_FOREACH(llt, &V_lltables, llt_link) { 12282f39c91SKip Macy if (llt->llt_af == af) { 12311cdad98SAlexander V. Chernikov error = lltable_dump_af(llt, wr); 12482f39c91SKip Macy if (error != 0) 12582f39c91SKip Macy goto done; 12682f39c91SKip Macy } 12782f39c91SKip Macy } 12882f39c91SKip Macy done: 129199511bcSAndrey V. Elsukov LLTABLE_LIST_RUNLOCK(); 13082f39c91SKip Macy return (error); 13182f39c91SKip Macy } 13282f39c91SKip Macy 13382f39c91SKip Macy /* 13411cdad98SAlexander V. Chernikov * Common function helpers for chained hash table. 13511cdad98SAlexander V. Chernikov */ 13611cdad98SAlexander V. Chernikov 13711cdad98SAlexander V. Chernikov /* 13811cdad98SAlexander V. Chernikov * Runs specified callback for each entry in @llt. 13911cdad98SAlexander V. Chernikov * Caller does the locking. 14011cdad98SAlexander V. Chernikov * 14111cdad98SAlexander V. Chernikov */ 14211cdad98SAlexander V. Chernikov static int 14311cdad98SAlexander V. Chernikov htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg) 14411cdad98SAlexander V. Chernikov { 14511cdad98SAlexander V. Chernikov struct llentry *lle, *next; 14611cdad98SAlexander V. Chernikov int i, error; 14711cdad98SAlexander V. Chernikov 14811cdad98SAlexander V. Chernikov error = 0; 14911cdad98SAlexander V. Chernikov 15041cb42a6SAlexander V. Chernikov for (i = 0; i < llt->llt_hsize; i++) { 1514f6c66ccSMatt Macy CK_LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) { 15211cdad98SAlexander V. Chernikov error = f(llt, lle, farg); 15311cdad98SAlexander V. Chernikov if (error != 0) 15411cdad98SAlexander V. Chernikov break; 15511cdad98SAlexander V. Chernikov } 15611cdad98SAlexander V. Chernikov } 15711cdad98SAlexander V. Chernikov 15811cdad98SAlexander V. Chernikov return (error); 15911cdad98SAlexander V. Chernikov } 16011cdad98SAlexander V. Chernikov 16111cdad98SAlexander V. Chernikov static void 16211cdad98SAlexander V. Chernikov htable_link_entry(struct lltable *llt, struct llentry *lle) 16311cdad98SAlexander V. Chernikov { 16411cdad98SAlexander V. Chernikov struct llentries *lleh; 16511cdad98SAlexander V. Chernikov uint32_t hashidx; 16611cdad98SAlexander V. Chernikov 16711cdad98SAlexander V. Chernikov if ((lle->la_flags & LLE_LINKED) != 0) 16811cdad98SAlexander V. Chernikov return; 16911cdad98SAlexander V. Chernikov 17011cdad98SAlexander V. Chernikov IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp); 17111cdad98SAlexander V. Chernikov 1723a749863SAlexander V. Chernikov hashidx = llt->llt_hash(lle, llt->llt_hsize); 17311cdad98SAlexander V. Chernikov lleh = &llt->lle_head[hashidx]; 17411cdad98SAlexander V. Chernikov 17511cdad98SAlexander V. Chernikov lle->lle_tbl = llt; 17611cdad98SAlexander V. Chernikov lle->lle_head = lleh; 17711cdad98SAlexander V. Chernikov lle->la_flags |= LLE_LINKED; 1784f6c66ccSMatt Macy CK_LIST_INSERT_HEAD(lleh, lle, lle_next); 17911cdad98SAlexander V. Chernikov } 18011cdad98SAlexander V. Chernikov 18111cdad98SAlexander V. Chernikov static void 18211cdad98SAlexander V. Chernikov htable_unlink_entry(struct llentry *lle) 18311cdad98SAlexander V. Chernikov { 18411cdad98SAlexander V. Chernikov 18511cdad98SAlexander V. Chernikov if ((lle->la_flags & LLE_LINKED) != 0) { 18611cdad98SAlexander V. Chernikov IF_AFDATA_WLOCK_ASSERT(lle->lle_tbl->llt_ifp); 1874f6c66ccSMatt Macy CK_LIST_REMOVE(lle, lle_next); 18811cdad98SAlexander V. Chernikov lle->la_flags &= ~(LLE_VALID | LLE_LINKED); 18911cdad98SAlexander V. Chernikov #if 0 19011cdad98SAlexander V. Chernikov lle->lle_tbl = NULL; 19111cdad98SAlexander V. Chernikov lle->lle_head = NULL; 19211cdad98SAlexander V. Chernikov #endif 19311cdad98SAlexander V. Chernikov } 19411cdad98SAlexander V. Chernikov } 19511cdad98SAlexander V. Chernikov 19611cdad98SAlexander V. Chernikov struct prefix_match_data { 1973e7a2321SAlexander V. Chernikov const struct sockaddr *addr; 19811cdad98SAlexander V. Chernikov const struct sockaddr *mask; 19911cdad98SAlexander V. Chernikov struct llentries dchain; 20011cdad98SAlexander V. Chernikov u_int flags; 20111cdad98SAlexander V. Chernikov }; 20211cdad98SAlexander V. Chernikov 20311cdad98SAlexander V. Chernikov static int 20411cdad98SAlexander V. Chernikov htable_prefix_free_cb(struct lltable *llt, struct llentry *lle, void *farg) 20511cdad98SAlexander V. Chernikov { 20611cdad98SAlexander V. Chernikov struct prefix_match_data *pmd; 20711cdad98SAlexander V. Chernikov 20811cdad98SAlexander V. Chernikov pmd = (struct prefix_match_data *)farg; 20911cdad98SAlexander V. Chernikov 2103e7a2321SAlexander V. Chernikov if (llt->llt_match_prefix(pmd->addr, pmd->mask, pmd->flags, lle)) { 21111cdad98SAlexander V. Chernikov LLE_WLOCK(lle); 2120f8d79d9SMatt Macy CK_LIST_INSERT_HEAD(&pmd->dchain, lle, lle_chain); 21311cdad98SAlexander V. Chernikov } 21411cdad98SAlexander V. Chernikov 21511cdad98SAlexander V. Chernikov return (0); 21611cdad98SAlexander V. Chernikov } 21711cdad98SAlexander V. Chernikov 21811cdad98SAlexander V. Chernikov static void 2193e7a2321SAlexander V. Chernikov htable_prefix_free(struct lltable *llt, const struct sockaddr *addr, 22011cdad98SAlexander V. Chernikov const struct sockaddr *mask, u_int flags) 22111cdad98SAlexander V. Chernikov { 22211cdad98SAlexander V. Chernikov struct llentry *lle, *next; 22311cdad98SAlexander V. Chernikov struct prefix_match_data pmd; 22411cdad98SAlexander V. Chernikov 22511cdad98SAlexander V. Chernikov bzero(&pmd, sizeof(pmd)); 2263e7a2321SAlexander V. Chernikov pmd.addr = addr; 22711cdad98SAlexander V. Chernikov pmd.mask = mask; 22811cdad98SAlexander V. Chernikov pmd.flags = flags; 2294f6c66ccSMatt Macy CK_LIST_INIT(&pmd.dchain); 23011cdad98SAlexander V. Chernikov 23111cdad98SAlexander V. Chernikov IF_AFDATA_WLOCK(llt->llt_ifp); 23211cdad98SAlexander V. Chernikov /* Push matching lles to chain */ 23311cdad98SAlexander V. Chernikov lltable_foreach_lle(llt, htable_prefix_free_cb, &pmd); 23411cdad98SAlexander V. Chernikov 23511cdad98SAlexander V. Chernikov llentries_unlink(llt, &pmd.dchain); 23611cdad98SAlexander V. Chernikov IF_AFDATA_WUNLOCK(llt->llt_ifp); 23711cdad98SAlexander V. Chernikov 2380f8d79d9SMatt Macy CK_LIST_FOREACH_SAFE(lle, &pmd.dchain, lle_chain, next) 2395a255516SAlexander V. Chernikov lltable_free_entry(llt, lle); 24011cdad98SAlexander V. Chernikov } 24111cdad98SAlexander V. Chernikov 24211cdad98SAlexander V. Chernikov static void 24341cb42a6SAlexander V. Chernikov htable_free_tbl(struct lltable *llt) 24441cb42a6SAlexander V. Chernikov { 24541cb42a6SAlexander V. Chernikov 24641cb42a6SAlexander V. Chernikov free(llt->lle_head, M_LLTABLE); 24741cb42a6SAlexander V. Chernikov free(llt, M_LLTABLE); 24841cb42a6SAlexander V. Chernikov } 24941cb42a6SAlexander V. Chernikov 250721cd2e0SAlexander V. Chernikov static void 25111cdad98SAlexander V. Chernikov llentries_unlink(struct lltable *llt, struct llentries *head) 25211cdad98SAlexander V. Chernikov { 25311cdad98SAlexander V. Chernikov struct llentry *lle, *next; 25411cdad98SAlexander V. Chernikov 2550f8d79d9SMatt Macy CK_LIST_FOREACH_SAFE(lle, head, lle_chain, next) 25611cdad98SAlexander V. Chernikov llt->llt_unlink_entry(lle); 25711cdad98SAlexander V. Chernikov } 25811cdad98SAlexander V. Chernikov 25911cdad98SAlexander V. Chernikov /* 26011cdad98SAlexander V. Chernikov * Helper function used to drop all mbufs in hold queue. 261e162ea60SGeorge V. Neville-Neil * 262e162ea60SGeorge V. Neville-Neil * Returns the number of held packets, if any, that were dropped. 26382f39c91SKip Macy */ 264e162ea60SGeorge V. Neville-Neil size_t 26511cdad98SAlexander V. Chernikov lltable_drop_entry_queue(struct llentry *lle) 26682f39c91SKip Macy { 267e162ea60SGeorge V. Neville-Neil size_t pkts_dropped; 268e162ea60SGeorge V. Neville-Neil struct mbuf *next; 26982f39c91SKip Macy 27082f39c91SKip Macy LLE_WLOCK_ASSERT(lle); 27182f39c91SKip Macy 272ea537929SGleb Smirnoff pkts_dropped = 0; 273e162ea60SGeorge V. Neville-Neil while ((lle->la_numheld > 0) && (lle->la_hold != NULL)) { 274e162ea60SGeorge V. Neville-Neil next = lle->la_hold->m_nextpkt; 27582f39c91SKip Macy m_freem(lle->la_hold); 276e162ea60SGeorge V. Neville-Neil lle->la_hold = next; 277e162ea60SGeorge V. Neville-Neil lle->la_numheld--; 278e162ea60SGeorge V. Neville-Neil pkts_dropped++; 279e162ea60SGeorge V. Neville-Neil } 280e162ea60SGeorge V. Neville-Neil 281e162ea60SGeorge V. Neville-Neil KASSERT(lle->la_numheld == 0, 2827b3b099eSKonstantin Belousov ("%s: la_numheld %d > 0, pkts_droped %zd", __func__, 283e162ea60SGeorge V. Neville-Neil lle->la_numheld, pkts_dropped)); 28482f39c91SKip Macy 28511cdad98SAlexander V. Chernikov return (pkts_dropped); 28611cdad98SAlexander V. Chernikov } 28711cdad98SAlexander V. Chernikov 288ddd208f7SAlexander V. Chernikov void 289ddd208f7SAlexander V. Chernikov lltable_set_entry_addr(struct ifnet *ifp, struct llentry *lle, 2904fb3a820SAlexander V. Chernikov const char *linkhdr, size_t linkhdrsize, int lladdr_off) 291ddd208f7SAlexander V. Chernikov { 292ddd208f7SAlexander V. Chernikov 2934fb3a820SAlexander V. Chernikov memcpy(lle->r_linkdata, linkhdr, linkhdrsize); 2944fb3a820SAlexander V. Chernikov lle->r_hdrlen = linkhdrsize; 2954fb3a820SAlexander V. Chernikov lle->ll_addr = &lle->r_linkdata[lladdr_off]; 296ddd208f7SAlexander V. Chernikov lle->la_flags |= LLE_VALID; 297f8aee88fSAlexander V. Chernikov lle->r_flags |= RLLE_VALID; 298ddd208f7SAlexander V. Chernikov } 299ddd208f7SAlexander V. Chernikov 30011cdad98SAlexander V. Chernikov /* 30112cb7521SAlexander V. Chernikov * Tries to update @lle link-level address. 30212cb7521SAlexander V. Chernikov * Since update requires AFDATA WLOCK, function 30312cb7521SAlexander V. Chernikov * drops @lle lock, acquires AFDATA lock and then acquires 30412cb7521SAlexander V. Chernikov * @lle lock to maintain lock order. 30512cb7521SAlexander V. Chernikov * 30612cb7521SAlexander V. Chernikov * Returns 1 on success. 30712cb7521SAlexander V. Chernikov */ 30812cb7521SAlexander V. Chernikov int 30912cb7521SAlexander V. Chernikov lltable_try_set_entry_addr(struct ifnet *ifp, struct llentry *lle, 3104fb3a820SAlexander V. Chernikov const char *linkhdr, size_t linkhdrsize, int lladdr_off) 31112cb7521SAlexander V. Chernikov { 31212cb7521SAlexander V. Chernikov 31312cb7521SAlexander V. Chernikov /* Perform real LLE update */ 31412cb7521SAlexander V. Chernikov /* use afdata WLOCK to update fields */ 31512cb7521SAlexander V. Chernikov LLE_WLOCK_ASSERT(lle); 31612cb7521SAlexander V. Chernikov LLE_ADDREF(lle); 31712cb7521SAlexander V. Chernikov LLE_WUNLOCK(lle); 31812cb7521SAlexander V. Chernikov IF_AFDATA_WLOCK(ifp); 31912cb7521SAlexander V. Chernikov LLE_WLOCK(lle); 32012cb7521SAlexander V. Chernikov 32112cb7521SAlexander V. Chernikov /* 32212cb7521SAlexander V. Chernikov * Since we droppped LLE lock, other thread might have deleted 32312cb7521SAlexander V. Chernikov * this lle. Check and return 32412cb7521SAlexander V. Chernikov */ 32512cb7521SAlexander V. Chernikov if ((lle->la_flags & LLE_DELETED) != 0) { 32612cb7521SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 32712cb7521SAlexander V. Chernikov LLE_FREE_LOCKED(lle); 32812cb7521SAlexander V. Chernikov return (0); 32912cb7521SAlexander V. Chernikov } 33012cb7521SAlexander V. Chernikov 33112cb7521SAlexander V. Chernikov /* Update data */ 3324fb3a820SAlexander V. Chernikov lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize, lladdr_off); 33312cb7521SAlexander V. Chernikov 33412cb7521SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 33512cb7521SAlexander V. Chernikov 33612cb7521SAlexander V. Chernikov LLE_REMREF(lle); 33712cb7521SAlexander V. Chernikov 33812cb7521SAlexander V. Chernikov return (1); 33912cb7521SAlexander V. Chernikov } 34012cb7521SAlexander V. Chernikov 34112cb7521SAlexander V. Chernikov /* 3424fb3a820SAlexander V. Chernikov * Helper function used to pre-compute full/partial link-layer 3434fb3a820SAlexander V. Chernikov * header data suitable for feeding into if_output(). 3444fb3a820SAlexander V. Chernikov */ 3454fb3a820SAlexander V. Chernikov int 3464fb3a820SAlexander V. Chernikov lltable_calc_llheader(struct ifnet *ifp, int family, char *lladdr, 3474fb3a820SAlexander V. Chernikov char *buf, size_t *bufsize, int *lladdr_off) 3484fb3a820SAlexander V. Chernikov { 3494fb3a820SAlexander V. Chernikov struct if_encap_req ereq; 3504fb3a820SAlexander V. Chernikov int error; 3514fb3a820SAlexander V. Chernikov 3524fb3a820SAlexander V. Chernikov bzero(buf, *bufsize); 3534fb3a820SAlexander V. Chernikov bzero(&ereq, sizeof(ereq)); 3544fb3a820SAlexander V. Chernikov ereq.buf = buf; 3554fb3a820SAlexander V. Chernikov ereq.bufsize = *bufsize; 3564fb3a820SAlexander V. Chernikov ereq.rtype = IFENCAP_LL; 3574fb3a820SAlexander V. Chernikov ereq.family = family; 3584fb3a820SAlexander V. Chernikov ereq.lladdr = lladdr; 3594fb3a820SAlexander V. Chernikov ereq.lladdr_len = ifp->if_addrlen; 3604fb3a820SAlexander V. Chernikov error = ifp->if_requestencap(ifp, &ereq); 3614fb3a820SAlexander V. Chernikov if (error == 0) { 3624fb3a820SAlexander V. Chernikov *bufsize = ereq.bufsize; 3634fb3a820SAlexander V. Chernikov *lladdr_off = ereq.lladdr_off; 3644fb3a820SAlexander V. Chernikov } 3654fb3a820SAlexander V. Chernikov 3664fb3a820SAlexander V. Chernikov return (error); 3674fb3a820SAlexander V. Chernikov } 3684fb3a820SAlexander V. Chernikov 3694fb3a820SAlexander V. Chernikov /* 3704fb3a820SAlexander V. Chernikov * Update link-layer header for given @lle after 3714fb3a820SAlexander V. Chernikov * interface lladdr was changed. 3724fb3a820SAlexander V. Chernikov */ 3734fb3a820SAlexander V. Chernikov static int 3744fb3a820SAlexander V. Chernikov llentry_update_ifaddr(struct lltable *llt, struct llentry *lle, void *farg) 3754fb3a820SAlexander V. Chernikov { 3764fb3a820SAlexander V. Chernikov struct ifnet *ifp; 3774fb3a820SAlexander V. Chernikov u_char linkhdr[LLE_MAX_LINKHDR]; 3784fb3a820SAlexander V. Chernikov size_t linkhdrsize; 3794fb3a820SAlexander V. Chernikov u_char *lladdr; 3804fb3a820SAlexander V. Chernikov int lladdr_off; 3814fb3a820SAlexander V. Chernikov 3824fb3a820SAlexander V. Chernikov ifp = (struct ifnet *)farg; 3834fb3a820SAlexander V. Chernikov 3844fb3a820SAlexander V. Chernikov lladdr = lle->ll_addr; 3854fb3a820SAlexander V. Chernikov 3864fb3a820SAlexander V. Chernikov LLE_WLOCK(lle); 3874fb3a820SAlexander V. Chernikov if ((lle->la_flags & LLE_VALID) == 0) { 3884fb3a820SAlexander V. Chernikov LLE_WUNLOCK(lle); 3894fb3a820SAlexander V. Chernikov return (0); 3904fb3a820SAlexander V. Chernikov } 3914fb3a820SAlexander V. Chernikov 3924fb3a820SAlexander V. Chernikov if ((lle->la_flags & LLE_IFADDR) != 0) 3934fb3a820SAlexander V. Chernikov lladdr = IF_LLADDR(ifp); 3944fb3a820SAlexander V. Chernikov 3954fb3a820SAlexander V. Chernikov linkhdrsize = sizeof(linkhdr); 3964fb3a820SAlexander V. Chernikov lltable_calc_llheader(ifp, llt->llt_af, lladdr, linkhdr, &linkhdrsize, 3974fb3a820SAlexander V. Chernikov &lladdr_off); 3984fb3a820SAlexander V. Chernikov memcpy(lle->r_linkdata, linkhdr, linkhdrsize); 3994fb3a820SAlexander V. Chernikov LLE_WUNLOCK(lle); 4004fb3a820SAlexander V. Chernikov 4014fb3a820SAlexander V. Chernikov return (0); 4024fb3a820SAlexander V. Chernikov } 4034fb3a820SAlexander V. Chernikov 4044fb3a820SAlexander V. Chernikov /* 4054fb3a820SAlexander V. Chernikov * Update all calculated headers for given @llt 4064fb3a820SAlexander V. Chernikov */ 4074fb3a820SAlexander V. Chernikov void 4084fb3a820SAlexander V. Chernikov lltable_update_ifaddr(struct lltable *llt) 4094fb3a820SAlexander V. Chernikov { 4104fb3a820SAlexander V. Chernikov 4114fb3a820SAlexander V. Chernikov if (llt->llt_ifp->if_flags & IFF_LOOPBACK) 4124fb3a820SAlexander V. Chernikov return; 4134fb3a820SAlexander V. Chernikov 4144fb3a820SAlexander V. Chernikov IF_AFDATA_WLOCK(llt->llt_ifp); 4154fb3a820SAlexander V. Chernikov lltable_foreach_lle(llt, llentry_update_ifaddr, llt->llt_ifp); 4164fb3a820SAlexander V. Chernikov IF_AFDATA_WUNLOCK(llt->llt_ifp); 4174fb3a820SAlexander V. Chernikov } 4184fb3a820SAlexander V. Chernikov 4194fb3a820SAlexander V. Chernikov /* 4205a255516SAlexander V. Chernikov * 421a4641f4eSPedro F. Giffuni * Performs generic cleanup routines and frees lle. 4225a255516SAlexander V. Chernikov * 4235a255516SAlexander V. Chernikov * Called for non-linked entries, with callouts and 4245a255516SAlexander V. Chernikov * other AF-specific cleanups performed. 4255a255516SAlexander V. Chernikov * 4265a255516SAlexander V. Chernikov * @lle must be passed WLOCK'ed 42711cdad98SAlexander V. Chernikov * 42811cdad98SAlexander V. Chernikov * Returns the number of held packets, if any, that were dropped. 42911cdad98SAlexander V. Chernikov */ 43011cdad98SAlexander V. Chernikov size_t 43111cdad98SAlexander V. Chernikov llentry_free(struct llentry *lle) 43211cdad98SAlexander V. Chernikov { 43311cdad98SAlexander V. Chernikov size_t pkts_dropped; 43411cdad98SAlexander V. Chernikov 43511cdad98SAlexander V. Chernikov LLE_WLOCK_ASSERT(lle); 43611cdad98SAlexander V. Chernikov 437d3cdb716SAlexander V. Chernikov KASSERT((lle->la_flags & LLE_LINKED) == 0, ("freeing linked lle")); 43811cdad98SAlexander V. Chernikov 43911cdad98SAlexander V. Chernikov pkts_dropped = lltable_drop_entry_queue(lle); 44011cdad98SAlexander V. Chernikov 441acf673edSAndrey V. Elsukov /* cancel timer */ 442acf673edSAndrey V. Elsukov if (callout_stop(&lle->lle_timer) > 0) 443acf673edSAndrey V. Elsukov LLE_REMREF(lle); 44482f39c91SKip Macy LLE_FREE_LOCKED(lle); 445e162ea60SGeorge V. Neville-Neil 446e162ea60SGeorge V. Neville-Neil return (pkts_dropped); 44782f39c91SKip Macy } 44882f39c91SKip Macy 449adfc35ffSKip Macy /* 450b1d86af7SGleb Smirnoff * (al)locate an llentry for address dst (equivalent to rtalloc for new-arp). 451e94ba2ceSKip Macy * 452b1d86af7SGleb Smirnoff * If found the llentry * is returned referenced and unlocked. 453adfc35ffSKip Macy */ 454b1d86af7SGleb Smirnoff struct llentry * 455b1d86af7SGleb Smirnoff llentry_alloc(struct ifnet *ifp, struct lltable *lt, 456b1d86af7SGleb Smirnoff struct sockaddr_storage *dst) 457c8da95acSKip Macy { 458a68cc388SGleb Smirnoff struct epoch_tracker et; 4595a255516SAlexander V. Chernikov struct llentry *la, *la_tmp; 460c8da95acSKip Macy 461a68cc388SGleb Smirnoff NET_EPOCH_ENTER(et); 462b1d86af7SGleb Smirnoff la = lla_lookup(lt, LLE_EXCLUSIVE, (struct sockaddr *)dst); 463a68cc388SGleb Smirnoff NET_EPOCH_EXIT(et); 464b1d86af7SGleb Smirnoff 465b1d86af7SGleb Smirnoff if (la != NULL) { 466c8da95acSKip Macy LLE_ADDREF(la); 467c8da95acSKip Macy LLE_WUNLOCK(la); 4685a255516SAlexander V. Chernikov return (la); 4695a255516SAlexander V. Chernikov } 4705a255516SAlexander V. Chernikov 4715a255516SAlexander V. Chernikov if ((ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0) { 4725a255516SAlexander V. Chernikov la = lltable_alloc_entry(lt, 0, (struct sockaddr *)dst); 4735a255516SAlexander V. Chernikov if (la == NULL) 4745a255516SAlexander V. Chernikov return (NULL); 4755a255516SAlexander V. Chernikov IF_AFDATA_WLOCK(ifp); 4765a255516SAlexander V. Chernikov LLE_WLOCK(la); 4775a255516SAlexander V. Chernikov /* Prefer any existing LLE over newly-created one */ 4785a255516SAlexander V. Chernikov la_tmp = lla_lookup(lt, LLE_EXCLUSIVE, (struct sockaddr *)dst); 4795a255516SAlexander V. Chernikov if (la_tmp == NULL) 4805a255516SAlexander V. Chernikov lltable_link_entry(lt, la); 4815a255516SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 4825a255516SAlexander V. Chernikov if (la_tmp != NULL) { 4835a255516SAlexander V. Chernikov lltable_free_entry(lt, la); 4845a255516SAlexander V. Chernikov la = la_tmp; 4855a255516SAlexander V. Chernikov } 4865a255516SAlexander V. Chernikov LLE_ADDREF(la); 4875a255516SAlexander V. Chernikov LLE_WUNLOCK(la); 488b1d86af7SGleb Smirnoff } 489c8da95acSKip Macy 490b1d86af7SGleb Smirnoff return (la); 491c8da95acSKip Macy } 492c8da95acSKip Macy 49382f39c91SKip Macy /* 49482f39c91SKip Macy * Free all entries from given table and free itself. 49582f39c91SKip Macy */ 49611cdad98SAlexander V. Chernikov 49711cdad98SAlexander V. Chernikov static int 49811cdad98SAlexander V. Chernikov lltable_free_cb(struct lltable *llt, struct llentry *lle, void *farg) 49911cdad98SAlexander V. Chernikov { 50011cdad98SAlexander V. Chernikov struct llentries *dchain; 50111cdad98SAlexander V. Chernikov 50211cdad98SAlexander V. Chernikov dchain = (struct llentries *)farg; 50311cdad98SAlexander V. Chernikov 50411cdad98SAlexander V. Chernikov LLE_WLOCK(lle); 5050f8d79d9SMatt Macy CK_LIST_INSERT_HEAD(dchain, lle, lle_chain); 50611cdad98SAlexander V. Chernikov 50711cdad98SAlexander V. Chernikov return (0); 50811cdad98SAlexander V. Chernikov } 50911cdad98SAlexander V. Chernikov 51011cdad98SAlexander V. Chernikov /* 51111cdad98SAlexander V. Chernikov * Free all entries from given table and free itself. 51211cdad98SAlexander V. Chernikov */ 51382f39c91SKip Macy void 51482f39c91SKip Macy lltable_free(struct lltable *llt) 51582f39c91SKip Macy { 51682f39c91SKip Macy struct llentry *lle, *next; 51711cdad98SAlexander V. Chernikov struct llentries dchain; 51882f39c91SKip Macy 51982f39c91SKip Macy KASSERT(llt != NULL, ("%s: llt is NULL", __func__)); 52082f39c91SKip Macy 521721cd2e0SAlexander V. Chernikov lltable_unlink(llt); 52282f39c91SKip Macy 5234f6c66ccSMatt Macy CK_LIST_INIT(&dchain); 524ea537929SGleb Smirnoff IF_AFDATA_WLOCK(llt->llt_ifp); 52511cdad98SAlexander V. Chernikov /* Push all lles to @dchain */ 52611cdad98SAlexander V. Chernikov lltable_foreach_lle(llt, lltable_free_cb, &dchain); 52711cdad98SAlexander V. Chernikov llentries_unlink(llt, &dchain); 52811cdad98SAlexander V. Chernikov IF_AFDATA_WUNLOCK(llt->llt_ifp); 52911cdad98SAlexander V. Chernikov 5300f8d79d9SMatt Macy CK_LIST_FOREACH_SAFE(lle, &dchain, lle_chain, next) { 53182f39c91SKip Macy llentry_free(lle); 53282f39c91SKip Macy } 53382f39c91SKip Macy 534721cd2e0SAlexander V. Chernikov llt->llt_free_tbl(llt); 53582f39c91SKip Macy } 53682f39c91SKip Macy 537fc2bfb32SBjoern A. Zeeb #if 0 53882f39c91SKip Macy void 53982f39c91SKip Macy lltable_drain(int af) 54082f39c91SKip Macy { 54182f39c91SKip Macy struct lltable *llt; 54282f39c91SKip Macy struct llentry *lle; 5433e85b721SEd Maste int i; 54482f39c91SKip Macy 545199511bcSAndrey V. Elsukov LLTABLE_LIST_RLOCK(); 546989e0411SMarko Zec SLIST_FOREACH(llt, &V_lltables, llt_link) { 54782f39c91SKip Macy if (llt->llt_af != af) 54882f39c91SKip Macy continue; 54982f39c91SKip Macy 5503a749863SAlexander V. Chernikov for (i=0; i < llt->llt_hsize; i++) { 5514f6c66ccSMatt Macy CK_LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { 552fc2bfb32SBjoern A. Zeeb LLE_WLOCK(lle); 55382f39c91SKip Macy if (lle->la_hold) { 55482f39c91SKip Macy m_freem(lle->la_hold); 55582f39c91SKip Macy lle->la_hold = NULL; 55682f39c91SKip Macy } 557fc2bfb32SBjoern A. Zeeb LLE_WUNLOCK(lle); 55882f39c91SKip Macy } 55982f39c91SKip Macy } 56082f39c91SKip Macy } 561199511bcSAndrey V. Elsukov LLTABLE_LIST_RUNLOCK(); 56282f39c91SKip Macy } 563fc2bfb32SBjoern A. Zeeb #endif 56482f39c91SKip Macy 5653e7a2321SAlexander V. Chernikov /* 5663e7a2321SAlexander V. Chernikov * Deletes an address from given lltable. 5673e7a2321SAlexander V. Chernikov * Used for userland interaction to remove 5683e7a2321SAlexander V. Chernikov * individual entries. Skips entries added by OS. 5693e7a2321SAlexander V. Chernikov */ 5703e7a2321SAlexander V. Chernikov int 5713e7a2321SAlexander V. Chernikov lltable_delete_addr(struct lltable *llt, u_int flags, 5723e7a2321SAlexander V. Chernikov const struct sockaddr *l3addr) 5733e7a2321SAlexander V. Chernikov { 5743e7a2321SAlexander V. Chernikov struct llentry *lle; 5753e7a2321SAlexander V. Chernikov struct ifnet *ifp; 5763e7a2321SAlexander V. Chernikov 5773e7a2321SAlexander V. Chernikov ifp = llt->llt_ifp; 5783e7a2321SAlexander V. Chernikov IF_AFDATA_WLOCK(ifp); 5793e7a2321SAlexander V. Chernikov lle = lla_lookup(llt, LLE_EXCLUSIVE, l3addr); 5803e7a2321SAlexander V. Chernikov 5813e7a2321SAlexander V. Chernikov if (lle == NULL) { 5823e7a2321SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 5833e7a2321SAlexander V. Chernikov return (ENOENT); 5843e7a2321SAlexander V. Chernikov } 5853e7a2321SAlexander V. Chernikov if ((lle->la_flags & LLE_IFADDR) != 0 && (flags & LLE_IFADDR) == 0) { 5863e7a2321SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 5873e7a2321SAlexander V. Chernikov LLE_WUNLOCK(lle); 5883e7a2321SAlexander V. Chernikov return (EPERM); 5893e7a2321SAlexander V. Chernikov } 5903e7a2321SAlexander V. Chernikov 5913e7a2321SAlexander V. Chernikov lltable_unlink_entry(llt, lle); 5923e7a2321SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 5933e7a2321SAlexander V. Chernikov 5943e7a2321SAlexander V. Chernikov llt->llt_delete_entry(llt, lle); 5953e7a2321SAlexander V. Chernikov 5963e7a2321SAlexander V. Chernikov return (0); 5973e7a2321SAlexander V. Chernikov } 5983e7a2321SAlexander V. Chernikov 599c9d763bfSQing Li void 6003e7a2321SAlexander V. Chernikov lltable_prefix_free(int af, struct sockaddr *addr, struct sockaddr *mask, 6015b84dc78SQing Li u_int flags) 602c9d763bfSQing Li { 603c9d763bfSQing Li struct lltable *llt; 604c9d763bfSQing Li 605199511bcSAndrey V. Elsukov LLTABLE_LIST_RLOCK(); 606989e0411SMarko Zec SLIST_FOREACH(llt, &V_lltables, llt_link) { 607c9d763bfSQing Li if (llt->llt_af != af) 608c9d763bfSQing Li continue; 609c9d763bfSQing Li 6103e7a2321SAlexander V. Chernikov llt->llt_prefix_free(llt, addr, mask, flags); 611c9d763bfSQing Li } 612199511bcSAndrey V. Elsukov LLTABLE_LIST_RUNLOCK(); 613c9d763bfSQing Li } 614c9d763bfSQing Li 61582f39c91SKip Macy struct lltable * 61641cb42a6SAlexander V. Chernikov lltable_allocate_htbl(uint32_t hsize) 61782f39c91SKip Macy { 61882f39c91SKip Macy struct lltable *llt; 61941cb42a6SAlexander V. Chernikov int i; 62082f39c91SKip Macy 62141cb42a6SAlexander V. Chernikov llt = malloc(sizeof(struct lltable), M_LLTABLE, M_WAITOK | M_ZERO); 62241cb42a6SAlexander V. Chernikov llt->llt_hsize = hsize; 62341cb42a6SAlexander V. Chernikov llt->lle_head = malloc(sizeof(struct llentries) * hsize, 62441cb42a6SAlexander V. Chernikov M_LLTABLE, M_WAITOK | M_ZERO); 62582f39c91SKip Macy 62641cb42a6SAlexander V. Chernikov for (i = 0; i < llt->llt_hsize; i++) 6274f6c66ccSMatt Macy CK_LIST_INIT(&llt->lle_head[i]); 62882f39c91SKip Macy 62911cdad98SAlexander V. Chernikov /* Set some default callbacks */ 63011cdad98SAlexander V. Chernikov llt->llt_link_entry = htable_link_entry; 63111cdad98SAlexander V. Chernikov llt->llt_unlink_entry = htable_unlink_entry; 63211cdad98SAlexander V. Chernikov llt->llt_prefix_free = htable_prefix_free; 63311cdad98SAlexander V. Chernikov llt->llt_foreach_entry = htable_foreach_lle; 63441cb42a6SAlexander V. Chernikov llt->llt_free_tbl = htable_free_tbl; 63541cb42a6SAlexander V. Chernikov 63641cb42a6SAlexander V. Chernikov return (llt); 63741cb42a6SAlexander V. Chernikov } 63841cb42a6SAlexander V. Chernikov 63982f39c91SKip Macy /* 640721cd2e0SAlexander V. Chernikov * Links lltable to global llt list. 64182f39c91SKip Macy */ 642721cd2e0SAlexander V. Chernikov void 643721cd2e0SAlexander V. Chernikov lltable_link(struct lltable *llt) 64482f39c91SKip Macy { 64511cdad98SAlexander V. Chernikov 646199511bcSAndrey V. Elsukov LLTABLE_LIST_WLOCK(); 647989e0411SMarko Zec SLIST_INSERT_HEAD(&V_lltables, llt, llt_link); 648199511bcSAndrey V. Elsukov LLTABLE_LIST_WUNLOCK(); 649721cd2e0SAlexander V. Chernikov } 65082f39c91SKip Macy 651721cd2e0SAlexander V. Chernikov static void 652721cd2e0SAlexander V. Chernikov lltable_unlink(struct lltable *llt) 653721cd2e0SAlexander V. Chernikov { 654721cd2e0SAlexander V. Chernikov 655199511bcSAndrey V. Elsukov LLTABLE_LIST_WLOCK(); 656721cd2e0SAlexander V. Chernikov SLIST_REMOVE(&V_lltables, llt, lltable, llt_link); 657199511bcSAndrey V. Elsukov LLTABLE_LIST_WUNLOCK(); 658721cd2e0SAlexander V. Chernikov 65982f39c91SKip Macy } 66082f39c91SKip Macy 66182f39c91SKip Macy /* 66211cdad98SAlexander V. Chernikov * External methods used by lltable consumers 66311cdad98SAlexander V. Chernikov */ 66411cdad98SAlexander V. Chernikov 66511cdad98SAlexander V. Chernikov int 66611cdad98SAlexander V. Chernikov lltable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg) 66711cdad98SAlexander V. Chernikov { 66811cdad98SAlexander V. Chernikov 66911cdad98SAlexander V. Chernikov return (llt->llt_foreach_entry(llt, f, farg)); 67011cdad98SAlexander V. Chernikov } 67111cdad98SAlexander V. Chernikov 6725a255516SAlexander V. Chernikov struct llentry * 6735a255516SAlexander V. Chernikov lltable_alloc_entry(struct lltable *llt, u_int flags, 6745a255516SAlexander V. Chernikov const struct sockaddr *l3addr) 6755a255516SAlexander V. Chernikov { 6765a255516SAlexander V. Chernikov 6775a255516SAlexander V. Chernikov return (llt->llt_alloc_entry(llt, flags, l3addr)); 6785a255516SAlexander V. Chernikov } 6795a255516SAlexander V. Chernikov 6805a255516SAlexander V. Chernikov void 6815a255516SAlexander V. Chernikov lltable_free_entry(struct lltable *llt, struct llentry *lle) 6825a255516SAlexander V. Chernikov { 6835a255516SAlexander V. Chernikov 6845a255516SAlexander V. Chernikov llt->llt_free_entry(llt, lle); 6855a255516SAlexander V. Chernikov } 6865a255516SAlexander V. Chernikov 68711cdad98SAlexander V. Chernikov void 68811cdad98SAlexander V. Chernikov lltable_link_entry(struct lltable *llt, struct llentry *lle) 68911cdad98SAlexander V. Chernikov { 69011cdad98SAlexander V. Chernikov 69111cdad98SAlexander V. Chernikov llt->llt_link_entry(llt, lle); 69211cdad98SAlexander V. Chernikov } 69311cdad98SAlexander V. Chernikov 69411cdad98SAlexander V. Chernikov void 69511cdad98SAlexander V. Chernikov lltable_unlink_entry(struct lltable *llt, struct llentry *lle) 69611cdad98SAlexander V. Chernikov { 69711cdad98SAlexander V. Chernikov 69811cdad98SAlexander V. Chernikov llt->llt_unlink_entry(lle); 69911cdad98SAlexander V. Chernikov } 70011cdad98SAlexander V. Chernikov 70111cdad98SAlexander V. Chernikov void 70211cdad98SAlexander V. Chernikov lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa) 70311cdad98SAlexander V. Chernikov { 70411cdad98SAlexander V. Chernikov struct lltable *llt; 70511cdad98SAlexander V. Chernikov 70611cdad98SAlexander V. Chernikov llt = lle->lle_tbl; 70711cdad98SAlexander V. Chernikov llt->llt_fill_sa_entry(lle, sa); 70811cdad98SAlexander V. Chernikov } 70911cdad98SAlexander V. Chernikov 71011cdad98SAlexander V. Chernikov struct ifnet * 71111cdad98SAlexander V. Chernikov lltable_get_ifp(const struct lltable *llt) 71211cdad98SAlexander V. Chernikov { 71311cdad98SAlexander V. Chernikov 71411cdad98SAlexander V. Chernikov return (llt->llt_ifp); 71511cdad98SAlexander V. Chernikov } 71611cdad98SAlexander V. Chernikov 71711cdad98SAlexander V. Chernikov int 71811cdad98SAlexander V. Chernikov lltable_get_af(const struct lltable *llt) 71911cdad98SAlexander V. Chernikov { 72011cdad98SAlexander V. Chernikov 72111cdad98SAlexander V. Chernikov return (llt->llt_af); 72211cdad98SAlexander V. Chernikov } 72311cdad98SAlexander V. Chernikov 72411cdad98SAlexander V. Chernikov /* 725b4b1367aSAlexander V. Chernikov * Called in route_output when rtm_flags contains RTF_LLDATA. 72682f39c91SKip Macy */ 72782f39c91SKip Macy int 72882f39c91SKip Macy lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info) 72982f39c91SKip Macy { 73082f39c91SKip Macy struct sockaddr_dl *dl = 73182f39c91SKip Macy (struct sockaddr_dl *)info->rti_info[RTAX_GATEWAY]; 73282f39c91SKip Macy struct sockaddr *dst = (struct sockaddr *)info->rti_info[RTAX_DST]; 73382f39c91SKip Macy struct ifnet *ifp; 73482f39c91SKip Macy struct lltable *llt; 7355a255516SAlexander V. Chernikov struct llentry *lle, *lle_tmp; 7364fb3a820SAlexander V. Chernikov uint8_t linkhdr[LLE_MAX_LINKHDR]; 7374fb3a820SAlexander V. Chernikov size_t linkhdrsize; 7384fb3a820SAlexander V. Chernikov int lladdr_off; 739b4b1367aSAlexander V. Chernikov u_int laflags = 0; 740b4b1367aSAlexander V. Chernikov int error; 74182f39c91SKip Macy 7421910bfcbSGleb Smirnoff KASSERT(dl != NULL && dl->sdl_family == AF_LINK, 7431910bfcbSGleb Smirnoff ("%s: invalid dl\n", __func__)); 7441910bfcbSGleb Smirnoff 74582f39c91SKip Macy ifp = ifnet_byindex(dl->sdl_index); 74682f39c91SKip Macy if (ifp == NULL) { 74782f39c91SKip Macy log(LOG_INFO, "%s: invalid ifp (sdl_index %d)\n", 74882f39c91SKip Macy __func__, dl->sdl_index); 74982f39c91SKip Macy return EINVAL; 75082f39c91SKip Macy } 75182f39c91SKip Macy 75282f39c91SKip Macy /* XXX linked list may be too expensive */ 753199511bcSAndrey V. Elsukov LLTABLE_LIST_RLOCK(); 754989e0411SMarko Zec SLIST_FOREACH(llt, &V_lltables, llt_link) { 75582f39c91SKip Macy if (llt->llt_af == dst->sa_family && 75682f39c91SKip Macy llt->llt_ifp == ifp) 75782f39c91SKip Macy break; 75882f39c91SKip Macy } 759199511bcSAndrey V. Elsukov LLTABLE_LIST_RUNLOCK(); 76082f39c91SKip Macy KASSERT(llt != NULL, ("Yep, ugly hacks are bad\n")); 76182f39c91SKip Macy 762b4b1367aSAlexander V. Chernikov error = 0; 76382f39c91SKip Macy 764b4b1367aSAlexander V. Chernikov switch (rtm->rtm_type) { 765b4b1367aSAlexander V. Chernikov case RTM_ADD: 766b4b1367aSAlexander V. Chernikov /* Add static LLE */ 7673b0fd911SAlexander V. Chernikov laflags = 0; 7683b0fd911SAlexander V. Chernikov if (rtm->rtm_rmx.rmx_expire == 0) 7693b0fd911SAlexander V. Chernikov laflags = LLE_STATIC; 7703b0fd911SAlexander V. Chernikov lle = lltable_alloc_entry(llt, laflags, dst); 7715a255516SAlexander V. Chernikov if (lle == NULL) 772b4b1367aSAlexander V. Chernikov return (ENOMEM); 773b4b1367aSAlexander V. Chernikov 7744fb3a820SAlexander V. Chernikov linkhdrsize = sizeof(linkhdr); 7754fb3a820SAlexander V. Chernikov if (lltable_calc_llheader(ifp, dst->sa_family, LLADDR(dl), 7764fb3a820SAlexander V. Chernikov linkhdr, &linkhdrsize, &lladdr_off) != 0) 7774fb3a820SAlexander V. Chernikov return (EINVAL); 7784fb3a820SAlexander V. Chernikov lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize, 7794fb3a820SAlexander V. Chernikov lladdr_off); 780b4b1367aSAlexander V. Chernikov if ((rtm->rtm_flags & RTF_ANNOUNCE)) 781b4b1367aSAlexander V. Chernikov lle->la_flags |= LLE_PUB; 78282f39c91SKip Macy lle->la_expire = rtm->rtm_rmx.rmx_expire; 7833b0fd911SAlexander V. Chernikov 78482f39c91SKip Macy laflags = lle->la_flags; 7855a255516SAlexander V. Chernikov 7865a255516SAlexander V. Chernikov /* Try to link new entry */ 7875a255516SAlexander V. Chernikov lle_tmp = NULL; 7885a255516SAlexander V. Chernikov IF_AFDATA_WLOCK(ifp); 7895a255516SAlexander V. Chernikov LLE_WLOCK(lle); 7905a255516SAlexander V. Chernikov lle_tmp = lla_lookup(llt, LLE_EXCLUSIVE, dst); 7915a255516SAlexander V. Chernikov if (lle_tmp != NULL) { 7925a255516SAlexander V. Chernikov /* Check if we are trying to replace immutable entry */ 7935a255516SAlexander V. Chernikov if ((lle_tmp->la_flags & LLE_IFADDR) != 0) { 794b4b1367aSAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 7955a255516SAlexander V. Chernikov LLE_WUNLOCK(lle_tmp); 7965a255516SAlexander V. Chernikov lltable_free_entry(llt, lle); 7975a255516SAlexander V. Chernikov return (EPERM); 7985a255516SAlexander V. Chernikov } 7995a255516SAlexander V. Chernikov /* Unlink existing entry from table */ 8005a255516SAlexander V. Chernikov lltable_unlink_entry(llt, lle_tmp); 8015a255516SAlexander V. Chernikov } 8025a255516SAlexander V. Chernikov lltable_link_entry(llt, lle); 8035a255516SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 8045a255516SAlexander V. Chernikov 8055a255516SAlexander V. Chernikov if (lle_tmp != NULL) { 8065a255516SAlexander V. Chernikov EVENTHANDLER_INVOKE(lle_event, lle_tmp,LLENTRY_EXPIRED); 8075a255516SAlexander V. Chernikov lltable_free_entry(llt, lle_tmp); 8085a255516SAlexander V. Chernikov } 8095a255516SAlexander V. Chernikov 8105a255516SAlexander V. Chernikov /* 8115a255516SAlexander V. Chernikov * By invoking LLE handler here we might get 8125a255516SAlexander V. Chernikov * two events on static LLE entry insertion 8135a255516SAlexander V. Chernikov * in routing socket. However, since we might have 8145a255516SAlexander V. Chernikov * other subscribers we need to generate this event. 8155a255516SAlexander V. Chernikov */ 8165a255516SAlexander V. Chernikov EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_RESOLVED); 8175a255516SAlexander V. Chernikov LLE_WUNLOCK(lle); 81882f39c91SKip Macy #ifdef INET 8197b4d716bSKip Macy /* gratuitous ARP */ 8209711a168SGleb Smirnoff if ((laflags & LLE_PUB) && dst->sa_family == AF_INET) 82182f39c91SKip Macy arprequest(ifp, 82282f39c91SKip Macy &((struct sockaddr_in *)dst)->sin_addr, 82382f39c91SKip Macy &((struct sockaddr_in *)dst)->sin_addr, 8249711a168SGleb Smirnoff (u_char *)LLADDR(dl)); 82582f39c91SKip Macy #endif 82682f39c91SKip Macy 827b4b1367aSAlexander V. Chernikov break; 828b4b1367aSAlexander V. Chernikov 829b4b1367aSAlexander V. Chernikov case RTM_DELETE: 8303e7a2321SAlexander V. Chernikov return (lltable_delete_addr(llt, 0, dst)); 831b4b1367aSAlexander V. Chernikov 832b4b1367aSAlexander V. Chernikov default: 833b4b1367aSAlexander V. Chernikov error = EINVAL; 834b4b1367aSAlexander V. Chernikov } 83582f39c91SKip Macy 83682f39c91SKip Macy return (error); 83782f39c91SKip Macy } 838989e0411SMarko Zec 839335b943fSBjoern A. Zeeb #ifdef DDB 840335b943fSBjoern A. Zeeb struct llentry_sa { 841335b943fSBjoern A. Zeeb struct llentry base; 842335b943fSBjoern A. Zeeb struct sockaddr l3_addr; 843335b943fSBjoern A. Zeeb }; 844335b943fSBjoern A. Zeeb 845335b943fSBjoern A. Zeeb static void 846335b943fSBjoern A. Zeeb llatbl_lle_show(struct llentry_sa *la) 847335b943fSBjoern A. Zeeb { 848335b943fSBjoern A. Zeeb struct llentry *lle; 849335b943fSBjoern A. Zeeb uint8_t octet[6]; 850335b943fSBjoern A. Zeeb 851335b943fSBjoern A. Zeeb lle = &la->base; 852335b943fSBjoern A. Zeeb db_printf("lle=%p\n", lle); 8530f8d79d9SMatt Macy db_printf(" lle_next=%p\n", lle->lle_next.cle_next); 854335b943fSBjoern A. Zeeb db_printf(" lle_lock=%p\n", &lle->lle_lock); 855335b943fSBjoern A. Zeeb db_printf(" lle_tbl=%p\n", lle->lle_tbl); 856335b943fSBjoern A. Zeeb db_printf(" lle_head=%p\n", lle->lle_head); 857335b943fSBjoern A. Zeeb db_printf(" la_hold=%p\n", lle->la_hold); 858e162ea60SGeorge V. Neville-Neil db_printf(" la_numheld=%d\n", lle->la_numheld); 859335b943fSBjoern A. Zeeb db_printf(" la_expire=%ju\n", (uintmax_t)lle->la_expire); 860335b943fSBjoern A. Zeeb db_printf(" la_flags=0x%04x\n", lle->la_flags); 861335b943fSBjoern A. Zeeb db_printf(" la_asked=%u\n", lle->la_asked); 862335b943fSBjoern A. Zeeb db_printf(" la_preempt=%u\n", lle->la_preempt); 863335b943fSBjoern A. Zeeb db_printf(" ln_state=%d\n", lle->ln_state); 864335b943fSBjoern A. Zeeb db_printf(" ln_router=%u\n", lle->ln_router); 865335b943fSBjoern A. Zeeb db_printf(" ln_ntick=%ju\n", (uintmax_t)lle->ln_ntick); 866335b943fSBjoern A. Zeeb db_printf(" lle_refcnt=%d\n", lle->lle_refcnt); 8674fb3a820SAlexander V. Chernikov bcopy(lle->ll_addr, octet, sizeof(octet)); 868335b943fSBjoern A. Zeeb db_printf(" ll_addr=%02x:%02x:%02x:%02x:%02x:%02x\n", 869335b943fSBjoern A. Zeeb octet[0], octet[1], octet[2], octet[3], octet[4], octet[5]); 8700447c136SAlexander V. Chernikov db_printf(" lle_timer=%p\n", &lle->lle_timer); 871335b943fSBjoern A. Zeeb 872335b943fSBjoern A. Zeeb switch (la->l3_addr.sa_family) { 873335b943fSBjoern A. Zeeb #ifdef INET 874335b943fSBjoern A. Zeeb case AF_INET: 875335b943fSBjoern A. Zeeb { 876335b943fSBjoern A. Zeeb struct sockaddr_in *sin; 877335b943fSBjoern A. Zeeb char l3s[INET_ADDRSTRLEN]; 878335b943fSBjoern A. Zeeb 879335b943fSBjoern A. Zeeb sin = (struct sockaddr_in *)&la->l3_addr; 880335b943fSBjoern A. Zeeb inet_ntoa_r(sin->sin_addr, l3s); 881335b943fSBjoern A. Zeeb db_printf(" l3_addr=%s\n", l3s); 882335b943fSBjoern A. Zeeb break; 883335b943fSBjoern A. Zeeb } 884335b943fSBjoern A. Zeeb #endif 885335b943fSBjoern A. Zeeb #ifdef INET6 886335b943fSBjoern A. Zeeb case AF_INET6: 887335b943fSBjoern A. Zeeb { 888335b943fSBjoern A. Zeeb struct sockaddr_in6 *sin6; 889335b943fSBjoern A. Zeeb char l3s[INET6_ADDRSTRLEN]; 890335b943fSBjoern A. Zeeb 891335b943fSBjoern A. Zeeb sin6 = (struct sockaddr_in6 *)&la->l3_addr; 892335b943fSBjoern A. Zeeb ip6_sprintf(l3s, &sin6->sin6_addr); 893335b943fSBjoern A. Zeeb db_printf(" l3_addr=%s\n", l3s); 894335b943fSBjoern A. Zeeb break; 895335b943fSBjoern A. Zeeb } 896335b943fSBjoern A. Zeeb #endif 897335b943fSBjoern A. Zeeb default: 898335b943fSBjoern A. Zeeb db_printf(" l3_addr=N/A (af=%d)\n", la->l3_addr.sa_family); 899335b943fSBjoern A. Zeeb break; 900335b943fSBjoern A. Zeeb } 901335b943fSBjoern A. Zeeb } 902335b943fSBjoern A. Zeeb 903335b943fSBjoern A. Zeeb DB_SHOW_COMMAND(llentry, db_show_llentry) 904335b943fSBjoern A. Zeeb { 905335b943fSBjoern A. Zeeb 906335b943fSBjoern A. Zeeb if (!have_addr) { 907335b943fSBjoern A. Zeeb db_printf("usage: show llentry <struct llentry *>\n"); 908335b943fSBjoern A. Zeeb return; 909335b943fSBjoern A. Zeeb } 910335b943fSBjoern A. Zeeb 911335b943fSBjoern A. Zeeb llatbl_lle_show((struct llentry_sa *)addr); 912335b943fSBjoern A. Zeeb } 913335b943fSBjoern A. Zeeb 914335b943fSBjoern A. Zeeb static void 915335b943fSBjoern A. Zeeb llatbl_llt_show(struct lltable *llt) 916335b943fSBjoern A. Zeeb { 917335b943fSBjoern A. Zeeb int i; 918335b943fSBjoern A. Zeeb struct llentry *lle; 919335b943fSBjoern A. Zeeb 920335b943fSBjoern A. Zeeb db_printf("llt=%p llt_af=%d llt_ifp=%p\n", 921335b943fSBjoern A. Zeeb llt, llt->llt_af, llt->llt_ifp); 922335b943fSBjoern A. Zeeb 9233a749863SAlexander V. Chernikov for (i = 0; i < llt->llt_hsize; i++) { 9244f6c66ccSMatt Macy CK_LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { 925335b943fSBjoern A. Zeeb 926335b943fSBjoern A. Zeeb llatbl_lle_show((struct llentry_sa *)lle); 927335b943fSBjoern A. Zeeb if (db_pager_quit) 928335b943fSBjoern A. Zeeb return; 929335b943fSBjoern A. Zeeb } 930335b943fSBjoern A. Zeeb } 931335b943fSBjoern A. Zeeb } 932335b943fSBjoern A. Zeeb 933335b943fSBjoern A. Zeeb DB_SHOW_COMMAND(lltable, db_show_lltable) 934335b943fSBjoern A. Zeeb { 935335b943fSBjoern A. Zeeb 936335b943fSBjoern A. Zeeb if (!have_addr) { 937335b943fSBjoern A. Zeeb db_printf("usage: show lltable <struct lltable *>\n"); 938335b943fSBjoern A. Zeeb return; 939335b943fSBjoern A. Zeeb } 940335b943fSBjoern A. Zeeb 941335b943fSBjoern A. Zeeb llatbl_llt_show((struct lltable *)addr); 942335b943fSBjoern A. Zeeb } 943335b943fSBjoern A. Zeeb 944335b943fSBjoern A. Zeeb DB_SHOW_ALL_COMMAND(lltables, db_show_all_lltables) 945335b943fSBjoern A. Zeeb { 946335b943fSBjoern A. Zeeb VNET_ITERATOR_DECL(vnet_iter); 947335b943fSBjoern A. Zeeb struct lltable *llt; 948335b943fSBjoern A. Zeeb 949335b943fSBjoern A. Zeeb VNET_FOREACH(vnet_iter) { 950335b943fSBjoern A. Zeeb CURVNET_SET_QUIET(vnet_iter); 951335b943fSBjoern A. Zeeb #ifdef VIMAGE 952335b943fSBjoern A. Zeeb db_printf("vnet=%p\n", curvnet); 953335b943fSBjoern A. Zeeb #endif 954335b943fSBjoern A. Zeeb SLIST_FOREACH(llt, &V_lltables, llt_link) { 955335b943fSBjoern A. Zeeb db_printf("llt=%p llt_af=%d llt_ifp=%p(%s)\n", 956335b943fSBjoern A. Zeeb llt, llt->llt_af, llt->llt_ifp, 957335b943fSBjoern A. Zeeb (llt->llt_ifp != NULL) ? 958335b943fSBjoern A. Zeeb llt->llt_ifp->if_xname : "?"); 959335b943fSBjoern A. Zeeb if (have_addr && addr != 0) /* verbose */ 960335b943fSBjoern A. Zeeb llatbl_llt_show(llt); 961335b943fSBjoern A. Zeeb if (db_pager_quit) { 962335b943fSBjoern A. Zeeb CURVNET_RESTORE(); 963335b943fSBjoern A. Zeeb return; 964335b943fSBjoern A. Zeeb } 965335b943fSBjoern A. Zeeb } 966335b943fSBjoern A. Zeeb CURVNET_RESTORE(); 967335b943fSBjoern A. Zeeb } 968335b943fSBjoern A. Zeeb } 969335b943fSBjoern A. Zeeb #endif 970