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 extern void arprequest(struct ifnet *, struct in_addr *, struct in_addr *, 69 u_char *); 70 71 static void vnet_lltable_init(void); 72 73 struct rwlock lltable_rwlock; 74 RW_SYSINIT(lltable_rwlock, &lltable_rwlock, "lltable_rwlock"); 75 76 /* 77 * Dump arp state for a specific address family. 78 */ 79 int 80 lltable_sysctl_dumparp(int af, struct sysctl_req *wr) 81 { 82 struct lltable *llt; 83 int error = 0; 84 85 LLTABLE_RLOCK(); 86 SLIST_FOREACH(llt, &V_lltables, llt_link) { 87 if (llt->llt_af == af) { 88 error = llt->llt_dump(llt, wr); 89 if (error != 0) 90 goto done; 91 } 92 } 93 done: 94 LLTABLE_RUNLOCK(); 95 return (error); 96 } 97 98 /* 99 * Deletes an address from the address table. 100 * This function is called by the timer functions 101 * such as arptimer() and nd6_llinfo_timer(), and 102 * the caller does the locking. 103 * 104 * Returns the number of held packets, if any, that were dropped. 105 */ 106 size_t 107 llentry_free(struct llentry *lle) 108 { 109 size_t pkts_dropped; 110 struct mbuf *next; 111 112 pkts_dropped = 0; 113 LLE_WLOCK_ASSERT(lle); 114 LIST_REMOVE(lle, lle_next); 115 116 while ((lle->la_numheld > 0) && (lle->la_hold != NULL)) { 117 next = lle->la_hold->m_nextpkt; 118 m_freem(lle->la_hold); 119 lle->la_hold = next; 120 lle->la_numheld--; 121 pkts_dropped++; 122 } 123 124 KASSERT(lle->la_numheld == 0, 125 ("%s: la_numheld %d > 0, pkts_droped %zd", __func__, 126 lle->la_numheld, pkts_dropped)); 127 128 LLE_FREE_LOCKED(lle); 129 130 return (pkts_dropped); 131 } 132 133 /* 134 * Update an llentry for address dst (equivalent to rtalloc for new-arp) 135 * Caller must pass in a valid struct llentry * (or NULL) 136 * 137 * if found the llentry * is returned referenced and unlocked 138 */ 139 int 140 llentry_update(struct llentry **llep, struct lltable *lt, 141 struct sockaddr_storage *dst, struct ifnet *ifp) 142 { 143 struct llentry *la; 144 145 IF_AFDATA_RLOCK(ifp); 146 la = lla_lookup(lt, LLE_EXCLUSIVE, 147 (struct sockaddr *)dst); 148 IF_AFDATA_RUNLOCK(ifp); 149 if ((la == NULL) && 150 (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0) { 151 IF_AFDATA_WLOCK(ifp); 152 la = lla_lookup(lt, 153 (LLE_CREATE | LLE_EXCLUSIVE), 154 (struct sockaddr *)dst); 155 IF_AFDATA_WUNLOCK(ifp); 156 } 157 if (la != NULL && (*llep != la)) { 158 if (*llep != NULL) 159 LLE_FREE(*llep); 160 LLE_ADDREF(la); 161 LLE_WUNLOCK(la); 162 *llep = la; 163 } else if (la != NULL) 164 LLE_WUNLOCK(la); 165 166 if (la == NULL) 167 return (ENOENT); 168 169 return (0); 170 } 171 172 /* 173 * Free all entries from given table and free itself. 174 */ 175 void 176 lltable_free(struct lltable *llt) 177 { 178 struct llentry *lle, *next; 179 int i; 180 181 KASSERT(llt != NULL, ("%s: llt is NULL", __func__)); 182 183 LLTABLE_WLOCK(); 184 SLIST_REMOVE(&V_lltables, llt, lltable, llt_link); 185 LLTABLE_WUNLOCK(); 186 187 for (i=0; i < LLTBL_HASHTBL_SIZE; i++) { 188 LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) { 189 int canceled; 190 191 canceled = callout_drain(&lle->la_timer); 192 LLE_WLOCK(lle); 193 if (canceled) 194 LLE_REMREF(lle); 195 llentry_free(lle); 196 } 197 } 198 199 free(llt, M_LLTABLE); 200 } 201 202 #if 0 203 void 204 lltable_drain(int af) 205 { 206 struct lltable *llt; 207 struct llentry *lle; 208 register int i; 209 210 LLTABLE_RLOCK(); 211 SLIST_FOREACH(llt, &V_lltables, llt_link) { 212 if (llt->llt_af != af) 213 continue; 214 215 for (i=0; i < LLTBL_HASHTBL_SIZE; i++) { 216 LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { 217 LLE_WLOCK(lle); 218 if (lle->la_hold) { 219 m_freem(lle->la_hold); 220 lle->la_hold = NULL; 221 } 222 LLE_WUNLOCK(lle); 223 } 224 } 225 } 226 LLTABLE_RUNLOCK(); 227 } 228 #endif 229 230 void 231 lltable_prefix_free(int af, struct sockaddr *prefix, struct sockaddr *mask, 232 u_int flags) 233 { 234 struct lltable *llt; 235 236 LLTABLE_RLOCK(); 237 SLIST_FOREACH(llt, &V_lltables, llt_link) { 238 if (llt->llt_af != af) 239 continue; 240 241 llt->llt_prefix_free(llt, prefix, mask, flags); 242 } 243 LLTABLE_RUNLOCK(); 244 } 245 246 247 248 /* 249 * Create a new lltable. 250 */ 251 struct lltable * 252 lltable_init(struct ifnet *ifp, int af) 253 { 254 struct lltable *llt; 255 register int i; 256 257 llt = malloc(sizeof(struct lltable), M_LLTABLE, M_WAITOK); 258 259 llt->llt_af = af; 260 llt->llt_ifp = ifp; 261 for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) 262 LIST_INIT(&llt->lle_head[i]); 263 264 LLTABLE_WLOCK(); 265 SLIST_INSERT_HEAD(&V_lltables, llt, llt_link); 266 LLTABLE_WUNLOCK(); 267 268 return (llt); 269 } 270 271 /* 272 * Called in route_output when adding/deleting a route to an interface. 273 */ 274 int 275 lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info) 276 { 277 struct sockaddr_dl *dl = 278 (struct sockaddr_dl *)info->rti_info[RTAX_GATEWAY]; 279 struct sockaddr *dst = (struct sockaddr *)info->rti_info[RTAX_DST]; 280 struct ifnet *ifp; 281 struct lltable *llt; 282 struct llentry *lle; 283 u_int laflags = 0, flags = 0; 284 int error = 0; 285 286 if (dl == NULL || dl->sdl_family != AF_LINK) { 287 log(LOG_INFO, "%s: invalid dl\n", __func__); 288 return EINVAL; 289 } 290 ifp = ifnet_byindex(dl->sdl_index); 291 if (ifp == NULL) { 292 log(LOG_INFO, "%s: invalid ifp (sdl_index %d)\n", 293 __func__, dl->sdl_index); 294 return EINVAL; 295 } 296 297 switch (rtm->rtm_type) { 298 case RTM_ADD: 299 if (rtm->rtm_flags & RTF_ANNOUNCE) { 300 flags |= LLE_PUB; 301 #ifdef INET 302 if (dst->sa_family == AF_INET && 303 ((struct sockaddr_inarp *)dst)->sin_other != 0) { 304 struct rtentry *rt; 305 ((struct sockaddr_inarp *)dst)->sin_other = 0; 306 rt = rtalloc1(dst, 0, 0); 307 if (rt == NULL || !(rt->rt_flags & RTF_HOST)) { 308 log(LOG_INFO, "%s: RTM_ADD publish " 309 "(proxy only) is invalid\n", 310 __func__); 311 if (rt) 312 RTFREE_LOCKED(rt); 313 return EINVAL; 314 } 315 RTFREE_LOCKED(rt); 316 317 flags |= LLE_PROXY; 318 } 319 #endif 320 } 321 flags |= LLE_CREATE; 322 break; 323 324 case RTM_DELETE: 325 flags |= LLE_DELETE; 326 break; 327 328 case RTM_CHANGE: 329 break; 330 331 default: 332 return EINVAL; /* XXX not implemented yet */ 333 } 334 335 /* XXX linked list may be too expensive */ 336 LLTABLE_RLOCK(); 337 SLIST_FOREACH(llt, &V_lltables, llt_link) { 338 if (llt->llt_af == dst->sa_family && 339 llt->llt_ifp == ifp) 340 break; 341 } 342 LLTABLE_RUNLOCK(); 343 KASSERT(llt != NULL, ("Yep, ugly hacks are bad\n")); 344 345 if (flags & LLE_CREATE) 346 flags |= LLE_EXCLUSIVE; 347 348 IF_AFDATA_LOCK(ifp); 349 lle = lla_lookup(llt, flags, dst); 350 IF_AFDATA_UNLOCK(ifp); 351 if (LLE_IS_VALID(lle)) { 352 if (flags & LLE_CREATE) { 353 /* 354 * If we delay the delete, then a subsequent 355 * "arp add" should look up this entry, reset the 356 * LLE_DELETED flag, and reset the expiration timer 357 */ 358 bcopy(LLADDR(dl), &lle->ll_addr, ifp->if_addrlen); 359 lle->la_flags |= (flags & (LLE_PUB | LLE_PROXY)); 360 lle->la_flags |= LLE_VALID; 361 lle->la_flags &= ~LLE_DELETED; 362 #ifdef INET6 363 /* 364 * ND6 365 */ 366 if (dst->sa_family == AF_INET6) 367 lle->ln_state = ND6_LLINFO_REACHABLE; 368 #endif 369 /* 370 * NB: arp and ndp always set (RTF_STATIC | RTF_HOST) 371 */ 372 373 if (rtm->rtm_rmx.rmx_expire == 0) { 374 lle->la_flags |= LLE_STATIC; 375 lle->la_expire = 0; 376 } else 377 lle->la_expire = rtm->rtm_rmx.rmx_expire; 378 laflags = lle->la_flags; 379 LLE_WUNLOCK(lle); 380 #ifdef INET 381 /* gratuitous ARP */ 382 if ((laflags & LLE_PUB) && dst->sa_family == AF_INET) { 383 arprequest(ifp, 384 &((struct sockaddr_in *)dst)->sin_addr, 385 &((struct sockaddr_in *)dst)->sin_addr, 386 ((laflags & LLE_PROXY) ? 387 (u_char *)IF_LLADDR(ifp) : 388 (u_char *)LLADDR(dl))); 389 } 390 #endif 391 } else { 392 if (flags & LLE_EXCLUSIVE) 393 LLE_WUNLOCK(lle); 394 else 395 LLE_RUNLOCK(lle); 396 } 397 } else if ((lle == NULL) && (flags & LLE_DELETE)) 398 error = EINVAL; 399 400 401 return (error); 402 } 403 404 static void 405 vnet_lltable_init() 406 { 407 408 SLIST_INIT(&V_lltables); 409 } 410 VNET_SYSINIT(vnet_lltable_init, SI_SUB_PSEUDO, SI_ORDER_FIRST, 411 vnet_lltable_init, NULL); 412 413 #ifdef DDB 414 struct llentry_sa { 415 struct llentry base; 416 struct sockaddr l3_addr; 417 }; 418 419 static void 420 llatbl_lle_show(struct llentry_sa *la) 421 { 422 struct llentry *lle; 423 uint8_t octet[6]; 424 425 lle = &la->base; 426 db_printf("lle=%p\n", lle); 427 db_printf(" lle_next=%p\n", lle->lle_next.le_next); 428 db_printf(" lle_lock=%p\n", &lle->lle_lock); 429 db_printf(" lle_tbl=%p\n", lle->lle_tbl); 430 db_printf(" lle_head=%p\n", lle->lle_head); 431 db_printf(" la_hold=%p\n", lle->la_hold); 432 db_printf(" la_numheld=%d\n", lle->la_numheld); 433 db_printf(" la_expire=%ju\n", (uintmax_t)lle->la_expire); 434 db_printf(" la_flags=0x%04x\n", lle->la_flags); 435 db_printf(" la_asked=%u\n", lle->la_asked); 436 db_printf(" la_preempt=%u\n", lle->la_preempt); 437 db_printf(" ln_byhint=%u\n", lle->ln_byhint); 438 db_printf(" ln_state=%d\n", lle->ln_state); 439 db_printf(" ln_router=%u\n", lle->ln_router); 440 db_printf(" ln_ntick=%ju\n", (uintmax_t)lle->ln_ntick); 441 db_printf(" lle_refcnt=%d\n", lle->lle_refcnt); 442 bcopy(&lle->ll_addr.mac16, octet, sizeof(octet)); 443 db_printf(" ll_addr=%02x:%02x:%02x:%02x:%02x:%02x\n", 444 octet[0], octet[1], octet[2], octet[3], octet[4], octet[5]); 445 db_printf(" la_timer=%p\n", &lle->la_timer); 446 447 switch (la->l3_addr.sa_family) { 448 #ifdef INET 449 case AF_INET: 450 { 451 struct sockaddr_in *sin; 452 char l3s[INET_ADDRSTRLEN]; 453 454 sin = (struct sockaddr_in *)&la->l3_addr; 455 inet_ntoa_r(sin->sin_addr, l3s); 456 db_printf(" l3_addr=%s\n", l3s); 457 break; 458 } 459 #endif 460 #ifdef INET6 461 case AF_INET6: 462 { 463 struct sockaddr_in6 *sin6; 464 char l3s[INET6_ADDRSTRLEN]; 465 466 sin6 = (struct sockaddr_in6 *)&la->l3_addr; 467 ip6_sprintf(l3s, &sin6->sin6_addr); 468 db_printf(" l3_addr=%s\n", l3s); 469 break; 470 } 471 #endif 472 default: 473 db_printf(" l3_addr=N/A (af=%d)\n", la->l3_addr.sa_family); 474 break; 475 } 476 } 477 478 DB_SHOW_COMMAND(llentry, db_show_llentry) 479 { 480 481 if (!have_addr) { 482 db_printf("usage: show llentry <struct llentry *>\n"); 483 return; 484 } 485 486 llatbl_lle_show((struct llentry_sa *)addr); 487 } 488 489 static void 490 llatbl_llt_show(struct lltable *llt) 491 { 492 int i; 493 struct llentry *lle; 494 495 db_printf("llt=%p llt_af=%d llt_ifp=%p\n", 496 llt, llt->llt_af, llt->llt_ifp); 497 498 for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) { 499 LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { 500 501 llatbl_lle_show((struct llentry_sa *)lle); 502 if (db_pager_quit) 503 return; 504 } 505 } 506 } 507 508 DB_SHOW_COMMAND(lltable, db_show_lltable) 509 { 510 511 if (!have_addr) { 512 db_printf("usage: show lltable <struct lltable *>\n"); 513 return; 514 } 515 516 llatbl_llt_show((struct lltable *)addr); 517 } 518 519 DB_SHOW_ALL_COMMAND(lltables, db_show_all_lltables) 520 { 521 VNET_ITERATOR_DECL(vnet_iter); 522 struct lltable *llt; 523 524 VNET_FOREACH(vnet_iter) { 525 CURVNET_SET_QUIET(vnet_iter); 526 #ifdef VIMAGE 527 db_printf("vnet=%p\n", curvnet); 528 #endif 529 SLIST_FOREACH(llt, &V_lltables, llt_link) { 530 db_printf("llt=%p llt_af=%d llt_ifp=%p(%s)\n", 531 llt, llt->llt_af, llt->llt_ifp, 532 (llt->llt_ifp != NULL) ? 533 llt->llt_ifp->if_xname : "?"); 534 if (have_addr && addr != 0) /* verbose */ 535 llatbl_llt_show(llt); 536 if (db_pager_quit) { 537 CURVNET_RESTORE(); 538 return; 539 } 540 } 541 CURVNET_RESTORE(); 542 } 543 } 544 #endif 545