Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 3 Jan 2016 06:51:57 +0000 (UTC)
From:      Garrett Cooper <ngie@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r293078 - in user/ngie/stable-10-libnv: etc/defaults etc/rc.d share/man/man5 usr.sbin usr.sbin/iovctl
Message-ID:  <201601030651.u036pvld085688@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ngie
Date: Sun Jan  3 06:51:57 2016
New Revision: 293078
URL: https://svnweb.freebsd.org/changeset/base/293078

Log:
  MFC r279457,r279458,r279459,r279460,r279461,r279463,r279469,r284891:
  
  r279457 (by rstone):
  
  Add a manpage for iovctl(8)
  
  r279458 (by rstone):
  
  Add manpage documenting iovctl config file format.
  
  r279459 (by rstone):
  
  Add iovctl functions for validating config
  
  Add an function to iovctl that validates the configuration against
  a schema.  This function is able to assume that the parser has
  done most of the validation already and it's only responsible for
  applying default VF values specified in the config file, confirming
  that all required parameters have been set and that no invalid VF
  numbers have been specified.
  
  r279460 (by rstone):
  
  Add functions for parsing the iovctl config file
  
  Add two functions for parsing the iovctl config file.  The config
  file is parsed using libucl[1], which accepts most YAML files and
  a superset of JSON.  The first function is an ad-hoc parser that
  searches the file for the PF.DEVICE configuration value.  We need
  to know that value in order to fetch the schema from the kernel,
  and we need the schema in order to be able to fully parse the file.
  
  The second function parses the config file and validates it
  against a schema.  This function will exit with an error message
  if any validation error occurs.  If it succeeds, the configuration
  is returned as an nvlist suitable for passing to the kernel.
  
  [1] https://github.com/vstakhov/libucl
  
  r279461 (by rstone):
  
  Add main() for iovctl and hook iovctl into build
  
  r279463 (by rstone):
  
  Add an rc.d script to invoke iovctl(8) during boot
  
  Relnotes:			yes
  
  r279469 (by rstone):
  
  Correct a typo.
  
  X-MFC-With:	r279458
  
  r284891 (by pkelsey):
  
  Use correct flag in iovctl_start().

Added:
  user/ngie/stable-10-libnv/etc/rc.d/iovctl
     - copied, changed from r279463, head/etc/rc.d/iovctl
  user/ngie/stable-10-libnv/usr.sbin/iovctl/
     - copied from r279457, head/usr.sbin/iovctl/
  user/ngie/stable-10-libnv/usr.sbin/iovctl/Makefile
     - copied unchanged from r279461, head/usr.sbin/iovctl/Makefile
  user/ngie/stable-10-libnv/usr.sbin/iovctl/iovctl.c
     - copied unchanged from r279461, head/usr.sbin/iovctl/iovctl.c
  user/ngie/stable-10-libnv/usr.sbin/iovctl/iovctl.conf.5
     - copied, changed from r279458, head/usr.sbin/iovctl/iovctl.conf.5
  user/ngie/stable-10-libnv/usr.sbin/iovctl/iovctl.h
     - copied unchanged from r279461, head/usr.sbin/iovctl/iovctl.h
  user/ngie/stable-10-libnv/usr.sbin/iovctl/parse.c
     - copied unchanged from r279460, head/usr.sbin/iovctl/parse.c
  user/ngie/stable-10-libnv/usr.sbin/iovctl/validate.c
     - copied unchanged from r279459, head/usr.sbin/iovctl/validate.c
Modified:
  user/ngie/stable-10-libnv/etc/defaults/rc.conf
  user/ngie/stable-10-libnv/etc/rc.d/Makefile
  user/ngie/stable-10-libnv/etc/rc.d/netif
  user/ngie/stable-10-libnv/share/man/man5/rc.conf.5
  user/ngie/stable-10-libnv/usr.sbin/Makefile
Directory Properties:
  user/ngie/stable-10-libnv/   (props changed)

Modified: user/ngie/stable-10-libnv/etc/defaults/rc.conf
==============================================================================
--- user/ngie/stable-10-libnv/etc/defaults/rc.conf	Sun Jan  3 06:38:50 2016	(r293077)
+++ user/ngie/stable-10-libnv/etc/defaults/rc.conf	Sun Jan  3 06:51:57 2016	(r293078)
@@ -683,6 +683,8 @@ opensm_enable="NO"	# Opensm(8) for infin
 rctl_enable="NO"		# Load rctl(8) rules on boot
 rctl_rules="/etc/rctl.conf"	# rctl(8) ruleset. See rctl.conf(5).
 
