2 * Copyright (c) 2014-2015 Sandvine Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
32 #include <sys/ctype.h>
33 #include <sys/kernel.h>
34 #include <sys/systm.h>
36 #include <sys/malloc.h>
37 #include <sys/module.h>
38 #include <sys/queue.h>
40 #include <machine/stdarg.h>
44 #include <sys/iov_schema.h>
46 #include <net/ethernet.h>
48 #include <dev/pci/schema_private.h>
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 *,
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;
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;
66 struct config_type_validator {
67 const char *type_name;
68 validate_func *validate;
69 default_validate_t *default_validate;
73 static struct config_type_validator pci_iov_schema_validators[] = {
76 .validate = pci_iov_schema_validate_bool,
77 .default_validate = pci_iov_validate_bool_default
80 .type_name = "string",
81 .validate = pci_iov_schema_validate_string,
82 .default_validate = pci_iov_validate_string_default
85 .type_name = "uint8_t",
86 .validate = pci_iov_schema_validate_uint,
87 .default_validate = pci_iov_validate_uint_default,
91 .type_name = "uint16_t",
92 .validate = pci_iov_schema_validate_uint,
93 .default_validate = pci_iov_validate_uint_default,
97 .type_name = "uint32_t",
98 .validate = pci_iov_schema_validate_uint,
99 .default_validate = pci_iov_validate_uint_default,
103 .type_name = "uint64_t",
104 .validate = pci_iov_schema_validate_uint,
105 .default_validate = pci_iov_validate_uint_default,
109 .type_name = "unicast-mac",
110 .validate = pci_iov_schema_validate_unicast_mac,
111 .default_validate = pci_iov_validate_unicast_mac_default,
115 static const struct config_type_validator *
116 pci_iov_schema_find_validator(const char *type)
118 struct config_type_validator *validator;
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)
131 pci_iov_schema_add_type(nvlist_t *entry, const char *type)
134 if (pci_iov_schema_find_validator(type) == NULL) {
135 nvlist_set_error(entry, EINVAL);
138 nvlist_add_string(entry, "type", type);
142 pci_iov_schema_add_required(nvlist_t *entry, uint32_t flags)
145 if (flags & IOV_SCHEMA_REQUIRED) {
146 if (flags & IOV_SCHEMA_HASDEFAULT) {
147 nvlist_set_error(entry, EINVAL);
151 nvlist_add_bool(entry, "required", 1);
156 pci_iov_schema_add_bool(nvlist_t *schema, const char *name, uint32_t flags,
161 entry = nvlist_create(NV_FLAG_IGNORE_CASE);
163 nvlist_set_error(schema, ENOMEM);
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);
172 nvlist_move_nvlist(schema, name, entry);
176 pci_iov_schema_add_string(nvlist_t *schema, const char *name, uint32_t flags,
177 const char *defaultVal)
181 entry = nvlist_create(NV_FLAG_IGNORE_CASE);
183 nvlist_set_error(schema, ENOMEM);
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);
192 nvlist_move_nvlist(schema, name, entry);
196 pci_iov_schema_int(nvlist_t *schema, const char *name, const char *type,
197 uint32_t flags, uint64_t defaultVal)
201 entry = nvlist_create(NV_FLAG_IGNORE_CASE);
203 nvlist_set_error(schema, ENOMEM);
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);
212 nvlist_move_nvlist(schema, name, entry);
216 pci_iov_schema_add_uint8(nvlist_t *schema, const char *name, uint32_t flags,
220 pci_iov_schema_int(schema, name, "uint8_t", flags, defaultVal);
224 pci_iov_schema_add_uint16(nvlist_t *schema, const char *name, uint32_t flags,
228 pci_iov_schema_int(schema, name, "uint16_t", flags, defaultVal);
232 pci_iov_schema_add_uint32(nvlist_t *schema, const char *name, uint32_t flags,
236 pci_iov_schema_int(schema, name, "uint32_t", flags, defaultVal);
240 pci_iov_schema_add_uint64(nvlist_t *schema, const char *name, uint32_t flags,
244 pci_iov_schema_int(schema, name, "uint64_t", flags, defaultVal);
248 pci_iov_schema_add_unicast_mac(nvlist_t *schema, const char *name,
249 uint32_t flags, const uint8_t * defaultVal)
253 entry = nvlist_create(NV_FLAG_IGNORE_CASE);
255 nvlist_set_error(schema, ENOMEM);
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);
264 nvlist_move_nvlist(schema, name, entry);
268 pci_iov_schema_validate_bool(const struct config_type_validator * validator,
269 const nvlist_t *config, const char *name)
272 if (!nvlist_exists_bool(config, name))
278 pci_iov_schema_validate_string(const struct config_type_validator * validator,
279 const nvlist_t *config, const char *name)
282 if (!nvlist_exists_string(config, name))
288 pci_iov_schema_validate_uint(const struct config_type_validator * validator,
289 const nvlist_t *config, const char *name)
293 if (!nvlist_exists_number(config, name))
296 value = nvlist_get_number(config, name);
298 if (value > validator->limit)
305 pci_iov_schema_validate_unicast_mac(
306 const struct config_type_validator * validator,
307 const nvlist_t *config, const char *name)
312 if (!nvlist_exists_binary(config, name))
315 mac = nvlist_get_binary(config, name, &size);
317 if (size != ETHER_ADDR_LEN)
320 if (ETHER_IS_MULTICAST(mac))
327 pci_iov_config_add_default(const nvlist_t *param_schema, const char *name,
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"));
349 panic("Unexpected nvlist type");
353 pci_iov_validate_bool_default(const struct config_type_validator * validator,
354 const nvlist_t *param)
357 if (!nvlist_exists_bool(param, DEFAULT_SCHEMA_NAME))
363 pci_iov_validate_string_default(const struct config_type_validator * validator,
364 const nvlist_t *param)
367 if (!nvlist_exists_string(param, DEFAULT_SCHEMA_NAME))
373 pci_iov_validate_uint_default(const struct config_type_validator * validator,
374 const nvlist_t *param)
378 if (!nvlist_exists_number(param, DEFAULT_SCHEMA_NAME))
381 defaultVal = nvlist_get_number(param, DEFAULT_SCHEMA_NAME);
382 if (defaultVal > validator->limit)
388 pci_iov_validate_unicast_mac_default(
389 const struct config_type_validator * validator, const nvlist_t *param)
394 if (!nvlist_exists_binary(param, DEFAULT_SCHEMA_NAME))
397 mac = nvlist_get_binary(param, DEFAULT_SCHEMA_NAME, &size);
398 if (size != ETHER_ADDR_LEN)
401 if (ETHER_IS_MULTICAST(mac))
407 pci_iov_validate_param_schema(const nvlist_t *schema)
409 const struct config_type_validator *validator;
413 /* All parameters must define a type. */
414 if (!nvlist_exists_string(schema, TYPE_SCHEMA_NAME))
416 type = nvlist_get_string(schema, TYPE_SCHEMA_NAME);
418 validator = pci_iov_schema_find_validator(type);
419 if (validator == NULL)
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);
428 /* Required and Default are mutually exclusive. */
429 if (nvlist_exists(schema, REQUIRED_SCHEMA_NAME))
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))
443 pci_iov_validate_subsystem_schema(const nvlist_t *dev_schema, const char *name)
445 const nvlist_t *sub_schema, *param_schema;
446 const char *param_name;
450 if (!nvlist_exists_nvlist(dev_schema, name))
452 sub_schema = nvlist_get_nvlist(dev_schema, name);
455 while ((param_name = nvlist_next(sub_schema, &type, &it)) != NULL) {
456 if (type != NV_TYPE_NVLIST)
458 param_schema = nvlist_get_nvlist(sub_schema, param_name);
460 error = pci_iov_validate_param_schema(param_schema);
469 * Validate that the driver schema does not define any configuration parameters
470 * whose names collide with configuration parameters defined in the iov schema.
473 pci_iov_validate_param_collisions(const nvlist_t *dev_schema)
475 const nvlist_t *iov_schema, *driver_schema;
480 driver_schema = nvlist_get_nvlist(dev_schema, DRIVER_CONFIG_NAME);
481 iov_schema = nvlist_get_nvlist(dev_schema, IOV_CONFIG_NAME);
484 while ((name = nvlist_next(driver_schema, &type, &it)) != NULL) {
485 if (nvlist_exists(iov_schema, name))
493 * Validate that we only have IOV and DRIVER subsystems beneath the given
494 * device schema node.
497 pci_iov_validate_schema_subsystems(const nvlist_t *dev_schema)
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)
514 pci_iov_validate_device_schema(const nvlist_t *schema, const char *name)
516 const nvlist_t *dev_schema;
519 if (!nvlist_exists_nvlist(schema, name))
521 dev_schema = nvlist_get_nvlist(schema, name);
523 error = pci_iov_validate_subsystem_schema(dev_schema, IOV_CONFIG_NAME);
527 error = pci_iov_validate_subsystem_schema(dev_schema,
532 error = pci_iov_validate_param_collisions(dev_schema);
536 return (pci_iov_validate_schema_subsystems(dev_schema));
539 /* Validate that we only have PF and VF devices beneath the top-level schema. */
541 pci_iov_validate_schema_devices(const nvlist_t *dev_schema)
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)
558 pci_iov_validate_schema(const nvlist_t *schema)
562 error = pci_iov_validate_device_schema(schema, PF_CONFIG_NAME);
566 error = pci_iov_validate_device_schema(schema, VF_SCHEMA_NAME);
570 return (pci_iov_validate_schema_devices(schema));
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.
579 pci_iov_schema_validate_required(const nvlist_t *schema, nvlist_t *config)
581 const nvlist_t *param_schema;
587 while ((name = nvlist_next(schema, &type, &cookie)) != NULL) {
588 param_schema = nvlist_get_nvlist(schema, name);
590 if (dnvlist_get_bool(param_schema, "required", 0)) {
591 if (!nvlist_exists(config, name))
595 if (nvlist_exists(param_schema, "default") &&
596 !nvlist_exists(config, name))
597 pci_iov_config_add_default(param_schema, name, config);
600 return (nvlist_error(config));
604 pci_iov_schema_validate_param(const nvlist_t *schema_param, const char *name,
605 const nvlist_t *config)
607 const struct config_type_validator *validator;
610 type = nvlist_get_string(schema_param, "type");
611 validator = pci_iov_schema_find_validator(type);
613 KASSERT(validator != NULL,
614 ("Schema was not validated: Unknown type %s", type));
616 return (validator->validate(validator, config, name));
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.
624 pci_iov_schema_validate_types(const nvlist_t *schema, const nvlist_t *config)
626 const nvlist_t *schema_param;
632 while ((name = nvlist_next(config, &type, &cookie)) != NULL) {
633 if (!nvlist_exists_nvlist(schema, name))
636 schema_param = nvlist_get_nvlist(schema, name);
638 error = pci_iov_schema_validate_param(schema_param, name,
649 pci_iov_schema_validate_device(const nvlist_t *schema, nvlist_t *config,
650 const char *schema_device, const char *config_device)
652 const nvlist_t *device_schema, *iov_schema, *driver_schema;
653 nvlist_t *device_config, *iov_config, *driver_config;
656 device_config = NULL;
658 driver_config = NULL;
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);
664 device_config = dnvlist_take_nvlist(config, config_device, NULL);
665 if (device_config == NULL) {
670 iov_config = dnvlist_take_nvlist(device_config, IOV_CONFIG_NAME, NULL);
671 if (iov_config == NULL) {
676 driver_config = dnvlist_take_nvlist(device_config, DRIVER_CONFIG_NAME,
678 if (driver_config == NULL) {
683 error = pci_iov_schema_validate_required(iov_schema, iov_config);
687 error = pci_iov_schema_validate_required(driver_schema, driver_config);
691 error = pci_iov_schema_validate_types(iov_schema, iov_config);
695 error = pci_iov_schema_validate_types(driver_schema, driver_config);
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);
709 pci_iov_schema_validate_vfs(const nvlist_t *schema, nvlist_t *config,
712 char device[VF_MAX_NAME];
715 for (i = 0; i < num_vfs; i++) {
716 snprintf(device, sizeof(device), VF_PREFIX"%d", i);
718 error = pci_iov_schema_validate_device(schema, config,
719 VF_SCHEMA_NAME, device);
728 * Validate that the device node only has IOV and DRIVER subnodes.
731 pci_iov_schema_validate_device_subsystems(const nvlist_t *config)
738 while ((name = nvlist_next(config, &type, &cookie)) != NULL) {
739 if (strcasecmp(name, IOV_CONFIG_NAME) == 0)
741 else if (strcasecmp(name, DRIVER_CONFIG_NAME) == 0)
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).
755 pci_iov_schema_validate_dev_name(const char *name, uint16_t num_vfs)
757 const char *number_start;
761 if (strcasecmp(PF_CONFIG_NAME, name) == 0)
764 /* Ensure that we start with "VF-" */
765 if (strncasecmp(name, VF_PREFIX, VF_PREFIX_LEN) != 0)
768 number_start = name + VF_PREFIX_LEN;
770 /* Filter out name == "VF-" (no number) */
771 if (number_start[0] == '\0')
774 /* Disallow leading whitespace or +/- */
775 if (!isdigit(number_start[0]))
778 vf_num = strtoul(number_start, &endp, 10);
782 /* Disallow leading zeros on VF-[1-9][0-9]* */
783 if (vf_num != 0 && number_start[0] == '0')
786 /* Disallow leading zeros on VF-0 */
787 if (vf_num == 0 && number_start[1] != '\0')
790 if (vf_num >= num_vfs)
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.
802 pci_iov_schema_validate_device_names(const nvlist_t *config, uint16_t num_vfs)
804 const nvlist_t *device;
810 while ((name = nvlist_next(config, &type, &cookie)) != NULL) {
811 error = pci_iov_schema_validate_dev_name(name, num_vfs);
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.
820 device = nvlist_get_nvlist(config, name);
821 error = pci_iov_schema_validate_device_subsystems(device);
830 pci_iov_schema_validate_config(const nvlist_t *schema, nvlist_t *config)
835 error = pci_iov_schema_validate_device(schema, config, PF_CONFIG_NAME,
840 num_vfs = pci_iov_config_get_num_vfs(config);
842 error = pci_iov_schema_validate_vfs(schema, config, num_vfs);
846 return (pci_iov_schema_validate_device_names(config, num_vfs));
850 * Return value of the num_vfs parameter. config must have already been
851 * validated, which guarantees that the parameter exists.
854 pci_iov_config_get_num_vfs(const nvlist_t *config)
856 const nvlist_t *pf, *iov;
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"));
863 /* Allocate a new empty schema node. */
865 pci_iov_schema_alloc_node(void)
868 return (nvlist_create(NV_FLAG_IGNORE_CASE));