1c398230bSWarner Losh /*- 251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 351369649SPedro F. Giffuni * 442a58907SGleb Smirnoff * Copyright (c) 2012 Gleb Smirnoff <glebius@FreeBSD.org> 5f889d2efSBrooks Davis * Copyright (c) 1980, 1986, 1993 6f889d2efSBrooks Davis * The Regents of the University of California. All rights reserved. 7f889d2efSBrooks Davis * 8f889d2efSBrooks Davis * Redistribution and use in source and binary forms, with or without 9f889d2efSBrooks Davis * modification, are permitted provided that the following conditions 10f889d2efSBrooks Davis * are met: 11f889d2efSBrooks Davis * 1. Redistributions of source code must retain the above copyright 12f889d2efSBrooks Davis * notice, this list of conditions and the following disclaimer. 13f889d2efSBrooks Davis * 2. Redistributions in binary form must reproduce the above copyright 14f889d2efSBrooks Davis * notice, this list of conditions and the following disclaimer in the 15f889d2efSBrooks Davis * documentation and/or other materials provided with the distribution. 16fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 17f889d2efSBrooks Davis * may be used to endorse or promote products derived from this software 18f889d2efSBrooks Davis * without specific prior written permission. 19f889d2efSBrooks Davis * 20f889d2efSBrooks Davis * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21f889d2efSBrooks Davis * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22f889d2efSBrooks Davis * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23f889d2efSBrooks Davis * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24f889d2efSBrooks Davis * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25f889d2efSBrooks Davis * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26f889d2efSBrooks Davis * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27f889d2efSBrooks Davis * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28f889d2efSBrooks Davis * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29f889d2efSBrooks Davis * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30f889d2efSBrooks Davis * SUCH DAMAGE. 31f889d2efSBrooks Davis * 32f889d2efSBrooks Davis * @(#)if.c 8.5 (Berkeley) 1/9/95 33f889d2efSBrooks Davis * $FreeBSD$ 34f889d2efSBrooks Davis */ 35f889d2efSBrooks Davis 36f889d2efSBrooks Davis #include <sys/param.h> 37c3322cb9SGleb Smirnoff #include <sys/eventhandler.h> 38f889d2efSBrooks Davis #include <sys/malloc.h> 39434dbbb3SRuslan Ermilov #include <sys/limits.h> 40f889d2efSBrooks Davis #include <sys/lock.h> 41f889d2efSBrooks Davis #include <sys/mutex.h> 42f889d2efSBrooks Davis #include <sys/kernel.h> 43f889d2efSBrooks Davis #include <sys/systm.h> 44f889d2efSBrooks Davis #include <sys/types.h> 45f889d2efSBrooks Davis #include <sys/socket.h> 46f889d2efSBrooks Davis 47f889d2efSBrooks Davis #include <net/if.h> 48f889d2efSBrooks Davis #include <net/if_var.h> 4976039bc8SGleb Smirnoff #include <net/if_clone.h> 50f889d2efSBrooks Davis #include <net/radix.h> 51f889d2efSBrooks Davis #include <net/route.h> 5221ca7b57SMarko Zec #include <net/vnet.h> 53f889d2efSBrooks Davis 5442a58907SGleb Smirnoff /* Current IF_MAXUNIT expands maximum to 5 characters. */ 5542a58907SGleb Smirnoff #define IFCLOSIZ (IFNAMSIZ - 5) 5642a58907SGleb Smirnoff 5742a58907SGleb Smirnoff /* 5842a58907SGleb Smirnoff * Structure describing a `cloning' interface. 5942a58907SGleb Smirnoff * 6042a58907SGleb Smirnoff * List of locks 6142a58907SGleb Smirnoff * (c) const until freeing 6242a58907SGleb Smirnoff * (d) driver specific data, may need external protection. 6342a58907SGleb Smirnoff * (e) locked by if_cloners_mtx 6442a58907SGleb Smirnoff * (i) locked by ifc_mtx mtx 6542a58907SGleb Smirnoff */ 6642a58907SGleb Smirnoff struct if_clone { 6742a58907SGleb Smirnoff char ifc_name[IFCLOSIZ]; /* (c) Name of device, e.g. `gif' */ 6842a58907SGleb Smirnoff struct unrhdr *ifc_unrhdr; /* (c) alloc_unr(9) header */ 6942a58907SGleb Smirnoff int ifc_maxunit; /* (c) maximum unit number */ 7009f6ff4fSMatt Macy int ifc_flags; 7142a58907SGleb Smirnoff long ifc_refcnt; /* (i) Reference count. */ 7242a58907SGleb Smirnoff LIST_HEAD(, ifnet) ifc_iflist; /* (i) List of cloned interfaces */ 7342a58907SGleb Smirnoff struct mtx ifc_mtx; /* Mutex to protect members. */ 7442a58907SGleb Smirnoff 7542a58907SGleb Smirnoff enum { SIMPLE, ADVANCED } ifc_type; /* (c) */ 7642a58907SGleb Smirnoff 7742a58907SGleb Smirnoff /* (c) Driver specific cloning functions. Called with no locks held. */ 7842a58907SGleb Smirnoff union { 7942a58907SGleb Smirnoff struct { /* advanced cloner */ 8042a58907SGleb Smirnoff ifc_match_t *_ifc_match; 8142a58907SGleb Smirnoff ifc_create_t *_ifc_create; 8242a58907SGleb Smirnoff ifc_destroy_t *_ifc_destroy; 8342a58907SGleb Smirnoff } A; 8442a58907SGleb Smirnoff struct { /* simple cloner */ 8542a58907SGleb Smirnoff ifcs_create_t *_ifcs_create; 8642a58907SGleb Smirnoff ifcs_destroy_t *_ifcs_destroy; 8742a58907SGleb Smirnoff int _ifcs_minifs; /* minimum ifs */ 8842a58907SGleb Smirnoff 8942a58907SGleb Smirnoff } S; 9042a58907SGleb Smirnoff } U; 9142a58907SGleb Smirnoff #define ifc_match U.A._ifc_match 9242a58907SGleb Smirnoff #define ifc_create U.A._ifc_create 9342a58907SGleb Smirnoff #define ifc_destroy U.A._ifc_destroy 9442a58907SGleb Smirnoff #define ifcs_create U.S._ifcs_create 9542a58907SGleb Smirnoff #define ifcs_destroy U.S._ifcs_destroy 9642a58907SGleb Smirnoff #define ifcs_minifs U.S._ifcs_minifs 9742a58907SGleb Smirnoff 9842a58907SGleb Smirnoff LIST_ENTRY(if_clone) ifc_list; /* (e) On list of cloners */ 9942a58907SGleb Smirnoff }; 10042a58907SGleb Smirnoff 101f889d2efSBrooks Davis static void if_clone_free(struct if_clone *ifc); 1026b7330e2SSam Leffler static int if_clone_createif(struct if_clone *ifc, char *name, size_t len, 1036b7330e2SSam Leffler caddr_t params); 104f889d2efSBrooks Davis 10542a58907SGleb Smirnoff static int ifc_simple_match(struct if_clone *, const char *); 10642a58907SGleb Smirnoff static int ifc_simple_create(struct if_clone *, char *, size_t, caddr_t); 10742a58907SGleb Smirnoff static int ifc_simple_destroy(struct if_clone *, struct ifnet *); 10842a58907SGleb Smirnoff 109f889d2efSBrooks Davis static struct mtx if_cloners_mtx; 1104ea05db8SGleb Smirnoff MTX_SYSINIT(if_cloners_lock, &if_cloners_mtx, "if_cloners lock", MTX_DEF); 1115f901c92SAndrew Turner VNET_DEFINE_STATIC(int, if_cloners_count); 112eddfbb76SRobert Watson VNET_DEFINE(LIST_HEAD(, if_clone), if_cloners); 113eddfbb76SRobert Watson 1141e77c105SRobert Watson #define V_if_cloners_count VNET(if_cloners_count) 1151e77c105SRobert Watson #define V_if_cloners VNET(if_cloners) 116f889d2efSBrooks Davis 117f889d2efSBrooks Davis #define IF_CLONERS_LOCK_ASSERT() mtx_assert(&if_cloners_mtx, MA_OWNED) 118f889d2efSBrooks Davis #define IF_CLONERS_LOCK() mtx_lock(&if_cloners_mtx) 119f889d2efSBrooks Davis #define IF_CLONERS_UNLOCK() mtx_unlock(&if_cloners_mtx) 120f889d2efSBrooks Davis 121f889d2efSBrooks Davis #define IF_CLONE_LOCK_INIT(ifc) \ 122f889d2efSBrooks Davis mtx_init(&(ifc)->ifc_mtx, "if_clone lock", NULL, MTX_DEF) 123f889d2efSBrooks Davis #define IF_CLONE_LOCK_DESTROY(ifc) mtx_destroy(&(ifc)->ifc_mtx) 124f889d2efSBrooks Davis #define IF_CLONE_LOCK_ASSERT(ifc) mtx_assert(&(ifc)->ifc_mtx, MA_OWNED) 125f889d2efSBrooks Davis #define IF_CLONE_LOCK(ifc) mtx_lock(&(ifc)->ifc_mtx) 126f889d2efSBrooks Davis #define IF_CLONE_UNLOCK(ifc) mtx_unlock(&(ifc)->ifc_mtx) 127f889d2efSBrooks Davis 128f889d2efSBrooks Davis #define IF_CLONE_ADDREF(ifc) \ 129f889d2efSBrooks Davis do { \ 130f889d2efSBrooks Davis IF_CLONE_LOCK(ifc); \ 131f889d2efSBrooks Davis IF_CLONE_ADDREF_LOCKED(ifc); \ 132f889d2efSBrooks Davis IF_CLONE_UNLOCK(ifc); \ 133f889d2efSBrooks Davis } while (0) 134f889d2efSBrooks Davis #define IF_CLONE_ADDREF_LOCKED(ifc) \ 135f889d2efSBrooks Davis do { \ 136f889d2efSBrooks Davis IF_CLONE_LOCK_ASSERT(ifc); \ 137f889d2efSBrooks Davis KASSERT((ifc)->ifc_refcnt >= 0, \ 138f889d2efSBrooks Davis ("negative refcnt %ld", (ifc)->ifc_refcnt)); \ 139f889d2efSBrooks Davis (ifc)->ifc_refcnt++; \ 140f889d2efSBrooks Davis } while (0) 141f889d2efSBrooks Davis #define IF_CLONE_REMREF(ifc) \ 142f889d2efSBrooks Davis do { \ 143f889d2efSBrooks Davis IF_CLONE_LOCK(ifc); \ 144f889d2efSBrooks Davis IF_CLONE_REMREF_LOCKED(ifc); \ 145f889d2efSBrooks Davis } while (0) 146f889d2efSBrooks Davis #define IF_CLONE_REMREF_LOCKED(ifc) \ 147f889d2efSBrooks Davis do { \ 148f889d2efSBrooks Davis IF_CLONE_LOCK_ASSERT(ifc); \ 149f889d2efSBrooks Davis KASSERT((ifc)->ifc_refcnt > 0, \ 150f889d2efSBrooks Davis ("bogus refcnt %ld", (ifc)->ifc_refcnt)); \ 151f889d2efSBrooks Davis if (--(ifc)->ifc_refcnt == 0) { \ 152f889d2efSBrooks Davis IF_CLONE_UNLOCK(ifc); \ 153f889d2efSBrooks Davis if_clone_free(ifc); \ 154ca64c799SMax Laier } else { \ 155f889d2efSBrooks Davis /* silently free the lock */ \ 156f889d2efSBrooks Davis IF_CLONE_UNLOCK(ifc); \ 157ca64c799SMax Laier } \ 158f889d2efSBrooks Davis } while (0) 159f889d2efSBrooks Davis 1604e7e0183SAndrew Thompson #define IFC_IFLIST_INSERT(_ifc, _ifp) \ 1614e7e0183SAndrew Thompson LIST_INSERT_HEAD(&_ifc->ifc_iflist, _ifp, if_clones) 1624e7e0183SAndrew Thompson #define IFC_IFLIST_REMOVE(_ifc, _ifp) \ 1634e7e0183SAndrew Thompson LIST_REMOVE(_ifp, if_clones) 1644e7e0183SAndrew Thompson 165c711aea6SPoul-Henning Kamp static MALLOC_DEFINE(M_CLONE, "clone", "interface cloning framework"); 166f889d2efSBrooks Davis 167d0728d71SRobert Watson void 168d0728d71SRobert Watson vnet_if_clone_init(void) 16937f17770SMarko Zec { 17037f17770SMarko Zec 17137f17770SMarko Zec LIST_INIT(&V_if_cloners); 17237f17770SMarko Zec } 17337f17770SMarko Zec 174f889d2efSBrooks Davis /* 1754e7e0183SAndrew Thompson * Lookup and create a clone network interface. 176f889d2efSBrooks Davis */ 177f889d2efSBrooks Davis int 1786b7330e2SSam Leffler if_clone_create(char *name, size_t len, caddr_t params) 179f889d2efSBrooks Davis { 180f889d2efSBrooks Davis struct if_clone *ifc; 181f889d2efSBrooks Davis 182f889d2efSBrooks Davis /* Try to find an applicable cloner for this request */ 183f889d2efSBrooks Davis IF_CLONERS_LOCK(); 18442a58907SGleb Smirnoff LIST_FOREACH(ifc, &V_if_cloners, ifc_list) 18542a58907SGleb Smirnoff if (ifc->ifc_type == SIMPLE) { 18642a58907SGleb Smirnoff if (ifc_simple_match(ifc, name)) 187f889d2efSBrooks Davis break; 18842a58907SGleb Smirnoff } else { 18942a58907SGleb Smirnoff if (ifc->ifc_match(ifc, name)) 19042a58907SGleb Smirnoff break; 191f889d2efSBrooks Davis } 19237f17770SMarko Zec #ifdef VIMAGE 19337f17770SMarko Zec if (ifc == NULL && !IS_DEFAULT_VNET(curvnet)) { 19437f17770SMarko Zec CURVNET_SET_QUIET(vnet0); 19542a58907SGleb Smirnoff LIST_FOREACH(ifc, &V_if_cloners, ifc_list) 19642a58907SGleb Smirnoff if (ifc->ifc_type == SIMPLE) { 19742a58907SGleb Smirnoff if (ifc_simple_match(ifc, name)) 19842a58907SGleb Smirnoff break; 19942a58907SGleb Smirnoff } else { 20037f17770SMarko Zec if (ifc->ifc_match(ifc, name)) 20137f17770SMarko Zec break; 20237f17770SMarko Zec } 20337f17770SMarko Zec CURVNET_RESTORE(); 20437f17770SMarko Zec } 20537f17770SMarko Zec #endif 206f889d2efSBrooks Davis IF_CLONERS_UNLOCK(); 207f889d2efSBrooks Davis 208f889d2efSBrooks Davis if (ifc == NULL) 209f889d2efSBrooks Davis return (EINVAL); 210f889d2efSBrooks Davis 2116b7330e2SSam Leffler return (if_clone_createif(ifc, name, len, params)); 2124e7e0183SAndrew Thompson } 2134e7e0183SAndrew Thompson 214b02fd8b7SKristof Provost void 215b02fd8b7SKristof Provost if_clone_addif(struct if_clone *ifc, struct ifnet *ifp) 216b02fd8b7SKristof Provost { 217b02fd8b7SKristof Provost 218b02fd8b7SKristof Provost if ((ifc->ifc_flags & IFC_NOGROUP) == 0) 219b02fd8b7SKristof Provost if_addgroup(ifp, ifc->ifc_name); 220b02fd8b7SKristof Provost 221b02fd8b7SKristof Provost IF_CLONE_LOCK(ifc); 222b02fd8b7SKristof Provost IFC_IFLIST_INSERT(ifc, ifp); 223b02fd8b7SKristof Provost IF_CLONE_UNLOCK(ifc); 224b02fd8b7SKristof Provost } 225b02fd8b7SKristof Provost 2264e7e0183SAndrew Thompson /* 2274e7e0183SAndrew Thompson * Create a clone network interface. 2284e7e0183SAndrew Thompson */ 2294e7e0183SAndrew Thompson static int 2306b7330e2SSam Leffler if_clone_createif(struct if_clone *ifc, char *name, size_t len, caddr_t params) 2314e7e0183SAndrew Thompson { 2324e7e0183SAndrew Thompson int err; 2334e7e0183SAndrew Thompson struct ifnet *ifp; 2344e7e0183SAndrew Thompson 2354e7e0183SAndrew Thompson if (ifunit(name) != NULL) 2364e7e0183SAndrew Thompson return (EEXIST); 2374e7e0183SAndrew Thompson 23842a58907SGleb Smirnoff if (ifc->ifc_type == SIMPLE) 23942a58907SGleb Smirnoff err = ifc_simple_create(ifc, name, len, params); 24042a58907SGleb Smirnoff else 2416b7330e2SSam Leffler err = (*ifc->ifc_create)(ifc, name, len, params); 2424e7e0183SAndrew Thompson 2434e7e0183SAndrew Thompson if (!err) { 2444e7e0183SAndrew Thompson ifp = ifunit(name); 2454e7e0183SAndrew Thompson if (ifp == NULL) 2464e7e0183SAndrew Thompson panic("%s: lookup failed for %s", __func__, name); 2474e7e0183SAndrew Thompson 248b02fd8b7SKristof Provost if_clone_addif(ifc, ifp); 2494e7e0183SAndrew Thompson } 2504e7e0183SAndrew Thompson 251f889d2efSBrooks Davis return (err); 252f889d2efSBrooks Davis } 253f889d2efSBrooks Davis 254f889d2efSBrooks Davis /* 2554e7e0183SAndrew Thompson * Lookup and destroy a clone network interface. 256f889d2efSBrooks Davis */ 257f889d2efSBrooks Davis int 258f889d2efSBrooks Davis if_clone_destroy(const char *name) 259f889d2efSBrooks Davis { 260d0088cdeSBjoern A. Zeeb int err; 261f889d2efSBrooks Davis struct if_clone *ifc; 262f889d2efSBrooks Davis struct ifnet *ifp; 263f889d2efSBrooks Davis 264d0088cdeSBjoern A. Zeeb ifp = ifunit_ref(name); 265f889d2efSBrooks Davis if (ifp == NULL) 266f889d2efSBrooks Davis return (ENXIO); 267f889d2efSBrooks Davis 268f889d2efSBrooks Davis /* Find the cloner for this interface */ 269f889d2efSBrooks Davis IF_CLONERS_LOCK(); 27037f17770SMarko Zec LIST_FOREACH(ifc, &V_if_cloners, ifc_list) { 271f889d2efSBrooks Davis if (strcmp(ifc->ifc_name, ifp->if_dname) == 0) { 272f889d2efSBrooks Davis break; 273f889d2efSBrooks Davis } 274f889d2efSBrooks Davis } 27537f17770SMarko Zec #ifdef VIMAGE 27637f17770SMarko Zec if (ifc == NULL && !IS_DEFAULT_VNET(curvnet)) { 27737f17770SMarko Zec CURVNET_SET_QUIET(vnet0); 27842a58907SGleb Smirnoff LIST_FOREACH(ifc, &V_if_cloners, ifc_list) 2793aaf0159SGleb Smirnoff if (ifc->ifc_type == SIMPLE) { 28042a58907SGleb Smirnoff if (ifc_simple_match(ifc, name)) 28142a58907SGleb Smirnoff break; 28242a58907SGleb Smirnoff } else { 28337f17770SMarko Zec if (ifc->ifc_match(ifc, name)) 28437f17770SMarko Zec break; 28537f17770SMarko Zec } 28637f17770SMarko Zec CURVNET_RESTORE(); 28737f17770SMarko Zec } 28837f17770SMarko Zec #endif 289f889d2efSBrooks Davis IF_CLONERS_UNLOCK(); 290d0088cdeSBjoern A. Zeeb if (ifc == NULL) { 291d0088cdeSBjoern A. Zeeb if_rele(ifp); 292f889d2efSBrooks Davis return (EINVAL); 293d0088cdeSBjoern A. Zeeb } 294f889d2efSBrooks Davis 295d0088cdeSBjoern A. Zeeb err = if_clone_destroyif(ifc, ifp); 296d0088cdeSBjoern A. Zeeb if_rele(ifp); 297d0088cdeSBjoern A. Zeeb return err; 2984e7e0183SAndrew Thompson } 2994e7e0183SAndrew Thompson 3004e7e0183SAndrew Thompson /* 3014e7e0183SAndrew Thompson * Destroy a clone network interface. 3024e7e0183SAndrew Thompson */ 303cb959fa2SAndrew Thompson int 3044e7e0183SAndrew Thompson if_clone_destroyif(struct if_clone *ifc, struct ifnet *ifp) 3054e7e0183SAndrew Thompson { 3064e7e0183SAndrew Thompson int err; 307c769e1beSBjoern A. Zeeb struct ifnet *ifcifp; 3084e7e0183SAndrew Thompson 30942a58907SGleb Smirnoff if (ifc->ifc_type == ADVANCED && ifc->ifc_destroy == NULL) 31021ca7b57SMarko Zec return(EOPNOTSUPP); 311f889d2efSBrooks Davis 31237f17770SMarko Zec /* 31337f17770SMarko Zec * Given that the cloned ifnet might be attached to a different 31437f17770SMarko Zec * vnet from where its cloner was registered, we have to 31537f17770SMarko Zec * switch to the vnet context of the target vnet. 31637f17770SMarko Zec */ 31737f17770SMarko Zec CURVNET_SET_QUIET(ifp->if_vnet); 31837f17770SMarko Zec 319434dbbb3SRuslan Ermilov IF_CLONE_LOCK(ifc); 320c769e1beSBjoern A. Zeeb LIST_FOREACH(ifcifp, &ifc->ifc_iflist, if_clones) { 321c769e1beSBjoern A. Zeeb if (ifcifp == ifp) { 322434dbbb3SRuslan Ermilov IFC_IFLIST_REMOVE(ifc, ifp); 323c769e1beSBjoern A. Zeeb break; 324c769e1beSBjoern A. Zeeb } 325c769e1beSBjoern A. Zeeb } 326434dbbb3SRuslan Ermilov IF_CLONE_UNLOCK(ifc); 327c769e1beSBjoern A. Zeeb if (ifcifp == NULL) { 328c769e1beSBjoern A. Zeeb CURVNET_RESTORE(); 329c769e1beSBjoern A. Zeeb return (ENXIO); /* ifp is not on the list. */ 330c769e1beSBjoern A. Zeeb } 33109f6ff4fSMatt Macy if ((ifc->ifc_flags & IFC_NOGROUP) == 0) 3320dad3f0eSMax Laier if_delgroup(ifp, ifc->ifc_name); 3330dad3f0eSMax Laier 33442a58907SGleb Smirnoff if (ifc->ifc_type == SIMPLE) 33542a58907SGleb Smirnoff err = ifc_simple_destroy(ifc, ifp); 33642a58907SGleb Smirnoff else 337f889d2efSBrooks Davis err = (*ifc->ifc_destroy)(ifc, ifp); 338f889d2efSBrooks Davis 339434dbbb3SRuslan Ermilov if (err != 0) { 34009f6ff4fSMatt Macy if ((ifc->ifc_flags & IFC_NOGROUP) == 0) 3410dad3f0eSMax Laier if_addgroup(ifp, ifc->ifc_name); 3420dad3f0eSMax Laier 343434dbbb3SRuslan Ermilov IF_CLONE_LOCK(ifc); 344434dbbb3SRuslan Ermilov IFC_IFLIST_INSERT(ifc, ifp); 345434dbbb3SRuslan Ermilov IF_CLONE_UNLOCK(ifc); 346434dbbb3SRuslan Ermilov } 34721ca7b57SMarko Zec CURVNET_RESTORE(); 348f889d2efSBrooks Davis return (err); 349f889d2efSBrooks Davis } 350f889d2efSBrooks Davis 35142a58907SGleb Smirnoff static struct if_clone * 35242a58907SGleb Smirnoff if_clone_alloc(const char *name, int maxunit) 35342a58907SGleb Smirnoff { 35442a58907SGleb Smirnoff struct if_clone *ifc; 35542a58907SGleb Smirnoff 35642a58907SGleb Smirnoff KASSERT(name != NULL, ("%s: no name\n", __func__)); 35742a58907SGleb Smirnoff 35842a58907SGleb Smirnoff ifc = malloc(sizeof(struct if_clone), M_CLONE, M_WAITOK | M_ZERO); 35942a58907SGleb Smirnoff strncpy(ifc->ifc_name, name, IFCLOSIZ-1); 36042a58907SGleb Smirnoff IF_CLONE_LOCK_INIT(ifc); 36142a58907SGleb Smirnoff IF_CLONE_ADDREF(ifc); 36242a58907SGleb Smirnoff ifc->ifc_maxunit = maxunit ? maxunit : IF_MAXUNIT; 36342a58907SGleb Smirnoff ifc->ifc_unrhdr = new_unrhdr(0, ifc->ifc_maxunit, &ifc->ifc_mtx); 36442a58907SGleb Smirnoff LIST_INIT(&ifc->ifc_iflist); 36542a58907SGleb Smirnoff 36642a58907SGleb Smirnoff return (ifc); 36742a58907SGleb Smirnoff } 36842a58907SGleb Smirnoff 36942a58907SGleb Smirnoff static int 370f889d2efSBrooks Davis if_clone_attach(struct if_clone *ifc) 371f889d2efSBrooks Davis { 3722e9fff5bSGleb Smirnoff struct if_clone *ifc1; 373f889d2efSBrooks Davis 374f889d2efSBrooks Davis IF_CLONERS_LOCK(); 3752e9fff5bSGleb Smirnoff LIST_FOREACH(ifc1, &V_if_cloners, ifc_list) 3762e9fff5bSGleb Smirnoff if (strcmp(ifc->ifc_name, ifc1->ifc_name) == 0) { 3772e9fff5bSGleb Smirnoff IF_CLONERS_UNLOCK(); 3782e9fff5bSGleb Smirnoff IF_CLONE_REMREF(ifc); 3792e9fff5bSGleb Smirnoff return (EEXIST); 3802e9fff5bSGleb Smirnoff } 38137f17770SMarko Zec LIST_INSERT_HEAD(&V_if_cloners, ifc, ifc_list); 38237f17770SMarko Zec V_if_cloners_count++; 383f889d2efSBrooks Davis IF_CLONERS_UNLOCK(); 384f889d2efSBrooks Davis 38542a58907SGleb Smirnoff return (0); 38642a58907SGleb Smirnoff } 38742a58907SGleb Smirnoff 38842a58907SGleb Smirnoff struct if_clone * 38942a58907SGleb Smirnoff if_clone_advanced(const char *name, u_int maxunit, ifc_match_t match, 39042a58907SGleb Smirnoff ifc_create_t create, ifc_destroy_t destroy) 39142a58907SGleb Smirnoff { 39242a58907SGleb Smirnoff struct if_clone *ifc; 39342a58907SGleb Smirnoff 39442a58907SGleb Smirnoff ifc = if_clone_alloc(name, maxunit); 39542a58907SGleb Smirnoff ifc->ifc_type = ADVANCED; 39642a58907SGleb Smirnoff ifc->ifc_match = match; 39742a58907SGleb Smirnoff ifc->ifc_create = create; 39842a58907SGleb Smirnoff ifc->ifc_destroy = destroy; 39942a58907SGleb Smirnoff 4003395dd6eSAlexander Kabaev if (if_clone_attach(ifc) != 0) 40142a58907SGleb Smirnoff return (NULL); 40242a58907SGleb Smirnoff 403f889d2efSBrooks Davis EVENTHANDLER_INVOKE(if_clone_event, ifc); 4042e9fff5bSGleb Smirnoff 40542a58907SGleb Smirnoff return (ifc); 40642a58907SGleb Smirnoff } 40742a58907SGleb Smirnoff 40842a58907SGleb Smirnoff struct if_clone * 40942a58907SGleb Smirnoff if_clone_simple(const char *name, ifcs_create_t create, ifcs_destroy_t destroy, 41042a58907SGleb Smirnoff u_int minifs) 41142a58907SGleb Smirnoff { 41242a58907SGleb Smirnoff struct if_clone *ifc; 41342a58907SGleb Smirnoff u_int unit; 41442a58907SGleb Smirnoff 41542a58907SGleb Smirnoff ifc = if_clone_alloc(name, 0); 41642a58907SGleb Smirnoff ifc->ifc_type = SIMPLE; 41742a58907SGleb Smirnoff ifc->ifcs_create = create; 41842a58907SGleb Smirnoff ifc->ifcs_destroy = destroy; 41942a58907SGleb Smirnoff ifc->ifcs_minifs = minifs; 42042a58907SGleb Smirnoff 4213395dd6eSAlexander Kabaev if (if_clone_attach(ifc) != 0) 42242a58907SGleb Smirnoff return (NULL); 42342a58907SGleb Smirnoff 42442a58907SGleb Smirnoff for (unit = 0; unit < minifs; unit++) { 42542a58907SGleb Smirnoff char name[IFNAMSIZ]; 42646d0f824SMatt Macy int error __unused; 42742a58907SGleb Smirnoff 42842a58907SGleb Smirnoff snprintf(name, IFNAMSIZ, "%s%d", ifc->ifc_name, unit); 42942a58907SGleb Smirnoff error = if_clone_createif(ifc, name, IFNAMSIZ, NULL); 43042a58907SGleb Smirnoff KASSERT(error == 0, 43142a58907SGleb Smirnoff ("%s: failed to create required interface %s", 43242a58907SGleb Smirnoff __func__, name)); 43342a58907SGleb Smirnoff } 43442a58907SGleb Smirnoff 43542a58907SGleb Smirnoff EVENTHANDLER_INVOKE(if_clone_event, ifc); 43642a58907SGleb Smirnoff 43742a58907SGleb Smirnoff return (ifc); 438f889d2efSBrooks Davis } 439f889d2efSBrooks Davis 440f889d2efSBrooks Davis /* 441f889d2efSBrooks Davis * Unregister a network interface cloner. 442f889d2efSBrooks Davis */ 443f889d2efSBrooks Davis void 444f889d2efSBrooks Davis if_clone_detach(struct if_clone *ifc) 445f889d2efSBrooks Davis { 446f889d2efSBrooks Davis 447f889d2efSBrooks Davis IF_CLONERS_LOCK(); 448f889d2efSBrooks Davis LIST_REMOVE(ifc, ifc_list); 44937f17770SMarko Zec V_if_cloners_count--; 450f889d2efSBrooks Davis IF_CLONERS_UNLOCK(); 451f889d2efSBrooks Davis 452febd0759SAndrew Thompson /* Allow all simples to be destroyed */ 45342a58907SGleb Smirnoff if (ifc->ifc_type == SIMPLE) 45442a58907SGleb Smirnoff ifc->ifcs_minifs = 0; 455febd0759SAndrew Thompson 4564e7e0183SAndrew Thompson /* destroy all interfaces for this cloner */ 4574e7e0183SAndrew Thompson while (!LIST_EMPTY(&ifc->ifc_iflist)) 4584e7e0183SAndrew Thompson if_clone_destroyif(ifc, LIST_FIRST(&ifc->ifc_iflist)); 4594e7e0183SAndrew Thompson 460f889d2efSBrooks Davis IF_CLONE_REMREF(ifc); 461f889d2efSBrooks Davis } 462f889d2efSBrooks Davis 463f889d2efSBrooks Davis static void 464f889d2efSBrooks Davis if_clone_free(struct if_clone *ifc) 465f889d2efSBrooks Davis { 466f889d2efSBrooks Davis 4674e7e0183SAndrew Thompson KASSERT(LIST_EMPTY(&ifc->ifc_iflist), 4684e7e0183SAndrew Thompson ("%s: ifc_iflist not empty", __func__)); 4694e7e0183SAndrew Thompson 470f889d2efSBrooks Davis IF_CLONE_LOCK_DESTROY(ifc); 4712e9fff5bSGleb Smirnoff delete_unrhdr(ifc->ifc_unrhdr); 47242a58907SGleb Smirnoff free(ifc, M_CLONE); 473f889d2efSBrooks Davis } 474f889d2efSBrooks Davis 475f889d2efSBrooks Davis /* 476f889d2efSBrooks Davis * Provide list of interface cloners to userspace. 477f889d2efSBrooks Davis */ 478f889d2efSBrooks Davis int 479f889d2efSBrooks Davis if_clone_list(struct if_clonereq *ifcr) 480f889d2efSBrooks Davis { 481c859ef97SBrooks Davis char *buf, *dst, *outbuf = NULL; 482f889d2efSBrooks Davis struct if_clone *ifc; 483c859ef97SBrooks Davis int buf_count, count, err = 0; 484c859ef97SBrooks Davis 485a6d00835SMaxim Konovalov if (ifcr->ifcr_count < 0) 486a6d00835SMaxim Konovalov return (EINVAL); 487a6d00835SMaxim Konovalov 488c859ef97SBrooks Davis IF_CLONERS_LOCK(); 489c859ef97SBrooks Davis /* 490c859ef97SBrooks Davis * Set our internal output buffer size. We could end up not 491c859ef97SBrooks Davis * reporting a cloner that is added between the unlock and lock 492c859ef97SBrooks Davis * below, but that's not a major problem. Not caping our 493c859ef97SBrooks Davis * allocation to the number of cloners actually in the system 494c859ef97SBrooks Davis * could be because that would let arbitrary users cause us to 495a4641f4eSPedro F. Giffuni * allocate arbitrary amounts of kernel memory. 496c859ef97SBrooks Davis */ 49737f17770SMarko Zec buf_count = (V_if_cloners_count < ifcr->ifcr_count) ? 49837f17770SMarko Zec V_if_cloners_count : ifcr->ifcr_count; 499c859ef97SBrooks Davis IF_CLONERS_UNLOCK(); 500c859ef97SBrooks Davis 501c859ef97SBrooks Davis outbuf = malloc(IFNAMSIZ*buf_count, M_CLONE, M_WAITOK | M_ZERO); 502f889d2efSBrooks Davis 503f889d2efSBrooks Davis IF_CLONERS_LOCK(); 504f889d2efSBrooks Davis 50537f17770SMarko Zec ifcr->ifcr_total = V_if_cloners_count; 506f889d2efSBrooks Davis if ((dst = ifcr->ifcr_buffer) == NULL) { 507f889d2efSBrooks Davis /* Just asking how many there are. */ 508f889d2efSBrooks Davis goto done; 509f889d2efSBrooks Davis } 51037f17770SMarko Zec count = (V_if_cloners_count < buf_count) ? 51137f17770SMarko Zec V_if_cloners_count : buf_count; 512f889d2efSBrooks Davis 51337f17770SMarko Zec for (ifc = LIST_FIRST(&V_if_cloners), buf = outbuf; 514c859ef97SBrooks Davis ifc != NULL && count != 0; 515c859ef97SBrooks Davis ifc = LIST_NEXT(ifc, ifc_list), count--, buf += IFNAMSIZ) { 516c859ef97SBrooks Davis strlcpy(buf, ifc->ifc_name, IFNAMSIZ); 517f889d2efSBrooks Davis } 518f889d2efSBrooks Davis 519f889d2efSBrooks Davis done: 520f889d2efSBrooks Davis IF_CLONERS_UNLOCK(); 52192f19df4SAlexander Kabaev if (err == 0 && dst != NULL) 522c859ef97SBrooks Davis err = copyout(outbuf, dst, buf_count*IFNAMSIZ); 523c859ef97SBrooks Davis if (outbuf != NULL) 524c859ef97SBrooks Davis free(outbuf, M_CLONE); 525f889d2efSBrooks Davis return (err); 526f889d2efSBrooks Davis } 527f889d2efSBrooks Davis 52854712fc4SGleb Smirnoff #ifdef VIMAGE 529f889d2efSBrooks Davis /* 53054712fc4SGleb Smirnoff * if_clone_restoregroup() is used in context of if_vmove(). 53154712fc4SGleb Smirnoff * 53254712fc4SGleb Smirnoff * Since if_detach_internal() has removed the interface from ALL groups, we 53354712fc4SGleb Smirnoff * need to "restore" interface membership in the cloner's group. Note that 53454712fc4SGleb Smirnoff * interface belongs to cloner in its home vnet, so we first find the original 53554712fc4SGleb Smirnoff * cloner, and then we confirm that cloner with the same name exists in the 53654712fc4SGleb Smirnoff * current vnet. 537c92a456bSHiroki Sato */ 53854712fc4SGleb Smirnoff void 53954712fc4SGleb Smirnoff if_clone_restoregroup(struct ifnet *ifp) 540c92a456bSHiroki Sato { 54154712fc4SGleb Smirnoff struct if_clone *ifc; 542c92a456bSHiroki Sato struct ifnet *ifcifp; 54354712fc4SGleb Smirnoff char ifc_name[IFCLOSIZ] = { [0] = '\0' }; 544c92a456bSHiroki Sato 54554712fc4SGleb Smirnoff CURVNET_SET_QUIET(ifp->if_home_vnet); 546c92a456bSHiroki Sato IF_CLONERS_LOCK(); 547c92a456bSHiroki Sato LIST_FOREACH(ifc, &V_if_cloners, ifc_list) { 548c92a456bSHiroki Sato IF_CLONE_LOCK(ifc); 549c92a456bSHiroki Sato LIST_FOREACH(ifcifp, &ifc->ifc_iflist, if_clones) { 550c92a456bSHiroki Sato if (ifp == ifcifp) { 55154712fc4SGleb Smirnoff strncpy(ifc_name, ifc->ifc_name, IFCLOSIZ-1); 552c92a456bSHiroki Sato break; 553c92a456bSHiroki Sato } 554c92a456bSHiroki Sato } 555c92a456bSHiroki Sato IF_CLONE_UNLOCK(ifc); 55654712fc4SGleb Smirnoff if (ifc_name[0] != '\0') 557c92a456bSHiroki Sato break; 558c92a456bSHiroki Sato } 55954712fc4SGleb Smirnoff CURVNET_RESTORE(); 56054712fc4SGleb Smirnoff LIST_FOREACH(ifc, &V_if_cloners, ifc_list) 56154712fc4SGleb Smirnoff if (strcmp(ifc->ifc_name, ifc_name) == 0 && 56254712fc4SGleb Smirnoff ((ifc->ifc_flags & IFC_NOGROUP) == 0)) 56354712fc4SGleb Smirnoff break; 564c92a456bSHiroki Sato IF_CLONERS_UNLOCK(); 565c92a456bSHiroki Sato 56654712fc4SGleb Smirnoff if (ifc != NULL) 56754712fc4SGleb Smirnoff if_addgroup(ifp, ifc_name); 568c92a456bSHiroki Sato } 56954712fc4SGleb Smirnoff #endif 570c92a456bSHiroki Sato 571c92a456bSHiroki Sato /* 572f889d2efSBrooks Davis * A utility function to extract unit numbers from interface names of 57353729367SAlexander V. Chernikov * the form name###. 574f889d2efSBrooks Davis * 575f889d2efSBrooks Davis * Returns 0 on success and an error on failure. 576f889d2efSBrooks Davis */ 577f889d2efSBrooks Davis int 578f889d2efSBrooks Davis ifc_name2unit(const char *name, int *unit) 579f889d2efSBrooks Davis { 580f889d2efSBrooks Davis const char *cp; 581434dbbb3SRuslan Ermilov int cutoff = INT_MAX / 10; 582434dbbb3SRuslan Ermilov int cutlim = INT_MAX % 10; 583f889d2efSBrooks Davis 58453729367SAlexander V. Chernikov for (cp = name; *cp != '\0' && (*cp < '0' || *cp > '9'); cp++) 58553729367SAlexander V. Chernikov ; 586f889d2efSBrooks Davis if (*cp == '\0') { 587f889d2efSBrooks Davis *unit = -1; 588434dbbb3SRuslan Ermilov } else if (cp[0] == '0' && cp[1] != '\0') { 589434dbbb3SRuslan Ermilov /* Disallow leading zeroes. */ 590434dbbb3SRuslan Ermilov return (EINVAL); 591f889d2efSBrooks Davis } else { 592f889d2efSBrooks Davis for (*unit = 0; *cp != '\0'; cp++) { 593f889d2efSBrooks Davis if (*cp < '0' || *cp > '9') { 594f889d2efSBrooks Davis /* Bogus unit number. */ 595f889d2efSBrooks Davis return (EINVAL); 596f889d2efSBrooks Davis } 597434dbbb3SRuslan Ermilov if (*unit > cutoff || 598434dbbb3SRuslan Ermilov (*unit == cutoff && *cp - '0' > cutlim)) 599434dbbb3SRuslan Ermilov return (EINVAL); 600f889d2efSBrooks Davis *unit = (*unit * 10) + (*cp - '0'); 601f889d2efSBrooks Davis } 602f889d2efSBrooks Davis } 603f889d2efSBrooks Davis 604f889d2efSBrooks Davis return (0); 605f889d2efSBrooks Davis } 606f889d2efSBrooks Davis 607c64c1f95SAndriy Voskoboinyk static int 608c64c1f95SAndriy Voskoboinyk ifc_alloc_unit_specific(struct if_clone *ifc, int *unit) 609f889d2efSBrooks Davis { 6102e9fff5bSGleb Smirnoff char name[IFNAMSIZ]; 611f889d2efSBrooks Davis 6123932d760SGleb Smirnoff if (*unit > ifc->ifc_maxunit) 6133932d760SGleb Smirnoff return (ENOSPC); 614c64c1f95SAndriy Voskoboinyk 615c64c1f95SAndriy Voskoboinyk if (alloc_unr_specific(ifc->ifc_unrhdr, *unit) == -1) 6162e9fff5bSGleb Smirnoff return (EEXIST); 617f889d2efSBrooks Davis 6182e9fff5bSGleb Smirnoff snprintf(name, IFNAMSIZ, "%s%d", ifc->ifc_name, *unit); 6192e9fff5bSGleb Smirnoff if (ifunit(name) != NULL) { 6203932d760SGleb Smirnoff free_unr(ifc->ifc_unrhdr, *unit); 6212e9fff5bSGleb Smirnoff return (EEXIST); 622f889d2efSBrooks Davis } 623f889d2efSBrooks Davis 6242e9fff5bSGleb Smirnoff IF_CLONE_ADDREF(ifc); 625f889d2efSBrooks Davis 6262e9fff5bSGleb Smirnoff return (0); 627f889d2efSBrooks Davis } 628f889d2efSBrooks Davis 629c64c1f95SAndriy Voskoboinyk static int 630c64c1f95SAndriy Voskoboinyk ifc_alloc_unit_next(struct if_clone *ifc, int *unit) 631c64c1f95SAndriy Voskoboinyk { 632c64c1f95SAndriy Voskoboinyk int error; 633c64c1f95SAndriy Voskoboinyk 634c64c1f95SAndriy Voskoboinyk *unit = alloc_unr(ifc->ifc_unrhdr); 635c64c1f95SAndriy Voskoboinyk if (*unit == -1) 636c64c1f95SAndriy Voskoboinyk return (ENOSPC); 637c64c1f95SAndriy Voskoboinyk 638c64c1f95SAndriy Voskoboinyk free_unr(ifc->ifc_unrhdr, *unit); 639c64c1f95SAndriy Voskoboinyk for (;;) { 640c64c1f95SAndriy Voskoboinyk error = ifc_alloc_unit_specific(ifc, unit); 641c64c1f95SAndriy Voskoboinyk if (error != EEXIST) 642c64c1f95SAndriy Voskoboinyk break; 643c64c1f95SAndriy Voskoboinyk 644c64c1f95SAndriy Voskoboinyk (*unit)++; 645c64c1f95SAndriy Voskoboinyk } 646c64c1f95SAndriy Voskoboinyk 647c64c1f95SAndriy Voskoboinyk return (error); 648c64c1f95SAndriy Voskoboinyk } 649c64c1f95SAndriy Voskoboinyk 650c64c1f95SAndriy Voskoboinyk int 651c64c1f95SAndriy Voskoboinyk ifc_alloc_unit(struct if_clone *ifc, int *unit) 652c64c1f95SAndriy Voskoboinyk { 653c64c1f95SAndriy Voskoboinyk if (*unit < 0) 654c64c1f95SAndriy Voskoboinyk return (ifc_alloc_unit_next(ifc, unit)); 655c64c1f95SAndriy Voskoboinyk else 656c64c1f95SAndriy Voskoboinyk return (ifc_alloc_unit_specific(ifc, unit)); 657c64c1f95SAndriy Voskoboinyk } 658c64c1f95SAndriy Voskoboinyk 659f889d2efSBrooks Davis void 660f889d2efSBrooks Davis ifc_free_unit(struct if_clone *ifc, int unit) 661f889d2efSBrooks Davis { 662f889d2efSBrooks Davis 6632e9fff5bSGleb Smirnoff free_unr(ifc->ifc_unrhdr, unit); 6642e9fff5bSGleb Smirnoff IF_CLONE_REMREF(ifc); 665f889d2efSBrooks Davis } 666f889d2efSBrooks Davis 66742a58907SGleb Smirnoff static int 668f889d2efSBrooks Davis ifc_simple_match(struct if_clone *ifc, const char *name) 669f889d2efSBrooks Davis { 670f889d2efSBrooks Davis const char *cp; 671f889d2efSBrooks Davis int i; 672f889d2efSBrooks Davis 673f889d2efSBrooks Davis /* Match the name */ 674f889d2efSBrooks Davis for (cp = name, i = 0; i < strlen(ifc->ifc_name); i++, cp++) { 675f889d2efSBrooks Davis if (ifc->ifc_name[i] != *cp) 676f889d2efSBrooks Davis return (0); 677f889d2efSBrooks Davis } 678f889d2efSBrooks Davis 679f889d2efSBrooks Davis /* Make sure there's a unit number or nothing after the name */ 680f889d2efSBrooks Davis for (; *cp != '\0'; cp++) { 681f889d2efSBrooks Davis if (*cp < '0' || *cp > '9') 682f889d2efSBrooks Davis return (0); 683f889d2efSBrooks Davis } 684f889d2efSBrooks Davis 685f889d2efSBrooks Davis return (1); 686f889d2efSBrooks Davis } 687f889d2efSBrooks Davis 68842a58907SGleb Smirnoff static int 6896b7330e2SSam Leffler ifc_simple_create(struct if_clone *ifc, char *name, size_t len, caddr_t params) 690f889d2efSBrooks Davis { 691f889d2efSBrooks Davis char *dp; 692f889d2efSBrooks Davis int wildcard; 693f889d2efSBrooks Davis int unit; 694f889d2efSBrooks Davis int err; 695f889d2efSBrooks Davis 696f889d2efSBrooks Davis err = ifc_name2unit(name, &unit); 697f889d2efSBrooks Davis if (err != 0) 698f889d2efSBrooks Davis return (err); 699f889d2efSBrooks Davis 700f889d2efSBrooks Davis wildcard = (unit < 0); 701f889d2efSBrooks Davis 702f889d2efSBrooks Davis err = ifc_alloc_unit(ifc, &unit); 703f889d2efSBrooks Davis if (err != 0) 704f889d2efSBrooks Davis return (err); 705f889d2efSBrooks Davis 70642a58907SGleb Smirnoff err = ifc->ifcs_create(ifc, unit, params); 707f889d2efSBrooks Davis if (err != 0) { 708f889d2efSBrooks Davis ifc_free_unit(ifc, unit); 709f889d2efSBrooks Davis return (err); 710f889d2efSBrooks Davis } 711f889d2efSBrooks Davis 712f889d2efSBrooks Davis /* In the wildcard case, we need to update the name. */ 713f889d2efSBrooks Davis if (wildcard) { 714f889d2efSBrooks Davis for (dp = name; *dp != '\0'; dp++); 715f889d2efSBrooks Davis if (snprintf(dp, len - (dp-name), "%d", unit) > 716f889d2efSBrooks Davis len - (dp-name) - 1) { 717f889d2efSBrooks Davis /* 718f889d2efSBrooks Davis * This can only be a programmer error and 719f889d2efSBrooks Davis * there's no straightforward way to recover if 720f889d2efSBrooks Davis * it happens. 721f889d2efSBrooks Davis */ 722f889d2efSBrooks Davis panic("if_clone_create(): interface name too long"); 723f889d2efSBrooks Davis } 724f889d2efSBrooks Davis } 725f889d2efSBrooks Davis 726f889d2efSBrooks Davis return (0); 727f889d2efSBrooks Davis } 728f889d2efSBrooks Davis 72942a58907SGleb Smirnoff static int 730f889d2efSBrooks Davis ifc_simple_destroy(struct if_clone *ifc, struct ifnet *ifp) 731f889d2efSBrooks Davis { 732f889d2efSBrooks Davis int unit; 733f889d2efSBrooks Davis 734f889d2efSBrooks Davis unit = ifp->if_dunit; 735f889d2efSBrooks Davis 73642a58907SGleb Smirnoff if (unit < ifc->ifcs_minifs) 737f889d2efSBrooks Davis return (EINVAL); 738f889d2efSBrooks Davis 73942a58907SGleb Smirnoff ifc->ifcs_destroy(ifp); 740f889d2efSBrooks Davis 741f889d2efSBrooks Davis ifc_free_unit(ifc, unit); 742f889d2efSBrooks Davis 743f889d2efSBrooks Davis return (0); 744f889d2efSBrooks Davis } 74509f6ff4fSMatt Macy 74609f6ff4fSMatt Macy const char * 74709f6ff4fSMatt Macy ifc_name(struct if_clone *ifc) 74809f6ff4fSMatt Macy { 74909f6ff4fSMatt Macy return (ifc->ifc_name); 75009f6ff4fSMatt Macy } 75109f6ff4fSMatt Macy 75209f6ff4fSMatt Macy void 75309f6ff4fSMatt Macy ifc_flags_set(struct if_clone *ifc, int flags) 75409f6ff4fSMatt Macy { 75509f6ff4fSMatt Macy ifc->ifc_flags = flags; 75609f6ff4fSMatt Macy } 75709f6ff4fSMatt Macy 75809f6ff4fSMatt Macy int 75909f6ff4fSMatt Macy ifc_flags_get(struct if_clone *ifc) 76009f6ff4fSMatt Macy { 76109f6ff4fSMatt Macy return (ifc->ifc_flags); 76209f6ff4fSMatt Macy } 763