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