+iovctl_files=""		# Config files for iovctl(8)
+
 ##############################################################
 ### Jail Configuration (see rc.conf(5) manual page) ##########
 ##############################################################

Modified: user/ngie/stable-10-libnv/etc/rc.d/Makefile
==============================================================================
--- user/ngie/stable-10-libnv/etc/rc.d/Makefile	Sun Jan  3 06:38:50 2016	(r293077)
+++ user/ngie/stable-10-libnv/etc/rc.d/Makefile	Sun Jan  3 06:51:57 2016	(r293078)
@@ -44,6 +44,7 @@ FILES=	DAEMON \
 	hostid_save \
 	hostname \
 	initrandom \
+	iovctl \
 	ip6addrctl \
 	ipfilter \
 	ipfs \

Copied and modified: user/ngie/stable-10-libnv/etc/rc.d/iovctl (from r279463, head/etc/rc.d/iovctl)
==============================================================================
--- head/etc/rc.d/iovctl	Sun Mar  1 00:58:23 2015	(r279463, copy source)
+++ user/ngie/stable-10-libnv/etc/rc.d/iovctl	Sun Jan  3 06:51:57 2016	(r293078)
@@ -27,7 +27,7 @@ run_iovctl()
 
 iovctl_start()
 {
-	run_iovctl -E
+	run_iovctl -C
 }
 
 iovctl_stop()

Modified: user/ngie/stable-10-libnv/etc/rc.d/netif
==============================================================================
--- user/ngie/stable-10-libnv/etc/rc.d/netif	Sun Jan  3 06:38:50 2016	(r293077)
+++ user/ngie/stable-10-libnv/etc/rc.d/netif	Sun Jan  3 06:51:57 2016	(r293078)
@@ -26,7 +26,7 @@
 #
 
 # PROVIDE: netif
-# REQUIRE: atm1 FILESYSTEMS serial sppp sysctl
+# REQUIRE: atm1 FILESYSTEMS iovctl serial sppp sysctl
 # REQUIRE: ipfilter ipfs
 # KEYWORD: nojailvnet
 

Modified: user/ngie/stable-10-libnv/share/man/man5/rc.conf.5
==============================================================================
--- user/ngie/stable-10-libnv/share/man/man5/rc.conf.5	Sun Jan  3 06:38:50 2016	(r293077)
+++ user/ngie/stable-10-libnv/share/man/man5/rc.conf.5	Sun Jan  3 06:51:57 2016	(r293078)
@@ -4524,6 +4524,11 @@ This variables contains the
 .Xr rctl.conf 5
 ruleset to load for
 .Xr rctl 8 .
+.It Va iovctl_files
+.Pq Vt str
+A space-separated list of configuration files used by
+.Xr iovctl 8 .
+The default value is an empty string.
 .El
 .Sh FILES
 .Bl -tag -width ".Pa /etc/defaults/rc.conf" -compact
@@ -4577,6 +4582,7 @@ ruleset to load for
 .Xr hcsecd 8 ,
 .Xr ifconfig 8 ,
 .Xr inetd 8 ,
+.Xr iovctl 8 ,
 .Xr ipf 8 ,
 .Xr ipfw 8 ,
 .Xr ipnat 8 ,

Modified: user/ngie/stable-10-libnv/usr.sbin/Makefile
==============================================================================
--- user/ngie/stable-10-libnv/usr.sbin/Makefile	Sun Jan  3 06:38:50 2016	(r293077)
+++ user/ngie/stable-10-libnv/usr.sbin/Makefile	Sun Jan  3 06:51:57 2016	(r293078)
@@ -35,6 +35,7 @@ SUBDIR=	adduser \
 	i2c \
 	ifmcstat \
 	iostat \
+	iovctl \
 	kldxref \
 	mailwrapper \
 	makefs \

Copied: user/ngie/stable-10-libnv/usr.sbin/iovctl/Makefile (from r279461, head/usr.sbin/iovctl/Makefile)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/ngie/stable-10-libnv/usr.sbin/iovctl/Makefile	Sun Jan  3 06:51:57 2016	(r293078, copy of r279461, head/usr.sbin/iovctl/Makefile)
@@ -0,0 +1,17 @@
+# $FreeBSD$
+
+PROG=	iovctl
+SRCS=	iovctl.c parse.c validate.c
+LIBADD=	nv ucl m
+
+CFLAGS+=-I${.CURDIR}/../../contrib/libucl/include
+
+WARNS?=6
+
+MAN=	\
+	iovctl.8 \
+	iovctl.conf.5 \
+
+.include <bsd.own.mk>
+.include <bsd.prog.mk>
+

