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 541