]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/net/if_llatbl.c
Update to 9.8.4-P1.
[FreeBSD/FreeBSD.git] / sys / net / if_llatbl.c
1 /*
2  * Copyright (c) 2004 Luigi Rizzo, Alessandro Cerri. All rights reserved.
3  * Copyright (c) 2004-2008 Qing Li. All rights reserved.
4  * Copyright (c) 2008 Kip Macy. All rights reserved.
5  * 
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 
15  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include "opt_ddb.h"
31 #include "opt_inet.h"
32 #include "opt_inet6.h"
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/malloc.h>
37 #include <sys/mbuf.h>
38 #include <sys/syslog.h>
39 #include <sys/sysctl.h>
40 #include <sys/socket.h>
41 #include <sys/kernel.h>
42 #include <sys/lock.h>
43 #include <sys/mutex.h>
44 #include <sys/rwlock.h>
45
46 #ifdef DDB
47 #include <ddb/ddb.h>
48 #endif
49
50 #include <vm/uma.h>
51
52 #include <netinet/in.h>
53 #include <net/if_llatbl.h>
54 #include <net/if.h>
55 #include <net/if_dl.h>
56 #include <net/if_var.h>
57 #include <net/route.h>
58 #include <net/vnet.h>
59 #include <netinet/if_ether.h>
60 #include <netinet6/in6_var.h>
61 #include <netinet6/nd6.h>
62
63 MALLOC_DEFINE(M_LLTABLE, "lltable", "link level address tables");
64
65 static VNET_DEFINE(SLIST_HEAD(, lltable), lltables);
66 #define V_lltables      VNET(lltables)
67
68 static void vnet_lltable_init(void);
69
70 struct rwlock lltable_rwlock;
71 RW_SYSINIT(lltable_rwlock, &lltable_rwlock, "lltable_rwlock");
72
73 /*
74  * Dump arp state for a specific address family.
75  */
76 int
77 lltable_sysctl_dumparp(int af, struct sysctl_req *wr)
78 {
79         struct lltable *llt;
80         int error = 0;
81
82         LLTABLE_RLOCK();
83         SLIST_FOREACH(llt, &V_lltables, llt_link) {
84                 if (llt->llt_af == af) {
85                         error = llt->llt_dump(llt, wr);
86                         if (error != 0)
87                                 goto done;
88                 }
89         }
90 done:
91         LLTABLE_RUNLOCK();
92         return (error);
93 }
94
95 /*
96  * Deletes an address from the address table.
97  * This function is called by the timer functions
98  * such as arptimer() and nd6_llinfo_timer(), and
99  * the caller does the locking.
100  *
101  * Returns the number of held packets, if any, that were dropped.
102  */
103 size_t
104 llentry_free(struct llentry *lle)
105 {
106         size_t pkts_dropped;
107         struct mbuf *next;
108
109         IF_AFDATA_WLOCK_ASSERT(lle->lle_tbl->llt_ifp);
110         LLE_WLOCK_ASSERT(lle);
111
112         /* XXX: guard against race with other llentry_free(). */
113         if (!(lle->la_flags & LLE_LINKED)) {
114                 LLE_FREE_LOCKED(lle);
115                 return (0);
116         }
117
118         LIST_REMOVE(lle, lle_next);
119         lle->la_flags &= ~(LLE_VALID | LLE_LINKED);
120
121         pkts_dropped = 0;
122         while ((lle->la_numheld > 0) && (lle->la_hold != NULL)) {
123                 next = lle->la_hold->m_nextpkt;
124                 m_freem(lle->la_hold);
125                 lle->la_hold = next;
126                 lle->la_numheld--;
127                 pkts_dropped++;
128         }
129
130         KASSERT(lle->la_numheld == 0,
131                 ("%s: la_numheld %d > 0, pkts_droped %zd", __func__,
132                  lle->la_numheld, pkts_dropped));
133
134         LLE_FREE_LOCKED(lle);
135
136         return (pkts_dropped);
137 }
138
139 /*
140  * (al)locate an llentry for address dst (equivalent to rtalloc for new-arp).
141  *
142  * If found the llentry * is returned referenced and unlocked.
143  */
144 struct llentry *
145 llentry_alloc(struct ifnet *ifp, struct lltable *lt,
146     struct sockaddr_storage *dst)
147 {
148         struct llentry *la;
149
150         IF_AFDATA_RLOCK(ifp);
151         la = lla_lookup(lt, LLE_EXCLUSIVE, (struct sockaddr *)dst);
152         IF_AFDATA_RUNLOCK(ifp);
153         if ((la == NULL) &&
154             (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0) {
155                 IF_AFDATA_WLOCK(ifp);
156                 la = lla_lookup(lt, (LLE_CREATE | LLE_EXCLUSIVE),
157                     (struct sockaddr *)dst);
158                 IF_AFDATA_WUNLOCK(ifp);
159         }
160
161         if (la != NULL) {
162                 LLE_ADDREF(la);
163                 LLE_WUNLOCK(la);
164         }
165
166         return (la);
167 }
168
169 /*
170  * Free all entries from given table and free itself.
171  */
172 void
173 lltable_free(struct lltable *llt)
174 {
175         struct llentry *lle, *next;
176         int i;
177
178         KASSERT(llt != NULL, ("%s: llt is NULL", __func__));
179
180         LLTABLE_WLOCK();
181         SLIST_REMOVE(&V_lltables, llt, lltable, llt_link);
182         LLTABLE_WUNLOCK();
183
184         IF_AFDATA_WLOCK(llt->llt_ifp);
185         for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) {
186                 LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
187                         LLE_WLOCK(lle);
188                         if (callout_stop(&lle->la_timer))
189                                 LLE_REMREF(lle);
190                         llentry_free(lle);
191                 }
192         }
193         IF_AFDATA_WUNLOCK(llt->llt_ifp);
194
195         free(llt, M_LLTABLE);
196 }
197
198 #if 0
199 void
200 lltable_drain(int af)
201 {
202         struct lltable  *llt;
203         struct llentry  *lle;
204         register int i;
205
206         LLTABLE_RLOCK();
207         SLIST_FOREACH(llt, &V_lltables, llt_link) {
208                 if (llt->llt_af != af)
209                         continue;
210
211                 for (i=0; i < LLTBL_HASHTBL_SIZE; i++) {
212                         LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
213                                 LLE_WLOCK(lle);
214                                 if (lle->la_hold) {
215                                         m_freem(lle->la_hold);
216                                         lle->la_hold = NULL;
217                                 }
218                                 LLE_WUNLOCK(lle);
219                         }
220                 }
221         }
222         LLTABLE_RUNLOCK();
223 }
224 #endif
225
226 void
227 lltable_prefix_free(int af, struct sockaddr *prefix, struct sockaddr *mask,
228     u_int flags)
229 {
230         struct lltable *llt;
231
232         LLTABLE_RLOCK();
233         SLIST_FOREACH(llt, &V_lltables, llt_link) {
234                 if (llt->llt_af != af)
235                         continue;
236
237                 llt->llt_prefix_free(llt, prefix, mask, flags);
238         }
239         LLTABLE_RUNLOCK();
240 }
241
242
243
244 /*
245  * Create a new lltable.
246  */
247 struct lltable *
248 lltable_init(struct ifnet *ifp, int af)
249 {
250         struct lltable *llt;
251         register int i;
252
253         llt = malloc(sizeof(struct lltable), M_LLTABLE, M_WAITOK);
254
255         llt->llt_af = af;
256         llt->llt_ifp = ifp;
257         for (i = 0; i < LLTBL_HASHTBL_SIZE; i++)
258                 LIST_INIT(&llt->lle_head[i]);
259
260         LLTABLE_WLOCK();
261         SLIST_INSERT_HEAD(&V_lltables, llt, llt_link);
262         LLTABLE_WUNLOCK();
263
264         return (llt);
265 }
266
267 /*
268  * Called in route_output when adding/deleting a route to an interface.
269  */
270 int
271 lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info)
272 {
273         struct sockaddr_dl *dl =
274             (struct sockaddr_dl *)info->rti_info[RTAX_GATEWAY];
275         struct sockaddr *dst = (struct sockaddr *)info->rti_info[RTAX_DST];
276         struct ifnet *ifp;
277         struct lltable *llt;
278         struct llentry *lle;
279         u_int laflags = 0, flags = 0;
280         int error = 0;
281
282         if (dl == NULL || dl->sdl_family != AF_LINK) {
283                 log(LOG_INFO, "%s: invalid dl\n", __func__);
284                 return EINVAL;
285         }
286         ifp = ifnet_byindex(dl->sdl_index);
287         if (ifp == NULL) {
288                 log(LOG_INFO, "%s: invalid ifp (sdl_index %d)\n",
289                     __func__, dl->sdl_index);
290                 return EINVAL;
291         }
292
293         switch (rtm->rtm_type) {
294         case RTM_ADD:
295                 if (rtm->rtm_flags & RTF_ANNOUNCE) {
296                         flags |= LLE_PUB;
297 #ifdef INET
298                         if (dst->sa_family == AF_INET &&
299                             ((struct sockaddr_inarp *)dst)->sin_other != 0) {
300                                 struct rtentry *rt;
301                                 ((struct sockaddr_inarp *)dst)->sin_other = 0;
302                                 rt = rtalloc1(dst, 0, 0);
303                                 if (rt == NULL || !(rt->rt_flags & RTF_HOST)) {
304                                         log(LOG_INFO, "%s: RTM_ADD publish "
305                                             "(proxy only) is invalid\n",
306                                             __func__);
307                                         if (rt)
308                                                 RTFREE_LOCKED(rt);
309                                         return EINVAL;
310                                 }
311                                 RTFREE_LOCKED(rt);
312
313                                 flags |= LLE_PROXY;
314                         }
315 #endif
316                 }
317                 flags |= LLE_CREATE;
318                 break;
319
320         case RTM_DELETE:
321                 flags |= LLE_DELETE;
322                 break;
323
324         case RTM_CHANGE:
325                 break;
326
327         default:
328                 return EINVAL; /* XXX not implemented yet */
329         }
330
331         /* XXX linked list may be too expensive */
332         LLTABLE_RLOCK();
333         SLIST_FOREACH(llt, &V_lltables, llt_link) {
334                 if (llt->llt_af == dst->sa_family &&
335                     llt->llt_ifp == ifp)
336                         break;
337         }
338         LLTABLE_RUNLOCK();
339         KASSERT(llt != NULL, ("Yep, ugly hacks are bad\n"));
340
341         if (flags & LLE_CREATE)
342                 flags |= LLE_EXCLUSIVE;
343
344         IF_AFDATA_LOCK(ifp);
345         lle = lla_lookup(llt, flags, dst);
346         IF_AFDATA_UNLOCK(ifp);
347         if (LLE_IS_VALID(lle)) {
348                 if (flags & LLE_CREATE) {
349                         /*
350                          * If we delay the delete, then a subsequent
351                          * "arp add" should look up this entry, reset the
352                          * LLE_DELETED flag, and reset the expiration timer
353                          */
354                         bcopy(LLADDR(dl), &lle->ll_addr, ifp->if_addrlen);
355                         lle->la_flags |= (flags & (LLE_PUB | LLE_PROXY));
356                         lle->la_flags |= LLE_VALID;
357                         lle->la_flags &= ~LLE_DELETED;
358 #ifdef INET6
359                         /*
360                          * ND6
361                          */
362                         if (dst->sa_family == AF_INET6)
363                                 lle->ln_state = ND6_LLINFO_REACHABLE;
364 #endif
365                         /*
366                          * NB: arp and ndp always set (RTF_STATIC | RTF_HOST)
367                          */
368
369                         if (rtm->rtm_rmx.rmx_expire == 0) {
370                                 lle->la_flags |= LLE_STATIC;
371                                 lle->la_expire = 0;
372                         } else
373                                 lle->la_expire = rtm->rtm_rmx.rmx_expire;
374                         laflags = lle->la_flags;
375                         LLE_WUNLOCK(lle);
376 #ifdef INET
377                         /*  gratuitous ARP */
378                         if ((laflags & LLE_PUB) && dst->sa_family == AF_INET) {
379                                 arprequest(ifp,
380                                     &((struct sockaddr_in *)dst)->sin_addr,
381                                     &((struct sockaddr_in *)dst)->sin_addr,
382                                     ((laflags & LLE_PROXY) ?
383                                         (u_char *)IF_LLADDR(ifp) :
384                                         (u_char *)LLADDR(dl)));
385                         }
386 #endif
387                 } else {
388                         if (flags & LLE_EXCLUSIVE)
389                                 LLE_WUNLOCK(lle);
390                         else
391                                 LLE_RUNLOCK(lle);
392                 }
393         } else if ((lle == NULL) && (flags & LLE_DELETE))
394                 error = EINVAL;
395
396
397         return (error);
398 }
399
400 static void
401 vnet_lltable_init()
402 {
403
404         SLIST_INIT(&V_lltables);
405 }
406 VNET_SYSINIT(vnet_lltable_init, SI_SUB_PSEUDO, SI_ORDER_FIRST,
407     vnet_lltable_init, NULL);
408
409 #ifdef DDB
410 struct llentry_sa {
411         struct llentry          base;
412         struct sockaddr         l3_addr;
413 };
414
415 static void
416 llatbl_lle_show(struct llentry_sa *la)
417 {
418         struct llentry *lle;
419         uint8_t octet[6];
420
421         lle = &la->base;
422         db_printf("lle=%p\n", lle);
423         db_printf(" lle_next=%p\n", lle->lle_next.le_next);
424         db_printf(" lle_lock=%p\n", &lle->lle_lock);
425         db_printf(" lle_tbl=%p\n", lle->lle_tbl);
426         db_printf(" lle_head=%p\n", lle->lle_head);
427         db_printf(" la_hold=%p\n", lle->la_hold);
428         db_printf(" la_numheld=%d\n", lle->la_numheld);
429         db_printf(" la_expire=%ju\n", (uintmax_t)lle->la_expire);
430         db_printf(" la_flags=0x%04x\n", lle->la_flags);
431         db_printf(" la_asked=%u\n", lle->la_asked);
432         db_printf(" la_preempt=%u\n", lle->la_preempt);
433         db_printf(" ln_byhint=%u\n", lle->ln_byhint);
434         db_printf(" ln_state=%d\n", lle->ln_state);
435         db_printf(" ln_router=%u\n", lle->ln_router);
436         db_printf(" ln_ntick=%ju\n", (uintmax_t)lle->ln_ntick);
437         db_printf(" lle_refcnt=%d\n", lle->lle_refcnt);
438         bcopy(&lle->ll_addr.mac16, octet, sizeof(octet));
439         db_printf(" ll_addr=%02x:%02x:%02x:%02x:%02x:%02x\n",
440             octet[0], octet[1], octet[2], octet[3], octet[4], octet[5]);
441         db_printf(" la_timer=%p\n", &lle->la_timer);
442
443         switch (la->l3_addr.sa_family) {
444 #ifdef INET
445         case AF_INET:
446         {
447                 struct sockaddr_in *sin;
448                 char l3s[INET_ADDRSTRLEN];
449
450                 sin = (struct sockaddr_in *)&la->l3_addr;
451                 inet_ntoa_r(sin->sin_addr, l3s);
452                 db_printf(" l3_addr=%s\n", l3s);
453                 break;
454         }
455 #endif
456 #ifdef INET6
457         case AF_INET6:
458         {
459                 struct sockaddr_in6 *sin6;
460                 char l3s[INET6_ADDRSTRLEN];
461
462                 sin6 = (struct sockaddr_in6 *)&la->l3_addr;
463                 ip6_sprintf(l3s, &sin6->sin6_addr);
464                 db_printf(" l3_addr=%s\n", l3s);
465                 break;
466         }
467 #endif
468         default:
469                 db_printf(" l3_addr=N/A (af=%d)\n", la->l3_addr.sa_family);
470                 break;
471         }
472 }
473
474 DB_SHOW_COMMAND(llentry, db_show_llentry)
475 {
476
477         if (!have_addr) {
478                 db_printf("usage: show llentry <struct llentry *>\n");
479                 return;
480         }
481
482         llatbl_lle_show((struct llentry_sa *)addr);
483 }
484
485 static void
486 llatbl_llt_show(struct lltable *llt)
487 {
488         int i;
489         struct llentry *lle;
490
491         db_printf("llt=%p llt_af=%d llt_ifp=%p\n",
492             llt, llt->llt_af, llt->llt_ifp);
493
494         for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) {
495                 LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
496
497                         llatbl_lle_show((struct llentry_sa *)lle);
498                         if (db_pager_quit)
499                                 return;
500                 }
501         }
502 }
503
504 DB_SHOW_COMMAND(lltable, db_show_lltable)
505 {
506
507         if (!have_addr) {
508                 db_printf("usage: show lltable <struct lltable *>\n");
509                 return;
510         }
511
512         llatbl_llt_show((struct lltable *)addr);
513 }
514
515 DB_SHOW_ALL_COMMAND(lltables, db_show_all_lltables)
516 {
517         VNET_ITERATOR_DECL(vnet_iter);
518         struct lltable *llt;
519
520         VNET_FOREACH(vnet_iter) {
521                 CURVNET_SET_QUIET(vnet_iter);
522 #ifdef VIMAGE
523                 db_printf("vnet=%p\n", curvnet);
524 #endif
525                 SLIST_FOREACH(llt, &V_lltables, llt_link) {
526                         db_printf("llt=%p llt_af=%d llt_ifp=%p(%s)\n",
527                             llt, llt->llt_af, llt->llt_ifp,
528                             (llt->llt_ifp != NULL) ?
529                                 llt->llt_ifp->if_xname : "?");
530                         if (have_addr && addr != 0) /* verbose */
531                                 llatbl_llt_show(llt);
532                         if (db_pager_quit) {
533                                 CURVNET_RESTORE();
534                                 return;
535                         }
536                 }
537                 CURVNET_RESTORE();
538         }
539 }
540 #endif