Copied: user/ngie/stable-10-libnv/usr.sbin/iovctl/iovctl.c (from r279461, head/usr.sbin/iovctl/iovctl.c)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/ngie/stable-10-libnv/usr.sbin/iovctl/iovctl.c	Sun Jan  3 06:51:57 2016	(r293078, copy of r279461, head/usr.sbin/iovctl/iovctl.c)
@@ -0,0 +1,403 @@
+/*-
+ * Copyright (c) 2013-2015 Sandvine Inc.  All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/iov.h>
+
+#include <dnv.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <nv.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "iovctl.h"
+
+static void	config_action(const char *filename, int dryrun);
+static void	delete_action(const char *device, int dryrun);
+static void	print_schema(const char *device);
+
+/*
+ * Fetch the config schema from the kernel via ioctl.  This function has to
+ * call the ioctl twice: the first returns the amount of memory that we need
+ * to allocate for the schema, and the second actually fetches the schema.
+ */
+static nvlist_t *
+get_schema(int fd)
+{
+	struct pci_iov_schema arg;
+	nvlist_t *schema;
+	int error;
+
+	/* Do the ioctl() once to fetch the size of the schema. */
+	arg.schema = NULL;
+	arg.len = 0;
+	arg.error = 0;
+	error = ioctl(fd, IOV_GET_SCHEMA, &arg);
+	if (error != 0)
+		err(1, "Could not fetch size of config schema");
+
+	arg.schema = malloc(arg.len);
+	if (arg.schema == NULL)
+		err(1, "Could not allocate %zu bytes for schema",
+		    arg.len);
+
+	/* Now do the ioctl() for real to get the schema. */
+	error = ioctl(fd, IOV_GET_SCHEMA, &arg);
+	if (error != 0 || arg.error != 0) {
+		if (arg.error != 0)
+			errno = arg.error;
+		err(1, "Could not fetch config schema");
+	}
+
+	schema = nvlist_unpack(arg.schema, arg.len);
+	if (schema == NULL)
+		err(1, "Could not unpack schema");
+
+	free(arg.schema);
+	return (schema);
+}
+
+/*
+ * Call the ioctl that activates SR-IOV and creates the VFs.
+ */
+static void
+config_iov(int fd, const char *dev_name, const nvlist_t *config, int dryrun)
+{
+	struct pci_iov_arg arg;
+	int error;
+
+	arg.config = nvlist_pack(config, &arg.len);
+	if (arg.config == NULL)
+		err(1, "Could not pack configuration");
+
+	if (dryrun) {
+		printf("Would enable SR-IOV on device '%s'.\n", dev_name);
+		printf(
+		    "The following configuration parameters would be used:\n");
+		nvlist_fdump(config, stdout);
+		printf(
+		"The configuration parameters consume %zu bytes when packed.\n",
+		    arg.len);
+	} else {
+		error = ioctl(fd, IOV_CONFIG, &arg);
+		if (error != 0)
+			err(1, "Failed to configure SR-IOV");
+	}
+
+	free(arg.config);
+}
+
+static int
+open_device(const char *dev_name)
+{
+	char *dev;
+	int fd;
+	size_t copied, size;
+	long path_max;
+
+	path_max = pathconf("/dev", _PC_PATH_MAX);
+	if (path_max < 0)
+		err(1, "Could not get maximum path length");
+
+	size = path_max;
+	dev = malloc(size);
+	if (dev == NULL)
+		err(1, "Could not allocate memory for device path");
+
+	if (dev_name[0] == '/')
+		copied = strlcpy(dev, dev_name, size);
+	else
+		copied = snprintf(dev, size, "/dev/iov/%s", dev_name);
+
+	/* >= to account for null terminator. */
+	if (copied >= size)
+		errx(1, "Provided file name too long");
+
+	fd = open(dev, O_RDWR);
+	if (fd < 0)
+		err(1, "Could not open device '%s'", dev);
+
+	free(dev);
+	return (fd);
+}
+
+static void
+usage(void)
+{
+
+	warnx("Usage: iovctl -C -f <config file> [-n]");
+	warnx("       iovctl -D [-d <PF device> | -f <config file>] [-n]");
+	warnx("       iovctl -S [-d <PF device> | -f <config file>]");
+	exit(1);
+
+}
+
+enum main_action {
+	NONE,
+	CONFIG,
+	DELETE,
+	PRINT_SCHEMA,
+};
+
+int
+main(int argc, char **argv)
+{
+	char *device;
+	const char *filename;
+	int ch, dryrun;
+	enum main_action action;
+
+	device = NULL;
+	filename = NULL;
+	dryrun = 0;
+	action = NONE;
+
+	while ((ch = getopt(argc, argv, "Cd:Df:nS")) != -1) {
+		switch (ch) {
+		case 'C':
+			if (action != NONE) {
+				warnx(
+				   "Only one of -C, -D or -S may be specified");
+				usage();
+			}
+			action = CONFIG;
+			break;
+		case 'd':
+			device = strdup(optarg);
+			break;
+		case 'D':
+			if (action != NONE) {
+				warnx(
+				   "Only one of -C, -D or -S may be specified");
+				usage();
+			}
+			action = DELETE;
+			break;
+		case 'f':
+			filename = optarg;
+			break;
+		case 'n':
+			dryrun = 1;
+			break;
+		case 'S':
+			if (action != NONE) {
+				warnx(
+				   "Only one of -C, -D or -S may be specified");
+				usage();
+			}
+			action = PRINT_SCHEMA;
+			break;
+		case '?':
+			warnx("Unrecognized argument '-%c'\n", optopt);
+			usage();
+			break;
+		}
+	}
+
+	if (device != NULL && filename != NULL) {
+		warnx("Only one of the -d and -f flags may be specified");
+		usage();
+	}
+
+	if (device == NULL && filename == NULL) {
+		warnx("Either the -d or -f flag must be specified");
+		usage();
+	}
+
+	switch (action) {
+	case CONFIG:
+		if (filename == NULL) {
+			warnx("-d flag cannot be used with the -C flag");
+			usage();
+		}
+		config_action(filename, dryrun);
+		break;
+	case DELETE:
+		if (device == NULL)
+			device = find_device(filename);
+		delete_action(device, dryrun);
+		free(device);
+		break;
+	case PRINT_SCHEMA:
+		if (dryrun) {
+			warnx("-n flag cannot be used with the -S flag");
+			usage();
+		}
+		if (device == NULL)
+			device = find_device(filename);
+		print_schema(device);
+		free(device);
+		break;
+	default:
+		usage();
+		break;
+	}
+
+	exit(0);
+}
+
+static void
+config_action(const char *filename, int dryrun)
+{
+	char *dev;
+	nvlist_t *schema, *config;
+	int fd;
+
+	dev = find_device(filename);
+	fd = open(dev, O_RDWR);
+	if (fd < 0)
+		err(1, "Could not open device '%s'", dev);
+
+	schema = get_schema(fd);
+	config = parse_config_file(filename, schema);
+	if (config == NULL)
+		errx(1, "Could not parse config");
+
+	config_iov(fd, dev, config, dryrun);
+
+	nvlist_destroy(config);
+	nvlist_destroy(schema);
+	free(dev);
+	close(fd);
+}
+
+static void
+delete_action(const char *dev_name, int dryrun)
+{
+	int fd, error;
+
+	fd = open_device(dev_name);
+
+	if (dryrun)
+		printf("Would attempt to delete all VF children of '%s'\n",
+		    dev_name);
+	else {
+		error = ioctl(fd, IOV_DELETE);
+		if (error != 0)
+			err(1, "Failed to delete VFs");
+	}
+
+	close(fd);
+}
+
+static void
+print_default_value(const nvlist_t *parameter, const char *type)
+{
+	const uint8_t *mac;
+	size_t size;
+
+	if (strcasecmp(type, "bool") == 0)
+		printf(" (default = %s)",
+		    nvlist_get_bool(parameter, DEFAULT_SCHEMA_NAME) ? "true" :
+		    "false");
+	else if (strcasecmp(type, "string") == 0)
+		printf(" (default = %s)",
+		    nvlist_get_string(parameter, DEFAULT_SCHEMA_NAME));
+	else if (strcasecmp(type, "uint8_t") == 0)
+		printf(" (default = %ju)",
+		    (uintmax_t)nvlist_get_number(parameter,
+		    DEFAULT_SCHEMA_NAME));
+	else if (strcasecmp(type, "uint16_t") == 0)
+		printf(" (default = %ju)",
+		    (uintmax_t)nvlist_get_number(parameter,
+		    DEFAULT_SCHEMA_NAME));
+	else if (strcasecmp(type, "uint32_t") == 0)
+		printf(" (default = %ju)",
+		    (uintmax_t)nvlist_get_number(parameter,
+		    DEFAULT_SCHEMA_NAME));
+	else if (strcasecmp(type, "uint64_t") == 0)
+		printf(" (default = %ju)",
+		    (uintmax_t)nvlist_get_number(parameter,
+		    DEFAULT_SCHEMA_NAME));
+	else if (strcasecmp(type, "unicast-mac") == 0) {
+		mac = nvlist_get_binary(parameter, DEFAULT_SCHEMA_NAME, &size);
+		printf(" (default = %02x:%02x:%02x:%02x:%02x:%02x)", mac[0],
+		    mac[1], mac[2], mac[3], mac[4], mac[5]);
+	} else
+		errx(1, "Unexpected type in schema: '%s'", type);
+}
+
+static void
+print_subsystem_schema(const nvlist_t * subsystem_schema)
+{
+	const char *name, *type;
+	const nvlist_t *parameter;
+	void *it;
+	int nvtype;
+
+	it = NULL;
+	while ((name = nvlist_next(subsystem_schema, &nvtype, &it)) != NULL) {
+		parameter = nvlist_get_nvlist(subsystem_schema, name);
+		type = nvlist_get_string(parameter, TYPE_SCHEMA_NAME);
+
+		printf("\t%s : %s", name, type);
+		if (dnvlist_get_bool(parameter, REQUIRED_SCHEMA_NAME, false))
+			printf(" (required)");
+		else if (nvlist_exists(parameter, DEFAULT_SCHEMA_NAME))
+			print_default_value(parameter, type);
+		else
+			printf(" (optional)");
+		printf("\n");
+	}
+}
+
+static void
+print_schema(const char *dev_name)
+{
+	nvlist_t *schema;
+	const nvlist_t *iov_schema, *driver_schema, *pf_schema, *vf_schema;
+	int fd;
+
+	fd = open_device(dev_name);
+	schema = get_schema(fd);
+
+	pf_schema = nvlist_get_nvlist(schema, PF_CONFIG_NAME);
+	iov_schema = nvlist_get_nvlist(pf_schema, IOV_CONFIG_NAME);
+	driver_schema = nvlist_get_nvlist(pf_schema, DRIVER_CONFIG_NAME);
+	printf(
+"The following configuration parameters may be configured on the PF:\n");
+	print_subsystem_schema(iov_schema);
+	print_subsystem_schema(driver_schema);
+
+	vf_schema = nvlist_get_nvlist(schema, VF_SCHEMA_NAME);
+	iov_schema = nvlist_get_nvlist(vf_schema, IOV_CONFIG_NAME);
+	driver_schema = nvlist_get_nvlist(vf_schema, DRIVER_CONFIG_NAME);
+	printf(
+"\nThe following configuration parameters may be configured on a VF:\n");
+	print_subsystem_schema(iov_schema);
+	print_subsystem_schema(driver_schema);
+
+	nvlist_destroy(schema);
+	close(fd);
+}

