11191f715SRyan Stone /*- 2faf139ccSRyan Stone * Copyright (c) 2014-2015 Sandvine Inc. 31191f715SRyan Stone * All rights reserved. 41191f715SRyan Stone * 51191f715SRyan Stone * Redistribution and use in source and binary forms, with or without 61191f715SRyan Stone * modification, are permitted provided that the following conditions 71191f715SRyan Stone * are met: 81191f715SRyan Stone * 1. Redistributions of source code must retain the above copyright 91191f715SRyan Stone * notice, this list of conditions and the following disclaimer. 101191f715SRyan Stone * 2. Redistributions in binary form must reproduce the above copyright 111191f715SRyan Stone * notice, this list of conditions and the following disclaimer in the 121191f715SRyan Stone * documentation and/or other materials provided with the distribution. 131191f715SRyan Stone * 141191f715SRyan Stone * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 151191f715SRyan Stone * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 161191f715SRyan Stone * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 171191f715SRyan Stone * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 181191f715SRyan Stone * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 191191f715SRyan Stone * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 201191f715SRyan Stone * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 211191f715SRyan Stone * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 221191f715SRyan Stone * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 231191f715SRyan Stone * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 241191f715SRyan Stone * SUCH DAMAGE. 251191f715SRyan Stone */ 261191f715SRyan Stone 271191f715SRyan Stone #include <sys/param.h> 281191f715SRyan Stone #include <sys/conf.h> 293c22f215SRyan Stone #include <sys/ctype.h> 301191f715SRyan Stone #include <sys/kernel.h> 311191f715SRyan Stone #include <sys/systm.h> 323c22f215SRyan Stone #include <sys/iov.h> 331191f715SRyan Stone #include <sys/malloc.h> 341191f715SRyan Stone #include <sys/module.h> 351191f715SRyan Stone #include <sys/queue.h> 361191f715SRyan Stone 371191f715SRyan Stone #include <machine/stdarg.h> 381191f715SRyan Stone 393c22f215SRyan Stone #include <sys/dnv.h> 401191f715SRyan Stone #include <sys/nv.h> 411191f715SRyan Stone #include <sys/iov_schema.h> 421191f715SRyan Stone 433c22f215SRyan Stone #include <net/ethernet.h> 443c22f215SRyan Stone 451191f715SRyan Stone #include <dev/pci/schema_private.h> 461191f715SRyan Stone 473c22f215SRyan Stone struct config_type_validator; 483c22f215SRyan Stone typedef int (validate_func)(const struct config_type_validator *, 493c22f215SRyan Stone const nvlist_t *, const char *name); 50bdc48af2SRyan Stone typedef int (default_validate_t)(const struct config_type_validator *, 51bdc48af2SRyan Stone const nvlist_t *); 523c22f215SRyan Stone 533c22f215SRyan Stone static validate_func pci_iov_schema_validate_bool; 543c22f215SRyan Stone static validate_func pci_iov_schema_validate_string; 553c22f215SRyan Stone static validate_func pci_iov_schema_validate_uint; 563c22f215SRyan Stone static validate_func pci_iov_schema_validate_unicast_mac; 57*c57c2617SKristof Provost static validate_func pci_iov_schema_validate_vlan; 583c22f215SRyan Stone 59bdc48af2SRyan Stone static default_validate_t pci_iov_validate_bool_default; 60bdc48af2SRyan Stone static default_validate_t pci_iov_validate_string_default; 61bdc48af2SRyan Stone static default_validate_t pci_iov_validate_uint_default; 62bdc48af2SRyan Stone static default_validate_t pci_iov_validate_unicast_mac_default; 63*c57c2617SKristof Provost static default_validate_t pci_iov_validate_vlan_default; 64bdc48af2SRyan Stone 653c22f215SRyan Stone struct config_type_validator { 663c22f215SRyan Stone const char *type_name; 673c22f215SRyan Stone validate_func *validate; 68bdc48af2SRyan Stone default_validate_t *default_validate; 693c22f215SRyan Stone uintmax_t limit; 701191f715SRyan Stone }; 711191f715SRyan Stone 723c22f215SRyan Stone static struct config_type_validator pci_iov_schema_validators[] = { 73bdc48af2SRyan Stone { 74bdc48af2SRyan Stone .type_name = "bool", 75bdc48af2SRyan Stone .validate = pci_iov_schema_validate_bool, 76bdc48af2SRyan Stone .default_validate = pci_iov_validate_bool_default 77bdc48af2SRyan Stone }, 78bdc48af2SRyan Stone { 79bdc48af2SRyan Stone .type_name = "string", 80bdc48af2SRyan Stone .validate = pci_iov_schema_validate_string, 81bdc48af2SRyan Stone .default_validate = pci_iov_validate_string_default 82bdc48af2SRyan Stone }, 83bdc48af2SRyan Stone { 84bdc48af2SRyan Stone .type_name = "uint8_t", 85bdc48af2SRyan Stone .validate = pci_iov_schema_validate_uint, 86bdc48af2SRyan Stone .default_validate = pci_iov_validate_uint_default, 87bdc48af2SRyan Stone .limit = UINT8_MAX 88bdc48af2SRyan Stone }, 89bdc48af2SRyan Stone { 90bdc48af2SRyan Stone .type_name = "uint16_t", 91bdc48af2SRyan Stone .validate = pci_iov_schema_validate_uint, 92bdc48af2SRyan Stone .default_validate = pci_iov_validate_uint_default, 93bdc48af2SRyan Stone .limit = UINT16_MAX 94bdc48af2SRyan Stone }, 95bdc48af2SRyan Stone { 96bdc48af2SRyan Stone .type_name = "uint32_t", 97bdc48af2SRyan Stone .validate = pci_iov_schema_validate_uint, 98bdc48af2SRyan Stone .default_validate = pci_iov_validate_uint_default, 99bdc48af2SRyan Stone .limit = UINT32_MAX 100bdc48af2SRyan Stone }, 101bdc48af2SRyan Stone { 102bdc48af2SRyan Stone .type_name = "uint64_t", 103bdc48af2SRyan Stone .validate = pci_iov_schema_validate_uint, 104bdc48af2SRyan Stone .default_validate = pci_iov_validate_uint_default, 105bdc48af2SRyan Stone .limit = UINT64_MAX 106bdc48af2SRyan Stone }, 107bdc48af2SRyan Stone { 108bdc48af2SRyan Stone .type_name = "unicast-mac", 109bdc48af2SRyan Stone .validate = pci_iov_schema_validate_unicast_mac, 110bdc48af2SRyan Stone .default_validate = pci_iov_validate_unicast_mac_default, 111bdc48af2SRyan Stone }, 112*c57c2617SKristof Provost { 113*c57c2617SKristof Provost .type_name = "vlan", 114*c57c2617SKristof Provost .validate = pci_iov_schema_validate_vlan, 115*c57c2617SKristof Provost .default_validate = pci_iov_validate_vlan_default, 116*c57c2617SKristof Provost }, 1173c22f215SRyan Stone }; 1183c22f215SRyan Stone 1193c22f215SRyan Stone static const struct config_type_validator * 1203c22f215SRyan Stone pci_iov_schema_find_validator(const char *type) 1213c22f215SRyan Stone { 1223c22f215SRyan Stone struct config_type_validator *validator; 1233c22f215SRyan Stone int i; 1243c22f215SRyan Stone 1253c22f215SRyan Stone for (i = 0; i < nitems(pci_iov_schema_validators); i++) { 1263c22f215SRyan Stone validator = &pci_iov_schema_validators[i]; 1273c22f215SRyan Stone if (strcmp(type, validator->type_name) == 0) 1283c22f215SRyan Stone return (validator); 1293c22f215SRyan Stone } 1303c22f215SRyan Stone 1313c22f215SRyan Stone return (NULL); 1323c22f215SRyan Stone } 1333c22f215SRyan Stone 1341191f715SRyan Stone static void 1351191f715SRyan Stone pci_iov_schema_add_type(nvlist_t *entry, const char *type) 1361191f715SRyan Stone { 1371191f715SRyan Stone 1383c22f215SRyan Stone if (pci_iov_schema_find_validator(type) == NULL) { 1393c22f215SRyan Stone nvlist_set_error(entry, EINVAL); 1401191f715SRyan Stone return; 1411191f715SRyan Stone } 1421191f715SRyan Stone nvlist_add_string(entry, "type", type); 1431191f715SRyan Stone } 1441191f715SRyan Stone 1451191f715SRyan Stone static void 1461191f715SRyan Stone pci_iov_schema_add_required(nvlist_t *entry, uint32_t flags) 1471191f715SRyan Stone { 1481191f715SRyan Stone 1491191f715SRyan Stone if (flags & IOV_SCHEMA_REQUIRED) { 1501191f715SRyan Stone if (flags & IOV_SCHEMA_HASDEFAULT) { 1511191f715SRyan Stone nvlist_set_error(entry, EINVAL); 1521191f715SRyan Stone return; 1531191f715SRyan Stone } 1541191f715SRyan Stone 1551191f715SRyan Stone nvlist_add_bool(entry, "required", 1); 1561191f715SRyan Stone } 1571191f715SRyan Stone } 1581191f715SRyan Stone 1591191f715SRyan Stone void 1601191f715SRyan Stone pci_iov_schema_add_bool(nvlist_t *schema, const char *name, uint32_t flags, 1611191f715SRyan Stone int defaultVal) 1621191f715SRyan Stone { 1631191f715SRyan Stone nvlist_t *entry; 1641191f715SRyan Stone 1651191f715SRyan Stone entry = nvlist_create(NV_FLAG_IGNORE_CASE); 1661191f715SRyan Stone if (entry == NULL) { 1671191f715SRyan Stone nvlist_set_error(schema, ENOMEM); 1681191f715SRyan Stone return; 1691191f715SRyan Stone } 1701191f715SRyan Stone 1711191f715SRyan Stone pci_iov_schema_add_type(entry, "bool"); 1721191f715SRyan Stone if (flags & IOV_SCHEMA_HASDEFAULT) 1731191f715SRyan Stone nvlist_add_bool(entry, "default", defaultVal); 1741191f715SRyan Stone pci_iov_schema_add_required(entry, flags); 1751191f715SRyan Stone 1761191f715SRyan Stone nvlist_move_nvlist(schema, name, entry); 1771191f715SRyan Stone } 1781191f715SRyan Stone 1791191f715SRyan Stone void 1801191f715SRyan Stone pci_iov_schema_add_string(nvlist_t *schema, const char *name, uint32_t flags, 1811191f715SRyan Stone const char *defaultVal) 1821191f715SRyan Stone { 1831191f715SRyan Stone nvlist_t *entry; 1841191f715SRyan Stone 1851191f715SRyan Stone entry = nvlist_create(NV_FLAG_IGNORE_CASE); 1861191f715SRyan Stone if (entry == NULL) { 1871191f715SRyan Stone nvlist_set_error(schema, ENOMEM); 1881191f715SRyan Stone return; 1891191f715SRyan Stone } 1901191f715SRyan Stone 1911191f715SRyan Stone pci_iov_schema_add_type(entry, "string"); 1921191f715SRyan Stone if (flags & IOV_SCHEMA_HASDEFAULT) 1931191f715SRyan Stone nvlist_add_string(entry, "default", defaultVal); 1941191f715SRyan Stone pci_iov_schema_add_required(entry, flags); 1951191f715SRyan Stone 1961191f715SRyan Stone nvlist_move_nvlist(schema, name, entry); 1971191f715SRyan Stone } 1981191f715SRyan Stone 1991191f715SRyan Stone static void 2001191f715SRyan Stone pci_iov_schema_int(nvlist_t *schema, const char *name, const char *type, 2011191f715SRyan Stone uint32_t flags, uint64_t defaultVal) 2021191f715SRyan Stone { 2031191f715SRyan Stone nvlist_t *entry; 2041191f715SRyan Stone 2051191f715SRyan Stone entry = nvlist_create(NV_FLAG_IGNORE_CASE); 2061191f715SRyan Stone if (entry == NULL) { 2071191f715SRyan Stone nvlist_set_error(schema, ENOMEM); 2081191f715SRyan Stone return; 2091191f715SRyan Stone } 2101191f715SRyan Stone 2111191f715SRyan Stone pci_iov_schema_add_type(entry, type); 2121191f715SRyan Stone if (flags & IOV_SCHEMA_HASDEFAULT) 2131191f715SRyan Stone nvlist_add_number(entry, "default", defaultVal); 2141191f715SRyan Stone pci_iov_schema_add_required(entry, flags); 2151191f715SRyan Stone 2161191f715SRyan Stone nvlist_move_nvlist(schema, name, entry); 2171191f715SRyan Stone } 2181191f715SRyan Stone 2191191f715SRyan Stone void 2201191f715SRyan Stone pci_iov_schema_add_uint8(nvlist_t *schema, const char *name, uint32_t flags, 2211191f715SRyan Stone uint8_t defaultVal) 2221191f715SRyan Stone { 2231191f715SRyan Stone 2241191f715SRyan Stone pci_iov_schema_int(schema, name, "uint8_t", flags, defaultVal); 2251191f715SRyan Stone } 2261191f715SRyan Stone 2271191f715SRyan Stone void 2281191f715SRyan Stone pci_iov_schema_add_uint16(nvlist_t *schema, const char *name, uint32_t flags, 2291191f715SRyan Stone uint16_t defaultVal) 2301191f715SRyan Stone { 2311191f715SRyan Stone 2321191f715SRyan Stone pci_iov_schema_int(schema, name, "uint16_t", flags, defaultVal); 2331191f715SRyan Stone } 2341191f715SRyan Stone 2351191f715SRyan Stone void 2361191f715SRyan Stone pci_iov_schema_add_uint32(nvlist_t *schema, const char *name, uint32_t flags, 2371191f715SRyan Stone uint32_t defaultVal) 2381191f715SRyan Stone { 2391191f715SRyan Stone 2401191f715SRyan Stone pci_iov_schema_int(schema, name, "uint32_t", flags, defaultVal); 2411191f715SRyan Stone } 2421191f715SRyan Stone 2431191f715SRyan Stone void 2441191f715SRyan Stone pci_iov_schema_add_uint64(nvlist_t *schema, const char *name, uint32_t flags, 2451191f715SRyan Stone uint64_t defaultVal) 2461191f715SRyan Stone { 2471191f715SRyan Stone 2481191f715SRyan Stone pci_iov_schema_int(schema, name, "uint64_t", flags, defaultVal); 2491191f715SRyan Stone } 2501191f715SRyan Stone 2511191f715SRyan Stone void 2521191f715SRyan Stone pci_iov_schema_add_unicast_mac(nvlist_t *schema, const char *name, 2531191f715SRyan Stone uint32_t flags, const uint8_t * defaultVal) 2541191f715SRyan Stone { 2551191f715SRyan Stone nvlist_t *entry; 2561191f715SRyan Stone 2571191f715SRyan Stone entry = nvlist_create(NV_FLAG_IGNORE_CASE); 2581191f715SRyan Stone if (entry == NULL) { 2591191f715SRyan Stone nvlist_set_error(schema, ENOMEM); 2601191f715SRyan Stone return; 2611191f715SRyan Stone } 2621191f715SRyan Stone 2631191f715SRyan Stone pci_iov_schema_add_type(entry, "unicast-mac"); 2641191f715SRyan Stone if (flags & IOV_SCHEMA_HASDEFAULT) 2651191f715SRyan Stone nvlist_add_binary(entry, "default", defaultVal, ETHER_ADDR_LEN); 2661191f715SRyan Stone pci_iov_schema_add_required(entry, flags); 2671191f715SRyan Stone 2681191f715SRyan Stone nvlist_move_nvlist(schema, name, entry); 2691191f715SRyan Stone } 2701191f715SRyan Stone 271*c57c2617SKristof Provost void 272*c57c2617SKristof Provost pci_iov_schema_add_vlan(nvlist_t *schema, const char *name, 273*c57c2617SKristof Provost uint32_t flags, const uint16_t defaultVal) 274*c57c2617SKristof Provost { 275*c57c2617SKristof Provost nvlist_t *entry; 276*c57c2617SKristof Provost 277*c57c2617SKristof Provost entry = nvlist_create(NV_FLAG_IGNORE_CASE); 278*c57c2617SKristof Provost if (entry == NULL) { 279*c57c2617SKristof Provost nvlist_set_error(schema, ENOMEM); 280*c57c2617SKristof Provost return; 281*c57c2617SKristof Provost } 282*c57c2617SKristof Provost 283*c57c2617SKristof Provost pci_iov_schema_add_type(entry, "vlan"); 284*c57c2617SKristof Provost if (flags & IOV_SCHEMA_HASDEFAULT) 285*c57c2617SKristof Provost nvlist_add_number(entry, "default", defaultVal); 286*c57c2617SKristof Provost pci_iov_schema_add_required(entry, flags); 287*c57c2617SKristof Provost 288*c57c2617SKristof Provost nvlist_move_nvlist(schema, name, entry); 289*c57c2617SKristof Provost } 290*c57c2617SKristof Provost 2913c22f215SRyan Stone static int 2923c22f215SRyan Stone pci_iov_schema_validate_bool(const struct config_type_validator * validator, 2933c22f215SRyan Stone const nvlist_t *config, const char *name) 2943c22f215SRyan Stone { 2953c22f215SRyan Stone 2963c22f215SRyan Stone if (!nvlist_exists_bool(config, name)) 2973c22f215SRyan Stone return (EINVAL); 2983c22f215SRyan Stone return (0); 2993c22f215SRyan Stone } 3003c22f215SRyan Stone 3013c22f215SRyan Stone static int 3023c22f215SRyan Stone pci_iov_schema_validate_string(const struct config_type_validator * validator, 3033c22f215SRyan Stone const nvlist_t *config, const char *name) 3043c22f215SRyan Stone { 3053c22f215SRyan Stone 3063c22f215SRyan Stone if (!nvlist_exists_string(config, name)) 3073c22f215SRyan Stone return (EINVAL); 3083c22f215SRyan Stone return (0); 3093c22f215SRyan Stone } 3103c22f215SRyan Stone 3113c22f215SRyan Stone static int 3123c22f215SRyan Stone pci_iov_schema_validate_uint(const struct config_type_validator * validator, 3133c22f215SRyan Stone const nvlist_t *config, const char *name) 3143c22f215SRyan Stone { 3153c22f215SRyan Stone uint64_t value; 3163c22f215SRyan Stone 3173c22f215SRyan Stone if (!nvlist_exists_number(config, name)) 3183c22f215SRyan Stone return (EINVAL); 3193c22f215SRyan Stone 3203c22f215SRyan Stone value = nvlist_get_number(config, name); 3213c22f215SRyan Stone 3223c22f215SRyan Stone if (value > validator->limit) 3233c22f215SRyan Stone return (EINVAL); 3243c22f215SRyan Stone 3253c22f215SRyan Stone return (0); 3263c22f215SRyan Stone } 3273c22f215SRyan Stone 3283c22f215SRyan Stone static int 3293c22f215SRyan Stone pci_iov_schema_validate_unicast_mac( 3303c22f215SRyan Stone const struct config_type_validator * validator, 3313c22f215SRyan Stone const nvlist_t *config, const char *name) 3323c22f215SRyan Stone { 3333c22f215SRyan Stone const uint8_t *mac; 3343c22f215SRyan Stone size_t size; 3353c22f215SRyan Stone 3363c22f215SRyan Stone if (!nvlist_exists_binary(config, name)) 3373c22f215SRyan Stone return (EINVAL); 3383c22f215SRyan Stone 3393c22f215SRyan Stone mac = nvlist_get_binary(config, name, &size); 3403c22f215SRyan Stone 3413c22f215SRyan Stone if (size != ETHER_ADDR_LEN) 3423c22f215SRyan Stone return (EINVAL); 3433c22f215SRyan Stone 3443c22f215SRyan Stone if (ETHER_IS_MULTICAST(mac)) 3453c22f215SRyan Stone return (EINVAL); 3463c22f215SRyan Stone 3473c22f215SRyan Stone return (0); 3483c22f215SRyan Stone } 3493c22f215SRyan Stone 350*c57c2617SKristof Provost static int 351*c57c2617SKristof Provost pci_iov_schema_validate_vlan( 352*c57c2617SKristof Provost const struct config_type_validator * validator, 353*c57c2617SKristof Provost const nvlist_t *config, const char *name) 354*c57c2617SKristof Provost { 355*c57c2617SKristof Provost uint16_t vlan; 356*c57c2617SKristof Provost 357*c57c2617SKristof Provost if (!nvlist_exists_number(config, name)) 358*c57c2617SKristof Provost return (EINVAL); 359*c57c2617SKristof Provost 360*c57c2617SKristof Provost vlan = nvlist_get_number(config, name); 361*c57c2617SKristof Provost 362*c57c2617SKristof Provost if (vlan > 4095 && vlan != VF_VLAN_TRUNK) 363*c57c2617SKristof Provost return (EINVAL); 364*c57c2617SKristof Provost 365*c57c2617SKristof Provost return (0); 366*c57c2617SKristof Provost } 367*c57c2617SKristof Provost 3683c22f215SRyan Stone static void 3693c22f215SRyan Stone pci_iov_config_add_default(const nvlist_t *param_schema, const char *name, 3703c22f215SRyan Stone nvlist_t *config) 3713c22f215SRyan Stone { 3723c22f215SRyan Stone const void *binary; 3733c22f215SRyan Stone size_t len; 3743c22f215SRyan Stone 3753c22f215SRyan Stone if (nvlist_exists_binary(param_schema, "default")) { 3763c22f215SRyan Stone binary = nvlist_get_binary(param_schema, "default", &len); 3773c22f215SRyan Stone nvlist_add_binary(config, name, binary, len); 3783c22f215SRyan Stone } else if (nvlist_exists_bool(param_schema, "default")) 3793c22f215SRyan Stone nvlist_add_bool(config, name, 3803c22f215SRyan Stone nvlist_get_bool(param_schema, "default")); 3813c22f215SRyan Stone else if (nvlist_exists_number(param_schema, "default")) 3823c22f215SRyan Stone nvlist_add_number(config, name, 3833c22f215SRyan Stone nvlist_get_number(param_schema, "default")); 3843c22f215SRyan Stone else if (nvlist_exists_nvlist(param_schema, "default")) 3853c22f215SRyan Stone nvlist_add_nvlist(config, name, 3863c22f215SRyan Stone nvlist_get_nvlist(param_schema, "default")); 3873c22f215SRyan Stone else if (nvlist_exists_string(param_schema, "default")) 3883c22f215SRyan Stone nvlist_add_string(config, name, 3893c22f215SRyan Stone nvlist_get_string(param_schema, "default")); 3903c22f215SRyan Stone else 3913c22f215SRyan Stone panic("Unexpected nvlist type"); 3923c22f215SRyan Stone } 3933c22f215SRyan Stone 394bdc48af2SRyan Stone static int 395bdc48af2SRyan Stone pci_iov_validate_bool_default(const struct config_type_validator * validator, 396bdc48af2SRyan Stone const nvlist_t *param) 397bdc48af2SRyan Stone { 398bdc48af2SRyan Stone 399bdc48af2SRyan Stone if (!nvlist_exists_bool(param, DEFAULT_SCHEMA_NAME)) 400bdc48af2SRyan Stone return (EINVAL); 401bdc48af2SRyan Stone return (0); 402bdc48af2SRyan Stone } 403bdc48af2SRyan Stone 404bdc48af2SRyan Stone static int 405bdc48af2SRyan Stone pci_iov_validate_string_default(const struct config_type_validator * validator, 406bdc48af2SRyan Stone const nvlist_t *param) 407bdc48af2SRyan Stone { 408bdc48af2SRyan Stone 409bdc48af2SRyan Stone if (!nvlist_exists_string(param, DEFAULT_SCHEMA_NAME)) 410bdc48af2SRyan Stone return (EINVAL); 411bdc48af2SRyan Stone return (0); 412bdc48af2SRyan Stone } 413bdc48af2SRyan Stone 414bdc48af2SRyan Stone static int 415bdc48af2SRyan Stone pci_iov_validate_uint_default(const struct config_type_validator * validator, 416bdc48af2SRyan Stone const nvlist_t *param) 417bdc48af2SRyan Stone { 418bdc48af2SRyan Stone uint64_t defaultVal; 419bdc48af2SRyan Stone 420bdc48af2SRyan Stone if (!nvlist_exists_number(param, DEFAULT_SCHEMA_NAME)) 421bdc48af2SRyan Stone return (EINVAL); 422bdc48af2SRyan Stone 423bdc48af2SRyan Stone defaultVal = nvlist_get_number(param, DEFAULT_SCHEMA_NAME); 424bdc48af2SRyan Stone if (defaultVal > validator->limit) 425bdc48af2SRyan Stone return (EINVAL); 426bdc48af2SRyan Stone return (0); 427bdc48af2SRyan Stone } 428bdc48af2SRyan Stone 429bdc48af2SRyan Stone static int 430bdc48af2SRyan Stone pci_iov_validate_unicast_mac_default( 431bdc48af2SRyan Stone const struct config_type_validator * validator, const nvlist_t *param) 432bdc48af2SRyan Stone { 433bdc48af2SRyan Stone const uint8_t *mac; 434bdc48af2SRyan Stone size_t size; 435bdc48af2SRyan Stone 436bdc48af2SRyan Stone if (!nvlist_exists_binary(param, DEFAULT_SCHEMA_NAME)) 437bdc48af2SRyan Stone return (EINVAL); 438bdc48af2SRyan Stone 439bdc48af2SRyan Stone mac = nvlist_get_binary(param, DEFAULT_SCHEMA_NAME, &size); 440bdc48af2SRyan Stone if (size != ETHER_ADDR_LEN) 441bdc48af2SRyan Stone return (EINVAL); 442bdc48af2SRyan Stone 443bdc48af2SRyan Stone if (ETHER_IS_MULTICAST(mac)) 444bdc48af2SRyan Stone return (EINVAL); 445bdc48af2SRyan Stone return (0); 446bdc48af2SRyan Stone } 447bdc48af2SRyan Stone 448bdc48af2SRyan Stone static int 449*c57c2617SKristof Provost pci_iov_validate_vlan_default( 450*c57c2617SKristof Provost const struct config_type_validator * validator, const nvlist_t *param) 451*c57c2617SKristof Provost { 452*c57c2617SKristof Provost uint16_t vlan; 453*c57c2617SKristof Provost 454*c57c2617SKristof Provost if (! nvlist_exists_number(param, DEFAULT_SCHEMA_NAME)) 455*c57c2617SKristof Provost return (EINVAL); 456*c57c2617SKristof Provost 457*c57c2617SKristof Provost vlan = nvlist_get_number(param, DEFAULT_SCHEMA_NAME); 458*c57c2617SKristof Provost if (vlan > 4095 && vlan != VF_VLAN_TRUNK) 459*c57c2617SKristof Provost return (EINVAL); 460*c57c2617SKristof Provost 461*c57c2617SKristof Provost return (0); 462*c57c2617SKristof Provost } 463*c57c2617SKristof Provost 464*c57c2617SKristof Provost static int 465bdc48af2SRyan Stone pci_iov_validate_param_schema(const nvlist_t *schema) 466bdc48af2SRyan Stone { 467bdc48af2SRyan Stone const struct config_type_validator *validator; 468bdc48af2SRyan Stone const char *type; 469bdc48af2SRyan Stone int error; 470bdc48af2SRyan Stone 471bdc48af2SRyan Stone /* All parameters must define a type. */ 472bdc48af2SRyan Stone if (!nvlist_exists_string(schema, TYPE_SCHEMA_NAME)) 473bdc48af2SRyan Stone return (EINVAL); 474bdc48af2SRyan Stone type = nvlist_get_string(schema, TYPE_SCHEMA_NAME); 475bdc48af2SRyan Stone 476bdc48af2SRyan Stone validator = pci_iov_schema_find_validator(type); 477bdc48af2SRyan Stone if (validator == NULL) 478bdc48af2SRyan Stone return (EINVAL); 479bdc48af2SRyan Stone 480bdc48af2SRyan Stone /* Validate that the default value conforms to the type. */ 481bdc48af2SRyan Stone if (nvlist_exists(schema, DEFAULT_SCHEMA_NAME)) { 482bdc48af2SRyan Stone error = validator->default_validate(validator, schema); 483bdc48af2SRyan Stone if (error != 0) 484bdc48af2SRyan Stone return (error); 485bdc48af2SRyan Stone 486bdc48af2SRyan Stone /* Required and Default are mutually exclusive. */ 487bdc48af2SRyan Stone if (nvlist_exists(schema, REQUIRED_SCHEMA_NAME)) 488bdc48af2SRyan Stone return (EINVAL); 489bdc48af2SRyan Stone } 490bdc48af2SRyan Stone 491bdc48af2SRyan Stone /* The "Required" field must be a bool. */ 492bdc48af2SRyan Stone if (nvlist_exists(schema, REQUIRED_SCHEMA_NAME)) { 493bdc48af2SRyan Stone if (!nvlist_exists_bool(schema, REQUIRED_SCHEMA_NAME)) 494bdc48af2SRyan Stone return (EINVAL); 495bdc48af2SRyan Stone } 496bdc48af2SRyan Stone 497bdc48af2SRyan Stone return (0); 498bdc48af2SRyan Stone } 499bdc48af2SRyan Stone 500bdc48af2SRyan Stone static int 501bdc48af2SRyan Stone pci_iov_validate_subsystem_schema(const nvlist_t *dev_schema, const char *name) 502bdc48af2SRyan Stone { 503bdc48af2SRyan Stone const nvlist_t *sub_schema, *param_schema; 504bdc48af2SRyan Stone const char *param_name; 505bdc48af2SRyan Stone void *it; 506bdc48af2SRyan Stone int type, error; 507bdc48af2SRyan Stone 508bdc48af2SRyan Stone if (!nvlist_exists_nvlist(dev_schema, name)) 509bdc48af2SRyan Stone return (EINVAL); 510bdc48af2SRyan Stone sub_schema = nvlist_get_nvlist(dev_schema, name); 511bdc48af2SRyan Stone 512bdc48af2SRyan Stone it = NULL; 513bdc48af2SRyan Stone while ((param_name = nvlist_next(sub_schema, &type, &it)) != NULL) { 514bdc48af2SRyan Stone if (type != NV_TYPE_NVLIST) 515bdc48af2SRyan Stone return (EINVAL); 516bdc48af2SRyan Stone param_schema = nvlist_get_nvlist(sub_schema, param_name); 517bdc48af2SRyan Stone 518bdc48af2SRyan Stone error = pci_iov_validate_param_schema(param_schema); 519bdc48af2SRyan Stone if (error != 0) 520bdc48af2SRyan Stone return (error); 521bdc48af2SRyan Stone } 522bdc48af2SRyan Stone 523bdc48af2SRyan Stone return (0); 524bdc48af2SRyan Stone } 525bdc48af2SRyan Stone 526bdc48af2SRyan Stone /* 527bdc48af2SRyan Stone * Validate that the driver schema does not define any configuration parameters 528bdc48af2SRyan Stone * whose names collide with configuration parameters defined in the iov schema. 529bdc48af2SRyan Stone */ 530bdc48af2SRyan Stone static int 531bdc48af2SRyan Stone pci_iov_validate_param_collisions(const nvlist_t *dev_schema) 532bdc48af2SRyan Stone { 533bdc48af2SRyan Stone const nvlist_t *iov_schema, *driver_schema; 534bdc48af2SRyan Stone const char *name; 535bdc48af2SRyan Stone void *it; 536bdc48af2SRyan Stone int type; 537bdc48af2SRyan Stone 538bdc48af2SRyan Stone driver_schema = nvlist_get_nvlist(dev_schema, DRIVER_CONFIG_NAME); 539bdc48af2SRyan Stone iov_schema = nvlist_get_nvlist(dev_schema, IOV_CONFIG_NAME); 540bdc48af2SRyan Stone 541bdc48af2SRyan Stone it = NULL; 542bdc48af2SRyan Stone while ((name = nvlist_next(driver_schema, &type, &it)) != NULL) { 543bdc48af2SRyan Stone if (nvlist_exists(iov_schema, name)) 544bdc48af2SRyan Stone return (EINVAL); 545bdc48af2SRyan Stone } 546bdc48af2SRyan Stone 547bdc48af2SRyan Stone return (0); 548bdc48af2SRyan Stone } 549bdc48af2SRyan Stone 550bdc48af2SRyan Stone /* 551bdc48af2SRyan Stone * Validate that we only have IOV and DRIVER subsystems beneath the given 552bdc48af2SRyan Stone * device schema node. 553bdc48af2SRyan Stone */ 554bdc48af2SRyan Stone static int 555bdc48af2SRyan Stone pci_iov_validate_schema_subsystems(const nvlist_t *dev_schema) 556bdc48af2SRyan Stone { 557bdc48af2SRyan Stone const char *name; 558bdc48af2SRyan Stone void *it; 559bdc48af2SRyan Stone int type; 560bdc48af2SRyan Stone 561bdc48af2SRyan Stone it = NULL; 562bdc48af2SRyan Stone while ((name = nvlist_next(dev_schema, &type, &it)) != NULL) { 563bdc48af2SRyan Stone if (strcmp(name, IOV_CONFIG_NAME) != 0 && 564bdc48af2SRyan Stone strcmp(name, DRIVER_CONFIG_NAME) != 0) 565bdc48af2SRyan Stone return (EINVAL); 566bdc48af2SRyan Stone } 567bdc48af2SRyan Stone 568bdc48af2SRyan Stone return (0); 569bdc48af2SRyan Stone } 570bdc48af2SRyan Stone 571bdc48af2SRyan Stone static int 572bdc48af2SRyan Stone pci_iov_validate_device_schema(const nvlist_t *schema, const char *name) 573bdc48af2SRyan Stone { 574bdc48af2SRyan Stone const nvlist_t *dev_schema; 575bdc48af2SRyan Stone int error; 576bdc48af2SRyan Stone 577bdc48af2SRyan Stone if (!nvlist_exists_nvlist(schema, name)) 578bdc48af2SRyan Stone return (EINVAL); 579bdc48af2SRyan Stone dev_schema = nvlist_get_nvlist(schema, name); 580bdc48af2SRyan Stone 581bdc48af2SRyan Stone error = pci_iov_validate_subsystem_schema(dev_schema, IOV_CONFIG_NAME); 582bdc48af2SRyan Stone if (error != 0) 583bdc48af2SRyan Stone return (error); 584bdc48af2SRyan Stone 585bdc48af2SRyan Stone error = pci_iov_validate_subsystem_schema(dev_schema, 586bdc48af2SRyan Stone DRIVER_CONFIG_NAME); 587bdc48af2SRyan Stone if (error != 0) 588bdc48af2SRyan Stone return (error); 589bdc48af2SRyan Stone 590bdc48af2SRyan Stone error = pci_iov_validate_param_collisions(dev_schema); 591bdc48af2SRyan Stone if (error != 0) 592bdc48af2SRyan Stone return (error); 593bdc48af2SRyan Stone 594bdc48af2SRyan Stone return (pci_iov_validate_schema_subsystems(dev_schema)); 595bdc48af2SRyan Stone } 596bdc48af2SRyan Stone 597bdc48af2SRyan Stone /* Validate that we only have PF and VF devices beneath the top-level schema. */ 598bdc48af2SRyan Stone static int 599bdc48af2SRyan Stone pci_iov_validate_schema_devices(const nvlist_t *dev_schema) 600bdc48af2SRyan Stone { 601bdc48af2SRyan Stone const char *name; 602bdc48af2SRyan Stone void *it; 603bdc48af2SRyan Stone int type; 604bdc48af2SRyan Stone 605bdc48af2SRyan Stone it = NULL; 606bdc48af2SRyan Stone while ((name = nvlist_next(dev_schema, &type, &it)) != NULL) { 607bdc48af2SRyan Stone if (strcmp(name, PF_CONFIG_NAME) != 0 && 608bdc48af2SRyan Stone strcmp(name, VF_SCHEMA_NAME) != 0) 609bdc48af2SRyan Stone return (EINVAL); 610bdc48af2SRyan Stone } 611bdc48af2SRyan Stone 612bdc48af2SRyan Stone return (0); 613bdc48af2SRyan Stone } 614bdc48af2SRyan Stone 615bdc48af2SRyan Stone int 616bdc48af2SRyan Stone pci_iov_validate_schema(const nvlist_t *schema) 617bdc48af2SRyan Stone { 618bdc48af2SRyan Stone int error; 619bdc48af2SRyan Stone 620bdc48af2SRyan Stone error = pci_iov_validate_device_schema(schema, PF_CONFIG_NAME); 621bdc48af2SRyan Stone if (error != 0) 622bdc48af2SRyan Stone return (error); 623bdc48af2SRyan Stone 624bdc48af2SRyan Stone error = pci_iov_validate_device_schema(schema, VF_SCHEMA_NAME); 625bdc48af2SRyan Stone if (error != 0) 626bdc48af2SRyan Stone return (error); 627bdc48af2SRyan Stone 628bdc48af2SRyan Stone return (pci_iov_validate_schema_devices(schema)); 629bdc48af2SRyan Stone } 630bdc48af2SRyan Stone 6313c22f215SRyan Stone /* 6323c22f215SRyan Stone * Validate that all required parameters from the schema are specified in the 6333c22f215SRyan Stone * config. If any parameter with a default value is not specified in the 6343c22f215SRyan Stone * config, add it to config. 6353c22f215SRyan Stone */ 6363c22f215SRyan Stone static int 6373c22f215SRyan Stone pci_iov_schema_validate_required(const nvlist_t *schema, nvlist_t *config) 6383c22f215SRyan Stone { 6393c22f215SRyan Stone const nvlist_t *param_schema; 6403c22f215SRyan Stone const char *name; 6413c22f215SRyan Stone void *cookie; 6423c22f215SRyan Stone int type; 6433c22f215SRyan Stone 6443c22f215SRyan Stone cookie = NULL; 6453c22f215SRyan Stone while ((name = nvlist_next(schema, &type, &cookie)) != NULL) { 6463c22f215SRyan Stone param_schema = nvlist_get_nvlist(schema, name); 6473c22f215SRyan Stone 6483c22f215SRyan Stone if (dnvlist_get_bool(param_schema, "required", 0)) { 6493c22f215SRyan Stone if (!nvlist_exists(config, name)) 6503c22f215SRyan Stone return (EINVAL); 6513c22f215SRyan Stone } 6523c22f215SRyan Stone 6533c22f215SRyan Stone if (nvlist_exists(param_schema, "default") && 6543c22f215SRyan Stone !nvlist_exists(config, name)) 6553c22f215SRyan Stone pci_iov_config_add_default(param_schema, name, config); 6563c22f215SRyan Stone } 6573c22f215SRyan Stone 6583c22f215SRyan Stone return (nvlist_error(config)); 6593c22f215SRyan Stone } 6603c22f215SRyan Stone 6613c22f215SRyan Stone static int 6623c22f215SRyan Stone pci_iov_schema_validate_param(const nvlist_t *schema_param, const char *name, 6633c22f215SRyan Stone const nvlist_t *config) 6643c22f215SRyan Stone { 6653c22f215SRyan Stone const struct config_type_validator *validator; 6663c22f215SRyan Stone const char *type; 6673c22f215SRyan Stone 6683c22f215SRyan Stone type = nvlist_get_string(schema_param, "type"); 6693c22f215SRyan Stone validator = pci_iov_schema_find_validator(type); 6703c22f215SRyan Stone 6713c22f215SRyan Stone KASSERT(validator != NULL, 6723c22f215SRyan Stone ("Schema was not validated: Unknown type %s", type)); 6733c22f215SRyan Stone 6743c22f215SRyan Stone return (validator->validate(validator, config, name)); 6753c22f215SRyan Stone } 6763c22f215SRyan Stone 6773c22f215SRyan Stone /* 6783c22f215SRyan Stone * Validate that all parameters in config are defined in the schema. Also 6793c22f215SRyan Stone * validate that the type of the parameter matches the type in the schema. 6803c22f215SRyan Stone */ 6813c22f215SRyan Stone static int 6823c22f215SRyan Stone pci_iov_schema_validate_types(const nvlist_t *schema, const nvlist_t *config) 6833c22f215SRyan Stone { 6843c22f215SRyan Stone const nvlist_t *schema_param; 6853c22f215SRyan Stone void *cookie; 6863c22f215SRyan Stone const char *name; 6873c22f215SRyan Stone int type, error; 6883c22f215SRyan Stone 6893c22f215SRyan Stone cookie = NULL; 6903c22f215SRyan Stone while ((name = nvlist_next(config, &type, &cookie)) != NULL) { 6913c22f215SRyan Stone if (!nvlist_exists_nvlist(schema, name)) 6923c22f215SRyan Stone return (EINVAL); 6933c22f215SRyan Stone 6943c22f215SRyan Stone schema_param = nvlist_get_nvlist(schema, name); 6953c22f215SRyan Stone 6963c22f215SRyan Stone error = pci_iov_schema_validate_param(schema_param, name, 6973c22f215SRyan Stone config); 6983c22f215SRyan Stone 6993c22f215SRyan Stone if (error != 0) 7003c22f215SRyan Stone return (error); 7013c22f215SRyan Stone } 7023c22f215SRyan Stone 7033c22f215SRyan Stone return (0); 7043c22f215SRyan Stone } 7053c22f215SRyan Stone 7063c22f215SRyan Stone static int 7073c22f215SRyan Stone pci_iov_schema_validate_device(const nvlist_t *schema, nvlist_t *config, 7083c22f215SRyan Stone const char *schema_device, const char *config_device) 7093c22f215SRyan Stone { 7103c22f215SRyan Stone const nvlist_t *device_schema, *iov_schema, *driver_schema; 7113c22f215SRyan Stone nvlist_t *device_config, *iov_config, *driver_config; 7123c22f215SRyan Stone int error; 7133c22f215SRyan Stone 7143c22f215SRyan Stone device_config = NULL; 7153c22f215SRyan Stone iov_config = NULL; 7163c22f215SRyan Stone driver_config = NULL; 7173c22f215SRyan Stone 7183c22f215SRyan Stone device_schema = nvlist_get_nvlist(schema, schema_device); 7193c22f215SRyan Stone iov_schema = nvlist_get_nvlist(device_schema, IOV_CONFIG_NAME); 7203c22f215SRyan Stone driver_schema = nvlist_get_nvlist(device_schema, DRIVER_CONFIG_NAME); 7213c22f215SRyan Stone 7223c22f215SRyan Stone device_config = dnvlist_take_nvlist(config, config_device, NULL); 7233c22f215SRyan Stone if (device_config == NULL) { 7243c22f215SRyan Stone error = EINVAL; 7253c22f215SRyan Stone goto out; 7263c22f215SRyan Stone } 7273c22f215SRyan Stone 7283c22f215SRyan Stone iov_config = dnvlist_take_nvlist(device_config, IOV_CONFIG_NAME, NULL); 7293c22f215SRyan Stone if (iov_config == NULL) { 7303c22f215SRyan Stone error = EINVAL; 7313c22f215SRyan Stone goto out; 7323c22f215SRyan Stone } 7333c22f215SRyan Stone 7343c22f215SRyan Stone driver_config = dnvlist_take_nvlist(device_config, DRIVER_CONFIG_NAME, 7353c22f215SRyan Stone NULL); 7363c22f215SRyan Stone if (driver_config == NULL) { 7373c22f215SRyan Stone error = EINVAL; 7383c22f215SRyan Stone goto out; 7393c22f215SRyan Stone } 7403c22f215SRyan Stone 7413c22f215SRyan Stone error = pci_iov_schema_validate_required(iov_schema, iov_config); 7423c22f215SRyan Stone if (error != 0) 7433c22f215SRyan Stone goto out; 7443c22f215SRyan Stone 7453c22f215SRyan Stone error = pci_iov_schema_validate_required(driver_schema, driver_config); 7463c22f215SRyan Stone if (error != 0) 7473c22f215SRyan Stone goto out; 7483c22f215SRyan Stone 7493c22f215SRyan Stone error = pci_iov_schema_validate_types(iov_schema, iov_config); 7503c22f215SRyan Stone if (error != 0) 7513c22f215SRyan Stone goto out; 7523c22f215SRyan Stone 7533c22f215SRyan Stone error = pci_iov_schema_validate_types(driver_schema, driver_config); 7543c22f215SRyan Stone if (error != 0) 7553c22f215SRyan Stone goto out; 7563c22f215SRyan Stone 7573c22f215SRyan Stone out: 7583c22f215SRyan Stone /* Note that these functions handle NULL pointers safely. */ 7593c22f215SRyan Stone nvlist_move_nvlist(device_config, IOV_CONFIG_NAME, iov_config); 7603c22f215SRyan Stone nvlist_move_nvlist(device_config, DRIVER_CONFIG_NAME, driver_config); 7613c22f215SRyan Stone nvlist_move_nvlist(config, config_device, device_config); 7623c22f215SRyan Stone 7633c22f215SRyan Stone return (error); 7643c22f215SRyan Stone } 7653c22f215SRyan Stone 7663c22f215SRyan Stone static int 7673c22f215SRyan Stone pci_iov_schema_validate_vfs(const nvlist_t *schema, nvlist_t *config, 7683c22f215SRyan Stone uint16_t num_vfs) 7693c22f215SRyan Stone { 7703c22f215SRyan Stone char device[VF_MAX_NAME]; 7713c22f215SRyan Stone int i, error; 7723c22f215SRyan Stone 7733c22f215SRyan Stone for (i = 0; i < num_vfs; i++) { 7743c22f215SRyan Stone snprintf(device, sizeof(device), VF_PREFIX"%d", i); 7753c22f215SRyan Stone 7763c22f215SRyan Stone error = pci_iov_schema_validate_device(schema, config, 7773c22f215SRyan Stone VF_SCHEMA_NAME, device); 7783c22f215SRyan Stone if (error != 0) 7793c22f215SRyan Stone return (error); 7803c22f215SRyan Stone } 7813c22f215SRyan Stone 7823c22f215SRyan Stone return (0); 7833c22f215SRyan Stone } 7843c22f215SRyan Stone 7853c22f215SRyan Stone /* 7863c22f215SRyan Stone * Validate that the device node only has IOV and DRIVER subnodes. 7873c22f215SRyan Stone */ 7883c22f215SRyan Stone static int 7893c22f215SRyan Stone pci_iov_schema_validate_device_subsystems(const nvlist_t *config) 7903c22f215SRyan Stone { 7913c22f215SRyan Stone void *cookie; 7923c22f215SRyan Stone const char *name; 7933c22f215SRyan Stone int type; 7943c22f215SRyan Stone 7953c22f215SRyan Stone cookie = NULL; 7963c22f215SRyan Stone while ((name = nvlist_next(config, &type, &cookie)) != NULL) { 7973c22f215SRyan Stone if (strcasecmp(name, IOV_CONFIG_NAME) == 0) 7983c22f215SRyan Stone continue; 7993c22f215SRyan Stone else if (strcasecmp(name, DRIVER_CONFIG_NAME) == 0) 8003c22f215SRyan Stone continue; 8013c22f215SRyan Stone 8023c22f215SRyan Stone return (EINVAL); 8033c22f215SRyan Stone } 8043c22f215SRyan Stone 8053c22f215SRyan Stone return (0); 8063c22f215SRyan Stone } 8073c22f215SRyan Stone 8083c22f215SRyan Stone /* 8093c22f215SRyan Stone * Validate that the string is a valid device node name. It must either be "PF" 8103c22f215SRyan Stone * or "VF-n", where n is an integer in the range [0, num_vfs). 8113c22f215SRyan Stone */ 8123c22f215SRyan Stone static int 8133c22f215SRyan Stone pci_iov_schema_validate_dev_name(const char *name, uint16_t num_vfs) 8143c22f215SRyan Stone { 8153c22f215SRyan Stone const char *number_start; 8163c22f215SRyan Stone char *endp; 8173c22f215SRyan Stone u_long vf_num; 8183c22f215SRyan Stone 8193c22f215SRyan Stone if (strcasecmp(PF_CONFIG_NAME, name) == 0) 8203c22f215SRyan Stone return (0); 8213c22f215SRyan Stone 8223c22f215SRyan Stone /* Ensure that we start with "VF-" */ 8233c22f215SRyan Stone if (strncasecmp(name, VF_PREFIX, VF_PREFIX_LEN) != 0) 8243c22f215SRyan Stone return (EINVAL); 8253c22f215SRyan Stone 8263c22f215SRyan Stone number_start = name + VF_PREFIX_LEN; 8273c22f215SRyan Stone 8283c22f215SRyan Stone /* Filter out name == "VF-" (no number) */ 8293c22f215SRyan Stone if (number_start[0] == '\0') 8303c22f215SRyan Stone return (EINVAL); 8313c22f215SRyan Stone 8323c22f215SRyan Stone /* Disallow leading whitespace or +/- */ 8333c22f215SRyan Stone if (!isdigit(number_start[0])) 8343c22f215SRyan Stone return (EINVAL); 8353c22f215SRyan Stone 8363c22f215SRyan Stone vf_num = strtoul(number_start, &endp, 10); 8373c22f215SRyan Stone if (*endp != '\0') 8383c22f215SRyan Stone return (EINVAL); 8393c22f215SRyan Stone 8403c22f215SRyan Stone /* Disallow leading zeros on VF-[1-9][0-9]* */ 8413c22f215SRyan Stone if (vf_num != 0 && number_start[0] == '0') 8423c22f215SRyan Stone return (EINVAL); 8433c22f215SRyan Stone 8443c22f215SRyan Stone /* Disallow leading zeros on VF-0 */ 8453c22f215SRyan Stone if (vf_num == 0 && number_start[1] != '\0') 8463c22f215SRyan Stone return (EINVAL); 8473c22f215SRyan Stone 8483c22f215SRyan Stone if (vf_num >= num_vfs) 8493c22f215SRyan Stone return (EINVAL); 8503c22f215SRyan Stone 8513c22f215SRyan Stone return (0); 8523c22f215SRyan Stone } 8533c22f215SRyan Stone 8543c22f215SRyan Stone /* 8553c22f215SRyan Stone * Validate that there are no device nodes in config other than the ones for 8563c22f215SRyan Stone * the PF and the VFs. This includes validating that all config nodes of the 8573c22f215SRyan Stone * form VF-n specify a VF number that is < num_vfs. 8583c22f215SRyan Stone */ 8593c22f215SRyan Stone static int 8603c22f215SRyan Stone pci_iov_schema_validate_device_names(const nvlist_t *config, uint16_t num_vfs) 8613c22f215SRyan Stone { 8623c22f215SRyan Stone const nvlist_t *device; 8633c22f215SRyan Stone void *cookie; 8643c22f215SRyan Stone const char *name; 8653c22f215SRyan Stone int type, error; 8663c22f215SRyan Stone 8673c22f215SRyan Stone cookie = NULL; 8683c22f215SRyan Stone while ((name = nvlist_next(config, &type, &cookie)) != NULL) { 8693c22f215SRyan Stone error = pci_iov_schema_validate_dev_name(name, num_vfs); 8703c22f215SRyan Stone if (error != 0) 8713c22f215SRyan Stone return (error); 8723c22f215SRyan Stone 8733c22f215SRyan Stone /* 8743c22f215SRyan Stone * Note that as this is a valid PF/VF node, we know that 8753c22f215SRyan Stone * pci_iov_schema_validate_device() has already checked that 8763c22f215SRyan Stone * the PF/VF node is an nvlist. 8773c22f215SRyan Stone */ 8783c22f215SRyan Stone device = nvlist_get_nvlist(config, name); 8793c22f215SRyan Stone error = pci_iov_schema_validate_device_subsystems(device); 8803c22f215SRyan Stone if (error != 0) 8813c22f215SRyan Stone return (error); 8823c22f215SRyan Stone } 8833c22f215SRyan Stone 8843c22f215SRyan Stone return (0); 8853c22f215SRyan Stone } 8863c22f215SRyan Stone 8873c22f215SRyan Stone int 8883c22f215SRyan Stone pci_iov_schema_validate_config(const nvlist_t *schema, nvlist_t *config) 8893c22f215SRyan Stone { 8903c22f215SRyan Stone int error; 8913c22f215SRyan Stone uint16_t num_vfs; 8923c22f215SRyan Stone 8933c22f215SRyan Stone error = pci_iov_schema_validate_device(schema, config, PF_CONFIG_NAME, 8943c22f215SRyan Stone PF_CONFIG_NAME); 8953c22f215SRyan Stone if (error != 0) 8963c22f215SRyan Stone return (error); 8973c22f215SRyan Stone 8983c22f215SRyan Stone num_vfs = pci_iov_config_get_num_vfs(config); 8993c22f215SRyan Stone 9003c22f215SRyan Stone error = pci_iov_schema_validate_vfs(schema, config, num_vfs); 9013c22f215SRyan Stone if (error != 0) 9023c22f215SRyan Stone return (error); 9033c22f215SRyan Stone 9043c22f215SRyan Stone return (pci_iov_schema_validate_device_names(config, num_vfs)); 9053c22f215SRyan Stone } 9063c22f215SRyan Stone 9073c22f215SRyan Stone /* 9083c22f215SRyan Stone * Return value of the num_vfs parameter. config must have already been 9093c22f215SRyan Stone * validated, which guarantees that the parameter exists. 9103c22f215SRyan Stone */ 9113c22f215SRyan Stone uint16_t 9123c22f215SRyan Stone pci_iov_config_get_num_vfs(const nvlist_t *config) 9133c22f215SRyan Stone { 9143c22f215SRyan Stone const nvlist_t *pf, *iov; 9153c22f215SRyan Stone 9163c22f215SRyan Stone pf = nvlist_get_nvlist(config, PF_CONFIG_NAME); 9173c22f215SRyan Stone iov = nvlist_get_nvlist(pf, IOV_CONFIG_NAME); 9183c22f215SRyan Stone return (nvlist_get_number(iov, "num_vfs")); 9193c22f215SRyan Stone } 9203c22f215SRyan Stone 9211191f715SRyan Stone /* Allocate a new empty schema node. */ 9221191f715SRyan Stone nvlist_t * 9231191f715SRyan Stone pci_iov_schema_alloc_node(void) 9241191f715SRyan Stone { 9251191f715SRyan Stone 9261191f715SRyan Stone return (nvlist_create(NV_FLAG_IGNORE_CASE)); 9271191f715SRyan Stone } 928