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/dev/pci/pci_iov_schema.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  * Copyright (c) 2014-2015 Sandvine Inc.
    3  * 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  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: releng/11.2/sys/dev/pci/pci_iov_schema.c 296865 2016-03-14 17:41:17Z rstone $");
   29 
   30 #include <sys/param.h>
   31 #include <sys/conf.h>
   32 #include <sys/ctype.h>
   33 #include <sys/kernel.h>
   34 #include <sys/systm.h>
   35 #include <sys/iov.h>
   36 #include <sys/malloc.h>
   37 #include <sys/module.h>
   38 #include <sys/queue.h>
   39 
   40 #include <machine/stdarg.h>
   41 
   42 #include <sys/dnv.h>
   43 #include <sys/nv.h>
   44 #include <sys/iov_schema.h>
   45 
   46 #include <net/ethernet.h>
   47 
   48 #include <dev/pci/schema_private.h>
   49 
   50 struct config_type_validator;
   51 typedef int (validate_func)(const struct config_type_validator *,
   52    const nvlist_t *, const char *name);
   53 typedef int (default_validate_t)(const struct config_type_validator *,
   54    const nvlist_t *);
   55 
   56 static validate_func pci_iov_schema_validate_bool;
   57 static validate_func pci_iov_schema_validate_string;
   58 static validate_func pci_iov_schema_validate_uint;
   59 static validate_func pci_iov_schema_validate_unicast_mac;
   60 
   61 static default_validate_t pci_iov_validate_bool_default;
   62 static default_validate_t pci_iov_validate_string_default;
   63 static default_validate_t pci_iov_validate_uint_default;
   64 static default_validate_t pci_iov_validate_unicast_mac_default;
   65 
   66 struct config_type_validator {
   67         const char *type_name;
   68         validate_func *validate;
   69         default_validate_t *default_validate;
   70         uintmax_t limit;
   71 };
   72 
   73 static struct config_type_validator pci_iov_schema_validators[] = {
   74         {
   75                 .type_name = "bool",
   76                 .validate = pci_iov_schema_validate_bool,
   77                 .default_validate = pci_iov_validate_bool_default
   78         },
   79         {
   80                 .type_name = "string",
   81                 .validate = pci_iov_schema_validate_string,
   82                 .default_validate = pci_iov_validate_string_default
   83         },
   84         {
   85                 .type_name = "uint8_t",
   86                 .validate = pci_iov_schema_validate_uint,
   87                 .default_validate = pci_iov_validate_uint_default,
   88                 .limit = UINT8_MAX
   89         },
   90         {
   91                 .type_name = "uint16_t",
   92                 .validate = pci_iov_schema_validate_uint,
   93                 .default_validate = pci_iov_validate_uint_default,
   94                 .limit = UINT16_MAX
   95         },
   96         {
   97                 .type_name = "uint32_t",
   98                 .validate = pci_iov_schema_validate_uint,
   99                 .default_validate = pci_iov_validate_uint_default,
  100                 .limit = UINT32_MAX
  101         },
  102         {
  103                 .type_name = "uint64_t",
  104                 .validate = pci_iov_schema_validate_uint,
  105                 .default_validate = pci_iov_validate_uint_default,
  106                 .limit = UINT64_MAX
  107         },
  108         {
  109                 .type_name = "unicast-mac",
  110                 .validate = pci_iov_schema_validate_unicast_mac,
  111                 .default_validate = pci_iov_validate_unicast_mac_default,
  112         },
  113 };
  114 
  115 static const struct config_type_validator *
  116 pci_iov_schema_find_validator(const char *type)
  117 {
  118         struct config_type_validator *validator;
  119         int i;
  120 
  121         for (i = 0; i < nitems(pci_iov_schema_validators); i++) {
  122                 validator = &pci_iov_schema_validators[i];
  123                 if (strcmp(type, validator->type_name) == 0)
  124                         return (validator);
  125         }
  126 
  127         return (NULL);
  128 }
  129 
  130 static void
  131 pci_iov_schema_add_type(nvlist_t *entry, const char *type)
  132 {
  133 
  134         if (pci_iov_schema_find_validator(type) == NULL) {
  135                 nvlist_set_error(entry, EINVAL);
  136                 return;
  137         }
  138         nvlist_add_string(entry, "type", type);
  139 }
  140 
  141 static void
  142 pci_iov_schema_add_required(nvlist_t *entry, uint32_t flags)
  143 {
  144 
  145         if (flags & IOV_SCHEMA_REQUIRED) {
  146                 if (flags & IOV_SCHEMA_HASDEFAULT) {
  147                         nvlist_set_error(entry, EINVAL);
  148                         return;
  149                 }
  150 
  151                 nvlist_add_bool(entry, "required", 1);
  152         }
  153 }
  154 
  155 void
  156 pci_iov_schema_add_bool(nvlist_t *schema, const char *name, uint32_t flags,
  157     int defaultVal)
  158 {
  159         nvlist_t *entry;
  160 
  161         entry = nvlist_create(NV_FLAG_IGNORE_CASE);
  162         if (entry == NULL) {
  163                 nvlist_set_error(schema, ENOMEM);
  164                 return;
  165         }
  166 
  167         pci_iov_schema_add_type(entry, "bool");
  168         if (flags & IOV_SCHEMA_HASDEFAULT)
  169                 nvlist_add_bool(entry, "default", defaultVal);
  170         pci_iov_schema_add_required(entry, flags);
  171 
  172         nvlist_move_nvlist(schema, name, entry);
  173 }
  174 
  175 void
  176 pci_iov_schema_add_string(nvlist_t *schema, const char *name, uint32_t flags,
  177     const char *defaultVal)
  178 {
  179         nvlist_t *entry;
  180 
  181         entry = nvlist_create(NV_FLAG_IGNORE_CASE);
  182         if (entry == NULL) {
  183                 nvlist_set_error(schema, ENOMEM);
  184                 return;
  185         }
  186 
  187         pci_iov_schema_add_type(entry, "string");
  188         if (flags & IOV_SCHEMA_HASDEFAULT)
  189                 nvlist_add_string(entry, "default", defaultVal);
  190         pci_iov_schema_add_required(entry, flags);
  191 
  192         nvlist_move_nvlist(schema, name, entry);
  193 }
  194 
  195 static void
  196 pci_iov_schema_int(nvlist_t *schema, const char *name, const char *type,
  197     uint32_t flags, uint64_t defaultVal)
  198 {
  199         nvlist_t *entry;
  200 
  201         entry = nvlist_create(NV_FLAG_IGNORE_CASE);
  202         if (entry == NULL) {
  203                 nvlist_set_error(schema, ENOMEM);
  204                 return;
  205         }
  206 
  207         pci_iov_schema_add_type(entry, type);
  208         if (flags & IOV_SCHEMA_HASDEFAULT)
  209                 nvlist_add_number(entry, "default", defaultVal);
  210         pci_iov_schema_add_required(entry, flags);
  211 
  212         nvlist_move_nvlist(schema, name, entry);
  213 }
  214 
  215 void
  216 pci_iov_schema_add_uint8(nvlist_t *schema, const char *name, uint32_t flags,
  217     uint8_t defaultVal)
  218 {
  219 
  220         pci_iov_schema_int(schema, name, "uint8_t", flags, defaultVal);
  221 }
  222 
  223 void
  224 pci_iov_schema_add_uint16(nvlist_t *schema, const char *name, uint32_t flags,
  225     uint16_t defaultVal)
  226 {
  227 
  228         pci_iov_schema_int(schema, name, "uint16_t", flags, defaultVal);
  229 }
  230 
  231 void
  232 pci_iov_schema_add_uint32(nvlist_t *schema, const char *name, uint32_t flags,
  233     uint32_t defaultVal)
  234 {
  235 
  236         pci_iov_schema_int(schema, name, "uint32_t", flags, defaultVal);
  237 }
  238 
  239 void
  240 pci_iov_schema_add_uint64(nvlist_t *schema, const char *name, uint32_t flags,
  241     uint64_t defaultVal)
  242 {
  243 
  244         pci_iov_schema_int(schema, name, "uint64_t", flags, defaultVal);
  245 }
  246 
  247 void
  248 pci_iov_schema_add_unicast_mac(nvlist_t *schema, const char *name,
  249     uint32_t flags, const uint8_t * defaultVal)
  250 {
  251         nvlist_t *entry;
  252 
  253         entry = nvlist_create(NV_FLAG_IGNORE_CASE);
  254         if (entry == NULL) {
  255                 nvlist_set_error(schema, ENOMEM);
  256                 return;
  257         }
  258 
  259         pci_iov_schema_add_type(entry, "unicast-mac");
  260         if (flags & IOV_SCHEMA_HASDEFAULT)
  261                 nvlist_add_binary(entry, "default", defaultVal, ETHER_ADDR_LEN);
  262         pci_iov_schema_add_required(entry, flags);
  263 
  264         nvlist_move_nvlist(schema, name, entry);
  265 }
  266 
  267 static int
  268 pci_iov_schema_validate_bool(const struct config_type_validator * validator,
  269    const nvlist_t *config, const char *name)
  270 {
  271 
  272         if (!nvlist_exists_bool(config, name))
  273                 return (EINVAL);
  274         return (0);
  275 }
  276 
  277 static int
  278 pci_iov_schema_validate_string(const struct config_type_validator * validator,
  279    const nvlist_t *config, const char *name)
  280 {
  281 
  282         if (!nvlist_exists_string(config, name))
  283                 return (EINVAL);
  284         return (0);
  285 }
  286 
  287 static int
  288 pci_iov_schema_validate_uint(const struct config_type_validator * validator,
  289    const nvlist_t *config, const char *name)
  290 {
  291         uint64_t value;
  292 
  293         if (!nvlist_exists_number(config, name))
  294                 return (EINVAL);
  295 
  296         value = nvlist_get_number(config, name);
  297 
  298         if (value > validator->limit)
  299                 return (EINVAL);
  300 
  301         return (0);
  302 }
  303 
  304 static int
  305 pci_iov_schema_validate_unicast_mac(
  306    const struct config_type_validator * validator,
  307    const nvlist_t *config, const char *name)
  308 {
  309         const uint8_t *mac;
  310         size_t size;
  311 
  312         if (!nvlist_exists_binary(config, name))
  313                 return (EINVAL);
  314 
  315         mac = nvlist_get_binary(config, name, &size);
  316 
  317         if (size != ETHER_ADDR_LEN)
  318                 return (EINVAL);
  319 
  320         if (ETHER_IS_MULTICAST(mac))
  321                 return (EINVAL);
  322 
  323         return (0);
  324 }
  325 
  326 static void
  327 pci_iov_config_add_default(const nvlist_t *param_schema, const char *name,
  328     nvlist_t *config)
  329 {
  330         const void *binary;
  331         size_t len;
  332 
  333         if (nvlist_exists_binary(param_schema, "default")) {
  334                 binary = nvlist_get_binary(param_schema, "default", &len);
  335                 nvlist_add_binary(config, name, binary, len);
  336         } else if (nvlist_exists_bool(param_schema, "default"))
  337                 nvlist_add_bool(config, name,
  338                     nvlist_get_bool(param_schema, "default"));
  339         else if (nvlist_exists_number(param_schema, "default"))
  340                 nvlist_add_number(config, name,
  341                     nvlist_get_number(param_schema, "default"));
  342         else if (nvlist_exists_nvlist(param_schema, "default"))
  343                 nvlist_add_nvlist(config, name,
  344                     nvlist_get_nvlist(param_schema, "default"));
  345         else if (nvlist_exists_string(param_schema, "default"))
  346                 nvlist_add_string(config, name,
  347                     nvlist_get_string(param_schema, "default"));
  348         else
  349                 panic("Unexpected nvlist type");
  350 }
  351 
  352 static int
  353 pci_iov_validate_bool_default(const struct config_type_validator * validator,
  354    const nvlist_t *param)
  355 {
  356 
  357         if (!nvlist_exists_bool(param, DEFAULT_SCHEMA_NAME))
  358                 return (EINVAL);
  359         return (0);
  360 }
  361 
  362 static int
  363 pci_iov_validate_string_default(const struct config_type_validator * validator,
  364    const nvlist_t *param)
  365 {
  366 
  367         if (!nvlist_exists_string(param, DEFAULT_SCHEMA_NAME))
  368                 return (EINVAL);
  369         return (0);
  370 }
  371 
  372 static int
  373 pci_iov_validate_uint_default(const struct config_type_validator * validator,
  374    const nvlist_t *param)
  375 {
  376         uint64_t defaultVal;
  377 
  378         if (!nvlist_exists_number(param, DEFAULT_SCHEMA_NAME))
  379                 return (EINVAL);
  380 
  381         defaultVal = nvlist_get_number(param, DEFAULT_SCHEMA_NAME);
  382         if (defaultVal > validator->limit)
  383                 return (EINVAL);
  384         return (0);
  385 }
  386 
  387 static int
  388 pci_iov_validate_unicast_mac_default(
  389    const struct config_type_validator * validator, const nvlist_t *param)
  390 {
  391         const uint8_t *mac;
  392         size_t size;
  393 
  394         if (!nvlist_exists_binary(param, DEFAULT_SCHEMA_NAME))
  395                 return (EINVAL);
  396 
  397         mac = nvlist_get_binary(param, DEFAULT_SCHEMA_NAME, &size);
  398         if (size != ETHER_ADDR_LEN)
  399                 return (EINVAL);
  400 
  401         if (ETHER_IS_MULTICAST(mac))
  402                 return (EINVAL);
  403         return (0);
  404 }
  405 
  406 static int
  407 pci_iov_validate_param_schema(const nvlist_t *schema)
  408 {
  409         const struct config_type_validator *validator;
  410         const char *type;
  411         int error;
  412 
  413         /* All parameters must define a type. */
  414         if (!nvlist_exists_string(schema, TYPE_SCHEMA_NAME))
  415                 return (EINVAL);
  416         type = nvlist_get_string(schema, TYPE_SCHEMA_NAME);
  417 
  418         validator = pci_iov_schema_find_validator(type);
  419         if (validator == NULL)
  420                 return (EINVAL);
  421 
  422         /* Validate that the default value conforms to the type. */
  423         if (nvlist_exists(schema, DEFAULT_SCHEMA_NAME)) {
  424                 error = validator->default_validate(validator, schema);
  425                 if (error != 0)
  426                         return (error);
  427 
  428                 /* Required and Default are mutually exclusive. */
  429                 if (nvlist_exists(schema, REQUIRED_SCHEMA_NAME))
  430                         return (EINVAL);
  431         }
  432 
  433         /* The "Required" field must be a bool. */
  434         if (nvlist_exists(schema, REQUIRED_SCHEMA_NAME)) {
  435                 if (!nvlist_exists_bool(schema, REQUIRED_SCHEMA_NAME))
  436                         return (EINVAL);
  437         }
  438 
  439         return (0);
  440 }
  441 
  442 static int
  443 pci_iov_validate_subsystem_schema(const nvlist_t *dev_schema, const char *name)
  444 {
  445         const nvlist_t *sub_schema, *param_schema;
  446         const char *param_name;
  447         void *it;
  448         int type, error;
  449 
  450         if (!nvlist_exists_nvlist(dev_schema, name))
  451                 return (EINVAL);
  452         sub_schema = nvlist_get_nvlist(dev_schema, name);
  453 
  454         it = NULL;
  455         while ((param_name = nvlist_next(sub_schema, &type, &it)) != NULL) {
  456                 if (type != NV_TYPE_NVLIST)
  457                         return (EINVAL);
  458                 param_schema = nvlist_get_nvlist(sub_schema, param_name);
  459 
  460                 error = pci_iov_validate_param_schema(param_schema);
  461                 if (error != 0)
  462                         return (error);
  463         }
  464 
  465         return (0);
  466 }
  467 
  468 /*
  469  * Validate that the driver schema does not define any configuration parameters
  470  * whose names collide with configuration parameters defined in the iov schema.
  471  */
  472 static int
  473 pci_iov_validate_param_collisions(const nvlist_t *dev_schema)
  474 {
  475         const nvlist_t *iov_schema, *driver_schema;
  476         const char *name;
  477         void *it;
  478         int type;
  479 
  480         driver_schema = nvlist_get_nvlist(dev_schema, DRIVER_CONFIG_NAME);
  481         iov_schema = nvlist_get_nvlist(dev_schema, IOV_CONFIG_NAME);
  482 
  483         it = NULL;
  484         while ((name = nvlist_next(driver_schema, &type, &it)) != NULL) {
  485                 if (nvlist_exists(iov_schema, name))
  486                         return (EINVAL);
  487         }
  488 
  489         return (0);
  490 }
  491 
  492 /*
  493  * Validate that we only have IOV and DRIVER subsystems beneath the given
  494  * device schema node.
  495  */
  496 static int
  497 pci_iov_validate_schema_subsystems(const nvlist_t *dev_schema)
  498 {
  499         const char *name;
  500         void *it;
  501         int type;
  502 
  503         it = NULL;
  504         while ((name = nvlist_next(dev_schema, &type, &it)) != NULL) {
  505                 if (strcmp(name, IOV_CONFIG_NAME) != 0 &&
  506                     strcmp(name, DRIVER_CONFIG_NAME) != 0)
  507                         return (EINVAL);
  508         }
  509 
  510         return (0);
  511 }
  512 
  513 static int
  514 pci_iov_validate_device_schema(const nvlist_t *schema, const char *name)
  515 {
  516         const nvlist_t *dev_schema;
  517         int error;
  518 
  519         if (!nvlist_exists_nvlist(schema, name))
  520                 return (EINVAL);
  521         dev_schema = nvlist_get_nvlist(schema, name);
  522 
  523         error = pci_iov_validate_subsystem_schema(dev_schema, IOV_CONFIG_NAME);
  524         if (error != 0)
  525                 return (error);
  526 
  527         error = pci_iov_validate_subsystem_schema(dev_schema,
  528             DRIVER_CONFIG_NAME);
  529         if (error != 0)
  530                 return (error);
  531 
  532         error = pci_iov_validate_param_collisions(dev_schema);
  533         if (error != 0)
  534                 return (error);
  535 
  536         return (pci_iov_validate_schema_subsystems(dev_schema));
  537 }
  538 
  539 /* Validate that we only have PF and VF devices beneath the top-level schema. */
  540 static int
  541 pci_iov_validate_schema_devices(const nvlist_t *dev_schema)
  542 {
  543         const char *name;
  544         void *it;
  545         int type;
  546 
  547         it = NULL;
  548         while ((name = nvlist_next(dev_schema, &type, &it)) != NULL) {
  549                 if (strcmp(name, PF_CONFIG_NAME) != 0 &&
  550                     strcmp(name, VF_SCHEMA_NAME) != 0)
  551                         return (EINVAL);
  552         }
  553 
  554         return (0);
  555 }
  556 
  557 int
  558 pci_iov_validate_schema(const nvlist_t *schema)
  559 {
  560         int error;
  561 
  562         error = pci_iov_validate_device_schema(schema, PF_CONFIG_NAME);
  563         if (error != 0)
  564                 return (error);
  565 
  566         error = pci_iov_validate_device_schema(schema, VF_SCHEMA_NAME);
  567         if (error != 0)
  568                 return (error);
  569 
  570         return (pci_iov_validate_schema_devices(schema));
  571 }
  572 
  573 /*
  574  * Validate that all required parameters from the schema are specified in the
  575  * config.  If any parameter with a default value is not specified in the
  576  * config, add it to config.
  577  */
  578 static int
  579 pci_iov_schema_validate_required(const nvlist_t *schema, nvlist_t *config)
  580 {
  581         const nvlist_t *param_schema;
  582         const char *name;
  583         void *cookie;
  584         int type;
  585 
  586         cookie = NULL;
  587         while ((name = nvlist_next(schema, &type, &cookie)) != NULL) {
  588                 param_schema = nvlist_get_nvlist(schema, name);
  589 
  590                 if (dnvlist_get_bool(param_schema, "required", 0)) {
  591                         if (!nvlist_exists(config, name))
  592                                 return (EINVAL);
  593                 }
  594 
  595                 if (nvlist_exists(param_schema, "default") &&
  596                     !nvlist_exists(config, name))
  597                         pci_iov_config_add_default(param_schema, name, config);
  598         }
  599 
  600         return (nvlist_error(config));
  601 }
  602 
  603 static int
  604 pci_iov_schema_validate_param(const nvlist_t *schema_param, const char *name,
  605     const nvlist_t *config)
  606 {
  607         const struct config_type_validator *validator;
  608         const char *type;
  609 
  610         type = nvlist_get_string(schema_param, "type");
  611         validator = pci_iov_schema_find_validator(type);
  612 
  613         KASSERT(validator != NULL,
  614             ("Schema was not validated: Unknown type %s", type));
  615 
  616         return (validator->validate(validator, config, name));
  617 }
  618 
  619 /*
  620  * Validate that all parameters in config are defined in the schema.  Also
  621  * validate that the type of the parameter matches the type in the schema.
  622  */
  623 static int
  624 pci_iov_schema_validate_types(const nvlist_t *schema, const nvlist_t *config)
  625 {
  626         const nvlist_t *schema_param;
  627         void *cookie;
  628         const char *name;
  629         int type, error;
  630 
  631         cookie = NULL;
  632         while ((name = nvlist_next(config, &type, &cookie)) != NULL) {
  633                 if (!nvlist_exists_nvlist(schema, name))
  634                         return (EINVAL);
  635 
  636                 schema_param = nvlist_get_nvlist(schema, name);
  637 
  638                 error = pci_iov_schema_validate_param(schema_param, name,
  639                     config);
  640 
  641                 if (error != 0)
  642                         return (error);
  643         }
  644 
  645         return (0);
  646 }
  647 
  648 static int
  649 pci_iov_schema_validate_device(const nvlist_t *schema, nvlist_t *config,
  650     const char *schema_device, const char *config_device)
  651 {
  652         const nvlist_t *device_schema, *iov_schema, *driver_schema;
  653         nvlist_t *device_config, *iov_config, *driver_config;
  654         int error;
  655 
  656         device_config = NULL;
  657         iov_config = NULL;
  658         driver_config = NULL;
  659 
  660         device_schema = nvlist_get_nvlist(schema, schema_device);
  661         iov_schema = nvlist_get_nvlist(device_schema, IOV_CONFIG_NAME);
  662         driver_schema = nvlist_get_nvlist(device_schema, DRIVER_CONFIG_NAME);
  663 
  664         device_config = dnvlist_take_nvlist(config, config_device, NULL);
  665         if (device_config == NULL) {
  666                 error = EINVAL;
  667                 goto out;
  668         }
  669 
  670         iov_config = dnvlist_take_nvlist(device_config, IOV_CONFIG_NAME, NULL);
  671         if (iov_config == NULL) {
  672                 error = EINVAL;
  673                 goto out;
  674         }
  675 
  676         driver_config = dnvlist_take_nvlist(device_config, DRIVER_CONFIG_NAME,
  677             NULL);
  678         if (driver_config == NULL) {
  679                 error = EINVAL;
  680                 goto out;
  681         }
  682 
  683         error = pci_iov_schema_validate_required(iov_schema, iov_config);
  684         if (error != 0)
  685                 goto out;
  686 
  687         error = pci_iov_schema_validate_required(driver_schema, driver_config);
  688         if (error != 0)
  689                 goto out;
  690 
  691         error = pci_iov_schema_validate_types(iov_schema, iov_config);
  692         if (error != 0)
  693                 goto out;
  694 
  695         error = pci_iov_schema_validate_types(driver_schema, driver_config);
  696         if (error != 0)
  697                 goto out;
  698 
  699 out:
  700         /* Note that these functions handle NULL pointers safely. */
  701         nvlist_move_nvlist(device_config, IOV_CONFIG_NAME, iov_config);
  702         nvlist_move_nvlist(device_config, DRIVER_CONFIG_NAME, driver_config);
  703         nvlist_move_nvlist(config, config_device, device_config);
  704 
  705         return (error);
  706 }
  707 
  708 static int
  709 pci_iov_schema_validate_vfs(const nvlist_t *schema, nvlist_t *config,
  710     uint16_t num_vfs)
  711 {
  712         char device[VF_MAX_NAME];
  713         int i, error;
  714 
  715         for (i = 0; i < num_vfs; i++) {
  716                 snprintf(device, sizeof(device), VF_PREFIX"%d", i);
  717 
  718                 error = pci_iov_schema_validate_device(schema, config,
  719                     VF_SCHEMA_NAME, device);
  720                 if (error != 0)
  721                         return (error);
  722         }
  723 
  724         return (0);
  725 }
  726 
  727 /*
  728  * Validate that the device node only has IOV and DRIVER subnodes.
  729  */
  730 static int
  731 pci_iov_schema_validate_device_subsystems(const nvlist_t *config)
  732 {
  733         void *cookie;
  734         const char *name;
  735         int type;
  736 
  737         cookie = NULL;
  738         while ((name = nvlist_next(config, &type, &cookie)) != NULL) {
  739                 if (strcasecmp(name, IOV_CONFIG_NAME) == 0)
  740                         continue;
  741                 else if (strcasecmp(name, DRIVER_CONFIG_NAME) == 0)
  742                         continue;
  743 
  744                 return (EINVAL);
  745         }
  746 
  747         return (0);
  748 }
  749 
  750 /*
  751  * Validate that the string is a valid device node name.  It must either be "PF"
  752  * or "VF-n", where n is an integer in the range [0, num_vfs).
  753  */
  754 static int
  755 pci_iov_schema_validate_dev_name(const char *name, uint16_t num_vfs)
  756 {
  757         const char *number_start;
  758         char *endp;
  759         u_long vf_num;
  760 
  761         if (strcasecmp(PF_CONFIG_NAME, name) == 0)
  762                 return (0);
  763 
  764         /* Ensure that we start with "VF-" */
  765         if (strncasecmp(name, VF_PREFIX, VF_PREFIX_LEN) != 0)
  766                 return (EINVAL);
  767 
  768         number_start = name + VF_PREFIX_LEN;
  769 
  770         /* Filter out name == "VF-" (no number) */
  771         if (number_start[0] == '\0')
  772                 return (EINVAL);
  773 
  774         /* Disallow leading whitespace or +/- */
  775         if (!isdigit(number_start[0]))
  776                 return (EINVAL);
  777 
  778         vf_num = strtoul(number_start, &endp, 10);
  779         if (*endp != '\0')
  780                 return (EINVAL);
  781 
  782         /* Disallow leading zeros on VF-[1-9][0-9]* */
  783         if (vf_num != 0 && number_start[0] == '')
  784                 return (EINVAL);
  785 
  786         /* Disallow leading zeros on VF-0 */
  787         if (vf_num == 0 && number_start[1] != '\0')
  788                 return (EINVAL);
  789 
  790         if (vf_num >= num_vfs)
  791                 return (EINVAL);
  792 
  793         return (0);
  794 }
  795 
  796 /*
  797  * Validate that there are no device nodes in config other than the ones for
  798  * the PF and the VFs.  This includes validating that all config nodes of the
  799  * form VF-n specify a VF number that is < num_vfs.
  800  */
  801 static int
  802 pci_iov_schema_validate_device_names(const nvlist_t *config, uint16_t num_vfs)
  803 {
  804         const nvlist_t *device;
  805         void *cookie;
  806         const char *name;
  807         int type, error;
  808 
  809         cookie = NULL;
  810         while ((name = nvlist_next(config, &type, &cookie)) != NULL) {
  811                 error = pci_iov_schema_validate_dev_name(name, num_vfs);
  812                 if (error != 0)
  813                         return (error);
  814 
  815                 /*
  816                  * Note that as this is a valid PF/VF node, we know that
  817                  * pci_iov_schema_validate_device() has already checked that
  818                  * the PF/VF node is an nvlist.
  819                  */
  820                 device = nvlist_get_nvlist(config, name);
  821                 error = pci_iov_schema_validate_device_subsystems(device);
  822                 if (error != 0)
  823                         return (error);
  824         }
  825 
  826         return (0);
  827 }
  828 
  829 int
  830 pci_iov_schema_validate_config(const nvlist_t *schema, nvlist_t *config)
  831 {
  832         int error;
  833         uint16_t num_vfs;
  834 
  835         error = pci_iov_schema_validate_device(schema, config, PF_CONFIG_NAME,
  836             PF_CONFIG_NAME);
  837         if (error != 0)
  838                 return (error);
  839 
  840         num_vfs = pci_iov_config_get_num_vfs(config);
  841 
  842         error = pci_iov_schema_validate_vfs(schema, config, num_vfs);
  843         if (error != 0)
  844                 return (error);
  845 
  846         return (pci_iov_schema_validate_device_names(config, num_vfs));
  847 }
  848 
  849 /*
  850  * Return value of the num_vfs parameter.  config must have already been
  851  * validated, which guarantees that the parameter exists.
  852  */
  853 uint16_t
  854 pci_iov_config_get_num_vfs(const nvlist_t *config)
  855 {
  856         const nvlist_t *pf, *iov;
  857 
  858         pf = nvlist_get_nvlist(config, PF_CONFIG_NAME);
  859         iov = nvlist_get_nvlist(pf, IOV_CONFIG_NAME);
  860         return (nvlist_get_number(iov, "num_vfs"));
  861 }
  862 
  863 /* Allocate a new empty schema node. */
  864 nvlist_t *
  865 pci_iov_schema_alloc_node(void)
  866 {
  867 
  868         return (nvlist_create(NV_FLAG_IGNORE_CASE));
  869 }

Cache object: 7c61c9de26a872cc1ebf3b249fe093fc


[ 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.