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$ 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 43 #include <net/if.h> 44 #include <net/if_clone.h> 45 #if 0 46 #include <net/if_dl.h> 47 #endif 48 #include <net/if_types.h> 49 #include <net/if_var.h> 50 #include <net/radix.h> 51 #include <net/route.h> 52 #include <net/vnet.h> 53 54 static void if_clone_free(struct if_clone *ifc); 55 static int if_clone_createif(struct if_clone *ifc, char *name, size_t len, 56 caddr_t params); 57 58 static struct mtx if_cloners_mtx; 59 static VNET_DEFINE(int, if_cloners_count); 60 VNET_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 115 static MALLOC_DEFINE(M_CLONE, "clone", "interface cloning framework"); 116 117 void 118 vnet_if_clone_init(void) 119 { 120 121 LIST_INIT(&V_if_cloners); 122 } 123 124 void 125 if_clone_init(void) 126 { 127 128 IF_CLONERS_LOCK_INIT(); 129 } 130 131 /* 132 * Lookup and create a clone network interface. 133 */ 134 int 135 if_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 */ 167 static int 168 if_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 */ 196 int 197 if_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 */ 238 int 239 if_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 */ 285 int 286 if_clone_attach(struct if_clone *ifc) 287 { 288 struct if_clone *ifc1; 289 290 KASSERT(ifc->ifc_name != NULL, ("%s: no name\n", __func__)); 291 292 IF_CLONE_LOCK_INIT(ifc); 293 IF_CLONE_ADDREF(ifc); 294 ifc->ifc_unrhdr = new_unrhdr(0, ifc->ifc_maxunit, &ifc->ifc_mtx); 295 LIST_INIT(&ifc->ifc_iflist); 296 297 IF_CLONERS_LOCK(); 298 LIST_FOREACH(ifc1, &V_if_cloners, ifc_list) 299 if (strcmp(ifc->ifc_name, ifc1->ifc_name) == 0) { 300 IF_CLONERS_UNLOCK(); 301 IF_CLONE_REMREF(ifc); 302 return (EEXIST); 303 } 304 LIST_INSERT_HEAD(&V_if_cloners, ifc, ifc_list); 305 V_if_cloners_count++; 306 IF_CLONERS_UNLOCK(); 307 308 if (ifc->ifc_attach != NULL) 309 (*ifc->ifc_attach)(ifc); 310 EVENTHANDLER_INVOKE(if_clone_event, ifc); 311 312 return (0); 313 } 314 315 /* 316 * Unregister a network interface cloner. 317 */ 318 void 319 if_clone_detach(struct if_clone *ifc) 320 { 321 struct ifc_simple_data *ifcs = ifc->ifc_data; 322 323 IF_CLONERS_LOCK(); 324 LIST_REMOVE(ifc, ifc_list); 325 V_if_cloners_count--; 326 IF_CLONERS_UNLOCK(); 327 328 /* Allow all simples to be destroyed */ 329 if (ifc->ifc_attach == ifc_simple_attach) 330 ifcs->ifcs_minifs = 0; 331 332 /* destroy all interfaces for this cloner */ 333 while (!LIST_EMPTY(&ifc->ifc_iflist)) 334 if_clone_destroyif(ifc, LIST_FIRST(&ifc->ifc_iflist)); 335 336 IF_CLONE_REMREF(ifc); 337 } 338 339 static void 340 if_clone_free(struct if_clone *ifc) 341 { 342 343 KASSERT(LIST_EMPTY(&ifc->ifc_iflist), 344 ("%s: ifc_iflist not empty", __func__)); 345 346 IF_CLONE_LOCK_DESTROY(ifc); 347 delete_unrhdr(ifc->ifc_unrhdr); 348 } 349 350 /* 351 * Provide list of interface cloners to userspace. 352 */ 353 int 354 if_clone_list(struct if_clonereq *ifcr) 355 { 356 char *buf, *dst, *outbuf = NULL; 357 struct if_clone *ifc; 358 int buf_count, count, err = 0; 359 360 if (ifcr->ifcr_count < 0) 361 return (EINVAL); 362 363 IF_CLONERS_LOCK(); 364 /* 365 * Set our internal output buffer size. We could end up not 366 * reporting a cloner that is added between the unlock and lock 367 * below, but that's not a major problem. Not caping our 368 * allocation to the number of cloners actually in the system 369 * could be because that would let arbitrary users cause us to 370 * allocate abritrary amounts of kernel memory. 371 */ 372 buf_count = (V_if_cloners_count < ifcr->ifcr_count) ? 373 V_if_cloners_count : ifcr->ifcr_count; 374 IF_CLONERS_UNLOCK(); 375 376 outbuf = malloc(IFNAMSIZ*buf_count, M_CLONE, M_WAITOK | M_ZERO); 377 378 IF_CLONERS_LOCK(); 379 380 ifcr->ifcr_total = V_if_cloners_count; 381 if ((dst = ifcr->ifcr_buffer) == NULL) { 382 /* Just asking how many there are. */ 383 goto done; 384 } 385 count = (V_if_cloners_count < buf_count) ? 386 V_if_cloners_count : buf_count; 387 388 for (ifc = LIST_FIRST(&V_if_cloners), buf = outbuf; 389 ifc != NULL && count != 0; 390 ifc = LIST_NEXT(ifc, ifc_list), count--, buf += IFNAMSIZ) { 391 strlcpy(buf, ifc->ifc_name, IFNAMSIZ); 392 } 393 394 done: 395 IF_CLONERS_UNLOCK(); 396 if (err == 0) 397 err = copyout(outbuf, dst, buf_count*IFNAMSIZ); 398 if (outbuf != NULL) 399 free(outbuf, M_CLONE); 400 return (err); 401 } 402 403 /* 404 * A utility function to extract unit numbers from interface names of 405 * the form name###. 406 * 407 * Returns 0 on success and an error on failure. 408 */ 409 int 410 ifc_name2unit(const char *name, int *unit) 411 { 412 const char *cp; 413 int cutoff = INT_MAX / 10; 414 int cutlim = INT_MAX % 10; 415 416 for (cp = name; *cp != '\0' && (*cp < '0' || *cp > '9'); cp++); 417 if (*cp == '\0') { 418 *unit = -1; 419 } else if (cp[0] == '0' && cp[1] != '\0') { 420 /* Disallow leading zeroes. */ 421 return (EINVAL); 422 } else { 423 for (*unit = 0; *cp != '\0'; cp++) { 424 if (*cp < '0' || *cp > '9') { 425 /* Bogus unit number. */ 426 return (EINVAL); 427 } 428 if (*unit > cutoff || 429 (*unit == cutoff && *cp - '0' > cutlim)) 430 return (EINVAL); 431 *unit = (*unit * 10) + (*cp - '0'); 432 } 433 } 434 435 return (0); 436 } 437 438 int 439 ifc_alloc_unit(struct if_clone *ifc, int *unit) 440 { 441 char name[IFNAMSIZ]; 442 int wildcard; 443 444 wildcard = (*unit < 0); 445 retry: 446 if (wildcard) { 447 *unit = alloc_unr(ifc->ifc_unrhdr); 448 if (*unit == -1) 449 return (ENOSPC); 450 } else { 451 *unit = alloc_unr_specific(ifc->ifc_unrhdr, *unit); 452 if (*unit == -1) 453 return (EEXIST); 454 } 455 456 snprintf(name, IFNAMSIZ, "%s%d", ifc->ifc_name, *unit); 457 if (ifunit(name) != NULL) { 458 if (wildcard) 459 goto retry; /* XXXGL: yep, it's a unit leak */ 460 else 461 return (EEXIST); 462 } 463 464 IF_CLONE_ADDREF(ifc); 465 466 return (0); 467 } 468 469 void 470 ifc_free_unit(struct if_clone *ifc, int unit) 471 { 472 473 free_unr(ifc->ifc_unrhdr, unit); 474 IF_CLONE_REMREF(ifc); 475 } 476 477 void 478 ifc_simple_attach(struct if_clone *ifc) 479 { 480 int err; 481 int unit; 482 char name[IFNAMSIZ]; 483 struct ifc_simple_data *ifcs = ifc->ifc_data; 484 485 KASSERT(ifcs->ifcs_minifs - 1 <= ifc->ifc_maxunit, 486 ("%s: %s requested more units than allowed (%d > %d)", 487 __func__, ifc->ifc_name, ifcs->ifcs_minifs, 488 ifc->ifc_maxunit + 1)); 489 490 for (unit = 0; unit < ifcs->ifcs_minifs; unit++) { 491 snprintf(name, IFNAMSIZ, "%s%d", ifc->ifc_name, unit); 492 err = if_clone_createif(ifc, name, IFNAMSIZ, NULL); 493 KASSERT(err == 0, 494 ("%s: failed to create required interface %s", 495 __func__, name)); 496 } 497 } 498 499 int 500 ifc_simple_match(struct if_clone *ifc, const char *name) 501 { 502 const char *cp; 503 int i; 504 505 /* Match the name */ 506 for (cp = name, i = 0; i < strlen(ifc->ifc_name); i++, cp++) { 507 if (ifc->ifc_name[i] != *cp) 508 return (0); 509 } 510 511 /* Make sure there's a unit number or nothing after the name */ 512 for (; *cp != '\0'; cp++) { 513 if (*cp < '0' || *cp > '9') 514 return (0); 515 } 516 517 return (1); 518 } 519 520 int 521 ifc_simple_create(struct if_clone *ifc, char *name, size_t len, caddr_t params) 522 { 523 char *dp; 524 int wildcard; 525 int unit; 526 int err; 527 struct ifc_simple_data *ifcs = ifc->ifc_data; 528 529 err = ifc_name2unit(name, &unit); 530 if (err != 0) 531 return (err); 532 533 wildcard = (unit < 0); 534 535 err = ifc_alloc_unit(ifc, &unit); 536 if (err != 0) 537 return (err); 538 539 err = ifcs->ifcs_create(ifc, unit, params); 540 if (err != 0) { 541 ifc_free_unit(ifc, unit); 542 return (err); 543 } 544 545 /* In the wildcard case, we need to update the name. */ 546 if (wildcard) { 547 for (dp = name; *dp != '\0'; dp++); 548 if (snprintf(dp, len - (dp-name), "%d", unit) > 549 len - (dp-name) - 1) { 550 /* 551 * This can only be a programmer error and 552 * there's no straightforward way to recover if 553 * it happens. 554 */ 555 panic("if_clone_create(): interface name too long"); 556 } 557 558 } 559 560 return (0); 561 } 562 563 int 564 ifc_simple_destroy(struct if_clone *ifc, struct ifnet *ifp) 565 { 566 int unit; 567 struct ifc_simple_data *ifcs = ifc->ifc_data; 568 569 unit = ifp->if_dunit; 570 571 if (unit < ifcs->ifcs_minifs) 572 return (EINVAL); 573 574 ifcs->ifcs_destroy(ifp); 575 576 ifc_free_unit(ifc, unit); 577 578 return (0); 579 } 580