1/*- 2 * Copyright (c) 1980, 1986, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 4. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * @(#)if.c 8.5 (Berkeley) 1/9/95
|
60VNET_DEFINE(LIST_HEAD(, if_clone), if_cloners); 61 62#define V_if_cloners_count VNET(if_cloners_count) 63#define V_if_cloners VNET(if_cloners) 64 65#define IF_CLONERS_LOCK_INIT() \ 66 mtx_init(&if_cloners_mtx, "if_cloners lock", NULL, MTX_DEF) 67#define IF_CLONERS_LOCK_ASSERT() mtx_assert(&if_cloners_mtx, MA_OWNED) 68#define IF_CLONERS_LOCK() mtx_lock(&if_cloners_mtx) 69#define IF_CLONERS_UNLOCK() mtx_unlock(&if_cloners_mtx) 70 71#define IF_CLONE_LOCK_INIT(ifc) \ 72 mtx_init(&(ifc)->ifc_mtx, "if_clone lock", NULL, MTX_DEF) 73#define IF_CLONE_LOCK_DESTROY(ifc) mtx_destroy(&(ifc)->ifc_mtx) 74#define IF_CLONE_LOCK_ASSERT(ifc) mtx_assert(&(ifc)->ifc_mtx, MA_OWNED) 75#define IF_CLONE_LOCK(ifc) mtx_lock(&(ifc)->ifc_mtx) 76#define IF_CLONE_UNLOCK(ifc) mtx_unlock(&(ifc)->ifc_mtx) 77 78#define IF_CLONE_ADDREF(ifc) \ 79 do { \ 80 IF_CLONE_LOCK(ifc); \ 81 IF_CLONE_ADDREF_LOCKED(ifc); \ 82 IF_CLONE_UNLOCK(ifc); \ 83 } while (0) 84#define IF_CLONE_ADDREF_LOCKED(ifc) \ 85 do { \ 86 IF_CLONE_LOCK_ASSERT(ifc); \ 87 KASSERT((ifc)->ifc_refcnt >= 0, \ 88 ("negative refcnt %ld", (ifc)->ifc_refcnt)); \ 89 (ifc)->ifc_refcnt++; \ 90 } while (0) 91#define IF_CLONE_REMREF(ifc) \ 92 do { \ 93 IF_CLONE_LOCK(ifc); \ 94 IF_CLONE_REMREF_LOCKED(ifc); \ 95 } while (0) 96#define IF_CLONE_REMREF_LOCKED(ifc) \ 97 do { \ 98 IF_CLONE_LOCK_ASSERT(ifc); \ 99 KASSERT((ifc)->ifc_refcnt > 0, \ 100 ("bogus refcnt %ld", (ifc)->ifc_refcnt)); \ 101 if (--(ifc)->ifc_refcnt == 0) { \ 102 IF_CLONE_UNLOCK(ifc); \ 103 if_clone_free(ifc); \ 104 } else { \ 105 /* silently free the lock */ \ 106 IF_CLONE_UNLOCK(ifc); \ 107 } \ 108 } while (0) 109 110#define IFC_IFLIST_INSERT(_ifc, _ifp) \ 111 LIST_INSERT_HEAD(&_ifc->ifc_iflist, _ifp, if_clones) 112#define IFC_IFLIST_REMOVE(_ifc, _ifp) \ 113 LIST_REMOVE(_ifp, if_clones) 114 115static MALLOC_DEFINE(M_CLONE, "clone", "interface cloning framework"); 116 117void 118vnet_if_clone_init(void) 119{ 120 121 LIST_INIT(&V_if_cloners); 122} 123 124void 125if_clone_init(void) 126{ 127 128 IF_CLONERS_LOCK_INIT(); 129} 130 131/* 132 * Lookup and create a clone network interface. 133 */ 134int 135if_clone_create(char *name, size_t len, caddr_t params) 136{ 137 struct if_clone *ifc; 138 139 /* Try to find an applicable cloner for this request */ 140 IF_CLONERS_LOCK(); 141 LIST_FOREACH(ifc, &V_if_cloners, ifc_list) { 142 if (ifc->ifc_match(ifc, name)) { 143 break; 144 } 145 } 146#ifdef VIMAGE 147 if (ifc == NULL && !IS_DEFAULT_VNET(curvnet)) { 148 CURVNET_SET_QUIET(vnet0); 149 LIST_FOREACH(ifc, &V_if_cloners, ifc_list) { 150 if (ifc->ifc_match(ifc, name)) 151 break; 152 } 153 CURVNET_RESTORE(); 154 } 155#endif 156 IF_CLONERS_UNLOCK(); 157 158 if (ifc == NULL) 159 return (EINVAL); 160 161 return (if_clone_createif(ifc, name, len, params)); 162} 163 164/* 165 * Create a clone network interface. 166 */ 167static int 168if_clone_createif(struct if_clone *ifc, char *name, size_t len, caddr_t params) 169{ 170 int err; 171 struct ifnet *ifp; 172 173 if (ifunit(name) != NULL) 174 return (EEXIST); 175 176 err = (*ifc->ifc_create)(ifc, name, len, params); 177 178 if (!err) { 179 ifp = ifunit(name); 180 if (ifp == NULL) 181 panic("%s: lookup failed for %s", __func__, name); 182 183 if_addgroup(ifp, ifc->ifc_name); 184 185 IF_CLONE_LOCK(ifc); 186 IFC_IFLIST_INSERT(ifc, ifp); 187 IF_CLONE_UNLOCK(ifc); 188 } 189 190 return (err); 191} 192 193/* 194 * Lookup and destroy a clone network interface. 195 */ 196int 197if_clone_destroy(const char *name) 198{ 199 int err; 200 struct if_clone *ifc; 201 struct ifnet *ifp; 202 203 ifp = ifunit_ref(name); 204 if (ifp == NULL) 205 return (ENXIO); 206 207 /* Find the cloner for this interface */ 208 IF_CLONERS_LOCK(); 209 LIST_FOREACH(ifc, &V_if_cloners, ifc_list) { 210 if (strcmp(ifc->ifc_name, ifp->if_dname) == 0) { 211 break; 212 } 213 } 214#ifdef VIMAGE 215 if (ifc == NULL && !IS_DEFAULT_VNET(curvnet)) { 216 CURVNET_SET_QUIET(vnet0); 217 LIST_FOREACH(ifc, &V_if_cloners, ifc_list) { 218 if (ifc->ifc_match(ifc, name)) 219 break; 220 } 221 CURVNET_RESTORE(); 222 } 223#endif 224 IF_CLONERS_UNLOCK(); 225 if (ifc == NULL) { 226 if_rele(ifp); 227 return (EINVAL); 228 } 229 230 err = if_clone_destroyif(ifc, ifp); 231 if_rele(ifp); 232 return err; 233} 234 235/* 236 * Destroy a clone network interface. 237 */ 238int 239if_clone_destroyif(struct if_clone *ifc, struct ifnet *ifp) 240{ 241 int err; 242 struct ifnet *ifcifp; 243 244 if (ifc->ifc_destroy == NULL) 245 return(EOPNOTSUPP); 246 247 /* 248 * Given that the cloned ifnet might be attached to a different 249 * vnet from where its cloner was registered, we have to 250 * switch to the vnet context of the target vnet. 251 */ 252 CURVNET_SET_QUIET(ifp->if_vnet); 253 254 IF_CLONE_LOCK(ifc); 255 LIST_FOREACH(ifcifp, &ifc->ifc_iflist, if_clones) { 256 if (ifcifp == ifp) { 257 IFC_IFLIST_REMOVE(ifc, ifp); 258 break; 259 } 260 } 261 IF_CLONE_UNLOCK(ifc); 262 if (ifcifp == NULL) { 263 CURVNET_RESTORE(); 264 return (ENXIO); /* ifp is not on the list. */ 265 } 266 267 if_delgroup(ifp, ifc->ifc_name); 268 269 err = (*ifc->ifc_destroy)(ifc, ifp); 270 271 if (err != 0) { 272 if_addgroup(ifp, ifc->ifc_name); 273 274 IF_CLONE_LOCK(ifc); 275 IFC_IFLIST_INSERT(ifc, ifp); 276 IF_CLONE_UNLOCK(ifc); 277 } 278 CURVNET_RESTORE(); 279 return (err); 280} 281 282/* 283 * Register a network interface cloner. 284 */ 285void 286if_clone_attach(struct if_clone *ifc) 287{ 288 int len, maxclone; 289 290 /* 291 * Compute bitmap size and allocate it. 292 */ 293 maxclone = ifc->ifc_maxunit + 1; 294 len = maxclone >> 3; 295 if ((len << 3) < maxclone) 296 len++; 297 ifc->ifc_units = malloc(len, M_CLONE, M_WAITOK | M_ZERO); 298 ifc->ifc_bmlen = len; 299 IF_CLONE_LOCK_INIT(ifc); 300 IF_CLONE_ADDREF(ifc); 301 302 IF_CLONERS_LOCK(); 303 LIST_INSERT_HEAD(&V_if_cloners, ifc, ifc_list); 304 V_if_cloners_count++; 305 IF_CLONERS_UNLOCK(); 306 307 LIST_INIT(&ifc->ifc_iflist); 308 309 if (ifc->ifc_attach != NULL) 310 (*ifc->ifc_attach)(ifc); 311 EVENTHANDLER_INVOKE(if_clone_event, ifc); 312} 313 314/* 315 * Unregister a network interface cloner. 316 */ 317void 318if_clone_detach(struct if_clone *ifc) 319{ 320 struct ifc_simple_data *ifcs = ifc->ifc_data; 321 322 IF_CLONERS_LOCK(); 323 LIST_REMOVE(ifc, ifc_list); 324 V_if_cloners_count--; 325 IF_CLONERS_UNLOCK(); 326 327 /* Allow all simples to be destroyed */ 328 if (ifc->ifc_attach == ifc_simple_attach) 329 ifcs->ifcs_minifs = 0; 330 331 /* destroy all interfaces for this cloner */ 332 while (!LIST_EMPTY(&ifc->ifc_iflist)) 333 if_clone_destroyif(ifc, LIST_FIRST(&ifc->ifc_iflist)); 334 335 IF_CLONE_REMREF(ifc); 336} 337 338static void 339if_clone_free(struct if_clone *ifc) 340{ 341 for (int bytoff = 0; bytoff < ifc->ifc_bmlen; bytoff++) { 342 KASSERT(ifc->ifc_units[bytoff] == 0x00, 343 ("ifc_units[%d] is not empty", bytoff)); 344 } 345 346 KASSERT(LIST_EMPTY(&ifc->ifc_iflist), 347 ("%s: ifc_iflist not empty", __func__)); 348 349 IF_CLONE_LOCK_DESTROY(ifc); 350 free(ifc->ifc_units, M_CLONE); 351} 352 353/* 354 * Provide list of interface cloners to userspace. 355 */ 356int 357if_clone_list(struct if_clonereq *ifcr) 358{ 359 char *buf, *dst, *outbuf = NULL; 360 struct if_clone *ifc; 361 int buf_count, count, err = 0; 362 363 if (ifcr->ifcr_count < 0) 364 return (EINVAL); 365 366 IF_CLONERS_LOCK(); 367 /* 368 * Set our internal output buffer size. We could end up not 369 * reporting a cloner that is added between the unlock and lock 370 * below, but that's not a major problem. Not caping our 371 * allocation to the number of cloners actually in the system 372 * could be because that would let arbitrary users cause us to 373 * allocate abritrary amounts of kernel memory. 374 */ 375 buf_count = (V_if_cloners_count < ifcr->ifcr_count) ? 376 V_if_cloners_count : ifcr->ifcr_count; 377 IF_CLONERS_UNLOCK(); 378 379 outbuf = malloc(IFNAMSIZ*buf_count, M_CLONE, M_WAITOK | M_ZERO); 380 381 IF_CLONERS_LOCK(); 382 383 ifcr->ifcr_total = V_if_cloners_count; 384 if ((dst = ifcr->ifcr_buffer) == NULL) { 385 /* Just asking how many there are. */ 386 goto done; 387 } 388 count = (V_if_cloners_count < buf_count) ? 389 V_if_cloners_count : buf_count; 390 391 for (ifc = LIST_FIRST(&V_if_cloners), buf = outbuf; 392 ifc != NULL && count != 0; 393 ifc = LIST_NEXT(ifc, ifc_list), count--, buf += IFNAMSIZ) { 394 strlcpy(buf, ifc->ifc_name, IFNAMSIZ); 395 } 396 397done: 398 IF_CLONERS_UNLOCK(); 399 if (err == 0) 400 err = copyout(outbuf, dst, buf_count*IFNAMSIZ); 401 if (outbuf != NULL) 402 free(outbuf, M_CLONE); 403 return (err); 404} 405 406/* 407 * A utility function to extract unit numbers from interface names of 408 * the form name###. 409 * 410 * Returns 0 on success and an error on failure. 411 */ 412int 413ifc_name2unit(const char *name, int *unit) 414{ 415 const char *cp; 416 int cutoff = INT_MAX / 10; 417 int cutlim = INT_MAX % 10; 418 419 for (cp = name; *cp != '\0' && (*cp < '0' || *cp > '9'); cp++); 420 if (*cp == '\0') { 421 *unit = -1; 422 } else if (cp[0] == '0' && cp[1] != '\0') { 423 /* Disallow leading zeroes. */ 424 return (EINVAL); 425 } else { 426 for (*unit = 0; *cp != '\0'; cp++) { 427 if (*cp < '0' || *cp > '9') { 428 /* Bogus unit number. */ 429 return (EINVAL); 430 } 431 if (*unit > cutoff || 432 (*unit == cutoff && *cp - '0' > cutlim)) 433 return (EINVAL); 434 *unit = (*unit * 10) + (*cp - '0'); 435 } 436 } 437 438 return (0); 439} 440 441int 442ifc_alloc_unit(struct if_clone *ifc, int *unit) 443{ 444 int wildcard, bytoff, bitoff; 445 int err = 0; 446 447 IF_CLONE_LOCK(ifc); 448 449 bytoff = bitoff = 0; 450 wildcard = (*unit < 0); 451 /* 452 * Find a free unit if none was given. 453 */ 454 if (wildcard) { 455 while ((bytoff < ifc->ifc_bmlen) 456 && (ifc->ifc_units[bytoff] == 0xff)) 457 bytoff++; 458 if (bytoff >= ifc->ifc_bmlen) { 459 err = ENOSPC; 460 goto done; 461 } 462 while ((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0) 463 bitoff++; 464 *unit = (bytoff << 3) + bitoff; 465 } 466 467 if (*unit > ifc->ifc_maxunit) { 468 err = ENOSPC; 469 goto done; 470 } 471 472 if (!wildcard) { 473 bytoff = *unit >> 3; 474 bitoff = *unit - (bytoff << 3); 475 } 476 477 if((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0) { 478 err = EEXIST; 479 goto done; 480 } 481 /* 482 * Allocate the unit in the bitmap. 483 */ 484 KASSERT((ifc->ifc_units[bytoff] & (1 << bitoff)) == 0, 485 ("%s: bit is already set", __func__)); 486 ifc->ifc_units[bytoff] |= (1 << bitoff); 487 IF_CLONE_ADDREF_LOCKED(ifc); 488 489done: 490 IF_CLONE_UNLOCK(ifc); 491 return (err); 492} 493 494void 495ifc_free_unit(struct if_clone *ifc, int unit) 496{ 497 int bytoff, bitoff; 498 499 500 /* 501 * Compute offset in the bitmap and deallocate the unit. 502 */ 503 bytoff = unit >> 3; 504 bitoff = unit - (bytoff << 3); 505 506 IF_CLONE_LOCK(ifc); 507 KASSERT((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0, 508 ("%s: bit is already cleared", __func__)); 509 ifc->ifc_units[bytoff] &= ~(1 << bitoff); 510 IF_CLONE_REMREF_LOCKED(ifc); /* releases lock */ 511} 512 513void 514ifc_simple_attach(struct if_clone *ifc) 515{ 516 int err; 517 int unit; 518 char name[IFNAMSIZ]; 519 struct ifc_simple_data *ifcs = ifc->ifc_data; 520 521 KASSERT(ifcs->ifcs_minifs - 1 <= ifc->ifc_maxunit, 522 ("%s: %s requested more units than allowed (%d > %d)", 523 __func__, ifc->ifc_name, ifcs->ifcs_minifs, 524 ifc->ifc_maxunit + 1)); 525 526 for (unit = 0; unit < ifcs->ifcs_minifs; unit++) { 527 snprintf(name, IFNAMSIZ, "%s%d", ifc->ifc_name, unit); 528 err = if_clone_createif(ifc, name, IFNAMSIZ, NULL); 529 KASSERT(err == 0, 530 ("%s: failed to create required interface %s", 531 __func__, name)); 532 } 533} 534 535int 536ifc_simple_match(struct if_clone *ifc, const char *name) 537{ 538 const char *cp; 539 int i; 540 541 /* Match the name */ 542 for (cp = name, i = 0; i < strlen(ifc->ifc_name); i++, cp++) { 543 if (ifc->ifc_name[i] != *cp) 544 return (0); 545 } 546 547 /* Make sure there's a unit number or nothing after the name */ 548 for (; *cp != '\0'; cp++) { 549 if (*cp < '0' || *cp > '9') 550 return (0); 551 } 552 553 return (1); 554} 555 556int 557ifc_simple_create(struct if_clone *ifc, char *name, size_t len, caddr_t params) 558{ 559 char *dp; 560 int wildcard; 561 int unit; 562 int err; 563 struct ifc_simple_data *ifcs = ifc->ifc_data; 564 565 err = ifc_name2unit(name, &unit); 566 if (err != 0) 567 return (err); 568 569 wildcard = (unit < 0); 570 571 err = ifc_alloc_unit(ifc, &unit); 572 if (err != 0) 573 return (err); 574 575 err = ifcs->ifcs_create(ifc, unit, params); 576 if (err != 0) { 577 ifc_free_unit(ifc, unit); 578 return (err); 579 } 580 581 /* In the wildcard case, we need to update the name. */ 582 if (wildcard) { 583 for (dp = name; *dp != '\0'; dp++); 584 if (snprintf(dp, len - (dp-name), "%d", unit) > 585 len - (dp-name) - 1) { 586 /* 587 * This can only be a programmer error and 588 * there's no straightforward way to recover if 589 * it happens. 590 */ 591 panic("if_clone_create(): interface name too long"); 592 } 593 594 } 595 596 return (0); 597} 598 599int 600ifc_simple_destroy(struct if_clone *ifc, struct ifnet *ifp) 601{ 602 int unit; 603 struct ifc_simple_data *ifcs = ifc->ifc_data; 604 605 unit = ifp->if_dunit; 606 607 if (unit < ifcs->ifcs_minifs) 608 return (EINVAL); 609 610 ifcs->ifcs_destroy(ifp); 611 612 ifc_free_unit(ifc, unit); 613 614 return (0); 615}
|