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> 3882f39c91SKip Macy #include <sys/malloc.h> 3982f39c91SKip Macy #include <sys/mbuf.h> 4082f39c91SKip Macy #include <sys/syslog.h> 4182f39c91SKip Macy #include <sys/sysctl.h> 4282f39c91SKip Macy #include <sys/socket.h> 4382f39c91SKip Macy #include <sys/kernel.h> 4482f39c91SKip Macy #include <sys/lock.h> 4582f39c91SKip Macy #include <sys/mutex.h> 4682f39c91SKip Macy #include <sys/rwlock.h> 4782f39c91SKip Macy 48335b943fSBjoern A. Zeeb #ifdef DDB 49335b943fSBjoern A. Zeeb #include <ddb/ddb.h> 50335b943fSBjoern A. Zeeb #endif 51335b943fSBjoern A. Zeeb 5282f39c91SKip Macy #include <vm/uma.h> 5382f39c91SKip Macy 5482f39c91SKip Macy #include <netinet/in.h> 5582f39c91SKip Macy #include <net/if_llatbl.h> 5682f39c91SKip Macy #include <net/if.h> 5782f39c91SKip Macy #include <net/if_dl.h> 5882f39c91SKip Macy #include <net/if_var.h> 5982f39c91SKip Macy #include <net/route.h> 60530c0060SRobert Watson #include <net/vnet.h> 6182f39c91SKip Macy #include <netinet/if_ether.h> 6282f39c91SKip Macy #include <netinet6/in6_var.h> 6382f39c91SKip Macy #include <netinet6/nd6.h> 6482f39c91SKip Macy 6582f39c91SKip Macy MALLOC_DEFINE(M_LLTABLE, "lltable", "link level address tables"); 6682f39c91SKip Macy 6776d68eccSBjoern A. Zeeb static VNET_DEFINE(SLIST_HEAD(, lltable), lltables) = 6876d68eccSBjoern A. Zeeb SLIST_HEAD_INITIALIZER(lltables); 69989e0411SMarko Zec #define V_lltables VNET(lltables) 7082f39c91SKip Macy 71199511bcSAndrey V. Elsukov static struct rwlock lltable_list_lock; 72199511bcSAndrey V. Elsukov RW_SYSINIT(lltable_list_lock, &lltable_list_lock, "lltable_list_lock"); 73199511bcSAndrey V. Elsukov #define LLTABLE_LIST_RLOCK() rw_rlock(&lltable_list_lock) 74199511bcSAndrey V. Elsukov #define LLTABLE_LIST_RUNLOCK() rw_runlock(&lltable_list_lock) 75199511bcSAndrey V. Elsukov #define LLTABLE_LIST_WLOCK() rw_wlock(&lltable_list_lock) 76199511bcSAndrey V. Elsukov #define LLTABLE_LIST_WUNLOCK() rw_wunlock(&lltable_list_lock) 77199511bcSAndrey V. Elsukov #define LLTABLE_LIST_LOCK_ASSERT() rw_assert(&lltable_list_lock, RA_LOCKED) 78dc56e98fSRobert Watson 79721cd2e0SAlexander V. Chernikov static void lltable_unlink(struct lltable *llt); 8011cdad98SAlexander V. Chernikov static void llentries_unlink(struct lltable *llt, struct llentries *head); 8111cdad98SAlexander V. Chernikov 8211cdad98SAlexander V. Chernikov static void htable_unlink_entry(struct llentry *lle); 8311cdad98SAlexander V. Chernikov static void htable_link_entry(struct lltable *llt, struct llentry *lle); 8411cdad98SAlexander V. Chernikov static int htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, 8511cdad98SAlexander V. Chernikov void *farg); 8611cdad98SAlexander V. Chernikov 8711cdad98SAlexander V. Chernikov /* 8811cdad98SAlexander V. Chernikov * Dump lle state for a specific address family. 8911cdad98SAlexander V. Chernikov */ 9011cdad98SAlexander V. Chernikov static int 9111cdad98SAlexander V. Chernikov lltable_dump_af(struct lltable *llt, struct sysctl_req *wr) 9211cdad98SAlexander V. Chernikov { 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 10111cdad98SAlexander V. Chernikov IF_AFDATA_RLOCK(llt->llt_ifp); 10211cdad98SAlexander V. Chernikov error = lltable_foreach_lle(llt, 10311cdad98SAlexander V. Chernikov (llt_foreach_cb_t *)llt->llt_dump_entry, wr); 10411cdad98SAlexander V. Chernikov IF_AFDATA_RUNLOCK(llt->llt_ifp); 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 /* 13211cdad98SAlexander V. Chernikov * Common function helpers for chained hash table. 13311cdad98SAlexander V. Chernikov */ 13411cdad98SAlexander V. Chernikov 13511cdad98SAlexander V. Chernikov /* 13611cdad98SAlexander V. Chernikov * Runs specified callback for each entry in @llt. 13711cdad98SAlexander V. Chernikov * Caller does the locking. 13811cdad98SAlexander V. Chernikov * 13911cdad98SAlexander V. Chernikov */ 14011cdad98SAlexander V. Chernikov static int 14111cdad98SAlexander V. Chernikov htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg) 14211cdad98SAlexander V. Chernikov { 14311cdad98SAlexander V. Chernikov struct llentry *lle, *next; 14411cdad98SAlexander V. Chernikov int i, error; 14511cdad98SAlexander V. Chernikov 14611cdad98SAlexander V. Chernikov error = 0; 14711cdad98SAlexander V. Chernikov 14841cb42a6SAlexander V. Chernikov for (i = 0; i < llt->llt_hsize; i++) { 1494f6c66ccSMatt Macy CK_LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) { 15011cdad98SAlexander V. Chernikov error = f(llt, lle, farg); 15111cdad98SAlexander V. Chernikov if (error != 0) 15211cdad98SAlexander V. Chernikov break; 15311cdad98SAlexander V. Chernikov } 15411cdad98SAlexander V. Chernikov } 15511cdad98SAlexander V. Chernikov 15611cdad98SAlexander V. Chernikov return (error); 15711cdad98SAlexander V. Chernikov } 15811cdad98SAlexander V. Chernikov 15911cdad98SAlexander V. Chernikov static void 16011cdad98SAlexander V. Chernikov htable_link_entry(struct lltable *llt, struct llentry *lle) 16111cdad98SAlexander V. Chernikov { 16211cdad98SAlexander V. Chernikov struct llentries *lleh; 16311cdad98SAlexander V. Chernikov uint32_t hashidx; 16411cdad98SAlexander V. Chernikov 16511cdad98SAlexander V. Chernikov if ((lle->la_flags & LLE_LINKED) != 0) 16611cdad98SAlexander V. Chernikov return; 16711cdad98SAlexander V. Chernikov 16811cdad98SAlexander V. Chernikov IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp); 16911cdad98SAlexander V. Chernikov 1703a749863SAlexander V. Chernikov hashidx = llt->llt_hash(lle, llt->llt_hsize); 17111cdad98SAlexander V. Chernikov lleh = &llt->lle_head[hashidx]; 17211cdad98SAlexander V. Chernikov 17311cdad98SAlexander V. Chernikov lle->lle_tbl = llt; 17411cdad98SAlexander V. Chernikov lle->lle_head = lleh; 17511cdad98SAlexander V. Chernikov lle->la_flags |= LLE_LINKED; 1764f6c66ccSMatt Macy CK_LIST_INSERT_HEAD(lleh, lle, lle_next); 17711cdad98SAlexander V. Chernikov } 17811cdad98SAlexander V. Chernikov 17911cdad98SAlexander V. Chernikov static void 18011cdad98SAlexander V. Chernikov htable_unlink_entry(struct llentry *lle) 18111cdad98SAlexander V. Chernikov { 18211cdad98SAlexander V. Chernikov 18311cdad98SAlexander V. Chernikov if ((lle->la_flags & LLE_LINKED) != 0) { 18411cdad98SAlexander V. Chernikov IF_AFDATA_WLOCK_ASSERT(lle->lle_tbl->llt_ifp); 1854f6c66ccSMatt Macy CK_LIST_REMOVE(lle, lle_next); 18611cdad98SAlexander V. Chernikov lle->la_flags &= ~(LLE_VALID | LLE_LINKED); 18711cdad98SAlexander V. Chernikov #if 0 18811cdad98SAlexander V. Chernikov lle->lle_tbl = NULL; 18911cdad98SAlexander V. Chernikov lle->lle_head = NULL; 19011cdad98SAlexander V. Chernikov #endif 19111cdad98SAlexander V. Chernikov } 19211cdad98SAlexander V. Chernikov } 19311cdad98SAlexander V. Chernikov 19411cdad98SAlexander V. Chernikov struct prefix_match_data { 1953e7a2321SAlexander V. Chernikov const struct sockaddr *addr; 19611cdad98SAlexander V. Chernikov const struct sockaddr *mask; 19711cdad98SAlexander V. Chernikov struct llentries dchain; 19811cdad98SAlexander V. Chernikov u_int flags; 19911cdad98SAlexander V. Chernikov }; 20011cdad98SAlexander V. Chernikov 20111cdad98SAlexander V. Chernikov static int 20211cdad98SAlexander V. Chernikov htable_prefix_free_cb(struct lltable *llt, struct llentry *lle, void *farg) 20311cdad98SAlexander V. Chernikov { 20411cdad98SAlexander V. Chernikov struct prefix_match_data *pmd; 20511cdad98SAlexander V. Chernikov 20611cdad98SAlexander V. Chernikov pmd = (struct prefix_match_data *)farg; 20711cdad98SAlexander V. Chernikov 2083e7a2321SAlexander V. Chernikov if (llt->llt_match_prefix(pmd->addr, pmd->mask, pmd->flags, lle)) { 20911cdad98SAlexander V. Chernikov LLE_WLOCK(lle); 2100f8d79d9SMatt Macy CK_LIST_INSERT_HEAD(&pmd->dchain, lle, lle_chain); 21111cdad98SAlexander V. Chernikov } 21211cdad98SAlexander V. Chernikov 21311cdad98SAlexander V. Chernikov return (0); 21411cdad98SAlexander V. Chernikov } 21511cdad98SAlexander V. Chernikov 21611cdad98SAlexander V. Chernikov static void 2173e7a2321SAlexander V. Chernikov htable_prefix_free(struct lltable *llt, const struct sockaddr *addr, 21811cdad98SAlexander V. Chernikov const struct sockaddr *mask, u_int flags) 21911cdad98SAlexander V. Chernikov { 22011cdad98SAlexander V. Chernikov struct llentry *lle, *next; 22111cdad98SAlexander V. Chernikov struct prefix_match_data pmd; 22211cdad98SAlexander V. Chernikov 22311cdad98SAlexander V. Chernikov bzero(&pmd, sizeof(pmd)); 2243e7a2321SAlexander V. Chernikov pmd.addr = addr; 22511cdad98SAlexander V. Chernikov pmd.mask = mask; 22611cdad98SAlexander V. Chernikov pmd.flags = flags; 2274f6c66ccSMatt Macy CK_LIST_INIT(&pmd.dchain); 22811cdad98SAlexander V. Chernikov 22911cdad98SAlexander V. Chernikov IF_AFDATA_WLOCK(llt->llt_ifp); 23011cdad98SAlexander V. Chernikov /* Push matching lles to chain */ 23111cdad98SAlexander V. Chernikov lltable_foreach_lle(llt, htable_prefix_free_cb, &pmd); 23211cdad98SAlexander V. Chernikov 23311cdad98SAlexander V. Chernikov llentries_unlink(llt, &pmd.dchain); 23411cdad98SAlexander V. Chernikov IF_AFDATA_WUNLOCK(llt->llt_ifp); 23511cdad98SAlexander V. Chernikov 2360f8d79d9SMatt Macy CK_LIST_FOREACH_SAFE(lle, &pmd.dchain, lle_chain, next) 2375a255516SAlexander V. Chernikov lltable_free_entry(llt, lle); 23811cdad98SAlexander V. Chernikov } 23911cdad98SAlexander V. Chernikov 24011cdad98SAlexander V. Chernikov static void 24141cb42a6SAlexander V. Chernikov htable_free_tbl(struct lltable *llt) 24241cb42a6SAlexander V. Chernikov { 24341cb42a6SAlexander V. Chernikov 24441cb42a6SAlexander V. Chernikov free(llt->lle_head, M_LLTABLE); 24541cb42a6SAlexander V. Chernikov free(llt, M_LLTABLE); 24641cb42a6SAlexander V. Chernikov } 24741cb42a6SAlexander V. Chernikov 248721cd2e0SAlexander V. Chernikov static void 24911cdad98SAlexander V. Chernikov llentries_unlink(struct lltable *llt, struct llentries *head) 25011cdad98SAlexander V. Chernikov { 25111cdad98SAlexander V. Chernikov struct llentry *lle, *next; 25211cdad98SAlexander V. Chernikov 2530f8d79d9SMatt Macy CK_LIST_FOREACH_SAFE(lle, head, lle_chain, next) 25411cdad98SAlexander V. Chernikov llt->llt_unlink_entry(lle); 25511cdad98SAlexander V. Chernikov } 25611cdad98SAlexander V. Chernikov 25711cdad98SAlexander V. Chernikov /* 25811cdad98SAlexander V. Chernikov * Helper function used to drop all mbufs in hold queue. 259e162ea60SGeorge V. Neville-Neil * 260e162ea60SGeorge V. Neville-Neil * Returns the number of held packets, if any, that were dropped. 26182f39c91SKip Macy */ 262e162ea60SGeorge V. Neville-Neil size_t 26311cdad98SAlexander V. Chernikov lltable_drop_entry_queue(struct llentry *lle) 26482f39c91SKip Macy { 265e162ea60SGeorge V. Neville-Neil size_t pkts_dropped; 266e162ea60SGeorge V. Neville-Neil struct mbuf *next; 26782f39c91SKip Macy 26882f39c91SKip Macy LLE_WLOCK_ASSERT(lle); 26982f39c91SKip Macy 270ea537929SGleb Smirnoff pkts_dropped = 0; 271e162ea60SGeorge V. Neville-Neil while ((lle->la_numheld > 0) && (lle->la_hold != NULL)) { 272e162ea60SGeorge V. Neville-Neil next = lle->la_hold->m_nextpkt; 27382f39c91SKip Macy m_freem(lle->la_hold); 274e162ea60SGeorge V. Neville-Neil lle->la_hold = next; 275e162ea60SGeorge V. Neville-Neil lle->la_numheld--; 276e162ea60SGeorge V. Neville-Neil pkts_dropped++; 277e162ea60SGeorge V. Neville-Neil } 278e162ea60SGeorge V. Neville-Neil 279e162ea60SGeorge V. Neville-Neil KASSERT(lle->la_numheld == 0, 2807b3b099eSKonstantin Belousov ("%s: la_numheld %d > 0, pkts_droped %zd", __func__, 281e162ea60SGeorge V. Neville-Neil lle->la_numheld, pkts_dropped)); 28282f39c91SKip Macy 28311cdad98SAlexander V. Chernikov return (pkts_dropped); 28411cdad98SAlexander V. Chernikov } 28511cdad98SAlexander V. Chernikov 286ddd208f7SAlexander V. Chernikov void 287ddd208f7SAlexander V. Chernikov lltable_set_entry_addr(struct ifnet *ifp, struct llentry *lle, 2884fb3a820SAlexander V. Chernikov const char *linkhdr, size_t linkhdrsize, int lladdr_off) 289ddd208f7SAlexander V. Chernikov { 290ddd208f7SAlexander V. Chernikov 2914fb3a820SAlexander V. Chernikov memcpy(lle->r_linkdata, linkhdr, linkhdrsize); 2924fb3a820SAlexander V. Chernikov lle->r_hdrlen = linkhdrsize; 2934fb3a820SAlexander V. Chernikov lle->ll_addr = &lle->r_linkdata[lladdr_off]; 294ddd208f7SAlexander V. Chernikov lle->la_flags |= LLE_VALID; 295f8aee88fSAlexander V. Chernikov lle->r_flags |= RLLE_VALID; 296ddd208f7SAlexander V. Chernikov } 297ddd208f7SAlexander V. Chernikov 29811cdad98SAlexander V. Chernikov /* 29912cb7521SAlexander V. Chernikov * Tries to update @lle link-level address. 30012cb7521SAlexander V. Chernikov * Since update requires AFDATA WLOCK, function 30112cb7521SAlexander V. Chernikov * drops @lle lock, acquires AFDATA lock and then acquires 30212cb7521SAlexander V. Chernikov * @lle lock to maintain lock order. 30312cb7521SAlexander V. Chernikov * 30412cb7521SAlexander V. Chernikov * Returns 1 on success. 30512cb7521SAlexander V. Chernikov */ 30612cb7521SAlexander V. Chernikov int 30712cb7521SAlexander V. Chernikov lltable_try_set_entry_addr(struct ifnet *ifp, struct llentry *lle, 3084fb3a820SAlexander V. Chernikov const char *linkhdr, size_t linkhdrsize, int lladdr_off) 30912cb7521SAlexander V. Chernikov { 31012cb7521SAlexander V. Chernikov 31112cb7521SAlexander V. Chernikov /* Perform real LLE update */ 31212cb7521SAlexander V. Chernikov /* use afdata WLOCK to update fields */ 31312cb7521SAlexander V. Chernikov LLE_WLOCK_ASSERT(lle); 31412cb7521SAlexander V. Chernikov LLE_ADDREF(lle); 31512cb7521SAlexander V. Chernikov LLE_WUNLOCK(lle); 31612cb7521SAlexander V. Chernikov IF_AFDATA_WLOCK(ifp); 31712cb7521SAlexander V. Chernikov LLE_WLOCK(lle); 31812cb7521SAlexander V. Chernikov 31912cb7521SAlexander V. Chernikov /* 32012cb7521SAlexander V. Chernikov * Since we droppped LLE lock, other thread might have deleted 32112cb7521SAlexander V. Chernikov * this lle. Check and return 32212cb7521SAlexander V. Chernikov */ 32312cb7521SAlexander V. Chernikov if ((lle->la_flags & LLE_DELETED) != 0) { 32412cb7521SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 32512cb7521SAlexander V. Chernikov LLE_FREE_LOCKED(lle); 32612cb7521SAlexander V. Chernikov return (0); 32712cb7521SAlexander V. Chernikov } 32812cb7521SAlexander V. Chernikov 32912cb7521SAlexander V. Chernikov /* Update data */ 3304fb3a820SAlexander V. Chernikov lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize, lladdr_off); 33112cb7521SAlexander V. Chernikov 33212cb7521SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 33312cb7521SAlexander V. Chernikov 33412cb7521SAlexander V. Chernikov LLE_REMREF(lle); 33512cb7521SAlexander V. Chernikov 33612cb7521SAlexander V. Chernikov return (1); 33712cb7521SAlexander V. Chernikov } 33812cb7521SAlexander V. Chernikov 33912cb7521SAlexander V. Chernikov /* 3404fb3a820SAlexander V. Chernikov * Helper function used to pre-compute full/partial link-layer 3414fb3a820SAlexander V. Chernikov * header data suitable for feeding into if_output(). 3424fb3a820SAlexander V. Chernikov */ 3434fb3a820SAlexander V. Chernikov int 3444fb3a820SAlexander V. Chernikov lltable_calc_llheader(struct ifnet *ifp, int family, char *lladdr, 3454fb3a820SAlexander V. Chernikov char *buf, size_t *bufsize, int *lladdr_off) 3464fb3a820SAlexander V. Chernikov { 3474fb3a820SAlexander V. Chernikov struct if_encap_req ereq; 3484fb3a820SAlexander V. Chernikov int error; 3494fb3a820SAlexander V. Chernikov 3504fb3a820SAlexander V. Chernikov bzero(buf, *bufsize); 3514fb3a820SAlexander V. Chernikov bzero(&ereq, sizeof(ereq)); 3524fb3a820SAlexander V. Chernikov ereq.buf = buf; 3534fb3a820SAlexander V. Chernikov ereq.bufsize = *bufsize; 3544fb3a820SAlexander V. Chernikov ereq.rtype = IFENCAP_LL; 3554fb3a820SAlexander V. Chernikov ereq.family = family; 3564fb3a820SAlexander V. Chernikov ereq.lladdr = lladdr; 3574fb3a820SAlexander V. Chernikov ereq.lladdr_len = ifp->if_addrlen; 3584fb3a820SAlexander V. Chernikov error = ifp->if_requestencap(ifp, &ereq); 3594fb3a820SAlexander V. Chernikov if (error == 0) { 3604fb3a820SAlexander V. Chernikov *bufsize = ereq.bufsize; 3614fb3a820SAlexander V. Chernikov *lladdr_off = ereq.lladdr_off; 3624fb3a820SAlexander V. Chernikov } 3634fb3a820SAlexander V. Chernikov 3644fb3a820SAlexander V. Chernikov return (error); 3654fb3a820SAlexander V. Chernikov } 3664fb3a820SAlexander V. Chernikov 3674fb3a820SAlexander V. Chernikov /* 3684fb3a820SAlexander V. Chernikov * Update link-layer header for given @lle after 3694fb3a820SAlexander V. Chernikov * interface lladdr was changed. 3704fb3a820SAlexander V. Chernikov */ 3714fb3a820SAlexander V. Chernikov static int 3724fb3a820SAlexander V. Chernikov llentry_update_ifaddr(struct lltable *llt, struct llentry *lle, void *farg) 3734fb3a820SAlexander V. Chernikov { 3744fb3a820SAlexander V. Chernikov struct ifnet *ifp; 3754fb3a820SAlexander V. Chernikov u_char linkhdr[LLE_MAX_LINKHDR]; 3764fb3a820SAlexander V. Chernikov size_t linkhdrsize; 3774fb3a820SAlexander V. Chernikov u_char *lladdr; 3784fb3a820SAlexander V. Chernikov int lladdr_off; 3794fb3a820SAlexander V. Chernikov 3804fb3a820SAlexander V. Chernikov ifp = (struct ifnet *)farg; 3814fb3a820SAlexander V. Chernikov 3824fb3a820SAlexander V. Chernikov lladdr = lle->ll_addr; 3834fb3a820SAlexander V. Chernikov 3844fb3a820SAlexander V. Chernikov LLE_WLOCK(lle); 3854fb3a820SAlexander V. Chernikov if ((lle->la_flags & LLE_VALID) == 0) { 3864fb3a820SAlexander V. Chernikov LLE_WUNLOCK(lle); 3874fb3a820SAlexander V. Chernikov return (0); 3884fb3a820SAlexander V. Chernikov } 3894fb3a820SAlexander V. Chernikov 3904fb3a820SAlexander V. Chernikov if ((lle->la_flags & LLE_IFADDR) != 0) 3914fb3a820SAlexander V. Chernikov lladdr = IF_LLADDR(ifp); 3924fb3a820SAlexander V. Chernikov 3934fb3a820SAlexander V. Chernikov linkhdrsize = sizeof(linkhdr); 3944fb3a820SAlexander V. Chernikov lltable_calc_llheader(ifp, llt->llt_af, lladdr, linkhdr, &linkhdrsize, 3954fb3a820SAlexander V. Chernikov &lladdr_off); 3964fb3a820SAlexander V. Chernikov memcpy(lle->r_linkdata, linkhdr, linkhdrsize); 3974fb3a820SAlexander V. Chernikov LLE_WUNLOCK(lle); 3984fb3a820SAlexander V. Chernikov 3994fb3a820SAlexander V. Chernikov return (0); 4004fb3a820SAlexander V. Chernikov } 4014fb3a820SAlexander V. Chernikov 4024fb3a820SAlexander V. Chernikov /* 4034fb3a820SAlexander V. Chernikov * Update all calculated headers for given @llt 4044fb3a820SAlexander V. Chernikov */ 4054fb3a820SAlexander V. Chernikov void 4064fb3a820SAlexander V. Chernikov lltable_update_ifaddr(struct lltable *llt) 4074fb3a820SAlexander V. Chernikov { 4084fb3a820SAlexander V. Chernikov 4094fb3a820SAlexander V. Chernikov if (llt->llt_ifp->if_flags & IFF_LOOPBACK) 4104fb3a820SAlexander V. Chernikov return; 4114fb3a820SAlexander V. Chernikov 4124fb3a820SAlexander V. Chernikov IF_AFDATA_WLOCK(llt->llt_ifp); 4134fb3a820SAlexander V. Chernikov lltable_foreach_lle(llt, llentry_update_ifaddr, llt->llt_ifp); 4144fb3a820SAlexander V. Chernikov IF_AFDATA_WUNLOCK(llt->llt_ifp); 4154fb3a820SAlexander V. Chernikov } 4164fb3a820SAlexander V. Chernikov 4174fb3a820SAlexander V. Chernikov /* 4185a255516SAlexander V. Chernikov * 419a4641f4eSPedro F. Giffuni * Performs generic cleanup routines and frees lle. 4205a255516SAlexander V. Chernikov * 4215a255516SAlexander V. Chernikov * Called for non-linked entries, with callouts and 4225a255516SAlexander V. Chernikov * other AF-specific cleanups performed. 4235a255516SAlexander V. Chernikov * 4245a255516SAlexander V. Chernikov * @lle must be passed WLOCK'ed 42511cdad98SAlexander V. Chernikov * 42611cdad98SAlexander V. Chernikov * Returns the number of held packets, if any, that were dropped. 42711cdad98SAlexander V. Chernikov */ 42811cdad98SAlexander V. Chernikov size_t 42911cdad98SAlexander V. Chernikov llentry_free(struct llentry *lle) 43011cdad98SAlexander V. Chernikov { 43111cdad98SAlexander V. Chernikov size_t pkts_dropped; 43211cdad98SAlexander V. Chernikov 43311cdad98SAlexander V. Chernikov LLE_WLOCK_ASSERT(lle); 43411cdad98SAlexander V. Chernikov 435d3cdb716SAlexander V. Chernikov KASSERT((lle->la_flags & LLE_LINKED) == 0, ("freeing linked lle")); 43611cdad98SAlexander V. Chernikov 43711cdad98SAlexander V. Chernikov pkts_dropped = lltable_drop_entry_queue(lle); 43811cdad98SAlexander V. Chernikov 439*acf673edSAndrey V. Elsukov /* cancel timer */ 440*acf673edSAndrey V. Elsukov if (callout_stop(&lle->lle_timer) > 0) 441*acf673edSAndrey V. Elsukov LLE_REMREF(lle); 44282f39c91SKip Macy LLE_FREE_LOCKED(lle); 443e162ea60SGeorge V. Neville-Neil 444e162ea60SGeorge V. Neville-Neil return (pkts_dropped); 44582f39c91SKip Macy } 44682f39c91SKip Macy 447adfc35ffSKip Macy /* 448b1d86af7SGleb Smirnoff * (al)locate an llentry for address dst (equivalent to rtalloc for new-arp). 449e94ba2ceSKip Macy * 450b1d86af7SGleb Smirnoff * If found the llentry * is returned referenced and unlocked. 451adfc35ffSKip Macy */ 452b1d86af7SGleb Smirnoff struct llentry * 453b1d86af7SGleb Smirnoff llentry_alloc(struct ifnet *ifp, struct lltable *lt, 454b1d86af7SGleb Smirnoff struct sockaddr_storage *dst) 455c8da95acSKip Macy { 4565a255516SAlexander V. Chernikov struct llentry *la, *la_tmp; 457c8da95acSKip Macy 458c8da95acSKip Macy IF_AFDATA_RLOCK(ifp); 459b1d86af7SGleb Smirnoff la = lla_lookup(lt, LLE_EXCLUSIVE, (struct sockaddr *)dst); 460c8da95acSKip Macy IF_AFDATA_RUNLOCK(ifp); 461b1d86af7SGleb Smirnoff 462b1d86af7SGleb Smirnoff if (la != NULL) { 463c8da95acSKip Macy LLE_ADDREF(la); 464c8da95acSKip Macy LLE_WUNLOCK(la); 4655a255516SAlexander V. Chernikov return (la); 4665a255516SAlexander V. Chernikov } 4675a255516SAlexander V. Chernikov 4685a255516SAlexander V. Chernikov if ((ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0) { 4695a255516SAlexander V. Chernikov la = lltable_alloc_entry(lt, 0, (struct sockaddr *)dst); 4705a255516SAlexander V. Chernikov if (la == NULL) 4715a255516SAlexander V. Chernikov return (NULL); 4725a255516SAlexander V. Chernikov IF_AFDATA_WLOCK(ifp); 4735a255516SAlexander V. Chernikov LLE_WLOCK(la); 4745a255516SAlexander V. Chernikov /* Prefer any existing LLE over newly-created one */ 4755a255516SAlexander V. Chernikov la_tmp = lla_lookup(lt, LLE_EXCLUSIVE, (struct sockaddr *)dst); 4765a255516SAlexander V. Chernikov if (la_tmp == NULL) 4775a255516SAlexander V. Chernikov lltable_link_entry(lt, la); 4785a255516SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 4795a255516SAlexander V. Chernikov if (la_tmp != NULL) { 4805a255516SAlexander V. Chernikov lltable_free_entry(lt, la); 4815a255516SAlexander V. Chernikov la = la_tmp; 4825a255516SAlexander V. Chernikov } 4835a255516SAlexander V. Chernikov LLE_ADDREF(la); 4845a255516SAlexander V. Chernikov LLE_WUNLOCK(la); 485b1d86af7SGleb Smirnoff } 486c8da95acSKip Macy 487b1d86af7SGleb Smirnoff return (la); 488c8da95acSKip Macy } 489c8da95acSKip Macy 49082f39c91SKip Macy /* 49182f39c91SKip Macy * Free all entries from given table and free itself. 49282f39c91SKip Macy */ 49311cdad98SAlexander V. Chernikov 49411cdad98SAlexander V. Chernikov static int 49511cdad98SAlexander V. Chernikov lltable_free_cb(struct lltable *llt, struct llentry *lle, void *farg) 49611cdad98SAlexander V. Chernikov { 49711cdad98SAlexander V. Chernikov struct llentries *dchain; 49811cdad98SAlexander V. Chernikov 49911cdad98SAlexander V. Chernikov dchain = (struct llentries *)farg; 50011cdad98SAlexander V. Chernikov 50111cdad98SAlexander V. Chernikov LLE_WLOCK(lle); 5020f8d79d9SMatt Macy CK_LIST_INSERT_HEAD(dchain, lle, lle_chain); 50311cdad98SAlexander V. Chernikov 50411cdad98SAlexander V. Chernikov return (0); 50511cdad98SAlexander V. Chernikov } 50611cdad98SAlexander V. Chernikov 50711cdad98SAlexander V. Chernikov /* 50811cdad98SAlexander V. Chernikov * Free all entries from given table and free itself. 50911cdad98SAlexander V. Chernikov */ 51082f39c91SKip Macy void 51182f39c91SKip Macy lltable_free(struct lltable *llt) 51282f39c91SKip Macy { 51382f39c91SKip Macy struct llentry *lle, *next; 51411cdad98SAlexander V. Chernikov struct llentries dchain; 51582f39c91SKip Macy 51682f39c91SKip Macy KASSERT(llt != NULL, ("%s: llt is NULL", __func__)); 51782f39c91SKip Macy 518721cd2e0SAlexander V. Chernikov lltable_unlink(llt); 51982f39c91SKip Macy 5204f6c66ccSMatt Macy CK_LIST_INIT(&dchain); 521ea537929SGleb Smirnoff IF_AFDATA_WLOCK(llt->llt_ifp); 52211cdad98SAlexander V. Chernikov /* Push all lles to @dchain */ 52311cdad98SAlexander V. Chernikov lltable_foreach_lle(llt, lltable_free_cb, &dchain); 52411cdad98SAlexander V. Chernikov llentries_unlink(llt, &dchain); 52511cdad98SAlexander V. Chernikov IF_AFDATA_WUNLOCK(llt->llt_ifp); 52611cdad98SAlexander V. Chernikov 5270f8d79d9SMatt Macy CK_LIST_FOREACH_SAFE(lle, &dchain, lle_chain, next) { 52882f39c91SKip Macy llentry_free(lle); 52982f39c91SKip Macy } 53082f39c91SKip Macy 531721cd2e0SAlexander V. Chernikov llt->llt_free_tbl(llt); 53282f39c91SKip Macy } 53382f39c91SKip Macy 534fc2bfb32SBjoern A. Zeeb #if 0 53582f39c91SKip Macy void 53682f39c91SKip Macy lltable_drain(int af) 53782f39c91SKip Macy { 53882f39c91SKip Macy struct lltable *llt; 53982f39c91SKip Macy struct llentry *lle; 5403e85b721SEd Maste int i; 54182f39c91SKip Macy 542199511bcSAndrey V. Elsukov LLTABLE_LIST_RLOCK(); 543989e0411SMarko Zec SLIST_FOREACH(llt, &V_lltables, llt_link) { 54482f39c91SKip Macy if (llt->llt_af != af) 54582f39c91SKip Macy continue; 54682f39c91SKip Macy 5473a749863SAlexander V. Chernikov for (i=0; i < llt->llt_hsize; i++) { 5484f6c66ccSMatt Macy CK_LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { 549fc2bfb32SBjoern A. Zeeb LLE_WLOCK(lle); 55082f39c91SKip Macy if (lle->la_hold) { 55182f39c91SKip Macy m_freem(lle->la_hold); 55282f39c91SKip Macy lle->la_hold = NULL; 55382f39c91SKip Macy } 554fc2bfb32SBjoern A. Zeeb LLE_WUNLOCK(lle); 55582f39c91SKip Macy } 55682f39c91SKip Macy } 55782f39c91SKip Macy } 558199511bcSAndrey V. Elsukov LLTABLE_LIST_RUNLOCK(); 55982f39c91SKip Macy } 560fc2bfb32SBjoern A. Zeeb #endif 56182f39c91SKip Macy 5623e7a2321SAlexander V. Chernikov /* 5633e7a2321SAlexander V. Chernikov * Deletes an address from given lltable. 5643e7a2321SAlexander V. Chernikov * Used for userland interaction to remove 5653e7a2321SAlexander V. Chernikov * individual entries. Skips entries added by OS. 5663e7a2321SAlexander V. Chernikov */ 5673e7a2321SAlexander V. Chernikov int 5683e7a2321SAlexander V. Chernikov lltable_delete_addr(struct lltable *llt, u_int flags, 5693e7a2321SAlexander V. Chernikov const struct sockaddr *l3addr) 5703e7a2321SAlexander V. Chernikov { 5713e7a2321SAlexander V. Chernikov struct llentry *lle; 5723e7a2321SAlexander V. Chernikov struct ifnet *ifp; 5733e7a2321SAlexander V. Chernikov 5743e7a2321SAlexander V. Chernikov ifp = llt->llt_ifp; 5753e7a2321SAlexander V. Chernikov IF_AFDATA_WLOCK(ifp); 5763e7a2321SAlexander V. Chernikov lle = lla_lookup(llt, LLE_EXCLUSIVE, l3addr); 5773e7a2321SAlexander V. Chernikov 5783e7a2321SAlexander V. Chernikov if (lle == NULL) { 5793e7a2321SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 5803e7a2321SAlexander V. Chernikov return (ENOENT); 5813e7a2321SAlexander V. Chernikov } 5823e7a2321SAlexander V. Chernikov if ((lle->la_flags & LLE_IFADDR) != 0 && (flags & LLE_IFADDR) == 0) { 5833e7a2321SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 5843e7a2321SAlexander V. Chernikov LLE_WUNLOCK(lle); 5853e7a2321SAlexander V. Chernikov return (EPERM); 5863e7a2321SAlexander V. Chernikov } 5873e7a2321SAlexander V. Chernikov 5883e7a2321SAlexander V. Chernikov lltable_unlink_entry(llt, lle); 5893e7a2321SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 5903e7a2321SAlexander V. Chernikov 5913e7a2321SAlexander V. Chernikov llt->llt_delete_entry(llt, lle); 5923e7a2321SAlexander V. Chernikov 5933e7a2321SAlexander V. Chernikov return (0); 5943e7a2321SAlexander V. Chernikov } 5953e7a2321SAlexander V. Chernikov 596c9d763bfSQing Li void 5973e7a2321SAlexander V. Chernikov lltable_prefix_free(int af, struct sockaddr *addr, struct sockaddr *mask, 5985b84dc78SQing Li u_int flags) 599c9d763bfSQing Li { 600c9d763bfSQing Li struct lltable *llt; 601c9d763bfSQing Li 602199511bcSAndrey V. Elsukov LLTABLE_LIST_RLOCK(); 603989e0411SMarko Zec SLIST_FOREACH(llt, &V_lltables, llt_link) { 604c9d763bfSQing Li if (llt->llt_af != af) 605c9d763bfSQing Li continue; 606c9d763bfSQing Li 6073e7a2321SAlexander V. Chernikov llt->llt_prefix_free(llt, addr, mask, flags); 608c9d763bfSQing Li } 609199511bcSAndrey V. Elsukov LLTABLE_LIST_RUNLOCK(); 610c9d763bfSQing Li } 611c9d763bfSQing Li 61282f39c91SKip Macy struct lltable * 61341cb42a6SAlexander V. Chernikov lltable_allocate_htbl(uint32_t hsize) 61482f39c91SKip Macy { 61582f39c91SKip Macy struct lltable *llt; 61641cb42a6SAlexander V. Chernikov int i; 61782f39c91SKip Macy 61841cb42a6SAlexander V. Chernikov llt = malloc(sizeof(struct lltable), M_LLTABLE, M_WAITOK | M_ZERO); 61941cb42a6SAlexander V. Chernikov llt->llt_hsize = hsize; 62041cb42a6SAlexander V. Chernikov llt->lle_head = malloc(sizeof(struct llentries) * hsize, 62141cb42a6SAlexander V. Chernikov M_LLTABLE, M_WAITOK | M_ZERO); 62282f39c91SKip Macy 62341cb42a6SAlexander V. Chernikov for (i = 0; i < llt->llt_hsize; i++) 6244f6c66ccSMatt Macy CK_LIST_INIT(&llt->lle_head[i]); 62582f39c91SKip Macy 62611cdad98SAlexander V. Chernikov /* Set some default callbacks */ 62711cdad98SAlexander V. Chernikov llt->llt_link_entry = htable_link_entry; 62811cdad98SAlexander V. Chernikov llt->llt_unlink_entry = htable_unlink_entry; 62911cdad98SAlexander V. Chernikov llt->llt_prefix_free = htable_prefix_free; 63011cdad98SAlexander V. Chernikov llt->llt_foreach_entry = htable_foreach_lle; 63141cb42a6SAlexander V. Chernikov llt->llt_free_tbl = htable_free_tbl; 63241cb42a6SAlexander V. Chernikov 63341cb42a6SAlexander V. Chernikov return (llt); 63441cb42a6SAlexander V. Chernikov } 63541cb42a6SAlexander V. Chernikov 63682f39c91SKip Macy /* 637721cd2e0SAlexander V. Chernikov * Links lltable to global llt list. 63882f39c91SKip Macy */ 639721cd2e0SAlexander V. Chernikov void 640721cd2e0SAlexander V. Chernikov lltable_link(struct lltable *llt) 64182f39c91SKip Macy { 64211cdad98SAlexander V. Chernikov 643199511bcSAndrey V. Elsukov LLTABLE_LIST_WLOCK(); 644989e0411SMarko Zec SLIST_INSERT_HEAD(&V_lltables, llt, llt_link); 645199511bcSAndrey V. Elsukov LLTABLE_LIST_WUNLOCK(); 646721cd2e0SAlexander V. Chernikov } 64782f39c91SKip Macy 648721cd2e0SAlexander V. Chernikov static void 649721cd2e0SAlexander V. Chernikov lltable_unlink(struct lltable *llt) 650721cd2e0SAlexander V. Chernikov { 651721cd2e0SAlexander V. Chernikov 652199511bcSAndrey V. Elsukov LLTABLE_LIST_WLOCK(); 653721cd2e0SAlexander V. Chernikov SLIST_REMOVE(&V_lltables, llt, lltable, llt_link); 654199511bcSAndrey V. Elsukov LLTABLE_LIST_WUNLOCK(); 655721cd2e0SAlexander V. Chernikov 65682f39c91SKip Macy } 65782f39c91SKip Macy 65882f39c91SKip Macy /* 65911cdad98SAlexander V. Chernikov * External methods used by lltable consumers 66011cdad98SAlexander V. Chernikov */ 66111cdad98SAlexander V. Chernikov 66211cdad98SAlexander V. Chernikov int 66311cdad98SAlexander V. Chernikov lltable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg) 66411cdad98SAlexander V. Chernikov { 66511cdad98SAlexander V. Chernikov 66611cdad98SAlexander V. Chernikov return (llt->llt_foreach_entry(llt, f, farg)); 66711cdad98SAlexander V. Chernikov } 66811cdad98SAlexander V. Chernikov 6695a255516SAlexander V. Chernikov struct llentry * 6705a255516SAlexander V. Chernikov lltable_alloc_entry(struct lltable *llt, u_int flags, 6715a255516SAlexander V. Chernikov const struct sockaddr *l3addr) 6725a255516SAlexander V. Chernikov { 6735a255516SAlexander V. Chernikov 6745a255516SAlexander V. Chernikov return (llt->llt_alloc_entry(llt, flags, l3addr)); 6755a255516SAlexander V. Chernikov } 6765a255516SAlexander V. Chernikov 6775a255516SAlexander V. Chernikov void 6785a255516SAlexander V. Chernikov lltable_free_entry(struct lltable *llt, struct llentry *lle) 6795a255516SAlexander V. Chernikov { 6805a255516SAlexander V. Chernikov 6815a255516SAlexander V. Chernikov llt->llt_free_entry(llt, lle); 6825a255516SAlexander V. Chernikov } 6835a255516SAlexander V. Chernikov 68411cdad98SAlexander V. Chernikov void 68511cdad98SAlexander V. Chernikov lltable_link_entry(struct lltable *llt, struct llentry *lle) 68611cdad98SAlexander V. Chernikov { 68711cdad98SAlexander V. Chernikov 68811cdad98SAlexander V. Chernikov llt->llt_link_entry(llt, lle); 68911cdad98SAlexander V. Chernikov } 69011cdad98SAlexander V. Chernikov 69111cdad98SAlexander V. Chernikov void 69211cdad98SAlexander V. Chernikov lltable_unlink_entry(struct lltable *llt, struct llentry *lle) 69311cdad98SAlexander V. Chernikov { 69411cdad98SAlexander V. Chernikov 69511cdad98SAlexander V. Chernikov llt->llt_unlink_entry(lle); 69611cdad98SAlexander V. Chernikov } 69711cdad98SAlexander V. Chernikov 69811cdad98SAlexander V. Chernikov void 69911cdad98SAlexander V. Chernikov lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa) 70011cdad98SAlexander V. Chernikov { 70111cdad98SAlexander V. Chernikov struct lltable *llt; 70211cdad98SAlexander V. Chernikov 70311cdad98SAlexander V. Chernikov llt = lle->lle_tbl; 70411cdad98SAlexander V. Chernikov llt->llt_fill_sa_entry(lle, sa); 70511cdad98SAlexander V. Chernikov } 70611cdad98SAlexander V. Chernikov 70711cdad98SAlexander V. Chernikov struct ifnet * 70811cdad98SAlexander V. Chernikov lltable_get_ifp(const struct lltable *llt) 70911cdad98SAlexander V. Chernikov { 71011cdad98SAlexander V. Chernikov 71111cdad98SAlexander V. Chernikov return (llt->llt_ifp); 71211cdad98SAlexander V. Chernikov } 71311cdad98SAlexander V. Chernikov 71411cdad98SAlexander V. Chernikov int 71511cdad98SAlexander V. Chernikov lltable_get_af(const struct lltable *llt) 71611cdad98SAlexander V. Chernikov { 71711cdad98SAlexander V. Chernikov 71811cdad98SAlexander V. Chernikov return (llt->llt_af); 71911cdad98SAlexander V. Chernikov } 72011cdad98SAlexander V. Chernikov 72111cdad98SAlexander V. Chernikov /* 722b4b1367aSAlexander V. Chernikov * Called in route_output when rtm_flags contains RTF_LLDATA. 72382f39c91SKip Macy */ 72482f39c91SKip Macy int 72582f39c91SKip Macy lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info) 72682f39c91SKip Macy { 72782f39c91SKip Macy struct sockaddr_dl *dl = 72882f39c91SKip Macy (struct sockaddr_dl *)info->rti_info[RTAX_GATEWAY]; 72982f39c91SKip Macy struct sockaddr *dst = (struct sockaddr *)info->rti_info[RTAX_DST]; 73082f39c91SKip Macy struct ifnet *ifp; 73182f39c91SKip Macy struct lltable *llt; 7325a255516SAlexander V. Chernikov struct llentry *lle, *lle_tmp; 7334fb3a820SAlexander V. Chernikov uint8_t linkhdr[LLE_MAX_LINKHDR]; 7344fb3a820SAlexander V. Chernikov size_t linkhdrsize; 7354fb3a820SAlexander V. Chernikov int lladdr_off; 736b4b1367aSAlexander V. Chernikov u_int laflags = 0; 737b4b1367aSAlexander V. Chernikov int error; 73882f39c91SKip Macy 7391910bfcbSGleb Smirnoff KASSERT(dl != NULL && dl->sdl_family == AF_LINK, 7401910bfcbSGleb Smirnoff ("%s: invalid dl\n", __func__)); 7411910bfcbSGleb Smirnoff 74282f39c91SKip Macy ifp = ifnet_byindex(dl->sdl_index); 74382f39c91SKip Macy if (ifp == NULL) { 74482f39c91SKip Macy log(LOG_INFO, "%s: invalid ifp (sdl_index %d)\n", 74582f39c91SKip Macy __func__, dl->sdl_index); 74682f39c91SKip Macy return EINVAL; 74782f39c91SKip Macy } 74882f39c91SKip Macy 74982f39c91SKip Macy /* XXX linked list may be too expensive */ 750199511bcSAndrey V. Elsukov LLTABLE_LIST_RLOCK(); 751989e0411SMarko Zec SLIST_FOREACH(llt, &V_lltables, llt_link) { 75282f39c91SKip Macy if (llt->llt_af == dst->sa_family && 75382f39c91SKip Macy llt->llt_ifp == ifp) 75482f39c91SKip Macy break; 75582f39c91SKip Macy } 756199511bcSAndrey V. Elsukov LLTABLE_LIST_RUNLOCK(); 75782f39c91SKip Macy KASSERT(llt != NULL, ("Yep, ugly hacks are bad\n")); 75882f39c91SKip Macy 759b4b1367aSAlexander V. Chernikov error = 0; 76082f39c91SKip Macy 761b4b1367aSAlexander V. Chernikov switch (rtm->rtm_type) { 762b4b1367aSAlexander V. Chernikov case RTM_ADD: 763b4b1367aSAlexander V. Chernikov /* Add static LLE */ 7643b0fd911SAlexander V. Chernikov laflags = 0; 7653b0fd911SAlexander V. Chernikov if (rtm->rtm_rmx.rmx_expire == 0) 7663b0fd911SAlexander V. Chernikov laflags = LLE_STATIC; 7673b0fd911SAlexander V. Chernikov lle = lltable_alloc_entry(llt, laflags, dst); 7685a255516SAlexander V. Chernikov if (lle == NULL) 769b4b1367aSAlexander V. Chernikov return (ENOMEM); 770b4b1367aSAlexander V. Chernikov 7714fb3a820SAlexander V. Chernikov linkhdrsize = sizeof(linkhdr); 7724fb3a820SAlexander V. Chernikov if (lltable_calc_llheader(ifp, dst->sa_family, LLADDR(dl), 7734fb3a820SAlexander V. Chernikov linkhdr, &linkhdrsize, &lladdr_off) != 0) 7744fb3a820SAlexander V. Chernikov return (EINVAL); 7754fb3a820SAlexander V. Chernikov lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize, 7764fb3a820SAlexander V. Chernikov lladdr_off); 777b4b1367aSAlexander V. Chernikov if ((rtm->rtm_flags & RTF_ANNOUNCE)) 778b4b1367aSAlexander V. Chernikov lle->la_flags |= LLE_PUB; 77982f39c91SKip Macy lle->la_expire = rtm->rtm_rmx.rmx_expire; 7803b0fd911SAlexander V. Chernikov 78182f39c91SKip Macy laflags = lle->la_flags; 7825a255516SAlexander V. Chernikov 7835a255516SAlexander V. Chernikov /* Try to link new entry */ 7845a255516SAlexander V. Chernikov lle_tmp = NULL; 7855a255516SAlexander V. Chernikov IF_AFDATA_WLOCK(ifp); 7865a255516SAlexander V. Chernikov LLE_WLOCK(lle); 7875a255516SAlexander V. Chernikov lle_tmp = lla_lookup(llt, LLE_EXCLUSIVE, dst); 7885a255516SAlexander V. Chernikov if (lle_tmp != NULL) { 7895a255516SAlexander V. Chernikov /* Check if we are trying to replace immutable entry */ 7905a255516SAlexander V. Chernikov if ((lle_tmp->la_flags & LLE_IFADDR) != 0) { 791b4b1367aSAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 7925a255516SAlexander V. Chernikov LLE_WUNLOCK(lle_tmp); 7935a255516SAlexander V. Chernikov lltable_free_entry(llt, lle); 7945a255516SAlexander V. Chernikov return (EPERM); 7955a255516SAlexander V. Chernikov } 7965a255516SAlexander V. Chernikov /* Unlink existing entry from table */ 7975a255516SAlexander V. Chernikov lltable_unlink_entry(llt, lle_tmp); 7985a255516SAlexander V. Chernikov } 7995a255516SAlexander V. Chernikov lltable_link_entry(llt, lle); 8005a255516SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp); 8015a255516SAlexander V. Chernikov 8025a255516SAlexander V. Chernikov if (lle_tmp != NULL) { 8035a255516SAlexander V. Chernikov EVENTHANDLER_INVOKE(lle_event, lle_tmp,LLENTRY_EXPIRED); 8045a255516SAlexander V. Chernikov lltable_free_entry(llt, lle_tmp); 8055a255516SAlexander V. Chernikov } 8065a255516SAlexander V. Chernikov 8075a255516SAlexander V. Chernikov /* 8085a255516SAlexander V. Chernikov * By invoking LLE handler here we might get 8095a255516SAlexander V. Chernikov * two events on static LLE entry insertion 8105a255516SAlexander V. Chernikov * in routing socket. However, since we might have 8115a255516SAlexander V. Chernikov * other subscribers we need to generate this event. 8125a255516SAlexander V. Chernikov */ 8135a255516SAlexander V. Chernikov EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_RESOLVED); 8145a255516SAlexander V. Chernikov LLE_WUNLOCK(lle); 81582f39c91SKip Macy #ifdef INET 8167b4d716bSKip Macy /* gratuitous ARP */ 8179711a168SGleb Smirnoff if ((laflags & LLE_PUB) && dst->sa_family == AF_INET) 81882f39c91SKip Macy arprequest(ifp, 81982f39c91SKip Macy &((struct sockaddr_in *)dst)->sin_addr, 82082f39c91SKip Macy &((struct sockaddr_in *)dst)->sin_addr, 8219711a168SGleb Smirnoff (u_char *)LLADDR(dl)); 82282f39c91SKip Macy #endif 82382f39c91SKip Macy 824b4b1367aSAlexander V. Chernikov break; 825b4b1367aSAlexander V. Chernikov 826b4b1367aSAlexander V. Chernikov case RTM_DELETE: 8273e7a2321SAlexander V. Chernikov return (lltable_delete_addr(llt, 0, dst)); 828b4b1367aSAlexander V. Chernikov 829b4b1367aSAlexander V. Chernikov default: 830b4b1367aSAlexander V. Chernikov error = EINVAL; 831b4b1367aSAlexander V. Chernikov } 83282f39c91SKip Macy 83382f39c91SKip Macy return (error); 83482f39c91SKip Macy } 835989e0411SMarko Zec 836335b943fSBjoern A. Zeeb #ifdef DDB 837335b943fSBjoern A. Zeeb struct llentry_sa { 838335b943fSBjoern A. Zeeb struct llentry base; 839335b943fSBjoern A. Zeeb struct sockaddr l3_addr; 840335b943fSBjoern A. Zeeb }; 841335b943fSBjoern A. Zeeb 842335b943fSBjoern A. Zeeb static void 843335b943fSBjoern A. Zeeb llatbl_lle_show(struct llentry_sa *la) 844335b943fSBjoern A. Zeeb { 845335b943fSBjoern A. Zeeb struct llentry *lle; 846335b943fSBjoern A. Zeeb uint8_t octet[6]; 847335b943fSBjoern A. Zeeb 848335b943fSBjoern A. Zeeb lle = &la->base; 849335b943fSBjoern A. Zeeb db_printf("lle=%p\n", lle); 8500f8d79d9SMatt Macy db_printf(" lle_next=%p\n", lle->lle_next.cle_next); 851335b943fSBjoern A. Zeeb db_printf(" lle_lock=%p\n", &lle->lle_lock); 852335b943fSBjoern A. Zeeb db_printf(" lle_tbl=%p\n", lle->lle_tbl); 853335b943fSBjoern A. Zeeb db_printf(" lle_head=%p\n", lle->lle_head); 854335b943fSBjoern A. Zeeb db_printf(" la_hold=%p\n", lle->la_hold); 855e162ea60SGeorge V. Neville-Neil db_printf(" la_numheld=%d\n", lle->la_numheld); 856335b943fSBjoern A. Zeeb db_printf(" la_expire=%ju\n", (uintmax_t)lle->la_expire); 857335b943fSBjoern A. Zeeb db_printf(" la_flags=0x%04x\n", lle->la_flags); 858335b943fSBjoern A. Zeeb db_printf(" la_asked=%u\n", lle->la_asked); 859335b943fSBjoern A. Zeeb db_printf(" la_preempt=%u\n", lle->la_preempt); 860335b943fSBjoern A. Zeeb db_printf(" ln_state=%d\n", lle->ln_state); 861335b943fSBjoern A. Zeeb db_printf(" ln_router=%u\n", lle->ln_router); 862335b943fSBjoern A. Zeeb db_printf(" ln_ntick=%ju\n", (uintmax_t)lle->ln_ntick); 863335b943fSBjoern A. Zeeb db_printf(" lle_refcnt=%d\n", lle->lle_refcnt); 8644fb3a820SAlexander V. Chernikov bcopy(lle->ll_addr, octet, sizeof(octet)); 865335b943fSBjoern A. Zeeb db_printf(" ll_addr=%02x:%02x:%02x:%02x:%02x:%02x\n", 866335b943fSBjoern A. Zeeb octet[0], octet[1], octet[2], octet[3], octet[4], octet[5]); 8670447c136SAlexander V. Chernikov db_printf(" lle_timer=%p\n", &lle->lle_timer); 868335b943fSBjoern A. Zeeb 869335b943fSBjoern A. Zeeb switch (la->l3_addr.sa_family) { 870335b943fSBjoern A. Zeeb #ifdef INET 871335b943fSBjoern A. Zeeb case AF_INET: 872335b943fSBjoern A. Zeeb { 873335b943fSBjoern A. Zeeb struct sockaddr_in *sin; 874335b943fSBjoern A. Zeeb char l3s[INET_ADDRSTRLEN]; 875335b943fSBjoern A. Zeeb 876335b943fSBjoern A. Zeeb sin = (struct sockaddr_in *)&la->l3_addr; 877335b943fSBjoern A. Zeeb inet_ntoa_r(sin->sin_addr, l3s); 878335b943fSBjoern A. Zeeb db_printf(" l3_addr=%s\n", l3s); 879335b943fSBjoern A. Zeeb break; 880335b943fSBjoern A. Zeeb } 881335b943fSBjoern A. Zeeb #endif 882335b943fSBjoern A. Zeeb #ifdef INET6 883335b943fSBjoern A. Zeeb case AF_INET6: 884335b943fSBjoern A. Zeeb { 885335b943fSBjoern A. Zeeb struct sockaddr_in6 *sin6; 886335b943fSBjoern A. Zeeb char l3s[INET6_ADDRSTRLEN]; 887335b943fSBjoern A. Zeeb 888335b943fSBjoern A. Zeeb sin6 = (struct sockaddr_in6 *)&la->l3_addr; 889335b943fSBjoern A. Zeeb ip6_sprintf(l3s, &sin6->sin6_addr); 890335b943fSBjoern A. Zeeb db_printf(" l3_addr=%s\n", l3s); 891335b943fSBjoern A. Zeeb break; 892335b943fSBjoern A. Zeeb } 893335b943fSBjoern A. Zeeb #endif 894335b943fSBjoern A. Zeeb default: 895335b943fSBjoern A. Zeeb db_printf(" l3_addr=N/A (af=%d)\n", la->l3_addr.sa_family); 896335b943fSBjoern A. Zeeb break; 897335b943fSBjoern A. Zeeb } 898335b943fSBjoern A. Zeeb } 899335b943fSBjoern A. Zeeb 900335b943fSBjoern A. Zeeb DB_SHOW_COMMAND(llentry, db_show_llentry) 901335b943fSBjoern A. Zeeb { 902335b943fSBjoern A. Zeeb 903335b943fSBjoern A. Zeeb if (!have_addr) { 904335b943fSBjoern A. Zeeb db_printf("usage: show llentry <struct llentry *>\n"); 905335b943fSBjoern A. Zeeb return; 906335b943fSBjoern A. Zeeb } 907335b943fSBjoern A. Zeeb 908335b943fSBjoern A. Zeeb llatbl_lle_show((struct llentry_sa *)addr); 909335b943fSBjoern A. Zeeb } 910335b943fSBjoern A. Zeeb 911335b943fSBjoern A. Zeeb static void 912335b943fSBjoern A. Zeeb llatbl_llt_show(struct lltable *llt) 913335b943fSBjoern A. Zeeb { 914335b943fSBjoern A. Zeeb int i; 915335b943fSBjoern A. Zeeb struct llentry *lle; 916335b943fSBjoern A. Zeeb 917335b943fSBjoern A. Zeeb db_printf("llt=%p llt_af=%d llt_ifp=%p\n", 918335b943fSBjoern A. Zeeb llt, llt->llt_af, llt->llt_ifp); 919335b943fSBjoern A. Zeeb 9203a749863SAlexander V. Chernikov for (i = 0; i < llt->llt_hsize; i++) { 9214f6c66ccSMatt Macy CK_LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { 922335b943fSBjoern A. Zeeb 923335b943fSBjoern A. Zeeb llatbl_lle_show((struct llentry_sa *)lle); 924335b943fSBjoern A. Zeeb if (db_pager_quit) 925335b943fSBjoern A. Zeeb return; 926335b943fSBjoern A. Zeeb } 927335b943fSBjoern A. Zeeb } 928335b943fSBjoern A. Zeeb } 929335b943fSBjoern A. Zeeb 930335b943fSBjoern A. Zeeb DB_SHOW_COMMAND(lltable, db_show_lltable) 931335b943fSBjoern A. Zeeb { 932335b943fSBjoern A. Zeeb 933335b943fSBjoern A. Zeeb if (!have_addr) { 934335b943fSBjoern A. Zeeb db_printf("usage: show lltable <struct lltable *>\n"); 935335b943fSBjoern A. Zeeb return; 936335b943fSBjoern A. Zeeb } 937335b943fSBjoern A. Zeeb 938335b943fSBjoern A. Zeeb llatbl_llt_show((struct lltable *)addr); 939335b943fSBjoern A. Zeeb } 940335b943fSBjoern A. Zeeb 941335b943fSBjoern A. Zeeb DB_SHOW_ALL_COMMAND(lltables, db_show_all_lltables) 942335b943fSBjoern A. Zeeb { 943335b943fSBjoern A. Zeeb VNET_ITERATOR_DECL(vnet_iter); 944335b943fSBjoern A. Zeeb struct lltable *llt; 945335b943fSBjoern A. Zeeb 946335b943fSBjoern A. Zeeb VNET_FOREACH(vnet_iter) { 947335b943fSBjoern A. Zeeb CURVNET_SET_QUIET(vnet_iter); 948335b943fSBjoern A. Zeeb #ifdef VIMAGE 949335b943fSBjoern A. Zeeb db_printf("vnet=%p\n", curvnet); 950335b943fSBjoern A. Zeeb #endif 951335b943fSBjoern A. Zeeb SLIST_FOREACH(llt, &V_lltables, llt_link) { 952335b943fSBjoern A. Zeeb db_printf("llt=%p llt_af=%d llt_ifp=%p(%s)\n", 953335b943fSBjoern A. Zeeb llt, llt->llt_af, llt->llt_ifp, 954335b943fSBjoern A. Zeeb (llt->llt_ifp != NULL) ? 955335b943fSBjoern A. Zeeb llt->llt_ifp->if_xname : "?"); 956335b943fSBjoern A. Zeeb if (have_addr && addr != 0) /* verbose */ 957335b943fSBjoern A. Zeeb llatbl_llt_show(llt); 958335b943fSBjoern A. Zeeb if (db_pager_quit) { 959335b943fSBjoern A. Zeeb CURVNET_RESTORE(); 960335b943fSBjoern A. Zeeb return; 961335b943fSBjoern A. Zeeb } 962335b943fSBjoern A. Zeeb } 963335b943fSBjoern A. Zeeb CURVNET_RESTORE(); 964335b943fSBjoern A. Zeeb } 965335b943fSBjoern A. Zeeb } 966335b943fSBjoern A. Zeeb #endif 967