The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/net/if_clone.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-3-Clause
    3  *
    4  * Copyright (c) 2012 Gleb Smirnoff <glebius@FreeBSD.org>
    5  * Copyright (c) 1980, 1986, 1993
    6  *      The Regents of the University of California.  All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. Neither the name of the University nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  *
   32  *      @(#)if.c        8.5 (Berkeley) 1/9/95
   33  * $FreeBSD$
   34  */
   35 
   36 #include <sys/param.h>
   37 #include <sys/eventhandler.h>
   38 #include <sys/malloc.h>
   39 #include <sys/limits.h>
   40 #include <sys/lock.h>
   41 #include <sys/mutex.h>
   42 #include <sys/kernel.h>
   43 #include <sys/systm.h>
   44 #include <sys/types.h>
   45 #include <sys/socket.h>
   46 
   47 #include <net/if.h>
   48 #include <net/if_var.h>
   49 #include <net/if_private.h>
   50 #include <net/if_clone.h>
   51 #include <net/radix.h>
   52 #include <net/route.h>
   53 #include <net/vnet.h>
   54 
   55 /* Current IF_MAXUNIT expands maximum to 5 characters. */
   56 #define IFCLOSIZ        (IFNAMSIZ - 5)
   57 
   58 /*
   59  * Structure describing a `cloning' interface.
   60  *
   61  * List of locks
   62  * (c)          const until freeing
   63  * (d)          driver specific data, may need external protection.
   64  * (e)          locked by if_cloners_mtx
   65  * (i)          locked by ifc_mtx mtx
   66  */
   67 struct if_clone {
   68         char ifc_name[IFCLOSIZ];        /* (c) Name of device, e.g. `gif' */
   69         struct unrhdr *ifc_unrhdr;      /* (c) alloc_unr(9) header */
   70         int ifc_maxunit;                /* (c) maximum unit number */
   71         int ifc_flags;
   72         long ifc_refcnt;                /* (i) Reference count. */
   73         LIST_HEAD(, ifnet) ifc_iflist;  /* (i) List of cloned interfaces */
   74         struct mtx ifc_mtx;             /* Mutex to protect members. */
   75 
   76         ifc_match_f *ifc_match;         /* (c) Matcher function */
   77         ifc_create_f *ifc_create;       /* (c) Creates new interface */
   78         ifc_destroy_f *ifc_destroy;     /* (c) Destroys cloned interface */
   79 
   80 #ifdef CLONE_COMPAT_13
   81         /* (c) Driver specific cloning functions.  Called with no locks held. */
   82         union {
   83                 struct {        /* advanced cloner */
   84                         ifc_create_t    *_ifc_create;
   85                         ifc_destroy_t   *_ifc_destroy;
   86                 } A;
   87                 struct {        /* simple cloner */
   88                         ifcs_create_t   *_ifcs_create;
   89                         ifcs_destroy_t  *_ifcs_destroy;
   90                         int             _ifcs_minifs;   /* minimum ifs */
   91 
   92                 } S;
   93         } U;
   94 #define ifca_create     U.A._ifc_create
   95 #define ifca_destroy    U.A._ifc_destroy
   96 #define ifcs_create     U.S._ifcs_create
   97 #define ifcs_destroy    U.S._ifcs_destroy
   98 #define ifcs_minifs     U.S._ifcs_minifs
   99 #endif
  100 
  101         LIST_ENTRY(if_clone) ifc_list;  /* (e) On list of cloners */
  102 };
  103 
  104 
  105 
  106 static void     if_clone_free(struct if_clone *ifc);
  107 static int      if_clone_createif(struct if_clone *ifc, char *name, size_t len,
  108                     struct ifc_data *ifd, struct ifnet **ifpp);
  109 
  110 static int ifc_simple_match(struct if_clone *ifc, const char *name);
  111 static int ifc_handle_unit(struct if_clone *ifc, char *name, size_t len, int *punit);
  112 
  113 #ifdef CLONE_COMPAT_13
  114 static int ifc_simple_create_wrapper(struct if_clone *ifc, char *name, size_t maxlen,
  115     struct ifc_data *ifc_data, struct ifnet **ifpp);
  116 static int ifc_advanced_create_wrapper(struct if_clone *ifc, char *name, size_t maxlen,
  117     struct ifc_data *ifc_data, struct ifnet **ifpp);
  118 #endif
  119 
  120 static struct mtx if_cloners_mtx;
  121 MTX_SYSINIT(if_cloners_lock, &if_cloners_mtx, "if_cloners lock", MTX_DEF);
  122 VNET_DEFINE_STATIC(int, if_cloners_count);
  123 VNET_DEFINE(LIST_HEAD(, if_clone), if_cloners);
  124 
  125 #define V_if_cloners_count      VNET(if_cloners_count)
  126 #define V_if_cloners            VNET(if_cloners)
  127 
  128 #define IF_CLONERS_LOCK_ASSERT()        mtx_assert(&if_cloners_mtx, MA_OWNED)
  129 #define IF_CLONERS_LOCK()               mtx_lock(&if_cloners_mtx)
  130 #define IF_CLONERS_UNLOCK()             mtx_unlock(&if_cloners_mtx)
  131 
  132 #define IF_CLONE_LOCK_INIT(ifc)         \
  133     mtx_init(&(ifc)->ifc_mtx, "if_clone lock", NULL, MTX_DEF)
  134 #define IF_CLONE_LOCK_DESTROY(ifc)      mtx_destroy(&(ifc)->ifc_mtx)
  135 #define IF_CLONE_LOCK_ASSERT(ifc)       mtx_assert(&(ifc)->ifc_mtx, MA_OWNED)
  136 #define IF_CLONE_LOCK(ifc)              mtx_lock(&(ifc)->ifc_mtx)
  137 #define IF_CLONE_UNLOCK(ifc)            mtx_unlock(&(ifc)->ifc_mtx)
  138 
  139 #define IF_CLONE_ADDREF(ifc)                                            \
  140         do {                                                            \
  141                 IF_CLONE_LOCK(ifc);                                     \
  142                 IF_CLONE_ADDREF_LOCKED(ifc);                            \
  143                 IF_CLONE_UNLOCK(ifc);                                   \
  144         } while (0)
  145 #define IF_CLONE_ADDREF_LOCKED(ifc)                                     \
  146         do {                                                            \
  147                 IF_CLONE_LOCK_ASSERT(ifc);                              \
  148                 KASSERT((ifc)->ifc_refcnt >= 0,                         \
  149                     ("negative refcnt %ld", (ifc)->ifc_refcnt));        \
  150                 (ifc)->ifc_refcnt++;                                    \
  151         } while (0)
  152 #define IF_CLONE_REMREF(ifc)                                            \
  153         do {                                                            \
  154                 IF_CLONE_LOCK(ifc);                                     \
  155                 IF_CLONE_REMREF_LOCKED(ifc);                            \
  156         } while (0)
  157 #define IF_CLONE_REMREF_LOCKED(ifc)                                     \
  158         do {                                                            \
  159                 IF_CLONE_LOCK_ASSERT(ifc);                              \
  160                 KASSERT((ifc)->ifc_refcnt > 0,                          \
  161                     ("bogus refcnt %ld", (ifc)->ifc_refcnt));           \
  162                 if (--(ifc)->ifc_refcnt == 0) {                         \
  163                         IF_CLONE_UNLOCK(ifc);                           \
  164                         if_clone_free(ifc);                             \
  165                 } else {                                                \
  166                         /* silently free the lock */                    \
  167                         IF_CLONE_UNLOCK(ifc);                           \
  168                 }                                                       \
  169         } while (0)
  170 
  171 #define IFC_IFLIST_INSERT(_ifc, _ifp)                                   \
  172         LIST_INSERT_HEAD(&_ifc->ifc_iflist, _ifp, if_clones)
  173 #define IFC_IFLIST_REMOVE(_ifc, _ifp)                                   \
  174         LIST_REMOVE(_ifp, if_clones)
  175 
  176 static MALLOC_DEFINE(M_CLONE, "clone", "interface cloning framework");
  177 
  178 void
  179 vnet_if_clone_init(void)
  180 {
  181 
  182         LIST_INIT(&V_if_cloners);
  183 }
  184 
  185 /*
  186  * Lookup and create a clone network interface.
  187  */
  188 int
  189 ifc_create_ifp(const char *name, struct ifc_data *ifd,
  190     struct ifnet **ifpp)
  191 {
  192         struct if_clone *ifc;
  193         char ifname[IFNAMSIZ];
  194         struct ifnet *ifp = NULL;
  195         int error;
  196 
  197         /* Try to find an applicable cloner for this request */
  198         IF_CLONERS_LOCK();
  199         LIST_FOREACH(ifc, &V_if_cloners, ifc_list) {
  200                 if (ifc->ifc_match(ifc, name))
  201                         break;
  202         }
  203         IF_CLONERS_UNLOCK();
  204 
  205         if (ifc == NULL)
  206                 return (EINVAL);
  207 
  208         strlcpy(ifname, name, IFNAMSIZ);
  209         error = if_clone_createif(ifc, ifname, IFNAMSIZ, ifd, &ifp);
  210         if (ifpp != NULL)
  211                 *ifpp = ifp;
  212 
  213         return (error);
  214 }
  215 
  216 int
  217 if_clone_create(char *name, size_t len, caddr_t params)
  218 {
  219         struct ifc_data ifd = { .params = params };
  220         struct ifnet *ifp;
  221 
  222         int error = ifc_create_ifp(name, &ifd, &ifp);
  223 
  224         if (error == 0)
  225                 strlcpy(name, if_name(ifp), len);
  226 
  227         return (error);
  228 }
  229 
  230 void
  231 ifc_link_ifp(struct if_clone *ifc, struct ifnet *ifp)
  232 {
  233 
  234         if ((ifc->ifc_flags & IFC_NOGROUP) == 0)
  235                 if_addgroup(ifp, ifc->ifc_name);
  236 
  237         IF_CLONE_LOCK(ifc);
  238         IFC_IFLIST_INSERT(ifc, ifp);
  239         IF_CLONE_UNLOCK(ifc);
  240 }
  241 
  242 void
  243 if_clone_addif(struct if_clone *ifc, struct ifnet *ifp)
  244 {
  245         ifc_link_ifp(ifc, ifp);
  246 }
  247 
  248 bool
  249 ifc_unlink_ifp(struct if_clone *ifc, struct ifnet *ifp)
  250 {
  251         struct ifnet *ifcifp;
  252 
  253         IF_CLONE_LOCK(ifc);
  254         LIST_FOREACH(ifcifp, &ifc->ifc_iflist, if_clones) {
  255                 if (ifcifp == ifp) {
  256                         IFC_IFLIST_REMOVE(ifc, ifp);
  257                         break;
  258                 }
  259         }
  260         IF_CLONE_UNLOCK(ifc);
  261 
  262         if (ifcifp != NULL && (ifc->ifc_flags & IFC_F_NOGROUP) == 0)
  263                 if_delgroup(ifp, ifc->ifc_name);
  264 
  265         return (ifcifp != NULL);
  266 }
  267 
  268 static struct if_clone *
  269 ifc_find_cloner(const char *name, struct vnet *vnet)
  270 {
  271         struct if_clone *ifc;
  272 
  273         CURVNET_SET_QUIET(vnet);
  274         IF_CLONERS_LOCK();
  275         LIST_FOREACH(ifc, &V_if_cloners, ifc_list) {
  276                 if (strcmp(ifc->ifc_name, name) == 0) {
  277                         break;
  278                 }
  279         }
  280         IF_CLONERS_UNLOCK();
  281         CURVNET_RESTORE();
  282 
  283         return (ifc);
  284 }
  285 
  286 /*
  287  * Create a clone network interface.
  288  */
  289 static int
  290 if_clone_createif(struct if_clone *ifc, char *name, size_t len,
  291     struct ifc_data *ifd, struct ifnet **ifpp)
  292 {
  293         int err, unit = 0;
  294 
  295         if (ifunit(name) != NULL)
  296                 return (EEXIST);
  297 
  298         if (ifc->ifc_flags & IFC_F_AUTOUNIT) {
  299                 if ((err = ifc_handle_unit(ifc, name, len, &unit)) != 0)
  300                         return (err);
  301                 ifd->unit = unit;
  302         }
  303         *ifpp = NULL;
  304         err = (*ifc->ifc_create)(ifc, name, len, ifd, ifpp);
  305 
  306         if (err == 0) {
  307                 MPASS(*ifpp != NULL);
  308                 if_clone_addif(ifc, *ifpp);
  309         } else if (ifc->ifc_flags & IFC_F_AUTOUNIT)
  310                 ifc_free_unit(ifc, unit);
  311 
  312         return (err);
  313 }
  314 
  315 /*
  316  * Lookup and destroy a clone network interface.
  317  */
  318 int
  319 if_clone_destroy(const char *name)
  320 {
  321         int err;
  322         struct if_clone *ifc;
  323         struct ifnet *ifp;
  324 
  325         ifp = ifunit_ref(name);
  326         if (ifp == NULL)
  327                 return (ENXIO);
  328 
  329         ifc = ifc_find_cloner(ifp->if_dname, ifp->if_home_vnet);
  330         if (ifc == NULL) {
  331                 if_rele(ifp);
  332                 return (EINVAL);
  333         }
  334 
  335         err = if_clone_destroyif(ifc, ifp);
  336         if_rele(ifp);
  337         return err;
  338 }
  339 
  340 /*
  341  * Destroy a clone network interface.
  342  */
  343 static int
  344 if_clone_destroyif_flags(struct if_clone *ifc, struct ifnet *ifp, uint32_t flags)
  345 {
  346         int err;
  347 
  348         /*
  349          * Given that the cloned ifnet might be attached to a different
  350          * vnet from where its cloner was registered, we have to
  351          * switch to the vnet context of the target vnet.
  352          */
  353         CURVNET_SET_QUIET(ifp->if_vnet);
  354 
  355         if (!ifc_unlink_ifp(ifc, ifp)) {
  356                 CURVNET_RESTORE();
  357                 return (ENXIO);         /* ifp is not on the list. */
  358         }
  359 
  360         int unit = ifp->if_dunit;
  361         err = (*ifc->ifc_destroy)(ifc, ifp, flags);
  362 
  363         if (err != 0)
  364                 ifc_link_ifp(ifc, ifp);
  365         else if (ifc->ifc_flags & IFC_F_AUTOUNIT)
  366                 ifc_free_unit(ifc, unit);
  367         CURVNET_RESTORE();
  368         return (err);
  369 }
  370 
  371 int
  372 if_clone_destroyif(struct if_clone *ifc, struct ifnet *ifp)
  373 {
  374         return (if_clone_destroyif_flags(ifc, ifp, 0));
  375 }
  376 
  377 static struct if_clone *
  378 if_clone_alloc(const char *name, int maxunit)
  379 {
  380         struct if_clone *ifc;
  381 
  382         KASSERT(name != NULL, ("%s: no name\n", __func__));
  383 
  384         ifc = malloc(sizeof(struct if_clone), M_CLONE, M_WAITOK | M_ZERO);
  385         strncpy(ifc->ifc_name, name, IFCLOSIZ-1);
  386         IF_CLONE_LOCK_INIT(ifc);
  387         IF_CLONE_ADDREF(ifc);
  388         ifc->ifc_maxunit = maxunit ? maxunit : IF_MAXUNIT;
  389         ifc->ifc_unrhdr = new_unrhdr(0, ifc->ifc_maxunit, &ifc->ifc_mtx);
  390         LIST_INIT(&ifc->ifc_iflist);
  391 
  392         return (ifc);
  393 }
  394 
  395 static int
  396 if_clone_attach(struct if_clone *ifc)
  397 {
  398         struct if_clone *ifc1;
  399 
  400         IF_CLONERS_LOCK();
  401         LIST_FOREACH(ifc1, &V_if_cloners, ifc_list)
  402                 if (strcmp(ifc->ifc_name, ifc1->ifc_name) == 0) {
  403                         IF_CLONERS_UNLOCK();
  404                         IF_CLONE_REMREF(ifc);
  405                         return (EEXIST);
  406                 }
  407         LIST_INSERT_HEAD(&V_if_cloners, ifc, ifc_list);
  408         V_if_cloners_count++;
  409         IF_CLONERS_UNLOCK();
  410 
  411         return (0);
  412 }
  413 
  414 struct if_clone *
  415 ifc_attach_cloner(const char *name, struct if_clone_addreq *req)
  416 {
  417         if (req->create_f == NULL || req->destroy_f == NULL)
  418                 return (NULL);
  419         if (strnlen(name, IFCLOSIZ) >= (IFCLOSIZ - 1))
  420                 return (NULL);
  421 
  422         struct if_clone *ifc = if_clone_alloc(name, req->maxunit);
  423         ifc->ifc_match = req->match_f != NULL ? req->match_f : ifc_simple_match;
  424         ifc->ifc_create = req->create_f;
  425         ifc->ifc_destroy = req->destroy_f;
  426         ifc->ifc_flags = (req->flags & (IFC_F_AUTOUNIT | IFC_F_NOGROUP));
  427 
  428         if (if_clone_attach(ifc) != 0)
  429                 return (NULL);
  430 
  431         EVENTHANDLER_INVOKE(if_clone_event, ifc);
  432 
  433         return (ifc);
  434 }
  435 
  436 void
  437 ifc_detach_cloner(struct if_clone *ifc)
  438 {
  439         if_clone_detach(ifc);
  440 }
  441 
  442 
  443 #ifdef CLONE_COMPAT_13
  444 
  445 static int
  446 ifc_advanced_create_wrapper(struct if_clone *ifc, char *name, size_t maxlen,
  447     struct ifc_data *ifc_data, struct ifnet **ifpp)
  448 {
  449         int error = ifc->ifca_create(ifc, name, maxlen, ifc_data->params);
  450 
  451         if (error == 0)
  452                 *ifpp = ifunit(name);
  453         return (error);
  454 }
  455 
  456 static int
  457 ifc_advanced_destroy_wrapper(struct if_clone *ifc, struct ifnet *ifp, uint32_t flags)
  458 {
  459         if (ifc->ifca_destroy == NULL)
  460                 return (ENOTSUP);
  461         return (ifc->ifca_destroy(ifc, ifp));
  462 }
  463 
  464 struct if_clone *
  465 if_clone_advanced(const char *name, u_int maxunit, ifc_match_t match,
  466         ifc_create_t create, ifc_destroy_t destroy)
  467 {
  468         struct if_clone *ifc;
  469 
  470         ifc = if_clone_alloc(name, maxunit);
  471         ifc->ifc_match = match;
  472         ifc->ifc_create = ifc_advanced_create_wrapper;
  473         ifc->ifc_destroy = ifc_advanced_destroy_wrapper;
  474         ifc->ifca_destroy = destroy;
  475         ifc->ifca_create = create;
  476 
  477         if (if_clone_attach(ifc) != 0)
  478                 return (NULL);
  479 
  480         EVENTHANDLER_INVOKE(if_clone_event, ifc);
  481 
  482         return (ifc);
  483 }
  484 
  485 static int
  486 ifc_simple_create_wrapper(struct if_clone *ifc, char *name, size_t maxlen,
  487     struct ifc_data *ifc_data, struct ifnet **ifpp)
  488 {
  489         int unit = 0;
  490 
  491         ifc_name2unit(name, &unit);
  492         int error = ifc->ifcs_create(ifc, unit, ifc_data->params);
  493         if (error == 0)
  494                 *ifpp = ifunit(name);
  495         return (error);
  496 }
  497 
  498 static int
  499 ifc_simple_destroy_wrapper(struct if_clone *ifc, struct ifnet *ifp, uint32_t flags)
  500 {
  501         if (ifp->if_dunit < ifc->ifcs_minifs && (flags & IFC_F_FORCE) == 0)
  502                 return (EINVAL);
  503 
  504         ifc->ifcs_destroy(ifp);
  505         return (0);
  506 }
  507 
  508 struct if_clone *
  509 if_clone_simple(const char *name, ifcs_create_t create, ifcs_destroy_t destroy,
  510         u_int minifs)
  511 {
  512         struct if_clone *ifc;
  513         u_int unit;
  514 
  515         ifc = if_clone_alloc(name, 0);
  516         ifc->ifc_match = ifc_simple_match;
  517         ifc->ifc_create = ifc_simple_create_wrapper;
  518         ifc->ifc_destroy = ifc_simple_destroy_wrapper;
  519         ifc->ifcs_create = create;
  520         ifc->ifcs_destroy = destroy;
  521         ifc->ifcs_minifs = minifs;
  522         ifc->ifc_flags = IFC_F_AUTOUNIT;
  523 
  524         if (if_clone_attach(ifc) != 0)
  525                 return (NULL);
  526 
  527         for (unit = 0; unit < minifs; unit++) {
  528                 char name[IFNAMSIZ];
  529                 int error __unused;
  530                 struct ifc_data ifd = {};
  531                 struct ifnet *ifp;
  532 
  533                 snprintf(name, IFNAMSIZ, "%s%d", ifc->ifc_name, unit);
  534                 error = if_clone_createif(ifc, name, IFNAMSIZ, &ifd, &ifp);
  535                 KASSERT(error == 0,
  536                     ("%s: failed to create required interface %s",
  537                     __func__, name));
  538         }
  539 
  540         EVENTHANDLER_INVOKE(if_clone_event, ifc);
  541 
  542         return (ifc);
  543 }
  544 #endif
  545 
  546 /*
  547  * Unregister a network interface cloner.
  548  */
  549 void
  550 if_clone_detach(struct if_clone *ifc)
  551 {
  552 
  553         IF_CLONERS_LOCK();
  554         LIST_REMOVE(ifc, ifc_list);
  555         V_if_cloners_count--;
  556         IF_CLONERS_UNLOCK();
  557 
  558         /* destroy all interfaces for this cloner */
  559         while (!LIST_EMPTY(&ifc->ifc_iflist))
  560                 if_clone_destroyif_flags(ifc, LIST_FIRST(&ifc->ifc_iflist), IFC_F_FORCE);
  561 
  562         IF_CLONE_REMREF(ifc);
  563 }
  564 
  565 static void
  566 if_clone_free(struct if_clone *ifc)
  567 {
  568 
  569         KASSERT(LIST_EMPTY(&ifc->ifc_iflist),
  570             ("%s: ifc_iflist not empty", __func__));
  571 
  572         IF_CLONE_LOCK_DESTROY(ifc);
  573         delete_unrhdr(ifc->ifc_unrhdr);
  574         free(ifc, M_CLONE);
  575 }
  576 
  577 /*
  578  * Provide list of interface cloners to userspace.
  579  */
  580 int
  581 if_clone_list(struct if_clonereq *ifcr)
  582 {
  583         char *buf, *dst, *outbuf = NULL;
  584         struct if_clone *ifc;
  585         int buf_count, count, err = 0;
  586 
  587         if (ifcr->ifcr_count < 0)
  588                 return (EINVAL);
  589 
  590         IF_CLONERS_LOCK();
  591         /*
  592          * Set our internal output buffer size.  We could end up not
  593          * reporting a cloner that is added between the unlock and lock
  594          * below, but that's not a major problem.  Not caping our
  595          * allocation to the number of cloners actually in the system
  596          * could be because that would let arbitrary users cause us to
  597          * allocate arbitrary amounts of kernel memory.
  598          */
  599         buf_count = (V_if_cloners_count < ifcr->ifcr_count) ?
  600             V_if_cloners_count : ifcr->ifcr_count;
  601         IF_CLONERS_UNLOCK();
  602 
  603         outbuf = malloc(IFNAMSIZ*buf_count, M_CLONE, M_WAITOK | M_ZERO);
  604 
  605         IF_CLONERS_LOCK();
  606 
  607         ifcr->ifcr_total = V_if_cloners_count;
  608         if ((dst = ifcr->ifcr_buffer) == NULL) {
  609                 /* Just asking how many there are. */
  610                 goto done;
  611         }
  612         count = (V_if_cloners_count < buf_count) ?
  613             V_if_cloners_count : buf_count;
  614 
  615         for (ifc = LIST_FIRST(&V_if_cloners), buf = outbuf;
  616             ifc != NULL && count != 0;
  617             ifc = LIST_NEXT(ifc, ifc_list), count--, buf += IFNAMSIZ) {
  618                 strlcpy(buf, ifc->ifc_name, IFNAMSIZ);
  619         }
  620 
  621 done:
  622         IF_CLONERS_UNLOCK();
  623         if (err == 0 && dst != NULL)
  624                 err = copyout(outbuf, dst, buf_count*IFNAMSIZ);
  625         if (outbuf != NULL)
  626                 free(outbuf, M_CLONE);
  627         return (err);
  628 }
  629 
  630 #ifdef VIMAGE
  631 /*
  632  * if_clone_restoregroup() is used in context of if_vmove().
  633  *
  634  * Since if_detach_internal() has removed the interface from ALL groups, we
  635  * need to "restore" interface membership in the cloner's group.  Note that
  636  * interface belongs to cloner in its home vnet, so we first find the original
  637  * cloner, and then we confirm that cloner with the same name exists in the
  638  * current vnet.
  639  */
  640 void
  641 if_clone_restoregroup(struct ifnet *ifp)
  642 {
  643         struct if_clone *ifc;
  644         struct ifnet *ifcifp;
  645         char ifc_name[IFCLOSIZ] = { [0] = '\0' };
  646 
  647         CURVNET_SET_QUIET(ifp->if_home_vnet);
  648         IF_CLONERS_LOCK();
  649         LIST_FOREACH(ifc, &V_if_cloners, ifc_list) {
  650                 IF_CLONE_LOCK(ifc);
  651                 LIST_FOREACH(ifcifp, &ifc->ifc_iflist, if_clones) {
  652                         if (ifp == ifcifp) {
  653                                 strncpy(ifc_name, ifc->ifc_name, IFCLOSIZ-1);
  654                                 break;
  655                         }
  656                 }
  657                 IF_CLONE_UNLOCK(ifc);
  658                 if (ifc_name[0] != '\0')
  659                         break;
  660         }
  661         CURVNET_RESTORE();
  662         LIST_FOREACH(ifc, &V_if_cloners, ifc_list)
  663                 if (strcmp(ifc->ifc_name, ifc_name) == 0 &&
  664                     ((ifc->ifc_flags & IFC_NOGROUP) == 0))
  665                         break;
  666         IF_CLONERS_UNLOCK();
  667 
  668         if (ifc != NULL)
  669                 if_addgroup(ifp, ifc_name);
  670 }
  671 #endif
  672 
  673 /*
  674  * A utility function to extract unit numbers from interface names of
  675  * the form name###.
  676  *
  677  * Returns 0 on success and an error on failure.
  678  */
  679 int
  680 ifc_name2unit(const char *name, int *unit)
  681 {
  682         const char      *cp;
  683         int             cutoff = INT_MAX / 10;
  684         int             cutlim = INT_MAX % 10;
  685 
  686         for (cp = name; *cp != '\0' && (*cp < '' || *cp > '9'); cp++)
  687                 ;
  688         if (*cp == '\0') {
  689                 *unit = -1;
  690         } else if (cp[0] == '' && cp[1] != '\0') {
  691                 /* Disallow leading zeroes. */
  692                 return (EINVAL);
  693         } else {
  694                 for (*unit = 0; *cp != '\0'; cp++) {
  695                         if (*cp < '' || *cp > '9') {
  696                                 /* Bogus unit number. */
  697                                 return (EINVAL);
  698                         }
  699                         if (*unit > cutoff ||
  700                             (*unit == cutoff && *cp - '' > cutlim))
  701                                 return (EINVAL);
  702                         *unit = (*unit * 10) + (*cp - '');
  703                 }
  704         }
  705 
  706         return (0);
  707 }
  708 
  709 static int
  710 ifc_alloc_unit_specific(struct if_clone *ifc, int *unit)
  711 {
  712         char name[IFNAMSIZ];
  713 
  714         if (*unit > ifc->ifc_maxunit)
  715                 return (ENOSPC);
  716 
  717         if (alloc_unr_specific(ifc->ifc_unrhdr, *unit) == -1)
  718                 return (EEXIST);
  719 
  720         snprintf(name, IFNAMSIZ, "%s%d", ifc->ifc_name, *unit);
  721         if (ifunit(name) != NULL) {
  722                 free_unr(ifc->ifc_unrhdr, *unit);
  723                 return (EEXIST);
  724         }
  725 
  726         IF_CLONE_ADDREF(ifc);
  727 
  728         return (0);
  729 }
  730 
  731 static int
  732 ifc_alloc_unit_next(struct if_clone *ifc, int *unit)
  733 {
  734         int error;
  735 
  736         *unit = alloc_unr(ifc->ifc_unrhdr);
  737         if (*unit == -1)
  738                 return (ENOSPC);
  739 
  740         free_unr(ifc->ifc_unrhdr, *unit);
  741         for (;;) {
  742                 error = ifc_alloc_unit_specific(ifc, unit);
  743                 if (error != EEXIST)
  744                         break;
  745 
  746                 (*unit)++;
  747         }
  748 
  749         return (error);
  750 }
  751 
  752 int
  753 ifc_alloc_unit(struct if_clone *ifc, int *unit)
  754 {
  755         if (*unit < 0)
  756                 return (ifc_alloc_unit_next(ifc, unit));
  757         else
  758                 return (ifc_alloc_unit_specific(ifc, unit));
  759 }
  760 
  761 void
  762 ifc_free_unit(struct if_clone *ifc, int unit)
  763 {
  764 
  765         free_unr(ifc->ifc_unrhdr, unit);
  766         IF_CLONE_REMREF(ifc);
  767 }
  768 
  769 static int
  770 ifc_simple_match(struct if_clone *ifc, const char *name)
  771 {
  772         const char *cp;
  773         int i;
  774 
  775         /* Match the name */
  776         for (cp = name, i = 0; i < strlen(ifc->ifc_name); i++, cp++) {
  777                 if (ifc->ifc_name[i] != *cp)
  778                         return (0);
  779         }
  780 
  781         /* Make sure there's a unit number or nothing after the name */
  782         for (; *cp != '\0'; cp++) {
  783                 if (*cp < '' || *cp > '9')
  784                         return (0);
  785         }
  786 
  787         return (1);
  788 }
  789 
  790 static int
  791 ifc_handle_unit(struct if_clone *ifc, char *name, size_t len, int *punit)
  792 {
  793         char *dp;
  794         int wildcard;
  795         int unit;
  796         int err;
  797 
  798         err = ifc_name2unit(name, &unit);
  799         if (err != 0)
  800                 return (err);
  801 
  802         wildcard = (unit < 0);
  803 
  804         err = ifc_alloc_unit(ifc, &unit);
  805         if (err != 0)
  806                 return (err);
  807 
  808         /* In the wildcard case, we need to update the name. */
  809         if (wildcard) {
  810                 for (dp = name; *dp != '\0'; dp++);
  811                 if (snprintf(dp, len - (dp-name), "%d", unit) >
  812                     len - (dp-name) - 1) {
  813                         /*
  814                          * This can only be a programmer error and
  815                          * there's no straightforward way to recover if
  816                          * it happens.
  817                          */
  818                         panic("if_clone_create(): interface name too long");
  819                 }
  820         }
  821         *punit = unit;
  822 
  823         return (0);
  824 }
  825 
  826 int
  827 ifc_copyin(const struct ifc_data *ifd, void *target, size_t len)
  828 {
  829         if (ifd->params == NULL)
  830                 return (EINVAL);
  831 
  832         if (ifd->flags & IFC_F_SYSSPACE) {
  833                 memcpy(target, ifd->params, len);
  834                 return (0);
  835         } else
  836                 return (copyin(ifd->params, target, len));
  837 }
  838 
  839 const char *
  840 ifc_name(struct if_clone *ifc)
  841 {
  842         return (ifc->ifc_name);
  843 }
  844 
  845 void
  846 ifc_flags_set(struct if_clone *ifc, int flags)
  847 {
  848         ifc->ifc_flags = flags;
  849 }
  850 
  851 int
  852 ifc_flags_get(struct if_clone *ifc)
  853 {
  854         return (ifc->ifc_flags);
  855 }

Cache object: 8ba6d207c366760b58cbd3152dd1d90b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.