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