1fe267a55SPedro F. Giffuni /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
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>
30335b943fSBjoern A. Zeeb #include "opt_ddb.h"
3182f39c91SKip Macy #include "opt_inet.h"
3282f39c91SKip Macy #include "opt_inet6.h"
3382f39c91SKip Macy
3482f39c91SKip Macy #include <sys/param.h>
3582f39c91SKip Macy #include <sys/systm.h>
36e2e050c8SConrad Meyer #include <sys/eventhandler.h>
3782f39c91SKip Macy #include <sys/malloc.h>
3882f39c91SKip Macy #include <sys/mbuf.h>
3982f39c91SKip Macy #include <sys/syslog.h>
4082f39c91SKip Macy #include <sys/sysctl.h>
4182f39c91SKip Macy #include <sys/socket.h>
4282f39c91SKip Macy #include <sys/kernel.h>
4382f39c91SKip Macy #include <sys/lock.h>
4482f39c91SKip Macy #include <sys/mutex.h>
4582f39c91SKip Macy #include <sys/rwlock.h>
4682f39c91SKip Macy
47335b943fSBjoern A. Zeeb #ifdef DDB
48335b943fSBjoern A. Zeeb #include <ddb/ddb.h>
49335b943fSBjoern A. Zeeb #endif
50335b943fSBjoern A. Zeeb
5182f39c91SKip Macy #include <vm/uma.h>
5282f39c91SKip Macy
5382f39c91SKip Macy #include <netinet/in.h>
5482f39c91SKip Macy #include <net/if_llatbl.h>
5582f39c91SKip Macy #include <net/if.h>
5682f39c91SKip Macy #include <net/if_dl.h>
5782f39c91SKip Macy #include <net/if_var.h>
582c2b37adSJustin Hibbits #include <net/if_private.h>
5982f39c91SKip Macy #include <net/route.h>
60da187ddbSAlexander V. Chernikov #include <net/route/route_ctl.h>
6163f7f392SAlexander V. Chernikov #include <net/route/route_debug.h>
62530c0060SRobert Watson #include <net/vnet.h>
6382f39c91SKip Macy #include <netinet/if_ether.h>
6482f39c91SKip Macy #include <netinet6/in6_var.h>
6582f39c91SKip Macy #include <netinet6/nd6.h>
6682f39c91SKip Macy
6782f39c91SKip Macy MALLOC_DEFINE(M_LLTABLE, "lltable", "link level address tables");
6882f39c91SKip Macy
695f901c92SAndrew Turner VNET_DEFINE_STATIC(SLIST_HEAD(, lltable), lltables) =
7076d68eccSBjoern A. Zeeb SLIST_HEAD_INITIALIZER(lltables);
71989e0411SMarko Zec #define V_lltables VNET(lltables)
7282f39c91SKip Macy
73199511bcSAndrey V. Elsukov static struct rwlock lltable_list_lock;
74199511bcSAndrey V. Elsukov RW_SYSINIT(lltable_list_lock, &lltable_list_lock, "lltable_list_lock");
75199511bcSAndrey V. Elsukov #define LLTABLE_LIST_RLOCK() rw_rlock(&lltable_list_lock)
76199511bcSAndrey V. Elsukov #define LLTABLE_LIST_RUNLOCK() rw_runlock(&lltable_list_lock)
77199511bcSAndrey V. Elsukov #define LLTABLE_LIST_WLOCK() rw_wlock(&lltable_list_lock)
78199511bcSAndrey V. Elsukov #define LLTABLE_LIST_WUNLOCK() rw_wunlock(&lltable_list_lock)
79199511bcSAndrey V. Elsukov #define LLTABLE_LIST_LOCK_ASSERT() rw_assert(&lltable_list_lock, RA_LOCKED)
80dc56e98fSRobert Watson
81721cd2e0SAlexander V. Chernikov static void lltable_unlink(struct lltable *llt);
8211cdad98SAlexander V. Chernikov static void llentries_unlink(struct lltable *llt, struct llentries *head);
8311cdad98SAlexander V. Chernikov
8411cdad98SAlexander V. Chernikov /*
8511cdad98SAlexander V. Chernikov * Dump lle state for a specific address family.
8611cdad98SAlexander V. Chernikov */
8711cdad98SAlexander V. Chernikov static int
lltable_dump_af(struct lltable * llt,struct sysctl_req * wr)8811cdad98SAlexander V. Chernikov lltable_dump_af(struct lltable *llt, struct sysctl_req *wr)
8911cdad98SAlexander V. Chernikov {
90a68cc388SGleb Smirnoff struct epoch_tracker et;
9111cdad98SAlexander V. Chernikov int error;
9211cdad98SAlexander V. Chernikov
93199511bcSAndrey V. Elsukov LLTABLE_LIST_LOCK_ASSERT();
9411cdad98SAlexander V. Chernikov
9511cdad98SAlexander V. Chernikov if (llt->llt_ifp->if_flags & IFF_LOOPBACK)
9611cdad98SAlexander V. Chernikov return (0);
9711cdad98SAlexander V. Chernikov error = 0;
9811cdad98SAlexander V. Chernikov
99a68cc388SGleb Smirnoff NET_EPOCH_ENTER(et);
10011cdad98SAlexander V. Chernikov error = lltable_foreach_lle(llt,
10111cdad98SAlexander V. Chernikov (llt_foreach_cb_t *)llt->llt_dump_entry, wr);
102a68cc388SGleb Smirnoff NET_EPOCH_EXIT(et);
10311cdad98SAlexander V. Chernikov
10411cdad98SAlexander V. Chernikov return (error);
10511cdad98SAlexander V. Chernikov }
10611cdad98SAlexander V. Chernikov
10782f39c91SKip Macy /*
10882f39c91SKip Macy * Dump arp state for a specific address family.
10982f39c91SKip Macy */
11082f39c91SKip Macy int
lltable_sysctl_dumparp(int af,struct sysctl_req * wr)11182f39c91SKip Macy lltable_sysctl_dumparp(int af, struct sysctl_req *wr)
11282f39c91SKip Macy {
11382f39c91SKip Macy struct lltable *llt;
11482f39c91SKip Macy int error = 0;
11582f39c91SKip Macy
116199511bcSAndrey V. Elsukov LLTABLE_LIST_RLOCK();
117989e0411SMarko Zec SLIST_FOREACH(llt, &V_lltables, llt_link) {
11882f39c91SKip Macy if (llt->llt_af == af) {
11911cdad98SAlexander V. Chernikov error = lltable_dump_af(llt, wr);
12082f39c91SKip Macy if (error != 0)
12182f39c91SKip Macy goto done;
12282f39c91SKip Macy }
12382f39c91SKip Macy }
12482f39c91SKip Macy done:
125199511bcSAndrey V. Elsukov LLTABLE_LIST_RUNLOCK();
12682f39c91SKip Macy return (error);
12782f39c91SKip Macy }
12882f39c91SKip Macy
12982f39c91SKip Macy /*
130d18b4becSArseny Smalyuk * Adds a mbuf to hold queue. Drops old packets if the queue is full.
131d18b4becSArseny Smalyuk *
132d18b4becSArseny Smalyuk * Returns the number of held packets that were dropped.
133d18b4becSArseny Smalyuk */
134d18b4becSArseny Smalyuk size_t
lltable_append_entry_queue(struct llentry * lle,struct mbuf * m,size_t maxheld)135d18b4becSArseny Smalyuk lltable_append_entry_queue(struct llentry *lle, struct mbuf *m,
136d18b4becSArseny Smalyuk size_t maxheld)
137d18b4becSArseny Smalyuk {
138d18b4becSArseny Smalyuk size_t pkts_dropped = 0;
139d18b4becSArseny Smalyuk
140d18b4becSArseny Smalyuk LLE_WLOCK_ASSERT(lle);
141d18b4becSArseny Smalyuk
142d18b4becSArseny Smalyuk while (lle->la_numheld >= maxheld && lle->la_hold != NULL) {
143d18b4becSArseny Smalyuk struct mbuf *next = lle->la_hold->m_nextpkt;
144d18b4becSArseny Smalyuk m_freem(lle->la_hold);
145d18b4becSArseny Smalyuk lle->la_hold = next;
146d18b4becSArseny Smalyuk lle->la_numheld--;
147d18b4becSArseny Smalyuk pkts_dropped++;
148d18b4becSArseny Smalyuk }
149d18b4becSArseny Smalyuk
150d18b4becSArseny Smalyuk if (lle->la_hold != NULL) {
151d18b4becSArseny Smalyuk struct mbuf *curr = lle->la_hold;
152d18b4becSArseny Smalyuk while (curr->m_nextpkt != NULL)
153d18b4becSArseny Smalyuk curr = curr->m_nextpkt;
154d18b4becSArseny Smalyuk curr->m_nextpkt = m;
155d18b4becSArseny Smalyuk } else
156d18b4becSArseny Smalyuk lle->la_hold = m;
157d18b4becSArseny Smalyuk
158d18b4becSArseny Smalyuk lle->la_numheld++;
159d18b4becSArseny Smalyuk
160d18b4becSArseny Smalyuk return pkts_dropped;
161d18b4becSArseny Smalyuk }
162d18b4becSArseny Smalyuk
163d18b4becSArseny Smalyuk
164d18b4becSArseny Smalyuk /*
16511cdad98SAlexander V. Chernikov * Common function helpers for chained hash table.
16611cdad98SAlexander V. Chernikov */
16711cdad98SAlexander V. Chernikov
16811cdad98SAlexander V. Chernikov /*
16911cdad98SAlexander V. Chernikov * Runs specified callback for each entry in @llt.
17011cdad98SAlexander V. Chernikov * Caller does the locking.
17111cdad98SAlexander V. Chernikov *
17211cdad98SAlexander V. Chernikov */
17311cdad98SAlexander V. Chernikov static int
htable_foreach_lle(struct lltable * llt,llt_foreach_cb_t * f,void * farg)17411cdad98SAlexander V. Chernikov htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg)
17511cdad98SAlexander V. Chernikov {
17611cdad98SAlexander V. Chernikov struct llentry *lle, *next;
17711cdad98SAlexander V. Chernikov int i, error;
17811cdad98SAlexander V. Chernikov
17911cdad98SAlexander V. Chernikov error = 0;
18011cdad98SAlexander V. Chernikov
18141cb42a6SAlexander V. Chernikov for (i = 0; i < llt->llt_hsize; i++) {
1824f6c66ccSMatt Macy CK_LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
18311cdad98SAlexander V. Chernikov error = f(llt, lle, farg);
18411cdad98SAlexander V. Chernikov if (error != 0)
18511cdad98SAlexander V. Chernikov break;
18611cdad98SAlexander V. Chernikov }
18711cdad98SAlexander V. Chernikov }
18811cdad98SAlexander V. Chernikov
18911cdad98SAlexander V. Chernikov return (error);
19011cdad98SAlexander V. Chernikov }
19111cdad98SAlexander V. Chernikov
1923818c25aSBjoern A. Zeeb /*
1933818c25aSBjoern A. Zeeb * The htable_[un]link_entry() functions return:
1943818c25aSBjoern A. Zeeb * 0 if the entry was (un)linked already and nothing changed,
1953818c25aSBjoern A. Zeeb * 1 if the entry was added/removed to/from the table, and
1963818c25aSBjoern A. Zeeb * -1 on error (e.g., not being able to add the entry due to limits reached).
1973818c25aSBjoern A. Zeeb * While the "unlink" operation should never error, callers of
1983818c25aSBjoern A. Zeeb * lltable_link_entry() need to check for errors and handle them.
1993818c25aSBjoern A. Zeeb */
2003818c25aSBjoern A. Zeeb static int
htable_link_entry(struct lltable * llt,struct llentry * lle)20111cdad98SAlexander V. Chernikov htable_link_entry(struct lltable *llt, struct llentry *lle)
20211cdad98SAlexander V. Chernikov {
20311cdad98SAlexander V. Chernikov struct llentries *lleh;
20411cdad98SAlexander V. Chernikov uint32_t hashidx;
20511cdad98SAlexander V. Chernikov
20611cdad98SAlexander V. Chernikov if ((lle->la_flags & LLE_LINKED) != 0)
2073818c25aSBjoern A. Zeeb return (0);
20811cdad98SAlexander V. Chernikov
20911cdad98SAlexander V. Chernikov IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp);
21011cdad98SAlexander V. Chernikov
2113818c25aSBjoern A. Zeeb if (llt->llt_maxentries > 0 &&
2123818c25aSBjoern A. Zeeb llt->llt_entries >= llt->llt_maxentries)
2133818c25aSBjoern A. Zeeb return (-1);
2143818c25aSBjoern A. Zeeb
2153a749863SAlexander V. Chernikov hashidx = llt->llt_hash(lle, llt->llt_hsize);
21611cdad98SAlexander V. Chernikov lleh = &llt->lle_head[hashidx];
21711cdad98SAlexander V. Chernikov
21811cdad98SAlexander V. Chernikov lle->lle_tbl = llt;
21911cdad98SAlexander V. Chernikov lle->lle_head = lleh;
22011cdad98SAlexander V. Chernikov lle->la_flags |= LLE_LINKED;
2214f6c66ccSMatt Macy CK_LIST_INSERT_HEAD(lleh, lle, lle_next);
2223818c25aSBjoern A. Zeeb llt->llt_entries++;
2233818c25aSBjoern A. Zeeb
2243818c25aSBjoern A. Zeeb return (1);
22511cdad98SAlexander V. Chernikov }
22611cdad98SAlexander V. Chernikov
2273818c25aSBjoern A. Zeeb static int
htable_unlink_entry(struct llentry * lle)22811cdad98SAlexander V. Chernikov htable_unlink_entry(struct llentry *lle)
22911cdad98SAlexander V. Chernikov {
2303818c25aSBjoern A. Zeeb struct lltable *llt;
23111cdad98SAlexander V. Chernikov
232d9a61c96SBjoern A. Zeeb if ((lle->la_flags & LLE_LINKED) == 0)
2333818c25aSBjoern A. Zeeb return (0);
234d9a61c96SBjoern A. Zeeb
2353818c25aSBjoern A. Zeeb llt = lle->lle_tbl;
2363818c25aSBjoern A. Zeeb IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp);
2373818c25aSBjoern A. Zeeb KASSERT(llt->llt_entries > 0, ("%s: lltable %p (%s) entries %d <= 0",
2383818c25aSBjoern A. Zeeb __func__, llt, if_name(llt->llt_ifp), llt->llt_entries));
2393818c25aSBjoern A. Zeeb
2404f6c66ccSMatt Macy CK_LIST_REMOVE(lle, lle_next);
24111cdad98SAlexander V. Chernikov lle->la_flags &= ~(LLE_VALID | LLE_LINKED);
24211cdad98SAlexander V. Chernikov #if 0
24311cdad98SAlexander V. Chernikov lle->lle_tbl = NULL;
24411cdad98SAlexander V. Chernikov lle->lle_head = NULL;
24511cdad98SAlexander V. Chernikov #endif
2463818c25aSBjoern A. Zeeb llt->llt_entries--;
2473818c25aSBjoern A. Zeeb
2483818c25aSBjoern A. Zeeb return (1);
24911cdad98SAlexander V. Chernikov }
25011cdad98SAlexander V. Chernikov
25111cdad98SAlexander V. Chernikov struct prefix_match_data {
2523e7a2321SAlexander V. Chernikov const struct sockaddr *addr;
25311cdad98SAlexander V. Chernikov const struct sockaddr *mask;
25411cdad98SAlexander V. Chernikov struct llentries dchain;
25511cdad98SAlexander V. Chernikov u_int flags;
25611cdad98SAlexander V. Chernikov };
25711cdad98SAlexander V. Chernikov
25811cdad98SAlexander V. Chernikov static int
htable_prefix_free_cb(struct lltable * llt,struct llentry * lle,void * farg)25911cdad98SAlexander V. Chernikov htable_prefix_free_cb(struct lltable *llt, struct llentry *lle, void *farg)
26011cdad98SAlexander V. Chernikov {
26111cdad98SAlexander V. Chernikov struct prefix_match_data *pmd;
26211cdad98SAlexander V. Chernikov
26311cdad98SAlexander V. Chernikov pmd = (struct prefix_match_data *)farg;
26411cdad98SAlexander V. Chernikov
2653e7a2321SAlexander V. Chernikov if (llt->llt_match_prefix(pmd->addr, pmd->mask, pmd->flags, lle)) {
26611cdad98SAlexander V. Chernikov LLE_WLOCK(lle);
2670f8d79d9SMatt Macy CK_LIST_INSERT_HEAD(&pmd->dchain, lle, lle_chain);
26811cdad98SAlexander V. Chernikov }
26911cdad98SAlexander V. Chernikov
27011cdad98SAlexander V. Chernikov return (0);
27111cdad98SAlexander V. Chernikov }
27211cdad98SAlexander V. Chernikov
27311cdad98SAlexander V. Chernikov static void
htable_prefix_free(struct lltable * llt,const struct sockaddr * addr,const struct sockaddr * mask,u_int flags)2743e7a2321SAlexander V. Chernikov htable_prefix_free(struct lltable *llt, const struct sockaddr *addr,
27511cdad98SAlexander V. Chernikov const struct sockaddr *mask, u_int flags)
27611cdad98SAlexander V. Chernikov {
27711cdad98SAlexander V. Chernikov struct llentry *lle, *next;
27811cdad98SAlexander V. Chernikov struct prefix_match_data pmd;
27911cdad98SAlexander V. Chernikov
28011cdad98SAlexander V. Chernikov bzero(&pmd, sizeof(pmd));
2813e7a2321SAlexander V. Chernikov pmd.addr = addr;
28211cdad98SAlexander V. Chernikov pmd.mask = mask;
28311cdad98SAlexander V. Chernikov pmd.flags = flags;
2844f6c66ccSMatt Macy CK_LIST_INIT(&pmd.dchain);
28511cdad98SAlexander V. Chernikov
28611cdad98SAlexander V. Chernikov IF_AFDATA_WLOCK(llt->llt_ifp);
28711cdad98SAlexander V. Chernikov /* Push matching lles to chain */
28811cdad98SAlexander V. Chernikov lltable_foreach_lle(llt, htable_prefix_free_cb, &pmd);
28911cdad98SAlexander V. Chernikov
29011cdad98SAlexander V. Chernikov llentries_unlink(llt, &pmd.dchain);
29111cdad98SAlexander V. Chernikov IF_AFDATA_WUNLOCK(llt->llt_ifp);
29211cdad98SAlexander V. Chernikov
2930f8d79d9SMatt Macy CK_LIST_FOREACH_SAFE(lle, &pmd.dchain, lle_chain, next)
2945a255516SAlexander V. Chernikov lltable_free_entry(llt, lle);
29511cdad98SAlexander V. Chernikov }
29611cdad98SAlexander V. Chernikov
29711cdad98SAlexander V. Chernikov static void
htable_free_tbl(struct lltable * llt)29841cb42a6SAlexander V. Chernikov htable_free_tbl(struct lltable *llt)
29941cb42a6SAlexander V. Chernikov {
30041cb42a6SAlexander V. Chernikov
30141cb42a6SAlexander V. Chernikov free(llt->lle_head, M_LLTABLE);
30241cb42a6SAlexander V. Chernikov free(llt, M_LLTABLE);
30341cb42a6SAlexander V. Chernikov }
30441cb42a6SAlexander V. Chernikov
305721cd2e0SAlexander V. Chernikov static void
llentries_unlink(struct lltable * llt,struct llentries * head)30611cdad98SAlexander V. Chernikov llentries_unlink(struct lltable *llt, struct llentries *head)
30711cdad98SAlexander V. Chernikov {
30811cdad98SAlexander V. Chernikov struct llentry *lle, *next;
30911cdad98SAlexander V. Chernikov
3100f8d79d9SMatt Macy CK_LIST_FOREACH_SAFE(lle, head, lle_chain, next)
31111cdad98SAlexander V. Chernikov llt->llt_unlink_entry(lle);
31211cdad98SAlexander V. Chernikov }
31311cdad98SAlexander V. Chernikov
31411cdad98SAlexander V. Chernikov /*
31511cdad98SAlexander V. Chernikov * Helper function used to drop all mbufs in hold queue.
316e162ea60SGeorge V. Neville-Neil *
317e162ea60SGeorge V. Neville-Neil * Returns the number of held packets, if any, that were dropped.
31882f39c91SKip Macy */
319e162ea60SGeorge V. Neville-Neil size_t
lltable_drop_entry_queue(struct llentry * lle)32011cdad98SAlexander V. Chernikov lltable_drop_entry_queue(struct llentry *lle)
32182f39c91SKip Macy {
322d18b4becSArseny Smalyuk size_t pkts_dropped = 0;
32382f39c91SKip Macy
32482f39c91SKip Macy LLE_WLOCK_ASSERT(lle);
32582f39c91SKip Macy
326d18b4becSArseny Smalyuk while (lle->la_hold != NULL) {
327d18b4becSArseny Smalyuk struct mbuf *next = lle->la_hold->m_nextpkt;
32882f39c91SKip Macy m_freem(lle->la_hold);
329e162ea60SGeorge V. Neville-Neil lle->la_hold = next;
330e162ea60SGeorge V. Neville-Neil lle->la_numheld--;
331e162ea60SGeorge V. Neville-Neil pkts_dropped++;
332e162ea60SGeorge V. Neville-Neil }
333e162ea60SGeorge V. Neville-Neil
334e162ea60SGeorge V. Neville-Neil KASSERT(lle->la_numheld == 0,
3354f493559SGordon Bergling ("%s: la_numheld %d > 0, pkts_dropped %zd", __func__,
336e162ea60SGeorge V. Neville-Neil lle->la_numheld, pkts_dropped));
33782f39c91SKip Macy
33811cdad98SAlexander V. Chernikov return (pkts_dropped);
33911cdad98SAlexander V. Chernikov }
34011cdad98SAlexander V. Chernikov
341ddd208f7SAlexander V. Chernikov void
lltable_set_entry_addr(struct ifnet * ifp,struct llentry * lle,const char * linkhdr,size_t linkhdrsize,int lladdr_off)342ddd208f7SAlexander V. Chernikov lltable_set_entry_addr(struct ifnet *ifp, struct llentry *lle,
3434fb3a820SAlexander V. Chernikov const char *linkhdr, size_t linkhdrsize, int lladdr_off)
344ddd208f7SAlexander V. Chernikov {
345ddd208f7SAlexander V. Chernikov
3464fb3a820SAlexander V. Chernikov memcpy(lle->r_linkdata, linkhdr, linkhdrsize);
3474fb3a820SAlexander V. Chernikov lle->r_hdrlen = linkhdrsize;
3484fb3a820SAlexander V. Chernikov lle->ll_addr = &lle->r_linkdata[lladdr_off];
349ddd208f7SAlexander V. Chernikov lle->la_flags |= LLE_VALID;
350f8aee88fSAlexander V. Chernikov lle->r_flags |= RLLE_VALID;
351ddd208f7SAlexander V. Chernikov }
352ddd208f7SAlexander V. Chernikov
35311cdad98SAlexander V. Chernikov /*
3540b79b007SAlexander V. Chernikov * Acquires lltable write lock.
3550b79b007SAlexander V. Chernikov *
3560b79b007SAlexander V. Chernikov * Returns true on success, with both lltable and lle lock held.
3570b79b007SAlexander V. Chernikov * On failure, false is returned and lle wlock is still held.
3580b79b007SAlexander V. Chernikov */
3590b79b007SAlexander V. Chernikov bool
lltable_acquire_wlock(struct ifnet * ifp,struct llentry * lle)3600b79b007SAlexander V. Chernikov lltable_acquire_wlock(struct ifnet *ifp, struct llentry *lle)
3610b79b007SAlexander V. Chernikov {
3620b79b007SAlexander V. Chernikov NET_EPOCH_ASSERT();
3630b79b007SAlexander V. Chernikov
3640b79b007SAlexander V. Chernikov /* Perform real LLE update */
3650b79b007SAlexander V. Chernikov /* use afdata WLOCK to update fields */
3660b79b007SAlexander V. Chernikov LLE_WUNLOCK(lle);
3670b79b007SAlexander V. Chernikov IF_AFDATA_WLOCK(ifp);
3680b79b007SAlexander V. Chernikov LLE_WLOCK(lle);
3690b79b007SAlexander V. Chernikov
3700b79b007SAlexander V. Chernikov /*
3710b79b007SAlexander V. Chernikov * Since we droppped LLE lock, other thread might have deleted
3720b79b007SAlexander V. Chernikov * this lle. Check and return
3730b79b007SAlexander V. Chernikov */
3740b79b007SAlexander V. Chernikov if ((lle->la_flags & LLE_DELETED) != 0) {
3750b79b007SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp);
3760b79b007SAlexander V. Chernikov return (false);
3770b79b007SAlexander V. Chernikov }
3780b79b007SAlexander V. Chernikov
3790b79b007SAlexander V. Chernikov return (true);
3800b79b007SAlexander V. Chernikov }
3810b79b007SAlexander V. Chernikov
3820b79b007SAlexander V. Chernikov /*
38312cb7521SAlexander V. Chernikov * Tries to update @lle link-level address.
38412cb7521SAlexander V. Chernikov * Since update requires AFDATA WLOCK, function
38512cb7521SAlexander V. Chernikov * drops @lle lock, acquires AFDATA lock and then acquires
38612cb7521SAlexander V. Chernikov * @lle lock to maintain lock order.
38712cb7521SAlexander V. Chernikov *
38812cb7521SAlexander V. Chernikov * Returns 1 on success.
38912cb7521SAlexander V. Chernikov */
39012cb7521SAlexander V. Chernikov int
lltable_try_set_entry_addr(struct ifnet * ifp,struct llentry * lle,const char * linkhdr,size_t linkhdrsize,int lladdr_off)39112cb7521SAlexander V. Chernikov lltable_try_set_entry_addr(struct ifnet *ifp, struct llentry *lle,
3924fb3a820SAlexander V. Chernikov const char *linkhdr, size_t linkhdrsize, int lladdr_off)
39312cb7521SAlexander V. Chernikov {
39412cb7521SAlexander V. Chernikov
3950b79b007SAlexander V. Chernikov if (!lltable_acquire_wlock(ifp, lle))
39612cb7521SAlexander V. Chernikov return (0);
39712cb7521SAlexander V. Chernikov
39812cb7521SAlexander V. Chernikov /* Update data */
3994fb3a820SAlexander V. Chernikov lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize, lladdr_off);
40012cb7521SAlexander V. Chernikov
40112cb7521SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp);
40212cb7521SAlexander V. Chernikov
40312cb7521SAlexander V. Chernikov return (1);
40412cb7521SAlexander V. Chernikov }
40512cb7521SAlexander V. Chernikov
40612cb7521SAlexander V. Chernikov /*
4074fb3a820SAlexander V. Chernikov * Helper function used to pre-compute full/partial link-layer
4084fb3a820SAlexander V. Chernikov * header data suitable for feeding into if_output().
4094fb3a820SAlexander V. Chernikov */
4104fb3a820SAlexander V. Chernikov int
lltable_calc_llheader(struct ifnet * ifp,int family,char * lladdr,char * buf,size_t * bufsize,int * lladdr_off)4114fb3a820SAlexander V. Chernikov lltable_calc_llheader(struct ifnet *ifp, int family, char *lladdr,
4124fb3a820SAlexander V. Chernikov char *buf, size_t *bufsize, int *lladdr_off)
4134fb3a820SAlexander V. Chernikov {
4144fb3a820SAlexander V. Chernikov struct if_encap_req ereq;
4154fb3a820SAlexander V. Chernikov int error;
4164fb3a820SAlexander V. Chernikov
4174fb3a820SAlexander V. Chernikov bzero(buf, *bufsize);
4184fb3a820SAlexander V. Chernikov bzero(&ereq, sizeof(ereq));
4194fb3a820SAlexander V. Chernikov ereq.buf = buf;
4204fb3a820SAlexander V. Chernikov ereq.bufsize = *bufsize;
4214fb3a820SAlexander V. Chernikov ereq.rtype = IFENCAP_LL;
4224fb3a820SAlexander V. Chernikov ereq.family = family;
4234fb3a820SAlexander V. Chernikov ereq.lladdr = lladdr;
4244fb3a820SAlexander V. Chernikov ereq.lladdr_len = ifp->if_addrlen;
4254fb3a820SAlexander V. Chernikov error = ifp->if_requestencap(ifp, &ereq);
4264fb3a820SAlexander V. Chernikov if (error == 0) {
4274fb3a820SAlexander V. Chernikov *bufsize = ereq.bufsize;
4284fb3a820SAlexander V. Chernikov *lladdr_off = ereq.lladdr_off;
4294fb3a820SAlexander V. Chernikov }
4304fb3a820SAlexander V. Chernikov
4314fb3a820SAlexander V. Chernikov return (error);
4324fb3a820SAlexander V. Chernikov }
4334fb3a820SAlexander V. Chernikov
4344fb3a820SAlexander V. Chernikov /*
435c541bd36SAlexander V. Chernikov * Searches for the child entry matching @family inside @lle.
436c541bd36SAlexander V. Chernikov * Returns the entry or NULL.
437c541bd36SAlexander V. Chernikov */
438c541bd36SAlexander V. Chernikov struct llentry *
llentry_lookup_family(struct llentry * lle,int family)439c541bd36SAlexander V. Chernikov llentry_lookup_family(struct llentry *lle, int family)
440c541bd36SAlexander V. Chernikov {
441c541bd36SAlexander V. Chernikov struct llentry *child_lle;
442c541bd36SAlexander V. Chernikov
443c541bd36SAlexander V. Chernikov if (lle == NULL)
444c541bd36SAlexander V. Chernikov return (NULL);
445c541bd36SAlexander V. Chernikov
446c541bd36SAlexander V. Chernikov CK_SLIST_FOREACH(child_lle, &lle->lle_children, lle_child_next) {
447c541bd36SAlexander V. Chernikov if (child_lle->r_family == family)
448c541bd36SAlexander V. Chernikov return (child_lle);
449c541bd36SAlexander V. Chernikov }
450c541bd36SAlexander V. Chernikov
451c541bd36SAlexander V. Chernikov return (NULL);
452c541bd36SAlexander V. Chernikov }
453c541bd36SAlexander V. Chernikov
454c541bd36SAlexander V. Chernikov /*
45563f7f392SAlexander V. Chernikov * Retrieves upper protocol family for the llentry.
45663f7f392SAlexander V. Chernikov * By default, all "normal" (e.g. upper_family == transport_family)
45763f7f392SAlexander V. Chernikov * llentries have r_family set to 0.
45863f7f392SAlexander V. Chernikov * Thus, use @default_family in that regard, otherwise use r_family.
45963f7f392SAlexander V. Chernikov *
46063f7f392SAlexander V. Chernikov * Returns upper protocol family
46163f7f392SAlexander V. Chernikov */
46263f7f392SAlexander V. Chernikov int
llentry_get_upper_family(const struct llentry * lle,int default_family)46363f7f392SAlexander V. Chernikov llentry_get_upper_family(const struct llentry *lle, int default_family)
46463f7f392SAlexander V. Chernikov {
46563f7f392SAlexander V. Chernikov return (lle->r_family == 0 ? default_family : lle->r_family);
46663f7f392SAlexander V. Chernikov }
46763f7f392SAlexander V. Chernikov
46863f7f392SAlexander V. Chernikov /*
46963f7f392SAlexander V. Chernikov * Prints llentry @lle data into provided buffer.
47063f7f392SAlexander V. Chernikov * Example: lle/inet/valid/em0/1.2.3.4
47163f7f392SAlexander V. Chernikov *
47263f7f392SAlexander V. Chernikov * Returns @buf.
47363f7f392SAlexander V. Chernikov */
47463f7f392SAlexander V. Chernikov char *
llentry_print_buf(const struct llentry * lle,struct ifnet * ifp,int family,char * buf,size_t bufsize)47563f7f392SAlexander V. Chernikov llentry_print_buf(const struct llentry *lle, struct ifnet *ifp, int family,
47663f7f392SAlexander V. Chernikov char *buf, size_t bufsize)
47763f7f392SAlexander V. Chernikov {
478a6668e31SEd Maste #if defined(INET) || defined(INET6)
47963f7f392SAlexander V. Chernikov char abuf[INET6_ADDRSTRLEN];
480a6668e31SEd Maste #endif
48163f7f392SAlexander V. Chernikov
48263f7f392SAlexander V. Chernikov const char *valid = (lle->r_flags & RLLE_VALID) ? "valid" : "no_l2";
48363f7f392SAlexander V. Chernikov const char *upper_str = rib_print_family(llentry_get_upper_family(lle, family));
48463f7f392SAlexander V. Chernikov
48563f7f392SAlexander V. Chernikov switch (family) {
48663f7f392SAlexander V. Chernikov #ifdef INET
48763f7f392SAlexander V. Chernikov case AF_INET:
48863f7f392SAlexander V. Chernikov inet_ntop(AF_INET, &lle->r_l3addr.addr4, abuf, sizeof(abuf));
48963f7f392SAlexander V. Chernikov snprintf(buf, bufsize, "lle/%s/%s/%s/%s", upper_str,
49063f7f392SAlexander V. Chernikov valid, if_name(ifp), abuf);
49163f7f392SAlexander V. Chernikov break;
49263f7f392SAlexander V. Chernikov #endif
49363f7f392SAlexander V. Chernikov #ifdef INET6
49463f7f392SAlexander V. Chernikov case AF_INET6:
49563f7f392SAlexander V. Chernikov inet_ntop(AF_INET6, &lle->r_l3addr.addr6, abuf, sizeof(abuf));
49663f7f392SAlexander V. Chernikov snprintf(buf, bufsize, "lle/%s/%s/%s/%s", upper_str,
49763f7f392SAlexander V. Chernikov valid, if_name(ifp), abuf);
49863f7f392SAlexander V. Chernikov break;
49963f7f392SAlexander V. Chernikov #endif
50063f7f392SAlexander V. Chernikov default:
50163f7f392SAlexander V. Chernikov snprintf(buf, bufsize, "lle/%s/%s/%s/????", upper_str,
50263f7f392SAlexander V. Chernikov valid, if_name(ifp));
50363f7f392SAlexander V. Chernikov break;
50463f7f392SAlexander V. Chernikov }
50563f7f392SAlexander V. Chernikov
50663f7f392SAlexander V. Chernikov return (buf);
50763f7f392SAlexander V. Chernikov }
50863f7f392SAlexander V. Chernikov
50963f7f392SAlexander V. Chernikov char *
llentry_print_buf_lltable(const struct llentry * lle,char * buf,size_t bufsize)51063f7f392SAlexander V. Chernikov llentry_print_buf_lltable(const struct llentry *lle, char *buf, size_t bufsize)
51163f7f392SAlexander V. Chernikov {
51263f7f392SAlexander V. Chernikov struct lltable *tbl = lle->lle_tbl;
51363f7f392SAlexander V. Chernikov
51463f7f392SAlexander V. Chernikov return (llentry_print_buf(lle, lltable_get_ifp(tbl), lltable_get_af(tbl), buf, bufsize));
51563f7f392SAlexander V. Chernikov }
51663f7f392SAlexander V. Chernikov
51763f7f392SAlexander V. Chernikov /*
518f3a3b061SAlexander V. Chernikov * Requests feedback from the datapath.
519f3a3b061SAlexander V. Chernikov * First packet using @lle should result in
520f3a3b061SAlexander V. Chernikov * setting r_skip_req back to 0 and updating
521f3a3b061SAlexander V. Chernikov * lle_hittime to the current time_uptime.
522f3a3b061SAlexander V. Chernikov */
523f3a3b061SAlexander V. Chernikov void
llentry_request_feedback(struct llentry * lle)524f3a3b061SAlexander V. Chernikov llentry_request_feedback(struct llentry *lle)
525f3a3b061SAlexander V. Chernikov {
526c541bd36SAlexander V. Chernikov struct llentry *child_lle;
527c541bd36SAlexander V. Chernikov
528f3a3b061SAlexander V. Chernikov LLE_REQ_LOCK(lle);
529f3a3b061SAlexander V. Chernikov lle->r_skip_req = 1;
530f3a3b061SAlexander V. Chernikov LLE_REQ_UNLOCK(lle);
531c541bd36SAlexander V. Chernikov
532c541bd36SAlexander V. Chernikov CK_SLIST_FOREACH(child_lle, &lle->lle_children, lle_child_next) {
533c541bd36SAlexander V. Chernikov LLE_REQ_LOCK(child_lle);
534c541bd36SAlexander V. Chernikov child_lle->r_skip_req = 1;
535c541bd36SAlexander V. Chernikov LLE_REQ_UNLOCK(child_lle);
536c541bd36SAlexander V. Chernikov }
537f3a3b061SAlexander V. Chernikov }
538f3a3b061SAlexander V. Chernikov
539f3a3b061SAlexander V. Chernikov /*
540f3a3b061SAlexander V. Chernikov * Updates the lle state to mark it has been used
541f3a3b061SAlexander V. Chernikov * and record the time.
542f3a3b061SAlexander V. Chernikov * Used by the llentry_provide_feedback() wrapper.
543f3a3b061SAlexander V. Chernikov */
544f3a3b061SAlexander V. Chernikov void
llentry_mark_used(struct llentry * lle)545f3a3b061SAlexander V. Chernikov llentry_mark_used(struct llentry *lle)
546f3a3b061SAlexander V. Chernikov {
547f3a3b061SAlexander V. Chernikov LLE_REQ_LOCK(lle);
548f3a3b061SAlexander V. Chernikov lle->r_skip_req = 0;
549f3a3b061SAlexander V. Chernikov lle->lle_hittime = time_uptime;
550f3a3b061SAlexander V. Chernikov LLE_REQ_UNLOCK(lle);
551f3a3b061SAlexander V. Chernikov }
552f3a3b061SAlexander V. Chernikov
553f3a3b061SAlexander V. Chernikov /*
554f3a3b061SAlexander V. Chernikov * Fetches the time when lle was used.
555f3a3b061SAlexander V. Chernikov * Return 0 if the entry was not used, relevant time_uptime
556f3a3b061SAlexander V. Chernikov * otherwise.
557f3a3b061SAlexander V. Chernikov */
558c541bd36SAlexander V. Chernikov static time_t
llentry_get_hittime_raw(struct llentry * lle)559c541bd36SAlexander V. Chernikov llentry_get_hittime_raw(struct llentry *lle)
560f3a3b061SAlexander V. Chernikov {
561f3a3b061SAlexander V. Chernikov time_t lle_hittime = 0;
562f3a3b061SAlexander V. Chernikov
563f3a3b061SAlexander V. Chernikov LLE_REQ_LOCK(lle);
564f3a3b061SAlexander V. Chernikov if ((lle->r_skip_req == 0) && (lle_hittime < lle->lle_hittime))
565f3a3b061SAlexander V. Chernikov lle_hittime = lle->lle_hittime;
566f3a3b061SAlexander V. Chernikov LLE_REQ_UNLOCK(lle);
567f3a3b061SAlexander V. Chernikov
568f3a3b061SAlexander V. Chernikov return (lle_hittime);
569f3a3b061SAlexander V. Chernikov }
570f3a3b061SAlexander V. Chernikov
571c541bd36SAlexander V. Chernikov time_t
llentry_get_hittime(struct llentry * lle)572c541bd36SAlexander V. Chernikov llentry_get_hittime(struct llentry *lle)
573c541bd36SAlexander V. Chernikov {
574c541bd36SAlexander V. Chernikov time_t lle_hittime = 0;
575c541bd36SAlexander V. Chernikov struct llentry *child_lle;
576c541bd36SAlexander V. Chernikov
577c541bd36SAlexander V. Chernikov lle_hittime = llentry_get_hittime_raw(lle);
578c541bd36SAlexander V. Chernikov
579c541bd36SAlexander V. Chernikov CK_SLIST_FOREACH(child_lle, &lle->lle_children, lle_child_next) {
580c541bd36SAlexander V. Chernikov time_t hittime = llentry_get_hittime_raw(child_lle);
581c541bd36SAlexander V. Chernikov if (hittime > lle_hittime)
582c541bd36SAlexander V. Chernikov lle_hittime = hittime;
583c541bd36SAlexander V. Chernikov }
584c541bd36SAlexander V. Chernikov
585c541bd36SAlexander V. Chernikov return (lle_hittime);
586c541bd36SAlexander V. Chernikov }
587c541bd36SAlexander V. Chernikov
588f3a3b061SAlexander V. Chernikov /*
5894fb3a820SAlexander V. Chernikov * Update link-layer header for given @lle after
5904fb3a820SAlexander V. Chernikov * interface lladdr was changed.
5914fb3a820SAlexander V. Chernikov */
5924fb3a820SAlexander V. Chernikov static int
llentry_update_ifaddr(struct lltable * llt,struct llentry * lle,void * farg)5934fb3a820SAlexander V. Chernikov llentry_update_ifaddr(struct lltable *llt, struct llentry *lle, void *farg)
5944fb3a820SAlexander V. Chernikov {
5954fb3a820SAlexander V. Chernikov struct ifnet *ifp;
5964fb3a820SAlexander V. Chernikov u_char linkhdr[LLE_MAX_LINKHDR];
5974fb3a820SAlexander V. Chernikov size_t linkhdrsize;
5984fb3a820SAlexander V. Chernikov u_char *lladdr;
5994fb3a820SAlexander V. Chernikov int lladdr_off;
6004fb3a820SAlexander V. Chernikov
6014fb3a820SAlexander V. Chernikov ifp = (struct ifnet *)farg;
6024fb3a820SAlexander V. Chernikov
6034fb3a820SAlexander V. Chernikov lladdr = lle->ll_addr;
6044fb3a820SAlexander V. Chernikov
6054fb3a820SAlexander V. Chernikov LLE_WLOCK(lle);
6064fb3a820SAlexander V. Chernikov if ((lle->la_flags & LLE_VALID) == 0) {
6074fb3a820SAlexander V. Chernikov LLE_WUNLOCK(lle);
6084fb3a820SAlexander V. Chernikov return (0);
6094fb3a820SAlexander V. Chernikov }
6104fb3a820SAlexander V. Chernikov
6114fb3a820SAlexander V. Chernikov if ((lle->la_flags & LLE_IFADDR) != 0)
6124fb3a820SAlexander V. Chernikov lladdr = IF_LLADDR(ifp);
6134fb3a820SAlexander V. Chernikov
6144fb3a820SAlexander V. Chernikov linkhdrsize = sizeof(linkhdr);
6154fb3a820SAlexander V. Chernikov lltable_calc_llheader(ifp, llt->llt_af, lladdr, linkhdr, &linkhdrsize,
6164fb3a820SAlexander V. Chernikov &lladdr_off);
6174fb3a820SAlexander V. Chernikov memcpy(lle->r_linkdata, linkhdr, linkhdrsize);
6184fb3a820SAlexander V. Chernikov LLE_WUNLOCK(lle);
6194fb3a820SAlexander V. Chernikov
6204fb3a820SAlexander V. Chernikov return (0);
6214fb3a820SAlexander V. Chernikov }
6224fb3a820SAlexander V. Chernikov
6234fb3a820SAlexander V. Chernikov /*
6244fb3a820SAlexander V. Chernikov * Update all calculated headers for given @llt
6254fb3a820SAlexander V. Chernikov */
6264fb3a820SAlexander V. Chernikov void
lltable_update_ifaddr(struct lltable * llt)6274fb3a820SAlexander V. Chernikov lltable_update_ifaddr(struct lltable *llt)
6284fb3a820SAlexander V. Chernikov {
6294fb3a820SAlexander V. Chernikov
6304fb3a820SAlexander V. Chernikov if (llt->llt_ifp->if_flags & IFF_LOOPBACK)
6314fb3a820SAlexander V. Chernikov return;
6324fb3a820SAlexander V. Chernikov
6334fb3a820SAlexander V. Chernikov IF_AFDATA_WLOCK(llt->llt_ifp);
6344fb3a820SAlexander V. Chernikov lltable_foreach_lle(llt, llentry_update_ifaddr, llt->llt_ifp);
6354fb3a820SAlexander V. Chernikov IF_AFDATA_WUNLOCK(llt->llt_ifp);
6364fb3a820SAlexander V. Chernikov }
6374fb3a820SAlexander V. Chernikov
6384fb3a820SAlexander V. Chernikov /*
6395a255516SAlexander V. Chernikov *
640a4641f4eSPedro F. Giffuni * Performs generic cleanup routines and frees lle.
6415a255516SAlexander V. Chernikov *
6425a255516SAlexander V. Chernikov * Called for non-linked entries, with callouts and
6435a255516SAlexander V. Chernikov * other AF-specific cleanups performed.
6445a255516SAlexander V. Chernikov *
6455a255516SAlexander V. Chernikov * @lle must be passed WLOCK'ed
64611cdad98SAlexander V. Chernikov *
64711cdad98SAlexander V. Chernikov * Returns the number of held packets, if any, that were dropped.
64811cdad98SAlexander V. Chernikov */
64911cdad98SAlexander V. Chernikov size_t
llentry_free(struct llentry * lle)65011cdad98SAlexander V. Chernikov llentry_free(struct llentry *lle)
65111cdad98SAlexander V. Chernikov {
65211cdad98SAlexander V. Chernikov size_t pkts_dropped;
65311cdad98SAlexander V. Chernikov
65411cdad98SAlexander V. Chernikov LLE_WLOCK_ASSERT(lle);
65511cdad98SAlexander V. Chernikov
656d3cdb716SAlexander V. Chernikov KASSERT((lle->la_flags & LLE_LINKED) == 0, ("freeing linked lle"));
65711cdad98SAlexander V. Chernikov
65811cdad98SAlexander V. Chernikov pkts_dropped = lltable_drop_entry_queue(lle);
65911cdad98SAlexander V. Chernikov
660acf673edSAndrey V. Elsukov /* cancel timer */
661acf673edSAndrey V. Elsukov if (callout_stop(&lle->lle_timer) > 0)
662acf673edSAndrey V. Elsukov LLE_REMREF(lle);
66382f39c91SKip Macy LLE_FREE_LOCKED(lle);
664e162ea60SGeorge V. Neville-Neil
665e162ea60SGeorge V. Neville-Neil return (pkts_dropped);
66682f39c91SKip Macy }
66782f39c91SKip Macy
668adfc35ffSKip Macy /*
66982f39c91SKip Macy * Free all entries from given table and free itself.
67082f39c91SKip Macy */
67111cdad98SAlexander V. Chernikov
67211cdad98SAlexander V. Chernikov static int
lltable_free_cb(struct lltable * llt,struct llentry * lle,void * farg)67311cdad98SAlexander V. Chernikov lltable_free_cb(struct lltable *llt, struct llentry *lle, void *farg)
67411cdad98SAlexander V. Chernikov {
67511cdad98SAlexander V. Chernikov struct llentries *dchain;
67611cdad98SAlexander V. Chernikov
67711cdad98SAlexander V. Chernikov dchain = (struct llentries *)farg;
67811cdad98SAlexander V. Chernikov
67911cdad98SAlexander V. Chernikov LLE_WLOCK(lle);
6800f8d79d9SMatt Macy CK_LIST_INSERT_HEAD(dchain, lle, lle_chain);
68111cdad98SAlexander V. Chernikov
68211cdad98SAlexander V. Chernikov return (0);
68311cdad98SAlexander V. Chernikov }
68411cdad98SAlexander V. Chernikov
68511cdad98SAlexander V. Chernikov /*
68611cdad98SAlexander V. Chernikov * Free all entries from given table and free itself.
68711cdad98SAlexander V. Chernikov */
68882f39c91SKip Macy void
lltable_free(struct lltable * llt)68982f39c91SKip Macy lltable_free(struct lltable *llt)
69082f39c91SKip Macy {
69182f39c91SKip Macy struct llentry *lle, *next;
69211cdad98SAlexander V. Chernikov struct llentries dchain;
69382f39c91SKip Macy
69482f39c91SKip Macy KASSERT(llt != NULL, ("%s: llt is NULL", __func__));
69582f39c91SKip Macy
696721cd2e0SAlexander V. Chernikov lltable_unlink(llt);
69782f39c91SKip Macy
6984f6c66ccSMatt Macy CK_LIST_INIT(&dchain);
699ea537929SGleb Smirnoff IF_AFDATA_WLOCK(llt->llt_ifp);
70011cdad98SAlexander V. Chernikov /* Push all lles to @dchain */
70111cdad98SAlexander V. Chernikov lltable_foreach_lle(llt, lltable_free_cb, &dchain);
70211cdad98SAlexander V. Chernikov llentries_unlink(llt, &dchain);
70311cdad98SAlexander V. Chernikov IF_AFDATA_WUNLOCK(llt->llt_ifp);
70411cdad98SAlexander V. Chernikov
7050f8d79d9SMatt Macy CK_LIST_FOREACH_SAFE(lle, &dchain, lle_chain, next) {
70682f39c91SKip Macy llentry_free(lle);
70782f39c91SKip Macy }
70882f39c91SKip Macy
709*b4c94968SGordon Bergling KASSERT(llt->llt_entries == 0, ("%s: lltable %p (%s) entries not 0: %d",
7103818c25aSBjoern A. Zeeb __func__, llt, llt->llt_ifp->if_xname, llt->llt_entries));
7113818c25aSBjoern A. Zeeb
712721cd2e0SAlexander V. Chernikov llt->llt_free_tbl(llt);
71382f39c91SKip Macy }
71482f39c91SKip Macy
7153e7a2321SAlexander V. Chernikov /*
7163e7a2321SAlexander V. Chernikov * Deletes an address from given lltable.
7173e7a2321SAlexander V. Chernikov * Used for userland interaction to remove
7183e7a2321SAlexander V. Chernikov * individual entries. Skips entries added by OS.
7193e7a2321SAlexander V. Chernikov */
7203e7a2321SAlexander V. Chernikov int
lltable_delete_addr(struct lltable * llt,u_int flags,const struct sockaddr * l3addr)7213e7a2321SAlexander V. Chernikov lltable_delete_addr(struct lltable *llt, u_int flags,
7223e7a2321SAlexander V. Chernikov const struct sockaddr *l3addr)
7233e7a2321SAlexander V. Chernikov {
7243e7a2321SAlexander V. Chernikov struct llentry *lle;
7253e7a2321SAlexander V. Chernikov struct ifnet *ifp;
7263e7a2321SAlexander V. Chernikov
7273e7a2321SAlexander V. Chernikov ifp = llt->llt_ifp;
7283e7a2321SAlexander V. Chernikov IF_AFDATA_WLOCK(ifp);
729c541bd36SAlexander V. Chernikov lle = lla_lookup(llt, LLE_SF(l3addr->sa_family, LLE_EXCLUSIVE), l3addr);
7303e7a2321SAlexander V. Chernikov
7313e7a2321SAlexander V. Chernikov if (lle == NULL) {
7323e7a2321SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp);
7333e7a2321SAlexander V. Chernikov return (ENOENT);
7343e7a2321SAlexander V. Chernikov }
7353e7a2321SAlexander V. Chernikov if ((lle->la_flags & LLE_IFADDR) != 0 && (flags & LLE_IFADDR) == 0) {
7363e7a2321SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp);
7373e7a2321SAlexander V. Chernikov LLE_WUNLOCK(lle);
7383e7a2321SAlexander V. Chernikov return (EPERM);
7393e7a2321SAlexander V. Chernikov }
7403e7a2321SAlexander V. Chernikov
7413e7a2321SAlexander V. Chernikov lltable_unlink_entry(llt, lle);
7423e7a2321SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp);
7433e7a2321SAlexander V. Chernikov
7443e7a2321SAlexander V. Chernikov llt->llt_delete_entry(llt, lle);
7453e7a2321SAlexander V. Chernikov
7463e7a2321SAlexander V. Chernikov return (0);
7473e7a2321SAlexander V. Chernikov }
7483e7a2321SAlexander V. Chernikov
749c9d763bfSQing Li void
lltable_prefix_free(int af,struct sockaddr * addr,struct sockaddr * mask,u_int flags)7503e7a2321SAlexander V. Chernikov lltable_prefix_free(int af, struct sockaddr *addr, struct sockaddr *mask,
7515b84dc78SQing Li u_int flags)
752c9d763bfSQing Li {
753c9d763bfSQing Li struct lltable *llt;
754c9d763bfSQing Li
755199511bcSAndrey V. Elsukov LLTABLE_LIST_RLOCK();
756989e0411SMarko Zec SLIST_FOREACH(llt, &V_lltables, llt_link) {
757c9d763bfSQing Li if (llt->llt_af != af)
758c9d763bfSQing Li continue;
759c9d763bfSQing Li
7603e7a2321SAlexander V. Chernikov llt->llt_prefix_free(llt, addr, mask, flags);
761c9d763bfSQing Li }
762199511bcSAndrey V. Elsukov LLTABLE_LIST_RUNLOCK();
763c9d763bfSQing Li }
764c9d763bfSQing Li
765d6cd20ccSKUROSAWA Takahiro /*
766d6cd20ccSKUROSAWA Takahiro * Delete llentries that func() returns true.
767d6cd20ccSKUROSAWA Takahiro */
768d6cd20ccSKUROSAWA Takahiro struct lle_match_data {
769d6cd20ccSKUROSAWA Takahiro struct llentries dchain;
770d6cd20ccSKUROSAWA Takahiro llt_match_cb_t *func;
771d6cd20ccSKUROSAWA Takahiro void *farg;
772d6cd20ccSKUROSAWA Takahiro };
773d6cd20ccSKUROSAWA Takahiro
774d6cd20ccSKUROSAWA Takahiro static int
lltable_delete_conditional_cb(struct lltable * llt,struct llentry * lle,void * farg)775d6cd20ccSKUROSAWA Takahiro lltable_delete_conditional_cb(struct lltable *llt, struct llentry *lle,
776d6cd20ccSKUROSAWA Takahiro void *farg)
777d6cd20ccSKUROSAWA Takahiro {
778d6cd20ccSKUROSAWA Takahiro struct lle_match_data *lmd;
779d6cd20ccSKUROSAWA Takahiro
780d6cd20ccSKUROSAWA Takahiro lmd = (struct lle_match_data *)farg;
781d6cd20ccSKUROSAWA Takahiro if (lmd->func(llt, lle, lmd->farg)) {
782d6cd20ccSKUROSAWA Takahiro LLE_WLOCK(lle);
783d6cd20ccSKUROSAWA Takahiro CK_LIST_INSERT_HEAD(&lmd->dchain, lle, lle_chain);
784d6cd20ccSKUROSAWA Takahiro }
785d6cd20ccSKUROSAWA Takahiro
786d6cd20ccSKUROSAWA Takahiro return (0);
787d6cd20ccSKUROSAWA Takahiro }
788d6cd20ccSKUROSAWA Takahiro
789d6cd20ccSKUROSAWA Takahiro void
lltable_delete_conditional(struct lltable * llt,llt_match_cb_t * func,void * farg)790d6cd20ccSKUROSAWA Takahiro lltable_delete_conditional(struct lltable *llt, llt_match_cb_t *func,
791d6cd20ccSKUROSAWA Takahiro void *farg)
792d6cd20ccSKUROSAWA Takahiro {
793d6cd20ccSKUROSAWA Takahiro struct llentry *lle, *next;
794d6cd20ccSKUROSAWA Takahiro struct lle_match_data lmd;
795d6cd20ccSKUROSAWA Takahiro
796d6cd20ccSKUROSAWA Takahiro bzero(&lmd, sizeof(lmd));
797d6cd20ccSKUROSAWA Takahiro CK_LIST_INIT(&lmd.dchain);
798d6cd20ccSKUROSAWA Takahiro lmd.func = func;
799d6cd20ccSKUROSAWA Takahiro lmd.farg = farg;
800d6cd20ccSKUROSAWA Takahiro
801d6cd20ccSKUROSAWA Takahiro IF_AFDATA_WLOCK(llt->llt_ifp);
802d6cd20ccSKUROSAWA Takahiro lltable_foreach_lle(llt, lltable_delete_conditional_cb, &lmd);
803d6cd20ccSKUROSAWA Takahiro llentries_unlink(llt, &lmd.dchain);
804d6cd20ccSKUROSAWA Takahiro IF_AFDATA_WUNLOCK(llt->llt_ifp);
805d6cd20ccSKUROSAWA Takahiro
806d6cd20ccSKUROSAWA Takahiro CK_LIST_FOREACH_SAFE(lle, &lmd.dchain, lle_chain, next)
807d6cd20ccSKUROSAWA Takahiro llt->llt_delete_entry(llt, lle);
808d6cd20ccSKUROSAWA Takahiro }
809d6cd20ccSKUROSAWA Takahiro
81082f39c91SKip Macy struct lltable *
lltable_allocate_htbl(uint32_t hsize)81141cb42a6SAlexander V. Chernikov lltable_allocate_htbl(uint32_t hsize)
81282f39c91SKip Macy {
81382f39c91SKip Macy struct lltable *llt;
81441cb42a6SAlexander V. Chernikov int i;
81582f39c91SKip Macy
81641cb42a6SAlexander V. Chernikov llt = malloc(sizeof(struct lltable), M_LLTABLE, M_WAITOK | M_ZERO);
81741cb42a6SAlexander V. Chernikov llt->llt_hsize = hsize;
81841cb42a6SAlexander V. Chernikov llt->lle_head = malloc(sizeof(struct llentries) * hsize,
81941cb42a6SAlexander V. Chernikov M_LLTABLE, M_WAITOK | M_ZERO);
82082f39c91SKip Macy
82141cb42a6SAlexander V. Chernikov for (i = 0; i < llt->llt_hsize; i++)
8224f6c66ccSMatt Macy CK_LIST_INIT(&llt->lle_head[i]);
82382f39c91SKip Macy
82411cdad98SAlexander V. Chernikov /* Set some default callbacks */
82511cdad98SAlexander V. Chernikov llt->llt_link_entry = htable_link_entry;
82611cdad98SAlexander V. Chernikov llt->llt_unlink_entry = htable_unlink_entry;
82711cdad98SAlexander V. Chernikov llt->llt_prefix_free = htable_prefix_free;
82811cdad98SAlexander V. Chernikov llt->llt_foreach_entry = htable_foreach_lle;
82941cb42a6SAlexander V. Chernikov llt->llt_free_tbl = htable_free_tbl;
83041cb42a6SAlexander V. Chernikov
83141cb42a6SAlexander V. Chernikov return (llt);
83241cb42a6SAlexander V. Chernikov }
83341cb42a6SAlexander V. Chernikov
83482f39c91SKip Macy /*
835721cd2e0SAlexander V. Chernikov * Links lltable to global llt list.
83682f39c91SKip Macy */
837721cd2e0SAlexander V. Chernikov void
lltable_link(struct lltable * llt)838721cd2e0SAlexander V. Chernikov lltable_link(struct lltable *llt)
83982f39c91SKip Macy {
84011cdad98SAlexander V. Chernikov
841199511bcSAndrey V. Elsukov LLTABLE_LIST_WLOCK();
842989e0411SMarko Zec SLIST_INSERT_HEAD(&V_lltables, llt, llt_link);
843199511bcSAndrey V. Elsukov LLTABLE_LIST_WUNLOCK();
844721cd2e0SAlexander V. Chernikov }
84582f39c91SKip Macy
846721cd2e0SAlexander V. Chernikov static void
lltable_unlink(struct lltable * llt)847721cd2e0SAlexander V. Chernikov lltable_unlink(struct lltable *llt)
848721cd2e0SAlexander V. Chernikov {
849721cd2e0SAlexander V. Chernikov
850199511bcSAndrey V. Elsukov LLTABLE_LIST_WLOCK();
851721cd2e0SAlexander V. Chernikov SLIST_REMOVE(&V_lltables, llt, lltable, llt_link);
852199511bcSAndrey V. Elsukov LLTABLE_LIST_WUNLOCK();
853721cd2e0SAlexander V. Chernikov
85482f39c91SKip Macy }
85582f39c91SKip Macy
85682f39c91SKip Macy /*
857ff3a85d3SAlexander V. Chernikov * Gets interface @ifp lltable for the specified @family
858ff3a85d3SAlexander V. Chernikov */
859ff3a85d3SAlexander V. Chernikov struct lltable *
lltable_get(struct ifnet * ifp,int family)860ff3a85d3SAlexander V. Chernikov lltable_get(struct ifnet *ifp, int family)
861ff3a85d3SAlexander V. Chernikov {
862ff3a85d3SAlexander V. Chernikov switch (family) {
863818952c6SEd Maste #ifdef INET
864ff3a85d3SAlexander V. Chernikov case AF_INET:
865ff3a85d3SAlexander V. Chernikov return (in_lltable_get(ifp));
866818952c6SEd Maste #endif
867818952c6SEd Maste #ifdef INET6
868ff3a85d3SAlexander V. Chernikov case AF_INET6:
869ff3a85d3SAlexander V. Chernikov return (in6_lltable_get(ifp));
870818952c6SEd Maste #endif
871ff3a85d3SAlexander V. Chernikov }
872ff3a85d3SAlexander V. Chernikov
873ff3a85d3SAlexander V. Chernikov return (NULL);
874ff3a85d3SAlexander V. Chernikov }
875ff3a85d3SAlexander V. Chernikov
876ff3a85d3SAlexander V. Chernikov /*
87711cdad98SAlexander V. Chernikov * External methods used by lltable consumers
87811cdad98SAlexander V. Chernikov */
87911cdad98SAlexander V. Chernikov
88011cdad98SAlexander V. Chernikov int
lltable_foreach_lle(struct lltable * llt,llt_foreach_cb_t * f,void * farg)88111cdad98SAlexander V. Chernikov lltable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg)
88211cdad98SAlexander V. Chernikov {
88311cdad98SAlexander V. Chernikov
88411cdad98SAlexander V. Chernikov return (llt->llt_foreach_entry(llt, f, farg));
88511cdad98SAlexander V. Chernikov }
88611cdad98SAlexander V. Chernikov
8875a255516SAlexander V. Chernikov struct llentry *
lltable_alloc_entry(struct lltable * llt,u_int flags,const struct sockaddr * l3addr)8885a255516SAlexander V. Chernikov lltable_alloc_entry(struct lltable *llt, u_int flags,
8895a255516SAlexander V. Chernikov const struct sockaddr *l3addr)
8905a255516SAlexander V. Chernikov {
8915a255516SAlexander V. Chernikov
8925a255516SAlexander V. Chernikov return (llt->llt_alloc_entry(llt, flags, l3addr));
8935a255516SAlexander V. Chernikov }
8945a255516SAlexander V. Chernikov
8955a255516SAlexander V. Chernikov void
lltable_free_entry(struct lltable * llt,struct llentry * lle)8965a255516SAlexander V. Chernikov lltable_free_entry(struct lltable *llt, struct llentry *lle)
8975a255516SAlexander V. Chernikov {
8985a255516SAlexander V. Chernikov
8995a255516SAlexander V. Chernikov llt->llt_free_entry(llt, lle);
9005a255516SAlexander V. Chernikov }
9015a255516SAlexander V. Chernikov
9023818c25aSBjoern A. Zeeb int
lltable_link_entry(struct lltable * llt,struct llentry * lle)90311cdad98SAlexander V. Chernikov lltable_link_entry(struct lltable *llt, struct llentry *lle)
90411cdad98SAlexander V. Chernikov {
90520b6945cSAlexander V. Chernikov int error = llt->llt_link_entry(llt, lle);
90611cdad98SAlexander V. Chernikov
90720b6945cSAlexander V. Chernikov if (error == 0 && (lle->la_flags & LLE_PUB) != 0)
90820b6945cSAlexander V. Chernikov llt->llt_flags |= LLT_ADDEDPROXY;
90920b6945cSAlexander V. Chernikov
91020b6945cSAlexander V. Chernikov return (error);
91111cdad98SAlexander V. Chernikov }
91211cdad98SAlexander V. Chernikov
913c541bd36SAlexander V. Chernikov void
lltable_link_child_entry(struct llentry * lle,struct llentry * child_lle)914c541bd36SAlexander V. Chernikov lltable_link_child_entry(struct llentry *lle, struct llentry *child_lle)
915c541bd36SAlexander V. Chernikov {
916c541bd36SAlexander V. Chernikov child_lle->lle_parent = lle;
917c541bd36SAlexander V. Chernikov child_lle->lle_tbl = lle->lle_tbl;
918c541bd36SAlexander V. Chernikov child_lle->la_flags |= LLE_LINKED;
919c541bd36SAlexander V. Chernikov CK_SLIST_INSERT_HEAD(&lle->lle_children, child_lle, lle_child_next);
920c541bd36SAlexander V. Chernikov }
921c541bd36SAlexander V. Chernikov
922c541bd36SAlexander V. Chernikov void
lltable_unlink_child_entry(struct llentry * child_lle)923c541bd36SAlexander V. Chernikov lltable_unlink_child_entry(struct llentry *child_lle)
924c541bd36SAlexander V. Chernikov {
925c541bd36SAlexander V. Chernikov struct llentry *lle = child_lle->lle_parent;
926c541bd36SAlexander V. Chernikov
927c541bd36SAlexander V. Chernikov child_lle->la_flags &= ~LLE_LINKED;
928c541bd36SAlexander V. Chernikov child_lle->lle_parent = NULL;
929c541bd36SAlexander V. Chernikov CK_SLIST_REMOVE(&lle->lle_children, child_lle, llentry, lle_child_next);
930c541bd36SAlexander V. Chernikov }
931c541bd36SAlexander V. Chernikov
9323818c25aSBjoern A. Zeeb int
lltable_unlink_entry(struct lltable * llt,struct llentry * lle)93311cdad98SAlexander V. Chernikov lltable_unlink_entry(struct lltable *llt, struct llentry *lle)
93411cdad98SAlexander V. Chernikov {
93511cdad98SAlexander V. Chernikov
9363818c25aSBjoern A. Zeeb return (llt->llt_unlink_entry(lle));
93711cdad98SAlexander V. Chernikov }
93811cdad98SAlexander V. Chernikov
93911cdad98SAlexander V. Chernikov void
lltable_fill_sa_entry(const struct llentry * lle,struct sockaddr * sa)94011cdad98SAlexander V. Chernikov lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa)
94111cdad98SAlexander V. Chernikov {
94211cdad98SAlexander V. Chernikov struct lltable *llt;
94311cdad98SAlexander V. Chernikov
94411cdad98SAlexander V. Chernikov llt = lle->lle_tbl;
94511cdad98SAlexander V. Chernikov llt->llt_fill_sa_entry(lle, sa);
94611cdad98SAlexander V. Chernikov }
94711cdad98SAlexander V. Chernikov
94811cdad98SAlexander V. Chernikov struct ifnet *
lltable_get_ifp(const struct lltable * llt)94911cdad98SAlexander V. Chernikov lltable_get_ifp(const struct lltable *llt)
95011cdad98SAlexander V. Chernikov {
95111cdad98SAlexander V. Chernikov
95211cdad98SAlexander V. Chernikov return (llt->llt_ifp);
95311cdad98SAlexander V. Chernikov }
95411cdad98SAlexander V. Chernikov
95511cdad98SAlexander V. Chernikov int
lltable_get_af(const struct lltable * llt)95611cdad98SAlexander V. Chernikov lltable_get_af(const struct lltable *llt)
95711cdad98SAlexander V. Chernikov {
95811cdad98SAlexander V. Chernikov
95911cdad98SAlexander V. Chernikov return (llt->llt_af);
96011cdad98SAlexander V. Chernikov }
96111cdad98SAlexander V. Chernikov
96211cdad98SAlexander V. Chernikov /*
963b4b1367aSAlexander V. Chernikov * Called in route_output when rtm_flags contains RTF_LLDATA.
96482f39c91SKip Macy */
96582f39c91SKip Macy int
lla_rt_output(struct rt_msghdr * rtm,struct rt_addrinfo * info)96682f39c91SKip Macy lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info)
96782f39c91SKip Macy {
96882f39c91SKip Macy struct sockaddr_dl *dl =
96982f39c91SKip Macy (struct sockaddr_dl *)info->rti_info[RTAX_GATEWAY];
97082f39c91SKip Macy struct sockaddr *dst = (struct sockaddr *)info->rti_info[RTAX_DST];
97182f39c91SKip Macy struct ifnet *ifp;
97282f39c91SKip Macy struct lltable *llt;
9735a255516SAlexander V. Chernikov struct llentry *lle, *lle_tmp;
9744fb3a820SAlexander V. Chernikov uint8_t linkhdr[LLE_MAX_LINKHDR];
9754fb3a820SAlexander V. Chernikov size_t linkhdrsize;
9764fb3a820SAlexander V. Chernikov int lladdr_off;
977b4b1367aSAlexander V. Chernikov u_int laflags = 0;
978b4b1367aSAlexander V. Chernikov int error;
97982f39c91SKip Macy
980c83dda36SAlexander V. Chernikov if (dl == NULL || dl->sdl_family != AF_LINK)
981c83dda36SAlexander V. Chernikov return (EINVAL);
9821910bfcbSGleb Smirnoff
983e5b394f2SAlexander V. Chernikov /* XXX: should be ntohs() */
98482f39c91SKip Macy ifp = ifnet_byindex(dl->sdl_index);
98582f39c91SKip Macy if (ifp == NULL) {
98682f39c91SKip Macy log(LOG_INFO, "%s: invalid ifp (sdl_index %d)\n",
98782f39c91SKip Macy __func__, dl->sdl_index);
98882f39c91SKip Macy return EINVAL;
98982f39c91SKip Macy }
99082f39c91SKip Macy
991ff3a85d3SAlexander V. Chernikov llt = lltable_get(ifp, dst->sa_family);
992ff3a85d3SAlexander V. Chernikov
993c83dda36SAlexander V. Chernikov if (llt == NULL)
994c83dda36SAlexander V. Chernikov return (ESRCH);
99582f39c91SKip Macy
996b4b1367aSAlexander V. Chernikov error = 0;
99782f39c91SKip Macy
998b4b1367aSAlexander V. Chernikov switch (rtm->rtm_type) {
999b4b1367aSAlexander V. Chernikov case RTM_ADD:
1000b4b1367aSAlexander V. Chernikov /* Add static LLE */
10013b0fd911SAlexander V. Chernikov laflags = 0;
10023b0fd911SAlexander V. Chernikov if (rtm->rtm_rmx.rmx_expire == 0)
10033b0fd911SAlexander V. Chernikov laflags = LLE_STATIC;
10043b0fd911SAlexander V. Chernikov lle = lltable_alloc_entry(llt, laflags, dst);
10055a255516SAlexander V. Chernikov if (lle == NULL)
1006b4b1367aSAlexander V. Chernikov return (ENOMEM);
1007b4b1367aSAlexander V. Chernikov
10084fb3a820SAlexander V. Chernikov linkhdrsize = sizeof(linkhdr);
10094fb3a820SAlexander V. Chernikov if (lltable_calc_llheader(ifp, dst->sa_family, LLADDR(dl),
1010990a6d18SMark Johnston linkhdr, &linkhdrsize, &lladdr_off) != 0) {
1011990a6d18SMark Johnston lltable_free_entry(llt, lle);
10124fb3a820SAlexander V. Chernikov return (EINVAL);
1013990a6d18SMark Johnston }
10144fb3a820SAlexander V. Chernikov lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize,
10154fb3a820SAlexander V. Chernikov lladdr_off);
1016b4b1367aSAlexander V. Chernikov if ((rtm->rtm_flags & RTF_ANNOUNCE))
1017b4b1367aSAlexander V. Chernikov lle->la_flags |= LLE_PUB;
101882f39c91SKip Macy lle->la_expire = rtm->rtm_rmx.rmx_expire;
10193b0fd911SAlexander V. Chernikov
102082f39c91SKip Macy laflags = lle->la_flags;
10215a255516SAlexander V. Chernikov
10225a255516SAlexander V. Chernikov /* Try to link new entry */
10235a255516SAlexander V. Chernikov lle_tmp = NULL;
10245a255516SAlexander V. Chernikov IF_AFDATA_WLOCK(ifp);
10255a255516SAlexander V. Chernikov LLE_WLOCK(lle);
10265a255516SAlexander V. Chernikov lle_tmp = lla_lookup(llt, LLE_EXCLUSIVE, dst);
10275a255516SAlexander V. Chernikov if (lle_tmp != NULL) {
10285a255516SAlexander V. Chernikov /* Check if we are trying to replace immutable entry */
10295a255516SAlexander V. Chernikov if ((lle_tmp->la_flags & LLE_IFADDR) != 0) {
1030b4b1367aSAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp);
10315a255516SAlexander V. Chernikov LLE_WUNLOCK(lle_tmp);
10325a255516SAlexander V. Chernikov lltable_free_entry(llt, lle);
10335a255516SAlexander V. Chernikov return (EPERM);
10345a255516SAlexander V. Chernikov }
10355a255516SAlexander V. Chernikov /* Unlink existing entry from table */
10365a255516SAlexander V. Chernikov lltable_unlink_entry(llt, lle_tmp);
10375a255516SAlexander V. Chernikov }
10385a255516SAlexander V. Chernikov lltable_link_entry(llt, lle);
10395a255516SAlexander V. Chernikov IF_AFDATA_WUNLOCK(ifp);
10405a255516SAlexander V. Chernikov
10415a255516SAlexander V. Chernikov if (lle_tmp != NULL) {
10425a255516SAlexander V. Chernikov EVENTHANDLER_INVOKE(lle_event, lle_tmp,LLENTRY_EXPIRED);
10435a255516SAlexander V. Chernikov lltable_free_entry(llt, lle_tmp);
10445a255516SAlexander V. Chernikov }
10455a255516SAlexander V. Chernikov
10465a255516SAlexander V. Chernikov /*
10475a255516SAlexander V. Chernikov * By invoking LLE handler here we might get
10485a255516SAlexander V. Chernikov * two events on static LLE entry insertion
10495a255516SAlexander V. Chernikov * in routing socket. However, since we might have
10505a255516SAlexander V. Chernikov * other subscribers we need to generate this event.
10515a255516SAlexander V. Chernikov */
10525a255516SAlexander V. Chernikov EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_RESOLVED);
10535a255516SAlexander V. Chernikov LLE_WUNLOCK(lle);
105477001f9bSKUROSAWA Takahiro llt->llt_post_resolved(llt, lle);
1055b4b1367aSAlexander V. Chernikov break;
1056b4b1367aSAlexander V. Chernikov
1057b4b1367aSAlexander V. Chernikov case RTM_DELETE:
10583e7a2321SAlexander V. Chernikov return (lltable_delete_addr(llt, 0, dst));
1059b4b1367aSAlexander V. Chernikov
1060b4b1367aSAlexander V. Chernikov default:
1061b4b1367aSAlexander V. Chernikov error = EINVAL;
1062b4b1367aSAlexander V. Chernikov }
106382f39c91SKip Macy
106482f39c91SKip Macy return (error);
106582f39c91SKip Macy }
1066989e0411SMarko Zec
1067335b943fSBjoern A. Zeeb #ifdef DDB
1068335b943fSBjoern A. Zeeb static void
llatbl_lle_show(struct llentry * lle)10696e281255SR. Christian McDonald llatbl_lle_show(struct llentry *lle)
1070335b943fSBjoern A. Zeeb {
1071335b943fSBjoern A. Zeeb uint8_t octet[6];
10726e281255SR. Christian McDonald sa_family_t af = AF_UNSPEC;
10736e281255SR. Christian McDonald char l3_addr_fmt[] = " l3_addr=%s (af=%d)\n";
1074335b943fSBjoern A. Zeeb
1075335b943fSBjoern A. Zeeb db_printf("lle=%p\n", lle);
10760f8d79d9SMatt Macy db_printf(" lle_next=%p\n", lle->lle_next.cle_next);
1077335b943fSBjoern A. Zeeb db_printf(" lle_lock=%p\n", &lle->lle_lock);
1078335b943fSBjoern A. Zeeb db_printf(" lle_tbl=%p\n", lle->lle_tbl);
1079335b943fSBjoern A. Zeeb db_printf(" lle_head=%p\n", lle->lle_head);
1080335b943fSBjoern A. Zeeb db_printf(" la_hold=%p\n", lle->la_hold);
1081e162ea60SGeorge V. Neville-Neil db_printf(" la_numheld=%d\n", lle->la_numheld);
1082335b943fSBjoern A. Zeeb db_printf(" la_expire=%ju\n", (uintmax_t)lle->la_expire);
1083335b943fSBjoern A. Zeeb db_printf(" la_flags=0x%04x\n", lle->la_flags);
1084335b943fSBjoern A. Zeeb db_printf(" la_asked=%u\n", lle->la_asked);
1085335b943fSBjoern A. Zeeb db_printf(" la_preempt=%u\n", lle->la_preempt);
1086335b943fSBjoern A. Zeeb db_printf(" ln_state=%d\n", lle->ln_state);
1087335b943fSBjoern A. Zeeb db_printf(" ln_router=%u\n", lle->ln_router);
1088335b943fSBjoern A. Zeeb db_printf(" ln_ntick=%ju\n", (uintmax_t)lle->ln_ntick);
1089335b943fSBjoern A. Zeeb db_printf(" lle_refcnt=%d\n", lle->lle_refcnt);
10904fb3a820SAlexander V. Chernikov bcopy(lle->ll_addr, octet, sizeof(octet));
1091335b943fSBjoern A. Zeeb db_printf(" ll_addr=%02x:%02x:%02x:%02x:%02x:%02x\n",
1092335b943fSBjoern A. Zeeb octet[0], octet[1], octet[2], octet[3], octet[4], octet[5]);
10930447c136SAlexander V. Chernikov db_printf(" lle_timer=%p\n", &lle->lle_timer);
1094335b943fSBjoern A. Zeeb
10956e281255SR. Christian McDonald if (lle->lle_tbl) {
10966e281255SR. Christian McDonald af = lle->lle_tbl->llt_af;
10976e281255SR. Christian McDonald }
10986e281255SR. Christian McDonald
10996e281255SR. Christian McDonald switch (af) {
1100335b943fSBjoern A. Zeeb #ifdef INET
1101335b943fSBjoern A. Zeeb case AF_INET:
1102335b943fSBjoern A. Zeeb {
11036e281255SR. Christian McDonald struct sockaddr_in sin;
1104335b943fSBjoern A. Zeeb char l3s[INET_ADDRSTRLEN];
1105335b943fSBjoern A. Zeeb
11066e281255SR. Christian McDonald lltable_fill_sa_entry(lle, (struct sockaddr *)&sin);
11076e281255SR. Christian McDonald (void) inet_ntop(af, &sin.sin_addr, l3s, sizeof(l3s));
11086e281255SR. Christian McDonald db_printf(l3_addr_fmt, l3s, af);
1109335b943fSBjoern A. Zeeb break;
1110335b943fSBjoern A. Zeeb }
1111335b943fSBjoern A. Zeeb #endif
1112335b943fSBjoern A. Zeeb #ifdef INET6
1113335b943fSBjoern A. Zeeb case AF_INET6:
1114335b943fSBjoern A. Zeeb {
11156e281255SR. Christian McDonald struct sockaddr_in6 sin6;
1116335b943fSBjoern A. Zeeb char l3s[INET6_ADDRSTRLEN];
1117335b943fSBjoern A. Zeeb
11186e281255SR. Christian McDonald lltable_fill_sa_entry(lle, (struct sockaddr *)&sin6);
11196e281255SR. Christian McDonald (void) inet_ntop(af, &sin6.sin6_addr, l3s, sizeof(l3s));
11206e281255SR. Christian McDonald db_printf(l3_addr_fmt, l3s, af);
1121335b943fSBjoern A. Zeeb break;
1122335b943fSBjoern A. Zeeb }
1123335b943fSBjoern A. Zeeb #endif
1124335b943fSBjoern A. Zeeb default:
11256e281255SR. Christian McDonald db_printf(l3_addr_fmt, "N/A", af);
1126335b943fSBjoern A. Zeeb break;
1127335b943fSBjoern A. Zeeb }
1128335b943fSBjoern A. Zeeb }
1129335b943fSBjoern A. Zeeb
DB_SHOW_COMMAND(llentry,db_show_llentry)1130335b943fSBjoern A. Zeeb DB_SHOW_COMMAND(llentry, db_show_llentry)
1131335b943fSBjoern A. Zeeb {
1132335b943fSBjoern A. Zeeb
1133335b943fSBjoern A. Zeeb if (!have_addr) {
1134335b943fSBjoern A. Zeeb db_printf("usage: show llentry <struct llentry *>\n");
1135335b943fSBjoern A. Zeeb return;
1136335b943fSBjoern A. Zeeb }
1137335b943fSBjoern A. Zeeb
11386e281255SR. Christian McDonald llatbl_lle_show((struct llentry *)addr);
1139335b943fSBjoern A. Zeeb }
1140335b943fSBjoern A. Zeeb
1141335b943fSBjoern A. Zeeb static void
llatbl_llt_show(struct lltable * llt)1142335b943fSBjoern A. Zeeb llatbl_llt_show(struct lltable *llt)
1143335b943fSBjoern A. Zeeb {
1144335b943fSBjoern A. Zeeb int i;
1145335b943fSBjoern A. Zeeb struct llentry *lle;
1146335b943fSBjoern A. Zeeb
1147335b943fSBjoern A. Zeeb db_printf("llt=%p llt_af=%d llt_ifp=%p\n",
1148335b943fSBjoern A. Zeeb llt, llt->llt_af, llt->llt_ifp);
1149335b943fSBjoern A. Zeeb
11503a749863SAlexander V. Chernikov for (i = 0; i < llt->llt_hsize; i++) {
11514f6c66ccSMatt Macy CK_LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
11526e281255SR. Christian McDonald llatbl_lle_show(lle);
1153335b943fSBjoern A. Zeeb if (db_pager_quit)
1154335b943fSBjoern A. Zeeb return;
1155335b943fSBjoern A. Zeeb }
1156335b943fSBjoern A. Zeeb }
1157335b943fSBjoern A. Zeeb }
1158335b943fSBjoern A. Zeeb
DB_SHOW_COMMAND(lltable,db_show_lltable)1159335b943fSBjoern A. Zeeb DB_SHOW_COMMAND(lltable, db_show_lltable)
1160335b943fSBjoern A. Zeeb {
1161335b943fSBjoern A. Zeeb
1162335b943fSBjoern A. Zeeb if (!have_addr) {
1163335b943fSBjoern A. Zeeb db_printf("usage: show lltable <struct lltable *>\n");
1164335b943fSBjoern A. Zeeb return;
1165335b943fSBjoern A. Zeeb }
1166335b943fSBjoern A. Zeeb
1167335b943fSBjoern A. Zeeb llatbl_llt_show((struct lltable *)addr);
1168335b943fSBjoern A. Zeeb }
1169335b943fSBjoern A. Zeeb
DB_SHOW_ALL_COMMAND(lltables,db_show_all_lltables)1170335b943fSBjoern A. Zeeb DB_SHOW_ALL_COMMAND(lltables, db_show_all_lltables)
1171335b943fSBjoern A. Zeeb {
1172335b943fSBjoern A. Zeeb VNET_ITERATOR_DECL(vnet_iter);
1173335b943fSBjoern A. Zeeb struct lltable *llt;
1174335b943fSBjoern A. Zeeb
1175335b943fSBjoern A. Zeeb VNET_FOREACH(vnet_iter) {
1176335b943fSBjoern A. Zeeb CURVNET_SET_QUIET(vnet_iter);
1177335b943fSBjoern A. Zeeb #ifdef VIMAGE
1178335b943fSBjoern A. Zeeb db_printf("vnet=%p\n", curvnet);
1179335b943fSBjoern A. Zeeb #endif
1180335b943fSBjoern A. Zeeb SLIST_FOREACH(llt, &V_lltables, llt_link) {
1181335b943fSBjoern A. Zeeb db_printf("llt=%p llt_af=%d llt_ifp=%p(%s)\n",
1182335b943fSBjoern A. Zeeb llt, llt->llt_af, llt->llt_ifp,
1183335b943fSBjoern A. Zeeb (llt->llt_ifp != NULL) ?
1184335b943fSBjoern A. Zeeb llt->llt_ifp->if_xname : "?");
1185335b943fSBjoern A. Zeeb if (have_addr && addr != 0) /* verbose */
1186335b943fSBjoern A. Zeeb llatbl_llt_show(llt);
1187335b943fSBjoern A. Zeeb if (db_pager_quit) {
1188335b943fSBjoern A. Zeeb CURVNET_RESTORE();
1189335b943fSBjoern A. Zeeb return;
1190335b943fSBjoern A. Zeeb }
1191335b943fSBjoern A. Zeeb }
1192335b943fSBjoern A. Zeeb CURVNET_RESTORE();
1193335b943fSBjoern A. Zeeb }
1194335b943fSBjoern A. Zeeb }
1195335b943fSBjoern A. Zeeb #endif
1196