Copied and modified: user/ngie/stable-10-libnv/usr.sbin/iovctl/iovctl.conf.5 (from r279458, head/usr.sbin/iovctl/iovctl.conf.5)
==============================================================================
--- head/usr.sbin/iovctl/iovctl.conf.5	Sun Mar  1 00:52:21 2015	(r279458, copy source)
+++ user/ngie/stable-10-libnv/usr.sbin/iovctl/iovctl.conf.5	Sun Jan  3 06:51:57 2016	(r293078)
@@ -91,7 +91,7 @@ An individual VF section may override a 
 providing a different value for the configuration parameter.
 Note that the default section applies to ALL VFs.
 The default section must appear before any VF sections.
-The default may appear before or after the PF section.
+The default section may appear before or after the PF section.
 .Pp
 The following option types are supported:
 .Bl -tag -width indent

Copied: user/ngie/stable-10-libnv/usr.sbin/iovctl/iovctl.h (from r279461, head/usr.sbin/iovctl/iovctl.h)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/ngie/stable-10-libnv/usr.sbin/iovctl/iovctl.h	Sun Jan  3 06:51:57 2016	(r293078, copy of r279461, head/usr.sbin/iovctl/iovctl.h)
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2013-2015 Sandvine Inc.  All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef IOVCTL_H
+#define IOVCTL_H
+
+char *		find_device(const char *);
+nvlist_t *	parse_config_file(const char *, const nvlist_t *);
+void		validate_config(nvlist_t *, const nvlist_t *, const regex_t *);
+
+#endif
+

