if_clone.c revision 195837
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 30 * $FreeBSD: head/sys/net/if_clone.c 195837 2009-07-23 20:46:49Z rwatson $ 31 */ 32 33#include <sys/param.h> 34#include <sys/malloc.h> 35#include <sys/limits.h> 36#include <sys/lock.h> 37#include <sys/mutex.h> 38#include <sys/kernel.h> 39#include <sys/systm.h> 40#include <sys/types.h> 41#include <sys/socket.h> 42#include <sys/vimage.h> 43 44#include <net/if.h> 45#include <net/if_clone.h> 46#if 0 47#include <net/if_dl.h> 48#endif 49#include <net/if_types.h> 50#include <net/if_var.h> 51#include <net/radix.h> 52#include <net/route.h> 53#include <net/vnet.h> 54 55static void if_clone_free(struct if_clone *ifc); 56static int if_clone_createif(struct if_clone *ifc, char *name, size_t len, 57 caddr_t params); 58 59static struct mtx if_cloners_mtx; 60static VNET_DEFINE(int, if_cloners_count); 61VNET_DEFINE(LIST_HEAD(, if_clone), if_cloners); 62 63#define V_if_cloners_count VNET(if_cloners_count) 64#define V_if_cloners VNET(if_cloners) 65 66#define IF_CLONERS_LOCK_INIT() \ 67 mtx_init(&if_cloners_mtx, "if_cloners lock", NULL, MTX_DEF) 68#define IF_CLONERS_LOCK_ASSERT() mtx_assert(&if_cloners_mtx, MA_OWNED) 69#define IF_CLONERS_LOCK() mtx_lock(&if_cloners_mtx) 70#define IF_CLONERS_UNLOCK() mtx_unlock(&if_cloners_mtx) 71 72#define IF_CLONE_LOCK_INIT(ifc) \ 73 mtx_init(&(ifc)->ifc_mtx, "if_clone lock", NULL, MTX_DEF) 74#define IF_CLONE_LOCK_DESTROY(ifc) mtx_destroy(&(ifc)->ifc_mtx) 75#define IF_CLONE_LOCK_ASSERT(ifc) mtx_assert(&(ifc)->ifc_mtx, MA_OWNED) 76#define IF_CLONE_LOCK(ifc) mtx_lock(&(ifc)->ifc_mtx) 77#define IF_CLONE_UNLOCK(ifc) mtx_unlock(&(ifc)->ifc_mtx) 78 79#define IF_CLONE_ADDREF(ifc) \ 80 do { \ 81 IF_CLONE_LOCK(ifc); \ 82 IF_CLONE_ADDREF_LOCKED(ifc); \ 83 IF_CLONE_UNLOCK(ifc); \ 84 } while (0) 85#define IF_CLONE_ADDREF_LOCKED(ifc) \ 86 do { \ 87 IF_CLONE_LOCK_ASSERT(ifc); \ 88 KASSERT((ifc)->ifc_refcnt >= 0, \ 89 ("negative refcnt %ld", (ifc)->ifc_refcnt)); \ 90 (ifc)->ifc_refcnt++; \ 91 } while (0) 92#define IF_CLONE_REMREF(ifc) \ 93 do { \ 94 IF_CLONE_LOCK(ifc); \ 95 IF_CLONE_REMREF_LOCKED(ifc); \ 96 } while (0) 97#define IF_CLONE_REMREF_LOCKED(ifc) \ 98 do { \ 99 IF_CLONE_LOCK_ASSERT(ifc); \ 100 KASSERT((ifc)->ifc_refcnt > 0, \ 101 ("bogus refcnt %ld", (ifc)->ifc_refcnt)); \ 102 if (--(ifc)->ifc_refcnt == 0) { \ 103 IF_CLONE_UNLOCK(ifc); \ 104 if_clone_free(ifc); \ 105 } else { \ 106 /* silently free the lock */ \ 107 IF_CLONE_UNLOCK(ifc); \ 108 } \ 109 } while (0) 110 111#define IFC_IFLIST_INSERT(_ifc, _ifp) \ 112 LIST_INSERT_HEAD(&_ifc->ifc_iflist, _ifp, if_clones) 113#define IFC_IFLIST_REMOVE(_ifc, _ifp) \ 114 LIST_REMOVE(_ifp, if_clones) 115 116static MALLOC_DEFINE(M_CLONE, "clone", "interface cloning framework"); 117 118void 119vnet_if_clone_init(void) 120{ 121 122 LIST_INIT(&V_if_cloners); 123} 124 125void 126if_clone_init(void) 127{ 128 129 IF_CLONERS_LOCK_INIT(); 130} 131 132/* 133 * Lookup and create a clone network interface. 134 */ 135int 136if_clone_create(char *name, size_t len, caddr_t params) 137{ 138 struct if_clone *ifc; 139 140 /* Try to find an applicable cloner for this request */ 141 IF_CLONERS_LOCK(); 142 LIST_FOREACH(ifc, &V_if_cloners, ifc_list) { 143 if (ifc->ifc_match(ifc, name)) { 144 break; 145 } 146 } 147#ifdef VIMAGE 148 if (ifc == NULL && !IS_DEFAULT_VNET(curvnet)) { 149 CURVNET_SET_QUIET(vnet0); 150 LIST_FOREACH(ifc, &V_if_cloners, ifc_list) { 151 if (ifc->ifc_match(ifc, name)) 152 break; 153 } 154 CURVNET_RESTORE(); 155 } 156#endif 157 IF_CLONERS_UNLOCK(); 158 159 if (ifc == NULL) 160 return (EINVAL); 161 162 return (if_clone_createif(ifc, name, len, params)); 163} 164 165/* 166 * Create a clone network interface. 167 */ 168static int 169if_clone_createif(struct if_clone *ifc, char *name, size_t len, caddr_t params) 170{ 171 int err; 172 struct ifnet *ifp; 173 174 if (ifunit(name) != NULL) 175 return (EEXIST); 176 177 err = (*ifc->ifc_create)(ifc, name, len, params); 178 179 if (!err) { 180 ifp = ifunit(name); 181 if (ifp == NULL) 182 panic("%s: lookup failed for %s", __func__, name); 183 184 if_addgroup(ifp, ifc->ifc_name); 185 186 IF_CLONE_LOCK(ifc); 187 IFC_IFLIST_INSERT(ifc, ifp); 188 IF_CLONE_UNLOCK(ifc); 189 } 190 191 return (err); 192} 193 194/* 195 * Lookup and destroy a clone network interface. 196 */ 197int 198if_clone_destroy(const char *name) 199{ 200 struct if_clone *ifc; 201 struct ifnet *ifp; 202 203 ifp = ifunit(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 return (EINVAL); 227 228 return (if_clone_destroyif(ifc, ifp)); 229} 230 231/* 232 * Destroy a clone network interface. 233 */ 234int 235if_clone_destroyif(struct if_clone *ifc, struct ifnet *ifp) 236{ 237 int err; 238 239 if (ifc->ifc_destroy == NULL) 240 return(EOPNOTSUPP); 241 242 /* 243 * Given that the cloned ifnet might be attached to a different 244 * vnet from where its cloner was registered, we have to 245 * switch to the vnet context of the target vnet. 246 */ 247 CURVNET_SET_QUIET(ifp->if_vnet); 248 249 IF_CLONE_LOCK(ifc); 250 IFC_IFLIST_REMOVE(ifc, ifp); 251 IF_CLONE_UNLOCK(ifc); 252 253 if_delgroup(ifp, ifc->ifc_name); 254 255 err = (*ifc->ifc_destroy)(ifc, ifp); 256 257 if (err != 0) { 258 if_addgroup(ifp, ifc->ifc_name); 259 260 IF_CLONE_LOCK(ifc); 261 IFC_IFLIST_INSERT(ifc, ifp); 262 IF_CLONE_UNLOCK(ifc); 263 } 264 CURVNET_RESTORE(); 265 return (err); 266} 267 268/* 269 * Register a network interface cloner. 270 */ 271void 272if_clone_attach(struct if_clone *ifc) 273{ 274 int len, maxclone; 275 276 /* 277 * Compute bitmap size and allocate it. 278 */ 279 maxclone = ifc->ifc_maxunit + 1; 280 len = maxclone >> 3; 281 if ((len << 3) < maxclone) 282 len++; 283 ifc->ifc_units = malloc(len, M_CLONE, M_WAITOK | M_ZERO); 284 ifc->ifc_bmlen = len; 285 IF_CLONE_LOCK_INIT(ifc); 286 IF_CLONE_ADDREF(ifc); 287 288 IF_CLONERS_LOCK(); 289 LIST_INSERT_HEAD(&V_if_cloners, ifc, ifc_list); 290 V_if_cloners_count++; 291 IF_CLONERS_UNLOCK(); 292 293 LIST_INIT(&ifc->ifc_iflist); 294 295 if (ifc->ifc_attach != NULL) 296 (*ifc->ifc_attach)(ifc); 297 EVENTHANDLER_INVOKE(if_clone_event, ifc); 298} 299 300/* 301 * Unregister a network interface cloner. 302 */ 303void 304if_clone_detach(struct if_clone *ifc) 305{ 306 struct ifc_simple_data *ifcs = ifc->ifc_data; 307 308 IF_CLONERS_LOCK(); 309 LIST_REMOVE(ifc, ifc_list); 310 V_if_cloners_count--; 311 IF_CLONERS_UNLOCK(); 312 313 /* Allow all simples to be destroyed */ 314 if (ifc->ifc_attach == ifc_simple_attach) 315 ifcs->ifcs_minifs = 0; 316 317 /* destroy all interfaces for this cloner */ 318 while (!LIST_EMPTY(&ifc->ifc_iflist)) 319 if_clone_destroyif(ifc, LIST_FIRST(&ifc->ifc_iflist)); 320 321 IF_CLONE_REMREF(ifc); 322} 323 324static void 325if_clone_free(struct if_clone *ifc) 326{ 327 for (int bytoff = 0; bytoff < ifc->ifc_bmlen; bytoff++) { 328 KASSERT(ifc->ifc_units[bytoff] == 0x00, 329 ("ifc_units[%d] is not empty", bytoff)); 330 } 331 332 KASSERT(LIST_EMPTY(&ifc->ifc_iflist), 333 ("%s: ifc_iflist not empty", __func__)); 334 335 IF_CLONE_LOCK_DESTROY(ifc); 336 free(ifc->ifc_units, M_CLONE); 337} 338 339/* 340 * Provide list of interface cloners to userspace. 341 */ 342int 343if_clone_list(struct if_clonereq *ifcr) 344{ 345 char *buf, *dst, *outbuf = NULL; 346 struct if_clone *ifc; 347 int buf_count, count, err = 0; 348 349 if (ifcr->ifcr_count < 0) 350 return (EINVAL); 351 352 IF_CLONERS_LOCK(); 353 /* 354 * Set our internal output buffer size. We could end up not 355 * reporting a cloner that is added between the unlock and lock 356 * below, but that's not a major problem. Not caping our 357 * allocation to the number of cloners actually in the system 358 * could be because that would let arbitrary users cause us to 359 * allocate abritrary amounts of kernel memory. 360 */ 361 buf_count = (V_if_cloners_count < ifcr->ifcr_count) ? 362 V_if_cloners_count : ifcr->ifcr_count; 363 IF_CLONERS_UNLOCK(); 364 365 outbuf = malloc(IFNAMSIZ*buf_count, M_CLONE, M_WAITOK | M_ZERO); 366 367 IF_CLONERS_LOCK(); 368 369 ifcr->ifcr_total = V_if_cloners_count; 370 if ((dst = ifcr->ifcr_buffer) == NULL) { 371 /* Just asking how many there are. */ 372 goto done; 373 } 374 count = (V_if_cloners_count < buf_count) ? 375 V_if_cloners_count : buf_count; 376 377 for (ifc = LIST_FIRST(&V_if_cloners), buf = outbuf; 378 ifc != NULL && count != 0; 379 ifc = LIST_NEXT(ifc, ifc_list), count--, buf += IFNAMSIZ) { 380 strlcpy(buf, ifc->ifc_name, IFNAMSIZ); 381 } 382 383done: 384 IF_CLONERS_UNLOCK(); 385 if (err == 0) 386 err = copyout(outbuf, dst, buf_count*IFNAMSIZ); 387 if (outbuf != NULL) 388 free(outbuf, M_CLONE); 389 return (err); 390} 391 392/* 393 * A utility function to extract unit numbers from interface names of 394 * the form name###. 395 * 396 * Returns 0 on success and an error on failure. 397 */ 398int 399ifc_name2unit(const char *name, int *unit) 400{ 401 const char *cp; 402 int cutoff = INT_MAX / 10; 403 int cutlim = INT_MAX % 10; 404 405 for (cp = name; *cp != '\0' && (*cp < '0' || *cp > '9'); cp++); 406 if (*cp == '\0') { 407 *unit = -1; 408 } else if (cp[0] == '0' && cp[1] != '\0') { 409 /* Disallow leading zeroes. */ 410 return (EINVAL); 411 } else { 412 for (*unit = 0; *cp != '\0'; cp++) { 413 if (*cp < '0' || *cp > '9') { 414 /* Bogus unit number. */ 415 return (EINVAL); 416 } 417 if (*unit > cutoff || 418 (*unit == cutoff && *cp - '0' > cutlim)) 419 return (EINVAL); 420 *unit = (*unit * 10) + (*cp - '0'); 421 } 422 } 423 424 return (0); 425} 426 427int 428ifc_alloc_unit(struct if_clone *ifc, int *unit) 429{ 430 int wildcard, bytoff, bitoff; 431 int err = 0; 432 433 IF_CLONE_LOCK(ifc); 434 435 bytoff = bitoff = 0; 436 wildcard = (*unit < 0); 437 /* 438 * Find a free unit if none was given. 439 */ 440 if (wildcard) { 441 while ((bytoff < ifc->ifc_bmlen) 442 && (ifc->ifc_units[bytoff] == 0xff)) 443 bytoff++; 444 if (bytoff >= ifc->ifc_bmlen) { 445 err = ENOSPC; 446 goto done; 447 } 448 while ((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0) 449 bitoff++; 450 *unit = (bytoff << 3) + bitoff; 451 } 452 453 if (*unit > ifc->ifc_maxunit) { 454 err = ENOSPC; 455 goto done; 456 } 457 458 if (!wildcard) { 459 bytoff = *unit >> 3; 460 bitoff = *unit - (bytoff << 3); 461 } 462 463 if((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0) { 464 err = EEXIST; 465 goto done; 466 } 467 /* 468 * Allocate the unit in the bitmap. 469 */ 470 KASSERT((ifc->ifc_units[bytoff] & (1 << bitoff)) == 0, 471 ("%s: bit is already set", __func__)); 472 ifc->ifc_units[bytoff] |= (1 << bitoff); 473 IF_CLONE_ADDREF_LOCKED(ifc); 474 475done: 476 IF_CLONE_UNLOCK(ifc); 477 return (err); 478} 479 480void 481ifc_free_unit(struct if_clone *ifc, int unit) 482{ 483 int bytoff, bitoff; 484 485 486 /* 487 * Compute offset in the bitmap and deallocate the unit. 488 */ 489 bytoff = unit >> 3; 490 bitoff = unit - (bytoff << 3); 491 492 IF_CLONE_LOCK(ifc); 493 KASSERT((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0, 494 ("%s: bit is already cleared", __func__)); 495 ifc->ifc_units[bytoff] &= ~(1 << bitoff); 496 IF_CLONE_REMREF_LOCKED(ifc); /* releases lock */ 497} 498 499void 500ifc_simple_attach(struct if_clone *ifc) 501{ 502 int err; 503 int unit; 504 char name[IFNAMSIZ]; 505 struct ifc_simple_data *ifcs = ifc->ifc_data; 506 507 KASSERT(ifcs->ifcs_minifs - 1 <= ifc->ifc_maxunit, 508 ("%s: %s requested more units than allowed (%d > %d)", 509 __func__, ifc->ifc_name, ifcs->ifcs_minifs, 510 ifc->ifc_maxunit + 1)); 511 512 for (unit = 0; unit < ifcs->ifcs_minifs; unit++) { 513 snprintf(name, IFNAMSIZ, "%s%d", ifc->ifc_name, unit); 514 err = if_clone_createif(ifc, name, IFNAMSIZ, NULL); 515 KASSERT(err == 0, 516 ("%s: failed to create required interface %s", 517 __func__, name)); 518 } 519} 520 521int 522ifc_simple_match(struct if_clone *ifc, const char *name) 523{ 524 const char *cp; 525 int i; 526 527 /* Match the name */ 528 for (cp = name, i = 0; i < strlen(ifc->ifc_name); i++, cp++) { 529 if (ifc->ifc_name[i] != *cp) 530 return (0); 531 } 532 533 /* Make sure there's a unit number or nothing after the name */ 534 for (; *cp != '\0'; cp++) { 535 if (*cp < '0' || *cp > '9') 536 return (0); 537 } 538 539 return (1); 540} 541 542int 543ifc_simple_create(struct if_clone *ifc, char *name, size_t len, caddr_t params) 544{ 545 char *dp; 546 int wildcard; 547 int unit; 548 int err; 549 struct ifc_simple_data *ifcs = ifc->ifc_data; 550 551 err = ifc_name2unit(name, &unit); 552 if (err != 0) 553 return (err); 554 555 wildcard = (unit < 0); 556 557 err = ifc_alloc_unit(ifc, &unit); 558 if (err != 0) 559 return (err); 560 561 err = ifcs->ifcs_create(ifc, unit, params); 562 if (err != 0) { 563 ifc_free_unit(ifc, unit); 564 return (err); 565 } 566 567 /* In the wildcard case, we need to update the name. */ 568 if (wildcard) { 569 for (dp = name; *dp != '\0'; dp++); 570 if (snprintf(dp, len - (dp-name), "%d", unit) > 571 len - (dp-name) - 1) { 572 /* 573 * This can only be a programmer error and 574 * there's no straightforward way to recover if 575 * it happens. 576 */ 577 panic("if_clone_create(): interface name too long"); 578 } 579 580 } 581 582 return (0); 583} 584 585int 586ifc_simple_destroy(struct if_clone *ifc, struct ifnet *ifp) 587{ 588 int unit; 589 struct ifc_simple_data *ifcs = ifc->ifc_data; 590 591 unit = ifp->if_dunit; 592 593 if (unit < ifcs->ifcs_minifs) 594 return (EINVAL); 595 596 ifcs->ifcs_destroy(ifp); 597 598 ifc_free_unit(ifc, unit); 599 600 return (0); 601} 602