FreeBSD/Linux Kernel Cross Reference
sys/net/if_llatbl.c
1 /* $NetBSD: if_llatbl.c,v 1.35 2022/11/19 08:00:51 yamt Exp $ */
2 /*
3 * Copyright (c) 2004 Luigi Rizzo, Alessandro Cerri. All rights reserved.
4 * Copyright (c) 2004-2008 Qing Li. All rights reserved.
5 * Copyright (c) 2008 Kip Macy. All rights reserved.
6 * Copyright (c) 2015 The NetBSD Foundation, Inc.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30 #include <sys/cdefs.h>
31
32 #ifdef _KERNEL_OPT
33 #include "opt_ddb.h"
34 #include "opt_inet.h"
35 #include "opt_inet6.h"
36 #include "opt_net_mpsafe.h"
37 #endif
38
39 #include "arp.h"
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/malloc.h>
44 #include <sys/mbuf.h>
45 #include <sys/syslog.h>
46 #include <sys/sysctl.h>
47 #include <sys/socket.h>
48 #include <sys/socketvar.h>
49 #include <sys/kernel.h>
50 #include <sys/lock.h>
51 #include <sys/mutex.h>
52 #include <sys/rwlock.h>
53
54 #ifdef DDB
55 #include <ddb/ddb.h>
56 #endif
57
58 #include <netinet/in.h>
59 #include <net/if_llatbl.h>
60 #include <net/if.h>
61 #include <net/if_dl.h>
62 #include <net/nd.h>
63 #include <net/route.h>
64 #include <netinet/if_inarp.h>
65 #include <netinet/in_var.h>
66 #include <netinet6/in6_var.h>
67
68 static SLIST_HEAD(, lltable) lltables;
69 krwlock_t lltable_rwlock;
70 static struct pool llentry_pool;
71
72 static void lltable_unlink(struct lltable *llt);
73 static void llentries_unlink(struct lltable *llt, struct llentries *head);
74
75 static void htable_unlink_entry(struct llentry *lle);
76 static void htable_link_entry(struct lltable *llt, struct llentry *lle);
77 static int htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f,
78 void *farg);
79
80 int
81 lltable_dump_entry(struct lltable *llt, struct llentry *lle,
82 struct rt_walkarg *w, struct sockaddr *sa)
83 {
84 #define RTF_LLINFO 0x400
85 #define RTF_CLONED 0x2000
86 struct ifnet *ifp = llt->llt_ifp;
87 int error;
88 void *a;
89 struct sockaddr_dl sdl;
90 int size;
91 struct rt_addrinfo info;
92
93 memset(&info, 0, sizeof(info));
94 info.rti_info[RTAX_DST] = sa;
95
96 a = (lle->la_flags & LLE_VALID) == LLE_VALID ? &lle->ll_addr : NULL;
97 if (sockaddr_dl_init(&sdl, sizeof(sdl), ifp->if_index, ifp->if_type,
98 NULL, 0, a, ifp->if_addrlen) == NULL)
99 return EINVAL;
100
101 info.rti_info[RTAX_GATEWAY] = sstocsa(&sdl);
102 if (sa->sa_family == AF_INET && lle->la_flags & LLE_PUB) {
103 struct sockaddr_inarp *sin;
104 sin = (struct sockaddr_inarp *)sa;
105 sin->sin_other = SIN_PROXY;
106 }
107 if ((error = rt_msg3(RTM_GET, &info, 0, w, &size)))
108 return error;
109 if (w->w_where && w->w_tmem && w->w_needed <= 0) {
110 struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem;
111
112 /* Need to copy by myself */
113 rtm->rtm_index = ifp->if_index;
114 rtm->rtm_rmx.rmx_mtu = 0;
115 rtm->rtm_rmx.rmx_expire = (lle->la_flags & LLE_STATIC) ? 0 :
116 time_mono_to_wall(lle->la_expire);
117 rtm->rtm_flags = RTF_UP;
118 rtm->rtm_flags |= RTF_HOST; /* For ndp */
119 /* For backward compatibility */
120 rtm->rtm_flags |= RTF_LLINFO | RTF_CLONED;
121 rtm->rtm_flags |= (lle->la_flags & LLE_STATIC) ? RTF_STATIC : 0;
122 if (lle->la_flags & LLE_PUB)
123 rtm->rtm_flags |= RTF_ANNOUNCE;
124 rtm->rtm_addrs = info.rti_addrs;
125 if ((error = copyout(rtm, w->w_where, size)) != 0)
126 w->w_where = NULL;
127 else
128 w->w_where = (char *)w->w_where + size;
129 }
130
131 return error;
132 #undef RTF_LLINFO
133 #undef RTF_CLONED
134 }
135
136 /*
137 * Dump lle state for a specific address family.
138 */
139 static int
140 lltable_dump_af(struct lltable *llt, struct rt_walkarg *w)
141 {
142 int error;
143
144 LLTABLE_LOCK_ASSERT();
145
146 if (llt->llt_ifp->if_flags & IFF_LOOPBACK)
147 return (0);
148 error = 0;
149
150 IF_AFDATA_RLOCK(llt->llt_ifp);
151 error = lltable_foreach_lle(llt,
152 (llt_foreach_cb_t *)llt->llt_dump_entry, w);
153 IF_AFDATA_RUNLOCK(llt->llt_ifp);
154
155 return (error);
156 }
157
158 /*
159 * Dump arp state for a specific address family.
160 */
161 int
162 lltable_sysctl_dump(int af, struct rt_walkarg *w)
163 {
164 struct lltable *llt;
165 int error = 0;
166
167 LLTABLE_RLOCK();
168 SLIST_FOREACH(llt, &lltables, llt_link) {
169 if (llt->llt_af == af) {
170 error = lltable_dump_af(llt, w);
171 if (error != 0)
172 goto done;
173 }
174 }
175 done:
176 LLTABLE_RUNLOCK();
177 return (error);
178 }
179
180 /*
181 * Common function helpers for chained hash table.
182 */
183
184 /*
185 * Runs specified callback for each entry in @llt.
186 * Caller does the locking.
187 *
188 */
189 static int
190 htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg)
191 {
192 struct llentry *lle, *next;
193 int i, error;
194
195 error = 0;
196
197 for (i = 0; i < llt->llt_hsize; i++) {
198 LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
199 error = f(llt, lle, farg);
200 if (error != 0)
201 break;
202 }
203 }
204
205 return (error);
206 }
207
208 static void
209 htable_link_entry(struct lltable *llt, struct llentry *lle)
210 {
211 struct llentries *lleh;
212 uint32_t hashidx;
213
214 if ((lle->la_flags & LLE_LINKED) != 0)
215 return;
216
217 IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp);
218
219 hashidx = llt->llt_hash(lle, llt->llt_hsize);
220 lleh = &llt->lle_head[hashidx];
221
222 lle->lle_tbl = llt;
223 lle->lle_head = lleh;
224 lle->la_flags |= LLE_LINKED;
225 LIST_INSERT_HEAD(lleh, lle, lle_next);
226
227 llt->llt_lle_count++;
228 }
229
230 static void
231 htable_unlink_entry(struct llentry *lle)
232 {
233
234 if ((lle->la_flags & LLE_LINKED) != 0) {
235 IF_AFDATA_WLOCK_ASSERT(lle->lle_tbl->llt_ifp);
236 LIST_REMOVE(lle, lle_next);
237 lle->la_flags &= ~(LLE_VALID | LLE_LINKED);
238 #if 0
239 lle->lle_tbl = NULL;
240 lle->lle_head = NULL;
241 #endif
242 KASSERTMSG(lle->lle_tbl->llt_lle_count != 0,
243 "llt_lle_count=%u", lle->lle_tbl->llt_lle_count);
244 lle->lle_tbl->llt_lle_count--;
245 }
246 }
247
248 struct prefix_match_data {
249 const struct sockaddr *prefix;
250 const struct sockaddr *mask;
251 struct llentries dchain;
252 u_int flags;
253 };
254
255 static int
256 htable_prefix_free_cb(struct lltable *llt, struct llentry *lle, void *farg)
257 {
258 struct prefix_match_data *pmd;
259
260 pmd = (struct prefix_match_data *)farg;
261
262 if (llt->llt_match_prefix(pmd->prefix, pmd->mask, pmd->flags, lle)) {
263 LLE_WLOCK(lle);
264 LIST_INSERT_HEAD(&pmd->dchain, lle, lle_chain);
265 }
266
267 return (0);
268 }
269
270 static void
271 htable_prefix_free(struct lltable *llt, const struct sockaddr *prefix,
272 const struct sockaddr *mask, u_int flags)
273 {
274 struct llentry *lle, *next;
275 struct prefix_match_data pmd;
276
277 memset(&pmd, 0, sizeof(pmd));
278 pmd.prefix = prefix;
279 pmd.mask = mask;
280 pmd.flags = flags;
281 LIST_INIT(&pmd.dchain);
282
283 IF_AFDATA_WLOCK(llt->llt_ifp);
284 /* Push matching lles to chain */
285 lltable_foreach_lle(llt, htable_prefix_free_cb, &pmd);
286
287 llentries_unlink(llt, &pmd.dchain);
288 IF_AFDATA_WUNLOCK(llt->llt_ifp);
289
290 LIST_FOREACH_SAFE(lle, &pmd.dchain, lle_chain, next)
291 llt->llt_free_entry(llt, lle);
292 }
293
294 static void
295 htable_free_tbl(struct lltable *llt)
296 {
297
298 free(llt->lle_head, M_LLTABLE);
299 free(llt, M_LLTABLE);
300 }
301
302 static void
303 llentries_unlink(struct lltable *llt, struct llentries *head)
304 {
305 struct llentry *lle, *next;
306
307 LIST_FOREACH_SAFE(lle, head, lle_chain, next)
308 llt->llt_unlink_entry(lle);
309 }
310
311 /*
312 * Helper function used to drop all mbufs in hold queue.
313 *
314 * Returns the number of held packets, if any, that were dropped.
315 */
316 size_t
317 lltable_drop_entry_queue(struct llentry *lle)
318 {
319 size_t pkts_dropped;
320 struct mbuf *next;
321
322 LLE_WLOCK_ASSERT(lle);
323
324 pkts_dropped = 0;
325 while ((lle->la_numheld > 0) && (lle->la_hold != NULL)) {
326 next = lle->la_hold->m_nextpkt;
327 m_freem(lle->la_hold);
328 lle->la_hold = next;
329 lle->la_numheld--;
330 pkts_dropped++;
331 }
332
333 KASSERTMSG(lle->la_numheld == 0,
334 "la_numheld %d > 0, pkts_dropped %zd",
335 lle->la_numheld, pkts_dropped);
336
337 return (pkts_dropped);
338 }
339
340 struct llentry *
341 llentry_pool_get(int flags)
342 {
343 struct llentry *lle;
344
345 lle = pool_get(&llentry_pool, flags);
346 if (lle != NULL)
347 memset(lle, 0, sizeof(*lle));
348 return lle;
349 }
350
351 void
352 llentry_pool_put(struct llentry *lle)
353 {
354
355 pool_put(&llentry_pool, lle);
356 }
357
358 /*
359 * Deletes an address from the address table.
360 * This function is called by the timer functions
361 * such as arptimer() and nd6_llinfo_timer(), and
362 * the caller does the locking.
363 *
364 * Returns the number of held packets, if any, that were dropped.
365 */
366 size_t
367 llentry_free(struct llentry *lle)
368 {
369 struct lltable *llt;
370 size_t pkts_dropped;
371
372 LLE_WLOCK_ASSERT(lle);
373
374 lle->la_flags |= LLE_DELETED;
375
376 if ((lle->la_flags & LLE_LINKED) != 0) {
377 llt = lle->lle_tbl;
378
379 IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp);
380 llt->llt_unlink_entry(lle);
381 }
382
383 /*
384 * Stop a pending callout if one exists. If we cancel one, we have to
385 * remove a reference to avoid a leak. callout_pending is required to
386 * to exclude the case that the callout has never been scheduled.
387 */
388 /* XXX once softnet_lock goes away, we should use callout_halt */
389 if (callout_pending(&lle->la_timer)) {
390 bool expired = callout_stop(&lle->la_timer);
391 if (!expired)
392 LLE_REMREF(lle);
393 }
394
395 pkts_dropped = lltable_drop_entry_queue(lle);
396
397 LLE_FREE_LOCKED(lle);
398
399 return (pkts_dropped);
400 }
401
402 /*
403 * (al)locate an llentry for address dst (equivalent to rtalloc for new-arp).
404 *
405 * If found the llentry * is returned referenced and unlocked.
406 */
407 struct llentry *
408 llentry_alloc(struct ifnet *ifp, struct lltable *lt,
409 struct sockaddr_storage *dst)
410 {
411 struct llentry *la;
412
413 IF_AFDATA_RLOCK(ifp);
414 la = lla_lookup(lt, LLE_EXCLUSIVE, (struct sockaddr *)dst);
415 IF_AFDATA_RUNLOCK(ifp);
416 if ((la == NULL) && (ifp->if_flags & IFF_NOARP) == 0) {
417 IF_AFDATA_WLOCK(ifp);
418 la = lla_create(lt, 0, (struct sockaddr *)dst, NULL /* XXX */);
419 IF_AFDATA_WUNLOCK(ifp);
420 }
421
422 if (la != NULL) {
423 LLE_ADDREF(la);
424 LLE_WUNLOCK(la);
425 }
426
427 return (la);
428 }
429
430 /*
431 * Free all entries from given table and free itself.
432 */
433
434 static int
435 lltable_free_cb(struct lltable *llt, struct llentry *lle, void *farg)
436 {
437 struct llentries *dchain;
438
439 dchain = (struct llentries *)farg;
440
441 LLE_WLOCK(lle);
442 LIST_INSERT_HEAD(dchain, lle, lle_chain);
443
444 return (0);
445 }
446
447 /*
448 * Free all entries from given table.
449 */
450 void
451 lltable_purge_entries(struct lltable *llt)
452 {
453 struct llentry *lle, *next;
454 struct llentries dchain;
455
456 KASSERTMSG(llt != NULL, "llt is NULL");
457
458 LIST_INIT(&dchain);
459 IF_AFDATA_WLOCK(llt->llt_ifp);
460 /* Push all lles to @dchain */
461 lltable_foreach_lle(llt, lltable_free_cb, &dchain);
462 llentries_unlink(llt, &dchain);
463 IF_AFDATA_WUNLOCK(llt->llt_ifp);
464
465 LIST_FOREACH_SAFE(lle, &dchain, lle_chain, next)
466 (void)llentry_free(lle);
467 }
468
469 /*
470 * Free all entries from given table and free itself.
471 */
472 void
473 lltable_free(struct lltable *llt)
474 {
475
476 KASSERTMSG(llt != NULL, "llt is NULL");
477
478 lltable_unlink(llt);
479 lltable_purge_entries(llt);
480 llt->llt_free_tbl(llt);
481 }
482
483 void
484 lltable_drain(int af)
485 {
486 struct lltable *llt;
487 struct llentry *lle;
488 register int i;
489
490 LLTABLE_RLOCK();
491 SLIST_FOREACH(llt, &lltables, llt_link) {
492 if (llt->llt_af != af)
493 continue;
494
495 for (i=0; i < llt->llt_hsize; i++) {
496 LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
497 LLE_WLOCK(lle);
498 lltable_drop_entry_queue(lle);
499 LLE_WUNLOCK(lle);
500 }
501 }
502 }
503 LLTABLE_RUNLOCK();
504 }
505
506 void
507 lltable_prefix_free(const int af, const struct sockaddr *prefix,
508 const struct sockaddr *mask, const u_int flags)
509 {
510 struct lltable *llt;
511
512 LLTABLE_RLOCK();
513 SLIST_FOREACH(llt, &lltables, llt_link) {
514 if (llt->llt_af != af)
515 continue;
516
517 llt->llt_prefix_free(llt, prefix, mask, flags);
518 }
519 LLTABLE_RUNLOCK();
520 }
521
522 struct lltable *
523 lltable_allocate_htbl(uint32_t hsize)
524 {
525 struct lltable *llt;
526 int i;
527
528 llt = malloc(sizeof(struct lltable), M_LLTABLE, M_WAITOK | M_ZERO);
529 llt->llt_hsize = hsize;
530 llt->lle_head = malloc(sizeof(struct llentries) * hsize,
531 M_LLTABLE, M_WAITOK | M_ZERO);
532
533 for (i = 0; i < llt->llt_hsize; i++)
534 LIST_INIT(&llt->lle_head[i]);
535
536 /* Set some default callbacks */
537 llt->llt_link_entry = htable_link_entry;
538 llt->llt_unlink_entry = htable_unlink_entry;
539 llt->llt_prefix_free = htable_prefix_free;
540 llt->llt_foreach_entry = htable_foreach_lle;
541
542 llt->llt_free_tbl = htable_free_tbl;
543 #ifdef MBUFTRACE
544 llt->llt_mowner = NULL;
545 #endif
546
547 return (llt);
548 }
549
550 /*
551 * Links lltable to global llt list.
552 */
553 void
554 lltable_link(struct lltable *llt)
555 {
556
557 LLTABLE_WLOCK();
558 SLIST_INSERT_HEAD(&lltables, llt, llt_link);
559 LLTABLE_WUNLOCK();
560 }
561
562 static void
563 lltable_unlink(struct lltable *llt)
564 {
565
566 LLTABLE_WLOCK();
567 SLIST_REMOVE(&lltables, llt, lltable, llt_link);
568 LLTABLE_WUNLOCK();
569
570 }
571
572 /*
573 * External methods used by lltable consumers
574 */
575
576 int
577 lltable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg)
578 {
579
580 return (llt->llt_foreach_entry(llt, f, farg));
581 }
582
583 void
584 lltable_link_entry(struct lltable *llt, struct llentry *lle)
585 {
586
587 llt->llt_link_entry(llt, lle);
588 }
589
590 void
591 lltable_unlink_entry(struct lltable *llt, struct llentry *lle)
592 {
593
594 llt->llt_unlink_entry(lle);
595 }
596
597 void
598 lltable_free_entry(struct lltable *llt, struct llentry *lle)
599 {
600
601 llt->llt_free_entry(llt, lle);
602 }
603
604 void
605 lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa)
606 {
607 struct lltable *llt;
608
609 llt = lle->lle_tbl;
610 llt->llt_fill_sa_entry(lle, sa);
611 }
612
613 struct ifnet *
614 lltable_get_ifp(const struct lltable *llt)
615 {
616
617 return (llt->llt_ifp);
618 }
619
620 int
621 lltable_get_af(const struct lltable *llt)
622 {
623
624 return (llt->llt_af);
625 }
626
627 /*
628 * Called in route_output when rtm_flags contains RTF_LLDATA.
629 */
630 int
631 lla_rt_output(const u_char rtm_type, const int rtm_flags, const time_t rtm_expire,
632 struct rt_addrinfo *info, int sdl_index)
633 {
634 const struct sockaddr_dl *dl = satocsdl(info->rti_info[RTAX_GATEWAY]);
635 const struct sockaddr *dst = info->rti_info[RTAX_DST];
636 struct ifnet *ifp;
637 struct lltable *llt;
638 struct llentry *lle;
639 u_int laflags;
640 int error;
641 struct psref psref;
642 int bound;
643
644 KASSERTMSG(dl != NULL && dl->sdl_family == AF_LINK, "invalid dl");
645
646 bound = curlwp_bind();
647 if (sdl_index != 0)
648 ifp = if_get_byindex(sdl_index, &psref);
649 else
650 ifp = if_get_byindex(dl->sdl_index, &psref);
651 if (ifp == NULL) {
652 curlwp_bindx(bound);
653 log(LOG_INFO, "%s: invalid ifp (sdl_index %d)\n",
654 __func__, sdl_index != 0 ? sdl_index : dl->sdl_index);
655 return EINVAL;
656 }
657
658 /* XXX linked list may be too expensive */
659 LLTABLE_RLOCK();
660 SLIST_FOREACH(llt, &lltables, llt_link) {
661 if (llt->llt_af == dst->sa_family &&
662 llt->llt_ifp == ifp)
663 break;
664 }
665 LLTABLE_RUNLOCK();
666 KASSERTMSG(llt != NULL, "Yep, ugly hacks are bad");
667
668 error = 0;
669
670 switch (rtm_type) {
671 case RTM_ADD: {
672 struct rtentry *rt;
673
674 /* Never call rtalloc1 with IF_AFDATA_WLOCK */
675 rt = rtalloc1(dst, 0);
676
677 /* Add static LLE */
678 IF_AFDATA_WLOCK(ifp);
679 lle = lla_lookup(llt, LLE_EXCLUSIVE, dst);
680
681 /* Cannot overwrite an existing static entry */
682 if (lle != NULL &&
683 (lle->la_flags & LLE_STATIC || lle->la_expire == 0)) {
684 LLE_RUNLOCK(lle);
685 IF_AFDATA_WUNLOCK(ifp);
686 if (rt != NULL)
687 rt_unref(rt);
688 error = EEXIST;
689 goto out;
690 }
691
692 /*
693 * We can't overwrite an existing entry to avoid race
694 * conditions so remove it first.
695 */
696 if (lle != NULL) {
697 #if defined(INET) && NARP > 0
698 size_t pkts_dropped = llentry_free(lle);
699 if (dst->sa_family == AF_INET) {
700 arp_stat_add(ARP_STAT_DFRDROPPED,
701 (uint64_t)pkts_dropped);
702 }
703 #else
704 (void) llentry_free(lle);
705 #endif
706 }
707
708 lle = lla_create(llt, 0, dst, rt);
709 if (lle == NULL) {
710 IF_AFDATA_WUNLOCK(ifp);
711 if (rt != NULL)
712 rt_unref(rt);
713 error = ENOMEM;
714 goto out;
715 }
716
717 KASSERT(ifp->if_addrlen <= sizeof(lle->ll_addr));
718 memcpy(&lle->ll_addr, CLLADDR(dl), ifp->if_addrlen);
719 if ((rtm_flags & RTF_ANNOUNCE))
720 lle->la_flags |= LLE_PUB;
721 lle->la_flags |= LLE_VALID;
722 switch (dst->sa_family) {
723 #ifdef INET
724 case AF_INET:
725 lle->ln_state = ND_LLINFO_REACHABLE;
726 break;
727 #endif
728 #ifdef INET6
729 case AF_INET6:
730 lle->ln_state = ND_LLINFO_REACHABLE;
731 break;
732 #endif
733 }
734
735 /*
736 * NB: arp and ndp always set (RTF_STATIC | RTF_HOST)
737 */
738
739 if (rtm_expire == 0) {
740 lle->la_flags |= LLE_STATIC;
741 lle->la_expire = 0;
742 } else
743 lle->la_expire = rtm_expire;
744 laflags = lle->la_flags;
745 LLE_WUNLOCK(lle);
746 IF_AFDATA_WUNLOCK(ifp);
747 if (rt != NULL)
748 rt_unref(rt);
749 #if defined(INET) && NARP > 0
750 /* gratuitous ARP */
751 if ((laflags & LLE_PUB) && dst->sa_family == AF_INET) {
752 const struct sockaddr_in *sin;
753 struct in_ifaddr *ia;
754 struct psref _psref;
755
756 sin = satocsin(dst);
757 ia = in_get_ia_on_iface_psref(sin->sin_addr,
758 ifp, &_psref);
759 if (ia != NULL) {
760 arpannounce(ifp, &ia->ia_ifa, CLLADDR(dl));
761 ia4_release(ia, &_psref);
762 }
763 }
764 #else
765 (void)laflags;
766 #endif
767 break;
768 }
769
770 case RTM_DELETE:
771 IF_AFDATA_WLOCK(ifp);
772 error = lla_delete(llt, 0, dst);
773 IF_AFDATA_WUNLOCK(ifp);
774 error = (error == 0 ? 0 : ENOENT);
775 break;
776
777 default:
778 error = EINVAL;
779 }
780
781 out:
782 if_put(ifp, &psref);
783 curlwp_bindx(bound);
784 return (error);
785 }
786
787 void
788 lltableinit(void)
789 {
790
791 SLIST_INIT(&lltables);
792 rw_init(&lltable_rwlock);
793
794 pool_init(&llentry_pool, sizeof(struct llentry), 0, 0, 0, "llentrypl",
795 NULL, IPL_SOFTNET);
796 }
797
798 #ifdef __FreeBSD__
799 #ifdef DDB
800 struct llentry_sa {
801 struct llentry base;
802 struct sockaddr l3_addr;
803 };
804
805 static void
806 llatbl_lle_show(struct llentry_sa *la)
807 {
808 struct llentry *lle;
809 uint8_t octet[6];
810
811 lle = &la->base;
812 db_printf("lle=%p\n", lle);
813 db_printf(" lle_next=%p\n", lle->lle_next.le_next);
814 db_printf(" lle_lock=%p\n", &lle->lle_lock);
815 db_printf(" lle_tbl=%p\n", lle->lle_tbl);
816 db_printf(" lle_head=%p\n", lle->lle_head);
817 db_printf(" la_hold=%p\n", lle->la_hold);
818 db_printf(" la_numheld=%d\n", lle->la_numheld);
819 db_printf(" la_expire=%ju\n", (uintmax_t)lle->la_expire);
820 db_printf(" la_flags=0x%04x\n", lle->la_flags);
821 db_printf(" la_asked=%u\n", lle->la_asked);
822 db_printf(" la_preempt=%u\n", lle->la_preempt);
823 db_printf(" ln_byhint=%u\n", lle->ln_byhint);
824 db_printf(" ln_state=%d\n", lle->ln_state);
825 db_printf(" ln_router=%u\n", lle->ln_router);
826 db_printf(" ln_ntick=%ju\n", (uintmax_t)lle->ln_ntick);
827 db_printf(" lle_refcnt=%d\n", lle->lle_refcnt);
828 memcopy(octet, &lle->ll_addr.mac16, sizeof(octet));
829 db_printf(" ll_addr=%02x:%02x:%02x:%02x:%02x:%02x\n",
830 octet[0], octet[1], octet[2], octet[3], octet[4], octet[5]);
831 db_printf(" lle_timer=%p\n", &lle->lle_timer);
832
833 switch (la->l3_addr.sa_family) {
834 #ifdef INET
835 case AF_INET:
836 {
837 struct sockaddr_in *sin;
838 char l3s[INET_ADDRSTRLEN];
839
840 sin = (struct sockaddr_in *)&la->l3_addr;
841 inet_ntoa_r(sin->sin_addr, l3s);
842 db_printf(" l3_addr=%s\n", l3s);
843 break;
844 }
845 #endif
846 #ifdef INET6
847 case AF_INET6:
848 {
849 struct sockaddr_in6 *sin6;
850 char l3s[INET6_ADDRSTRLEN];
851
852 sin6 = (struct sockaddr_in6 *)&la->l3_addr;
853 IN6_PRINT(l3s, &sin6->sin6_addr);
854 db_printf(" l3_addr=%s\n", l3s);
855 break;
856 }
857 #endif
858 default:
859 db_printf(" l3_addr=N/A (af=%d)\n", la->l3_addr.sa_family);
860 break;
861 }
862 }
863
864 DB_SHOW_COMMAND(llentry, db_show_llentry)
865 {
866
867 if (!have_addr) {
868 db_printf("usage: show llentry <struct llentry *>\n");
869 return;
870 }
871
872 llatbl_lle_show((struct llentry_sa *)addr);
873 }
874
875 static void
876 llatbl_llt_show(struct lltable *llt)
877 {
878 int i;
879 struct llentry *lle;
880
881 db_printf("llt=%p llt_af=%d llt_ifp=%p\n",
882 llt, llt->llt_af, llt->llt_ifp);
883
884 for (i = 0; i < llt->llt_hsize; i++) {
885 LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
886
887 llatbl_lle_show((struct llentry_sa *)lle);
888 if (db_pager_quit)
889 return;
890 }
891 }
892 }
893
894 DB_SHOW_COMMAND(lltable, db_show_lltable)
895 {
896
897 if (!have_addr) {
898 db_printf("usage: show lltable <struct lltable *>\n");
899 return;
900 }
901
902 llatbl_llt_show((struct lltable *)addr);
903 }
904
905 DB_SHOW_ALL_COMMAND(lltables, db_show_all_lltables)
906 {
907 VNET_ITERATOR_DECL(vnet_iter);
908 struct lltable *llt;
909
910 VNET_FOREACH(vnet_iter) {
911 CURVNET_SET_QUIET(vnet_iter);
912 #ifdef VIMAGE
913 db_printf("vnet=%p\n", curvnet);
914 #endif
915 SLIST_FOREACH(llt, &lltables, llt_link) {
916 db_printf("llt=%p llt_af=%d llt_ifp=%p(%s)\n",
917 llt, llt->llt_af, llt->llt_ifp,
918 (llt->llt_ifp != NULL) ?
919 llt->llt_ifp->if_xname : "?");
920 if (have_addr && addr != 0) /* verbose */
921 llatbl_llt_show(llt);
922 if (db_pager_quit) {
923 CURVNET_RESTORE();
924 return;
925 }
926 }
927 CURVNET_RESTORE();
928 }
929 }
930 #endif /* DDB */
931 #endif /* __FreeBSD__ */
Cache object: 0ee31f19d023923244268551697d70e7
|