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