Copied: user/ngie/stable-10-libnv/usr.sbin/iovctl/parse.c (from r279460, head/usr.sbin/iovctl/parse.c)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/ngie/stable-10-libnv/usr.sbin/iovctl/parse.c	Sun Jan  3 06:51:57 2016	(r293078, copy of r279460, head/usr.sbin/iovctl/parse.c)
@@ -0,0 +1,416 @@
+/*-
+ * Copyright (c) 2014-2015 Sandvine Inc.  All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/iov.h>
+#include <net/ethernet.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <nv.h>
+#include <regex.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ucl.h>
+#include <unistd.h>
+
+#include "iovctl.h"
+
+static void
+report_config_error(const char *key, const ucl_object_t *obj, const char *type)
+{
+
+	errx(1, "Value '%s' of key '%s' is not of type %s",
+	    ucl_object_tostring(obj), key, type);
+}
+
+/*
+ * Verifies that the value specified in the config file is a boolean value, and
+ * then adds the value to the configuration.
+ */
+static void
+add_bool_config(const char *key, const ucl_object_t *obj, nvlist_t *config)
+{
+	bool val;
+
+	if (!ucl_object_toboolean_safe(obj, &val))
+		report_config_error(key, obj, "bool");
+
+	nvlist_add_bool(config, key, val);
+}
+
+/*
+ * Verifies that the value specified in the config file is a string, and then
+ * adds the value to the configuration.
+ */
+static void
+add_string_config(const char *key, const ucl_object_t *obj, nvlist_t *config)
+{
+	const char *val;
+
+	if (!ucl_object_tostring_safe(obj, &val))
+		report_config_error(key, obj, "string");
+
+	nvlist_add_string(config, key, val);
+}
+
+/*
+ * Verifies that the value specified in the config file is a integer value
+ * within the specified range, and then adds the value to the configuration.
+ */
+static void
+add_uint_config(const char *key, const ucl_object_t *obj, nvlist_t *config,
+    const char *type, uint64_t max)
+{
+	int64_t val;
+	uint64_t uval;
+
+	/* I must use a signed type here as libucl doesn't provide unsigned. */
+	if (!ucl_object_toint_safe(obj, &val))
+		report_config_error(key, obj, type);
+
+	if (val < 0)
+		report_config_error(key, obj, type);
+
+	uval = val;
+	if (uval > max)
+		report_config_error(key, obj, type);
+
+	nvlist_add_number(config, key, uval);
+}
+
+/*
+ * Verifies that the value specified in the config file is a unicast MAC
+ * address, and then adds the value to the configuration.
+ */
+static void
+add_unicast_mac_config(const char *key, const ucl_object_t *obj, nvlist_t *config)
+{
+	uint8_t mac[ETHER_ADDR_LEN];
+	const char *val, *token;
+	char *parse, *orig_parse, *tokpos, *endpos;
+	size_t len;
+	u_long value;
+	int i;
+
+	if (!ucl_object_tostring_safe(obj, &val))
+		report_config_error(key, obj, "unicast-mac");
+
+	parse = strdup(val);
+	orig_parse = parse;
+
+	i = 0;
+	while ((token = strtok_r(parse, ":", &tokpos)) != NULL) {
+		parse = NULL;
+
+		len = strlen(token);
+		if (len < 1 || len > 2)
+			report_config_error(key, obj, "unicast-mac");
+
+		value = strtoul(token, &endpos, 16);
+
+		if (*endpos != '\0')
+			report_config_error(key, obj, "unicast-mac");
+
+		if (value > UINT8_MAX)
+			report_config_error(key, obj, "unicast-mac");
+
+		if (i >= ETHER_ADDR_LEN)
+			report_config_error(key, obj, "unicast-mac");
+
+		mac[i] = value;
+		i++;
+	}
+
+	free(orig_parse);
+
+	if (i != ETHER_ADDR_LEN)
+		report_config_error(key, obj, "unicast-mac");
+
+	if (ETHER_IS_MULTICAST(mac))
+		errx(1, "Value '%s' of key '%s' is a multicast address",
+		    ucl_object_tostring(obj), key);
+
+	nvlist_add_binary(config, key, mac, ETHER_ADDR_LEN);
+}
+
+/*
+ * Validates that the given configuation value has the right type as specified
+ * in the schema, and then adds the value to the configuation node.
+ */
+static void
+add_config(const char *key, const ucl_object_t *obj, nvlist_t *config,
+    const nvlist_t *schema)
+{
+	const char *type;
+
+	type = nvlist_get_string(schema, TYPE_SCHEMA_NAME);
+
+	if (strcasecmp(type, "bool") == 0)
+		add_bool_config(key, obj, config);
+	else if (strcasecmp(type, "string") == 0)
+		add_string_config(key, obj, config);
+	else if (strcasecmp(type, "uint8_t") == 0)
+		add_uint_config(key, obj, config, type, UINT8_MAX);
+	else if (strcasecmp(type, "uint16_t") == 0)
+		add_uint_config(key, obj, config, type, UINT16_MAX);
+	else if (strcasecmp(type, "uint32_t") == 0)
+		add_uint_config(key, obj, config, type, UINT32_MAX);
+	else if (strcasecmp(type, "uint64_t") == 0)
+		add_uint_config(key, obj, config, type, UINT64_MAX);
+	else if (strcasecmp(type, "unicast-mac") == 0)
+		add_unicast_mac_config(key, obj, config);
+	else
+		errx(1, "Unexpected type '%s' in schema", type);
+}
+
+/*
+ * Parses all values specified in a device section in the configuration file,
+ * validates that the key/value pair is valid in the schema, and then adds
+ * the key/value pair to the correct subsystem in the config.
+ */
+static void
+parse_device_config(const ucl_object_t *top, nvlist_t *config,
+    const char *subsystem, const nvlist_t *schema)
+{
+	ucl_object_iter_t it;
+	const ucl_object_t *obj;
+	nvlist_t *subsystem_config, *driver_config, *iov_config;
+	const nvlist_t *driver_schema, *iov_schema;
+	const char *key;
+
+	if (nvlist_exists(config, subsystem))
+		errx(1, "Multiple definitions of '%s' in config file",
+		    subsystem);
+
+	driver_schema = nvlist_get_nvlist(schema, DRIVER_CONFIG_NAME);
+	iov_schema = nvlist_get_nvlist(schema, IOV_CONFIG_NAME);
+
+	driver_config = nvlist_create(NV_FLAG_IGNORE_CASE);
+	if (driver_config == NULL)
+		err(1, "Could not allocate config nvlist");
+
+	iov_config = nvlist_create(NV_FLAG_IGNORE_CASE);
+	if (iov_config == NULL)
+		err(1, "Could not allocate config nvlist");
+
+	subsystem_config = nvlist_create(NV_FLAG_IGNORE_CASE);
+	if (subsystem_config == NULL)
+		err(1, "Could not allocate config nvlist");
+
+	it = NULL;
+	while ((obj = ucl_iterate_object(top, &it, true)) != NULL) {
+		key = ucl_object_key(obj);
+
+		if (nvlist_exists_nvlist(iov_schema, key))
+			add_config(key, obj, iov_config,
+			    nvlist_get_nvlist(iov_schema, key));
+		else if (nvlist_exists_nvlist(driver_schema, key))
+			add_config(key, obj, driver_config,
+			    nvlist_get_nvlist(driver_schema, key));
+		else
+			errx(1, "%s: Invalid config key '%s'", subsystem, key);
+	}
+
+	nvlist_move_nvlist(subsystem_config, DRIVER_CONFIG_NAME, driver_config);
+	nvlist_move_nvlist(subsystem_config, IOV_CONFIG_NAME, iov_config);
+	nvlist_move_nvlist(config, subsystem, subsystem_config);
+}
+
+/*
+ * Parses the specified config file using the given schema, and returns an
+ * nvlist containing the configuration specified by the file.
+ *
+ * Exits with a message to stderr and an error if any config validation fails.
+ */
+nvlist_t *
+parse_config_file(const char *filename, const nvlist_t *schema)
+{
+	ucl_object_iter_t it;
+	struct ucl_parser *parser;
+	ucl_object_t *top;
+	const ucl_object_t *obj;
+	nvlist_t *config;
+	const nvlist_t *pf_schema, *vf_schema;
+	const char *errmsg, *key;
+	regex_t vf_pat;
+	int regex_err, processed_vf;
+
+	regex_err = regcomp(&vf_pat, "^"VF_PREFIX"([1-9][0-9]*|0)$",
+	    REG_EXTENDED | REG_ICASE);
+	if (regex_err != 0)
+		errx(1, "Could not compile VF regex");
+
+	parser = ucl_parser_new(0);
+	if (parser == NULL)
+		err(1, "Could not allocate parser");
+
+	if (!ucl_parser_add_file(parser, filename))
+		err(1, "Could not open '%s' for reading", filename);
+
+	errmsg = ucl_parser_get_error(parser);
+	if (errmsg != NULL)
+		errx(1, "Could not parse '%s': %s", filename, errmsg);
+
+	config = nvlist_create(NV_FLAG_IGNORE_CASE);
+	if (config == NULL)
+		err(1, "Could not allocate config nvlist");
+
+	pf_schema = nvlist_get_nvlist(schema, PF_CONFIG_NAME);
+	vf_schema = nvlist_get_nvlist(schema, VF_SCHEMA_NAME);
+
+	processed_vf = 0;
+	top = ucl_parser_get_object(parser);
+	it = NULL;
+	while ((obj = ucl_iterate_object(top, &it, true)) != NULL) {
+		key = ucl_object_key(obj);
+
+		if (strcasecmp(key, PF_CONFIG_NAME) == 0)
+			parse_device_config(obj, config, key, pf_schema);
+		else if (strcasecmp(key, DEFAULT_SCHEMA_NAME) == 0) {
+			/*
+			 * Enforce that the default section must come before all
+			 * VF sections.  This will hopefully prevent confusing
+			 * the user by having a default value apply to a VF
+			 * that was declared earlier in the file.
+			 *
+			 * This also gives us the flexibility to extend the file
+			 * format in the future to allow for multiple default
+			 * sections that do only apply to subsequent VF
+			 * sections.
+			 */
+			if (processed_vf)
+				errx(1,
+			"'default' section must precede all VF sections");
+
+			parse_device_config(obj, config, key, vf_schema);
+		} else if (regexec(&vf_pat, key, 0, NULL, 0) == 0) {
+			processed_vf = 1;
+			parse_device_config(obj, config, key, vf_schema);
+		} else
+			errx(1, "Unexpected top-level node: %s", key);
+	}
+
+	validate_config(config, schema, &vf_pat);
+
+	ucl_object_unref(top);
+	ucl_parser_free(parser);
+	regfree(&vf_pat);
+
+	return (config);
+}
+
+/*
+ * Parse the PF configuration section for and return the value specified for
+ * the device parameter, or NULL if the device is not specified.
+ */
+static const char *
+find_pf_device(const ucl_object_t *pf)
+{
+	ucl_object_iter_t it;
+	const ucl_object_t *obj;
+	const char *key, *device;
+
+	it = NULL;
+	while ((obj = ucl_iterate_object(pf, &it, true)) != NULL) {
+		key = ucl_object_key(obj);
+
+		if (strcasecmp(key, "device") == 0) {
+			if (!ucl_object_tostring_safe(obj, &device))
+				err(1,
+				    "Config PF.device must be a string");
+
+			return (device);
+		}
+	}
+
+	return (NULL);
+}
+
+/*
+ * Manually parse the config file looking for the name of the PF device.  We
+ * have to do this separately because we need the config schema to call the
+ * normal config file parsing code, and we need to know the name of the PF
+ * device so that we can fetch the schema from it.
+ *
+ * This will always exit on failure, so if it returns then it is guaranteed to
+ * have returned a valid device name.
+ */
+char *
+find_device(const char *filename)
+{
+	char *device;
+	const char *deviceName;
+	ucl_object_iter_t it;
+	struct ucl_parser *parser;
+	ucl_object_t *top;
+	const ucl_object_t *obj;
+	const char *errmsg, *key;
+	int error;
+
+	device = NULL;
+	deviceName = NULL;
+
+	parser = ucl_parser_new(0);
+	if (parser == NULL)
+		err(1, "Could not allocate parser");
+
+	if (!ucl_parser_add_file(parser, filename))
+		err(1, "Could not open '%s' for reading", filename);
+
+	errmsg = ucl_parser_get_error(parser);
+	if (errmsg != NULL)
+		errx(1, "Could not parse '%s': %s", filename, errmsg);
+
+	top = ucl_parser_get_object (parser);
+	it = NULL;
+	while ((obj = ucl_iterate_object(top, &it, true)) != NULL) {
+		key = ucl_object_key(obj);
+
+		if (strcasecmp(key, PF_CONFIG_NAME) == 0) {
+			deviceName = find_pf_device(obj);
+			break;
+		}
+	}
+
+	if (deviceName == NULL)
+		errx(1, "Config file does not specify device");
+
+	error = asprintf(&device, "/dev/iov/%s", deviceName);
+	if (error < 0)
+		err(1, "Could not allocate memory for device");
+
+	ucl_object_unref(top);
+	ucl_parser_free(parser);
+
+	return (device);
+}

Copied: user/ngie/stable-10-libnv/usr.sbin/iovctl/validate.c (from r279459, head/usr.sbin/iovctl/validate.c)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/ngie/stable-10-libnv/usr.sbin/iovctl/validate.c	Sun Jan  3 06:51:57 2016	(r293078, copy of r279459, head/usr.sbin/iovctl/validate.c)
@@ -0,0 +1,274 @@
+/*-
+ * Copyright (c) 2014-2015 Sandvine Inc.  All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201601030651.u036pvld085688>