Page MenuHomeFreeBSD

D4767.diff
No OneTemporary

D4767.diff

This file is larger than 256 KB, so syntax highlighting was skipped.
Index: ObsoleteFiles.inc
===================================================================
--- ObsoleteFiles.inc
+++ ObsoleteFiles.inc
@@ -78,6 +78,72 @@
OLD_FILES+=usr/share/man/man9/MFREE.9.gz
# 20151023: unused sgsmsg utility is removed
OLD_FILES+=usr/bin/sgsmsg
+# 20150702: Remove duplicated nvlist includes.
+OLD_FILES+=usr/include/dnv.h
+OLD_FILES+=usr/include/nv.h
+# 20150604: Move nvlist man pages to section 9.
+OLD_FILES+=usr/share/man/man3/libnv.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_add_binary.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_add_bool.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_add_descriptor.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_add_null.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_add_number.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_add_nvlist.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_add_string.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_add_stringf.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_add_stringv.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_clone.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_create.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_destroy.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_dump.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_empty.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_error.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_exists.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_exists_binary.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_exists_bool.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_exists_descriptor.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_exists_null.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_exists_number.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_exists_nvlist.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_exists_string.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_exists_type.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_fdump.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_flags.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_free.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_free_binary.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_free_bool.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_free_descriptor.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_free_null.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_free_number.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_free_nvlist.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_free_string.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_free_type.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_get_binary.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_get_bool.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_get_descriptor.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_get_number.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_get_nvlist.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_get_parent.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_get_string.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_move_binary.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_move_descriptor.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_move_nvlist.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_move_string.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_next.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_pack.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_recv.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_send.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_set_error.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_size.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_take_binary.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_take_bool.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_take_descriptor.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_take_number.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_take_nvlist.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_take_string.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_unpack.3.gz
+OLD_FILES+=usr/share/man/man3/nvlist_xfer.3.gz
# 20150506
OLD_FILES+=usr/share/man/man9/NDHASGIANT.9.gz
# 20141223: remove in6_gif.h and in_gif.h
Index: etc/defaults/rc.conf
===================================================================
--- etc/defaults/rc.conf
+++ etc/defaults/rc.conf
@@ -683,6 +683,8 @@
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) ##########
##############################################################
Index: etc/rc.d/Makefile
===================================================================
--- etc/rc.d/Makefile
+++ etc/rc.d/Makefile
@@ -44,6 +44,7 @@
hostid_save \
hostname \
initrandom \
+ iovctl \
ip6addrctl \
ipfilter \
ipfs \
Index: etc/rc.d/iovctl
===================================================================
--- etc/rc.d/iovctl
+++ etc/rc.d/iovctl
@@ -0,0 +1,39 @@
+#!/bin/sh
+#
+# $FreeBSD$
+#
+
+# PROVIDE: iovctl
+# REQUIRE: FILESYSTEMS sysctl
+
+. /etc/rc.subr
+
+name="iovctl"
+command="/usr/sbin/iovctl"
+start_cmd="iovctl_start"
+stop_cmd="iovctl_stop"
+
+run_iovctl()
+{
+ local _f flag
+
+ flag=$1
+ for _f in ${iovctl_files} ; do
+ if [ -r ${_f} ]; then
+ ${command} ${flag} -f ${_f} > /dev/null
+ fi
+ done
+}
+
+iovctl_start()
+{
+ run_iovctl -C
+}
+
+iovctl_stop()
+{
+ run_iovctl -D
+}
+
+load_rc_config $name
+run_rc_command "$1"
Index: etc/rc.d/netif
===================================================================
--- etc/rc.d/netif
+++ etc/rc.d/netif
@@ -26,7 +26,7 @@
#
# PROVIDE: netif
-# REQUIRE: atm1 FILESYSTEMS serial sppp sysctl
+# REQUIRE: atm1 FILESYSTEMS iovctl serial sppp sysctl
# REQUIRE: ipfilter ipfs
# KEYWORD: nojailvnet
Index: lib/libnv/Makefile
===================================================================
--- lib/libnv/Makefile
+++ lib/libnv/Makefile
@@ -7,82 +7,14 @@
LIB= nv
SHLIB_MAJOR= 0
-.PATH: ${.CURDIR}/../../sys/kern ${.CURDIR}/../../sys/sys
+.PATH: ${.CURDIR}/../../sys/contrib/libnv ${.CURDIR}/../../sys/sys
CFLAGS+=-I${.CURDIR}/../../sys -I${.CURDIR}
-SRCS= subr_dnvlist.c
+SRCS= dnvlist.c
SRCS+= msgio.c
-SRCS+= subr_nvlist.c
-SRCS+= subr_nvpair.c
+SRCS+= nvlist.c
+SRCS+= nvpair.c
-INCS= dnv.h
-INCS+= nv.h
-
-MAN+= nv.3
-
-MLINKS+=nv.3 libnv.3 \
- nv.3 nvlist.3
-MLINKS+=nv.3 nvlist_add_binary.3 \
- nv.3 nvlist_add_bool.3 \
- nv.3 nvlist_add_descriptor.3 \
- nv.3 nvlist_add_null.3 \
- nv.3 nvlist_add_number.3 \
- nv.3 nvlist_add_nvlist.3 \
- nv.3 nvlist_add_string.3 \
- nv.3 nvlist_add_stringf.3 \
- nv.3 nvlist_add_stringv.3 \
- nv.3 nvlist_clone.3 \
- nv.3 nvlist_create.3 \
- nv.3 nvlist_destroy.3 \
- nv.3 nvlist_dump.3 \
- nv.3 nvlist_empty.3 \
- nv.3 nvlist_error.3 \
- nv.3 nvlist_exists.3 \
- nv.3 nvlist_exists_binary.3 \
- nv.3 nvlist_exists_bool.3 \
- nv.3 nvlist_exists_descriptor.3 \
- nv.3 nvlist_exists_null.3 \
- nv.3 nvlist_exists_number.3 \
- nv.3 nvlist_exists_nvlist.3 \
- nv.3 nvlist_exists_string.3 \
- nv.3 nvlist_exists_type.3 \
- nv.3 nvlist_fdump.3 \
- nv.3 nvlist_flags.3 \
- nv.3 nvlist_free.3 \
- nv.3 nvlist_free_binary.3 \
- nv.3 nvlist_free_bool.3 \
- nv.3 nvlist_free_descriptor.3 \
- nv.3 nvlist_free_null.3 \
- nv.3 nvlist_free_number.3 \
- nv.3 nvlist_free_nvlist.3 \
- nv.3 nvlist_free_string.3 \
- nv.3 nvlist_free_type.3 \
- nv.3 nvlist_get_binary.3 \
- nv.3 nvlist_get_bool.3 \
- nv.3 nvlist_get_descriptor.3 \
- nv.3 nvlist_get_number.3 \
- nv.3 nvlist_get_nvlist.3 \
- nv.3 nvlist_get_parent.3 \
- nv.3 nvlist_get_string.3 \
- nv.3 nvlist_move_binary.3 \
- nv.3 nvlist_move_descriptor.3 \
- nv.3 nvlist_move_nvlist.3 \
- nv.3 nvlist_move_string.3 \
- nv.3 nvlist_next.3 \
- nv.3 nvlist_pack.3 \
- nv.3 nvlist_recv.3 \
- nv.3 nvlist_send.3 \
- nv.3 nvlist_set_error.3 \
- nv.3 nvlist_size.3 \
- nv.3 nvlist_take_binary.3 \
- nv.3 nvlist_take_bool.3 \
- nv.3 nvlist_take_descriptor.3 \
- nv.3 nvlist_take_number.3 \
- nv.3 nvlist_take_nvlist.3 \
- nv.3 nvlist_take_string.3 \
- nv.3 nvlist_unpack.3 \
- nv.3 nvlist_xfer.3
-
WARNS?= 6
.if ${MK_TESTS} != "no"
Index: lib/libnv/nv.3
===================================================================
--- lib/libnv/nv.3
+++ lib/libnv/nv.3
@@ -1,653 +0,0 @@
-.\"
-.\" Copyright (c) 2013 The FreeBSD Foundation
-.\" All rights reserved.
-.\"
-.\" This documentation was written by Pawel Jakub Dawidek under sponsorship
-.\" the FreeBSD Foundation.
-.\"
-.\" 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$
-.\"
-.Dd May 1, 2015
-.Dt NV 3
-.Os
-.Sh NAME
-.Nm nvlist_create ,
-.Nm nvlist_destroy ,
-.Nm nvlist_error ,
-.Nm nvlist_set_error ,
-.Nm nvlist_empty ,
-.Nm nvlist_flags ,
-.Nm nvlist_exists ,
-.Nm nvlist_free ,
-.Nm nvlist_clone ,
-.Nm nvlist_dump ,
-.Nm nvlist_fdump ,
-.Nm nvlist_size ,
-.Nm nvlist_pack ,
-.Nm nvlist_unpack ,
-.Nm nvlist_send ,
-.Nm nvlist_recv ,
-.Nm nvlist_xfer ,
-.Nm nvlist_next ,
-.Nm nvlist_add ,
-.Nm nvlist_move ,
-.Nm nvlist_get ,
-.Nm nvlist_take
-.Nd "library for name/value pairs"
-.Sh LIBRARY
-.Lb libnv
-.Sh SYNOPSIS
-.In nv.h
-.Ft "nvlist_t *"
-.Fn nvlist_create "int flags"
-.Ft void
-.Fn nvlist_destroy "nvlist_t *nvl"
-.Ft int
-.Fn nvlist_error "const nvlist_t *nvl"
-.Ft void
-.Fn nvlist_set_error "nvlist_t *nvl, int error"
-.Ft bool
-.Fn nvlist_empty "const nvlist_t *nvl"
-.Ft int
-.Fn nvlist_flags "const nvlist_t *nvl"
-.\"
-.Ft "nvlist_t *"
-.Fn nvlist_clone "const nvlist_t *nvl"
-.\"
-.Ft void
-.Fn nvlist_dump "const nvlist_t *nvl, int fd"
-.Ft void
-.Fn nvlist_fdump "const nvlist_t *nvl, FILE *fp"
-.\"
-.Ft size_t
-.Fn nvlist_size "const nvlist_t *nvl"
-.Ft "void *"
-.Fn nvlist_pack "const nvlist_t *nvl" "size_t *sizep"
-.Ft "nvlist_t *"
-.Fn nvlist_unpack "const void *buf" "size_t size"
-.\"
-.Ft int
-.Fn nvlist_send "int sock" "const nvlist_t *nvl"
-.Ft "nvlist_t *"
-.Fn nvlist_recv "int sock"
-.Ft "nvlist_t *"
-.Fn nvlist_xfer "int sock" "nvlist_t *nvl"
-.\"
-.Ft "const char *"
-.Fn nvlist_next "const nvlist_t *nvl" "int *typep" "void **cookiep"
-.\"
-.Ft bool
-.Fn nvlist_exists "const nvlist_t *nvl" "const char *name"
-.Ft bool
-.Fn nvlist_exists_type "const nvlist_t *nvl" "const char *name" "int type"
-.Ft bool
-.Fn nvlist_exists_null "const nvlist_t *nvl" "const char *name"
-.Ft bool
-.Fn nvlist_exists_bool "const nvlist_t *nvl" "const char *name"
-.Ft bool
-.Fn nvlist_exists_number "const nvlist_t *nvl" "const char *name"
-.Ft bool
-.Fn nvlist_exists_string "const nvlist_t *nvl" "const char *name"
-.Ft bool
-.Fn nvlist_exists_nvlist "const nvlist_t *nvl" "const char *name"
-.Ft bool
-.Fn nvlist_exists_descriptor "const nvlist_t *nvl" "const char *name"
-.Ft bool
-.Fn nvlist_exists_binary "const nvlist_t *nvl" "const char *name"
-.\"
-.Ft void
-.Fn nvlist_add_null "nvlist_t *nvl" "const char *name"
-.Ft void
-.Fn nvlist_add_bool "nvlist_t *nvl" "const char *name" "bool value"
-.Ft void
-.Fn nvlist_add_number "nvlist_t *nvl" "const char *name" "uint64_t value"
-.Ft void
-.Fn nvlist_add_string "nvlist_t *nvl" "const char *name" "const char *value"
-.Ft void
-.Fn nvlist_add_stringf "nvlist_t *nvl" "const char *name" "const char *valuefmt" "..."
-.Ft void
-.Fn nvlist_add_stringv "nvlist_t *nvl" "const char *name" "const char *valuefmt" "va_list valueap"
-.Ft void
-.Fn nvlist_add_nvlist "nvlist_t *nvl" "const char *name" "const nvlist_t *value"
-.Ft void
-.Fn nvlist_add_descriptor "nvlist_t *nvl" "const char *name" "int value"
-.Ft void
-.Fn nvlist_add_binary "nvlist_t *nvl" "const char *name" "const void *value" "size_t size"
-.\"
-.Ft void
-.Fn nvlist_move_string "nvlist_t *nvl" "const char *name" "char *value"
-.Ft void
-.Fn nvlist_move_nvlist "nvlist_t *nvl" "const char *name" "nvlist_t *value"
-.Ft void
-.Fn nvlist_move_descriptor "nvlist_t *nvl" "const char *name" "int value"
-.Ft void
-.Fn nvlist_move_binary "nvlist_t *nvl" "const char *name" "void *value" "size_t size"
-.\"
-.Ft bool
-.Fn nvlist_get_bool "const nvlist_t *nvl" "const char *name"
-.Ft uint64_t
-.Fn nvlist_get_number "const nvlist_t *nvl" "const char *name"
-.Ft "const char *"
-.Fn nvlist_get_string "const nvlist_t *nvl" "const char *name"
-.Ft "const nvlist_t *"
-.Fn nvlist_get_nvlist "const nvlist_t *nvl" "const char *name"
-.Ft int
-.Fn nvlist_get_descriptor "const nvlist_t *nvl" "const char *name"
-.Ft "const void *"
-.Fn nvlist_get_binary "const nvlist_t *nvl" "const char *name" "size_t *sizep"
-.Ft "const nvlist_t *"
-.Fn nvlist_get_parent "const nvlist_t *nvl" "void **cookiep"
-.\"
-.Ft bool
-.Fn nvlist_take_bool "nvlist_t *nvl" "const char *name"
-.Ft uint64_t
-.Fn nvlist_take_number "nvlist_t *nvl" "const char *name"
-.Ft "char *"
-.Fn nvlist_take_string "nvlist_t *nvl" "const char *name"
-.Ft "nvlist_t *"
-.Fn nvlist_take_nvlist "nvlist_t *nvl" "const char *name"
-.Ft int
-.Fn nvlist_take_descriptor "nvlist_t *nvl" "const char *name"
-.Ft "void *"
-.Fn nvlist_take_binary "nvlist_t *nvl" "const char *name" "size_t *sizep"
-.\"
-.Ft void
-.Fn nvlist_free "nvlist_t *nvl" "const char *name"
-.Ft void
-.Fn nvlist_free_type "nvlist_t *nvl" "const char *name" "int type"
-.\"
-.Ft void
-.Fn nvlist_free_null "nvlist_t *nvl" "const char *name"
-.Ft void
-.Fn nvlist_free_bool "nvlist_t *nvl" "const char *name"
-.Ft void
-.Fn nvlist_free_number "nvlist_t *nvl" "const char *name"
-.Ft void
-.Fn nvlist_free_string "nvlist_t *nvl" "const char *name"
-.Ft void
-.Fn nvlist_free_nvlist "nvlist_t *nvl" "const char *name"
-.Ft void
-.Fn nvlist_free_descriptor "nvlist_t *nvl" "const char *name"
-.Ft void
-.Fn nvlist_free_binary "nvlist_t *nvl" "const char *name"
-.Sh DESCRIPTION
-The
-.Nm libnv
-library allows to easily manage name value pairs as well as send and receive
-them over sockets.
-A group (list) of name value pairs is called an
-.Nm nvlist .
-The API supports the following data types:
-.Bl -ohang -offset indent
-.It Sy null ( NV_TYPE_NULL )
-There is no data associated with the name.
-.It Sy bool ( NV_TYPE_BOOL )
-The value can be either
-.Dv true
-or
-.Dv false .
-.It Sy number ( NV_TYPE_NUMBER )
-The value is a number stored as
-.Vt uint64_t .
-.It Sy string ( NV_TYPE_STRING )
-The value is a C string.
-.It Sy nvlist ( NV_TYPE_NVLIST )
-The value is a nested nvlist.
-.It Sy descriptor ( NV_TYPE_DESCRIPTOR )
-The value is a file descriptor.
-Note that file descriptors can be sent only over
-.Xr unix 4
-domain sockets.
-.It Sy binary ( NV_TYPE_BINARY )
-The value is a binary buffer.
-.El
-.Pp
-The
-.Fn nvlist_create
-function allocates memory and initializes an nvlist.
-.Pp
-The following flag can be provided:
-.Pp
-.Bl -tag -width "NV_FLAG_IGNORE_CASE" -compact -offset indent
-.It Dv NV_FLAG_IGNORE_CASE
-Perform case-insensitive lookups of provided names.
-.El
-.Pp
-The
-.Fn nvlist_destroy
-function destroys the given nvlist.
-Function does nothing if
-.Dv NULL
-nvlist is provided.
-Function never modifies the
-.Va errno
-global variable.
-.Pp
-The
-.Fn nvlist_error
-function returns any error value that the nvlist accumulated.
-If the given nvlist is
-.Dv NULL
-the
-.Er ENOMEM
-error will be returned.
-.Pp
-The
-.Fn nvlist_set_error
-function sets an nvlist to be in the error state.
-Subsequent calls to
-.Fn nvlist_error
-will return the given error value.
-This function cannot be used to clear the error state from an nvlist.
-This function does nothing if the nvlist is already in the error state.
-.Pp
-The
-.Fn nvlist_empty
-function returns
-.Dv true
-if the given nvlist is empty and
-.Dv false
-otherwise.
-The nvlist must not be in error state.
-.Pp
-The
-.Fn nvlist_flags
-function returns flags used to create the nvlist with the
-.Fn nvlist_create
-function.
-.Pp
-The
-.Fn nvlist_clone
-functions clones the given nvlist.
-The clone shares no resources with its origin.
-This also means that all file descriptors that are part of the nvlist will be
-duplicated with the
-.Xr dup 2
-system call before placing them in the clone.
-.Pp
-The
-.Fn nvlist_dump
-dumps nvlist content for debugging purposes to the given file descriptor
-.Fa fd .
-.Pp
-The
-.Fn nvlist_fdump
-dumps nvlist content for debugging purposes to the given file stream
-.Fa fp .
-.Pp
-The
-.Fn nvlist_size
-function returns the size of the given nvlist after converting it to binary
-buffer with the
-.Fn nvlist_pack
-function.
-.Pp
-The
-.Fn nvlist_pack
-function converts the given nvlist to a binary buffer.
-The function allocates memory for the buffer, which should be freed with the
-.Xr free 3
-function.
-If the
-.Fa sizep
-argument is not
-.Dv NULL ,
-the size of the buffer will be stored there.
-The function returns
-.Dv NULL
-in case of an error (allocation failure).
-If the nvlist contains any file descriptors
-.Dv NULL
-will be returned.
-The nvlist must not be in error state.
-.Pp
-The
-.Fn nvlist_unpack
-function converts the given buffer to the nvlist.
-The function returns
-.Dv NULL
-in case of an error.
-.Pp
-The
-.Fn nvlist_send
-function sends the given nvlist over the socket given by the
-.Fa sock
-argument.
-Note that nvlist that contains file descriptors can only be send over
-.Xr unix 4
-domain sockets.
-.Pp
-The
-.Fn nvlist_recv
-function receives nvlist over the socket given by the
-.Fa sock
-argument.
-.Pp
-The
-.Fn nvlist_xfer
-function sends the given nvlist over the socket given by the
-.Fa sock
-argument and receives nvlist over the same socket.
-The given nvlist is always destroyed.
-.Pp
-The
-.Fn nvlist_next
-function iterates over the given nvlist returning names and types of subsequent
-elements.
-The
-.Fa cookiep
-argument allows the function to figure out which element should be returned
-next.
-The
-.Va *cookiep
-should be set to
-.Dv NULL
-for the first call and should not be changed later.
-Returning
-.Dv NULL
-means there are no more elements on the nvlist.
-The
-.Fa typep
-argument can be NULL.
-Elements may not be removed from the nvlist while traversing it.
-The nvlist must not be in error state.
-.Pp
-The
-.Fn nvlist_exists
-function returns
-.Dv true
-if element of the given name exists (besides of its type) or
-.Dv false
-otherwise.
-The nvlist must not be in error state.
-.Pp
-The
-.Fn nvlist_exists_type
-function returns
-.Dv true
-if element of the given name and the given type exists or
-.Dv false
-otherwise.
-The nvlist must not be in error state.
-.Pp
-The
-.Fn nvlist_exists_null ,
-.Fn nvlist_exists_bool ,
-.Fn nvlist_exists_number ,
-.Fn nvlist_exists_string ,
-.Fn nvlist_exists_nvlist ,
-.Fn nvlist_exists_descriptor ,
-.Fn nvlist_exists_binary
-functions return
-.Dv true
-if element of the given name and the given type determined by the function name
-exists or
-.Dv false
-otherwise.
-The nvlist must not be in error state.
-.Pp
-The
-.Fn nvlist_add_null ,
-.Fn nvlist_add_bool ,
-.Fn nvlist_add_number ,
-.Fn nvlist_add_string ,
-.Fn nvlist_add_stringf ,
-.Fn nvlist_add_stringv ,
-.Fn nvlist_add_nvlist ,
-.Fn nvlist_add_descriptor ,
-.Fn nvlist_add_binary
-functions add element to the given nvlist.
-When adding string or binary buffor the functions will allocate memory
-and copy the data over.
-When adding nvlist, the nvlist will be cloned and clone will be added.
-When adding descriptor, the descriptor will be duplicated using the
-.Xr dup 2
-system call and the new descriptor will be added.
-If an error occurs while adding new element, internal error is set which can be
-examined using the
-.Fn nvlist_error
-function.
-.Pp
-The
-.Fn nvlist_move_string ,
-.Fn nvlist_move_nvlist ,
-.Fn nvlist_move_descriptor ,
-.Fn nvlist_move_binary
-functions add new element to the given nvlist, but unlike
-.Fn nvlist_add_<type>
-functions they will consume the given resource.
-If an error occurs while adding new element, the resource is destroyed and
-internal error is set which can be examined using the
-.Fn nvlist_error
-function.
-.Pp
-The
-.Fn nvlist_get_bool ,
-.Fn nvlist_get_number ,
-.Fn nvlist_get_string ,
-.Fn nvlist_get_nvlist ,
-.Fn nvlist_get_descriptor ,
-.Fn nvlist_get_binary
-functions allow to obtain value of the given name.
-In case of string, nvlist, descriptor or binary, returned resource should
-not be modified - it still belongs to the nvlist.
-If element of the given name does not exist, the program will be aborted.
-To avoid that the caller should check for existence before trying to obtain
-the value or use
-.Xr dnvlist 3
-extension, which allows to provide default value for a missing element.
-The nvlist must not be in error state.
-.Pp
-The
-.Fn nvlist_get_parent
-function allows to obtain the parent nvlist from the nested nvlist.
-.Pp
-The
-.Fn nvlist_take_bool ,
-.Fn nvlist_take_number ,
-.Fn nvlist_take_string ,
-.Fn nvlist_take_nvlist ,
-.Fn nvlist_take_descriptor ,
-.Fn nvlist_take_binary
-functions return value associated with the given name and remove the element
-from the nvlist.
-In case of string and binary values, the caller is responsible for free returned
-memory using the
-.Xr free 3
-function.
-In case of nvlist, the caller is responsible for destroying returned nvlist
-using the
-.Fn nvlist_destroy
-function.
-In case of descriptor, the caller is responsible for closing returned descriptor
-using the
-.Fn close 2
-system call.
-If element of the given name does not exist, the program will be aborted.
-To avoid that the caller should check for existence before trying to obtain
-the value or use
-.Xr dnvlist 3
-extension, which allows to provide default value for a missing element.
-The nvlist must not be in error state.
-.Pp
-The
-.Fn nvlist_free
-function removes element of the given name from the nvlist (besides of its type)
-and frees all resources associated with it.
-If element of the given name does not exist, the program will be aborted.
-The nvlist must not be in error state.
-.Pp
-The
-.Fn nvlist_free_type
-function removes element of the given name and the given type from the nvlist
-and frees all resources associated with it.
-If element of the given name and the given type does not exist, the program
-will be aborted.
-The nvlist must not be in error state.
-.Pp
-The
-.Fn nvlist_free_null ,
-.Fn nvlist_free_bool ,
-.Fn nvlist_free_number ,
-.Fn nvlist_free_string ,
-.Fn nvlist_free_nvlist ,
-.Fn nvlist_free_descriptor ,
-.Fn nvlist_free_binary
-functions remove element of the given name and the given type determined by the
-function name from the nvlist and free all resources associated with it.
-If element of the given name and the given type does not exist, the program
-will be aborted.
-The nvlist must not be in error state.
-.Sh EXAMPLES
-The following example demonstrates how to prepare an nvlist and send it over
-.Xr unix 4
-domain socket.
-.Bd -literal
-nvlist_t *nvl;
-int fd;
-
-fd = open("/tmp/foo", O_RDONLY);
-if (fd < 0)
- err(1, "open(\\"/tmp/foo\\") failed");
-
-nvl = nvlist_create(0);
-/*
- * There is no need to check if nvlist_create() succeeded,
- * as the nvlist_add_<type>() functions can cope.
- * If it failed, nvlist_send() will fail.
- */
-nvlist_add_string(nvl, "filename", "/tmp/foo");
-nvlist_add_number(nvl, "flags", O_RDONLY);
-/*
- * We just want to send the descriptor, so we can give it
- * for the nvlist to consume (that's why we use nvlist_move
- * not nvlist_add).
- */
-nvlist_move_descriptor(nvl, "fd", fd);
-if (nvlist_send(sock, nvl) < 0) {
- nvlist_destroy(nvl);
- err(1, "nvlist_send() failed");
-}
-nvlist_destroy(nvl);
-.Ed
-.Pp
-Receiving nvlist and getting data:
-.Bd -literal
-nvlist_t *nvl;
-const char *command;
-char *filename;
-int fd;
-
-nvl = nvlist_recv(sock);
-if (nvl == NULL)
- err(1, "nvlist_recv() failed");
-
-/* For command we take pointer to nvlist's buffer. */
-command = nvlist_get_string(nvl, "command");
-/*
- * For filename we remove it from the nvlist and take
- * ownership of the buffer.
- */
-filename = nvlist_take_string(nvl, "filename");
-/* The same for the descriptor. */
-fd = nvlist_take_descriptor(nvl, "fd");
-
-printf("command=%s filename=%s fd=%d\n", command, filename, fd);
-
-nvlist_destroy(nvl);
-free(filename);
-close(fd);
-/* command was freed by nvlist_destroy() */
-.Ed
-.Pp
-Iterating over nvlist:
-.Bd -literal
-nvlist_t *nvl;
-const char *name;
-void *cookie;
-int type;
-
-nvl = nvlist_recv(sock);
-if (nvl == NULL)
- err(1, "nvlist_recv() failed");
-
-cookie = NULL;
-while ((name = nvlist_next(nvl, &type, &cookie)) != NULL) {
- printf("%s=", name);
- switch (type) {
- case NV_TYPE_NUMBER:
- printf("%ju", (uintmax_t)nvlist_get_number(nvl, name));
- break;
- case NV_TYPE_STRING:
- printf("%s", nvlist_get_string(nvl, name));
- break;
- default:
- printf("N/A");
- break;
- }
- printf("\\n");
-}
-.Ed
-.Pp
-Iterating over every nested nvlist:
-.Bd -literal
-nvlist_t *nvl;
-const char *name;
-void *cookie;
-int type;
-
-nvl = nvlist_recv(sock);
-if (nvl == NULL)
- err(1, "nvlist_recv() failed");
-
-cookie = NULL;
-do {
- while ((name = nvlist_next(nvl, &type, &cookie)) != NULL) {
- if (type == NV_TYPE_NVLIST) {
- nvl = nvlist_get_nvlist(nvl, name);
- cookie = NULL;
- }
- }
-} while ((nvl = nvlist_get_parent(nvl, &cookie)) != NULL);
-.Ed
-.Sh SEE ALSO
-.Xr close 2 ,
-.Xr dup 2 ,
-.Xr open 2 ,
-.Xr err 3 ,
-.Xr free 3 ,
-.Xr printf 3 ,
-.Xr unix 4
-.Sh HISTORY
-The
-.Nm libnv
-library appeared in
-.Fx 11.0 .
-.Sh AUTHORS
-.An -nosplit
-The
-.Nm libnv
-library was implemented by
-.An Pawel Jakub Dawidek Aq pawel@dawidek.net
-under sponsorship from the FreeBSD Foundation.
Index: lib/libnv/tests/Makefile
===================================================================
--- lib/libnv/tests/Makefile
+++ lib/libnv/tests/Makefile
@@ -4,6 +4,7 @@
ATF_TESTS_CXX= \
dnv_tests \
+ nv_array_tests \
nv_tests \
TAP_TESTS_C+= nvlist_add_test
Index: lib/libnv/tests/dnv_tests.cc
===================================================================
--- lib/libnv/tests/dnv_tests.cc
+++ lib/libnv/tests/dnv_tests.cc
@@ -27,9 +27,11 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <sys/types.h>
+#include <sys/dnv.h>
+#include <sys/nv.h>
+
#include <atf-c++.hpp>
-#include <dnv.h>
-#include <nv.h>
ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_get_bool__present);
ATF_TEST_CASE_BODY(dnvlist_get_bool__present)
Index: lib/libnv/tests/nv_array_tests.cc
===================================================================
--- lib/libnv/tests/nv_array_tests.cc
+++ lib/libnv/tests/nv_array_tests.cc
@@ -0,0 +1,1196 @@
+/*-
+ * Copyright (c) 2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
+ * 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/types.h>
+#include <sys/nv.h>
+#include <sys/socket.h>
+
+#include <atf-c++.hpp>
+
+#include <cstdio>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits>
+#include <set>
+#include <sstream>
+#include <string>
+
+#define fd_is_valid(fd) (fcntl((fd), F_GETFL) != -1 || errno != EBADF)
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_bool_array__basic);
+ATF_TEST_CASE_BODY(nvlist_bool_array__basic)
+{
+ bool testbool[16];
+ const bool *const_result;
+ bool *result;
+ nvlist_t *nvl;
+ size_t num_items;
+ unsigned int i;
+ const char *key;
+
+ key = "nvl/bool";
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+
+ for (i = 0; i < 16; i++)
+ testbool[i] = (i % 2 == 0);
+
+ nvlist_add_bool_array(nvl, key, testbool, 16);
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_bool_array(nvl, key));
+ ATF_REQUIRE(nvlist_exists_bool_array(nvl, "nvl/bool"));
+
+ const_result = nvlist_get_bool_array(nvl, key, &num_items);
+ ATF_REQUIRE_EQ(num_items, 16);
+ ATF_REQUIRE(const_result != NULL);
+ for (i = 0; i < num_items; i++)
+ ATF_REQUIRE_EQ(const_result[i], testbool[i]);
+
+ result = nvlist_take_bool_array(nvl, key, &num_items);
+ ATF_REQUIRE_EQ(num_items, 16);
+ ATF_REQUIRE(const_result != NULL);
+ for (i = 0; i < num_items; i++)
+ ATF_REQUIRE_EQ(result[i], testbool[i]);
+
+ ATF_REQUIRE(!nvlist_exists_bool_array(nvl, key));
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+
+ free(result);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_string_array__basic);
+ATF_TEST_CASE_BODY(nvlist_string_array__basic)
+{
+ const char * const *const_result;
+ char **result;
+ nvlist_t *nvl;
+ size_t num_items;
+ unsigned int i;
+ const char *key;
+ const char *string_arr[8] = { "a", "b", "kot", "foo",
+ "tests", "nice test", "", "abcdef" };
+
+ key = "nvl/string";
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+
+ nvlist_add_string_array(nvl, key, string_arr, nitems(string_arr));
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_string_array(nvl, key));
+ ATF_REQUIRE(nvlist_exists_string_array(nvl, "nvl/string"));
+
+ const_result = nvlist_get_string_array(nvl, key, &num_items);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(const_result != NULL);
+ ATF_REQUIRE(num_items == nitems(string_arr));
+ for (i = 0; i < num_items; i++) {
+ if (string_arr[i] != NULL) {
+ ATF_REQUIRE(strcmp(const_result[i],
+ string_arr[i]) == 0);
+ } else {
+ ATF_REQUIRE(const_result[i] == string_arr[i]);
+ }
+ }
+
+ result = nvlist_take_string_array(nvl, key, &num_items);
+ ATF_REQUIRE(result != NULL);
+ ATF_REQUIRE_EQ(num_items, nitems(string_arr));
+ for (i = 0; i < num_items; i++) {
+ if (string_arr[i] != NULL) {
+ ATF_REQUIRE_EQ(strcmp(result[i], string_arr[i]), 0);
+ } else {
+ ATF_REQUIRE_EQ(result[i], string_arr[i]);
+ }
+ }
+
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+
+ for (i = 0; i < num_items; i++)
+ free(result[i]);
+ free(result);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_descriptor_array__basic);
+ATF_TEST_CASE_BODY(nvlist_descriptor_array__basic)
+{
+ int fd[32], *result;
+ const int *const_result;
+ nvlist_t *nvl;
+ size_t num_items;
+ unsigned int i;
+ const char *key;
+
+ for (i = 0; i < nitems(fd); i++) {
+ fd[i] = dup(STDERR_FILENO);
+ ATF_REQUIRE(fd_is_valid(fd[i]));
+ }
+
+ key = "nvl/descriptor";
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_descriptor_array(nvl, key));
+
+ nvlist_add_descriptor_array(nvl, key, fd, nitems(fd));
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_descriptor_array(nvl, key));
+ ATF_REQUIRE(nvlist_exists_descriptor_array(nvl, "nvl/descriptor"));
+
+ const_result = nvlist_get_descriptor_array(nvl, key, &num_items);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(const_result != NULL);
+ ATF_REQUIRE(num_items == nitems(fd));
+ for (i = 0; i < num_items; i++) {
+ ATF_REQUIRE(fd_is_valid(const_result[i]));
+ if (i > 0)
+ ATF_REQUIRE(const_result[i] != const_result[i - 1]);
+ }
+
+ result = nvlist_take_descriptor_array(nvl, key, &num_items);
+ ATF_REQUIRE(result != NULL);
+ ATF_REQUIRE_EQ(num_items, nitems(fd));
+ for (i = 0; i < num_items; i++) {
+ ATF_REQUIRE(fd_is_valid(result[i]));
+ if (i > 0)
+ ATF_REQUIRE(const_result[i] != const_result[i - 1]);
+ }
+
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+
+ for (i = 0; i < num_items; i++) {
+ close(result[i]);
+ close(fd[i]);
+ }
+ free(result);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_number_array__basic);
+ATF_TEST_CASE_BODY(nvlist_number_array__basic)
+{
+ const uint64_t *const_result;
+ uint64_t *result;
+ nvlist_t *nvl;
+ size_t num_items;
+ unsigned int i;
+ const char *key;
+ const uint64_t number[8] = { 0, UINT_MAX, 7, 123, 90,
+ 100000, 8, 1 };
+
+ key = "nvl/number";
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+
+ nvlist_add_number_array(nvl, key, number, nitems(number));
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_number_array(nvl, key));
+ ATF_REQUIRE(nvlist_exists_number_array(nvl, "nvl/number"));
+
+ const_result = nvlist_get_number_array(nvl, key, &num_items);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(const_result != NULL);
+ ATF_REQUIRE(num_items == nitems(number));
+ for (i = 0; i < num_items; i++)
+ ATF_REQUIRE_EQ(const_result[i], number[i]);
+
+ result = nvlist_take_number_array(nvl, key, &num_items);
+ ATF_REQUIRE(result != NULL);
+ ATF_REQUIRE_EQ(num_items, nitems(number));
+ for (i = 0; i < num_items; i++)
+ ATF_REQUIRE_EQ(result[i], number[i]);
+
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+
+ free(result);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_nvlist_array__basic);
+ATF_TEST_CASE_BODY(nvlist_nvlist_array__basic)
+{
+ nvlist_t *testnvl[8];
+ const nvlist_t * const *const_result;
+ nvlist_t **result;
+ nvlist_t *nvl;
+ size_t num_items;
+ unsigned int i;
+ const char *somestr[8] = { "a", "b", "c", "d", "e", "f", "g", "h" };
+ const char *key;
+
+ for (i = 0; i < 8; i++) {
+ testnvl[i] = nvlist_create(0);
+ ATF_REQUIRE(testnvl[i] != NULL);
+ ATF_REQUIRE_EQ(nvlist_error(testnvl[i]), 0);
+ nvlist_add_string(testnvl[i], "nvl/string", somestr[i]);
+ ATF_REQUIRE_EQ(nvlist_error(testnvl[i]), 0);
+ ATF_REQUIRE(nvlist_exists_string(testnvl[i], "nvl/string"));
+ }
+
+ key = "nvl/nvlist";
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+
+ nvlist_add_nvlist_array(nvl, key, (const nvlist_t * const *)testnvl, 8);
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_nvlist_array(nvl, key));
+ ATF_REQUIRE(nvlist_exists_nvlist_array(nvl, "nvl/nvlist"));
+
+ const_result = nvlist_get_nvlist_array(nvl, key, &num_items);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(const_result != NULL);
+ ATF_REQUIRE(num_items == nitems(testnvl));
+
+ for (i = 0; i < num_items; i++) {
+ ATF_REQUIRE_EQ(nvlist_error(const_result[i]), 0);
+ if (i < num_items - 1) {
+ ATF_REQUIRE(nvlist_get_array_next(const_result[i]) ==
+ const_result[i + 1]);
+ } else {
+ ATF_REQUIRE(nvlist_get_array_next(const_result[i]) ==
+ NULL);
+ }
+ ATF_REQUIRE(nvlist_get_parent(const_result[i], NULL) == nvl);
+ ATF_REQUIRE(nvlist_in_array(const_result[i]));
+ ATF_REQUIRE(nvlist_exists_string(const_result[i],
+ "nvl/string"));
+ ATF_REQUIRE(strcmp(nvlist_get_string(const_result[i],
+ "nvl/string"), somestr[i]) == 0);
+ }
+
+ result = nvlist_take_nvlist_array(nvl, key, &num_items);
+ ATF_REQUIRE(result != NULL);
+ ATF_REQUIRE_EQ(num_items, 8);
+ for (i = 0; i < num_items; i++) {
+ ATF_REQUIRE_EQ(nvlist_error(result[i]), 0);
+ ATF_REQUIRE(nvlist_get_array_next(result[i]) == NULL);
+ ATF_REQUIRE(nvlist_get_array_next(const_result[i]) == NULL);
+ ATF_REQUIRE(!nvlist_in_array(const_result[i]));
+ }
+
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+
+ for (i = 0; i < 8; i++) {
+ nvlist_destroy(result[i]);
+ nvlist_destroy(testnvl[i]);
+ }
+
+ free(result);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_clone_array);
+ATF_TEST_CASE_BODY(nvlist_clone_array)
+{
+ nvlist_t *testnvl[8];
+ nvlist_t *src, *dst;
+ const nvlist_t *nvl;
+ bool testbool[16];
+ int testfd[16];
+ size_t i, num_items;
+ const char *string_arr[8] = { "a", "b", "kot", "foo",
+ "tests", "nice test", "", "abcdef" };
+ const char *somestr[8] = { "a", "b", "c", "d", "e", "f", "g", "h" };
+ const uint64_t number[8] = { 0, UINT_MAX, 7, 123, 90,
+ 100000, 8, 1 };
+
+ for (i = 0; i < nitems(testfd); i++) {
+ testbool[i] = (i % 2 == 0);
+ testfd[i] = dup(STDERR_FILENO);
+ ATF_REQUIRE(fd_is_valid(testfd[i]));
+ }
+ for (i = 0; i < nitems(testnvl); i++) {
+ testnvl[i] = nvlist_create(0);
+ ATF_REQUIRE(nvlist_error(testnvl[i]) == 0);
+ nvlist_add_string(testnvl[i], "nvl/nvl/teststr", somestr[i]);
+ ATF_REQUIRE(nvlist_error(testnvl[i]) == 0);
+ }
+
+ src = nvlist_create(0);
+ ATF_REQUIRE(nvlist_error(src) == 0);
+
+ ATF_REQUIRE(!nvlist_exists_bool_array(src, "nvl/bool"));
+ nvlist_add_bool_array(src, "nvl/bool", testbool, nitems(testbool));
+ ATF_REQUIRE_EQ(nvlist_error(src), 0);
+ ATF_REQUIRE(nvlist_exists_bool_array(src, "nvl/bool"));
+
+ ATF_REQUIRE(!nvlist_exists_string_array(src, "nvl/string"));
+ nvlist_add_string_array(src, "nvl/string", string_arr,
+ nitems(string_arr));
+ ATF_REQUIRE_EQ(nvlist_error(src), 0);
+ ATF_REQUIRE(nvlist_exists_string_array(src, "nvl/string"));
+
+ ATF_REQUIRE(!nvlist_exists_descriptor_array(src, "nvl/fd"));
+ nvlist_add_descriptor_array(src, "nvl/fd", testfd, nitems(testfd));
+ ATF_REQUIRE_EQ(nvlist_error(src), 0);
+ ATF_REQUIRE(nvlist_exists_descriptor_array(src, "nvl/fd"));
+
+ ATF_REQUIRE(!nvlist_exists_number_array(src, "nvl/number"));
+ nvlist_add_number_array(src, "nvl/number", number,
+ nitems(number));
+ ATF_REQUIRE_EQ(nvlist_error(src), 0);
+ ATF_REQUIRE(nvlist_exists_number_array(src, "nvl/number"));
+
+ ATF_REQUIRE(!nvlist_exists_nvlist_array(src, "nvl/array"));
+ nvlist_add_nvlist_array(src, "nvl/array",
+ (const nvlist_t * const *)testnvl, nitems(testnvl));
+ ATF_REQUIRE_EQ(nvlist_error(src), 0);
+ ATF_REQUIRE(nvlist_exists_nvlist_array(src, "nvl/array"));
+
+ dst = nvlist_clone(src);
+ ATF_REQUIRE(dst != NULL);
+
+ ATF_REQUIRE(nvlist_exists_bool_array(dst, "nvl/bool"));
+ (void) nvlist_get_bool_array(dst, "nvl/bool", &num_items);
+ ATF_REQUIRE_EQ(num_items, nitems(testbool));
+ for (i = 0; i < num_items; i++) {
+ ATF_REQUIRE(
+ nvlist_get_bool_array(dst, "nvl/bool", &num_items)[i] ==
+ nvlist_get_bool_array(src, "nvl/bool", &num_items)[i]);
+ }
+
+ ATF_REQUIRE(nvlist_exists_string_array(dst, "nvl/string"));
+ (void) nvlist_get_string_array(dst, "nvl/string", &num_items);
+ ATF_REQUIRE_EQ(num_items, nitems(string_arr));
+ for (i = 0; i < num_items; i++) {
+ if (nvlist_get_string_array(dst, "nvl/string",
+ &num_items)[i] == NULL) {
+ ATF_REQUIRE(nvlist_get_string_array(dst, "nvl/string",
+ &num_items)[i] == nvlist_get_string_array(src,
+ "nvl/string", &num_items)[i]);
+ } else {
+ ATF_REQUIRE(strcmp(nvlist_get_string_array(dst,
+ "nvl/string", &num_items)[i], nvlist_get_string_array(
+ src, "nvl/string", &num_items)[i]) == 0);
+ }
+ }
+
+ ATF_REQUIRE(nvlist_exists_descriptor_array(dst, "nvl/fd"));
+ (void) nvlist_get_descriptor_array(dst, "nvl/fd", &num_items);
+ ATF_REQUIRE_EQ(num_items, nitems(testfd));
+ for (i = 0; i < num_items; i++) {
+ ATF_REQUIRE(fd_is_valid(
+ nvlist_get_descriptor_array(dst, "nvl/fd", &num_items)[i]));
+ }
+ ATF_REQUIRE(nvlist_exists_number_array(dst, "nvl/number"));
+ (void) nvlist_get_number_array(dst, "nvl/number", &num_items);
+ ATF_REQUIRE_EQ(num_items, nitems(number));
+
+ for (i = 0; i < num_items; i++) {
+ ATF_REQUIRE(
+ nvlist_get_number_array(dst, "nvl/number", &num_items)[i] ==
+ nvlist_get_number_array(src, "nvl/number", &num_items)[i]);
+ }
+
+ ATF_REQUIRE(nvlist_exists_nvlist_array(dst, "nvl/array"));
+ (void) nvlist_get_nvlist_array(dst, "nvl/array", &num_items);
+ ATF_REQUIRE_EQ(num_items, nitems(testnvl));
+ for (i = 0; i < num_items; i++) {
+ nvl = nvlist_get_nvlist_array(dst, "nvl/array", &num_items)[i];
+ ATF_REQUIRE(nvlist_exists_string(nvl, "nvl/nvl/teststr"));
+ ATF_REQUIRE(strcmp(nvlist_get_string(nvl, "nvl/nvl/teststr"),
+ somestr[i]) == 0);
+ }
+
+ for (i = 0; i < nitems(testfd); i++) {
+ close(testfd[i]);
+ }
+ for (i = 0; i < nitems(testnvl); i++) {
+ nvlist_destroy(testnvl[i]);
+ }
+ nvlist_destroy(src);
+ nvlist_destroy(dst);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_bool_array__move);
+ATF_TEST_CASE_BODY(nvlist_bool_array__move)
+{
+ bool *testbool;
+ const bool *const_result;
+ nvlist_t *nvl;
+ size_t num_items, count;
+ unsigned int i;
+ const char *key;
+
+ key = "nvl/bool";
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+
+ count = 16;
+ testbool = (bool*)malloc(sizeof(*testbool) * count);
+ ATF_REQUIRE(testbool != NULL);
+ for (i = 0; i < count; i++)
+ testbool[i] = (i % 2 == 0);
+
+ nvlist_move_bool_array(nvl, key, testbool, count);
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_bool_array(nvl, key));
+
+ const_result = nvlist_get_bool_array(nvl, key, &num_items);
+ ATF_REQUIRE_EQ(num_items, count);
+ ATF_REQUIRE(const_result != NULL);
+ ATF_REQUIRE(const_result == testbool);
+ for (i = 0; i < num_items; i++)
+ ATF_REQUIRE_EQ(const_result[i], (i % 2 == 0));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_string_array__move);
+ATF_TEST_CASE_BODY(nvlist_string_array__move)
+{
+ char **teststr;
+ const char * const *const_result;
+ nvlist_t *nvl;
+ size_t num_items, count;
+ unsigned int i;
+ const char *key;
+
+ key = "nvl/string";
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+
+ count = 26;
+ teststr = (char**)malloc(sizeof(*teststr) * count);
+ ATF_REQUIRE(teststr != NULL);
+ for (i = 0; i < count; i++) {
+ teststr[i] = (char*)malloc(sizeof(**teststr) * 2);
+ ATF_REQUIRE(teststr[i] != NULL);
+ teststr[i][0] = 'a' + i;
+ teststr[i][1] = '\0';
+ }
+
+ nvlist_move_string_array(nvl, key, teststr, count);
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_string_array(nvl, key));
+
+ const_result = nvlist_get_string_array(nvl, key, &num_items);
+ ATF_REQUIRE_EQ(num_items, count);
+ ATF_REQUIRE(const_result != NULL);
+ ATF_REQUIRE((intptr_t)const_result == (intptr_t)teststr);
+ for (i = 0; i < num_items; i++) {
+ ATF_REQUIRE_EQ(const_result[i][0], (char)('a' + i));
+ ATF_REQUIRE_EQ(const_result[i][1], '\0');
+ }
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_nvlist_array__move);
+ATF_TEST_CASE_BODY(nvlist_nvlist_array__move)
+{
+ nvlist **testnv;
+ const nvlist * const *const_result;
+ nvlist_t *nvl;
+ size_t num_items, count;
+ unsigned int i;
+ const char *key;
+
+ key = "nvl/nvlist";
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_nvlist_array(nvl, key));
+
+ count = 26;
+ testnv = (nvlist**)malloc(sizeof(*testnv) * count);
+ ATF_REQUIRE(testnv != NULL);
+ for (i = 0; i < count; i++) {
+ testnv[i] = nvlist_create(0);
+ ATF_REQUIRE(testnv[i] != NULL);
+ }
+
+ nvlist_move_nvlist_array(nvl, key, testnv, count);
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_nvlist_array(nvl, key));
+
+ const_result = nvlist_get_nvlist_array(nvl, key, &num_items);
+ ATF_REQUIRE_EQ(num_items, count);
+ ATF_REQUIRE(const_result != NULL);
+ ATF_REQUIRE((intptr_t)const_result == (intptr_t)testnv);
+ for (i = 0; i < num_items; i++) {
+ ATF_REQUIRE_EQ(nvlist_error(const_result[i]), 0);
+ ATF_REQUIRE(nvlist_empty(const_result[i]));
+ if (i < num_items - 1) {
+ ATF_REQUIRE(nvlist_get_array_next(const_result[i]) ==
+ const_result[i + 1]);
+ } else {
+ ATF_REQUIRE(nvlist_get_array_next(const_result[i]) ==
+ NULL);
+ }
+ ATF_REQUIRE(nvlist_get_parent(const_result[i], NULL) == nvl);
+ ATF_REQUIRE(nvlist_in_array(const_result[i]));
+ }
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_number_array__move);
+ATF_TEST_CASE_BODY(nvlist_number_array__move)
+{
+ uint64_t *testnumber;
+ const uint64_t *const_result;
+ nvlist_t *nvl;
+ size_t num_items, count;
+ unsigned int i;
+ const char *key;
+
+ key = "nvl/number";
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+
+ count = 1000;
+ testnumber = (uint64_t*)malloc(sizeof(*testnumber) * count);
+ ATF_REQUIRE(testnumber != NULL);
+ for (i = 0; i < count; i++)
+ testnumber[i] = i;
+
+ nvlist_move_number_array(nvl, key, testnumber, count);
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_number_array(nvl, key));
+
+ const_result = nvlist_get_number_array(nvl, key, &num_items);
+ ATF_REQUIRE_EQ(num_items, count);
+ ATF_REQUIRE(const_result != NULL);
+ ATF_REQUIRE(const_result == testnumber);
+ for (i = 0; i < num_items; i++)
+ ATF_REQUIRE_EQ(const_result[i], i);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_descriptor_array__move);
+ATF_TEST_CASE_BODY(nvlist_descriptor_array__move)
+{
+ int *testfd;
+ const int *const_result;
+ nvlist_t *nvl;
+ size_t num_items, count;
+ unsigned int i;
+ const char *key;
+
+ key = "nvl/fd";
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+
+ count = 50;
+ testfd = (int*)malloc(sizeof(*testfd) * count);
+ ATF_REQUIRE(testfd != NULL);
+ for (i = 0; i < count; i++) {
+ testfd[i] = dup(STDERR_FILENO);
+ ATF_REQUIRE(fd_is_valid(testfd[i]));
+ }
+
+ nvlist_move_descriptor_array(nvl, key, testfd, count);
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_descriptor_array(nvl, key));
+
+ const_result = nvlist_get_descriptor_array(nvl, key, &num_items);
+ ATF_REQUIRE_EQ(num_items, count);
+ ATF_REQUIRE(const_result != NULL);
+ ATF_REQUIRE(const_result == testfd);
+ for (i = 0; i < num_items; i++)
+ ATF_REQUIRE(fd_is_valid(const_result[i]));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_arrays__error_null);
+ATF_TEST_CASE_BODY(nvlist_arrays__error_null)
+{
+ nvlist_t *nvl;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_add_number_array(nvl, "nvl/number", NULL, 0);
+ ATF_REQUIRE(nvlist_error(nvl) != 0);
+ nvlist_destroy(nvl);
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_move_number_array(nvl, "nvl/number", NULL, 0);
+ ATF_REQUIRE(nvlist_error(nvl) != 0);
+ nvlist_destroy(nvl);
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_add_descriptor_array(nvl, "nvl/fd", NULL, 0);
+ ATF_REQUIRE(nvlist_error(nvl) != 0);
+ nvlist_destroy(nvl);
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_move_descriptor_array(nvl, "nvl/fd", NULL, 0);
+ ATF_REQUIRE(nvlist_error(nvl) != 0);
+ nvlist_destroy(nvl);
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_add_string_array(nvl, "nvl/string", NULL, 0);
+ ATF_REQUIRE(nvlist_error(nvl) != 0);
+ nvlist_destroy(nvl);
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_move_string_array(nvl, "nvl/string", NULL, 0);
+ ATF_REQUIRE(nvlist_error(nvl) != 0);
+ nvlist_destroy(nvl);
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_add_nvlist_array(nvl, "nvl/nvlist", NULL, 0);
+ ATF_REQUIRE(nvlist_error(nvl) != 0);
+ nvlist_destroy(nvl);
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_move_nvlist_array(nvl, "nvl/nvlist", NULL, 0);
+ ATF_REQUIRE(nvlist_error(nvl) != 0);
+ nvlist_destroy(nvl);
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_add_bool_array(nvl, "nvl/bool", NULL, 0);
+ ATF_REQUIRE(nvlist_error(nvl) != 0);
+ nvlist_destroy(nvl);
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_move_bool_array(nvl, "nvl/bool", NULL, 0);
+ ATF_REQUIRE(nvlist_error(nvl) != 0);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_arrays__bad_value);
+ATF_TEST_CASE_BODY(nvlist_arrays__bad_value)
+{
+ nvlist_t *nvl, *nvladd[1], **nvlmove;
+ int fdadd[1], *fdmove;
+
+ nvladd[0] = NULL;
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_add_nvlist_array(nvl, "nvl/nvlist", nvladd, 1);
+ ATF_REQUIRE(nvlist_error(nvl) != 0);
+ nvlist_destroy(nvl);
+
+ nvlmove = (nvlist_t**)malloc(sizeof(*nvlmove));
+ ATF_REQUIRE(nvlmove != NULL);
+ nvlmove[0] = NULL;
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_move_nvlist_array(nvl, "nvl/nvlist", nvlmove, 1);
+ ATF_REQUIRE(nvlist_error(nvl) != 0);
+ nvlist_destroy(nvl);
+
+ fdadd[0] = -2;
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_add_descriptor_array(nvl, "nvl/fd", fdadd, 1);
+ ATF_REQUIRE(nvlist_error(nvl) != 0);
+ nvlist_destroy(nvl);
+
+ fdmove = (int*)malloc(sizeof(*fdmove));
+ ATF_REQUIRE(fdmove != NULL);
+ fdmove[0] = -2;
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_move_descriptor_array(nvl, "nvl/fd", fdmove, 1);
+ ATF_REQUIRE(nvlist_error(nvl) != 0);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_nvlist_array__travel);
+ATF_TEST_CASE_BODY(nvlist_nvlist_array__travel)
+{
+ nvlist_t *nvl, *test[5], *nasted;
+ const nvlist_t *travel;
+ const char *name;
+ void *cookie;
+ int type;
+ unsigned int i, index;
+
+ for (i = 0; i < nitems(test); i++) {
+ test[i] = nvlist_create(0);
+ ATF_REQUIRE(test[i] != NULL);
+ nvlist_add_number(test[i], "nvl/number", i);
+ ATF_REQUIRE(nvlist_error(test[i]) == 0);
+ }
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_add_nvlist_array(nvl, "nvl/nvlist_array", test, nitems(test));
+ ATF_REQUIRE(nvlist_error(nvl) == 0);
+ nasted = nvlist_create(0);
+ ATF_REQUIRE(nasted != NULL);
+ nvlist_add_nvlist_array(nasted, "nvl/nvl/nvlist_array", test,
+ nitems(test));
+ ATF_REQUIRE(nvlist_error(nasted) == 0);
+ nvlist_move_nvlist(nvl, "nvl/nvl", nasted);
+ ATF_REQUIRE(nvlist_error(nvl) == 0);
+ nvlist_add_string(nvl, "nvl/string", "END");
+ ATF_REQUIRE(nvlist_error(nvl) == 0);
+
+ cookie = NULL;
+ index = 0;
+ travel = nvl;
+ do {
+ while ((name = nvlist_next(travel, &type, &cookie)) != NULL) {
+ if (index == 0) {
+ ATF_REQUIRE(type == NV_TYPE_NVLIST_ARRAY);
+ } else if (index >= 1 && index <= nitems(test)) {
+ ATF_REQUIRE(type == NV_TYPE_NUMBER);
+ } else if (index == nitems(test) + 1) {
+ ATF_REQUIRE(type == NV_TYPE_NVLIST);
+ } else if (index == nitems(test) + 2) {
+ ATF_REQUIRE(type == NV_TYPE_NVLIST_ARRAY);
+ } else if (index >= nitems(test) + 3 &&
+ index <= 2 * nitems(test) + 2) {
+ ATF_REQUIRE(type == NV_TYPE_NUMBER);
+ } else if (index == 2 * nitems(test) + 3) {
+ ATF_REQUIRE(type == NV_TYPE_STRING);
+ }
+
+ if (type == NV_TYPE_NVLIST) {
+ travel = nvlist_get_nvlist(travel, name);
+ cookie = NULL;
+ } else if (type == NV_TYPE_NVLIST_ARRAY) {
+ travel = nvlist_get_nvlist_array(travel, name,
+ NULL)[0];
+ cookie = NULL;
+ }
+ index ++;
+ }
+ } while ((travel = nvlist_get_pararr(travel, &cookie)) != NULL);
+
+ for (i = 0; i < nitems(test); i++)
+ nvlist_destroy(test[i]);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_nvlist_array__travel_alternative);
+ATF_TEST_CASE_BODY(nvlist_nvlist_array__travel_alternative)
+{
+ nvlist_t *nvl, *test[5], *nasted;
+ const nvlist_t *travel, *tmp;
+ void *cookie;
+ int index, i, type;
+ const char *name;
+
+ for (i = 0; i < 5; i++) {
+ test[i] = nvlist_create(0);
+ ATF_REQUIRE(test[i] != NULL);
+ nvlist_add_number(test[i], "nvl/number", i);
+ ATF_REQUIRE(nvlist_error(test[i]) == 0);
+ }
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_add_nvlist_array(nvl, "nvl/nvlist_array", test, 5);
+ ATF_REQUIRE(nvlist_error(nvl) == 0);
+ nasted = nvlist_create(0);
+ ATF_REQUIRE(nasted != NULL);
+ nvlist_add_nvlist_array(nasted, "nvl/nvl/nvlist_array", test, 5);
+ ATF_REQUIRE(nvlist_error(nasted) == 0);
+ nvlist_move_nvlist(nvl, "nvl/nvl", nasted);
+ ATF_REQUIRE(nvlist_error(nvl) == 0);
+ nvlist_add_string(nvl, "nvl/string", "END");
+ ATF_REQUIRE(nvlist_error(nvl) == 0);
+
+ cookie = NULL;
+ index = 0;
+ tmp = travel = nvl;
+ do {
+ do {
+ travel = tmp;
+ while ((name = nvlist_next(travel, &type, &cookie)) !=
+ NULL) {
+ if (index == 0) {
+ ATF_REQUIRE(type ==
+ NV_TYPE_NVLIST_ARRAY);
+ } else if (index >= 1 && index <= 5) {
+ ATF_REQUIRE(type == NV_TYPE_NUMBER);
+ } else if (index == 6) {
+ ATF_REQUIRE(type == NV_TYPE_NVLIST);
+ } else if (index == 7) {
+ ATF_REQUIRE(type ==
+ NV_TYPE_NVLIST_ARRAY);
+ } else if (index >= 8 && index <= 12) {
+ ATF_REQUIRE(type == NV_TYPE_NUMBER);
+ } else if (index == 13) {
+ ATF_REQUIRE(type == NV_TYPE_STRING);
+ }
+
+ if (type == NV_TYPE_NVLIST) {
+ travel = nvlist_get_nvlist(travel,
+ name);
+ cookie = NULL;
+ } else if (type == NV_TYPE_NVLIST_ARRAY) {
+ travel = nvlist_get_nvlist_array(travel,
+ name, NULL)[0];
+ cookie = NULL;
+ }
+ index ++;
+ }
+ cookie = NULL;
+ } while ((tmp = nvlist_get_array_next(travel)) != NULL);
+ } while ((tmp = nvlist_get_parent(travel, &cookie)) != NULL);
+
+ for (i = 0; i < 5; i++)
+ nvlist_destroy(test[i]);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_bool_array__pack);
+ATF_TEST_CASE_BODY(nvlist_bool_array__pack)
+{
+ nvlist_t *nvl, *unpacked;
+ const char *key;
+ size_t packed_size, count;
+ void *packed;
+ unsigned int i;
+ const bool *const_result;
+ bool testbool[16];
+
+ for (i = 0; i < nitems(testbool); i++)
+ testbool[i] = (i % 2 == 0);
+
+ key = "nvl/bool";
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+
+ nvlist_add_bool_array(nvl, key, testbool, nitems(testbool));
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_bool_array(nvl, key));
+
+ packed = nvlist_pack(nvl, &packed_size);
+ ATF_REQUIRE(packed != NULL);
+
+ unpacked = nvlist_unpack(packed, packed_size, 0);
+ ATF_REQUIRE(unpacked != NULL);
+ ATF_REQUIRE_EQ(nvlist_error(unpacked), 0);
+ ATF_REQUIRE(nvlist_exists_bool_array(unpacked, key));
+
+ const_result = nvlist_get_bool_array(unpacked, key, &count);
+ ATF_REQUIRE_EQ(count, nitems(testbool));
+ for (i = 0; i < count; i++) {
+ ATF_REQUIRE_EQ(testbool[i], const_result[i]);
+ }
+
+ nvlist_destroy(nvl);
+ nvlist_destroy(unpacked);
+ free(packed);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_number_array__pack);
+ATF_TEST_CASE_BODY(nvlist_number_array__pack)
+{
+ nvlist_t *nvl, *unpacked;
+ const char *key;
+ size_t packed_size, count;
+ void *packed;
+ unsigned int i;
+ const uint64_t *const_result;
+ const uint64_t number[8] = { 0, UINT_MAX, 7, 123, 90,
+ 100000, 8, 1 };
+
+ key = "nvl/number";
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+
+ nvlist_add_number_array(nvl, key, number, 8);
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_number_array(nvl, key));
+
+ packed = nvlist_pack(nvl, &packed_size);
+ ATF_REQUIRE(packed != NULL);
+
+ unpacked = nvlist_unpack(packed, packed_size, 0);
+ ATF_REQUIRE(unpacked != NULL);
+ ATF_REQUIRE_EQ(nvlist_error(unpacked), 0);
+ ATF_REQUIRE(nvlist_exists_number_array(unpacked, key));
+
+ const_result = nvlist_get_number_array(unpacked, key, &count);
+ ATF_REQUIRE_EQ(count, nitems(number));
+ for (i = 0; i < count; i++) {
+ ATF_REQUIRE_EQ(number[i], const_result[i]);
+ }
+
+ nvlist_destroy(nvl);
+ nvlist_destroy(unpacked);
+ free(packed);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_descriptor_array__pack);
+ATF_TEST_CASE_BODY(nvlist_descriptor_array__pack)
+{
+ nvlist_t *nvl;
+ const char *key;
+ size_t num_items;
+ unsigned int i;
+ const int *const_result;
+ int desc[32], fd, socks[2];
+ pid_t pid;
+
+ key = "nvl/descriptor";
+
+ ATF_REQUIRE_EQ(socketpair(PF_UNIX, SOCK_STREAM, 0, socks), 0);
+
+ pid = atf::utils::fork();
+ ATF_REQUIRE(pid >= 0);
+ if (pid == 0) {
+ /* Child. */
+ fd = socks[0];
+ close(socks[1]);
+ for (i = 0; i < nitems(desc); i++) {
+ desc[i] = dup(STDERR_FILENO);
+ ATF_REQUIRE(fd_is_valid(desc[i]));
+ }
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_descriptor_array(nvl, key));
+
+ nvlist_add_descriptor_array(nvl, key, desc, nitems(desc));
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_descriptor_array(nvl, key));
+
+ ATF_REQUIRE(nvlist_send(fd, nvl) >= 0);
+
+ for (i = 0; i < nitems(desc); i++)
+ close(desc[i]);
+ } else {
+ /* Parent */
+ fd = socks[1];
+ close(socks[0]);
+
+ errno = 0;
+ nvl = nvlist_recv(fd, 0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(nvlist_exists_descriptor_array(nvl, key));
+
+ const_result = nvlist_get_descriptor_array(nvl, key, &num_items);
+ ATF_REQUIRE(const_result != NULL);
+ ATF_REQUIRE_EQ(num_items, nitems(desc));
+ for (i = 0; i < num_items; i++)
+ ATF_REQUIRE(fd_is_valid(const_result[i]));
+
+ atf::utils::wait(pid, 0, "", "");
+ }
+
+ nvlist_destroy(nvl);
+ close(fd);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_string_array__pack);
+ATF_TEST_CASE_BODY(nvlist_string_array__pack)
+{
+ nvlist_t *nvl, *unpacked;
+ const char *key;
+ size_t packed_size, count;
+ void *packed;
+ unsigned int i;
+ const char * const *const_result;
+ const char *string_arr[8] = { "a", "b", "kot", "foo",
+ "tests", "nice test", "", "abcdef" };
+
+ key = "nvl/string";
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+
+ nvlist_add_string_array(nvl, key, string_arr, nitems(string_arr));
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_string_array(nvl, key));
+
+ packed = nvlist_pack(nvl, &packed_size);
+ ATF_REQUIRE(packed != NULL);
+
+ unpacked = nvlist_unpack(packed, packed_size, 0);
+ ATF_REQUIRE(unpacked != NULL);
+ ATF_REQUIRE_EQ(nvlist_error(unpacked), 0);
+ ATF_REQUIRE(nvlist_exists_string_array(unpacked, key));
+
+ const_result = nvlist_get_string_array(unpacked, key, &count);
+ ATF_REQUIRE_EQ(count, nitems(string_arr));
+ for (i = 0; i < count; i++) {
+ ATF_REQUIRE_EQ(strcmp(string_arr[i], const_result[i]), 0);
+ }
+
+ nvlist_destroy(nvl);
+ nvlist_destroy(unpacked);
+ free(packed);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_nvlist_array__pack);
+ATF_TEST_CASE_BODY(nvlist_nvlist_array__pack)
+{
+ nvlist_t *testnvl[8], *unpacked;
+ const nvlist_t * const *const_result;
+ nvlist_t *nvl;
+ size_t num_items, packed_size;
+ unsigned int i;
+ void *packed;
+ const char *somestr[8] = { "a", "b", "c", "d", "e", "f", "g", "h" };
+ const char *key;
+
+ for (i = 0; i < nitems(testnvl); i++) {
+ testnvl[i] = nvlist_create(0);
+ ATF_REQUIRE(testnvl[i] != NULL);
+ ATF_REQUIRE_EQ(nvlist_error(testnvl[i]), 0);
+ nvlist_add_string(testnvl[i], "nvl/string", somestr[i]);
+ ATF_REQUIRE_EQ(nvlist_error(testnvl[i]), 0);
+ ATF_REQUIRE(nvlist_exists_string(testnvl[i], "nvl/string"));
+ }
+
+ key = "nvl/nvlist";
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+
+ nvlist_add_nvlist_array(nvl, key, (const nvlist_t * const *)testnvl, 8);
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_nvlist_array(nvl, key));
+ ATF_REQUIRE(nvlist_exists_nvlist_array(nvl, "nvl/nvlist"));
+ packed = nvlist_pack(nvl, &packed_size);
+ ATF_REQUIRE(packed != NULL);
+
+ unpacked = nvlist_unpack(packed, packed_size, 0);
+ ATF_REQUIRE(unpacked != NULL);
+ ATF_REQUIRE_EQ(nvlist_error(unpacked), 0);
+ ATF_REQUIRE(nvlist_exists_nvlist_array(unpacked, key));
+
+ const_result = nvlist_get_nvlist_array(unpacked, key, &num_items);
+ ATF_REQUIRE(const_result != NULL);
+ ATF_REQUIRE_EQ(num_items, nitems(testnvl));
+ for (i = 0; i < num_items; i++) {
+ ATF_REQUIRE_EQ(nvlist_error(const_result[i]), 0);
+ if (i < num_items - 1) {
+ ATF_REQUIRE(nvlist_get_array_next(const_result[i]) ==
+ const_result[i + 1]);
+ } else {
+ ATF_REQUIRE(nvlist_get_array_next(const_result[i]) ==
+ NULL);
+ }
+ ATF_REQUIRE(nvlist_get_parent(const_result[i], NULL) == unpacked);
+ ATF_REQUIRE(nvlist_in_array(const_result[i]));
+ ATF_REQUIRE(nvlist_exists_string(const_result[i],
+ "nvl/string"));
+ ATF_REQUIRE(strcmp(nvlist_get_string(const_result[i],
+ "nvl/string"), somestr[i]) == 0);
+ }
+
+ for (i = 0; i < nitems(testnvl); i++)
+ nvlist_destroy(testnvl[i]);
+ nvlist_destroy(nvl);
+ nvlist_destroy(unpacked);
+ free(packed);
+}
+
+ATF_INIT_TEST_CASES(tp)
+{
+
+ ATF_ADD_TEST_CASE(tp, nvlist_bool_array__basic);
+ ATF_ADD_TEST_CASE(tp, nvlist_string_array__basic);
+ ATF_ADD_TEST_CASE(tp, nvlist_descriptor_array__basic);
+ ATF_ADD_TEST_CASE(tp, nvlist_number_array__basic);
+ ATF_ADD_TEST_CASE(tp, nvlist_nvlist_array__basic)
+
+ ATF_ADD_TEST_CASE(tp, nvlist_clone_array)
+
+ ATF_ADD_TEST_CASE(tp, nvlist_bool_array__move);
+ ATF_ADD_TEST_CASE(tp, nvlist_string_array__move);
+ ATF_ADD_TEST_CASE(tp, nvlist_nvlist_array__move);
+ ATF_ADD_TEST_CASE(tp, nvlist_number_array__move);
+ ATF_ADD_TEST_CASE(tp, nvlist_descriptor_array__move);
+
+ ATF_ADD_TEST_CASE(tp, nvlist_arrays__error_null);
+
+ ATF_ADD_TEST_CASE(tp, nvlist_arrays__bad_value)
+
+ ATF_ADD_TEST_CASE(tp, nvlist_nvlist_array__travel)
+ ATF_ADD_TEST_CASE(tp, nvlist_nvlist_array__travel_alternative)
+
+ ATF_ADD_TEST_CASE(tp, nvlist_bool_array__pack)
+ ATF_ADD_TEST_CASE(tp, nvlist_number_array__pack)
+ ATF_ADD_TEST_CASE(tp, nvlist_descriptor_array__pack)
+ ATF_ADD_TEST_CASE(tp, nvlist_string_array__pack)
+ ATF_ADD_TEST_CASE(tp, nvlist_nvlist_array__pack)
+}
+
Index: lib/libnv/tests/nv_tests.cc
===================================================================
--- lib/libnv/tests/nv_tests.cc
+++ lib/libnv/tests/nv_tests.cc
@@ -27,8 +27,9 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <sys/nv.h>
+
#include <atf-c++.hpp>
-#include <nv.h>
#include <errno.h>
#include <limits>
@@ -440,7 +441,7 @@
packed = nvlist_pack(nvl, &packed_size);
ATF_REQUIRE(packed != NULL);
- unpacked = nvlist_unpack(packed, packed_size);
+ unpacked = nvlist_unpack(packed, packed_size, 0);
ATF_REQUIRE(unpacked != NULL);
ATF_REQUIRE(unpacked != nvl);
ATF_REQUIRE(nvlist_empty(unpacked));
@@ -450,6 +451,40 @@
free(packed);
}
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_unpack__flags_nvlist);
+ATF_TEST_CASE_BODY(nvlist_unpack__flags_nvlist)
+{
+ nvlist_t *nvl, *unpacked;
+ void *packed;
+ size_t packed_size;
+
+ nvl = nvlist_create(NV_FLAG_NO_UNIQUE);
+ ATF_REQUIRE(nvl != NULL);
+
+ nvlist_add_bool(nvl, "name", true);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_bool(nvl, "name"));
+
+ packed = nvlist_pack(nvl, &packed_size);
+ ATF_REQUIRE(packed != NULL);
+
+ unpacked = nvlist_unpack(packed, packed_size, 0);
+ ATF_REQUIRE(unpacked == NULL);
+
+ unpacked = nvlist_unpack(packed, packed_size, NV_FLAG_IGNORE_CASE);
+ ATF_REQUIRE(unpacked == NULL);
+
+ unpacked = nvlist_unpack(packed, packed_size, NV_FLAG_NO_UNIQUE);
+ ATF_REQUIRE(unpacked != NULL);
+ ATF_REQUIRE(unpacked != nvl);
+ ATF_REQUIRE(!nvlist_empty(unpacked));
+ ATF_REQUIRE(nvlist_exists_bool(unpacked, "name"));
+
+ nvlist_destroy(unpacked);
+ nvlist_destroy(nvl);
+ free(packed);
+}
+
static void
verify_null(const nvlist_t *nvl, int type)
{
@@ -534,7 +569,7 @@
packed = nvlist_pack(nvl, &packed_size);
ATF_REQUIRE(packed != NULL);
- unpacked = nvlist_unpack(packed, packed_size);
+ unpacked = nvlist_unpack(packed, packed_size, 0);
ATF_REQUIRE(unpacked != 0);
it = NULL;
@@ -614,7 +649,7 @@
ATF_REQUIRE(keypos != NULL);
memcpy(keypos, key2, keylen);
- unpacked = nvlist_unpack(packed, size);
+ unpacked = nvlist_unpack(packed, size, 0);
ATF_REQUIRE(nvlist_error(unpacked) != 0);
free(packed);
@@ -1206,6 +1241,7 @@
ATF_ADD_TEST_CASE(tp, nvlist_pack__multiple_values);
ATF_ADD_TEST_CASE(tp, nvlist_pack__error_nvlist);
ATF_ADD_TEST_CASE(tp, nvlist_unpack__duplicate_key);
+ ATF_ADD_TEST_CASE(tp, nvlist_unpack__flags_nvlist);
ATF_ADD_TEST_CASE(tp, nvlist_move_string__single_insert);
ATF_ADD_TEST_CASE(tp, nvlist_move_nvlist__single_insert);
Index: lib/libnv/tests/nvlist_add_test.c
===================================================================
--- lib/libnv/tests/nvlist_add_test.c
+++ lib/libnv/tests/nvlist_add_test.c
@@ -29,12 +29,12 @@
* $FreeBSD$
*/
+#include <sys/nv.h>
+
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
-#include <nv.h>
-
static int ntest = 1;
#define CHECK(expr) do { \
Index: lib/libnv/tests/nvlist_exists_test.c
===================================================================
--- lib/libnv/tests/nvlist_exists_test.c
+++ lib/libnv/tests/nvlist_exists_test.c
@@ -29,11 +29,11 @@
* $FreeBSD$
*/
+#include <sys/nv.h>
+
#include <stdio.h>
#include <unistd.h>
-#include <nv.h>
-
static int ntest = 1;
#define CHECK(expr) do { \
Index: lib/libnv/tests/nvlist_free_test.c
===================================================================
--- lib/libnv/tests/nvlist_free_test.c
+++ lib/libnv/tests/nvlist_free_test.c
@@ -29,11 +29,11 @@
* $FreeBSD$
*/
+#include <sys/nv.h>
+
#include <stdio.h>
#include <unistd.h>
-#include <nv.h>
-
static int ntest = 1;
#define CHECK(expr) do { \
Index: lib/libnv/tests/nvlist_get_test.c
===================================================================
--- lib/libnv/tests/nvlist_get_test.c
+++ lib/libnv/tests/nvlist_get_test.c
@@ -28,6 +28,7 @@
*
* $FreeBSD$
*/
+#include <sys/nv.h>
#include <errno.h>
#include <fcntl.h>
@@ -35,8 +36,6 @@
#include <string.h>
#include <unistd.h>
-#include <nv.h>
-
static int ntest = 1;
#define CHECK(expr) do { \
Index: lib/libnv/tests/nvlist_move_test.c
===================================================================
--- lib/libnv/tests/nvlist_move_test.c
+++ lib/libnv/tests/nvlist_move_test.c
@@ -29,6 +29,8 @@
* $FreeBSD$
*/
+#include <sys/nv.h>
+
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
@@ -35,8 +37,6 @@
#include <string.h>
#include <unistd.h>
-#include <nv.h>
-
static int ntest = 1;
#define CHECK(expr) do { \
Index: lib/libnv/tests/nvlist_send_recv_test.c
===================================================================
--- lib/libnv/tests/nvlist_send_recv_test.c
+++ lib/libnv/tests/nvlist_send_recv_test.c
@@ -32,6 +32,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
+#include <sys/nv.h>
#include <err.h>
#include <errno.h>
@@ -40,8 +41,6 @@
#include <string.h>
#include <unistd.h>
-#include <nv.h>
-
static int ntest = 1;
#define CHECK(expr) do { \
@@ -95,7 +94,7 @@
int type, ctype;
size_t size;
- nvl = nvlist_recv(sock);
+ nvl = nvlist_recv(sock, 0);
CHECK(nvlist_error(nvl) == 0);
if (nvlist_error(nvl) != 0)
err(1, "nvlist_recv() failed");
Index: share/man/man5/rc.conf.5
===================================================================
--- share/man/man5/rc.conf.5
+++ share/man/man5/rc.conf.5
@@ -4524,6 +4524,11 @@
.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 @@
.Xr hcsecd 8 ,
.Xr ifconfig 8 ,
.Xr inetd 8 ,
+.Xr iovctl 8 ,
.Xr ipf 8 ,
.Xr ipfw 8 ,
.Xr ipnat 8 ,
Index: share/man/man9/Makefile
===================================================================
--- share/man/man9/Makefile
+++ share/man/man9/Makefile
@@ -188,6 +188,7 @@
mutex.9 \
namei.9 \
netisr.9 \
+ nv.9 \
osd.9 \
panic.9 \
pbuf.9 \
@@ -194,6 +195,10 @@
p_candebug.9 \
p_cansee.9 \
pci.9 \
+ PCI_IOV_ADD_VF.9 \
+ PCI_IOV_INIT.9 \
+ pci_iov_schema.9 \
+ PCI_IOV_UNINIT.9 \
pfil.9 \
pfind.9 \
pget.9 \
@@ -999,6 +1004,68 @@
mutex.9 mtx_unlock_spin_flags.9
MLINKS+=namei.9 NDFREE.9 \
namei.9 NDINIT.9
+MLINKS+=nv.9 libnv.9 \
+ nv.9 nvlist.9 \
+ nv.9 nvlist_add_binary.9 \
+ nv.9 nvlist_add_bool.9 \
+ nv.9 nvlist_add_descriptor.9 \
+ nv.9 nvlist_add_null.9 \
+ nv.9 nvlist_add_number.9 \
+ nv.9 nvlist_add_nvlist.9 \
+ nv.9 nvlist_add_string.9 \
+ nv.9 nvlist_add_stringf.9 \
+ nv.9 nvlist_add_stringv.9 \
+ nv.9 nvlist_clone.9 \
+ nv.9 nvlist_create.9 \
+ nv.9 nvlist_destroy.9 \
+ nv.9 nvlist_dump.9 \
+ nv.9 nvlist_empty.9 \
+ nv.9 nvlist_error.9 \
+ nv.9 nvlist_exists.9 \
+ nv.9 nvlist_exists_binary.9 \
+ nv.9 nvlist_exists_bool.9 \
+ nv.9 nvlist_exists_descriptor.9 \
+ nv.9 nvlist_exists_null.9 \
+ nv.9 nvlist_exists_number.9 \
+ nv.9 nvlist_exists_nvlist.9 \
+ nv.9 nvlist_exists_string.9 \
+ nv.9 nvlist_exists_type.9 \
+ nv.9 nvlist_fdump.9 \
+ nv.9 nvlist_flags.9 \
+ nv.9 nvlist_free.9 \
+ nv.9 nvlist_free_binary.9 \
+ nv.9 nvlist_free_bool.9 \
+ nv.9 nvlist_free_descriptor.9 \
+ nv.9 nvlist_free_null.9 \
+ nv.9 nvlist_free_number.9 \
+ nv.9 nvlist_free_nvlist.9 \
+ nv.9 nvlist_free_string.9 \
+ nv.9 nvlist_free_type.9 \
+ nv.9 nvlist_get_binary.9 \
+ nv.9 nvlist_get_bool.9 \
+ nv.9 nvlist_get_descriptor.9 \
+ nv.9 nvlist_get_number.9 \
+ nv.9 nvlist_get_nvlist.9 \
+ nv.9 nvlist_get_parent.9 \
+ nv.9 nvlist_get_string.9 \
+ nv.9 nvlist_move_binary.9 \
+ nv.9 nvlist_move_descriptor.9 \
+ nv.9 nvlist_move_nvlist.9 \
+ nv.9 nvlist_move_string.9 \
+ nv.9 nvlist_next.9 \
+ nv.9 nvlist_pack.9 \
+ nv.9 nvlist_recv.9 \
+ nv.9 nvlist_send.9 \
+ nv.9 nvlist_set_error.9 \
+ nv.9 nvlist_size.9 \
+ nv.9 nvlist_take_binary.9 \
+ nv.9 nvlist_take_bool.9 \
+ nv.9 nvlist_take_descriptor.9 \
+ nv.9 nvlist_take_number.9 \
+ nv.9 nvlist_take_nvlist.9 \
+ nv.9 nvlist_take_string.9 \
+ nv.9 nvlist_unpack.9 \
+ nv.9 nvlist_xfer.9
MLINKS+=panic.9 vpanic.9
MLINKS+=pbuf.9 getpbuf.9 \
pbuf.9 relpbuf.9 \
@@ -1020,6 +1087,8 @@
pci.9 pci_get_powerstate.9 \
pci.9 pci_get_vpd_ident.9 \
pci.9 pci_get_vpd_readonly.9 \
+ pci.9 pci_iov_attach.9 \
+ pci.9 pci_iov_detach.9 \
pci.9 pci_msi_count.9 \
pci.9 pci_msix_count.9 \
pci.9 pci_pending_msix.9 \
@@ -1034,6 +1103,14 @@
pci.9 pcie_adjust_config.9 \
pci.9 pcie_read_config.9 \
pci.9 pcie_write_config.9
+MLINKS+=pci_iov_schema.9 pci_iov_schema_alloc_node.9 \
+ pci_iov_schema.9 pci_iov_schema_add_bool.9 \
+ pci_iov_schema.9 pci_iov_schema_add_string.9 \
+ pci_iov_schema.9 pci_iov_schema_add_uint8.9 \
+ pci_iov_schema.9 pci_iov_schema_add_uint16.9 \
+ pci_iov_schema.9 pci_iov_schema_add_uint32.9 \
+ pci_iov_schema.9 pci_iov_schema_add_uint64.9 \
+ pci_iov_schema.9 pci_iov_schema_add_unicast_mac.9
MLINKS+=pfil.9 pfil_add_hook.9 \
pfil.9 pfil_hook_get.9 \
pfil.9 pfil_remove_hook.9
Index: share/man/man9/PCI_IOV_ADD_VF.9
===================================================================
--- share/man/man9/PCI_IOV_ADD_VF.9
+++ share/man/man9/PCI_IOV_ADD_VF.9
@@ -0,0 +1,112 @@
+.\"
+.\" Copyright (c) 2014 Sandvine Inc.
+.\" 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$
+.\"
+.Dd May 28, 2015
+.Dt PCI_IOV_ADD_VF 9
+.Os
+.Sh NAME
+.Nm PCI_IOV_ADD_VF
+.Nd inform a PF driver that a VF is being created
+.Sh SYNOPSIS
+.In sys/bus.h
+.In machine/stdarg.h
+.In sys/nv.h
+.In dev/pci/pci_iov.h
+.Ft int
+.Fn PCI_IOV_ADD_VF "device_t dev" "uint16_t vfnum" "const nvlist_t *vf_config"
+.Sh DESCRIPTION
+The
+.Fn PCI_IOV_ADD_VF
+method is called by the PCI Single-Root I/O Virtualization
+.Pq SR-IOV
+infrastructure when it is initializating a new Virtual Function (VF) as a child
+of the given Physical Function (PF) device.
+This method will not be called until a successful call to
+.Xr PCI_IOV_INIT 9
+has been made.
+It is not guaranteed that this method will be called following a successful call
+to
+.Xr PCI_IOV_INIT 9 .
+If the infrastructure encounters a failure to allocate resources following the
+call to
+.Xr PCI_IOV_INIT 9 ,
+the VF creation will be aborted and
+.Xr PCI_IOV_UNINIT 9
+will be called immediately without any preceding calls to
+.Nm .
+.Pp
+The index of the VF being initialized is passed in the
+.Fa vfnum
+argument.
+VFs are always numbered sequentially starting at 0.
+.Pp
+If the driver requested device-specific configuration parameters via a VF schema
+in its call to
+.Xr pci_iov_attach 9 ,
+those parameters will be contained in the
+.Pa vf_config
+argument.
+All configuration parameters that were either set as required parameters or that
+had a default value set in the VF schema are guaranteed to be present in
+.Fa vf_config .
+Configuration parameters that were neither set as required nor were given a
+default value are optional and may or may not be present in
+.Fa vf_config .
+.Fa vf_config
+will not contain any configuration parameters that were not specified in the VF
+schema.
+All configuration parameters will have the correct type and will be in the range
+of valid values specified in the schema.
+.Pp
+Note that it is possible for the user to set different configuration values on
+different VF devices that are children of the same PF.
+The PF driver must not cache configuration parameters passed in previous calls
+to
+.Fn PCI_IOV_ADD_VF
+for other VFs and apply those parameters to the current VF.
+.Pp
+This function will not be called twice for the same
+.Fa vf_num
+on the same PF device without
+.Xr PCI_IOV_UNINIT 9
+and
+.Xr PCI_IOV_INIT 9
+first being called, in that order.
+.Sh RETURN VALUES
+This method returns 0 on success, otherwise an appropriate error is returned.
+If this method returns an error then the current VF device will be destroyed
+but the rest of the VF devices will be created and SR-IOV will be enabled on
+the PF.
+.Sh SEE ALSO
+.Xr nv 9 ,
+.Xr pci 9 ,
+.Xr pci_iov_schema 9 ,
+.Xr PCI_IOV_INIT 9 ,
+.Xr PCI_IOV_UNINIT 9
+.Sh AUTHORS
+This manual page was written by
+.An Ryan Stone Aq Mt rstone@FreeBSD.org .
Index: share/man/man9/PCI_IOV_INIT.9
===================================================================
--- share/man/man9/PCI_IOV_INIT.9
+++ share/man/man9/PCI_IOV_INIT.9
@@ -0,0 +1,85 @@
+.\"
+.\" Copyright (c) 2014 Sandvine Inc.
+.\" 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$
+.\"
+.Dd May 28, 2015
+.Dt PCI_IOV_INIT 9
+.Os
+.Sh NAME
+.Nm PCI_IOV_INIT
+.Nd enable SR-IOV on a PF device
+.Sh SYNOPSIS
+.In sys/bus.h
+.In machine/stdarg.h
+.In sys/nv.h
+.In dev/pci/pci_iov.h
+.Ft int
+.Fn PCI_IOV_INIT "device_t dev" "uint16_t num_vfs" "const nvlist_t *pf_config"
+.Sh DESCRIPTION
+The
+.Fn PCI_IOV_INIT
+method is called by the PCI Single-Root I/O Virtualization (SR-IOV)
+infrastucture when the user requests that SR-IOV be enabled on a Physical
+Function (PF).
+The number of Virtual Functions (VFs) that will be created is passed to this
+method in the
+.Fa num_vfs
+argument.
+.Pp
+If the driver requested device-specific PF configuration parameters via a PF
+schema in its call to
+.Xr pci_iov_attach 9 ,
+those parameters will be available in the
+.Fa pf_config
+argument.
+All configuration parameters that were either set as required parameters or that
+had a default value set in the PF schema are guaranteed to be present in
+.Fa pf_config .
+Configuration parameters that were neither set as required nor were given a
+default value are optional and may or may not be present in
+.Fa pf_config .
+.Fa pf_config
+will not contain any configuration parameters that were not specified in the PF
+schema.
+All configuration parameters will have the correct type and are in the range of
+valid values specified in the schema.
+.Pp
+If this method returns successfully, then this method will not be called again
+on the same device until after a call to
+.Xr PCI_IOV_UNINIT .
+.Sh RETURN VALUES
+Returns 0 on success, otherwise an appropriate error is returned.
+If this method returns an error then the SR-IOV configuration will be aborted
+and no VFs will be created.
+.Sh SEE ALSO
+.Xr nv 9 ,
+.Xr pci 9 ,
+.Xr pci_iov_schema 9 ,
+.Xr PCI_IOV_ADD_VF 9 ,
+.Xr PCI_IOV_UNINIT 9
+.Sh AUTHORS
+This manual page was written by
+.An Ryan Stone Aq Mt rstone@FreeBSD.org .
Index: share/man/man9/PCI_IOV_UNINIT.9
===================================================================
--- share/man/man9/PCI_IOV_UNINIT.9
+++ share/man/man9/PCI_IOV_UNINIT.9
@@ -0,0 +1,63 @@
+.\"
+.\" Copyright (c) 2014 Sandvine Inc.
+.\" 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$
+.\"
+.Dd May 28, 2015
+.Dt PCI_IOV_UNINIT 9
+.Os
+.Sh NAME
+.Nm PCI_IOV_UNINIT
+.Nd disable SR-IOV on a PF device
+.Sh SYNOPSIS
+.In sys/bus.h
+.In dev/pci/pci_iov.h
+.Ft void
+.Fn PCI_IOV_UNINIT "device_t dev"
+.Sh DESCRIPTION
+The
+.Fn PCI_IOV_UNINIT
+method is called by the PCI Single-Root I/O Virtualization (SR-IOV)
+infrastructure when the user requests that SR-IOV be disabled on a Physical
+Function (PF).
+When this method is called, the PF driver must release any SR-IOV-related
+resources that it has allocated and disable any device-specific SR-IOV
+configuration in the device.
+.Pp
+This method will only be called following a successful call to
+.Xr PCI_IOV_INIT .
+It is not guaranteed that
+.Xr PCI_IOV_ADD_VF
+will have been called for any Virtual Function (VF) after the call to
+.Xr PCI_IOV_INIT
+and before the call to
+.Nm .
+.Sh SEE ALSO
+.Xr pci 9 ,
+.Xr PCI_IOV_ADD_VF 9 ,
+.Xr PCI_IOV_INIT 9
+.Sh AUTHORS
+This manual page was written by
+.An Ryan Stone Aq Mt rstone@FreeBSD.org .
Index: share/man/man9/nv.9
===================================================================
--- share/man/man9/nv.9
+++ share/man/man9/nv.9
@@ -0,0 +1,935 @@
+.\"
+.\" Copyright (c) 2013 The FreeBSD Foundation
+.\" Copyright (c) 2013-2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" This documentation was written by Pawel Jakub Dawidek under sponsorship
+.\" the FreeBSD Foundation.
+.\"
+.\" 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$
+.\"
+.Dd August 15, 2015
+.Dt NV 9
+.Os
+.Sh NAME
+.Nm nvlist_create ,
+.Nm nvlist_destroy ,
+.Nm nvlist_error ,
+.Nm nvlist_set_error ,
+.Nm nvlist_empty ,
+.Nm nvlist_flags ,
+.Nm nvlist_exists ,
+.Nm nvlist_free ,
+.Nm nvlist_clone ,
+.Nm nvlist_dump ,
+.Nm nvlist_fdump ,
+.Nm nvlist_size ,
+.Nm nvlist_pack ,
+.Nm nvlist_unpack ,
+.Nm nvlist_send ,
+.Nm nvlist_recv ,
+.Nm nvlist_xfer ,
+.Nm nvlist_in_array ,
+.Nm nvlist_next ,
+.Nm nvlist_add ,
+.Nm nvlist_move ,
+.Nm nvlist_get ,
+.Nm nvlist_take
+.Nd "library for name/value pairs"
+.Sh LIBRARY
+.Lb libnv
+.Sh SYNOPSIS
+.In nv.h
+.Ft "nvlist_t *"
+.Fn nvlist_create "int flags"
+.Ft void
+.Fn nvlist_destroy "nvlist_t *nvl"
+.Ft int
+.Fn nvlist_error "const nvlist_t *nvl"
+.Ft void
+.Fn nvlist_set_error "nvlist_t *nvl, int error"
+.Ft bool
+.Fn nvlist_empty "const nvlist_t *nvl"
+.Ft int
+.Fn nvlist_flags "const nvlist_t *nvl"
+.Ft bool
+.Fn nvlist_in_array "const nvlist_t *nvl"
+.\"
+.Ft "nvlist_t *"
+.Fn nvlist_clone "const nvlist_t *nvl"
+.\"
+.Ft void
+.Fn nvlist_dump "const nvlist_t *nvl, int fd"
+.Ft void
+.Fn nvlist_fdump "const nvlist_t *nvl, FILE *fp"
+.\"
+.Ft size_t
+.Fn nvlist_size "const nvlist_t *nvl"
+.Ft "void *"
+.Fn nvlist_pack "const nvlist_t *nvl" "size_t *sizep"
+.Ft "nvlist_t *"
+.Fn nvlist_unpack "const void *buf" "size_t size" "int flags"
+.\"
+.Ft int
+.Fn nvlist_send "int sock" "const nvlist_t *nvl"
+.Ft "nvlist_t *"
+.Fn nvlist_recv "int sock" "int flags"
+.Ft "nvlist_t *"
+.Fn nvlist_xfer "int sock" "nvlist_t *nvl" "int flags"
+.\"
+.Ft "const char *"
+.Fn nvlist_next "const nvlist_t *nvl" "int *typep" "void **cookiep"
+.\"
+.Ft bool
+.Fn nvlist_exists "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_type "const nvlist_t *nvl" "const char *name" "int type"
+.Ft bool
+.Fn nvlist_exists_null "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_bool "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_number "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_string "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_nvlist "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_descriptor "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_binary "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_bool_array "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_number_array "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_string_array "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_nvlist_array "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_descriptor_array "const nvlist_t *nvl" "const char *name"
+.\"
+.Ft void
+.Fn nvlist_add_null "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_add_bool "nvlist_t *nvl" "const char *name" "bool value"
+.Ft void
+.Fn nvlist_add_number "nvlist_t *nvl" "const char *name" "uint64_t value"
+.Ft void
+.Fn nvlist_add_string "nvlist_t *nvl" "const char *name" "const char *value"
+.Ft void
+.Fn nvlist_add_stringf "nvlist_t *nvl" "const char *name" "const char *valuefmt" "..."
+.Ft void
+.Fn nvlist_add_stringv "nvlist_t *nvl" "const char *name" "const char *valuefmt" "va_list valueap"
+.Ft void
+.Fn nvlist_add_nvlist "nvlist_t *nvl" "const char *name" "const nvlist_t *value"
+.Ft void
+.Fn nvlist_add_descriptor "nvlist_t *nvl" "const char *name" "int value"
+.Ft void
+.Fn nvlist_add_binary "nvlist_t *nvl" "const char *name" "const void *value" "size_t size"
+.Ft void
+.Fn nvlist_add_bool_array "nvlist_t *nvl" "const char *name" "const bool *value" "size_t nitems"
+.
+.Ft void
+.Fn nvlist_add_number_array "nvlist_t *nvl" "const char *name" "const uint64_t *value" "size_t nitems"
+.
+.Ft void
+.Fn nvlist_add_string_array "nvlist_t *nvl" "const char *name" "const char * const * value" "size_t nitems"
+.
+.Ft void
+.Fn nvlist_add_nvlist_array "nvlist_t *nvl" "const char *name" "const nvlist_t * const * value" "size_t nitems"
+.
+.Ft void
+.Fn nvlist_add_descriptor_array "nvlist_t *nvl" "const char *name" "const int *value" "size_t nitems"
+.\"
+.Ft void
+.Fn nvlist_move_string "nvlist_t *nvl" "const char *name" "char *value"
+.Ft void
+.Fn nvlist_move_nvlist "nvlist_t *nvl" "const char *name" "nvlist_t *value"
+.Ft void
+.Fn nvlist_move_descriptor "nvlist_t *nvl" "const char *name" "int value"
+.Ft void
+.Fn nvlist_move_binary "nvlist_t *nvl" "const char *name" "void *value" "size_t size"
+.Ft void
+.Fn nvlist_move_bool_array "nvlist_t *nvl" "const char *name" "bool *value" "size_t nitems"
+.
+.Ft void
+.Fn nvlist_move_number_array "nvlist_t *nvl" "const char *name" "uint64_t *value" "size_t nitems"
+.
+.Ft void
+.Fn nvlist_move_string_array "nvlist_t *nvl" "const char *name" "char **value" "size_t nitems"
+.
+.Ft void
+.Fn nvlist_move_nvlist_array "nvlist_t *nvl" "const char *name" "nvlist_t **value" "size_t nitems"
+.
+.Ft void
+.Fn nvlist_move_descriptor_array "nvlist_t *nvl" "const char *name" "int *value" "size_t nitems"
+.\"
+.Ft bool
+.Fn nvlist_get_bool "const nvlist_t *nvl" "const char *name"
+.Ft uint64_t
+.Fn nvlist_get_number "const nvlist_t *nvl" "const char *name"
+.Ft "const char *"
+.Fn nvlist_get_string "const nvlist_t *nvl" "const char *name"
+.Ft "const nvlist_t *"
+.Fn nvlist_get_nvlist "const nvlist_t *nvl" "const char *name"
+.Ft int
+.Fn nvlist_get_descriptor "const nvlist_t *nvl" "const char *name"
+.Ft "const void *"
+.Fn nvlist_get_binary "const nvlist_t *nvl" "const char *name" "size_t *sizep"
+.Ft "const bool *"
+.Fn nvlist_get_bool_array "const nvlist_t *nvl" "const char *name" "size_t *nitems"
+.Ft "const uint64_t *"
+.Fn nvlist_get_number "const nvlist_t *nvl" "const char *name" "size_t *nitems"
+.Ft "const char * const *"
+.Fn nvlist_get_string "const nvlist_t *nvl" "const char *name" "size_t *nitems"
+.Ft "const nvlist_t * const *"
+.Fn nvlist_get_nvlist "const nvlist_t *nvl" "const char *name" "size_t *nitems"
+.Ft "const int *"
+.Fn nvlist_get_descriptor_array "const nvlist_t *nvl" "const char *name" "size_t *nitems"
+.Ft "const nvlist_t *"
+.Fn nvlist_get_parent "const nvlist_t *nvl" "void **cookiep"
+.Ft "const nvlist_t *"
+.Fn nvlist_get_array_next "const nvlist_t *nvl"
+.Ft "const nvlist_t *"
+.Fn nvlist_get_pararr "const nvlist_t *nvl" "void **cookiep"
+.\"
+.Ft bool
+.Fn nvlist_take_bool "nvlist_t *nvl" "const char *name"
+.Ft uint64_t
+.Fn nvlist_take_number "nvlist_t *nvl" "const char *name"
+.Ft "char *"
+.Fn nvlist_take_string "nvlist_t *nvl" "const char *name"
+.Ft "nvlist_t *"
+.Fn nvlist_take_nvlist "nvlist_t *nvl" "const char *name"
+.Ft int
+.Fn nvlist_take_descriptor "nvlist_t *nvl" "const char *name"
+.Ft "void *"
+.Fn nvlist_take_binary "nvlist_t *nvl" "const char *name" "size_t *sizep"
+.Ft "bool *"
+.Fn nvlist_take_bool_array "nvlist_t *nvl" "const char *name" "size_t *nitems"
+.Ft "uint64_t **"
+.Fn nvlist_take_number "nvlist_t *nvl" "const char *name" "size_t *nitems"
+.Ft "char **"
+.Fn nvlist_take_string "nvlist_t *nvl" "const char *name" "size_t *nitems"
+.Ft "nvlist_t **"
+.Fn nvlist_take_nvlist "nvlist_t *nvl" "const char *name" "size_t *nitems"
+.Ft "int *"
+.Fn nvlist_take_descriptor "nvlist_t *nvl" "const char *name" "size_t *nitems"
+.\"
+.Ft void
+.Fn nvlist_free "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_type "nvlist_t *nvl" "const char *name" "int type"
+.\"
+.Ft void
+.Fn nvlist_free_null "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_bool "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_number "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_string "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_nvlist "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_descriptor "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_binary "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_bool_array "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_number_array "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_string_array "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_nvlist_array "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_descriptor_array "nvlist_t *nvl" "const char *name"
+.Sh DESCRIPTION
+The
+.Nm libnv
+library allows to easily manage name value pairs as well as send and receive
+them over sockets.
+A group (list) of name value pairs is called an
+.Nm nvlist .
+The API supports the following data types:
+.Bl -ohang -offset indent
+.It Sy null ( NV_TYPE_NULL )
+There is no data associated with the name.
+.It Sy bool ( NV_TYPE_BOOL )
+The value can be either
+.Dv true
+or
+.Dv false .
+.It Sy number ( NV_TYPE_NUMBER )
+The value is a number stored as
+.Vt uint64_t .
+.It Sy string ( NV_TYPE_STRING )
+The value is a C string.
+.It Sy nvlist ( NV_TYPE_NVLIST )
+The value is a nested nvlist.
+.It Sy descriptor ( NV_TYPE_DESCRIPTOR )
+The value is a file descriptor.
+Note that file descriptors can be sent only over
+.Xr unix 4
+domain sockets.
+.It Sy binary ( NV_TYPE_BINARY )
+The value is a binary buffer.
+.It Sy bool array ( NV_TYPE_BOOL_ARRAY )
+The value is an array of boolean values.
+.It Sy number array ( NV_TYPE_NUMBER_ARRAY )
+The value is an array of numbers, each stored as
+.Vt uint64_t .
+.It Sy string array ( NV_TYPE_STRING_ARRAY )
+The value is an array of C strings.
+.It Sy nvlist array ( NV_TYPE_NVLIST_ARRAY )
+The value is an array of nvlists.
+When an nvlist is added to an array, it becomes part of the primary nvlist.
+Traversing these arrays can be done using the
+.Fn nvlist_get_array_next
+and
+.Fn nvlist_get_pararr
+functions.
+.It Sy descriptor array ( NV_TYPE_DESCRIPTOR_ARRAY )
+The value is an array of files descriptors.
+.El
+.Pp
+The
+.Fn nvlist_create
+function allocates memory and initializes an nvlist.
+.Pp
+The following flag can be provided:
+.Pp
+.Bl -tag -width "NV_FLAG_IGNORE_CASE" -compact -offset indent
+.It Dv NV_FLAG_IGNORE_CASE
+Perform case-insensitive lookups of provided names.
+.It Dv NV_FLAG_NO_UNIQUE
+Names in the nvlist do not have to be unique.
+.El
+.Pp
+The
+.Fn nvlist_destroy
+function destroys the given nvlist.
+Function does nothing if
+.Dv NULL
+nvlist is provided.
+Function never modifies the
+.Va errno
+global variable.
+.Pp
+The
+.Fn nvlist_error
+function returns any error value that the nvlist accumulated.
+If the given nvlist is
+.Dv NULL
+the
+.Er ENOMEM
+error will be returned.
+.Pp
+The
+.Fn nvlist_set_error
+function sets an nvlist to be in the error state.
+Subsequent calls to
+.Fn nvlist_error
+will return the given error value.
+This function cannot be used to clear the error state from an nvlist.
+This function does nothing if the nvlist is already in the error state.
+.Pp
+The
+.Fn nvlist_empty
+function returns
+.Dv true
+if the given nvlist is empty and
+.Dv false
+otherwise.
+The nvlist must not be in error state.
+.Pp
+The
+.Fn nvlist_flags
+function returns flags used to create the nvlist with the
+.Fn nvlist_create
+function.
+.Pp
+The
+.Fn nvlist_in_array
+function returns
+.Dv true
+if
+.Fa nvl
+is part of an array that is a member of another nvlist.
+.Pp
+The
+.Fn nvlist_clone
+functions clones the given nvlist.
+The clone shares no resources with its origin.
+This also means that all file descriptors that are part of the nvlist will be
+duplicated with the
+.Xr dup 2
+system call before placing them in the clone.
+.Pp
+The
+.Fn nvlist_dump
+dumps nvlist content for debugging purposes to the given file descriptor
+.Fa fd .
+.Pp
+The
+.Fn nvlist_fdump
+dumps nvlist content for debugging purposes to the given file stream
+.Fa fp .
+.Pp
+The
+.Fn nvlist_size
+function returns the size of the given nvlist after converting it to binary
+buffer with the
+.Fn nvlist_pack
+function.
+.Pp
+The
+.Fn nvlist_pack
+function converts the given nvlist to a binary buffer.
+The function allocates memory for the buffer, which should be freed with the
+.Xr free 3
+function.
+If the
+.Fa sizep
+argument is not
+.Dv NULL ,
+the size of the buffer will be stored there.
+The function returns
+.Dv NULL
+in case of an error (allocation failure).
+If the nvlist contains any file descriptors
+.Dv NULL
+will be returned.
+The nvlist must not be in error state.
+.Pp
+The
+.Fn nvlist_unpack
+function converts the given buffer to the nvlist.
+The
+.Fa flags
+argument defines what type of the top level nvlist is expected to be.
+Flags are set up using the
+.Fn nvlist_create
+function.
+If the nvlist flags do not match the flags passed to
+.Fn nvlist_unpack ,
+the nvlist will not be returned.
+Every nested nvlist list should be checked using
+.Fn nvlist_flags
+function.
+The function returns
+.Dv NULL
+in case of an error.
+.Pp
+The
+.Fn nvlist_send
+function sends the given nvlist over the socket given by the
+.Fa sock
+argument.
+Note that nvlist that contains file descriptors can only be send over
+.Xr unix 4
+domain sockets.
+.Pp
+The
+.Fn nvlist_recv
+function receives nvlist over the socket given by the
+.Fa sock
+argument.
+The
+.Fa flags
+argument defines what type of the top level nvlist is expected to be.
+Flags are set up using the
+.Fn nvlist_create
+function.
+If the nvlist flags do not match the flags passed to
+.Fn nvlist_recv ,
+the nvlist will not be returned.
+Every nested nvlist list should be checked using
+.Fn nvlist_flags
+function.
+.Pp
+The
+.Fn nvlist_xfer
+function sends the given nvlist over the socket given by the
+.Fa sock
+argument and receives nvlist over the same socket.
+The
+.Fa flags
+argument defines what type of the top level nvlist is expected to be.
+Flags are set up using the
+.Fn nvlist_create
+function.
+If the nvlist flags do not match the flags passed to
+.Fn nvlist_xfer ,
+the nvlist will not be returned.
+Every nested nvlist list should be checked using
+.Fn nvlist_flags
+function.
+The given nvlist is always destroyed.
+.Pp
+The
+.Fn nvlist_next
+function iterates over the given nvlist returning names and types of subsequent
+elements.
+The
+.Fa cookiep
+argument allows the function to figure out which element should be returned
+next.
+The
+.Va *cookiep
+should be set to
+.Dv NULL
+for the first call and should not be changed later.
+Returning
+.Dv NULL
+means there are no more elements on the nvlist.
+The
+.Fa typep
+argument can be NULL.
+Elements may not be removed from the nvlist while traversing it.
+The nvlist must not be in error state.
+Note that
+.Fn nvlist_next
+will handle
+.Va cookiep
+being set to
+.Dv NULL .
+In this case first element is returned or
+.Dv NULL
+if nvlist is empty.
+This behavior simplifies removing the first element from the list.
+.Pp
+The
+.Fn nvlist_exists
+function returns
+.Dv true
+if element of the given name exists (besides of its type) or
+.Dv false
+otherwise.
+The nvlist must not be in error state.
+.Pp
+The
+.Fn nvlist_exists_type
+function returns
+.Dv true
+if element of the given name and the given type exists or
+.Dv false
+otherwise.
+The nvlist must not be in error state.
+.Pp
+The
+.Fn nvlist_exists_null ,
+.Fn nvlist_exists_bool ,
+.Fn nvlist_exists_number ,
+.Fn nvlist_exists_string ,
+.Fn nvlist_exists_nvlist ,
+.Fn nvlist_exists_descriptor ,
+.Fn nvlist_exists_binary ,
+.Fn nvlist_exists_bool_array ,
+.Fn nvlist_exists_number_array ,
+.Fn nvlist_exists_string_array ,
+.Fn nvlist_exists_nvlist_array ,
+.Fn nvlist_exists_descriptor_array
+functions return
+.Dv true
+if element of the given name and the given type determined by the function name
+exists or
+.Dv false
+otherwise.
+The nvlist must not be in error state.
+.Pp
+The
+.Fn nvlist_add_null ,
+.Fn nvlist_add_bool ,
+.Fn nvlist_add_number ,
+.Fn nvlist_add_string ,
+.Fn nvlist_add_stringf ,
+.Fn nvlist_add_stringv ,
+.Fn nvlist_add_nvlist ,
+.Fn nvlist_add_descriptor ,
+.Fn nvlist_add_binary ,
+.Fn nvlist_add_bool_array ,
+.Fn nvlist_add_number_array ,
+.Fn nvlist_add_string_array ,
+.Fn nvlist_add_nvlist_array ,
+.Fn nvlist_add_descriptor_array
+functions add element to the given nvlist.
+When adding string or binary buffor the functions will allocate memory
+and copy the data over.
+When adding nvlist, the nvlist will be cloned and clone will be added.
+When adding descriptor, the descriptor will be duplicated using the
+.Xr dup 2
+system call and the new descriptor will be added.
+The array functions will fail if there are any
+.Dv NULL
+elements in the array, or if the array pointer is
+.Dv NULL .
+If an error occurs while adding new element, internal error is set which can be
+examined using the
+.Fn nvlist_error
+function.
+.Pp
+The
+.Fn nvlist_move_string ,
+.Fn nvlist_move_nvlist ,
+.Fn nvlist_move_descriptor ,
+.Fn nvlist_move_binary ,
+.Fn nvlist_move_bool_array ,
+.Fn nvlist_move_number_array ,
+.Fn nvlist_move_string_array ,
+.Fn nvlist_move_nvlist_array ,
+.Fn nvlist_move_descriptor_array
+functions add new element to the given nvlist, but unlike
+.Fn nvlist_add_<type>
+functions they will consume the given resource.
+In the case of strings, descriptors, or nvlists every elements must be
+unique, or it could cause a double free.
+The array functions will fail if there are any
+.Dv NULL
+elements, or if the array pointer is
+.Dv NULL .
+If an error occurs while adding new element, the resource is destroyed and
+internal error is set which can be examined using the
+.Fn nvlist_error
+function.
+.Pp
+The
+.Fn nvlist_get_bool ,
+.Fn nvlist_get_number ,
+.Fn nvlist_get_string ,
+.Fn nvlist_get_nvlist ,
+.Fn nvlist_get_descriptor ,
+.Fn nvlist_get_binary ,
+.Fn nvlist_get_bool_array ,
+.Fn nvlist_get_number_array ,
+.Fn nvlist_get_string_array ,
+.Fn nvlist_get_nvlist_array ,
+.Fn nvlist_get_descriptor_array
+functions return the value that corresponds to the given key name.
+In the case of strings, nvlists, descriptors, binary, or arrays, the returned
+resource should not be modified - they still belong to the nvlist.
+If an element of the given name does not exist, the program will be aborted.
+To avoid this, the caller should check for the existence of the name before
+trying to obtain the value, or use the
+.Xr dnvlist 3
+extension, which can provide a default value in the case of a missing element.
+The nvlist must not be in error state.
+.Pp
+The
+.Fn nvlist_get_parent
+function returns the parent nvlist of the nested nvlist.
+.Pp
+The
+.Fn nvlist_get_array_next
+function returns the next element from the array or
+.Dv NULL
+if the nvlist is not in array or it is the last element.
+Note that
+.Fn nvlist_get_array_next
+only works if you added the nvlist array using the
+.Fn nvlist_move_nvlist_array
+or
+.Fn nvlist_add_nvlist_array
+functions.
+.Pp
+The
+.Fn nvlist_get_pararr
+function returns the next element in the array, or if not available
+the parent of the nested nvlist.
+.Pp
+The
+.Fn nvlist_take_bool ,
+.Fn nvlist_take_number ,
+.Fn nvlist_take_string ,
+.Fn nvlist_take_nvlist ,
+.Fn nvlist_take_descriptor ,
+.Fn nvlist_take_binary ,
+.Fn nvlist_take_bool_array ,
+.Fn nvlist_take_number_array ,
+.Fn nvlist_take_string_array ,
+.Fn nvlist_take_nvlist_array ,
+.Fn nvlist_take_descriptor_array
+functions return value associated with the given name and remove the element
+from the nvlist.
+In case of string and binary values, the caller is responsible for free returned
+memory using the
+.Xr free 3
+function.
+In case of nvlist, the caller is responsible for destroying returned nvlist
+using the
+.Fn nvlist_destroy
+function.
+In case of descriptor, the caller is responsible for closing returned descriptor
+using the
+.Fn close 2
+system call.
+If an element of the given name does not exist, the program will be aborted.
+To avoid that the caller should check for the existence of the given name
+before trying to obtain the value, or use the
+.Xr dnvlist 3
+extension, which can provide a default value in the case of a missing element.
+In the case of an array of strings or binary values, the caller is responsible
+for freeing every element of the array using the
+.Xr free 3
+function.
+In the case of an array of nvlists, the caller is responsible for destroying
+every element of array using the
+.Fn nvlist_destroy
+function.
+In the case of descriptors, the caller is responsible for closing every
+element of array using the
+.Fn close 2
+system call.
+In every case involving an array, the caller must also free the pointer to
+the array using the
+.Xr free 3
+function.
+The nvlist must not be in error state.
+.Pp
+The
+.Fn nvlist_free
+function removes element of the given name from the nvlist (besides of its type)
+and frees all resources associated with it.
+If element of the given name does not exist, the program will be aborted.
+The nvlist must not be in error state.
+.Pp
+The
+.Fn nvlist_free_type
+function removes element of the given name and the given type from the nvlist
+and frees all resources associated with it.
+If element of the given name and the given type does not exist, the program
+will be aborted.
+The nvlist must not be in error state.
+.Pp
+The
+.Fn nvlist_free_null ,
+.Fn nvlist_free_bool ,
+.Fn nvlist_free_number ,
+.Fn nvlist_free_string ,
+.Fn nvlist_free_nvlist ,
+.Fn nvlist_free_descriptor ,
+.Fn nvlist_free_binary ,
+.Fn nvlist_free_bool_array ,
+.Fn nvlist_free_number_array ,
+.Fn nvlist_free_string_array ,
+.Fn nvlist_free_nvlist_array ,
+.Fn nvlist_free_descriptor_array
+functions remove element of the given name and the given type determined by the
+function name from the nvlist and free all resources associated with it.
+If element of the given name and the given type does not exist, the program
+will be aborted.
+The nvlist must not be in error state.
+.Sh EXAMPLES
+The following example demonstrates how to prepare an nvlist and send it over
+.Xr unix 4
+domain socket.
+.Bd -literal
+nvlist_t *nvl;
+int fd;
+
+fd = open("/tmp/foo", O_RDONLY);
+if (fd < 0)
+ err(1, "open(\\"/tmp/foo\\") failed");
+
+nvl = nvlist_create(0);
+/*
+ * There is no need to check if nvlist_create() succeeded,
+ * as the nvlist_add_<type>() functions can cope.
+ * If it failed, nvlist_send() will fail.
+ */
+nvlist_add_string(nvl, "filename", "/tmp/foo");
+nvlist_add_number(nvl, "flags", O_RDONLY);
+/*
+ * We just want to send the descriptor, so we can give it
+ * for the nvlist to consume (that's why we use nvlist_move
+ * not nvlist_add).
+ */
+nvlist_move_descriptor(nvl, "fd", fd);
+if (nvlist_send(sock, nvl) < 0) {
+ nvlist_destroy(nvl);
+ err(1, "nvlist_send() failed");
+}
+nvlist_destroy(nvl);
+.Ed
+.Pp
+Receiving nvlist and getting data:
+.Bd -literal
+nvlist_t *nvl;
+const char *command;
+char *filename;
+int fd;
+
+nvl = nvlist_recv(sock, 0);
+if (nvl == NULL)
+ err(1, "nvlist_recv() failed");
+
+/* For command we take pointer to nvlist's buffer. */
+command = nvlist_get_string(nvl, "command");
+/*
+ * For filename we remove it from the nvlist and take
+ * ownership of the buffer.
+ */
+filename = nvlist_take_string(nvl, "filename");
+/* The same for the descriptor. */
+fd = nvlist_take_descriptor(nvl, "fd");
+
+printf("command=%s filename=%s fd=%d\n", command, filename, fd);
+
+nvlist_destroy(nvl);
+free(filename);
+close(fd);
+/* command was freed by nvlist_destroy() */
+.Ed
+.Pp
+Iterating over nvlist:
+.Bd -literal
+nvlist_t *nvl;
+const char *name;
+void *cookie;
+int type;
+
+nvl = nvlist_recv(sock, 0);
+if (nvl == NULL)
+ err(1, "nvlist_recv() failed");
+
+cookie = NULL;
+while ((name = nvlist_next(nvl, &type, &cookie)) != NULL) {
+ printf("%s=", name);
+ switch (type) {
+ case NV_TYPE_NUMBER:
+ printf("%ju", (uintmax_t)nvlist_get_number(nvl, name));
+ break;
+ case NV_TYPE_STRING:
+ printf("%s", nvlist_get_string(nvl, name));
+ break;
+ default:
+ printf("N/A");
+ break;
+ }
+ printf("\\n");
+}
+.Ed
+.Pp
+Iterating over every nested nvlist:
+.Bd -literal
+nvlist_t *nvl;
+const char *name;
+void *cookie;
+int type;
+
+nvl = nvlist_recv(sock, 0);
+if (nvl == NULL)
+ err(1, "nvlist_recv() failed");
+
+cookie = NULL;
+do {
+ while ((name = nvlist_next(nvl, &type, &cookie)) != NULL) {
+ if (type == NV_TYPE_NVLIST) {
+ nvl = nvlist_get_nvlist(nvl, name);
+ cookie = NULL;
+ }
+ }
+} while ((nvl = nvlist_get_parent(nvl, &cookie)) != NULL);
+.Ed
+.Pp
+Iterating over every nested nvlist and every nvlist element:
+.Bd -literal
+nvlist_t *nvl;
+const nvlist_t * const *array;
+const char *name;
+void *cookie;
+int type;
+
+nvl = nvlist_recv(sock, 0);
+if (nvl == null)
+ err(1, "nvlist_recv() failed");
+
+cookie = null;
+do {
+ while ((name = nvlist_next(nvl, &type, &cookie)) != NULL) {
+ if (type == NV_TYPE_NVLIST) {
+ nvl = nvlist_get_nvlist(nvl, name);
+ cookie = NULL;
+ } else if (type == NV_TYPE_NVLIST_ARRAY) {
+ nvl = nvlist_get_nvlist_array(nvl, name, NULL)[0];
+ cookie = NULL;
+ }
+ }
+} while ((nvl = nvlist_get_pararr(nvl, &cookie)) != NULL);
+.Ed
+.Pp
+Or alternatively:
+.Bd -literal
+nvlist_t *nvl, *tmp;
+const nvlist_t * const *array;
+const char *name;
+void *cookie;
+int type;
+
+nvl = nvlist_recv(sock, 0);
+if (nvl == null)
+ err(1, "nvlist_recv() failed");
+
+cooke = NULL;
+tmp = nvl;
+do {
+ do {
+ nvl = tmp;
+ while ((name = nvlist_next(nvl, &type, &cookie)) != NULL) {
+ if (type == NV_TYPE_NVLIST) {
+ nvl = nvlist_get_nvlist(nvl,
+ name);
+ cookie = NULL;
+ } else if (type == NV_TYPE_NVLIST_ARRAY) {
+ nvl = nvlist_get_nvlist_array(nvl, name,
+ NULL)[0];
+ cookie = NULL;
+ }
+ }
+ cookie = NULL;
+ } while ((tmp = nvlist_get_array_next(nvl)) != NULL);
+} while ((tmp = nvlist_get_parent(nvl, &cookie)) != NULL);
+.Ed
+.Sh SEE ALSO
+.Xr close 2 ,
+.Xr dup 2 ,
+.Xr open 2 ,
+.Xr err 3 ,
+.Xr free 3 ,
+.Xr printf 3 ,
+.Xr unix 4
+.Sh HISTORY
+The
+.Nm libnv
+library appeared in
+.Fx 11.0 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm libnv
+library was implemented by
+.An Pawel Jakub Dawidek Aq Mt pawel@dawidek.net
+under sponsorship from the FreeBSD Foundation.
Index: share/man/man9/pci.9
===================================================================
--- share/man/man9/pci.9
+++ share/man/man9/pci.9
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd November 5, 2015
+.Dd January 3, 2015
.Dt PCI 9
.Os
.Sh NAME
@@ -47,6 +47,8 @@
.Nm pci_get_powerstate ,
.Nm pci_get_vpd_ident ,
.Nm pci_get_vpd_readonly ,
+.Nm pci_iov_attach ,
+.Nm pci_iov_detach ,
.Nm pci_msi_count ,
.Nm pci_msix_count ,
.Nm pci_pending_msix ,
@@ -134,6 +136,11 @@
.Fn pcie_read_config "device_t dev" "int reg" "int width"
.Ft void
.Fn pcie_write_config "device_t dev" "int reg" "uint32_t val" "int width"
+.In dev/pci/pci_iov.h
+.Ft int
+.Fn pci_iov_attach "device_t dev" "nvlist_t *pf_schema" "nvlist_t *vf_schema"
+.Ft int
+.Fn pci_iov_detach "device_t dev"
.Sh DESCRIPTION
The
.Nm
@@ -504,6 +511,75 @@
.Er EOPNOTSUPP .
.Pp
The
+.Fn pci_iov_attach
+function is used to advertise that the given device
+.Pq and associated device driver
+supports PCI Single-Root I/O Virtualization
+.Pq SR-IOV .
+A driver that supports SR-IOV must implement the
+.Xr PCI_IOV_INIT 9 ,
+.Xr PCI_IOV_ADD_VF 9
+and
+.Xr PCI_IOV_UNINIT 9
+methods.
+This function should be called during the
+.Xr DEVICE_ATTACH 9
+method.
+If this function returns an error, it is recommended that the device driver
+still successfully attaches, but runs with SR-IOV disabled.
+The
+.Fa pf_schema
+and
+.Fa vf_schema
+parameters are used to define what device-specific configuration parameters the
+device driver accepts when SR-IOV is enabled for the Physical Function
+.Pq PF
+and for individual Virtual Functions
+.Pq VFs
+respectively.
+See
+.Xr pci_iov_schema 9
+for details on how to construct the schema.
+If either the
+.Pa pf_schema
+or
+.Pa vf_schema
+is invalid or specifies parameter names that conflict with parameter names that
+are already in use,
+.Fn pci_iov_attach
+will return an error and SR-IOV will not be available on the PF device.
+If a driver does not accept configuration parameters for either the PF device
+or the VF devices, the driver must pass an empty schema for that device.
+The SR-IOV infrastructure takes ownership of the
+.Fa pf_schema
+and
+.Fa vf_schema
+and is responsible for freeing them.
+The driver must never free the schemas itself.
+.Pp
+The
+.Fn pci_iov_detach
+function is used to advise the SR-IOV infrastructure that the driver for the
+given device is attempting to detach and that all SR-IOV resources for the
+device must be released.
+This function must be called during the
+.Xr DEVICE_DETACH 9
+method if
+.Fn pci_iov_attach
+was successfully called on the device and
+.Fn pci_iov_detach
+has not subsequently been called on the device and returned no error.
+If this function returns an error, the
+.Xr DEVICE_DETACH 9
+method must fail and return an error, as detaching the PF driver while VF
+devices are active would cause system instability.
+This function is safe to call and will always succeed if
+.Fn pci_iov_attach
+previously failed with an error on the given device, or if
+.Fn pci_iov_attach
+was never called on the device.
+.Pp
+The
.Fn pci_save_state
and
.Fn pci_restore_state
Index: share/man/man9/pci_iov_schema.9
===================================================================
--- share/man/man9/pci_iov_schema.9
+++ share/man/man9/pci_iov_schema.9
@@ -0,0 +1,265 @@
+.\"
+.\" Copyright (c) 2014 Sandvine Inc.
+.\" 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$
+.\"
+.Dd July 8, 2015
+.Dt PCI_IOV_SCHEMA 9
+.Os
+.Sh NAME
+.Nm pci_iov_schema ,
+.Nm pci_iov_schema_alloc_node ,
+.Nm pci_iov_schema_add_bool ,
+.Nm pci_iov_schema_add_string ,
+.Nm pci_iov_schema_add_uint8 ,
+.Nm pci_iov_schema_add_uint16 ,
+.Nm pci_iov_schema_add_uint32 ,
+.Nm pci_iov_schema_add_uint64 ,
+.Nm pci_iov_schema_add_unicast_mac
+.Nd PCI SR-IOV config schema interface
+.Sh SYNOPSIS
+.In machine/stdarg.h
+.In sys/nv.h
+.In sys/iov_schema.h
+.Ft nvlist_t *
+.Fn pci_iov_schema_alloc_node "void"
+.Ft void
+.Fn pci_iov_schema_add_bool "nvlist_t *schema" "const char *name" \
+"uint32_t flags" "int defaultVal"
+.Ft void
+.Fn pci_iov_schema_add_string "nvlist_t *schema" "const char *name" \
+"uint32_t flags" "const char *defaultVal"
+.Ft void
+.Fn pci_iov_schema_add_uint8 "nvlist_t *schema" "const char *name" \
+"uint32_t flags" "uint8_t defaultVal"
+.Ft void
+.Fn pci_iov_schema_add_uint16 "nvlist_t *schema" "const char *name" \
+"uint32_t flags" "uint16_t defaultVal"
+.Ft void
+.Fn pci_iov_schema_add_uint32 "nvlist_t *schema" "const char *name" \
+"uint32_t flags" "uint32_t defaultVal"
+.Ft void
+.Fn pci_iov_schema_add_uint64 "nvlist_t *schema" "const char *name" \
+"uint32_t flags" "uint64_t defaultVal"
+.Ft void
+.Fn pci_iov_schema_add_unicast_mac "nvlist_t *schema" "const char *name" \
+"uint32_t flags" "const uint8_t *defaultVal"
+.Sh DESCRIPTION
+The PCI Single-Root I/O Virtualization
+.Pq SR-IOV
+configuration schema is a data
+structure that describes the device-specific configuration parameters that a PF
+driver will accept when SR-IOV is enabled on the PF device.
+Each PF driver defines two schema instances: the PF schema and the VF schema.
+The PF schema describes configuration that applies to the PF device as a whole.
+The VF schema describes configuration that applies to an individual VF device.
+Different VF devices may have different configuration applied to them, as long
+as the configuration for each VF conforms to the VF schema.
+.Pp
+A PF driver builds a configuration schema by first allocating a schema node and
+then adding configuration parameter specifications to the schema.
+The configuration parameter specification consists of a name and a value type.
+.Pp
+Configuration parameter names are case-insensitive.
+It is an error to specify two or more configuration parameters with the same
+name.
+It is also an error to specific a configuration parameter that uses the same
+name as a configuration parameter used by the SR-IOV infrastructure.
+See
+.Xr iovctl.conf 5
+for documentation of all configuration parameters used by the SR-IOV
+infrastructure.
+.Pp
+The parameter type constrains the possible values that the configuration
+parameter may take.
+.Pp
+A configuration parameter may be specified as a required parameter by setting
+the
+.Dv IOV_SCHEMA_REQUIRED
+flag in the
+.Pa flags
+argument.
+Required parameters must be specified by the user when SR-IOV is enabled.
+If the user does not specify a required parameter, the SR-IOV infrastructure
+will abort the request to enable SR-IOV and return an error to the user.
+.Pp
+Alternatively, a configuration parameter may be given a default value by
+setting the
+.Dv IOV_SCHEMA_HASDEFAULT
+flag in the
+.Pa flags
+argument.
+If a configuration parameter has a default value but the user has not specified
+a value for that parameter, then the SR-IOV infrastructure will apply
+.Pa defaultVal
+for that parameter in the configuration before passing it to the PF driver.
+It is an error for the value of the
+.Pa defaultVal
+parameter to not conform to the restrictions of the specified type.
+If this flag is not specified then the
+.Pa defaultVal
+argument is ignored.
+This flag is not compatible with the
+.Dv IOV_SCHEMA_REQUIRED
+flag; it is an error to specify both on the same parameter.
+.Pp
+The SR-IOV infrastructure guarantees that all configuration parameters that are
+either specified as required or given a default value will be present in the
+configuration passed to the PF driver.
+Configuration parameters that are neither specified as required nor given a
+default value are optional and may or may not be present in the configuration
+passed to the PF driver.
+.Pp
+It is highly recommended that a PF driver reserve the use of optional parameters
+for configuration that is truly optional.
+For example, a Network Interface PF device might have the option to encapsulate
+all traffic to and from a VF device in a vlan tag.
+The PF driver could expose that option as a "vlan" parameter accepting an
+integer argument specifying the vlan tag.
+In this case, it would be appropriate to set the "vlan" parameter as an optional
+parameter as it would be legitimate for a VF to be configured to have no vlan
+tagging enabled at all.
+.Pp
+Alternatively, if the PF device had an boolean option that controlled whether
+the VF was allowed to change its MAC address, it would not be appropriate to
+set this parameter as optional.
+The PF driver must either allow the MAC to change or not, so it would be more
+appropriate for the PF driver to document the default behaviour by specifying
+a default value in the schema
+.Po or potentially force the user to make the choice by setting the parameter
+to be required
+.Pc .
+.Pp
+Configuration parameters that have security implications must default to the
+most secure configuration possible.
+.Pp
+All device-specific configuration parameters must be documented in the manual
+page for the PF driver, or in a separate manual page that is cross-referenced
+from the main driver manual page.
+.Pp
+It is not necessary for a PF driver to check for failure from any of these
+functions.
+If an error occurs, it is flagged in the schema.
+The
+.Xr pci_iov_attach 9
+function checks for this error and will fail to initialize SR-IOV on the PF
+device if an error is set in the schema.
+If this occurs, it is recommended that the PF driver still succeed in attaching
+and run with SR-IOV disabled on the device.
+.Pp
+The
+.Fn pci_iov_schema_alloc_node
+function is used to allocate an empty configuration schema.
+It is not necessary to check for failure from this function.
+The SR-IOV infrastructure will gracefully handle failure to allocate a schema
+and will simply not enable SR-IOV on the PF device.
+.Pp
+The
+.Fn pci_iov_schema_add_bool
+function is used to specify a configuration parameter in the given schema with
+the name
+.Pa name
+and having a boolean type.
+Boolean values can only take the value true or false (1 or 0, respectively).
+.Pp
+The
+.Fn pci_iov_schema_add_string
+function is used to specify a configuration parameter in the given schema with
+the name
+.Pa name
+and having a string type.
+String values are standard C strings.
+.Pp
+The
+.Fn pci_iov_schema_add_uint8
+function is used to specify a configuration parameter in the given schema with
+the name
+.Pa name
+and having a
+.Vt uint8_t
+type.
+Values of type
+.Vt uint8_t
+are unsigned integers in the range 0 to 255, inclusive.
+.Pp
+The
+.Fn pci_iov_schema_add_uint16
+function is used to specify a configuration parameter in the given schema with
+the name
+.Pa name
+and having a
+.Vt uint16_t
+type.
+Values of type
+.Vt uint16_t
+are unsigned integers in the range 0 to 65535, inclusive.
+.Pp
+The
+.Fn pci_iov_schema_add_uint32
+function is used to specify a configuration parameter in the given schema with
+the name
+.Pa name
+and having a
+.Vt uint32_t
+type.
+Values of type
+.Vt uint32_t
+are unsigned integers in the range 0 to
+.Pq 2**32 - 1 ,
+inclusive.
+.Pp
+The
+.Fn pci_iov_schema_add_uint64
+function is used to specify a configuration parameter in the given schema with
+the name
+.Pa name
+and having a
+.Vt uint64_t
+type.
+Values of type
+.Vt uint64_t
+are unsigned integers in the range 0 to
+.Pq 2**64 - 1 ,
+inclusive.
+.Pp
+The
+.Fn pci_iov_schema_add_unicast_mac
+function is used to specify a configuration parameter in the given schema with
+the name
+.Pa name
+and having a unicast-mac type.
+Values of type unicast-mac are binary values exactly 6 bytes long.
+The MAC address is guaranteed to not be a multicast or broadcast address.
+.Sh RETURN VALUES
+The
+.Fn pci_iov_schema_alloc_node
+function returns a pointer to the allocated schema, or NULL if a failure occurs.
+.Sh SEE ALSO
+.Xr pci 9 ,
+.Xr PCI_IOV_ADD_VF 9 ,
+.Xr PCI_IOV_INIT 9
+.Sh AUTHORS
+This manual page was written by
+.An Ryan Stone Aq rstone@FreeBSD.org .
Index: sys/amd64/conf/GENERIC
===================================================================
--- sys/amd64/conf/GENERIC
+++ sys/amd64/conf/GENERIC
@@ -90,6 +90,7 @@
device acpi
options ACPI_DMAR
device pci
+options PCI_IOV # PCI SR-IOV support
# Floppy drives
device fdc
Index: sys/cddl/compat/opensolaris/sys/nvpair.h
===================================================================
--- sys/cddl/compat/opensolaris/sys/nvpair.h
+++ sys/cddl/compat/opensolaris/sys/nvpair.h
@@ -42,29 +42,19 @@
*/
#define nvlist_add_binary illumos_nvlist_add_binary
#define nvlist_add_bool illumos_nvlist_add_bool
+#define nvlist_add_bool_array illumos_nvlist_add_bool_array
#define nvlist_add_descriptor illumos_nvlist_add_descriptor
+#define nvlist_add_descriptor_array illumos_nvlist_add_descriptor_array
#define nvlist_add_null illumos_nvlist_add_null
#define nvlist_add_number illumos_nvlist_add_number
+#define nvlist_add_number_array illumos_nvlist_add_number_array
#define nvlist_add_nvlist illumos_nvlist_add_nvlist
+#define nvlist_add_nvlist_array illumos_nvlist_add_nvlist_array
#define nvlist_add_nvpair illumos_nvlist_add_nvpair
#define nvlist_add_string illumos_nvlist_add_string
+#define nvlist_add_string_array illumos_nvlist_add_string_array
#define nvlist_add_stringf illumos_nvlist_add_stringf
#define nvlist_add_stringv illumos_nvlist_add_stringv
-#define nvlist_addf_binary illumos_nvlist_addf_binary
-#define nvlist_addf_bool illumos_nvlist_addf_bool
-#define nvlist_addf_descriptor illumos_nvlist_addf_descriptor
-#define nvlist_addf_null illumos_nvlist_addf_null
-#define nvlist_addf_number illumos_nvlist_addf_number
-#define nvlist_addf_nvlist illumos_nvlist_addf_nvlist
-#define nvlist_addf_string illumos_nvlist_addf_string
-#define nvlist_addv_binary illumos_nvlist_addv_binary
-#define nvlist_addv_bool illumos_nvlist_addv_bool
-#define nvlist_addv_descriptor illumos_nvlist_addv_descriptor
-#define nvlist_addv_null illumos_nvlist_addv_null
-#define nvlist_addv_number illumos_nvlist_addv_number
-#define nvlist_addv_nvlist illumos_nvlist_addv_nvlist
-#define nvlist_addv_string illumos_nvlist_addv_string
-#define nvlist_check_header illumos_nvlist_check_header
#define nvlist_clone illumos_nvlist_clone
#define nvlist_create illumos_nvlist_create
#define nvlist_descriptors illumos_nvlist_descriptors
@@ -75,92 +65,61 @@
#define nvlist_exists illumos_nvlist_exists
#define nvlist_exists_binary illumos_nvlist_exists_binary
#define nvlist_exists_bool illumos_nvlist_exists_bool
+#define nvlist_exists_bool_array illumos_nvlist_exists_bool_array
#define nvlist_exists_descriptor illumos_nvlist_exists_descriptor
+#define nvlist_exists_descriptor_array illumos_nvlist_exists_descriptor_array
#define nvlist_exists_null illumos_nvlist_exists_null
#define nvlist_exists_number illumos_nvlist_exists_number
+#define nvlist_exists_number_array illumos_nvlist_exists_number_array
#define nvlist_exists_nvlist illumos_nvlist_exists_nvlist
+#define nvlist_exists_nvlist_array illumos_nvlist_exists_nvlist_array
#define nvlist_exists_string illumos_nvlist_exists_string
+#define nvlist_exists_string_array illumos_nvlist_exists_string_array
#define nvlist_exists_type illumos_nvlist_exists_type
-#define nvlist_existsf illumos_nvlist_existsf
-#define nvlist_existsf_binary illumos_nvlist_existsf_binary
-#define nvlist_existsf_bool illumos_nvlist_existsf_bool
-#define nvlist_existsf_descriptor illumos_nvlist_existsf_descriptor
-#define nvlist_existsf_null illumos_nvlist_existsf_null
-#define nvlist_existsf_number illumos_nvlist_existsf_number
-#define nvlist_existsf_nvlist illumos_nvlist_existsf_nvlist
-#define nvlist_existsf_string illumos_nvlist_existsf_string
-#define nvlist_existsf_type illumos_nvlist_existsf_type
-#define nvlist_existsv illumos_nvlist_existsv
-#define nvlist_existsv_binary illumos_nvlist_existsv_binary
-#define nvlist_existsv_bool illumos_nvlist_existsv_bool
-#define nvlist_existsv_descriptor illumos_nvlist_existsv_descriptor
-#define nvlist_existsv_null illumos_nvlist_existsv_null
-#define nvlist_existsv_number illumos_nvlist_existsv_number
-#define nvlist_existsv_nvlist illumos_nvlist_existsv_nvlist
-#define nvlist_existsv_string illumos_nvlist_existsv_string
-#define nvlist_existsv_type illumos_nvlist_existsv_type
#define nvlist_fdump illumos_nvlist_fdump
#define nvlist_first_nvpair illumos_nvlist_first_nvpair
+#define nvlist_flags illumos_nvlist_flags
#define nvlist_free illumos_nvlist_free
#define nvlist_free_binary illumos_nvlist_free_binary
+#define nvlist_free_binary_array illumos_nvlist_free_binary_array
#define nvlist_free_bool illumos_nvlist_free_bool
+#define nvlist_free_bool_array illumos_nvlist_free_bool_array
#define nvlist_free_descriptor illumos_nvlist_free_descriptor
+#define nvlist_free_descriptor_array illumos_nvlist_free_descriptor_array
#define nvlist_free_null illumos_nvlist_free_null
#define nvlist_free_number illumos_nvlist_free_number
+#define nvlist_free_number_array illumos_nvlist_free_number_array
#define nvlist_free_nvlist illumos_nvlist_free_nvlist
+#define nvlist_free_nvlist_array illumos_nvlist_free_nvlist_array
#define nvlist_free_nvpair illumos_nvlist_free_nvpair
#define nvlist_free_string illumos_nvlist_free_string
+#define nvlist_free_string_array illumos_nvlist_free_string_array
#define nvlist_free_type illumos_nvlist_free_type
-#define nvlist_freef illumos_nvlist_freef
-#define nvlist_freef_binary illumos_nvlist_freef_binary
-#define nvlist_freef_bool illumos_nvlist_freef_bool
-#define nvlist_freef_descriptor illumos_nvlist_freef_descriptor
-#define nvlist_freef_null illumos_nvlist_freef_null
-#define nvlist_freef_number illumos_nvlist_freef_number
-#define nvlist_freef_nvlist illumos_nvlist_freef_nvlist
-#define nvlist_freef_string illumos_nvlist_freef_string
-#define nvlist_freef_type illumos_nvlist_freef_type
-#define nvlist_freev illumos_nvlist_freev
-#define nvlist_freev_binary illumos_nvlist_freev_binary
-#define nvlist_freev_bool illumos_nvlist_freev_bool
-#define nvlist_freev_descriptor illumos_nvlist_freev_descriptor
-#define nvlist_freev_null illumos_nvlist_freev_null
-#define nvlist_freev_number illumos_nvlist_freev_number
-#define nvlist_freev_nvlist illumos_nvlist_freev_nvlist
-#define nvlist_freev_string illumos_nvlist_freev_string
-#define nvlist_freev_type illumos_nvlist_freev_type
+#define nvlist_get_array_next illumos_nvlist_get_array_next
#define nvlist_get_binary illumos_nvlist_get_binary
#define nvlist_get_bool illumos_nvlist_get_bool
+#define nvlist_get_bool_array illumos_nvlist_get_bool_array
#define nvlist_get_descriptor illumos_nvlist_get_descriptor
+#define nvlist_get_descriptor_array illumos_nvlist_get_descriptor_array
#define nvlist_get_number illumos_nvlist_get_number
+#define nvlist_get_number_array illumos_nvlist_get_number_array
#define nvlist_get_nvlist illumos_nvlist_get_nvlist
#define nvlist_get_nvpair illumos_nvlist_get_nvpair
+#define nvlist_get_nvpair_parent illumos_nvlist_get_nvpair_parent
+#define nvlist_get_pararr illumos_nvlist_get_pararr
+#define nvlist_get_parent illumos_nvlist_get_parent
#define nvlist_get_string illumos_nvlist_get_string
-#define nvlist_getf_binary illumos_nvlist_getf_binary
-#define nvlist_getf_bool illumos_nvlist_getf_bool
-#define nvlist_getf_descriptor illumos_nvlist_getf_descriptor
-#define nvlist_getf_number illumos_nvlist_getf_number
-#define nvlist_getf_nvlist illumos_nvlist_getf_nvlist
-#define nvlist_getf_string illumos_nvlist_getf_string
-#define nvlist_getv_binary illumos_nvlist_getv_binary
-#define nvlist_getv_bool illumos_nvlist_getv_bool
-#define nvlist_getv_descriptor illumos_nvlist_getv_descriptor
-#define nvlist_getv_number illumos_nvlist_getv_number
-#define nvlist_getv_nvlist illumos_nvlist_getv_nvlist
-#define nvlist_getv_string illumos_nvlist_getv_string
+#define nvlist_in_array illumos_nvlist_in_array
#define nvlist_move_binary illumos_nvlist_move_binary
+#define nvlist_move_bool_array illumos_nvlist_move_bool_array
#define nvlist_move_descriptor illumos_nvlist_move_descriptor
+#define nvlist_move_descriptor_array illumos_nvlist_move_descriptor_array
+#define nvlist_move_number_array illumos_nvlist_move_number_array
#define nvlist_move_nvlist illumos_nvlist_move_nvlist
+#define nvlist_move_nvlist_array illumos_nvlist_move_nvlist_array
#define nvlist_move_nvpair illumos_nvlist_move_nvpair
#define nvlist_move_string illumos_nvlist_move_string
-#define nvlist_movef_binary illumos_nvlist_movef_binary
-#define nvlist_movef_descriptor illumos_nvlist_movef_descriptor
-#define nvlist_movef_nvlist illumos_nvlist_movef_nvlist
-#define nvlist_movef_string illumos_nvlist_movef_string
-#define nvlist_movev_binary illumos_nvlist_movev_binary
-#define nvlist_movev_descriptor illumos_nvlist_movev_descriptor
-#define nvlist_movev_nvlist illumos_nvlist_movev_nvlist
-#define nvlist_movev_string illumos_nvlist_movev_string
+#define nvlist_move_string_array illumos_nvlist_move_string_array
#define nvlist_ndescriptors illumos_nvlist_ndescriptors
#define nvlist_next illumos_nvlist_next
#define nvlist_next_nvpair illumos_nvlist_next_nvpair
@@ -168,86 +127,82 @@
#define nvlist_prev_nvpair illumos_nvlist_prev_nvpair
#define nvlist_recv illumos_nvlist_recv
#define nvlist_remove_nvpair illumos_nvlist_remove_nvpair
-#define nvlist_report_missing illumos_nvlist_report_missing
#define nvlist_send illumos_nvlist_send
+#define nvlist_set_array_next illumos_nvlist_set_array_next
#define nvlist_set_error illumos_nvlist_set_error
+#define nvlist_set_flags illumos_nvlist_set_flags
+#define nvlist_set_parent illumos_nvlist_set_parent
#define nvlist_size illumos_nvlist_size
#define nvlist_take_binary illumos_nvlist_take_binary
#define nvlist_take_bool illumos_nvlist_take_bool
+#define nvlist_take_bool_array illumos_nvlist_take_bool_array
#define nvlist_take_descriptor illumos_nvlist_take_descriptor
+#define nvlist_take_descriptor_array illumos_nvlist_take_descriptor_array
#define nvlist_take_number illumos_nvlist_take_number
+#define nvlist_take_number_array illumos_nvlist_take_number_array
#define nvlist_take_nvlist illumos_nvlist_take_nvlist
+#define nvlist_take_nvlist_array illumos_nvlist_take_nvlist_array
#define nvlist_take_nvpair illumos_nvlist_take_nvpair
#define nvlist_take_string illumos_nvlist_take_string
-#define nvlist_takef_binary illumos_nvlist_takef_binary
-#define nvlist_takef_bool illumos_nvlist_takef_bool
-#define nvlist_takef_descriptor illumos_nvlist_takef_descriptor
-#define nvlist_takef_number illumos_nvlist_takef_number
-#define nvlist_takef_nvlist illumos_nvlist_takef_nvlist
-#define nvlist_takef_string illumos_nvlist_takef_string
-#define nvlist_takev_binary illumos_nvlist_takev_binary
-#define nvlist_takev_bool illumos_nvlist_takev_bool
-#define nvlist_takev_descriptor illumos_nvlist_takev_descriptor
-#define nvlist_takev_number illumos_nvlist_takev_number
-#define nvlist_takev_nvlist illumos_nvlist_takev_nvlist
-#define nvlist_takev_string illumos_nvlist_takev_string
+#define nvlist_take_string_array illumos_nvlist_take_string_array
#define nvlist_unpack illumos_nvlist_unpack
+#define nvlist_unpack_header illumos_nvlist_unpack_header
#define nvlist_xfer illumos_nvlist_xfer
-#define nvlist_xpack illumos_nvlist_xpack
-#define nvlist_xunpack illumos_nvlist_xunpack
-#define nvpair_allocv illumos_nvpair_allocv
#define nvpair_assert illumos_nvpair_assert
#define nvpair_clone illumos_nvpair_clone
#define nvpair_create_binary illumos_nvpair_create_binary
#define nvpair_create_bool illumos_nvpair_create_bool
+#define nvpair_create_bool_array illumos_nvpair_create_bool_array
#define nvpair_create_descriptor illumos_nvpair_create_descriptor
+#define nvpair_create_descriptor_array illumos_nvpair_create_descriptor_array
#define nvpair_create_null illumos_nvpair_create_null
#define nvpair_create_number illumos_nvpair_create_number
+#define nvpair_create_number_array illumos_nvpair_create_number_array
#define nvpair_create_nvlist illumos_nvpair_create_nvlist
+#define nvpair_create_nvlist_array illumos_nvpair_create_nvlist_array
#define nvpair_create_string illumos_nvpair_create_string
+#define nvpair_create_string_array illumos_nvpair_create_string_array
#define nvpair_create_stringf illumos_nvpair_create_stringf
#define nvpair_create_stringv illumos_nvpair_create_stringv
-#define nvpair_createf_binary illumos_nvpair_createf_binary
-#define nvpair_createf_bool illumos_nvpair_createf_bool
-#define nvpair_createf_descriptor illumos_nvpair_createf_descriptor
-#define nvpair_createf_null illumos_nvpair_createf_null
-#define nvpair_createf_number illumos_nvpair_createf_number
-#define nvpair_createf_nvlist illumos_nvpair_createf_nvlist
-#define nvpair_createf_string illumos_nvpair_createf_string
-#define nvpair_createv_binary illumos_nvpair_createv_binary
-#define nvpair_createv_bool illumos_nvpair_createv_bool
-#define nvpair_createv_descriptor illumos_nvpair_createv_descriptor
-#define nvpair_createv_null illumos_nvpair_createv_null
-#define nvpair_createv_number illumos_nvpair_createv_number
-#define nvpair_createv_nvlist illumos_nvpair_createv_nvlist
-#define nvpair_createv_string illumos_nvpair_createv_string
#define nvpair_free illumos_nvpair_free
#define nvpair_free_structure illumos_nvpair_free_structure
#define nvpair_get_binary illumos_nvpair_get_binary
#define nvpair_get_bool illumos_nvpair_get_bool
+#define nvpair_get_bool_array illumos_nvpair_get_bool_array
#define nvpair_get_descriptor illumos_nvpair_get_descriptor
+#define nvpair_get_descriptor_array illumos_nvpair_get_descriptor_array
#define nvpair_get_number illumos_nvpair_get_number
+#define nvpair_get_number_array illumos_nvpair_get_number_array
#define nvpair_get_nvlist illumos_nvpair_get_nvlist
#define nvpair_get_string illumos_nvpair_get_string
#define nvpair_header_size illumos_nvpair_header_size
+#define nvpair_init_datasize illumos_nvpair_init_datasize
#define nvpair_insert illumos_nvpair_insert
#define nvpair_move_binary illumos_nvpair_move_binary
+#define nvpair_move_bool_array illumos_nvpair_move_bool_array
#define nvpair_move_descriptor illumos_nvpair_move_descriptor
+#define nvpair_move_descriptor_array illumos_nvpair_move_descriptor_array
+#define nvpair_move_number_array illumos_nvpair_move_number_array
#define nvpair_move_nvlist illumos_nvpair_move_nvlist
+#define nvpair_move_nvlist_array illumos_nvpair_move_nvlist_array
#define nvpair_move_string illumos_nvpair_move_string
-#define nvpair_movef_binary illumos_nvpair_movef_binary
-#define nvpair_movef_descriptor illumos_nvpair_movef_descriptor
-#define nvpair_movef_nvlist illumos_nvpair_movef_nvlist
-#define nvpair_movef_string illumos_nvpair_movef_string
-#define nvpair_movev_binary illumos_nvpair_movev_binary
-#define nvpair_movev_descriptor illumos_nvpair_movev_descriptor
-#define nvpair_movev_nvlist illumos_nvpair_movev_nvlist
-#define nvpair_movev_string illumos_nvpair_movev_string
+#define nvpair_move_string_array illumos_nvpair_move_string_array
#define nvpair_name illumos_nvpair_name
#define nvpair_next illumos_nvpair_next
#define nvpair_nvlist illumos_nvpair_nvlist
-#define nvpair_pack illumos_nvpair_pack
+#define nvpair_pack_binary illumos_nvpair_pack_binary
+#define nvpair_pack_bool illumos_nvpair_pack_bool
+#define nvpair_pack_bool_array illumos_nvpair_pack_bool_array
#define nvpair_pack_descriptor illumos_nvpair_pack_descriptor
+#define nvpair_pack_descriptor_array illumos_nvpair_pack_descriptor_array
+#define nvpair_pack_header illumos_nvpair_pack_header
+#define nvpair_pack_null illumos_nvpair_pack_null
+#define nvpair_pack_number illumos_nvpair_pack_number
+#define nvpair_pack_number_array illumos_nvpair_pack_number_array
+#define nvpair_pack_nvlist_array_next illumos_nvpair_pack_nvlist_array_next
+#define nvpair_pack_nvlist_up illumos_nvpair_pack_nvlist_up
+#define nvpair_pack_string illumos_nvpair_pack_string
+#define nvpair_pack_string_array illumos_nvpair_pack_string_array
#define nvpair_prev illumos_nvpair_prev
#define nvpair_remove illumos_nvpair_remove
#define nvpair_size illumos_nvpair_size
@@ -254,7 +209,19 @@
#define nvpair_type illumos_nvpair_type
#define nvpair_type_string illumos_nvpair_type_string
#define nvpair_unpack illumos_nvpair_unpack
+#define nvpair_unpack_binary illumos_nvpair_unpack_binary
+#define nvpair_unpack_bool illumos_nvpair_unpack_bool
+#define nvpair_unpack_bool_array illumos_nvpair_unpack_bool_array
#define nvpair_unpack_descriptor illumos_nvpair_unpack_descriptor
+#define nvpair_unpack_descriptor_array illumos_nvpair_unpack_descriptor_array
+#define nvpair_unpack_header illumos_nvpair_unpack_header
+#define nvpair_unpack_null illumos_nvpair_unpack_null
+#define nvpair_unpack_number illumos_nvpair_unpack_number
+#define nvpair_unpack_number_array illumos_nvpair_unpack_number_array
+#define nvpair_unpack_nvlist illumos_nvpair_unpack_nvlist
+#define nvpair_unpack_nvlist_array illumos_nvpair_unpack_nvlist_array
+#define nvpair_unpack_string illumos_nvpair_unpack_string
+#define nvpair_unpack_string_array illumos_nvpair_unpack_string_array
#endif /* _KERNEL */
Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -476,6 +476,9 @@
contrib/libfdt/fdt_strerror.c optional fdt
contrib/libfdt/fdt_sw.c optional fdt
contrib/libfdt/fdt_wip.c optional fdt
+contrib/libnv/dnvlist.c standard
+contrib/libnv/nvlist.c standard
+contrib/libnv/nvpair.c standard
contrib/ngatm/netnatm/api/cc_conn.c optional ngatm_ccatm \
compile-with "${NORMAL_C_NOWERROR} -I$S/contrib/ngatm"
contrib/ngatm/netnatm/api/cc_data.c optional ngatm_ccatm \
@@ -2003,6 +2006,9 @@
dev/pci/isa_pci.c optional pci isa
dev/pci/pci.c optional pci
dev/pci/pci_if.m standard
+dev/pci/pci_iov.c optional pci pci_iov
+dev/pci/pci_iov_if.m standard
+dev/pci/pci_iov_schema.c optional pci pci_iov
dev/pci/pci_pci.c optional pci
dev/pci/pci_subr.c optional pci
dev/pci/pci_user.c optional pci
@@ -3076,7 +3082,6 @@
kern/subr_counter.c standard
kern/subr_devstat.c standard
kern/subr_disk.c standard
-kern/subr_dnvlist.c standard
kern/subr_eventhandler.c standard
kern/subr_fattime.c standard
kern/subr_firmware.c optional firmware
@@ -3090,8 +3095,6 @@
kern/subr_mchain.c optional libmchain
kern/subr_module.c standard
kern/subr_msgbuf.c standard
-kern/subr_nvlist.c standard
-kern/subr_nvpair.c standard
kern/subr_param.c standard
kern/subr_pcpu.c standard
kern/subr_pctrie.c standard
Index: sys/conf/kmod.mk
===================================================================
--- sys/conf/kmod.mk
+++ sys/conf/kmod.mk
@@ -357,7 +357,7 @@
dev/mmc/mmcbr_if.m dev/mmc/mmcbus_if.m \
dev/mii/miibus_if.m dev/mvs/mvs_if.m dev/ofw/ofw_bus_if.m \
dev/pccard/card_if.m dev/pccard/power_if.m dev/pci/pci_if.m \
- dev/pci/pcib_if.m dev/ppbus/ppbus_if.m \
+ dev/pci/pci_iov_if.m dev/pci/pcib_if.m dev/ppbus/ppbus_if.m \
dev/sdhci/sdhci_if.m dev/smbus/smbus_if.m dev/spibus/spibus_if.m \
dev/sound/pci/hda/hdac_if.m \
dev/sound/pcm/ac97_if.m dev/sound/pcm/channel_if.m \
Index: sys/conf/options
===================================================================
--- sys/conf/options
+++ sys/conf/options
@@ -166,6 +166,7 @@
NSWBUF_MIN opt_swap.h
MBUF_PACKET_ZONE_DISABLE opt_global.h
PANIC_REBOOT_WAIT_TIME opt_panic.h
+PCI_IOV opt_global.h
PPC_DEBUG opt_ppc.h
PPC_PROBE_CHIPSET opt_ppc.h
PPS_SYNC opt_ntp.h
Index: sys/contrib/libnv/dnvlist.c
===================================================================
--- sys/contrib/libnv/dnvlist.c
+++ sys/contrib/libnv/dnvlist.c
@@ -0,0 +1,128 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * 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 AUTHORS 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 AUTHORS 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$");
+
+#ifdef _KERNEL
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+
+#include <machine/stdarg.h>
+
+#else
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#endif
+
+#include <sys/dnv.h>
+#include <sys/nv.h>
+
+#include "nv_impl.h"
+
+#define DNVLIST_GET(ftype, type) \
+ftype \
+dnvlist_get_##type(const nvlist_t *nvl, const char *name, ftype defval) \
+{ \
+ \
+ if (nvlist_exists_##type(nvl, name)) \
+ return (nvlist_get_##type(nvl, name)); \
+ else \
+ return (defval); \
+}
+
+DNVLIST_GET(bool, bool)
+DNVLIST_GET(uint64_t, number)
+DNVLIST_GET(const char *, string)
+DNVLIST_GET(const nvlist_t *, nvlist)
+#ifndef _KERNEL
+DNVLIST_GET(int, descriptor)
+#endif
+
+#undef DNVLIST_GET
+
+const void *
+dnvlist_get_binary(const nvlist_t *nvl, const char *name, size_t *sizep,
+ const void *defval, size_t defsize)
+{
+ const void *value;
+
+ if (nvlist_exists_binary(nvl, name))
+ value = nvlist_get_binary(nvl, name, sizep);
+ else {
+ if (sizep != NULL)
+ *sizep = defsize;
+ value = defval;
+ }
+ return (value);
+}
+
+#define DNVLIST_TAKE(ftype, type) \
+ftype \
+dnvlist_take_##type(nvlist_t *nvl, const char *name, ftype defval) \
+{ \
+ \
+ if (nvlist_exists_##type(nvl, name)) \
+ return (nvlist_take_##type(nvl, name)); \
+ else \
+ return (defval); \
+}
+
+DNVLIST_TAKE(bool, bool)
+DNVLIST_TAKE(uint64_t, number)
+DNVLIST_TAKE(char *, string)
+DNVLIST_TAKE(nvlist_t *, nvlist)
+#ifndef _KERNEL
+DNVLIST_TAKE(int, descriptor)
+#endif
+
+#undef DNVLIST_TAKE
+
+void *
+dnvlist_take_binary(nvlist_t *nvl, const char *name, size_t *sizep,
+ void *defval, size_t defsize)
+{
+ void *value;
+
+ if (nvlist_exists_binary(nvl, name))
+ value = nvlist_take_binary(nvl, name, sizep);
+ else {
+ if (sizep != NULL)
+ *sizep = defsize;
+ value = defval;
+ }
+ return (value);
+}
+
Index: sys/contrib/libnv/nv_impl.h
===================================================================
--- sys/contrib/libnv/nv_impl.h
+++ sys/contrib/libnv/nv_impl.h
@@ -0,0 +1,158 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * Copyright (c) 2013-2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * 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 AUTHORS 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 AUTHORS 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 _NV_IMPL_H_
+#define _NV_IMPL_H_
+
+#ifndef _NVPAIR_T_DECLARED
+#define _NVPAIR_T_DECLARED
+struct nvpair;
+
+typedef struct nvpair nvpair_t;
+#endif
+
+#define NV_TYPE_NVLIST_ARRAY_NEXT 254
+#define NV_TYPE_NVLIST_UP 255
+
+#define NV_TYPE_FIRST NV_TYPE_NULL
+#define NV_TYPE_LAST NV_TYPE_DESCRIPTOR_ARRAY
+
+#define NV_FLAG_BIG_ENDIAN 0x080
+#define NV_FLAG_IN_ARRAY 0x100
+
+#ifdef _KERNEL
+#define nv_malloc(size) malloc((size), M_NVLIST, M_WAITOK)
+#define nv_calloc(n, size) malloc((n) * (size), M_NVLIST, \
+ M_WAITOK | M_ZERO)
+#define nv_realloc(buf, size) realloc((buf), (size), M_NVLIST, \
+ M_WAITOK)
+#define nv_free(buf) free((buf), M_NVLIST)
+#define nv_strdup(buf) strdup((buf), M_NVLIST)
+#define nv_vasprintf(ptr, ...) vasprintf(ptr, M_NVLIST, __VA_ARGS__)
+
+#define ERRNO_SET(var) do { } while (0)
+#define ERRNO_SAVE() do { do { } while(0)
+#define ERRNO_RESTORE() } while (0)
+
+#define ERRNO_OR_DEFAULT(default) (default)
+
+#else
+
+#define nv_malloc(size) malloc((size))
+#define nv_calloc(n, size) calloc((n), (size))
+#define nv_realloc(buf, size) realloc((buf), (size))
+#define nv_free(buf) free((buf))
+#define nv_strdup(buf) strdup((buf))
+#define nv_vasprintf(ptr, ...) vasprintf(ptr, __VA_ARGS__)
+
+#define ERRNO_SET(var) do { errno = (var); } while (0)
+#define ERRNO_SAVE() do { \
+ int _serrno; \
+ \
+ _serrno = errno
+
+#define ERRNO_RESTORE() errno = _serrno; \
+ } while (0)
+
+#define ERRNO_OR_DEFAULT(default) (errno == 0 ? (default) : errno)
+
+#endif
+
+int *nvlist_descriptors(const nvlist_t *nvl, size_t *nitemsp);
+size_t nvlist_ndescriptors(const nvlist_t *nvl);
+void nvlist_set_flags(nvlist_t *nvl, int flags);
+
+nvpair_t *nvlist_first_nvpair(const nvlist_t *nvl);
+nvpair_t *nvlist_next_nvpair(const nvlist_t *nvl, const nvpair_t *nvp);
+nvpair_t *nvlist_prev_nvpair(const nvlist_t *nvl, const nvpair_t *nvp);
+
+void nvlist_add_nvpair(nvlist_t *nvl, const nvpair_t *nvp);
+
+bool nvlist_move_nvpair(nvlist_t *nvl, nvpair_t *nvp);
+
+void nvlist_set_parent(nvlist_t *nvl, nvpair_t *parent);
+void nvlist_set_array_next(nvlist_t *nvl, nvpair_t *ele);
+
+const nvpair_t *nvlist_get_nvpair(const nvlist_t *nvl, const char *name);
+
+nvpair_t *nvlist_take_nvpair(nvlist_t *nvl, const char *name);
+
+/* Function removes the given nvpair from the nvlist. */
+void nvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp);
+
+void nvlist_free_nvpair(nvlist_t *nvl, nvpair_t *nvp);
+
+int nvpair_type(const nvpair_t *nvp);
+const char *nvpair_name(const nvpair_t *nvp);
+
+nvpair_t *nvpair_clone(const nvpair_t *nvp);
+
+nvpair_t *nvpair_create_null(const char *name);
+nvpair_t *nvpair_create_bool(const char *name, bool value);
+nvpair_t *nvpair_create_number(const char *name, uint64_t value);
+nvpair_t *nvpair_create_string(const char *name, const char *value);
+nvpair_t *nvpair_create_stringf(const char *name, const char *valuefmt, ...) __printflike(2, 3);
+nvpair_t *nvpair_create_stringv(const char *name, const char *valuefmt, va_list valueap) __printflike(2, 0);
+nvpair_t *nvpair_create_nvlist(const char *name, const nvlist_t *value);
+nvpair_t *nvpair_create_descriptor(const char *name, int value);
+nvpair_t *nvpair_create_binary(const char *name, const void *value, size_t size);
+nvpair_t *nvpair_create_bool_array(const char *name, const bool *value, size_t nitems);
+nvpair_t *nvpair_create_number_array(const char *name, const uint64_t *value, size_t nitems);
+nvpair_t *nvpair_create_string_array(const char *name, const char * const *value, size_t nitems);
+nvpair_t *nvpair_create_nvlist_array(const char *name, const nvlist_t * const *value, size_t nitems);
+nvpair_t *nvpair_create_descriptor_array(const char *name, const int *value, size_t nitems);
+
+nvpair_t *nvpair_move_string(const char *name, char *value);
+nvpair_t *nvpair_move_nvlist(const char *name, nvlist_t *value);
+nvpair_t *nvpair_move_descriptor(const char *name, int value);
+nvpair_t *nvpair_move_binary(const char *name, void *value, size_t size);
+nvpair_t *nvpair_move_bool_array(const char *name, bool *value, size_t nitems);
+nvpair_t *nvpair_move_nvlist_array(const char *name, nvlist_t **value, size_t nitems);
+nvpair_t *nvpair_move_descriptor_array(const char *name, int *value, size_t nitems);
+nvpair_t *nvpair_move_number_array(const char *name, uint64_t *value, size_t nitems);
+nvpair_t *nvpair_move_string_array(const char *name, char **value, size_t nitems);
+
+bool nvpair_get_bool(const nvpair_t *nvp);
+uint64_t nvpair_get_number(const nvpair_t *nvp);
+const char *nvpair_get_string(const nvpair_t *nvp);
+const nvlist_t *nvpair_get_nvlist(const nvpair_t *nvp);
+int nvpair_get_descriptor(const nvpair_t *nvp);
+const void *nvpair_get_binary(const nvpair_t *nvp, size_t *sizep);
+const bool *nvpair_get_bool_array(const nvpair_t *nvp, size_t *nitemsp);
+const uint64_t *nvpair_get_number_array(const nvpair_t *nvp, size_t *nitemsp);
+const char * const *nvpair_get_string_array(const nvpair_t *nvp, size_t *nitemsp);
+const nvlist_t * const *nvpair_get_nvlist_array(const nvpair_t *nvp, size_t *nitemsp);
+const int *nvpair_get_descriptor_array(const nvpair_t *nvp, size_t *nitemsp);
+
+void nvpair_free(nvpair_t *nvp);
+
+#endif /* !_NV_IMPL_H_ */
Index: sys/contrib/libnv/nvlist.c
===================================================================
--- sys/contrib/libnv/nvlist.c
+++ sys/contrib/libnv/nvlist.c
@@ -0,0 +1,2024 @@
+/*-
+ * Copyright (c) 2009-2013 The FreeBSD Foundation
+ * Copyright (c) 2013-2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * 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 AUTHORS 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 AUTHORS 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/endian.h>
+#include <sys/queue.h>
+
+#ifdef _KERNEL
+
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+
+#include <machine/stdarg.h>
+
+#else
+#include <sys/socket.h>
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#define _WITH_DPRINTF
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "msgio.h"
+#endif
+
+#ifdef HAVE_PJDLOG
+#include <pjdlog.h>
+#endif
+
+#include <sys/nv.h>
+
+#include "nv_impl.h"
+#include "nvlist_impl.h"
+#include "nvpair_impl.h"
+
+#ifndef HAVE_PJDLOG
+#ifdef _KERNEL
+#define PJDLOG_ASSERT(...) MPASS(__VA_ARGS__)
+#define PJDLOG_RASSERT(expr, ...) KASSERT(expr, (__VA_ARGS__))
+#define PJDLOG_ABORT(...) panic(__VA_ARGS__)
+#else
+#include <assert.h>
+#define PJDLOG_ASSERT(...) assert(__VA_ARGS__)
+#define PJDLOG_RASSERT(expr, ...) assert(expr)
+#define PJDLOG_ABORT(...) do { \
+ fprintf(stderr, "%s:%u: ", __FILE__, __LINE__); \
+ fprintf(stderr, __VA_ARGS__); \
+ fprintf(stderr, "\n"); \
+ abort(); \
+} while (0)
+#endif
+#endif
+
+#define NV_FLAG_PRIVATE_MASK (NV_FLAG_BIG_ENDIAN | NV_FLAG_IN_ARRAY)
+#define NV_FLAG_PUBLIC_MASK (NV_FLAG_IGNORE_CASE | NV_FLAG_NO_UNIQUE)
+#define NV_FLAG_ALL_MASK (NV_FLAG_PRIVATE_MASK | NV_FLAG_PUBLIC_MASK)
+
+#define NVLIST_MAGIC 0x6e766c /* "nvl" */
+struct nvlist {
+ int nvl_magic;
+ int nvl_error;
+ int nvl_flags;
+ nvpair_t *nvl_parent;
+ nvpair_t *nvl_array_next;
+ struct nvl_head nvl_head;
+};
+
+#define NVLIST_ASSERT(nvl) do { \
+ PJDLOG_ASSERT((nvl) != NULL); \
+ PJDLOG_ASSERT((nvl)->nvl_magic == NVLIST_MAGIC); \
+} while (0)
+
+#ifdef _KERNEL
+MALLOC_DEFINE(M_NVLIST, "nvlist", "kernel nvlist");
+#endif
+
+#define NVPAIR_ASSERT(nvp) nvpair_assert(nvp)
+
+#define NVLIST_HEADER_MAGIC 0x6c
+#define NVLIST_HEADER_VERSION 0x00
+struct nvlist_header {
+ uint8_t nvlh_magic;
+ uint8_t nvlh_version;
+ uint8_t nvlh_flags;
+ uint64_t nvlh_descriptors;
+ uint64_t nvlh_size;
+} __packed;
+
+nvlist_t *
+nvlist_create(int flags)
+{
+ nvlist_t *nvl;
+
+ PJDLOG_ASSERT((flags & ~(NV_FLAG_PUBLIC_MASK)) == 0);
+
+ nvl = nv_malloc(sizeof(*nvl));
+ if (nvl == NULL)
+ return (NULL);
+ nvl->nvl_error = 0;
+ nvl->nvl_flags = flags;
+ nvl->nvl_parent = NULL;
+ nvl->nvl_array_next = NULL;
+ TAILQ_INIT(&nvl->nvl_head);
+ nvl->nvl_magic = NVLIST_MAGIC;
+
+ return (nvl);
+}
+
+void
+nvlist_destroy(nvlist_t *nvl)
+{
+ nvpair_t *nvp;
+
+ if (nvl == NULL)
+ return;
+
+ ERRNO_SAVE();
+
+ NVLIST_ASSERT(nvl);
+
+ while ((nvp = nvlist_first_nvpair(nvl)) != NULL) {
+ nvlist_remove_nvpair(nvl, nvp);
+ nvpair_free(nvp);
+ }
+ if (nvl->nvl_array_next != NULL)
+ nvpair_free_structure(nvl->nvl_array_next);
+ nvl->nvl_array_next = NULL;
+ nvl->nvl_parent = NULL;
+ nvl->nvl_magic = 0;
+ nv_free(nvl);
+
+ ERRNO_RESTORE();
+}
+
+void
+nvlist_set_error(nvlist_t *nvl, int error)
+{
+
+ PJDLOG_ASSERT(error != 0);
+
+ /*
+ * Check for error != 0 so that we don't do the wrong thing if somebody
+ * tries to abuse this API when asserts are disabled.
+ */
+ if (nvl != NULL && error != 0 && nvl->nvl_error == 0)
+ nvl->nvl_error = error;
+}
+
+int
+nvlist_error(const nvlist_t *nvl)
+{
+
+ if (nvl == NULL)
+ return (ENOMEM);
+
+ NVLIST_ASSERT(nvl);
+
+ return (nvl->nvl_error);
+}
+
+nvpair_t *
+nvlist_get_nvpair_parent(const nvlist_t *nvl)
+{
+
+ NVLIST_ASSERT(nvl);
+
+ return (nvl->nvl_parent);
+}
+
+const nvlist_t *
+nvlist_get_parent(const nvlist_t *nvl, void **cookiep)
+{
+ nvpair_t *nvp;
+
+ NVLIST_ASSERT(nvl);
+
+ nvp = nvl->nvl_parent;
+ if (cookiep != NULL)
+ *cookiep = nvp;
+ if (nvp == NULL)
+ return (NULL);
+
+ return (nvpair_nvlist(nvp));
+}
+
+void
+nvlist_set_parent(nvlist_t *nvl, nvpair_t *parent)
+{
+
+ NVLIST_ASSERT(nvl);
+
+ nvl->nvl_parent = parent;
+}
+
+void
+nvlist_set_array_next(nvlist_t *nvl, nvpair_t *ele)
+{
+
+ NVLIST_ASSERT(nvl);
+
+ if (ele != NULL)
+ nvl->nvl_flags |= NV_FLAG_IN_ARRAY;
+ else
+ nvl->nvl_flags &= ~NV_FLAG_IN_ARRAY;
+
+ nvl->nvl_array_next = ele;
+}
+
+bool
+nvlist_in_array(const nvlist_t *nvl)
+{
+
+ NVLIST_ASSERT(nvl);
+
+ return ((nvl->nvl_flags & NV_FLAG_IN_ARRAY) != 0);
+}
+
+const nvlist_t *
+nvlist_get_array_next(const nvlist_t *nvl)
+{
+ nvpair_t *nvp;
+
+ NVLIST_ASSERT(nvl);
+
+ nvp = nvl->nvl_array_next;
+ if (nvp == NULL)
+ return (NULL);
+
+ return (nvpair_get_nvlist(nvp));
+}
+
+const nvlist_t *
+nvlist_get_pararr(const nvlist_t *nvl, void **cookiep)
+{
+ const nvlist_t *ret;
+
+ ret = nvlist_get_array_next(nvl);
+ if (ret != NULL) {
+ if (cookiep != NULL)
+ *cookiep = NULL;
+ return (ret);
+ }
+
+ ret = nvlist_get_parent(nvl, cookiep);
+ return (ret);
+}
+
+bool
+nvlist_empty(const nvlist_t *nvl)
+{
+
+ NVLIST_ASSERT(nvl);
+ PJDLOG_ASSERT(nvl->nvl_error == 0);
+
+ return (nvlist_first_nvpair(nvl) == NULL);
+}
+
+int
+nvlist_flags(const nvlist_t *nvl)
+{
+
+ NVLIST_ASSERT(nvl);
+ PJDLOG_ASSERT(nvl->nvl_error == 0);
+
+ return (nvl->nvl_flags & NV_FLAG_PUBLIC_MASK);
+}
+
+void
+nvlist_set_flags(nvlist_t *nvl, int flags)
+{
+
+ NVLIST_ASSERT(nvl);
+ PJDLOG_ASSERT(nvl->nvl_error == 0);
+
+ nvl->nvl_flags = flags;
+}
+
+static void
+nvlist_report_missing(int type, const char *name)
+{
+
+ PJDLOG_ABORT("Element '%s' of type %s doesn't exist.",
+ name, nvpair_type_string(type));
+}
+
+static nvpair_t *
+nvlist_find(const nvlist_t *nvl, int type, const char *name)
+{
+ nvpair_t *nvp;
+
+ NVLIST_ASSERT(nvl);
+ PJDLOG_ASSERT(nvl->nvl_error == 0);
+ PJDLOG_ASSERT(type == NV_TYPE_NONE ||
+ (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
+
+ for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
+ nvp = nvlist_next_nvpair(nvl, nvp)) {
+ if (type != NV_TYPE_NONE && nvpair_type(nvp) != type)
+ continue;
+ if ((nvl->nvl_flags & NV_FLAG_IGNORE_CASE) != 0) {
+ if (strcasecmp(nvpair_name(nvp), name) != 0)
+ continue;
+ } else {
+ if (strcmp(nvpair_name(nvp), name) != 0)
+ continue;
+ }
+ break;
+ }
+
+ if (nvp == NULL)
+ ERRNO_SET(ENOENT);
+
+ return (nvp);
+}
+
+bool
+nvlist_exists_type(const nvlist_t *nvl, const char *name, int type)
+{
+
+ NVLIST_ASSERT(nvl);
+ PJDLOG_ASSERT(nvl->nvl_error == 0);
+ PJDLOG_ASSERT(type == NV_TYPE_NONE ||
+ (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
+
+ return (nvlist_find(nvl, type, name) != NULL);
+}
+
+void
+nvlist_free_type(nvlist_t *nvl, const char *name, int type)
+{
+ nvpair_t *nvp;
+
+ NVLIST_ASSERT(nvl);
+ PJDLOG_ASSERT(nvl->nvl_error == 0);
+ PJDLOG_ASSERT(type == NV_TYPE_NONE ||
+ (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
+
+ nvp = nvlist_find(nvl, type, name);
+ if (nvp != NULL)
+ nvlist_free_nvpair(nvl, nvp);
+ else
+ nvlist_report_missing(type, name);
+}
+
+nvlist_t *
+nvlist_clone(const nvlist_t *nvl)
+{
+ nvlist_t *newnvl;
+ nvpair_t *nvp, *newnvp;
+
+ NVLIST_ASSERT(nvl);
+
+ if (nvl->nvl_error != 0) {
+ ERRNO_SET(nvl->nvl_error);
+ return (NULL);
+ }
+
+ newnvl = nvlist_create(nvl->nvl_flags & NV_FLAG_PUBLIC_MASK);
+ for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
+ nvp = nvlist_next_nvpair(nvl, nvp)) {
+ newnvp = nvpair_clone(nvp);
+ if (newnvp == NULL)
+ break;
+ (void)nvlist_move_nvpair(newnvl, newnvp);
+ }
+ if (nvp != NULL) {
+ nvlist_destroy(newnvl);
+ return (NULL);
+ }
+ return (newnvl);
+}
+
+#ifndef _KERNEL
+static bool
+nvlist_dump_error_check(const nvlist_t *nvl, int fd, int level)
+{
+
+ if (nvlist_error(nvl) != 0) {
+ dprintf(fd, "%*serror: %d\n", level * 4, "",
+ nvlist_error(nvl));
+ return (true);
+ }
+
+ return (false);
+}
+
+/*
+ * Dump content of nvlist.
+ */
+void
+nvlist_dump(const nvlist_t *nvl, int fd)
+{
+ const nvlist_t *tmpnvl;
+ nvpair_t *nvp, *tmpnvp;
+ void *cookie;
+ int level;
+
+ level = 0;
+ if (nvlist_dump_error_check(nvl, fd, level))
+ return;
+
+ nvp = nvlist_first_nvpair(nvl);
+ while (nvp != NULL) {
+ dprintf(fd, "%*s%s (%s):", level * 4, "", nvpair_name(nvp),
+ nvpair_type_string(nvpair_type(nvp)));
+ switch (nvpair_type(nvp)) {
+ case NV_TYPE_NULL:
+ dprintf(fd, " null\n");
+ break;
+ case NV_TYPE_BOOL:
+ dprintf(fd, " %s\n", nvpair_get_bool(nvp) ?
+ "TRUE" : "FALSE");
+ break;
+ case NV_TYPE_NUMBER:
+ dprintf(fd, " %ju (%jd) (0x%jx)\n",
+ (uintmax_t)nvpair_get_number(nvp),
+ (intmax_t)nvpair_get_number(nvp),
+ (uintmax_t)nvpair_get_number(nvp));
+ break;
+ case NV_TYPE_STRING:
+ dprintf(fd, " [%s]\n", nvpair_get_string(nvp));
+ break;
+ case NV_TYPE_NVLIST:
+ dprintf(fd, "\n");
+ tmpnvl = nvpair_get_nvlist(nvp);
+ if (nvlist_dump_error_check(tmpnvl, fd, level + 1))
+ break;
+ tmpnvp = nvlist_first_nvpair(tmpnvl);
+ if (tmpnvp != NULL) {
+ nvl = tmpnvl;
+ nvp = tmpnvp;
+ level++;
+ continue;
+ }
+ break;
+ case NV_TYPE_DESCRIPTOR:
+ dprintf(fd, " %d\n", nvpair_get_descriptor(nvp));
+ break;
+ case NV_TYPE_BINARY:
+ {
+ const unsigned char *binary;
+ unsigned int ii;
+ size_t size;
+
+ binary = nvpair_get_binary(nvp, &size);
+ dprintf(fd, " %zu ", size);
+ for (ii = 0; ii < size; ii++)
+ dprintf(fd, "%02hhx", binary[ii]);
+ dprintf(fd, "\n");
+ break;
+ }
+ case NV_TYPE_BOOL_ARRAY:
+ {
+ const bool *value;
+ unsigned int ii;
+ size_t nitems;
+
+ value = nvpair_get_bool_array(nvp, &nitems);
+ dprintf(fd, " [ ");
+ for (ii = 0; ii < nitems; ii++) {
+ dprintf(fd, "%s", value[ii] ? "TRUE" : "FALSE");
+ if (ii != nitems - 1)
+ dprintf(fd, ", ");
+ }
+ dprintf(fd, " ]\n");
+ break;
+ }
+ case NV_TYPE_STRING_ARRAY:
+ {
+ const char * const *value;
+ unsigned int ii;
+ size_t nitems;
+
+ value = nvpair_get_string_array(nvp, &nitems);
+ dprintf(fd, " [ ");
+ for (ii = 0; ii < nitems; ii++) {
+ if (value[ii] == NULL)
+ dprintf(fd, "NULL");
+ else
+ dprintf(fd, "\"%s\"", value[ii]);
+ if (ii != nitems - 1)
+ dprintf(fd, ", ");
+ }
+ dprintf(fd, " ]\n");
+ break;
+ }
+ case NV_TYPE_NUMBER_ARRAY:
+ {
+ const uint64_t *value;
+ unsigned int ii;
+ size_t nitems;
+
+ value = nvpair_get_number_array(nvp, &nitems);
+ dprintf(fd, " [ ");
+ for (ii = 0; ii < nitems; ii++) {
+ dprintf(fd, "%ju (%jd) (0x%jx)",
+ value[ii], value[ii], value[ii]);
+ if (ii != nitems - 1)
+ dprintf(fd, ", ");
+ }
+ dprintf(fd, " ]\n");
+ break;
+ }
+ case NV_TYPE_DESCRIPTOR_ARRAY:
+ {
+ const int *value;
+ unsigned int ii;
+ size_t nitems;
+
+ value = nvpair_get_descriptor_array(nvp, &nitems);
+ dprintf(fd, " [ ");
+ for (ii = 0; ii < nitems; ii++) {
+ dprintf(fd, "%d", value[ii]);
+ if (ii != nitems - 1)
+ dprintf(fd, ", ");
+ }
+ dprintf(fd, " ]\n");
+ break;
+ }
+ case NV_TYPE_NVLIST_ARRAY:
+ {
+ const nvlist_t * const *value;
+ unsigned int ii;
+ size_t nitems;
+
+ value = nvpair_get_nvlist_array(nvp, &nitems);
+ dprintf(fd, " %zu\n", nitems);
+ tmpnvl = NULL;
+ tmpnvp = NULL;
+ for (ii = 0; ii < nitems; ii++) {
+ if (nvlist_dump_error_check(value[ii], fd,
+ level + 1)) {
+ break;
+ }
+
+ if (tmpnvl == NULL) {
+ tmpnvp = nvlist_first_nvpair(value[ii]);
+ if (tmpnvp != NULL) {
+ tmpnvl = value[ii];
+ } else {
+ dprintf(fd, "%*s,\n",
+ (level + 1) * 4, "");
+ }
+ }
+ }
+ if (tmpnvp != NULL) {
+ nvl = tmpnvl;
+ nvp = tmpnvp;
+ level++;
+ continue;
+ }
+ break;
+ }
+ default:
+ PJDLOG_ABORT("Unknown type: %d.", nvpair_type(nvp));
+ }
+
+ while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
+ do {
+ cookie = NULL;
+ if (nvlist_in_array(nvl))
+ dprintf(fd, "%*s,\n", level * 4, "");
+ nvl = nvlist_get_pararr(nvl, &cookie);
+ if (nvl == NULL)
+ return;
+ if (nvlist_in_array(nvl) && cookie == NULL) {
+ nvp = nvlist_first_nvpair(nvl);
+ } else {
+ nvp = cookie;
+ level--;
+ }
+ } while (nvp == NULL);
+ if (nvlist_in_array(nvl) && cookie == NULL)
+ break;
+ }
+ }
+}
+
+void
+nvlist_fdump(const nvlist_t *nvl, FILE *fp)
+{
+
+ fflush(fp);
+ nvlist_dump(nvl, fileno(fp));
+}
+#endif
+
+/*
+ * The function obtains size of the nvlist after nvlist_pack().
+ */
+size_t
+nvlist_size(const nvlist_t *nvl)
+{
+ const nvlist_t *tmpnvl;
+ const nvlist_t * const *nvlarray;
+ const nvpair_t *nvp, *tmpnvp;
+ void *cookie;
+ size_t size, nitems;
+ unsigned int ii;
+
+ NVLIST_ASSERT(nvl);
+ PJDLOG_ASSERT(nvl->nvl_error == 0);
+
+ size = sizeof(struct nvlist_header);
+ nvp = nvlist_first_nvpair(nvl);
+ while (nvp != NULL) {
+ size += nvpair_header_size();
+ size += strlen(nvpair_name(nvp)) + 1;
+ if (nvpair_type(nvp) == NV_TYPE_NVLIST) {
+ size += sizeof(struct nvlist_header);
+ size += nvpair_header_size() + 1;
+ tmpnvl = nvpair_get_nvlist(nvp);
+ PJDLOG_ASSERT(tmpnvl->nvl_error == 0);
+ tmpnvp = nvlist_first_nvpair(tmpnvl);
+ if (tmpnvp != NULL) {
+ nvl = tmpnvl;
+ nvp = tmpnvp;
+ continue;
+ }
+ } else if (nvpair_type(nvp) == NV_TYPE_NVLIST_ARRAY) {
+ nvlarray = nvpair_get_nvlist_array(nvp, &nitems);
+ PJDLOG_ASSERT(nitems > 0);
+
+ size += (nvpair_header_size() + 1) * nitems;
+ size += sizeof(struct nvlist_header) * nitems;
+
+ tmpnvl = NULL;
+ tmpnvp = NULL;
+ for (ii = 0; ii < nitems; ii++) {
+ PJDLOG_ASSERT(nvlarray[ii]->nvl_error == 0);
+ tmpnvp = nvlist_first_nvpair(nvlarray[ii]);
+ if (tmpnvp != NULL) {
+ tmpnvl = nvlarray[ii];
+ break;
+ }
+ }
+ if (tmpnvp != NULL) {
+ nvp = tmpnvp;
+ nvl = tmpnvl;
+ continue;
+ }
+
+ } else {
+ size += nvpair_size(nvp);
+ }
+
+ while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
+ do {
+ cookie = NULL;
+ nvl = nvlist_get_pararr(nvl, &cookie);
+ if (nvl == NULL)
+ goto out;
+ if (nvlist_in_array(nvl) && cookie == NULL) {
+ nvp = nvlist_first_nvpair(nvl);
+ } else {
+ nvp = cookie;
+ }
+ } while (nvp == NULL);
+ if (nvlist_in_array(nvl) && cookie == NULL)
+ break;
+ }
+ }
+
+out:
+ return (size);
+}
+
+#ifndef _KERNEL
+static int *
+nvlist_xdescriptors(const nvlist_t *nvl, int *descs)
+{
+ nvpair_t *nvp;
+ const char *name;
+ int type;
+
+ NVLIST_ASSERT(nvl);
+ PJDLOG_ASSERT(nvl->nvl_error == 0);
+
+ nvp = NULL;
+ do {
+ while ((name = nvlist_next(nvl, &type, (void**)&nvp)) != NULL) {
+ switch (type) {
+ case NV_TYPE_DESCRIPTOR:
+ *descs = nvpair_get_descriptor(nvp);
+ descs++;
+ break;
+ case NV_TYPE_DESCRIPTOR_ARRAY:
+ {
+ const int *value;
+ size_t nitems;
+ unsigned int ii;
+
+ value = nvpair_get_descriptor_array(nvp,
+ &nitems);
+ for (ii = 0; ii < nitems; ii++) {
+ *descs = value[ii];
+ descs++;
+ }
+ break;
+ }
+ case NV_TYPE_NVLIST:
+ nvl = nvpair_get_nvlist(nvp);
+ nvp = NULL;
+ break;
+ case NV_TYPE_NVLIST_ARRAY:
+ {
+ const nvlist_t * const *value;
+ size_t nitems;
+
+ value = nvpair_get_nvlist_array(nvp, &nitems);
+ PJDLOG_ASSERT(value != NULL);
+ PJDLOG_ASSERT(nitems > 0);
+
+ nvl = value[0];
+ nvp = NULL;
+ break;
+ }
+ }
+ }
+ } while ((nvl = nvlist_get_pararr(nvl, (void**)&nvp)) != NULL);
+
+ return (descs);
+}
+#endif
+
+#ifndef _KERNEL
+int *
+nvlist_descriptors(const nvlist_t *nvl, size_t *nitemsp)
+{
+ size_t nitems;
+ int *fds;
+
+ nitems = nvlist_ndescriptors(nvl);
+ fds = nv_malloc(sizeof(fds[0]) * (nitems + 1));
+ if (fds == NULL)
+ return (NULL);
+ if (nitems > 0)
+ nvlist_xdescriptors(nvl, fds);
+ fds[nitems] = -1;
+ if (nitemsp != NULL)
+ *nitemsp = nitems;
+ return (fds);
+}
+#endif
+
+size_t
+nvlist_ndescriptors(const nvlist_t *nvl)
+{
+#ifndef _KERNEL
+ nvpair_t *nvp;
+ const char *name;
+ size_t ndescs;
+ int type;
+
+ NVLIST_ASSERT(nvl);
+ PJDLOG_ASSERT(nvl->nvl_error == 0);
+
+ ndescs = 0;
+ nvp = NULL;
+ do {
+ while ((name = nvlist_next(nvl, &type, (void**)&nvp)) != NULL) {
+ switch (type) {
+ case NV_TYPE_DESCRIPTOR:
+ ndescs++;
+ break;
+ case NV_TYPE_NVLIST:
+ nvl = nvpair_get_nvlist(nvp);
+ nvp = NULL;
+ break;
+ case NV_TYPE_NVLIST_ARRAY:
+ {
+ const nvlist_t * const *value;
+ size_t nitems;
+
+ value = nvpair_get_nvlist_array(nvp, &nitems);
+ PJDLOG_ASSERT(value != NULL);
+ PJDLOG_ASSERT(nitems > 0);
+
+ nvl = value[0];
+ nvp = NULL;
+ break;
+ }
+ case NV_TYPE_DESCRIPTOR_ARRAY:
+ {
+ size_t nitems;
+
+ (void)nvpair_get_descriptor_array(nvp,
+ &nitems);
+ ndescs += nitems;
+ break;
+ }
+ }
+ }
+ } while ((nvl = nvlist_get_pararr(nvl, (void**)&nvp)) != NULL);
+
+ return (ndescs);
+#else
+ return (0);
+#endif
+}
+
+static unsigned char *
+nvlist_pack_header(const nvlist_t *nvl, unsigned char *ptr, size_t *leftp)
+{
+ struct nvlist_header nvlhdr;
+
+ NVLIST_ASSERT(nvl);
+
+ nvlhdr.nvlh_magic = NVLIST_HEADER_MAGIC;
+ nvlhdr.nvlh_version = NVLIST_HEADER_VERSION;
+ nvlhdr.nvlh_flags = nvl->nvl_flags;
+#if BYTE_ORDER == BIG_ENDIAN
+ nvlhdr.nvlh_flags |= NV_FLAG_BIG_ENDIAN;
+#endif
+ nvlhdr.nvlh_descriptors = nvlist_ndescriptors(nvl);
+ nvlhdr.nvlh_size = *leftp - sizeof(nvlhdr);
+ PJDLOG_ASSERT(*leftp >= sizeof(nvlhdr));
+ memcpy(ptr, &nvlhdr, sizeof(nvlhdr));
+ ptr += sizeof(nvlhdr);
+ *leftp -= sizeof(nvlhdr);
+
+ return (ptr);
+}
+
+static void *
+nvlist_xpack(const nvlist_t *nvl, int64_t *fdidxp, size_t *sizep)
+{
+ unsigned char *buf, *ptr;
+ size_t left, size;
+ const nvlist_t *tmpnvl;
+ nvpair_t *nvp, *tmpnvp;
+ void *cookie;
+
+ NVLIST_ASSERT(nvl);
+
+ if (nvl->nvl_error != 0) {
+ ERRNO_SET(nvl->nvl_error);
+ return (NULL);
+ }
+
+ size = nvlist_size(nvl);
+ buf = nv_malloc(size);
+ if (buf == NULL)
+ return (NULL);
+
+ ptr = buf;
+ left = size;
+
+ ptr = nvlist_pack_header(nvl, ptr, &left);
+
+ nvp = nvlist_first_nvpair(nvl);
+ while (nvp != NULL) {
+ NVPAIR_ASSERT(nvp);
+
+ nvpair_init_datasize(nvp);
+ ptr = nvpair_pack_header(nvp, ptr, &left);
+ if (ptr == NULL)
+ goto fail;
+ switch (nvpair_type(nvp)) {
+ case NV_TYPE_NULL:
+ ptr = nvpair_pack_null(nvp, ptr, &left);
+ break;
+ case NV_TYPE_BOOL:
+ ptr = nvpair_pack_bool(nvp, ptr, &left);
+ break;
+ case NV_TYPE_NUMBER:
+ ptr = nvpair_pack_number(nvp, ptr, &left);
+ break;
+ case NV_TYPE_STRING:
+ ptr = nvpair_pack_string(nvp, ptr, &left);
+ break;
+ case NV_TYPE_NVLIST:
+ tmpnvl = nvpair_get_nvlist(nvp);
+ ptr = nvlist_pack_header(tmpnvl, ptr, &left);
+ if (ptr == NULL)
+ goto fail;
+ tmpnvp = nvlist_first_nvpair(tmpnvl);
+ if (tmpnvp != NULL) {
+ nvl = tmpnvl;
+ nvp = tmpnvp;
+ continue;
+ }
+ ptr = nvpair_pack_nvlist_up(ptr, &left);
+ break;
+#ifndef _KERNEL
+ case NV_TYPE_DESCRIPTOR:
+ ptr = nvpair_pack_descriptor(nvp, ptr, fdidxp, &left);
+ break;
+ case NV_TYPE_DESCRIPTOR_ARRAY:
+ ptr = nvpair_pack_descriptor_array(nvp, ptr, fdidxp,
+ &left);
+ break;
+#endif
+ case NV_TYPE_BINARY:
+ ptr = nvpair_pack_binary(nvp, ptr, &left);
+ break;
+ case NV_TYPE_BOOL_ARRAY:
+ ptr = nvpair_pack_bool_array(nvp, ptr, &left);
+ break;
+ case NV_TYPE_NUMBER_ARRAY:
+ ptr = nvpair_pack_number_array(nvp, ptr, &left);
+ break;
+ case NV_TYPE_STRING_ARRAY:
+ ptr = nvpair_pack_string_array(nvp, ptr, &left);
+ break;
+ case NV_TYPE_NVLIST_ARRAY:
+ {
+ const nvlist_t * const * value;
+ size_t nitems;
+ unsigned int ii;
+
+ tmpnvl = NULL;
+ value = nvpair_get_nvlist_array(nvp, &nitems);
+ for (ii = 0; ii < nitems; ii++) {
+ ptr = nvlist_pack_header(value[ii], ptr, &left);
+ if (ptr == NULL)
+ goto out;
+ tmpnvp = nvlist_first_nvpair(value[ii]);
+ if (tmpnvp != NULL) {
+ tmpnvl = value[ii];
+ break;
+ }
+ ptr = nvpair_pack_nvlist_array_next(ptr, &left);
+ if (ptr == NULL)
+ goto out;
+ }
+ if (tmpnvl != NULL) {
+ nvl = tmpnvl;
+ nvp = tmpnvp;
+ continue;
+ }
+ break;
+ }
+ default:
+ PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp));
+ }
+ if (ptr == NULL)
+ goto fail;
+ while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
+ do {
+ cookie = NULL;
+ if (nvlist_in_array(nvl)) {
+ ptr = nvpair_pack_nvlist_array_next(ptr,
+ &left);
+ if (ptr == NULL)
+ goto fail;
+ }
+ nvl = nvlist_get_pararr(nvl, &cookie);
+ if (nvl == NULL)
+ goto out;
+ if (nvlist_in_array(nvl) && cookie == NULL) {
+ nvp = nvlist_first_nvpair(nvl);
+ ptr = nvlist_pack_header(nvl, ptr,
+ &left);
+ if (ptr == NULL)
+ goto fail;
+ } else if (nvpair_type((nvpair_t *)cookie) !=
+ NV_TYPE_NVLIST_ARRAY) {
+ ptr = nvpair_pack_nvlist_up(ptr, &left);
+ if (ptr == NULL)
+ goto fail;
+ nvp = cookie;
+ } else {
+ nvp = cookie;
+ }
+ } while (nvp == NULL);
+ if (nvlist_in_array(nvl) && cookie == NULL)
+ break;
+ }
+ }
+
+out:
+ if (sizep != NULL)
+ *sizep = size;
+ return (buf);
+fail:
+ nv_free(buf);
+ return (NULL);
+}
+
+void *
+nvlist_pack(const nvlist_t *nvl, size_t *sizep)
+{
+
+ NVLIST_ASSERT(nvl);
+
+ if (nvl->nvl_error != 0) {
+ ERRNO_SET(nvl->nvl_error);
+ return (NULL);
+ }
+
+ if (nvlist_ndescriptors(nvl) > 0) {
+ ERRNO_SET(EOPNOTSUPP);
+ return (NULL);
+ }
+
+ return (nvlist_xpack(nvl, NULL, sizep));
+}
+
+static bool
+nvlist_check_header(struct nvlist_header *nvlhdrp)
+{
+
+ if (nvlhdrp->nvlh_magic != NVLIST_HEADER_MAGIC) {
+ ERRNO_SET(EINVAL);
+ return (false);
+ }
+ if ((nvlhdrp->nvlh_flags & ~NV_FLAG_ALL_MASK) != 0) {
+ ERRNO_SET(EINVAL);
+ return (false);
+ }
+#if BYTE_ORDER == BIG_ENDIAN
+ if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) == 0) {
+ nvlhdrp->nvlh_size = le64toh(nvlhdrp->nvlh_size);
+ nvlhdrp->nvlh_descriptors = le64toh(nvlhdrp->nvlh_descriptors);
+ }
+#else
+ if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0) {
+ nvlhdrp->nvlh_size = be64toh(nvlhdrp->nvlh_size);
+ nvlhdrp->nvlh_descriptors = be64toh(nvlhdrp->nvlh_descriptors);
+ }
+#endif
+ return (true);
+}
+
+const unsigned char *
+nvlist_unpack_header(nvlist_t *nvl, const unsigned char *ptr, size_t nfds,
+ bool *isbep, size_t *leftp)
+{
+ struct nvlist_header nvlhdr;
+ int inarrayf;
+
+ if (*leftp < sizeof(nvlhdr))
+ goto failed;
+
+ memcpy(&nvlhdr, ptr, sizeof(nvlhdr));
+
+ if (!nvlist_check_header(&nvlhdr))
+ goto failed;
+
+ if (nvlhdr.nvlh_size != *leftp - sizeof(nvlhdr))
+ goto failed;
+
+ /*
+ * nvlh_descriptors might be smaller than nfds in embedded nvlists.
+ */
+ if (nvlhdr.nvlh_descriptors > nfds)
+ goto failed;
+
+ if ((nvlhdr.nvlh_flags & ~NV_FLAG_ALL_MASK) != 0)
+ goto failed;
+
+ inarrayf = (nvl->nvl_flags & NV_FLAG_IN_ARRAY);
+ nvl->nvl_flags = (nvlhdr.nvlh_flags & NV_FLAG_PUBLIC_MASK) | inarrayf;
+
+ ptr += sizeof(nvlhdr);
+ if (isbep != NULL)
+ *isbep = (((int)nvlhdr.nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0);
+ *leftp -= sizeof(nvlhdr);
+
+ return (ptr);
+failed:
+ ERRNO_SET(EINVAL);
+ return (NULL);
+}
+
+static nvlist_t *
+nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds,
+ int flags)
+{
+ const unsigned char *ptr;
+ nvlist_t *nvl, *retnvl, *tmpnvl, *array;
+ nvpair_t *nvp;
+ size_t left;
+ bool isbe;
+
+ PJDLOG_ASSERT((flags & ~(NV_FLAG_PUBLIC_MASK)) == 0);
+
+ left = size;
+ ptr = buf;
+
+ tmpnvl = array = NULL;
+ nvl = retnvl = nvlist_create(0);
+ if (nvl == NULL)
+ goto failed;
+
+ ptr = nvlist_unpack_header(nvl, ptr, nfds, &isbe, &left);
+ if (ptr == NULL)
+ goto failed;
+ if (nvl->nvl_flags != flags) {
+ ERRNO_SET(EILSEQ);
+ goto failed;
+ }
+
+ while (left > 0) {
+ ptr = nvpair_unpack(isbe, ptr, &left, &nvp);
+ if (ptr == NULL)
+ goto failed;
+ switch (nvpair_type(nvp)) {
+ case NV_TYPE_NULL:
+ ptr = nvpair_unpack_null(isbe, nvp, ptr, &left);
+ break;
+ case NV_TYPE_BOOL:
+ ptr = nvpair_unpack_bool(isbe, nvp, ptr, &left);
+ break;
+ case NV_TYPE_NUMBER:
+ ptr = nvpair_unpack_number(isbe, nvp, ptr, &left);
+ break;
+ case NV_TYPE_STRING:
+ ptr = nvpair_unpack_string(isbe, nvp, ptr, &left);
+ break;
+ case NV_TYPE_NVLIST:
+ ptr = nvpair_unpack_nvlist(isbe, nvp, ptr, &left, nfds,
+ &tmpnvl);
+ if (tmpnvl == NULL || ptr == NULL)
+ goto failed;
+ nvlist_set_parent(tmpnvl, nvp);
+ break;
+#ifndef _KERNEL
+ case NV_TYPE_DESCRIPTOR:
+ ptr = nvpair_unpack_descriptor(isbe, nvp, ptr, &left,
+ fds, nfds);
+ break;
+ case NV_TYPE_DESCRIPTOR_ARRAY:
+ ptr = nvpair_unpack_descriptor_array(isbe, nvp, ptr,
+ &left, fds, nfds);
+ break;
+#endif
+ case NV_TYPE_BINARY:
+ ptr = nvpair_unpack_binary(isbe, nvp, ptr, &left);
+ break;
+ case NV_TYPE_NVLIST_UP:
+ if (nvl->nvl_parent == NULL)
+ goto failed;
+ nvl = nvpair_nvlist(nvl->nvl_parent);
+ nvpair_free_structure(nvp);
+ continue;
+ case NV_TYPE_NVLIST_ARRAY_NEXT:
+ if (nvl->nvl_array_next == NULL) {
+ if (nvl->nvl_parent == NULL)
+ goto failed;
+ nvl = nvpair_nvlist(nvl->nvl_parent);
+ } else {
+ nvl = __DECONST(nvlist_t *,
+ nvlist_get_array_next(nvl));
+ ptr = nvlist_unpack_header(nvl, ptr, nfds,
+ &isbe, &left);
+ if (ptr == NULL)
+ goto failed;
+ }
+ nvpair_free_structure(nvp);
+ continue;
+ case NV_TYPE_BOOL_ARRAY:
+ ptr = nvpair_unpack_bool_array(isbe, nvp, ptr, &left);
+ break;
+ case NV_TYPE_NUMBER_ARRAY:
+ ptr = nvpair_unpack_number_array(isbe, nvp, ptr, &left);
+ break;
+ case NV_TYPE_STRING_ARRAY:
+ ptr = nvpair_unpack_string_array(isbe, nvp, ptr, &left);
+ break;
+ case NV_TYPE_NVLIST_ARRAY:
+ ptr = nvpair_unpack_nvlist_array(isbe, nvp, ptr, &left,
+ &array);
+ if (ptr == NULL)
+ goto failed;
+ tmpnvl = array;
+ while (array != NULL) {
+ nvlist_set_parent(array, nvp);
+ array = __DECONST(nvlist_t *,
+ nvlist_get_array_next(array));
+ }
+ ptr = nvlist_unpack_header(tmpnvl, ptr, nfds, &isbe,
+ &left);
+ break;
+ default:
+ PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp));
+ }
+ if (ptr == NULL)
+ goto failed;
+ if (!nvlist_move_nvpair(nvl, nvp))
+ goto failed;
+ if (tmpnvl != NULL) {
+ nvl = tmpnvl;
+ tmpnvl = NULL;
+ }
+ }
+
+ return (retnvl);
+failed:
+ nvlist_destroy(retnvl);
+ return (NULL);
+}
+
+nvlist_t *
+nvlist_unpack(const void *buf, size_t size, int flags)
+{
+
+ return (nvlist_xunpack(buf, size, NULL, 0, flags));
+}
+
+#ifndef _KERNEL
+int
+nvlist_send(int sock, const nvlist_t *nvl)
+{
+ size_t datasize, nfds;
+ int *fds;
+ void *data;
+ int64_t fdidx;
+ int ret;
+
+ if (nvlist_error(nvl) != 0) {
+ ERRNO_SET(nvlist_error(nvl));
+ return (-1);
+ }
+
+ fds = nvlist_descriptors(nvl, &nfds);
+ if (fds == NULL)
+ return (-1);
+
+ ret = -1;
+ data = NULL;
+ fdidx = 0;
+
+ data = nvlist_xpack(nvl, &fdidx, &datasize);
+ if (data == NULL)
+ goto out;
+
+ if (buf_send(sock, data, datasize) == -1)
+ goto out;
+
+ if (nfds > 0) {
+ if (fd_send(sock, fds, nfds) == -1)
+ goto out;
+ }
+
+ ret = 0;
+out:
+ ERRNO_SAVE();
+ nv_free(fds);
+ nv_free(data);
+ ERRNO_RESTORE();
+ return (ret);
+}
+
+nvlist_t *
+nvlist_recv(int sock, int flags)
+{
+ struct nvlist_header nvlhdr;
+ nvlist_t *nvl, *ret;
+ unsigned char *buf;
+ size_t nfds, size, i;
+ int *fds;
+
+ if (buf_recv(sock, &nvlhdr, sizeof(nvlhdr)) == -1)
+ return (NULL);
+
+ if (!nvlist_check_header(&nvlhdr))
+ return (NULL);
+
+ nfds = (size_t)nvlhdr.nvlh_descriptors;
+ size = sizeof(nvlhdr) + (size_t)nvlhdr.nvlh_size;
+
+ buf = nv_malloc(size);
+ if (buf == NULL)
+ return (NULL);
+
+ memcpy(buf, &nvlhdr, sizeof(nvlhdr));
+
+ ret = NULL;
+ fds = NULL;
+
+ if (buf_recv(sock, buf + sizeof(nvlhdr), size - sizeof(nvlhdr)) == -1)
+ goto out;
+
+ if (nfds > 0) {
+ fds = nv_malloc(nfds * sizeof(fds[0]));
+ if (fds == NULL)
+ goto out;
+ if (fd_recv(sock, fds, nfds) == -1)
+ goto out;
+ }
+
+ nvl = nvlist_xunpack(buf, size, fds, nfds, flags);
+ if (nvl == NULL) {
+ ERRNO_SAVE();
+ for (i = 0; i < nfds; i++)
+ close(fds[i]);
+ ERRNO_RESTORE();
+ goto out;
+ }
+
+ ret = nvl;
+out:
+ ERRNO_SAVE();
+ nv_free(buf);
+ nv_free(fds);
+ ERRNO_RESTORE();
+
+ return (ret);
+}
+
+nvlist_t *
+nvlist_xfer(int sock, nvlist_t *nvl, int flags)
+{
+
+ if (nvlist_send(sock, nvl) < 0) {
+ nvlist_destroy(nvl);
+ return (NULL);
+ }
+ nvlist_destroy(nvl);
+ return (nvlist_recv(sock, flags));
+}
+#endif
+
+nvpair_t *
+nvlist_first_nvpair(const nvlist_t *nvl)
+{
+
+ NVLIST_ASSERT(nvl);
+
+ return (TAILQ_FIRST(&nvl->nvl_head));
+}
+
+nvpair_t *
+nvlist_next_nvpair(const nvlist_t *nvl, const nvpair_t *nvp)
+{
+ nvpair_t *retnvp;
+
+ NVLIST_ASSERT(nvl);
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
+
+ retnvp = nvpair_next(nvp);
+ PJDLOG_ASSERT(retnvp == NULL || nvpair_nvlist(retnvp) == nvl);
+
+ return (retnvp);
+
+}
+
+nvpair_t *
+nvlist_prev_nvpair(const nvlist_t *nvl, const nvpair_t *nvp)
+{
+ nvpair_t *retnvp;
+
+ NVLIST_ASSERT(nvl);
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
+
+ retnvp = nvpair_prev(nvp);
+ PJDLOG_ASSERT(nvpair_nvlist(retnvp) == nvl);
+
+ return (retnvp);
+}
+
+const char *
+nvlist_next(const nvlist_t *nvl, int *typep, void **cookiep)
+{
+ nvpair_t *nvp;
+
+ NVLIST_ASSERT(nvl);
+
+ if (cookiep == NULL || *cookiep == NULL)
+ nvp = nvlist_first_nvpair(nvl);
+ else
+ nvp = nvlist_next_nvpair(nvl, *cookiep);
+ if (nvp == NULL)
+ return (NULL);
+ if (typep != NULL)
+ *typep = nvpair_type(nvp);
+ if (cookiep != NULL)
+ *cookiep = nvp;
+ return (nvpair_name(nvp));
+}
+
+bool
+nvlist_exists(const nvlist_t *nvl, const char *name)
+{
+
+ return (nvlist_find(nvl, NV_TYPE_NONE, name) != NULL);
+}
+
+#define NVLIST_EXISTS(type, TYPE) \
+bool \
+nvlist_exists_##type(const nvlist_t *nvl, const char *name) \
+{ \
+ \
+ return (nvlist_find(nvl, NV_TYPE_##TYPE, name) != NULL); \
+}
+
+NVLIST_EXISTS(null, NULL)
+NVLIST_EXISTS(bool, BOOL)
+NVLIST_EXISTS(number, NUMBER)
+NVLIST_EXISTS(string, STRING)
+NVLIST_EXISTS(nvlist, NVLIST)
+NVLIST_EXISTS(binary, BINARY)
+NVLIST_EXISTS(bool_array, BOOL_ARRAY)
+NVLIST_EXISTS(number_array, NUMBER_ARRAY)
+NVLIST_EXISTS(string_array, STRING_ARRAY)
+NVLIST_EXISTS(nvlist_array, NVLIST_ARRAY)
+#ifndef _KERNEL
+NVLIST_EXISTS(descriptor, DESCRIPTOR)
+NVLIST_EXISTS(descriptor_array, DESCRIPTOR_ARRAY)
+#endif
+
+#undef NVLIST_EXISTS
+
+void
+nvlist_add_nvpair(nvlist_t *nvl, const nvpair_t *nvp)
+{
+ nvpair_t *newnvp;
+
+ NVPAIR_ASSERT(nvp);
+
+ if (nvlist_error(nvl) != 0) {
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+ if ((nvl->nvl_flags & NV_FLAG_NO_UNIQUE) == 0) {
+ if (nvlist_exists(nvl, nvpair_name(nvp))) {
+ nvl->nvl_error = EEXIST;
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+ }
+
+ newnvp = nvpair_clone(nvp);
+ if (newnvp == NULL) {
+ nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+
+ nvpair_insert(&nvl->nvl_head, newnvp, nvl);
+}
+
+void
+nvlist_add_stringf(nvlist_t *nvl, const char *name, const char *valuefmt, ...)
+{
+ va_list valueap;
+
+ va_start(valueap, valuefmt);
+ nvlist_add_stringv(nvl, name, valuefmt, valueap);
+ va_end(valueap);
+}
+
+void
+nvlist_add_stringv(nvlist_t *nvl, const char *name, const char *valuefmt,
+ va_list valueap)
+{
+ nvpair_t *nvp;
+
+ if (nvlist_error(nvl) != 0) {
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+
+ nvp = nvpair_create_stringv(name, valuefmt, valueap);
+ if (nvp == NULL) {
+ nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
+ ERRNO_SET(nvl->nvl_error);
+ } else {
+ (void)nvlist_move_nvpair(nvl, nvp);
+ }
+}
+
+void
+nvlist_add_null(nvlist_t *nvl, const char *name)
+{
+ nvpair_t *nvp;
+
+ if (nvlist_error(nvl) != 0) {
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+
+ nvp = nvpair_create_null(name);
+ if (nvp == NULL) {
+ nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
+ ERRNO_SET(nvl->nvl_error);
+ } else {
+ (void)nvlist_move_nvpair(nvl, nvp);
+ }
+}
+
+void
+nvlist_add_binary(nvlist_t *nvl, const char *name, const void *value,
+ size_t size)
+{
+ nvpair_t *nvp;
+
+ if (nvlist_error(nvl) != 0) {
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+
+ nvp = nvpair_create_binary(name, value, size);
+ if (nvp == NULL) {
+ nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
+ ERRNO_SET(nvl->nvl_error);
+ } else {
+ (void)nvlist_move_nvpair(nvl, nvp);
+ }
+}
+
+
+#define NVLIST_ADD(vtype, type) \
+void \
+nvlist_add_##type(nvlist_t *nvl, const char *name, vtype value) \
+{ \
+ nvpair_t *nvp; \
+ \
+ if (nvlist_error(nvl) != 0) { \
+ ERRNO_SET(nvlist_error(nvl)); \
+ return; \
+ } \
+ \
+ nvp = nvpair_create_##type(name, value); \
+ if (nvp == NULL) { \
+ nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); \
+ ERRNO_SET(nvl->nvl_error); \
+ } else { \
+ (void)nvlist_move_nvpair(nvl, nvp); \
+ } \
+}
+
+NVLIST_ADD(bool, bool)
+NVLIST_ADD(uint64_t, number)
+NVLIST_ADD(const char *, string)
+NVLIST_ADD(const nvlist_t *, nvlist)
+#ifndef _KERNEL
+NVLIST_ADD(int, descriptor);
+#endif
+
+#undef NVLIST_ADD
+
+#define NVLIST_ADD_ARRAY(vtype, type) \
+void \
+nvlist_add_##type##_array(nvlist_t *nvl, const char *name, vtype value, \
+ size_t nitems) \
+{ \
+ nvpair_t *nvp; \
+ \
+ if (nvlist_error(nvl) != 0) { \
+ ERRNO_SET(nvlist_error(nvl)); \
+ return; \
+ } \
+ \
+ nvp = nvpair_create_##type##_array(name, value, nitems); \
+ if (nvp == NULL) { \
+ nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); \
+ ERRNO_SET(nvl->nvl_error); \
+ } else { \
+ (void)nvlist_move_nvpair(nvl, nvp); \
+ } \
+}
+
+NVLIST_ADD_ARRAY(const bool *, bool)
+NVLIST_ADD_ARRAY(const uint64_t *, number)
+NVLIST_ADD_ARRAY(const char * const *, string)
+NVLIST_ADD_ARRAY(const nvlist_t * const *, nvlist)
+#ifndef _KERNEL
+NVLIST_ADD_ARRAY(const int *, descriptor)
+#endif
+
+#undef NVLIST_ADD_ARRAY
+
+bool
+nvlist_move_nvpair(nvlist_t *nvl, nvpair_t *nvp)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvpair_nvlist(nvp) == NULL);
+
+ if (nvlist_error(nvl) != 0) {
+ nvpair_free(nvp);
+ ERRNO_SET(nvlist_error(nvl));
+ return (false);
+ }
+ if ((nvl->nvl_flags & NV_FLAG_NO_UNIQUE) == 0) {
+ if (nvlist_exists(nvl, nvpair_name(nvp))) {
+ nvpair_free(nvp);
+ nvl->nvl_error = EEXIST;
+ ERRNO_SET(nvl->nvl_error);
+ return (false);
+ }
+ }
+
+ nvpair_insert(&nvl->nvl_head, nvp, nvl);
+ return (true);
+}
+
+void
+nvlist_move_string(nvlist_t *nvl, const char *name, char *value)
+{
+ nvpair_t *nvp;
+
+ if (nvlist_error(nvl) != 0) {
+ nv_free(value);
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+
+ nvp = nvpair_move_string(name, value);
+ if (nvp == NULL) {
+ nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
+ ERRNO_SET(nvl->nvl_error);
+ } else {
+ (void)nvlist_move_nvpair(nvl, nvp);
+ }
+}
+
+void
+nvlist_move_nvlist(nvlist_t *nvl, const char *name, nvlist_t *value)
+{
+ nvpair_t *nvp;
+
+ if (nvlist_error(nvl) != 0) {
+ if (value != NULL && nvlist_get_nvpair_parent(value) != NULL)
+ nvlist_destroy(value);
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+
+ nvp = nvpair_move_nvlist(name, value);
+ if (nvp == NULL) {
+ nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
+ ERRNO_SET(nvl->nvl_error);
+ } else {
+ (void)nvlist_move_nvpair(nvl, nvp);
+ }
+}
+
+#ifndef _KERNEL
+void
+nvlist_move_descriptor(nvlist_t *nvl, const char *name, int value)
+{
+ nvpair_t *nvp;
+
+ if (nvlist_error(nvl) != 0) {
+ close(value);
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+
+ nvp = nvpair_move_descriptor(name, value);
+ if (nvp == NULL) {
+ nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
+ ERRNO_SET(nvl->nvl_error);
+ } else {
+ (void)nvlist_move_nvpair(nvl, nvp);
+ }
+}
+#endif
+
+void
+nvlist_move_binary(nvlist_t *nvl, const char *name, void *value, size_t size)
+{
+ nvpair_t *nvp;
+
+ if (nvlist_error(nvl) != 0) {
+ nv_free(value);
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+
+ nvp = nvpair_move_binary(name, value, size);
+ if (nvp == NULL) {
+ nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
+ ERRNO_SET(nvl->nvl_error);
+ } else {
+ (void)nvlist_move_nvpair(nvl, nvp);
+ }
+}
+
+void
+nvlist_move_bool_array(nvlist_t *nvl, const char *name, bool *value,
+ size_t nitems)
+{
+ nvpair_t *nvp;
+
+ if (nvlist_error(nvl) != 0) {
+ nv_free(value);
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+
+ nvp = nvpair_move_bool_array(name, value, nitems);
+ if (nvp == NULL) {
+ nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
+ ERRNO_SET(nvl->nvl_error);
+ } else {
+ (void)nvlist_move_nvpair(nvl, nvp);
+ }
+}
+
+void
+nvlist_move_string_array(nvlist_t *nvl, const char *name, char **value,
+ size_t nitems)
+{
+ nvpair_t *nvp;
+ size_t i;
+
+ if (nvlist_error(nvl) != 0) {
+ if (value != NULL) {
+ for (i = 0; i < nitems; i++)
+ nv_free(value[i]);
+ nv_free(value);
+ }
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+
+ nvp = nvpair_move_string_array(name, value, nitems);
+ if (nvp == NULL) {
+ nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
+ ERRNO_SET(nvl->nvl_error);
+ } else {
+ (void)nvlist_move_nvpair(nvl, nvp);
+ }
+}
+
+void
+nvlist_move_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **value,
+ size_t nitems)
+{
+ nvpair_t *nvp;
+ size_t i;
+
+ if (nvlist_error(nvl) != 0) {
+ if (value != NULL) {
+ for (i = 0; i < nitems; i++) {
+ if (nvlist_get_pararr(value[i], NULL) == NULL)
+ nvlist_destroy(value[i]);
+ }
+ }
+ nv_free(value);
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+
+ nvp = nvpair_move_nvlist_array(name, value, nitems);
+ if (nvp == NULL) {
+ nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
+ ERRNO_SET(nvl->nvl_error);
+ } else {
+ (void)nvlist_move_nvpair(nvl, nvp);
+ }
+}
+
+void
+nvlist_move_number_array(nvlist_t *nvl, const char *name, uint64_t *value,
+ size_t nitems)
+{
+ nvpair_t *nvp;
+
+ if (nvlist_error(nvl) != 0) {
+ nv_free(value);
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+
+ nvp = nvpair_move_number_array(name, value, nitems);
+ if (nvp == NULL) {
+ nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
+ ERRNO_SET(nvl->nvl_error);
+ } else {
+ (void)nvlist_move_nvpair(nvl, nvp);
+ }
+}
+
+#ifndef _KERNEL
+void
+nvlist_move_descriptor_array(nvlist_t *nvl, const char *name, int *value,
+ size_t nitems)
+{
+ nvpair_t *nvp;
+ size_t i;
+
+ if (nvlist_error(nvl) != 0) {
+ if (value != 0) {
+ for (i = 0; i < nitems; i++)
+ close(value[i]);
+ nv_free(value);
+ }
+
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+
+ nvp = nvpair_move_descriptor_array(name, value, nitems);
+ if (nvp == NULL) {
+ nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
+ ERRNO_SET(nvl->nvl_error);
+ } else {
+ (void)nvlist_move_nvpair(nvl, nvp);
+ }
+}
+#endif
+
+const nvpair_t *
+nvlist_get_nvpair(const nvlist_t *nvl, const char *name)
+{
+
+ return (nvlist_find(nvl, NV_TYPE_NONE, name));
+}
+
+#define NVLIST_GET(ftype, type, TYPE) \
+ftype \
+nvlist_get_##type(const nvlist_t *nvl, const char *name) \
+{ \
+ const nvpair_t *nvp; \
+ \
+ nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name); \
+ if (nvp == NULL) \
+ nvlist_report_missing(NV_TYPE_##TYPE, name); \
+ return (nvpair_get_##type(nvp)); \
+}
+
+NVLIST_GET(bool, bool, BOOL)
+NVLIST_GET(uint64_t, number, NUMBER)
+NVLIST_GET(const char *, string, STRING)
+NVLIST_GET(const nvlist_t *, nvlist, NVLIST)
+#ifndef _KERNEL
+NVLIST_GET(int, descriptor, DESCRIPTOR)
+#endif
+
+#undef NVLIST_GET
+
+const void *
+nvlist_get_binary(const nvlist_t *nvl, const char *name, size_t *sizep)
+{
+ nvpair_t *nvp;
+
+ nvp = nvlist_find(nvl, NV_TYPE_BINARY, name);
+ if (nvp == NULL)
+ nvlist_report_missing(NV_TYPE_BINARY, name);
+
+ return (nvpair_get_binary(nvp, sizep));
+}
+
+#define NVLIST_GET_ARRAY(ftype, type, TYPE) \
+ftype \
+nvlist_get_##type##_array(const nvlist_t *nvl, const char *name, \
+ size_t *nitems) \
+{ \
+ const nvpair_t *nvp; \
+ \
+ nvp = nvlist_find(nvl, NV_TYPE_##TYPE##_ARRAY, name); \
+ if (nvp == NULL) \
+ nvlist_report_missing(NV_TYPE_##TYPE##_ARRAY, name); \
+ return (nvpair_get_##type##_array(nvp, nitems)); \
+}
+
+NVLIST_GET_ARRAY(const bool *, bool, BOOL)
+NVLIST_GET_ARRAY(const uint64_t *, number, NUMBER)
+NVLIST_GET_ARRAY(const char * const *, string, STRING)
+NVLIST_GET_ARRAY(const nvlist_t * const *, nvlist, NVLIST)
+#ifndef _KERNEL
+NVLIST_GET_ARRAY(const int *, descriptor, DESCRIPTOR)
+#endif
+
+#undef NVLIST_GET_ARRAY
+
+#define NVLIST_TAKE(ftype, type, TYPE) \
+ftype \
+nvlist_take_##type(nvlist_t *nvl, const char *name) \
+{ \
+ nvpair_t *nvp; \
+ ftype value; \
+ \
+ nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name); \
+ if (nvp == NULL) \
+ nvlist_report_missing(NV_TYPE_##TYPE, name); \
+ value = (ftype)(intptr_t)nvpair_get_##type(nvp); \
+ nvlist_remove_nvpair(nvl, nvp); \
+ nvpair_free_structure(nvp); \
+ return (value); \
+}
+
+NVLIST_TAKE(bool, bool, BOOL)
+NVLIST_TAKE(uint64_t, number, NUMBER)
+NVLIST_TAKE(char *, string, STRING)
+NVLIST_TAKE(nvlist_t *, nvlist, NVLIST)
+#ifndef _KERNEL
+NVLIST_TAKE(int, descriptor, DESCRIPTOR)
+#endif
+
+#undef NVLIST_TAKE
+
+void *
+nvlist_take_binary(nvlist_t *nvl, const char *name, size_t *sizep)
+{
+ nvpair_t *nvp;
+ void *value;
+
+ nvp = nvlist_find(nvl, NV_TYPE_BINARY, name);
+ if (nvp == NULL)
+ nvlist_report_missing(NV_TYPE_BINARY, name);
+
+ value = (void *)(intptr_t)nvpair_get_binary(nvp, sizep);
+ nvlist_remove_nvpair(nvl, nvp);
+ nvpair_free_structure(nvp);
+ return (value);
+}
+
+#define NVLIST_TAKE_ARRAY(ftype, type, TYPE) \
+ftype \
+nvlist_take_##type##_array(nvlist_t *nvl, const char *name, \
+ size_t *nitems) \
+{ \
+ nvpair_t *nvp; \
+ ftype value; \
+ \
+ nvp = nvlist_find(nvl, NV_TYPE_##TYPE##_ARRAY, name); \
+ if (nvp == NULL) \
+ nvlist_report_missing(NV_TYPE_##TYPE##_ARRAY, name); \
+ value = (ftype)(intptr_t)nvpair_get_##type##_array(nvp, nitems);\
+ nvlist_remove_nvpair(nvl, nvp); \
+ nvpair_free_structure(nvp); \
+ return (value); \
+}
+
+NVLIST_TAKE_ARRAY(bool *, bool, BOOL)
+NVLIST_TAKE_ARRAY(uint64_t *, number, NUMBER)
+NVLIST_TAKE_ARRAY(char **, string, STRING)
+NVLIST_TAKE_ARRAY(nvlist_t **, nvlist, NVLIST)
+#ifndef _KERNEL
+NVLIST_TAKE_ARRAY(int *, descriptor, DESCRIPTOR)
+#endif
+
+void
+nvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp)
+{
+
+ NVLIST_ASSERT(nvl);
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
+
+ nvpair_remove(&nvl->nvl_head, nvp, nvl);
+}
+
+void
+nvlist_free(nvlist_t *nvl, const char *name)
+{
+
+ nvlist_free_type(nvl, name, NV_TYPE_NONE);
+}
+
+#define NVLIST_FREE(type, TYPE) \
+void \
+nvlist_free_##type(nvlist_t *nvl, const char *name) \
+{ \
+ \
+ nvlist_free_type(nvl, name, NV_TYPE_##TYPE); \
+}
+
+NVLIST_FREE(null, NULL)
+NVLIST_FREE(bool, BOOL)
+NVLIST_FREE(number, NUMBER)
+NVLIST_FREE(string, STRING)
+NVLIST_FREE(nvlist, NVLIST)
+NVLIST_FREE(binary, BINARY)
+NVLIST_FREE(bool_array, BOOL_ARRAY)
+NVLIST_FREE(number_array, NUMBER_ARRAY)
+NVLIST_FREE(string_array, STRING_ARRAY)
+NVLIST_FREE(nvlist_array, NVLIST_ARRAY)
+#ifndef _KERNEL
+NVLIST_FREE(descriptor, DESCRIPTOR)
+NVLIST_FREE(descriptor_array, DESCRIPTOR_ARRAY)
+#endif
+
+#undef NVLIST_FREE
+
+void
+nvlist_free_nvpair(nvlist_t *nvl, nvpair_t *nvp)
+{
+
+ NVLIST_ASSERT(nvl);
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
+
+ nvlist_remove_nvpair(nvl, nvp);
+ nvpair_free(nvp);
+}
+
Index: sys/contrib/libnv/nvlist_impl.h
===================================================================
--- sys/contrib/libnv/nvlist_impl.h
+++ sys/contrib/libnv/nvlist_impl.h
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * Copyright (c) 2013-2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * 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 AUTHORS 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 AUTHORS 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 _NVLIST_IMPL_H_
+#define _NVLIST_IMPL_H_
+
+#include <sys/nv.h>
+
+#ifndef _KERNEL
+#include <stdint.h>
+#endif
+
+nvpair_t *nvlist_get_nvpair_parent(const nvlist_t *nvl);
+const unsigned char *nvlist_unpack_header(nvlist_t *nvl,
+ const unsigned char *ptr, size_t nfds, bool *isbep, size_t *leftp);
+
+#endif /* !_NVLIST_IMPL_H_ */
Index: sys/contrib/libnv/nvpair.c
===================================================================
--- sys/contrib/libnv/nvpair.c
+++ sys/contrib/libnv/nvpair.c
@@ -0,0 +1,1997 @@
+/*-
+ * Copyright (c) 2009-2013 The FreeBSD Foundation
+ * Copyright (c) 2013-2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * 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 AUTHORS 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 AUTHORS 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/endian.h>
+#include <sys/queue.h>
+
+#ifdef _KERNEL
+
+#include <sys/errno.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+
+#include <machine/stdarg.h>
+
+#else
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "common_impl.h"
+#endif
+
+#ifdef HAVE_PJDLOG
+#include <pjdlog.h>
+#endif
+
+#include <sys/nv.h>
+
+#include "nv_impl.h"
+#include "nvlist_impl.h"
+#include "nvpair_impl.h"
+
+#ifndef HAVE_PJDLOG
+#ifdef _KERNEL
+#define PJDLOG_ASSERT(...) MPASS(__VA_ARGS__)
+#define PJDLOG_RASSERT(expr, ...) KASSERT(expr, (__VA_ARGS__))
+#define PJDLOG_ABORT(...) panic(__VA_ARGS__)
+#else
+#include <assert.h>
+#define PJDLOG_ASSERT(...) assert(__VA_ARGS__)
+#define PJDLOG_RASSERT(expr, ...) assert(expr)
+#define PJDLOG_ABORT(...) abort()
+#endif
+#endif
+
+#define NVPAIR_MAGIC 0x6e7670 /* "nvp" */
+struct nvpair {
+ int nvp_magic;
+ char *nvp_name;
+ int nvp_type;
+ uint64_t nvp_data;
+ size_t nvp_datasize;
+ size_t nvp_nitems; /* Used only for array types. */
+ nvlist_t *nvp_list;
+ TAILQ_ENTRY(nvpair) nvp_next;
+};
+
+#define NVPAIR_ASSERT(nvp) do { \
+ PJDLOG_ASSERT((nvp) != NULL); \
+ PJDLOG_ASSERT((nvp)->nvp_magic == NVPAIR_MAGIC); \
+} while (0)
+
+struct nvpair_header {
+ uint8_t nvph_type;
+ uint16_t nvph_namesize;
+ uint64_t nvph_datasize;
+ uint64_t nvph_nitems;
+} __packed;
+
+
+void
+nvpair_assert(const nvpair_t *nvp)
+{
+
+ NVPAIR_ASSERT(nvp);
+}
+
+static nvpair_t *
+nvpair_allocv(const char *name, int type, uint64_t data, size_t datasize,
+ size_t nitems)
+{
+ nvpair_t *nvp;
+ size_t namelen;
+
+ PJDLOG_ASSERT(type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST);
+
+ namelen = strlen(name);
+ if (namelen >= NV_NAME_MAX) {
+ ERRNO_SET(ENAMETOOLONG);
+ return (NULL);
+ }
+
+ nvp = nv_calloc(1, sizeof(*nvp) + namelen + 1);
+ if (nvp != NULL) {
+ nvp->nvp_name = (char *)(nvp + 1);
+ memcpy(nvp->nvp_name, name, namelen);
+ nvp->nvp_name[namelen] = '\0';
+ nvp->nvp_type = type;
+ nvp->nvp_data = data;
+ nvp->nvp_datasize = datasize;
+ nvp->nvp_nitems = nitems;
+ nvp->nvp_magic = NVPAIR_MAGIC;
+ }
+
+ return (nvp);
+}
+
+nvlist_t *
+nvpair_nvlist(const nvpair_t *nvp)
+{
+
+ NVPAIR_ASSERT(nvp);
+
+ return (nvp->nvp_list);
+}
+
+nvpair_t *
+nvpair_next(const nvpair_t *nvp)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_list != NULL);
+
+ return (TAILQ_NEXT(nvp, nvp_next));
+}
+
+nvpair_t *
+nvpair_prev(const nvpair_t *nvp)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_list != NULL);
+
+ return (TAILQ_PREV(nvp, nvl_head, nvp_next));
+}
+
+void
+nvpair_insert(struct nvl_head *head, nvpair_t *nvp, nvlist_t *nvl)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_list == NULL);
+ PJDLOG_ASSERT((nvlist_flags(nvl) & NV_FLAG_NO_UNIQUE) != 0 ||
+ !nvlist_exists(nvl, nvpair_name(nvp)));
+
+ TAILQ_INSERT_TAIL(head, nvp, nvp_next);
+ nvp->nvp_list = nvl;
+}
+
+static void
+nvpair_remove_nvlist(nvpair_t *nvp)
+{
+ nvlist_t *nvl;
+
+ /* XXX: DECONST is bad, mkay? */
+ nvl = __DECONST(nvlist_t *, nvpair_get_nvlist(nvp));
+ PJDLOG_ASSERT(nvl != NULL);
+ nvlist_set_parent(nvl, NULL);
+}
+
+static void
+nvpair_remove_nvlist_array(nvpair_t *nvp)
+{
+ nvlist_t **nvlarray;
+ size_t count, i;
+
+ /* XXX: DECONST is bad, mkay? */
+ nvlarray = __DECONST(nvlist_t **,
+ nvpair_get_nvlist_array(nvp, &count));
+ for (i = 0; i < count; i++)
+ nvlist_set_array_next(nvlarray[i], NULL);
+}
+
+void
+nvpair_remove(struct nvl_head *head, nvpair_t *nvp, const nvlist_t *nvl)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_list == nvl);
+
+ if (nvpair_type(nvp) == NV_TYPE_NVLIST)
+ nvpair_remove_nvlist(nvp);
+ else if (nvpair_type(nvp) == NV_TYPE_NVLIST_ARRAY)
+ nvpair_remove_nvlist_array(nvp);
+
+ TAILQ_REMOVE(head, nvp, nvp_next);
+ nvp->nvp_list = NULL;
+}
+
+nvpair_t *
+nvpair_clone(const nvpair_t *nvp)
+{
+ nvpair_t *newnvp;
+ const char *name;
+ const void *data;
+ size_t datasize;
+
+ NVPAIR_ASSERT(nvp);
+
+ name = nvpair_name(nvp);
+
+ switch (nvpair_type(nvp)) {
+ case NV_TYPE_NULL:
+ newnvp = nvpair_create_null(name);
+ break;
+ case NV_TYPE_BOOL:
+ newnvp = nvpair_create_bool(name, nvpair_get_bool(nvp));
+ break;
+ case NV_TYPE_NUMBER:
+ newnvp = nvpair_create_number(name, nvpair_get_number(nvp));
+ break;
+ case NV_TYPE_STRING:
+ newnvp = nvpair_create_string(name, nvpair_get_string(nvp));
+ break;
+ case NV_TYPE_NVLIST:
+ newnvp = nvpair_create_nvlist(name, nvpair_get_nvlist(nvp));
+ break;
+ case NV_TYPE_BINARY:
+ data = nvpair_get_binary(nvp, &datasize);
+ newnvp = nvpair_create_binary(name, data, datasize);
+ break;
+ case NV_TYPE_BOOL_ARRAY:
+ data = nvpair_get_bool_array(nvp, &datasize);
+ newnvp = nvpair_create_bool_array(name, data, datasize);
+ break;
+ case NV_TYPE_NUMBER_ARRAY:
+ data = nvpair_get_number_array(nvp, &datasize);
+ newnvp = nvpair_create_number_array(name, data, datasize);
+ break;
+ case NV_TYPE_STRING_ARRAY:
+ data = nvpair_get_string_array(nvp, &datasize);
+ newnvp = nvpair_create_string_array(name, data, datasize);
+ break;
+ case NV_TYPE_NVLIST_ARRAY:
+ data = nvpair_get_nvlist_array(nvp, &datasize);
+ newnvp = nvpair_create_nvlist_array(name, data, datasize);
+ break;
+#ifndef _KERNEL
+ case NV_TYPE_DESCRIPTOR:
+ newnvp = nvpair_create_descriptor(name,
+ nvpair_get_descriptor(nvp));
+ break;
+ case NV_TYPE_DESCRIPTOR_ARRAY:
+ data = nvpair_get_descriptor_array(nvp, &datasize);
+ newnvp = nvpair_create_descriptor_array(name, data, datasize);
+ break;
+#endif
+ default:
+ PJDLOG_ABORT("Unknown type: %d.", nvpair_type(nvp));
+ }
+
+ return (newnvp);
+}
+
+size_t
+nvpair_header_size(void)
+{
+
+ return (sizeof(struct nvpair_header));
+}
+
+size_t
+nvpair_size(const nvpair_t *nvp)
+{
+
+ NVPAIR_ASSERT(nvp);
+
+ return (nvp->nvp_datasize);
+}
+
+unsigned char *
+nvpair_pack_header(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
+{
+ struct nvpair_header nvphdr;
+ size_t namesize;
+
+ NVPAIR_ASSERT(nvp);
+
+ nvphdr.nvph_type = nvp->nvp_type;
+ namesize = strlen(nvp->nvp_name) + 1;
+ PJDLOG_ASSERT(namesize > 0 && namesize <= UINT16_MAX);
+ nvphdr.nvph_namesize = namesize;
+ nvphdr.nvph_datasize = nvp->nvp_datasize;
+ nvphdr.nvph_nitems = nvp->nvp_nitems;
+ PJDLOG_ASSERT(*leftp >= sizeof(nvphdr));
+ memcpy(ptr, &nvphdr, sizeof(nvphdr));
+ ptr += sizeof(nvphdr);
+ *leftp -= sizeof(nvphdr);
+
+ PJDLOG_ASSERT(*leftp >= namesize);
+ memcpy(ptr, nvp->nvp_name, namesize);
+ ptr += namesize;
+ *leftp -= namesize;
+
+ return (ptr);
+}
+
+unsigned char *
+nvpair_pack_null(const nvpair_t *nvp, unsigned char *ptr,
+ size_t *leftp __unused)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NULL);
+
+ return (ptr);
+}
+
+unsigned char *
+nvpair_pack_bool(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
+{
+ uint8_t value;
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL);
+
+ value = (uint8_t)nvp->nvp_data;
+
+ PJDLOG_ASSERT(*leftp >= sizeof(value));
+ memcpy(ptr, &value, sizeof(value));
+ ptr += sizeof(value);
+ *leftp -= sizeof(value);
+
+ return (ptr);
+}
+
+unsigned char *
+nvpair_pack_number(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
+{
+ uint64_t value;
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER);
+
+ value = (uint64_t)nvp->nvp_data;
+
+ PJDLOG_ASSERT(*leftp >= sizeof(value));
+ memcpy(ptr, &value, sizeof(value));
+ ptr += sizeof(value);
+ *leftp -= sizeof(value);
+
+ return (ptr);
+}
+
+unsigned char *
+nvpair_pack_string(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
+
+ PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
+ memcpy(ptr, (const void *)(intptr_t)nvp->nvp_data, nvp->nvp_datasize);
+ ptr += nvp->nvp_datasize;
+ *leftp -= nvp->nvp_datasize;
+
+ return (ptr);
+}
+
+unsigned char *
+nvpair_pack_nvlist_up(unsigned char *ptr, size_t *leftp)
+{
+ struct nvpair_header nvphdr;
+ size_t namesize;
+ const char *name = "";
+
+ namesize = 1;
+ nvphdr.nvph_type = NV_TYPE_NVLIST_UP;
+ nvphdr.nvph_namesize = namesize;
+ nvphdr.nvph_datasize = 0;
+ nvphdr.nvph_nitems = 0;
+ PJDLOG_ASSERT(*leftp >= sizeof(nvphdr));
+ memcpy(ptr, &nvphdr, sizeof(nvphdr));
+ ptr += sizeof(nvphdr);
+ *leftp -= sizeof(nvphdr);
+
+ PJDLOG_ASSERT(*leftp >= namesize);
+ memcpy(ptr, name, namesize);
+ ptr += namesize;
+ *leftp -= namesize;
+
+ return (ptr);
+}
+
+unsigned char *
+nvpair_pack_nvlist_array_next(unsigned char *ptr, size_t *leftp)
+{
+ struct nvpair_header nvphdr;
+ size_t namesize;
+ const char *name = "";
+
+ namesize = 1;
+ nvphdr.nvph_type = NV_TYPE_NVLIST_ARRAY_NEXT;
+ nvphdr.nvph_namesize = namesize;
+ nvphdr.nvph_datasize = 0;
+ nvphdr.nvph_nitems = 0;
+ PJDLOG_ASSERT(*leftp >= sizeof(nvphdr));
+ memcpy(ptr, &nvphdr, sizeof(nvphdr));
+ ptr += sizeof(nvphdr);
+ *leftp -= sizeof(nvphdr);
+
+ PJDLOG_ASSERT(*leftp >= namesize);
+ memcpy(ptr, name, namesize);
+ ptr += namesize;
+ *leftp -= namesize;
+
+ return (ptr);
+}
+
+#ifndef _KERNEL
+unsigned char *
+nvpair_pack_descriptor(const nvpair_t *nvp, unsigned char *ptr, int64_t *fdidxp,
+ size_t *leftp)
+{
+ int64_t value;
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
+
+ value = (int64_t)nvp->nvp_data;
+ if (value != -1) {
+ /*
+ * If there is a real descriptor here, we change its number
+ * to position in the array of descriptors send via control
+ * message.
+ */
+ PJDLOG_ASSERT(fdidxp != NULL);
+
+ value = *fdidxp;
+ (*fdidxp)++;
+ }
+
+ PJDLOG_ASSERT(*leftp >= sizeof(value));
+ memcpy(ptr, &value, sizeof(value));
+ ptr += sizeof(value);
+ *leftp -= sizeof(value);
+
+ return (ptr);
+}
+#endif
+
+unsigned char *
+nvpair_pack_binary(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
+
+ PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
+ memcpy(ptr, (const void *)(intptr_t)nvp->nvp_data, nvp->nvp_datasize);
+ ptr += nvp->nvp_datasize;
+ *leftp -= nvp->nvp_datasize;
+
+ return (ptr);
+}
+
+unsigned char *
+nvpair_pack_bool_array(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL_ARRAY);
+ PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
+
+ memcpy(ptr, (const void *)(intptr_t)nvp->nvp_data, nvp->nvp_datasize);
+ ptr += nvp->nvp_datasize;
+ *leftp -= nvp->nvp_datasize;
+
+ return (ptr);
+}
+
+unsigned char *
+nvpair_pack_number_array(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER_ARRAY);
+ PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
+
+ memcpy(ptr, (const void *)(intptr_t)nvp->nvp_data, nvp->nvp_datasize);
+ ptr += nvp->nvp_datasize;
+ *leftp -= nvp->nvp_datasize;
+
+ return (ptr);
+}
+
+unsigned char *
+nvpair_pack_string_array(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
+{
+ unsigned int ii;
+ size_t size, len;
+ const char * const *array;
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING_ARRAY);
+ PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
+
+ size = 0;
+ array = nvpair_get_string_array(nvp, NULL);
+ PJDLOG_ASSERT(array != NULL);
+
+ for (ii = 0; ii < nvp->nvp_nitems; ii++) {
+ len = strlen(array[ii]) + 1;
+ PJDLOG_ASSERT(*leftp >= len);
+
+ memcpy(ptr, (const void *)array[ii], len);
+ size += len;
+ ptr += len;
+ *leftp -= len;
+ }
+
+ PJDLOG_ASSERT(size == nvp->nvp_datasize);
+
+ return (ptr);
+}
+
+#ifndef _KERNEL
+unsigned char *
+nvpair_pack_descriptor_array(const nvpair_t *nvp, unsigned char *ptr,
+ int64_t *fdidxp, size_t *leftp)
+{
+ int64_t value;
+ const int *array;
+ unsigned int ii;
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR_ARRAY);
+ PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
+
+ array = nvpair_get_descriptor_array(nvp, NULL);
+ PJDLOG_ASSERT(array != NULL);
+
+ for (ii = 0; ii < nvp->nvp_nitems; ii++) {
+ PJDLOG_ASSERT(*leftp >= sizeof(value));
+
+ value = array[ii];
+ if (value != -1) {
+ /*
+ * If there is a real descriptor here, we change its
+ * number to position in the array of descriptors send
+ * via control message.
+ */
+ PJDLOG_ASSERT(fdidxp != NULL);
+
+ value = *fdidxp;
+ (*fdidxp)++;
+ }
+ memcpy(ptr, &value, sizeof(value));
+ ptr += sizeof(value);
+ *leftp -= sizeof(value);
+ }
+
+ return (ptr);
+}
+#endif
+
+void
+nvpair_init_datasize(nvpair_t *nvp)
+{
+
+ NVPAIR_ASSERT(nvp);
+
+ if (nvp->nvp_type == NV_TYPE_NVLIST) {
+ if (nvp->nvp_data == 0) {
+ nvp->nvp_datasize = 0;
+ } else {
+ nvp->nvp_datasize =
+ nvlist_size((const nvlist_t *)(intptr_t)nvp->nvp_data);
+ }
+ }
+}
+
+const unsigned char *
+nvpair_unpack_header(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
+ size_t *leftp)
+{
+ struct nvpair_header nvphdr;
+
+ if (*leftp < sizeof(nvphdr))
+ goto failed;
+
+ memcpy(&nvphdr, ptr, sizeof(nvphdr));
+ ptr += sizeof(nvphdr);
+ *leftp -= sizeof(nvphdr);
+
+#if NV_TYPE_FIRST > 0
+ if (nvphdr.nvph_type < NV_TYPE_FIRST)
+ goto failed;
+#endif
+ if (nvphdr.nvph_type > NV_TYPE_LAST &&
+ nvphdr.nvph_type != NV_TYPE_NVLIST_UP &&
+ nvphdr.nvph_type != NV_TYPE_NVLIST_ARRAY_NEXT) {
+ goto failed;
+ }
+
+#if BYTE_ORDER == BIG_ENDIAN
+ if (!isbe) {
+ nvphdr.nvph_namesize = le16toh(nvphdr.nvph_namesize);
+ nvphdr.nvph_datasize = le64toh(nvphdr.nvph_datasize);
+ }
+#else
+ if (isbe) {
+ nvphdr.nvph_namesize = be16toh(nvphdr.nvph_namesize);
+ nvphdr.nvph_datasize = be64toh(nvphdr.nvph_datasize);
+ }
+#endif
+
+ if (nvphdr.nvph_namesize > NV_NAME_MAX)
+ goto failed;
+ if (*leftp < nvphdr.nvph_namesize)
+ goto failed;
+ if (nvphdr.nvph_namesize < 1)
+ goto failed;
+ if (strnlen((const char *)ptr, nvphdr.nvph_namesize) !=
+ (size_t)(nvphdr.nvph_namesize - 1)) {
+ goto failed;
+ }
+
+ memcpy(nvp->nvp_name, ptr, nvphdr.nvph_namesize);
+ ptr += nvphdr.nvph_namesize;
+ *leftp -= nvphdr.nvph_namesize;
+
+ if (*leftp < nvphdr.nvph_datasize)
+ goto failed;
+
+ nvp->nvp_type = nvphdr.nvph_type;
+ nvp->nvp_data = 0;
+ nvp->nvp_datasize = nvphdr.nvph_datasize;
+ nvp->nvp_nitems = nvphdr.nvph_nitems;
+
+ return (ptr);
+failed:
+ ERRNO_SET(EINVAL);
+ return (NULL);
+}
+
+const unsigned char *
+nvpair_unpack_null(bool isbe __unused, nvpair_t *nvp, const unsigned char *ptr,
+ size_t *leftp __unused)
+{
+
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NULL);
+
+ if (nvp->nvp_datasize != 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ return (ptr);
+}
+
+const unsigned char *
+nvpair_unpack_bool(bool isbe __unused, nvpair_t *nvp, const unsigned char *ptr,
+ size_t *leftp)
+{
+ uint8_t value;
+
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL);
+
+ if (nvp->nvp_datasize != sizeof(value)) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+ if (*leftp < sizeof(value)) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ memcpy(&value, ptr, sizeof(value));
+ ptr += sizeof(value);
+ *leftp -= sizeof(value);
+
+ if (value != 0 && value != 1) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ nvp->nvp_data = (uint64_t)value;
+
+ return (ptr);
+}
+
+const unsigned char *
+nvpair_unpack_number(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
+ size_t *leftp)
+{
+
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER);
+
+ if (nvp->nvp_datasize != sizeof(uint64_t)) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+ if (*leftp < sizeof(uint64_t)) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ if (isbe)
+ nvp->nvp_data = be64dec(ptr);
+ else
+ nvp->nvp_data = le64dec(ptr);
+
+ ptr += sizeof(uint64_t);
+ *leftp -= sizeof(uint64_t);
+
+ return (ptr);
+}
+
+const unsigned char *
+nvpair_unpack_string(bool isbe __unused, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp)
+{
+
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
+
+ if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ if (strnlen((const char *)ptr, nvp->nvp_datasize) !=
+ nvp->nvp_datasize - 1) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ nvp->nvp_data = (uint64_t)(uintptr_t)nv_strdup((const char *)ptr);
+ if (nvp->nvp_data == 0)
+ return (NULL);
+
+ ptr += nvp->nvp_datasize;
+ *leftp -= nvp->nvp_datasize;
+
+ return (ptr);
+}
+
+const unsigned char *
+nvpair_unpack_nvlist(bool isbe __unused, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp, size_t nfds, nvlist_t **child)
+{
+ nvlist_t *value;
+
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST);
+
+ if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ value = nvlist_create(0);
+ if (value == NULL)
+ return (NULL);
+
+ ptr = nvlist_unpack_header(value, ptr, nfds, NULL, leftp);
+ if (ptr == NULL)
+ return (NULL);
+
+ nvp->nvp_data = (uint64_t)(uintptr_t)value;
+ *child = value;
+
+ return (ptr);
+}
+
+#ifndef _KERNEL
+const unsigned char *
+nvpair_unpack_descriptor(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
+ size_t *leftp, const int *fds, size_t nfds)
+{
+ int64_t idx;
+
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
+
+ if (nvp->nvp_datasize != sizeof(idx)) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+ if (*leftp < sizeof(idx)) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ if (isbe)
+ idx = be64dec(ptr);
+ else
+ idx = le64dec(ptr);
+
+ if (idx < 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ if ((size_t)idx >= nfds) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ nvp->nvp_data = (uint64_t)fds[idx];
+
+ ptr += sizeof(idx);
+ *leftp -= sizeof(idx);
+
+ return (ptr);
+}
+#endif
+
+const unsigned char *
+nvpair_unpack_binary(bool isbe __unused, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp)
+{
+ void *value;
+
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
+
+ if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ value = nv_malloc(nvp->nvp_datasize);
+ if (value == NULL)
+ return (NULL);
+
+ memcpy(value, ptr, nvp->nvp_datasize);
+ ptr += nvp->nvp_datasize;
+ *leftp -= nvp->nvp_datasize;
+
+ nvp->nvp_data = (uint64_t)(uintptr_t)value;
+
+ return (ptr);
+}
+
+const unsigned char *
+nvpair_unpack_bool_array(bool isbe __unused, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp)
+{
+ uint8_t *value;
+ size_t size;
+ unsigned int i;
+
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL_ARRAY);
+
+ size = sizeof(*value) * nvp->nvp_nitems;
+ if (nvp->nvp_datasize != size || *leftp < size ||
+ nvp->nvp_nitems == 0 || size < nvp->nvp_nitems) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ value = nv_malloc(size);
+ if (value == NULL)
+ return (NULL);
+
+ for (i = 0; i < nvp->nvp_nitems; i++) {
+ value[i] = *(const uint8_t *)ptr;
+
+ ptr += sizeof(*value);
+ *leftp -= sizeof(*value);
+ }
+
+ nvp->nvp_data = (uint64_t)(uintptr_t)value;
+
+ return (ptr);
+}
+
+const unsigned char *
+nvpair_unpack_number_array(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
+ size_t *leftp)
+{
+ uint64_t *value;
+ size_t size;
+ unsigned int i;
+
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER_ARRAY);
+
+ size = sizeof(*value) * nvp->nvp_nitems;
+ if (nvp->nvp_datasize != size || *leftp < size ||
+ nvp->nvp_nitems == 0 || size < nvp->nvp_nitems) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ value = nv_malloc(size);
+ if (value == NULL)
+ return (NULL);
+
+ for (i = 0; i < nvp->nvp_nitems; i++) {
+ if (isbe)
+ value[i] = be64dec(ptr);
+ else
+ value[i] = le64dec(ptr);
+
+ ptr += sizeof(*value);
+ *leftp -= sizeof(*value);
+ }
+
+ nvp->nvp_data = (uint64_t)(uintptr_t)value;
+
+ return (ptr);
+}
+
+const unsigned char *
+nvpair_unpack_string_array(bool isbe __unused, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp)
+{
+ ssize_t size;
+ size_t len;
+ const char *tmp;
+ char **value;
+ unsigned int ii, j;
+
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING_ARRAY);
+
+ if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0 ||
+ nvp->nvp_nitems == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ size = nvp->nvp_datasize;
+ tmp = (const char *)ptr;
+ for (ii = 0; ii < nvp->nvp_nitems; ii++) {
+ len = strnlen(tmp, size - 1) + 1;
+ size -= len;
+ if (size < 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+ tmp += len;
+ }
+ if (size != 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ value = nv_malloc(sizeof(*value) * nvp->nvp_nitems);
+ if (value == NULL)
+ return (NULL);
+
+ for (ii = 0; ii < nvp->nvp_nitems; ii++) {
+ value[ii] = nv_strdup((const char *)ptr);
+ if (value[ii] == NULL)
+ goto out;
+ len = strlen(value[ii]) + 1;
+ ptr += len;
+ *leftp -= len;
+ }
+ nvp->nvp_data = (uint64_t)(uintptr_t)value;
+
+ return (ptr);
+out:
+ for (j = 0; j < ii; j++)
+ nv_free(value[j]);
+ nv_free(value);
+ return (NULL);
+}
+
+#ifndef _KERNEL
+const unsigned char *
+nvpair_unpack_descriptor_array(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp, const int *fds, size_t nfds)
+{
+ int64_t idx;
+ size_t size;
+ unsigned int ii;
+ int *array;
+
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR_ARRAY);
+
+ size = sizeof(idx) * nvp->nvp_nitems;
+ if (nvp->nvp_datasize != size || *leftp < size ||
+ nvp->nvp_nitems == 0 || size < nvp->nvp_nitems) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ array = (int *)nv_malloc(size);
+ if (array == NULL)
+ return (NULL);
+
+ for (ii = 0; ii < nvp->nvp_nitems; ii++) {
+ if (isbe)
+ idx = be64dec(ptr);
+ else
+ idx = le64dec(ptr);
+
+ if (idx < 0) {
+ ERRNO_SET(EINVAL);
+ nv_free(array);
+ return (NULL);
+ }
+
+ if ((size_t)idx >= nfds) {
+ ERRNO_SET(EINVAL);
+ nv_free(array);
+ return (NULL);
+ }
+
+ array[ii] = (uint64_t)fds[idx];
+
+ ptr += sizeof(idx);
+ *leftp -= sizeof(idx);
+ }
+
+ nvp->nvp_data = (uint64_t)(uintptr_t)array;
+
+ return (ptr);
+}
+#endif
+
+const unsigned char *
+nvpair_unpack_nvlist_array(bool isbe __unused, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp, nvlist_t **firstel)
+{
+ nvlist_t **value;
+ nvpair_t *tmpnvp;
+ unsigned int ii, j;
+ size_t sizeup;
+
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST_ARRAY);
+
+ sizeup = sizeof(struct nvpair_header) * nvp->nvp_nitems;
+ if (nvp->nvp_nitems == 0 || sizeup < nvp->nvp_nitems ||
+ sizeup > *leftp) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ value = nv_malloc(nvp->nvp_nitems * sizeof(*value));
+ if (value == NULL)
+ return (NULL);
+
+ for (ii = 0; ii < nvp->nvp_nitems; ii++) {
+ value[ii] = nvlist_create(0);
+ if (value[ii] == NULL)
+ goto fail;
+ if (ii > 0) {
+ tmpnvp = nvpair_allocv(" ", NV_TYPE_NVLIST,
+ (uint64_t)(uintptr_t)value[ii], 0, 0);
+ if (tmpnvp == NULL)
+ goto fail;
+ nvlist_set_array_next(value[ii - 1], tmpnvp);
+ }
+ }
+ nvlist_set_flags(value[nvp->nvp_nitems - 1], NV_FLAG_IN_ARRAY);
+
+ nvp->nvp_data = (uint64_t)(uintptr_t)value;
+ *firstel = value[0];
+
+ return (ptr);
+fail:
+ ERRNO_SAVE();
+ for (j = 0; j < ii; j++)
+ nvlist_destroy(value[j]);
+ nv_free(value);
+ ERRNO_RESTORE();
+
+ return (NULL);
+}
+
+const unsigned char *
+nvpair_unpack(bool isbe, const unsigned char *ptr, size_t *leftp,
+ nvpair_t **nvpp)
+{
+ nvpair_t *nvp, *tmp;
+
+ nvp = nv_calloc(1, sizeof(*nvp) + NV_NAME_MAX);
+ if (nvp == NULL)
+ return (NULL);
+ nvp->nvp_name = (char *)(nvp + 1);
+
+ ptr = nvpair_unpack_header(isbe, nvp, ptr, leftp);
+ if (ptr == NULL)
+ goto failed;
+ tmp = nv_realloc(nvp, sizeof(*nvp) + strlen(nvp->nvp_name) + 1);
+ if (tmp == NULL)
+ goto failed;
+ nvp = tmp;
+
+ /* Update nvp_name after realloc(). */
+ nvp->nvp_name = (char *)(nvp + 1);
+ nvp->nvp_data = 0x00;
+ nvp->nvp_magic = NVPAIR_MAGIC;
+ *nvpp = nvp;
+ return (ptr);
+failed:
+ nv_free(nvp);
+ return (NULL);
+}
+
+int
+nvpair_type(const nvpair_t *nvp)
+{
+
+ NVPAIR_ASSERT(nvp);
+
+ return (nvp->nvp_type);
+}
+
+const char *
+nvpair_name(const nvpair_t *nvp)
+{
+
+ NVPAIR_ASSERT(nvp);
+
+ return (nvp->nvp_name);
+}
+
+nvpair_t *
+nvpair_create_stringf(const char *name, const char *valuefmt, ...)
+{
+ va_list valueap;
+ nvpair_t *nvp;
+
+ va_start(valueap, valuefmt);
+ nvp = nvpair_create_stringv(name, valuefmt, valueap);
+ va_end(valueap);
+
+ return (nvp);
+}
+
+nvpair_t *
+nvpair_create_stringv(const char *name, const char *valuefmt, va_list valueap)
+{
+ nvpair_t *nvp;
+ char *str;
+ int len;
+
+ len = nv_vasprintf(&str, valuefmt, valueap);
+ if (len < 0)
+ return (NULL);
+ nvp = nvpair_create_string(name, str);
+ if (nvp == NULL)
+ nv_free(str);
+ return (nvp);
+}
+
+nvpair_t *
+nvpair_create_null(const char *name)
+{
+
+ return (nvpair_allocv(name, NV_TYPE_NULL, 0, 0, 0));
+}
+
+nvpair_t *
+nvpair_create_bool(const char *name, bool value)
+{
+
+ return (nvpair_allocv(name, NV_TYPE_BOOL, value ? 1 : 0,
+ sizeof(uint8_t), 0));
+}
+
+nvpair_t *
+nvpair_create_number(const char *name, uint64_t value)
+{
+
+ return (nvpair_allocv(name, NV_TYPE_NUMBER, value, sizeof(value), 0));
+}
+
+nvpair_t *
+nvpair_create_string(const char *name, const char *value)
+{
+ nvpair_t *nvp;
+ size_t size;
+ char *data;
+
+ if (value == NULL) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ data = nv_strdup(value);
+ if (data == NULL)
+ return (NULL);
+ size = strlen(value) + 1;
+
+ nvp = nvpair_allocv(name, NV_TYPE_STRING, (uint64_t)(uintptr_t)data,
+ size, 0);
+ if (nvp == NULL)
+ nv_free(data);
+
+ return (nvp);
+}
+
+nvpair_t *
+nvpair_create_nvlist(const char *name, const nvlist_t *value)
+{
+ nvlist_t *nvl;
+ nvpair_t *nvp;
+
+ if (value == NULL) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ nvl = nvlist_clone(value);
+ if (nvl == NULL)
+ return (NULL);
+
+ nvp = nvpair_allocv(name, NV_TYPE_NVLIST, (uint64_t)(uintptr_t)nvl, 0,
+ 0);
+ if (nvp == NULL)
+ nvlist_destroy(nvl);
+ else
+ nvlist_set_parent(nvl, nvp);
+
+ return (nvp);
+}
+
+#ifndef _KERNEL
+nvpair_t *
+nvpair_create_descriptor(const char *name, int value)
+{
+ nvpair_t *nvp;
+
+ if (value < 0 || !fd_is_valid(value)) {
+ ERRNO_SET(EBADF);
+ return (NULL);
+ }
+
+ value = fcntl(value, F_DUPFD_CLOEXEC, 0);
+ if (value < 0)
+ return (NULL);
+
+ nvp = nvpair_allocv(name, NV_TYPE_DESCRIPTOR, (uint64_t)value,
+ sizeof(int64_t), 0);
+ if (nvp == NULL) {
+ ERRNO_SAVE();
+ close(value);
+ ERRNO_RESTORE();
+ }
+
+ return (nvp);
+}
+#endif
+
+nvpair_t *
+nvpair_create_binary(const char *name, const void *value, size_t size)
+{
+ nvpair_t *nvp;
+ void *data;
+
+ if (value == NULL || size == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ data = nv_malloc(size);
+ if (data == NULL)
+ return (NULL);
+ memcpy(data, value, size);
+
+ nvp = nvpair_allocv(name, NV_TYPE_BINARY, (uint64_t)(uintptr_t)data,
+ size, 0);
+ if (nvp == NULL)
+ nv_free(data);
+
+ return (nvp);
+}
+
+nvpair_t *
+nvpair_create_bool_array(const char *name, const bool *value, size_t nitems)
+{
+ nvpair_t *nvp;
+ size_t size;
+ void *data;
+
+ if (value == NULL || nitems == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ size = sizeof(value[0]) * nitems;
+ data = nv_malloc(size);
+ if (data == NULL)
+ return (NULL);
+
+ memcpy(data, value, size);
+ nvp = nvpair_allocv(name, NV_TYPE_BOOL_ARRAY, (uint64_t)(uintptr_t)data,
+ size, nitems);
+ if (nvp == NULL) {
+ ERRNO_SAVE();
+ nv_free(data);
+ ERRNO_RESTORE();
+ }
+
+ return (nvp);
+}
+
+nvpair_t *
+nvpair_create_number_array(const char *name, const uint64_t *value,
+ size_t nitems)
+{
+ nvpair_t *nvp;
+ size_t size;
+ void *data;
+
+ if (value == NULL || nitems == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ size = sizeof(value[0]) * nitems;
+ data = nv_malloc(size);
+ if (data == NULL)
+ return (NULL);
+
+ memcpy(data, value, size);
+ nvp = nvpair_allocv(name, NV_TYPE_NUMBER_ARRAY,
+ (uint64_t)(uintptr_t)data, size, nitems);
+ if (nvp == NULL) {
+ ERRNO_SAVE();
+ nv_free(data);
+ ERRNO_RESTORE();
+ }
+
+ return (nvp);
+}
+
+nvpair_t *
+nvpair_create_string_array(const char *name, const char * const *value,
+ size_t nitems)
+{
+ nvpair_t *nvp;
+ unsigned int ii;
+ size_t datasize, size;
+ char **data;
+
+ if (value == NULL || nitems == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ nvp = NULL;
+ datasize = 0;
+ data = nv_malloc(sizeof(value[0]) * nitems);
+ if (data == NULL)
+ return (NULL);
+
+ for (ii = 0; ii < nitems; ii++) {
+ if (value[ii] == NULL) {
+ ERRNO_SET(EINVAL);
+ goto fail;
+ }
+
+ size = strlen(value[ii]) + 1;
+ datasize += size;
+ data[ii] = nv_strdup(value[ii]);
+ if (data[ii] == NULL)
+ goto fail;
+ }
+ nvp = nvpair_allocv(name, NV_TYPE_STRING_ARRAY,
+ (uint64_t)(uintptr_t)data, datasize, nitems);
+
+fail:
+ if (nvp == NULL) {
+ ERRNO_SAVE();
+ for (; ii > 0; ii--)
+ nv_free(data[ii - 1]);
+ nv_free(data);
+ ERRNO_RESTORE();
+ }
+
+ return (nvp);
+}
+
+nvpair_t *
+nvpair_create_nvlist_array(const char *name, const nvlist_t * const *value,
+ size_t nitems)
+{
+ unsigned int ii;
+ nvlist_t **nvls;
+ nvpair_t *nvp;
+ int flags;
+
+ nvp = NULL;
+ nvls = NULL;
+ ii = 0;
+
+ if (value == NULL || nitems == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ nvls = nv_malloc(sizeof(value[0]) * nitems);
+ if (nvls == NULL)
+ return (NULL);
+
+ for (ii = 0; ii < nitems; ii++) {
+ if (value[ii] == NULL) {
+ ERRNO_SET(EINVAL);
+ goto fail;
+ }
+
+ nvls[ii] = nvlist_clone(value[ii]);
+ if (nvls[ii] == NULL)
+ goto fail;
+
+ if (ii > 0) {
+ nvp = nvpair_allocv(" ", NV_TYPE_NVLIST,
+ (uint64_t)(uintptr_t)nvls[ii], 0, 0);
+ if (nvp == NULL)
+ goto fail;
+ nvlist_set_array_next(nvls[ii - 1], nvp);
+ }
+ }
+ flags = nvlist_flags(nvls[nitems - 1]) | NV_FLAG_IN_ARRAY;
+ nvlist_set_flags(nvls[nitems - 1], flags);
+
+ nvp = nvpair_allocv(name, NV_TYPE_NVLIST_ARRAY,
+ (uint64_t)(uintptr_t)nvls, 0, nitems);
+
+fail:
+ if (nvp == NULL) {
+ ERRNO_SAVE();
+ for (; ii > 0; ii--)
+ nvlist_destroy(nvls[ii - 1]);
+
+ nv_free(nvls);
+ ERRNO_RESTORE();
+ } else {
+ for (ii = 0; ii < nitems; ii++)
+ nvlist_set_parent(nvls[ii], nvp);
+ }
+
+ return (nvp);
+}
+
+#ifndef _KERNEL
+nvpair_t *
+nvpair_create_descriptor_array(const char *name, const int *value,
+ size_t nitems)
+{
+ unsigned int ii;
+ nvpair_t *nvp;
+ int *fds;
+
+ if (value == NULL) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ nvp = NULL;
+
+ fds = nv_malloc(sizeof(value[0]) * nitems);
+ if (fds == NULL)
+ return (NULL);
+ for (ii = 0; ii < nitems; ii++) {
+ if (value[ii] == -1) {
+ fds[ii] = -1;
+ } else {
+ if (!fd_is_valid(value[ii])) {
+ ERRNO_SET(EBADF);
+ goto fail;
+ }
+
+ fds[ii] = fcntl(value[ii], F_DUPFD_CLOEXEC, 0);
+ if (fds[ii] == -1)
+ goto fail;
+ }
+ }
+
+ nvp = nvpair_allocv(name, NV_TYPE_DESCRIPTOR_ARRAY,
+ (uint64_t)(uintptr_t)fds, sizeof(int64_t) * nitems, nitems);
+
+fail:
+ if (nvp == NULL) {
+ ERRNO_SAVE();
+ for (; ii > 0; ii--) {
+ if (fds[ii - 1] != -1)
+ close(fds[ii - 1]);
+ }
+ nv_free(fds);
+ ERRNO_RESTORE();
+ }
+
+ return (nvp);
+}
+#endif
+
+nvpair_t *
+nvpair_move_string(const char *name, char *value)
+{
+ nvpair_t *nvp;
+
+ if (value == NULL) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ nvp = nvpair_allocv(name, NV_TYPE_STRING, (uint64_t)(uintptr_t)value,
+ strlen(value) + 1, 0);
+ if (nvp == NULL) {
+ ERRNO_SAVE();
+ nv_free(value);
+ ERRNO_RESTORE();
+ }
+
+ return (nvp);
+}
+
+nvpair_t *
+nvpair_move_nvlist(const char *name, nvlist_t *value)
+{
+ nvpair_t *nvp;
+
+ if (value == NULL || nvlist_get_nvpair_parent(value) != NULL) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ if (nvlist_error(value) != 0) {
+ ERRNO_SET(nvlist_error(value));
+ nvlist_destroy(value);
+ return (NULL);
+ }
+
+ nvp = nvpair_allocv(name, NV_TYPE_NVLIST, (uint64_t)(uintptr_t)value,
+ 0, 0);
+ if (nvp == NULL)
+ nvlist_destroy(value);
+ else
+ nvlist_set_parent(value, nvp);
+
+ return (nvp);
+}
+
+#ifndef _KERNEL
+nvpair_t *
+nvpair_move_descriptor(const char *name, int value)
+{
+ nvpair_t *nvp;
+
+ if (value < 0 || !fd_is_valid(value)) {
+ ERRNO_SET(EBADF);
+ return (NULL);
+ }
+
+ nvp = nvpair_allocv(name, NV_TYPE_DESCRIPTOR, (uint64_t)value,
+ sizeof(int64_t), 0);
+ if (nvp == NULL) {
+ ERRNO_SAVE();
+ close(value);
+ ERRNO_RESTORE();
+ }
+
+ return (nvp);
+}
+#endif
+
+nvpair_t *
+nvpair_move_binary(const char *name, void *value, size_t size)
+{
+ nvpair_t *nvp;
+
+ if (value == NULL || size == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ nvp = nvpair_allocv(name, NV_TYPE_BINARY, (uint64_t)(uintptr_t)value,
+ size, 0);
+ if (nvp == NULL) {
+ ERRNO_SAVE();
+ nv_free(value);
+ ERRNO_RESTORE();
+ }
+
+ return (nvp);
+}
+
+nvpair_t *
+nvpair_move_bool_array(const char *name, bool *value, size_t nitems)
+{
+ nvpair_t *nvp;
+
+ if (value == NULL || nitems == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ nvp = nvpair_allocv(name, NV_TYPE_BOOL_ARRAY,
+ (uint64_t)(uintptr_t)value, sizeof(value[0]) * nitems, nitems);
+ if (nvp == NULL) {
+ ERRNO_SAVE();
+ nv_free(value);
+ ERRNO_RESTORE();
+ }
+
+ return (nvp);
+}
+
+nvpair_t *
+nvpair_move_string_array(const char *name, char **value, size_t nitems)
+{
+ nvpair_t *nvp;
+ size_t i, size;
+
+ if (value == NULL || nitems == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ size = 0;
+ for (i = 0; i < nitems; i++) {
+ if (value[i] == NULL) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ size += strlen(value[i]) + 1;
+ }
+
+ nvp = nvpair_allocv(name, NV_TYPE_STRING_ARRAY,
+ (uint64_t)(uintptr_t)value, size, nitems);
+ if (nvp == NULL) {
+ ERRNO_SAVE();
+ for (i = 0; i < nitems; i++)
+ nv_free(value[i]);
+ nv_free(value);
+ ERRNO_RESTORE();
+ }
+
+ return (nvp);
+}
+
+nvpair_t *
+nvpair_move_number_array(const char *name, uint64_t *value, size_t nitems)
+{
+ nvpair_t *nvp;
+
+ if (value == NULL || nitems == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ nvp = nvpair_allocv(name, NV_TYPE_NUMBER_ARRAY,
+ (uint64_t)(uintptr_t)value, sizeof(value[0]) * nitems, nitems);
+ if (nvp == NULL) {
+ ERRNO_SAVE();
+ nv_free(value);
+ ERRNO_RESTORE();
+ }
+
+ return (nvp);
+}
+
+nvpair_t *
+nvpair_move_nvlist_array(const char *name, nvlist_t **value, size_t nitems)
+{
+ unsigned int ii;
+ nvpair_t *nvp;
+ int flags;
+
+ nvp = NULL;
+ if (value == NULL || nitems == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ for (ii = 0; ii < nitems; ii++) {
+ if (value == NULL || nvlist_error(value[ii]) != 0 ||
+ nvlist_get_pararr(value[ii], NULL) != NULL) {
+ ERRNO_SET(EINVAL);
+ goto fail;
+ }
+ if (ii > 0) {
+ nvp = nvpair_allocv(" ", NV_TYPE_NVLIST,
+ (uint64_t)(uintptr_t)value[ii], 0, 0);
+ if (nvp == NULL)
+ goto fail;
+ nvlist_set_array_next(value[ii - 1], nvp);
+ }
+ }
+ flags = nvlist_flags(value[nitems - 1]) | NV_FLAG_IN_ARRAY;
+ nvlist_set_flags(value[nitems - 1], flags);
+
+ nvp = nvpair_allocv(name, NV_TYPE_NVLIST_ARRAY,
+ (uint64_t)(uintptr_t)value, 0, nitems);
+fail:
+ if (nvp == NULL) {
+ ERRNO_SAVE();
+ for (ii = 0; ii < nitems; ii++) {
+ if (value[ii] != NULL &&
+ nvlist_get_pararr(value[ii], NULL) != NULL) {
+ nvlist_destroy(value[ii]);
+ }
+ nv_free(value);
+ }
+ ERRNO_RESTORE();
+ } else {
+ for (ii = 0; ii < nitems; ii++)
+ nvlist_set_parent(value[ii], nvp);
+ }
+
+ return (nvp);
+}
+
+#ifndef _KERNEL
+nvpair_t *
+nvpair_move_descriptor_array(const char *name, int *value, size_t nitems)
+{
+ nvpair_t *nvp;
+ size_t i;
+
+ nvp = NULL;
+ if (value == NULL || nitems == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ for (i = 0; i < nitems; i++) {
+ if (value[i] != -1 && !fd_is_valid(value[i])) {
+ ERRNO_SET(EBADF);
+ goto fail;
+ }
+ }
+
+ nvp = nvpair_allocv(name, NV_TYPE_DESCRIPTOR_ARRAY,
+ (uint64_t)(uintptr_t)value, sizeof(value[0]) * nitems, nitems);
+
+fail:
+ if (nvp == NULL) {
+ ERRNO_SAVE();
+ for (i = 0; i < nitems; i++) {
+ if (fd_is_valid(value[i]))
+ close(value[i]);
+ }
+ nv_free(value);
+ ERRNO_RESTORE();
+ }
+
+ return (nvp);
+}
+#endif
+
+bool
+nvpair_get_bool(const nvpair_t *nvp)
+{
+
+ NVPAIR_ASSERT(nvp);
+
+ return (nvp->nvp_data == 1);
+}
+
+uint64_t
+nvpair_get_number(const nvpair_t *nvp)
+{
+
+ NVPAIR_ASSERT(nvp);
+
+ return (nvp->nvp_data);
+}
+
+const char *
+nvpair_get_string(const nvpair_t *nvp)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
+
+ return ((const char *)(intptr_t)nvp->nvp_data);
+}
+
+const nvlist_t *
+nvpair_get_nvlist(const nvpair_t *nvp)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST);
+
+ return ((const nvlist_t *)(intptr_t)nvp->nvp_data);
+}
+
+#ifndef _KERNEL
+int
+nvpair_get_descriptor(const nvpair_t *nvp)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
+
+ return ((int)nvp->nvp_data);
+}
+#endif
+
+const void *
+nvpair_get_binary(const nvpair_t *nvp, size_t *sizep)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
+
+ if (sizep != NULL)
+ *sizep = nvp->nvp_datasize;
+
+ return ((const void *)(intptr_t)nvp->nvp_data);
+}
+
+const bool *
+nvpair_get_bool_array(const nvpair_t *nvp, size_t *nitems)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL_ARRAY);
+
+ if (nitems != NULL)
+ *nitems = nvp->nvp_nitems;
+
+ return ((const bool *)(intptr_t)nvp->nvp_data);
+}
+
+const uint64_t *
+nvpair_get_number_array(const nvpair_t *nvp, size_t *nitems)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER_ARRAY);
+
+ if (nitems != NULL)
+ *nitems = nvp->nvp_nitems;
+
+ return ((const uint64_t *)(intptr_t)nvp->nvp_data);
+}
+
+const char * const *
+nvpair_get_string_array(const nvpair_t *nvp, size_t *nitems)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING_ARRAY);
+
+ if (nitems != NULL)
+ *nitems = nvp->nvp_nitems;
+
+ return ((const char * const *)(intptr_t)nvp->nvp_data);
+}
+
+const nvlist_t * const *
+nvpair_get_nvlist_array(const nvpair_t *nvp, size_t *nitems)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST_ARRAY);
+
+ if (nitems != NULL)
+ *nitems = nvp->nvp_nitems;
+
+ return ((const nvlist_t * const *)((intptr_t)nvp->nvp_data));
+}
+
+#ifndef _KERNEL
+const int *
+nvpair_get_descriptor_array(const nvpair_t *nvp, size_t *nitems)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR_ARRAY);
+
+ if (nitems != NULL)
+ *nitems = nvp->nvp_nitems;
+
+ return ((const int *)(intptr_t)nvp->nvp_data);
+}
+#endif
+
+void
+nvpair_free(nvpair_t *nvp)
+{
+ size_t i;
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_list == NULL);
+
+ nvp->nvp_magic = 0;
+ switch (nvp->nvp_type) {
+#ifndef _KERNEL
+ case NV_TYPE_DESCRIPTOR:
+ close((int)nvp->nvp_data);
+ break;
+ case NV_TYPE_DESCRIPTOR_ARRAY:
+ for (i = 0; i < nvp->nvp_nitems; i++)
+ close(((int *)(intptr_t)nvp->nvp_data)[i]);
+ break;
+#endif
+ case NV_TYPE_NVLIST:
+ nvlist_destroy((nvlist_t *)(intptr_t)nvp->nvp_data);
+ break;
+ case NV_TYPE_STRING:
+ nv_free((char *)(intptr_t)nvp->nvp_data);
+ break;
+ case NV_TYPE_BINARY:
+ nv_free((void *)(intptr_t)nvp->nvp_data);
+ break;
+ case NV_TYPE_NVLIST_ARRAY:
+ for (i = 0; i < nvp->nvp_nitems; i++) {
+ nvlist_destroy(
+ ((nvlist_t **)(intptr_t)nvp->nvp_data)[i]);
+ }
+ nv_free(((nvlist_t **)(intptr_t)nvp->nvp_data));
+ break;
+ case NV_TYPE_NUMBER_ARRAY:
+ nv_free((uint64_t *)(intptr_t)nvp->nvp_data);
+ break;
+ case NV_TYPE_BOOL_ARRAY:
+ nv_free((bool *)(intptr_t)nvp->nvp_data);
+ break;
+ case NV_TYPE_STRING_ARRAY:
+ for (i = 0; i < nvp->nvp_nitems; i++)
+ nv_free(((char **)(intptr_t)nvp->nvp_data)[i]);
+ break;
+ }
+ nv_free(nvp);
+}
+
+void
+nvpair_free_structure(nvpair_t *nvp)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_list == NULL);
+
+ nvp->nvp_magic = 0;
+ nv_free(nvp);
+}
+
+const char *
+nvpair_type_string(int type)
+{
+
+ switch (type) {
+ case NV_TYPE_NULL:
+ return ("NULL");
+ case NV_TYPE_BOOL:
+ return ("BOOL");
+ case NV_TYPE_NUMBER:
+ return ("NUMBER");
+ case NV_TYPE_STRING:
+ return ("STRING");
+ case NV_TYPE_NVLIST:
+ return ("NVLIST");
+ case NV_TYPE_DESCRIPTOR:
+ return ("DESCRIPTOR");
+ case NV_TYPE_BINARY:
+ return ("BINARY");
+ case NV_TYPE_BOOL_ARRAY:
+ return ("BOOL ARRAY");
+ case NV_TYPE_NUMBER_ARRAY:
+ return ("NUMBER ARRAY");
+ case NV_TYPE_STRING_ARRAY:
+ return ("STRING ARRAY");
+ case NV_TYPE_NVLIST_ARRAY:
+ return ("NVLIST ARRAY");
+ case NV_TYPE_DESCRIPTOR_ARRAY:
+ return ("DESCRIPTOR ARRAY");
+ default:
+ return ("<UNKNOWN>");
+ }
+}
+
Index: sys/contrib/libnv/nvpair_impl.h
===================================================================
--- sys/contrib/libnv/nvpair_impl.h
+++ sys/contrib/libnv/nvpair_impl.h
@@ -0,0 +1,113 @@
+/*-
+ * Copyright (c) 2009-2013 The FreeBSD Foundation
+ * Copyright (c) 2013-2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * 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 AUTHORS 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 AUTHORS 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 _NVPAIR_IMPL_H_
+#define _NVPAIR_IMPL_H_
+
+#include <sys/nv.h>
+#include <sys/queue.h>
+
+#ifndef _KERNEL
+#include <stdint.h>
+#endif
+
+TAILQ_HEAD(nvl_head, nvpair);
+
+void nvpair_assert(const nvpair_t *nvp);
+nvlist_t *nvpair_nvlist(const nvpair_t *nvp);
+nvpair_t *nvpair_next(const nvpair_t *nvp);
+nvpair_t *nvpair_prev(const nvpair_t *nvp);
+void nvpair_insert(struct nvl_head *head, nvpair_t *nvp, nvlist_t *nvl);
+void nvpair_remove(struct nvl_head *head, nvpair_t *nvp, const nvlist_t *nvl);
+size_t nvpair_header_size(void);
+size_t nvpair_size(const nvpair_t *nvp);
+const unsigned char *nvpair_unpack(bool isbe, const unsigned char *ptr,
+ size_t *leftp, nvpair_t **nvpp);
+void nvpair_free_structure(nvpair_t *nvp);
+void nvpair_init_datasize(nvpair_t *nvp);
+const char *nvpair_type_string(int type);
+
+/* Pack functions. */
+unsigned char *nvpair_pack_header(const nvpair_t *nvp, unsigned char *ptr,
+ size_t *leftp);
+unsigned char *nvpair_pack_null(const nvpair_t *nvp, unsigned char *ptr,
+ size_t *leftp);
+unsigned char *nvpair_pack_bool(const nvpair_t *nvp, unsigned char *ptr,
+ size_t *leftp);
+unsigned char *nvpair_pack_number(const nvpair_t *nvp, unsigned char *ptr,
+ size_t *leftp);
+unsigned char *nvpair_pack_string(const nvpair_t *nvp, unsigned char *ptr,
+ size_t *leftp);
+unsigned char *nvpair_pack_descriptor(const nvpair_t *nvp, unsigned char *ptr,
+ int64_t *fdidxp, size_t *leftp);
+unsigned char *nvpair_pack_binary(const nvpair_t *nvp, unsigned char *ptr,
+ size_t *leftp);
+unsigned char *nvpair_pack_nvlist_up(unsigned char *ptr, size_t *leftp);
+unsigned char *nvpair_pack_bool_array(const nvpair_t *nvp, unsigned char *ptr,
+ size_t *leftp);
+unsigned char *nvpair_pack_number_array(const nvpair_t *nvp, unsigned char *ptr,
+ size_t *leftp);
+unsigned char *nvpair_pack_string_array(const nvpair_t *nvp, unsigned char *ptr,
+ size_t *leftp);
+unsigned char *nvpair_pack_descriptor_array(const nvpair_t *nvp,
+ unsigned char *ptr, int64_t *fdidxp, size_t *leftp);
+unsigned char *nvpair_pack_nvlist_array_next(unsigned char *ptr, size_t *leftp);
+
+/* Unpack data functions. */
+const unsigned char *nvpair_unpack_header(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp);
+const unsigned char *nvpair_unpack_null(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp);
+const unsigned char *nvpair_unpack_bool(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp);
+const unsigned char *nvpair_unpack_number(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp);
+const unsigned char *nvpair_unpack_string(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp);
+const unsigned char *nvpair_unpack_nvlist(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp, size_t nfds, nvlist_t **child);
+const unsigned char *nvpair_unpack_descriptor(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp, const int *fds, size_t nfds);
+const unsigned char *nvpair_unpack_binary(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp);
+const unsigned char *nvpair_unpack_bool_array(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp);
+const unsigned char *nvpair_unpack_number_array(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp);
+const unsigned char *nvpair_unpack_string_array(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp);
+const unsigned char *nvpair_unpack_descriptor_array(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp, const int *fds, size_t nfds);
+const unsigned char *nvpair_unpack_nvlist_array(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp, nvlist_t **firstel);
+
+#endif /* !_NVPAIR_IMPL_H_ */
Index: sys/dev/acpica/acpi_pci.c
===================================================================
--- sys/dev/acpica/acpi_pci.c
+++ sys/dev/acpica/acpi_pci.c
@@ -84,6 +84,11 @@
static void acpi_pci_update_device(ACPI_HANDLE handle, device_t pci_child);
static bus_dma_tag_t acpi_pci_get_dma_tag(device_t bus, device_t child);
+#ifdef PCI_IOV
+static device_t acpi_pci_create_iov_child(device_t bus, device_t pf,
+ uint16_t rid, uint16_t vid, uint16_t did);
+#endif
+
static device_method_t acpi_pci_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, acpi_pci_probe),
@@ -98,6 +103,9 @@
/* PCI interface */
DEVMETHOD(pci_set_powerstate, acpi_pci_set_powerstate_method),
+#ifdef PCI_IOV
+ DEVMETHOD(pci_create_iov_child, acpi_pci_create_iov_child),
+#endif
DEVMETHOD_END
};
@@ -345,3 +353,23 @@
return (pci_get_dma_tag(bus, child));
}
#endif
+
+#ifdef PCI_IOV
+static device_t
+acpi_pci_create_iov_child(device_t bus, device_t pf, uint16_t rid, uint16_t vid,
+ uint16_t did)
+{
+ struct acpi_pci_devinfo *dinfo;
+ device_t vf;
+
+ vf = pci_add_iov_child(bus, pf, sizeof(struct acpi_pci_devinfo), rid,
+ vid, did);
+ if (vf == NULL)
+ return (NULL);
+
+ dinfo = device_get_ivars(vf);
+ dinfo->ap_handle = NULL;
+ return (vf);
+}
+#endif
+
Index: sys/dev/ixl/if_ixl.c
===================================================================
--- sys/dev/ixl/if_ixl.c
+++ sys/dev/ixl/if_ixl.c
@@ -207,8 +207,8 @@
#ifdef PCI_IOV
static int ixl_adminq_err_to_errno(enum i40e_admin_queue_err err);
-static int ixl_init_iov(device_t dev, uint16_t num_vfs, const nvlist_t*);
-static void ixl_uninit_iov(device_t dev);
+static int ixl_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t*);
+static void ixl_iov_uninit(device_t dev);
static int ixl_add_vf(device_t dev, uint16_t vfnum, const nvlist_t*);
static void ixl_handle_vf_msg(struct ixl_pf *,
@@ -230,9 +230,9 @@
DEVMETHOD(device_detach, ixl_detach),
DEVMETHOD(device_shutdown, ixl_shutdown),
#ifdef PCI_IOV
- DEVMETHOD(pci_init_iov, ixl_init_iov),
- DEVMETHOD(pci_uninit_iov, ixl_uninit_iov),
- DEVMETHOD(pci_add_vf, ixl_add_vf),
+ DEVMETHOD(pci_iov_init, ixl_iov_init),
+ DEVMETHOD(pci_iov_uninit, ixl_iov_uninit),
+ DEVMETHOD(pci_iov_add_vf, ixl_add_vf),
#endif
{0, 0}
};
@@ -6546,7 +6546,7 @@
}
static int
-ixl_init_iov(device_t dev, uint16_t num_vfs, const nvlist_t *params)
+ixl_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *params)
{
struct ixl_pf *pf;
struct i40e_hw *hw;
@@ -6594,7 +6594,7 @@
}
static void
-ixl_uninit_iov(device_t dev)
+ixl_iov_uninit(device_t dev)
{
struct ixl_pf *pf;
struct i40e_hw *hw;
@@ -6619,7 +6619,11 @@
pf->veb_seid = 0;
}
+#if __FreeBSD_version > 1100022
if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0)
+#else
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+#endif
ixl_disable_intr(vsi);
vfs = pf->vfs;
Index: sys/dev/ixl/ixl.h
===================================================================
--- sys/dev/ixl/ixl.h
+++ sys/dev/ixl/ixl.h
@@ -93,6 +93,7 @@
#ifdef PCI_IOV
#include <sys/nv.h>
#include <sys/iov_schema.h>
+#include <dev/pci/pci_iov.h>
#endif
#include "i40e_type.h"
Index: sys/dev/pci/pci.c
===================================================================
--- sys/dev/pci/pci.c
+++ sys/dev/pci/pci.c
@@ -77,7 +77,6 @@
static int pci_has_quirk(uint32_t devid, int quirk);
static pci_addr_t pci_mapbase(uint64_t mapreg);
static const char *pci_maptype(uint64_t mapreg);
-static int pci_mapsize(uint64_t testval);
static int pci_maprange(uint64_t mapreg);
static pci_addr_t pci_rombase(uint64_t mapreg);
static int pci_romsize(uint64_t testval);
@@ -121,6 +120,9 @@
static uint16_t pci_get_rid_method(device_t dev, device_t child);
+static struct pci_devinfo * pci_fill_devinfo(device_t pcib, int d, int b, int s,
+ int f, uint16_t vid, uint16_t did, size_t size);
+
static device_method_t pci_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, pci_probe),
@@ -184,6 +186,11 @@
DEVMETHOD(pci_msix_count, pci_msix_count_method),
DEVMETHOD(pci_get_rid, pci_get_rid_method),
DEVMETHOD(pci_child_added, pci_child_added_method),
+#ifdef PCI_IOV
+ DEVMETHOD(pci_iov_attach, pci_iov_attach_method),
+ DEVMETHOD(pci_iov_detach, pci_iov_detach_method),
+ DEVMETHOD(pci_create_iov_child, pci_create_iov_child_method),
+#endif
DEVMETHOD_END
};
@@ -492,7 +499,7 @@
/* return log2 of map size decoded for memory or port map */
-static int
+int
pci_mapsize(uint64_t testval)
{
int ln2size;
@@ -605,71 +612,85 @@
pci_read_device(device_t pcib, int d, int b, int s, int f, size_t size)
{
#define REG(n, w) PCIB_READ_CONFIG(pcib, b, s, f, n, w)
- pcicfgregs *cfg = NULL;
+ uint16_t vid, did;
+
+ vid = REG(PCIR_VENDOR, 2);
+ did = REG(PCIR_DEVICE, 2);
+ if (vid != 0xffff)
+ return (pci_fill_devinfo(pcib, d, b, s, f, vid, did, size));
+
+ return (NULL);
+}
+
+static struct pci_devinfo *
+pci_fill_devinfo(device_t pcib, int d, int b, int s, int f, uint16_t vid,
+ uint16_t did, size_t size)
+{
struct pci_devinfo *devlist_entry;
- struct devlist *devlist_head;
+ pcicfgregs *cfg;
- devlist_head = &pci_devq;
+ devlist_entry = malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
- devlist_entry = NULL;
+ cfg = &devlist_entry->cfg;
- if (REG(PCIR_DEVVENDOR, 4) != 0xfffffffful) {
- devlist_entry = malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
+ cfg->domain = d;
+ cfg->bus = b;
+ cfg->slot = s;
+ cfg->func = f;
+ cfg->vendor = vid;
+ cfg->device = did;
+ cfg->cmdreg = REG(PCIR_COMMAND, 2);
+ cfg->statreg = REG(PCIR_STATUS, 2);
+ cfg->baseclass = REG(PCIR_CLASS, 1);
+ cfg->subclass = REG(PCIR_SUBCLASS, 1);
+ cfg->progif = REG(PCIR_PROGIF, 1);
+ cfg->revid = REG(PCIR_REVID, 1);
+ cfg->hdrtype = REG(PCIR_HDRTYPE, 1);
+ cfg->cachelnsz = REG(PCIR_CACHELNSZ, 1);
+ cfg->lattimer = REG(PCIR_LATTIMER, 1);
+ cfg->intpin = REG(PCIR_INTPIN, 1);
+ cfg->intline = REG(PCIR_INTLINE, 1);
- cfg = &devlist_entry->cfg;
+ cfg->mingnt = REG(PCIR_MINGNT, 1);
+ cfg->maxlat = REG(PCIR_MAXLAT, 1);
- cfg->domain = d;
- cfg->bus = b;
- cfg->slot = s;
- cfg->func = f;
- cfg->vendor = REG(PCIR_VENDOR, 2);
- cfg->device = REG(PCIR_DEVICE, 2);
- cfg->cmdreg = REG(PCIR_COMMAND, 2);
- cfg->statreg = REG(PCIR_STATUS, 2);
- cfg->baseclass = REG(PCIR_CLASS, 1);
- cfg->subclass = REG(PCIR_SUBCLASS, 1);
- cfg->progif = REG(PCIR_PROGIF, 1);
- cfg->revid = REG(PCIR_REVID, 1);
- cfg->hdrtype = REG(PCIR_HDRTYPE, 1);
- cfg->cachelnsz = REG(PCIR_CACHELNSZ, 1);
- cfg->lattimer = REG(PCIR_LATTIMER, 1);
- cfg->intpin = REG(PCIR_INTPIN, 1);
- cfg->intline = REG(PCIR_INTLINE, 1);
+ cfg->mfdev = (cfg->hdrtype & PCIM_MFDEV) != 0;
+ cfg->hdrtype &= ~PCIM_MFDEV;
+ STAILQ_INIT(&cfg->maps);
- cfg->mfdev = (cfg->hdrtype & PCIM_MFDEV) != 0;
- cfg->hdrtype &= ~PCIM_MFDEV;
- STAILQ_INIT(&cfg->maps);
+ cfg->devinfo_size = size;
+ cfg->iov = NULL;
- pci_fixancient(cfg);
- pci_hdrtypedata(pcib, b, s, f, cfg);
+ pci_fixancient(cfg);
+ pci_hdrtypedata(pcib, b, s, f, cfg);
- if (REG(PCIR_STATUS, 2) & PCIM_STATUS_CAPPRESENT)
- pci_read_cap(pcib, cfg);
+ if (REG(PCIR_STATUS, 2) & PCIM_STATUS_CAPPRESENT)
+ pci_read_cap(pcib, cfg);
- STAILQ_INSERT_TAIL(devlist_head, devlist_entry, pci_links);
+ STAILQ_INSERT_TAIL(&pci_devq, devlist_entry, pci_links);
- devlist_entry->conf.pc_sel.pc_domain = cfg->domain;
- devlist_entry->conf.pc_sel.pc_bus = cfg->bus;
- devlist_entry->conf.pc_sel.pc_dev = cfg->slot;
- devlist_entry->conf.pc_sel.pc_func = cfg->func;
- devlist_entry->conf.pc_hdr = cfg->hdrtype;
+ devlist_entry->conf.pc_sel.pc_domain = cfg->domain;
+ devlist_entry->conf.pc_sel.pc_bus = cfg->bus;
+ devlist_entry->conf.pc_sel.pc_dev = cfg->slot;
+ devlist_entry->conf.pc_sel.pc_func = cfg->func;
+ devlist_entry->conf.pc_hdr = cfg->hdrtype;
- devlist_entry->conf.pc_subvendor = cfg->subvendor;
- devlist_entry->conf.pc_subdevice = cfg->subdevice;
- devlist_entry->conf.pc_vendor = cfg->vendor;
- devlist_entry->conf.pc_device = cfg->device;
+ devlist_entry->conf.pc_subvendor = cfg->subvendor;
+ devlist_entry->conf.pc_subdevice = cfg->subdevice;
+ devlist_entry->conf.pc_vendor = cfg->vendor;
+ devlist_entry->conf.pc_device = cfg->device;
- devlist_entry->conf.pc_class = cfg->baseclass;
- devlist_entry->conf.pc_subclass = cfg->subclass;
- devlist_entry->conf.pc_progif = cfg->progif;
- devlist_entry->conf.pc_revid = cfg->revid;
+ devlist_entry->conf.pc_class = cfg->baseclass;
+ devlist_entry->conf.pc_subclass = cfg->subclass;
+ devlist_entry->conf.pc_progif = cfg->progif;
+ devlist_entry->conf.pc_revid = cfg->revid;
- pci_numdevs++;
- pci_generation++;
- }
+ pci_numdevs++;
+ pci_generation++;
+
return (devlist_entry);
+}
#undef REG
-}
static void
pci_read_cap(device_t pcib, pcicfgregs *cfg)
@@ -2672,8 +2693,9 @@
return (pci_read_config(dev, PCIR_COMMAND, 2) & PCIM_CMD_MEMEN) != 0;
}
-static void
-pci_read_bar(device_t dev, int reg, pci_addr_t *mapp, pci_addr_t *testvalp)
+void
+pci_read_bar(device_t dev, int reg, pci_addr_t *mapp, pci_addr_t *testvalp,
+ int *bar64)
{
struct pci_devinfo *dinfo;
pci_addr_t map, testval;
@@ -2693,6 +2715,8 @@
pci_write_config(dev, reg, map, 4);
*mapp = map;
*testvalp = testval;
+ if (bar64 != NULL)
+ *bar64 = 0;
return;
}
@@ -2734,6 +2758,8 @@
*mapp = map;
*testvalp = testval;
+ if (bar64 != NULL)
+ *bar64 = (ln2range == 64);
}
static void
@@ -2788,7 +2814,7 @@
return ((cmd & PCIM_CMD_PORTEN) != 0);
}
-static struct pci_map *
+struct pci_map *
pci_add_bar(device_t dev, int reg, pci_addr_t value, pci_addr_t size)
{
struct pci_devinfo *dinfo;
@@ -2859,7 +2885,7 @@
return (barlen);
}
- pci_read_bar(dev, reg, &map, &testval);
+ pci_read_bar(dev, reg, &map, &testval, NULL);
if (PCI_BAR_MEM(map)) {
type = SYS_RES_MEMORY;
if (map & PCIM_BAR_MEM_PREFETCH)
@@ -3593,6 +3619,51 @@
#undef REG
}
+#ifdef PCI_IOV
+device_t
+pci_add_iov_child(device_t bus, device_t pf, size_t size, uint16_t rid,
+ uint16_t vid, uint16_t did)
+{
+ struct pci_devinfo *pf_dinfo, *vf_dinfo;
+ device_t pcib;
+ int busno, slot, func;
+
+ pf_dinfo = device_get_ivars(pf);
+
+ /*
+ * Do a sanity check that we have been passed the correct size. If this
+ * test fails then likely the pci subclass hasn't implemented the
+ * pci_create_iov_child method like it's supposed it.
+ */
+ if (size != pf_dinfo->cfg.devinfo_size) {
+ device_printf(pf,
+ "PCI subclass does not properly implement PCI_IOV\n");
+ return (NULL);
+ }
+
+ pcib = device_get_parent(bus);
+
+ PCIB_DECODE_RID(pcib, rid, &busno, &slot, &func);
+
+ vf_dinfo = pci_fill_devinfo(pcib, pci_get_domain(pcib), busno, slot, func,
+ vid, did, size);
+
+ vf_dinfo->cfg.flags |= PCICFG_VF;
+ pci_add_child(bus, vf_dinfo);
+
+ return (vf_dinfo->cfg.dev);
+}
+
+device_t
+pci_create_iov_child_method(device_t bus, device_t pf, uint16_t rid,
+ uint16_t vid, uint16_t did)
+{
+
+ return (pci_add_iov_child(bus, pf, sizeof(struct pci_devinfo), rid, vid,
+ did));
+}
+#endif
+
void
pci_add_child(device_t bus, struct pci_devinfo *dinfo)
{
@@ -4529,7 +4600,7 @@
static struct resource *
pci_reserve_map(device_t dev, device_t child, int type, int *rid,
- u_long start, u_long end, u_long count, u_int flags)
+ u_long start, u_long end, u_long count, u_int num, u_int flags)
{
struct pci_devinfo *dinfo = device_get_ivars(child);
struct resource_list *rl = &dinfo->resources;
@@ -4553,7 +4624,7 @@
* have a atapci device in legacy mode and it fails
* here, that other code is broken.
*/
- pci_read_bar(child, *rid, &map, &testval);
+ pci_read_bar(child, *rid, &map, &testval, NULL);
/*
* Determine the size of the BAR and ignore BARs with a size
@@ -4595,7 +4666,7 @@
* situation where we might allocate the excess to
* another driver, which won't work.
*/
- count = (pci_addr_t)1 << mapsize;
+ count = ((pci_addr_t)1 << mapsize) * num;
if (RF_ALIGNMENT(flags) < mapsize)
flags = (flags & ~RF_ALIGNMENT_MASK) | RF_ALIGNMENT_LOG2(mapsize);
if (PCI_BAR_MEM(map) && (map & PCIM_BAR_MEM_PREFETCH))
@@ -4626,8 +4697,8 @@
}
struct resource *
-pci_alloc_resource(device_t dev, device_t child, int type, int *rid,
- u_long start, u_long end, u_long count, u_int flags)
+pci_alloc_multi_resource(device_t dev, device_t child, int type, int *rid,
+ u_long start, u_long end, u_long count, u_long num, u_int flags)
{
struct pci_devinfo *dinfo;
struct resource_list *rl;
@@ -4635,10 +4706,6 @@
struct resource *res;
pcicfgregs *cfg;
- if (device_get_parent(child) != dev)
- return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
- type, rid, start, end, count, flags));
-
/*
* Perform lazy resource allocation
*/
@@ -4695,7 +4762,7 @@
rle = resource_list_find(rl, type, *rid);
if (rle == NULL) {
res = pci_reserve_map(dev, child, type, rid, start, end,
- count, flags);
+ count, num, flags);
if (res == NULL)
return (NULL);
}
@@ -4704,6 +4771,38 @@
start, end, count, flags));
}
+struct resource *
+pci_alloc_resource(device_t dev, device_t child, int type, int *rid,
+ u_long start, u_long end, u_long count, u_int flags)
+{
+#ifdef PCI_IOV
+ struct pci_devinfo *dinfo;
+#endif
+
+ if (device_get_parent(child) != dev)
+ return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
+ type, rid, start, end, count, flags));
+
+#ifdef PCI_IOV
+ dinfo = device_get_ivars(child);
+ if (dinfo->cfg.flags & PCICFG_VF) {
+ switch (type) {
+ /* VFs can't have I/O BARs. */
+ case SYS_RES_IOPORT:
+ return (NULL);
+ case SYS_RES_MEMORY:
+ return (pci_vf_alloc_mem_resource(dev, child, rid,
+ start, end, count, flags));
+ }
+
+ /* Fall through for other types of resource allocations. */
+ }
+#endif
+
+ return (pci_alloc_multi_resource(dev, child, type, rid, start, end,
+ count, 1, flags));
+}
+
int
pci_release_resource(device_t dev, device_t child, int type, int rid,
struct resource *r)
@@ -4718,6 +4817,22 @@
dinfo = device_get_ivars(child);
cfg = &dinfo->cfg;
+
+#ifdef PCI_IOV
+ if (dinfo->cfg.flags & PCICFG_VF) {
+ switch (type) {
+ /* VFs can't have I/O BARs. */
+ case SYS_RES_IOPORT:
+ return (EDOOFUS);
+ case SYS_RES_MEMORY:
+ return (pci_vf_release_mem_resource(dev, child, rid,
+ r));
+ }
+
+ /* Fall through for other types of resource allocations. */
+ }
+#endif
+
#ifdef NEW_PCIB
/*
* PCI-PCI bridge I/O window resources are not BARs. For
@@ -4880,6 +4995,37 @@
struct pci_devinfo *dinfo = device_get_ivars(child);
pcicfgregs *cfg = &dinfo->cfg;
+#ifdef PCI_IOV
+ /*
+ * SR-IOV VFs don't implement the VID or DID registers, so we have to
+ * emulate them here.
+ */
+ if (cfg->flags & PCICFG_VF) {
+ if (reg == PCIR_VENDOR) {
+ switch (width) {
+ case 4:
+ return (cfg->device << 16 | cfg->vendor);
+ case 2:
+ return (cfg->vendor);
+ case 1:
+ return (cfg->vendor & 0xff);
+ default:
+ return (0xffffffff);
+ }
+ } else if (reg == PCIR_DEVICE) {
+ switch (width) {
+ /* Note that an unaligned 4-byte read is an error. */
+ case 2:
+ return (cfg->device);
+ case 1:
+ return (cfg->device & 0xff);
+ default:
+ return (0xffffffff);
+ }
+ }
+ }
+#endif
+
return (PCIB_READ_CONFIG(device_get_parent(dev),
cfg->bus, cfg->slot, cfg->func, reg, width));
}
Index: sys/dev/pci/pci_if.m
===================================================================
--- sys/dev/pci/pci_if.m
+++ sys/dev/pci/pci_if.m
@@ -36,9 +36,21 @@
{
return (0);
}
+
+ static device_t
+ null_create_iov_child(device_t bus, device_t pf, uint16_t rid,
+ uint16_t vid, uint16_t did)
+ {
+ device_printf(bus, "PCI_IOV not implemented on this bus.\n");
+ return (NULL);
+ }
};
+HEADER {
+ struct nvlist;
+}
+
METHOD u_int32_t read_config {
device_t dev;
device_t child;
@@ -189,3 +201,23 @@
device_t dev;
device_t child;
};
+
+METHOD int iov_attach {
+ device_t dev;
+ device_t child;
+ struct nvlist *pf_schema;
+ struct nvlist *vf_schema;
+};
+
+METHOD int iov_detach {
+ device_t dev;
+ device_t child;
+};
+
+METHOD device_t create_iov_child {
+ device_t bus;
+ device_t pf;
+ uint16_t rid;
+ uint16_t vid;
+ uint16_t did;
+} DEFAULT null_create_iov_child;
Index: sys/dev/pci/pci_iov.h
===================================================================
--- sys/dev/pci/pci_iov.h
+++ sys/dev/pci/pci_iov.h
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2013-2015 Sandvine Inc.
+ * 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 _PCI_IOV_H_
+#define _PCI_IOV_H_
+
+#include "pci_iov_if.h"
+
+struct nvlist;
+
+static __inline int
+pci_iov_attach(device_t dev, struct nvlist *pf_schema, struct nvlist *vf_schema)
+{
+ return (PCI_IOV_ATTACH(device_get_parent(dev), dev, pf_schema,
+ vf_schema));
+}
+
+static __inline int
+pci_iov_detach(device_t dev)
+{
+ return (PCI_IOV_DETACH(device_get_parent(dev), dev));
+}
+
+#endif /* !_PCI_IOV_H_ */
Index: sys/dev/pci/pci_iov.c
===================================================================
--- sys/dev/pci/pci_iov.c
+++ sys/dev/pci/pci_iov.c
@@ -0,0 +1,980 @@
+/*-
+ * 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 "opt_bus.h"
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/fcntl.h>
+#include <sys/ioccom.h>
+#include <sys/iov.h>
+#include <sys/linker.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/pciio.h>
+#include <sys/queue.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+
+#include <machine/bus.h>
+#include <machine/stdarg.h>
+
+#include <sys/nv.h>
+#include <sys/iov_schema.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pci_iov.h>
+#include <dev/pci/pci_private.h>
+#include <dev/pci/pci_iov_private.h>
+#include <dev/pci/schema_private.h>
+
+#include "pcib_if.h"
+
+static MALLOC_DEFINE(M_SRIOV, "sr_iov", "PCI SR-IOV allocations");
+
+static d_ioctl_t pci_iov_ioctl;
+
+static struct cdevsw iov_cdevsw = {
+ .d_version = D_VERSION,
+ .d_name = "iov",
+ .d_ioctl = pci_iov_ioctl
+};
+
+SYSCTL_DECL(_hw_pci);
+
+/*
+ * The maximum amount of memory we will allocate for user configuration of an
+ * SR-IOV device. 1MB ought to be enough for anyone, but leave this
+ * configurable just in case.
+ */
+static u_long pci_iov_max_config = 1024 * 1024;
+SYSCTL_ULONG(_hw_pci, OID_AUTO, iov_max_config, CTLFLAG_RWTUN,
+ &pci_iov_max_config, 0, "Maximum allowed size of SR-IOV configuration.");
+
+
+#define IOV_READ(d, r, w) \
+ pci_read_config((d)->cfg.dev, (d)->cfg.iov->iov_pos + r, w)
+
+#define IOV_WRITE(d, r, v, w) \
+ pci_write_config((d)->cfg.dev, (d)->cfg.iov->iov_pos + r, v, w)
+
+static nvlist_t *pci_iov_build_schema(nvlist_t **pf_schema,
+ nvlist_t **vf_schema);
+static void pci_iov_build_pf_schema(nvlist_t *schema,
+ nvlist_t **driver_schema);
+static void pci_iov_build_vf_schema(nvlist_t *schema,
+ nvlist_t **driver_schema);
+static nvlist_t *pci_iov_get_pf_subsystem_schema(void);
+static nvlist_t *pci_iov_get_vf_subsystem_schema(void);
+
+int
+pci_iov_attach_method(device_t bus, device_t dev, nvlist_t *pf_schema,
+ nvlist_t *vf_schema)
+{
+ device_t pcib;
+ struct pci_devinfo *dinfo;
+ struct pcicfg_iov *iov;
+ nvlist_t *schema;
+ uint32_t version;
+ int error;
+ int iov_pos;
+
+ dinfo = device_get_ivars(dev);
+ pcib = device_get_parent(bus);
+ schema = NULL;
+
+ error = pci_find_extcap(dev, PCIZ_SRIOV, &iov_pos);
+
+ if (error != 0)
+ return (error);
+
+ version = pci_read_config(dev, iov_pos, 4);
+ if (PCI_EXTCAP_VER(version) != 1) {
+ if (bootverbose)
+ device_printf(dev,
+ "Unsupported version of SR-IOV (%d) detected\n",
+ PCI_EXTCAP_VER(version));
+
+ return (ENXIO);
+ }
+
+ iov = malloc(sizeof(*dinfo->cfg.iov), M_SRIOV, M_WAITOK | M_ZERO);
+
+ mtx_lock(&Giant);
+ if (dinfo->cfg.iov != NULL) {
+ error = EBUSY;
+ goto cleanup;
+ }
+ iov->iov_pos = iov_pos;
+
+ schema = pci_iov_build_schema(&pf_schema, &vf_schema);
+ if (schema == NULL) {
+ error = ENOMEM;
+ goto cleanup;
+ }
+
+ error = pci_iov_validate_schema(schema);
+ if (error != 0)
+ goto cleanup;
+ iov->iov_schema = schema;
+
+ iov->iov_cdev = make_dev(&iov_cdevsw, device_get_unit(dev),
+ UID_ROOT, GID_WHEEL, 0600, "iov/%s", device_get_nameunit(dev));
+
+ if (iov->iov_cdev == NULL) {
+ error = ENOMEM;
+ goto cleanup;
+ }
+
+ dinfo->cfg.iov = iov;
+ iov->iov_cdev->si_drv1 = dinfo;
+ mtx_unlock(&Giant);
+
+ return (0);
+
+cleanup:
+ nvlist_destroy(schema);
+ nvlist_destroy(pf_schema);
+ nvlist_destroy(vf_schema);
+ free(iov, M_SRIOV);
+ mtx_unlock(&Giant);
+ return (error);
+}
+
+int
+pci_iov_detach_method(device_t bus, device_t dev)
+{
+ struct pci_devinfo *dinfo;
+ struct pcicfg_iov *iov;
+
+ mtx_lock(&Giant);
+ dinfo = device_get_ivars(dev);
+ iov = dinfo->cfg.iov;
+
+ if (iov == NULL) {
+ mtx_unlock(&Giant);
+ return (0);
+ }
+
+ if (iov->iov_num_vfs != 0 || iov->iov_flags & IOV_BUSY) {
+ mtx_unlock(&Giant);
+ return (EBUSY);
+ }
+
+ dinfo->cfg.iov = NULL;
+
+ if (iov->iov_cdev) {
+ destroy_dev(iov->iov_cdev);
+ iov->iov_cdev = NULL;
+ }
+ nvlist_destroy(iov->iov_schema);
+
+ free(iov, M_SRIOV);
+ mtx_unlock(&Giant);
+
+ return (0);
+}
+
+static nvlist_t *
+pci_iov_build_schema(nvlist_t **pf, nvlist_t **vf)
+{
+ nvlist_t *schema, *pf_driver, *vf_driver;
+
+ /* We always take ownership of the schemas. */
+ pf_driver = *pf;
+ *pf = NULL;
+ vf_driver = *vf;
+ *vf = NULL;
+
+ schema = pci_iov_schema_alloc_node();
+ if (schema == NULL)
+ goto cleanup;
+
+ pci_iov_build_pf_schema(schema, &pf_driver);
+ pci_iov_build_vf_schema(schema, &vf_driver);
+
+ if (nvlist_error(schema) != 0)
+ goto cleanup;
+
+ return (schema);
+
+cleanup:
+ nvlist_destroy(schema);
+ nvlist_destroy(pf_driver);
+ nvlist_destroy(vf_driver);
+ return (NULL);
+}
+
+static void
+pci_iov_build_pf_schema(nvlist_t *schema, nvlist_t **driver_schema)
+{
+ nvlist_t *pf_schema, *iov_schema;
+
+ pf_schema = pci_iov_schema_alloc_node();
+ if (pf_schema == NULL) {
+ nvlist_set_error(schema, ENOMEM);
+ return;
+ }
+
+ iov_schema = pci_iov_get_pf_subsystem_schema();
+
+ /*
+ * Note that if either *driver_schema or iov_schema is NULL, then
+ * nvlist_move_nvlist will put the schema in the error state and
+ * SR-IOV will fail to initialize later, so we don't have to explicitly
+ * handle that case.
+ */
+ nvlist_move_nvlist(pf_schema, DRIVER_CONFIG_NAME, *driver_schema);
+ nvlist_move_nvlist(pf_schema, IOV_CONFIG_NAME, iov_schema);
+ nvlist_move_nvlist(schema, PF_CONFIG_NAME, pf_schema);
+ *driver_schema = NULL;
+}
+
+static void
+pci_iov_build_vf_schema(nvlist_t *schema, nvlist_t **driver_schema)
+{
+ nvlist_t *vf_schema, *iov_schema;
+
+ vf_schema = pci_iov_schema_alloc_node();
+ if (vf_schema == NULL) {
+ nvlist_set_error(schema, ENOMEM);
+ return;
+ }
+
+ iov_schema = pci_iov_get_vf_subsystem_schema();
+
+ /*
+ * Note that if either *driver_schema or iov_schema is NULL, then
+ * nvlist_move_nvlist will put the schema in the error state and
+ * SR-IOV will fail to initialize later, so we don't have to explicitly
+ * handle that case.
+ */
+ nvlist_move_nvlist(vf_schema, DRIVER_CONFIG_NAME, *driver_schema);
+ nvlist_move_nvlist(vf_schema, IOV_CONFIG_NAME, iov_schema);
+ nvlist_move_nvlist(schema, VF_SCHEMA_NAME, vf_schema);
+ *driver_schema = NULL;
+}
+
+static nvlist_t *
+pci_iov_get_pf_subsystem_schema(void)
+{
+ nvlist_t *pf;
+
+ pf = pci_iov_schema_alloc_node();
+ if (pf == NULL)
+ return (NULL);
+
+ pci_iov_schema_add_uint16(pf, "num_vfs", IOV_SCHEMA_REQUIRED, -1);
+ pci_iov_schema_add_string(pf, "device", IOV_SCHEMA_REQUIRED, NULL);
+
+ return (pf);
+}
+
+static nvlist_t *
+pci_iov_get_vf_subsystem_schema(void)
+{
+ nvlist_t *vf;
+
+ vf = pci_iov_schema_alloc_node();
+ if (vf == NULL)
+ return (NULL);
+
+ pci_iov_schema_add_bool(vf, "passthrough", IOV_SCHEMA_HASDEFAULT, 0);
+
+ return (vf);
+}
+
+static int
+pci_iov_alloc_bar(struct pci_devinfo *dinfo, int bar, pci_addr_t bar_shift)
+{
+ struct resource *res;
+ struct pcicfg_iov *iov;
+ device_t dev, bus;
+ u_long start, end;
+ pci_addr_t bar_size;
+ int rid;
+
+ iov = dinfo->cfg.iov;
+ dev = dinfo->cfg.dev;
+ bus = device_get_parent(dev);
+ rid = iov->iov_pos + PCIR_SRIOV_BAR(bar);
+ bar_size = 1 << bar_shift;
+
+ res = pci_alloc_multi_resource(bus, dev, SYS_RES_MEMORY, &rid, 0ul,
+ ~0ul, 1, iov->iov_num_vfs, RF_ACTIVE);
+
+ if (res == NULL)
+ return (ENXIO);
+
+ iov->iov_bar[bar].res = res;
+ iov->iov_bar[bar].bar_size = bar_size;
+ iov->iov_bar[bar].bar_shift = bar_shift;
+
+ start = rman_get_start(res);
+ end = rman_get_end(res);
+ return (rman_manage_region(&iov->rman, start, end));
+}
+
+static void
+pci_iov_add_bars(struct pcicfg_iov *iov, struct pci_devinfo *dinfo)
+{
+ struct pci_iov_bar *bar;
+ uint64_t bar_start;
+ int i;
+
+ for (i = 0; i <= PCIR_MAX_BAR_0; i++) {
+ bar = &iov->iov_bar[i];
+ if (bar->res != NULL) {
+ bar_start = rman_get_start(bar->res) +
+ dinfo->cfg.vf.index * bar->bar_size;
+
+ pci_add_bar(dinfo->cfg.dev, PCIR_BAR(i), bar_start,
+ bar->bar_shift);
+ }
+ }
+}
+
+static int
+pci_iov_parse_config(struct pcicfg_iov *iov, struct pci_iov_arg *arg,
+ nvlist_t **ret)
+{
+ void *packed_config;
+ nvlist_t *config;
+ int error;
+
+ config = NULL;
+ packed_config = NULL;
+
+ if (arg->len > pci_iov_max_config) {
+ error = EMSGSIZE;
+ goto out;
+ }
+
+ packed_config = malloc(arg->len, M_SRIOV, M_WAITOK);
+
+ error = copyin(arg->config, packed_config, arg->len);
+ if (error != 0)
+ goto out;
+
+ config = nvlist_unpack(packed_config, arg->len, NV_FLAG_IGNORE_CASE);
+ if (config == NULL) {
+ error = EINVAL;
+ goto out;
+ }
+
+ error = pci_iov_schema_validate_config(iov->iov_schema, config);
+ if (error != 0)
+ goto out;
+
+ error = nvlist_error(config);
+ if (error != 0)
+ goto out;
+
+ *ret = config;
+ config = NULL;
+
+out:
+ nvlist_destroy(config);
+ free(packed_config, M_SRIOV);
+ return (error);
+}
+
+/*
+ * Set the ARI_EN bit in the lowest-numbered PCI function with the SR-IOV
+ * capability. This bit is only writeable on the lowest-numbered PF but
+ * affects all PFs on the device.
+ */
+static int
+pci_iov_set_ari(device_t bus)
+{
+ device_t lowest;
+ device_t *devlist;
+ int i, error, devcount, lowest_func, lowest_pos, iov_pos, dev_func;
+ uint16_t iov_ctl;
+
+ /* If ARI is disabled on the downstream port there is nothing to do. */
+ if (!PCIB_ARI_ENABLED(device_get_parent(bus)))
+ return (0);
+
+ error = device_get_children(bus, &devlist, &devcount);
+
+ if (error != 0)
+ return (error);
+
+ lowest = NULL;
+ for (i = 0; i < devcount; i++) {
+ if (pci_find_extcap(devlist[i], PCIZ_SRIOV, &iov_pos) == 0) {
+ dev_func = pci_get_function(devlist[i]);
+ if (lowest == NULL || dev_func < lowest_func) {
+ lowest = devlist[i];
+ lowest_func = dev_func;
+ lowest_pos = iov_pos;
+ }
+ }
+ }
+
+ /*
+ * If we called this function some device must have the SR-IOV
+ * capability.
+ */
+ KASSERT(lowest != NULL,
+ ("Could not find child of %s with SR-IOV capability",
+ device_get_nameunit(bus)));
+
+ iov_ctl = pci_read_config(lowest, iov_pos + PCIR_SRIOV_CTL, 2);
+ iov_ctl |= PCIM_SRIOV_ARI_EN;
+ pci_write_config(lowest, iov_pos + PCIR_SRIOV_CTL, iov_ctl, 2);
+ free(devlist, M_TEMP);
+ return (0);
+}
+
+static int
+pci_iov_config_page_size(struct pci_devinfo *dinfo)
+{
+ uint32_t page_cap, page_size;
+
+ page_cap = IOV_READ(dinfo, PCIR_SRIOV_PAGE_CAP, 4);
+
+ /*
+ * If the system page size is less than the smallest SR-IOV page size
+ * then round up to the smallest SR-IOV page size.
+ */
+ if (PAGE_SHIFT < PCI_SRIOV_BASE_PAGE_SHIFT)
+ page_size = (1 << 0);
+ else
+ page_size = (1 << (PAGE_SHIFT - PCI_SRIOV_BASE_PAGE_SHIFT));
+
+ /* Check that the device supports the system page size. */
+ if (!(page_size & page_cap))
+ return (ENXIO);
+
+ IOV_WRITE(dinfo, PCIR_SRIOV_PAGE_SIZE, page_size, 4);
+ return (0);
+}
+
+static int
+pci_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *config)
+{
+ const nvlist_t *device, *driver_config;
+
+ device = nvlist_get_nvlist(config, PF_CONFIG_NAME);
+ driver_config = nvlist_get_nvlist(device, DRIVER_CONFIG_NAME);
+ return (PCI_IOV_INIT(dev, num_vfs, driver_config));
+}
+
+static int
+pci_iov_init_rman(device_t pf, struct pcicfg_iov *iov)
+{
+ int error;
+
+ iov->rman.rm_start = 0;
+ iov->rman.rm_end = ~0ul;
+ iov->rman.rm_type = RMAN_ARRAY;
+ snprintf(iov->rman_name, sizeof(iov->rman_name), "%s VF I/O memory",
+ device_get_nameunit(pf));
+ iov->rman.rm_descr = iov->rman_name;
+
+ error = rman_init(&iov->rman);
+ if (error != 0)
+ return (error);
+
+ iov->iov_flags |= IOV_RMAN_INITED;
+ return (0);
+}
+
+static int
+pci_iov_setup_bars(struct pci_devinfo *dinfo)
+{
+ device_t dev;
+ struct pcicfg_iov *iov;
+ pci_addr_t bar_value, testval;
+ int i, last_64, error;
+
+ iov = dinfo->cfg.iov;
+ dev = dinfo->cfg.dev;
+ last_64 = 0;
+
+ for (i = 0; i <= PCIR_MAX_BAR_0; i++) {
+ /*
+ * If a PCI BAR is a 64-bit wide BAR, then it spans two
+ * consecutive registers. Therefore if the last BAR that
+ * we looked at was a 64-bit BAR, we need to skip this
+ * register as it's the second half of the last BAR.
+ */
+ if (!last_64) {
+ pci_read_bar(dev,
+ iov->iov_pos + PCIR_SRIOV_BAR(i),
+ &bar_value, &testval, &last_64);
+
+ if (testval != 0) {
+ error = pci_iov_alloc_bar(dinfo, i,
+ pci_mapsize(testval));
+ if (error != 0)
+ return (error);
+ }
+ } else
+ last_64 = 0;
+ }
+
+ return (0);
+}
+
+static void
+pci_iov_enumerate_vfs(struct pci_devinfo *dinfo, const nvlist_t *config,
+ uint16_t first_rid, uint16_t rid_stride)
+{
+ char device_name[VF_MAX_NAME];
+ const nvlist_t *device, *driver_config, *iov_config;
+ device_t bus, dev, vf;
+ struct pcicfg_iov *iov;
+ struct pci_devinfo *vfinfo;
+ size_t size;
+ int i, error;
+ uint16_t vid, did, next_rid;
+
+ iov = dinfo->cfg.iov;
+ dev = dinfo->cfg.dev;
+ bus = device_get_parent(dev);
+ size = dinfo->cfg.devinfo_size;
+ next_rid = first_rid;
+ vid = pci_get_vendor(dev);
+ did = IOV_READ(dinfo, PCIR_SRIOV_VF_DID, 2);
+
+ for (i = 0; i < iov->iov_num_vfs; i++, next_rid += rid_stride) {
+ snprintf(device_name, sizeof(device_name), VF_PREFIX"%d", i);
+ device = nvlist_get_nvlist(config, device_name);
+ iov_config = nvlist_get_nvlist(device, IOV_CONFIG_NAME);
+ driver_config = nvlist_get_nvlist(device, DRIVER_CONFIG_NAME);
+
+ vf = PCI_CREATE_IOV_CHILD(bus, dev, next_rid, vid, did);
+ if (vf == NULL)
+ break;
+
+ /*
+ * If we are creating passthrough devices then force the ppt
+ * driver to attach to prevent a VF driver from claiming the
+ * VFs.
+ */
+ if (nvlist_get_bool(iov_config, "passthrough"))
+ device_set_devclass_fixed(vf, "ppt");
+
+ vfinfo = device_get_ivars(vf);
+
+ vfinfo->cfg.iov = iov;
+ vfinfo->cfg.vf.index = i;
+
+ pci_iov_add_bars(iov, vfinfo);
+
+ error = PCI_IOV_ADD_VF(dev, i, driver_config);
+ if (error != 0) {
+ device_printf(dev, "Failed to add VF %d\n", i);
+ pci_delete_child(bus, vf);
+ }
+ }
+
+ bus_generic_attach(bus);
+}
+
+static int
+pci_iov_config(struct cdev *cdev, struct pci_iov_arg *arg)
+{
+ device_t bus, dev;
+ struct pci_devinfo *dinfo;
+ struct pcicfg_iov *iov;
+ nvlist_t *config;
+ int i, error;
+ uint16_t rid_off, rid_stride;
+ uint16_t first_rid, last_rid;
+ uint16_t iov_ctl;
+ uint16_t num_vfs, total_vfs;
+ int iov_inited;
+
+ mtx_lock(&Giant);
+ dinfo = cdev->si_drv1;
+ iov = dinfo->cfg.iov;
+ dev = dinfo->cfg.dev;
+ bus = device_get_parent(dev);
+ iov_inited = 0;
+ config = NULL;
+
+ if ((iov->iov_flags & IOV_BUSY) || iov->iov_num_vfs != 0) {
+ mtx_unlock(&Giant);
+ return (EBUSY);
+ }
+ iov->iov_flags |= IOV_BUSY;
+
+ error = pci_iov_parse_config(iov, arg, &config);
+ if (error != 0)
+ goto out;
+
+ num_vfs = pci_iov_config_get_num_vfs(config);
+ total_vfs = IOV_READ(dinfo, PCIR_SRIOV_TOTAL_VFS, 2);
+ if (num_vfs > total_vfs) {
+ error = EINVAL;
+ goto out;
+ }
+
+ error = pci_iov_config_page_size(dinfo);
+ if (error != 0)
+ goto out;
+
+ error = pci_iov_set_ari(bus);
+ if (error != 0)
+ goto out;
+
+ error = pci_iov_init(dev, num_vfs, config);
+ if (error != 0)
+ goto out;
+ iov_inited = 1;
+
+ IOV_WRITE(dinfo, PCIR_SRIOV_NUM_VFS, num_vfs, 2);
+
+ rid_off = IOV_READ(dinfo, PCIR_SRIOV_VF_OFF, 2);
+ rid_stride = IOV_READ(dinfo, PCIR_SRIOV_VF_STRIDE, 2);
+
+ first_rid = pci_get_rid(dev) + rid_off;
+ last_rid = first_rid + (num_vfs - 1) * rid_stride;
+
+ /* We don't yet support allocating extra bus numbers for VFs. */
+ if (pci_get_bus(dev) != PCI_RID2BUS(last_rid)) {
+ error = ENOSPC;
+ goto out;
+ }
+
+ iov_ctl = IOV_READ(dinfo, PCIR_SRIOV_CTL, 2);
+ iov_ctl &= ~(PCIM_SRIOV_VF_EN | PCIM_SRIOV_VF_MSE);
+ IOV_WRITE(dinfo, PCIR_SRIOV_CTL, iov_ctl, 2);
+
+ error = pci_iov_init_rman(dev, iov);
+ if (error != 0)
+ goto out;
+
+ iov->iov_num_vfs = num_vfs;
+
+ error = pci_iov_setup_bars(dinfo);
+ if (error != 0)
+ goto out;
+
+ iov_ctl = IOV_READ(dinfo, PCIR_SRIOV_CTL, 2);
+ iov_ctl |= PCIM_SRIOV_VF_EN | PCIM_SRIOV_VF_MSE;
+ IOV_WRITE(dinfo, PCIR_SRIOV_CTL, iov_ctl, 2);
+
+ /* Per specification, we must wait 100ms before accessing VFs. */
+ pause("iov", roundup(hz, 10));
+ pci_iov_enumerate_vfs(dinfo, config, first_rid, rid_stride);
+
+ nvlist_destroy(config);
+ iov->iov_flags &= ~IOV_BUSY;
+ mtx_unlock(&Giant);
+
+ return (0);
+out:
+ if (iov_inited)
+ PCI_IOV_UNINIT(dev);
+
+ for (i = 0; i <= PCIR_MAX_BAR_0; i++) {
+ if (iov->iov_bar[i].res != NULL) {
+ pci_release_resource(bus, dev, SYS_RES_MEMORY,
+ iov->iov_pos + PCIR_SRIOV_BAR(i),
+ iov->iov_bar[i].res);
+ pci_delete_resource(bus, dev, SYS_RES_MEMORY,
+ iov->iov_pos + PCIR_SRIOV_BAR(i));
+ iov->iov_bar[i].res = NULL;
+ }
+ }
+
+ if (iov->iov_flags & IOV_RMAN_INITED) {
+ rman_fini(&iov->rman);
+ iov->iov_flags &= ~IOV_RMAN_INITED;
+ }
+
+ nvlist_destroy(config);
+ iov->iov_num_vfs = 0;
+ iov->iov_flags &= ~IOV_BUSY;
+ mtx_unlock(&Giant);
+ return (error);
+}
+
+/* Return true if child is a VF of the given PF. */
+static int
+pci_iov_is_child_vf(struct pcicfg_iov *pf, device_t child)
+{
+ struct pci_devinfo *vfinfo;
+
+ vfinfo = device_get_ivars(child);
+
+ if (!(vfinfo->cfg.flags & PCICFG_VF))
+ return (0);
+
+ return (pf == vfinfo->cfg.iov);
+}
+
+static int
+pci_iov_delete(struct cdev *cdev)
+{
+ device_t bus, dev, vf, *devlist;
+ struct pci_devinfo *dinfo;
+ struct pcicfg_iov *iov;
+ int i, error, devcount;
+ uint32_t iov_ctl;
+
+ mtx_lock(&Giant);
+ dinfo = cdev->si_drv1;
+ iov = dinfo->cfg.iov;
+ dev = dinfo->cfg.dev;
+ bus = device_get_parent(dev);
+ devlist = NULL;
+
+ if (iov->iov_flags & IOV_BUSY) {
+ mtx_unlock(&Giant);
+ return (EBUSY);
+ }
+
+ if (iov->iov_num_vfs == 0) {
+ mtx_unlock(&Giant);
+ return (ECHILD);
+ }
+
+ iov->iov_flags |= IOV_BUSY;
+
+ error = device_get_children(bus, &devlist, &devcount);
+
+ if (error != 0)
+ goto out;
+
+ for (i = 0; i < devcount; i++) {
+ vf = devlist[i];
+
+ if (!pci_iov_is_child_vf(iov, vf))
+ continue;
+
+ error = device_detach(vf);
+ if (error != 0) {
+ device_printf(dev,
+ "Could not disable SR-IOV: failed to detach VF %s\n",
+ device_get_nameunit(vf));
+ goto out;
+ }
+ }
+
+ for (i = 0; i < devcount; i++) {
+ vf = devlist[i];
+
+ if (pci_iov_is_child_vf(iov, vf))
+ pci_delete_child(bus, vf);
+ }
+ PCI_IOV_UNINIT(dev);
+
+ iov_ctl = IOV_READ(dinfo, PCIR_SRIOV_CTL, 2);
+ iov_ctl &= ~(PCIM_SRIOV_VF_EN | PCIM_SRIOV_VF_MSE);
+ IOV_WRITE(dinfo, PCIR_SRIOV_CTL, iov_ctl, 2);
+ IOV_WRITE(dinfo, PCIR_SRIOV_NUM_VFS, 0, 2);
+
+ iov->iov_num_vfs = 0;
+
+ for (i = 0; i <= PCIR_MAX_BAR_0; i++) {
+ if (iov->iov_bar[i].res != NULL) {
+ pci_release_resource(bus, dev, SYS_RES_MEMORY,
+ iov->iov_pos + PCIR_SRIOV_BAR(i),
+ iov->iov_bar[i].res);
+ pci_delete_resource(bus, dev, SYS_RES_MEMORY,
+ iov->iov_pos + PCIR_SRIOV_BAR(i));
+ iov->iov_bar[i].res = NULL;
+ }
+ }
+
+ if (iov->iov_flags & IOV_RMAN_INITED) {
+ rman_fini(&iov->rman);
+ iov->iov_flags &= ~IOV_RMAN_INITED;
+ }
+
+ error = 0;
+out:
+ free(devlist, M_TEMP);
+ iov->iov_flags &= ~IOV_BUSY;
+ mtx_unlock(&Giant);
+ return (error);
+}
+
+static int
+pci_iov_get_schema_ioctl(struct cdev *cdev, struct pci_iov_schema *output)
+{
+ struct pci_devinfo *dinfo;
+ void *packed;
+ size_t output_len, size;
+ int error;
+
+ packed = NULL;
+
+ mtx_lock(&Giant);
+ dinfo = cdev->si_drv1;
+ packed = nvlist_pack(dinfo->cfg.iov->iov_schema, &size);
+ mtx_unlock(&Giant);
+
+ if (packed == NULL) {
+ error = ENOMEM;
+ goto fail;
+ }
+
+ output_len = output->len;
+ output->len = size;
+ if (size <= output_len) {
+ error = copyout(packed, output->schema, size);
+
+ if (error != 0)
+ goto fail;
+
+ output->error = 0;
+ } else
+ /*
+ * If we return an error then the ioctl code won't copyout
+ * output back to userland, so we flag the error in the struct
+ * instead.
+ */
+ output->error = EMSGSIZE;
+
+ error = 0;
+
+fail:
+ free(packed, M_NVLIST);
+
+ return (error);
+}
+
+static int
+pci_iov_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
+ struct thread *td)
+{
+
+ switch (cmd) {
+ case IOV_CONFIG:
+ return (pci_iov_config(dev, (struct pci_iov_arg *)data));
+ case IOV_DELETE:
+ return (pci_iov_delete(dev));
+ case IOV_GET_SCHEMA:
+ return (pci_iov_get_schema_ioctl(dev,
+ (struct pci_iov_schema *)data));
+ default:
+ return (EINVAL);
+ }
+}
+
+struct resource *
+pci_vf_alloc_mem_resource(device_t dev, device_t child, int *rid, u_long start,
+ u_long end, u_long count, u_int flags)
+{
+ struct pci_devinfo *dinfo;
+ struct pcicfg_iov *iov;
+ struct pci_map *map;
+ struct resource *res;
+ struct resource_list_entry *rle;
+ u_long bar_start, bar_end;
+ pci_addr_t bar_length;
+ int error;
+
+ dinfo = device_get_ivars(child);
+ iov = dinfo->cfg.iov;
+
+ map = pci_find_bar(child, *rid);
+ if (map == NULL)
+ return (NULL);
+
+ bar_length = 1 << map->pm_size;
+ bar_start = map->pm_value;
+ bar_end = bar_start + bar_length - 1;
+
+ /* Make sure that the resource fits the constraints. */
+ if (bar_start >= end || bar_end <= bar_start || count != 1)
+ return (NULL);
+
+ /* Clamp the resource to the constraints if necessary. */
+ if (bar_start < start)
+ bar_start = start;
+ if (bar_end > end)
+ bar_end = end;
+ bar_length = bar_end - bar_start + 1;
+
+ res = rman_reserve_resource(&iov->rman, bar_start, bar_end,
+ bar_length, flags, child);
+ if (res == NULL)
+ return (NULL);
+
+ rle = resource_list_add(&dinfo->resources, SYS_RES_MEMORY, *rid,
+ bar_start, bar_end, 1);
+ if (rle == NULL) {
+ rman_release_resource(res);
+ return (NULL);
+ }
+
+ rman_set_rid(res, *rid);
+
+ if (flags & RF_ACTIVE) {
+ error = bus_activate_resource(child, SYS_RES_MEMORY, *rid, res);
+ if (error != 0) {
+ resource_list_delete(&dinfo->resources, SYS_RES_MEMORY,
+ *rid);
+ rman_release_resource(res);
+ return (NULL);
+ }
+ }
+ rle->res = res;
+
+ return (res);
+}
+
+int
+pci_vf_release_mem_resource(device_t dev, device_t child, int rid,
+ struct resource *r)
+{
+ struct pci_devinfo *dinfo;
+ struct resource_list_entry *rle;
+ int error;
+
+ dinfo = device_get_ivars(child);
+
+ if (rman_get_flags(r) & RF_ACTIVE) {
+ error = bus_deactivate_resource(child, SYS_RES_MEMORY, rid, r);
+ if (error != 0)
+ return (error);
+ }
+
+ rle = resource_list_find(&dinfo->resources, SYS_RES_MEMORY, rid);
+ if (rle != NULL) {
+ rle->res = NULL;
+ resource_list_delete(&dinfo->resources, SYS_RES_MEMORY,
+ rid);
+ }
+
+ return (rman_release_resource(r));
+}
+
Index: sys/dev/pci/pci_iov_if.m
===================================================================
--- sys/dev/pci/pci_iov_if.m
+++ sys/dev/pci/pci_iov_if.m
@@ -0,0 +1,52 @@
+#-
+# Copyright (c) 2013-2015 Sandvine Inc.
+# 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$
+#
+
+#include <sys/bus.h>
+
+INTERFACE pci_iov;
+
+HEADER {
+ struct nvlist;
+}
+
+
+METHOD int init {
+ device_t dev;
+ uint16_t num_vfs;
+ const struct nvlist *config;
+};
+
+METHOD void uninit {
+ device_t dev;
+};
+
+METHOD int add_vf {
+ device_t dev;
+ uint16_t vfnum;
+ const struct nvlist *config;
+};
Index: sys/dev/pci/pci_iov_private.h
===================================================================
--- sys/dev/pci/pci_iov_private.h
+++ sys/dev/pci/pci_iov_private.h
@@ -0,0 +1,56 @@
+/*-
+ * 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 _PCI_IOV_PRIVATE_H_
+#define _PCI_IOV_PRIVATE_H_
+
+struct pci_iov_bar {
+ struct resource *res;
+
+ pci_addr_t bar_size;
+ pci_addr_t bar_shift;
+};
+
+struct pcicfg_iov {
+ struct cdev *iov_cdev;
+ nvlist_t *iov_schema;
+
+ struct pci_iov_bar iov_bar[PCIR_MAX_BAR_0 + 1];
+ struct rman rman;
+ char rman_name[64];
+
+ int iov_pos;
+ int iov_num_vfs;
+ uint32_t iov_flags;
+};
+
+#define IOV_RMAN_INITED 0x0001
+#define IOV_BUSY 0x0002
+
+#endif
+
Index: sys/dev/pci/pci_iov_schema.c
===================================================================
--- sys/dev/pci/pci_iov_schema.c
+++ sys/dev/pci/pci_iov_schema.c
@@ -0,0 +1,869 @@
+/*-
+ * 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/conf.h>
+#include <sys/ctype.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/iov.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/queue.h>
+
+#include <machine/stdarg.h>
+
+#include <sys/dnv.h>
+#include <sys/nv.h>
+#include <sys/iov_schema.h>
+
+#include <net/ethernet.h>
+
+#include <dev/pci/schema_private.h>
+
+struct config_type_validator;
+typedef int (validate_func)(const struct config_type_validator *,
+ const nvlist_t *, const char *name);
+typedef int (default_validate_t)(const struct config_type_validator *,
+ const nvlist_t *);
+
+static validate_func pci_iov_schema_validate_bool;
+static validate_func pci_iov_schema_validate_string;
+static validate_func pci_iov_schema_validate_uint;
+static validate_func pci_iov_schema_validate_unicast_mac;
+
+static default_validate_t pci_iov_validate_bool_default;
+static default_validate_t pci_iov_validate_string_default;
+static default_validate_t pci_iov_validate_uint_default;
+static default_validate_t pci_iov_validate_unicast_mac_default;
+
+struct config_type_validator {
+ const char *type_name;
+ validate_func *validate;
+ default_validate_t *default_validate;
+ uintmax_t limit;
+};
+
+static struct config_type_validator pci_iov_schema_validators[] = {
+ {
+ .type_name = "bool",
+ .validate = pci_iov_schema_validate_bool,
+ .default_validate = pci_iov_validate_bool_default
+ },
+ {
+ .type_name = "string",
+ .validate = pci_iov_schema_validate_string,
+ .default_validate = pci_iov_validate_string_default
+ },
+ {
+ .type_name = "uint8_t",
+ .validate = pci_iov_schema_validate_uint,
+ .default_validate = pci_iov_validate_uint_default,
+ .limit = UINT8_MAX
+ },
+ {
+ .type_name = "uint16_t",
+ .validate = pci_iov_schema_validate_uint,
+ .default_validate = pci_iov_validate_uint_default,
+ .limit = UINT16_MAX
+ },
+ {
+ .type_name = "uint32_t",
+ .validate = pci_iov_schema_validate_uint,
+ .default_validate = pci_iov_validate_uint_default,
+ .limit = UINT32_MAX
+ },
+ {
+ .type_name = "uint64_t",
+ .validate = pci_iov_schema_validate_uint,
+ .default_validate = pci_iov_validate_uint_default,
+ .limit = UINT64_MAX
+ },
+ {
+ .type_name = "unicast-mac",
+ .validate = pci_iov_schema_validate_unicast_mac,
+ .default_validate = pci_iov_validate_unicast_mac_default,
+ },
+};
+
+static const struct config_type_validator *
+pci_iov_schema_find_validator(const char *type)
+{
+ struct config_type_validator *validator;
+ int i;
+
+ for (i = 0; i < nitems(pci_iov_schema_validators); i++) {
+ validator = &pci_iov_schema_validators[i];
+ if (strcmp(type, validator->type_name) == 0)
+ return (validator);
+ }
+
+ return (NULL);
+}
+
+static void
+pci_iov_schema_add_type(nvlist_t *entry, const char *type)
+{
+
+ if (pci_iov_schema_find_validator(type) == NULL) {
+ nvlist_set_error(entry, EINVAL);
+ return;
+ }
+ nvlist_add_string(entry, "type", type);
+}
+
+static void
+pci_iov_schema_add_required(nvlist_t *entry, uint32_t flags)
+{
+
+ if (flags & IOV_SCHEMA_REQUIRED) {
+ if (flags & IOV_SCHEMA_HASDEFAULT) {
+ nvlist_set_error(entry, EINVAL);
+ return;
+ }
+
+ nvlist_add_bool(entry, "required", 1);
+ }
+}
+
+void
+pci_iov_schema_add_bool(nvlist_t *schema, const char *name, uint32_t flags,
+ int defaultVal)
+{
+ nvlist_t *entry;
+
+ entry = nvlist_create(NV_FLAG_IGNORE_CASE);
+ if (entry == NULL) {
+ nvlist_set_error(schema, ENOMEM);
+ return;
+ }
+
+ pci_iov_schema_add_type(entry, "bool");
+ if (flags & IOV_SCHEMA_HASDEFAULT)
+ nvlist_add_bool(entry, "default", defaultVal);
+ pci_iov_schema_add_required(entry, flags);
+
+ nvlist_move_nvlist(schema, name, entry);
+}
+
+void
+pci_iov_schema_add_string(nvlist_t *schema, const char *name, uint32_t flags,
+ const char *defaultVal)
+{
+ nvlist_t *entry;
+
+ entry = nvlist_create(NV_FLAG_IGNORE_CASE);
+ if (entry == NULL) {
+ nvlist_set_error(schema, ENOMEM);
+ return;
+ }
+
+ pci_iov_schema_add_type(entry, "string");
+ if (flags & IOV_SCHEMA_HASDEFAULT)
+ nvlist_add_string(entry, "default", defaultVal);
+ pci_iov_schema_add_required(entry, flags);
+
+ nvlist_move_nvlist(schema, name, entry);
+}
+
+static void
+pci_iov_schema_int(nvlist_t *schema, const char *name, const char *type,
+ uint32_t flags, uint64_t defaultVal)
+{
+ nvlist_t *entry;
+
+ entry = nvlist_create(NV_FLAG_IGNORE_CASE);
+ if (entry == NULL) {
+ nvlist_set_error(schema, ENOMEM);
+ return;
+ }
+
+ pci_iov_schema_add_type(entry, type);
+ if (flags & IOV_SCHEMA_HASDEFAULT)
+ nvlist_add_number(entry, "default", defaultVal);
+ pci_iov_schema_add_required(entry, flags);
+
+ nvlist_move_nvlist(schema, name, entry);
+}
+
+void
+pci_iov_schema_add_uint8(nvlist_t *schema, const char *name, uint32_t flags,
+ uint8_t defaultVal)
+{
+
+ pci_iov_schema_int(schema, name, "uint8_t", flags, defaultVal);
+}
+
+void
+pci_iov_schema_add_uint16(nvlist_t *schema, const char *name, uint32_t flags,
+ uint16_t defaultVal)
+{
+
+ pci_iov_schema_int(schema, name, "uint16_t", flags, defaultVal);
+}
+
+void
+pci_iov_schema_add_uint32(nvlist_t *schema, const char *name, uint32_t flags,
+ uint32_t defaultVal)
+{
+
+ pci_iov_schema_int(schema, name, "uint32_t", flags, defaultVal);
+}
+
+void
+pci_iov_schema_add_uint64(nvlist_t *schema, const char *name, uint32_t flags,
+ uint64_t defaultVal)
+{
+
+ pci_iov_schema_int(schema, name, "uint64_t", flags, defaultVal);
+}
+
+void
+pci_iov_schema_add_unicast_mac(nvlist_t *schema, const char *name,
+ uint32_t flags, const uint8_t * defaultVal)
+{
+ nvlist_t *entry;
+
+ entry = nvlist_create(NV_FLAG_IGNORE_CASE);
+ if (entry == NULL) {
+ nvlist_set_error(schema, ENOMEM);
+ return;
+ }
+
+ pci_iov_schema_add_type(entry, "unicast-mac");
+ if (flags & IOV_SCHEMA_HASDEFAULT)
+ nvlist_add_binary(entry, "default", defaultVal, ETHER_ADDR_LEN);
+ pci_iov_schema_add_required(entry, flags);
+
+ nvlist_move_nvlist(schema, name, entry);
+}
+
+static int
+pci_iov_schema_validate_bool(const struct config_type_validator * validator,
+ const nvlist_t *config, const char *name)
+{
+
+ if (!nvlist_exists_bool(config, name))
+ return (EINVAL);
+ return (0);
+}
+
+static int
+pci_iov_schema_validate_string(const struct config_type_validator * validator,
+ const nvlist_t *config, const char *name)
+{
+
+ if (!nvlist_exists_string(config, name))
+ return (EINVAL);
+ return (0);
+}
+
+static int
+pci_iov_schema_validate_uint(const struct config_type_validator * validator,
+ const nvlist_t *config, const char *name)
+{
+ uint64_t value;
+
+ if (!nvlist_exists_number(config, name))
+ return (EINVAL);
+
+ value = nvlist_get_number(config, name);
+
+ if (value > validator->limit)
+ return (EINVAL);
+
+ return (0);
+}
+
+static int
+pci_iov_schema_validate_unicast_mac(
+ const struct config_type_validator * validator,
+ const nvlist_t *config, const char *name)
+{
+ const uint8_t *mac;
+ size_t size;
+
+ if (!nvlist_exists_binary(config, name))
+ return (EINVAL);
+
+ mac = nvlist_get_binary(config, name, &size);
+
+ if (size != ETHER_ADDR_LEN)
+ return (EINVAL);
+
+ if (ETHER_IS_MULTICAST(mac))
+ return (EINVAL);
+
+ return (0);
+}
+
+static void
+pci_iov_config_add_default(const nvlist_t *param_schema, const char *name,
+ nvlist_t *config)
+{
+ const void *binary;
+ size_t len;
+
+ if (nvlist_exists_binary(param_schema, "default")) {
+ binary = nvlist_get_binary(param_schema, "default", &len);
+ nvlist_add_binary(config, name, binary, len);
+ } else if (nvlist_exists_bool(param_schema, "default"))
+ nvlist_add_bool(config, name,
+ nvlist_get_bool(param_schema, "default"));
+ else if (nvlist_exists_number(param_schema, "default"))
+ nvlist_add_number(config, name,
+ nvlist_get_number(param_schema, "default"));
+ else if (nvlist_exists_nvlist(param_schema, "default"))
+ nvlist_add_nvlist(config, name,
+ nvlist_get_nvlist(param_schema, "default"));
+ else if (nvlist_exists_string(param_schema, "default"))
+ nvlist_add_string(config, name,
+ nvlist_get_string(param_schema, "default"));
+ else
+ panic("Unexpected nvlist type");
+}
+
+static int
+pci_iov_validate_bool_default(const struct config_type_validator * validator,
+ const nvlist_t *param)
+{
+
+ if (!nvlist_exists_bool(param, DEFAULT_SCHEMA_NAME))
+ return (EINVAL);
+ return (0);
+}
+
+static int
+pci_iov_validate_string_default(const struct config_type_validator * validator,
+ const nvlist_t *param)
+{
+
+ if (!nvlist_exists_string(param, DEFAULT_SCHEMA_NAME))
+ return (EINVAL);
+ return (0);
+}
+
+static int
+pci_iov_validate_uint_default(const struct config_type_validator * validator,
+ const nvlist_t *param)
+{
+ uint64_t defaultVal;
+
+ if (!nvlist_exists_number(param, DEFAULT_SCHEMA_NAME))
+ return (EINVAL);
+
+ defaultVal = nvlist_get_number(param, DEFAULT_SCHEMA_NAME);
+ if (defaultVal > validator->limit)
+ return (EINVAL);
+ return (0);
+}
+
+static int
+pci_iov_validate_unicast_mac_default(
+ const struct config_type_validator * validator, const nvlist_t *param)
+{
+ const uint8_t *mac;
+ size_t size;
+
+ if (!nvlist_exists_binary(param, DEFAULT_SCHEMA_NAME))
+ return (EINVAL);
+
+ mac = nvlist_get_binary(param, DEFAULT_SCHEMA_NAME, &size);
+ if (size != ETHER_ADDR_LEN)
+ return (EINVAL);
+
+ if (ETHER_IS_MULTICAST(mac))
+ return (EINVAL);
+ return (0);
+}
+
+static int
+pci_iov_validate_param_schema(const nvlist_t *schema)
+{
+ const struct config_type_validator *validator;
+ const char *type;
+ int error;
+
+ /* All parameters must define a type. */
+ if (!nvlist_exists_string(schema, TYPE_SCHEMA_NAME))
+ return (EINVAL);
+ type = nvlist_get_string(schema, TYPE_SCHEMA_NAME);
+
+ validator = pci_iov_schema_find_validator(type);
+ if (validator == NULL)
+ return (EINVAL);
+
+ /* Validate that the default value conforms to the type. */
+ if (nvlist_exists(schema, DEFAULT_SCHEMA_NAME)) {
+ error = validator->default_validate(validator, schema);
+ if (error != 0)
+ return (error);
+
+ /* Required and Default are mutually exclusive. */
+ if (nvlist_exists(schema, REQUIRED_SCHEMA_NAME))
+ return (EINVAL);
+ }
+
+ /* The "Required" field must be a bool. */
+ if (nvlist_exists(schema, REQUIRED_SCHEMA_NAME)) {
+ if (!nvlist_exists_bool(schema, REQUIRED_SCHEMA_NAME))
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+static int
+pci_iov_validate_subsystem_schema(const nvlist_t *dev_schema, const char *name)
+{
+ const nvlist_t *sub_schema, *param_schema;
+ const char *param_name;
+ void *it;
+ int type, error;
+
+ if (!nvlist_exists_nvlist(dev_schema, name))
+ return (EINVAL);
+ sub_schema = nvlist_get_nvlist(dev_schema, name);
+
+ it = NULL;
+ while ((param_name = nvlist_next(sub_schema, &type, &it)) != NULL) {
+ if (type != NV_TYPE_NVLIST)
+ return (EINVAL);
+ param_schema = nvlist_get_nvlist(sub_schema, param_name);
+
+ error = pci_iov_validate_param_schema(param_schema);
+ if (error != 0)
+ return (error);
+ }
+
+ return (0);
+}
+
+/*
+ * Validate that the driver schema does not define any configuration parameters
+ * whose names collide with configuration parameters defined in the iov schema.
+ */
+static int
+pci_iov_validate_param_collisions(const nvlist_t *dev_schema)
+{
+ const nvlist_t *iov_schema, *driver_schema;
+ const char *name;
+ void *it;
+ int type;
+
+ driver_schema = nvlist_get_nvlist(dev_schema, DRIVER_CONFIG_NAME);
+ iov_schema = nvlist_get_nvlist(dev_schema, IOV_CONFIG_NAME);
+
+ it = NULL;
+ while ((name = nvlist_next(driver_schema, &type, &it)) != NULL) {
+ if (nvlist_exists(iov_schema, name))
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+/*
+ * Validate that we only have IOV and DRIVER subsystems beneath the given
+ * device schema node.
+ */
+static int
+pci_iov_validate_schema_subsystems(const nvlist_t *dev_schema)
+{
+ const char *name;
+ void *it;
+ int type;
+
+ it = NULL;
+ while ((name = nvlist_next(dev_schema, &type, &it)) != NULL) {
+ if (strcmp(name, IOV_CONFIG_NAME) != 0 &&
+ strcmp(name, DRIVER_CONFIG_NAME) != 0)
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+static int
+pci_iov_validate_device_schema(const nvlist_t *schema, const char *name)
+{
+ const nvlist_t *dev_schema;
+ int error;
+
+ if (!nvlist_exists_nvlist(schema, name))
+ return (EINVAL);
+ dev_schema = nvlist_get_nvlist(schema, name);
+
+ error = pci_iov_validate_subsystem_schema(dev_schema, IOV_CONFIG_NAME);
+ if (error != 0)
+ return (error);
+
+ error = pci_iov_validate_subsystem_schema(dev_schema,
+ DRIVER_CONFIG_NAME);
+ if (error != 0)
+ return (error);
+
+ error = pci_iov_validate_param_collisions(dev_schema);
+ if (error != 0)
+ return (error);
+
+ return (pci_iov_validate_schema_subsystems(dev_schema));
+}
+
+/* Validate that we only have PF and VF devices beneath the top-level schema. */
+static int
+pci_iov_validate_schema_devices(const nvlist_t *dev_schema)
+{
+ const char *name;
+ void *it;
+ int type;
+
+ it = NULL;
+ while ((name = nvlist_next(dev_schema, &type, &it)) != NULL) {
+ if (strcmp(name, PF_CONFIG_NAME) != 0 &&
+ strcmp(name, VF_SCHEMA_NAME) != 0)
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+int
+pci_iov_validate_schema(const nvlist_t *schema)
+{
+ int error;
+
+ error = pci_iov_validate_device_schema(schema, PF_CONFIG_NAME);
+ if (error != 0)
+ return (error);
+
+ error = pci_iov_validate_device_schema(schema, VF_SCHEMA_NAME);
+ if (error != 0)
+ return (error);
+
+ return (pci_iov_validate_schema_devices(schema));
+}
+
+/*
+ * Validate that all required parameters from the schema are specified in the
+ * config. If any parameter with a default value is not specified in the
+ * config, add it to config.
+ */
+static int
+pci_iov_schema_validate_required(const nvlist_t *schema, nvlist_t *config)
+{
+ const nvlist_t *param_schema;
+ const char *name;
+ void *cookie;
+ int type;
+
+ cookie = NULL;
+ while ((name = nvlist_next(schema, &type, &cookie)) != NULL) {
+ param_schema = nvlist_get_nvlist(schema, name);
+
+ if (dnvlist_get_bool(param_schema, "required", 0)) {
+ if (!nvlist_exists(config, name))
+ return (EINVAL);
+ }
+
+ if (nvlist_exists(param_schema, "default") &&
+ !nvlist_exists(config, name))
+ pci_iov_config_add_default(param_schema, name, config);
+ }
+
+ return (nvlist_error(config));
+}
+
+static int
+pci_iov_schema_validate_param(const nvlist_t *schema_param, const char *name,
+ const nvlist_t *config)
+{
+ const struct config_type_validator *validator;
+ const char *type;
+
+ type = nvlist_get_string(schema_param, "type");
+ validator = pci_iov_schema_find_validator(type);
+
+ KASSERT(validator != NULL,
+ ("Schema was not validated: Unknown type %s", type));
+
+ return (validator->validate(validator, config, name));
+}
+
+/*
+ * Validate that all parameters in config are defined in the schema. Also
+ * validate that the type of the parameter matches the type in the schema.
+ */
+static int
+pci_iov_schema_validate_types(const nvlist_t *schema, const nvlist_t *config)
+{
+ const nvlist_t *schema_param;
+ void *cookie;
+ const char *name;
+ int type, error;
+
+ cookie = NULL;
+ while ((name = nvlist_next(config, &type, &cookie)) != NULL) {
+ if (!nvlist_exists_nvlist(schema, name))
+ return (EINVAL);
+
+ schema_param = nvlist_get_nvlist(schema, name);
+
+ error = pci_iov_schema_validate_param(schema_param, name,
+ config);
+
+ if (error != 0)
+ return (error);
+ }
+
+ return (0);
+}
+
+static int
+pci_iov_schema_validate_device(const nvlist_t *schema, nvlist_t *config,
+ const char *schema_device, const char *config_device)
+{
+ const nvlist_t *device_schema, *iov_schema, *driver_schema;
+ nvlist_t *device_config, *iov_config, *driver_config;
+ int error;
+
+ device_config = NULL;
+ iov_config = NULL;
+ driver_config = NULL;
+
+ device_schema = nvlist_get_nvlist(schema, schema_device);
+ iov_schema = nvlist_get_nvlist(device_schema, IOV_CONFIG_NAME);
+ driver_schema = nvlist_get_nvlist(device_schema, DRIVER_CONFIG_NAME);
+
+ device_config = dnvlist_take_nvlist(config, config_device, NULL);
+ if (device_config == NULL) {
+ error = EINVAL;
+ goto out;
+ }
+
+ iov_config = dnvlist_take_nvlist(device_config, IOV_CONFIG_NAME, NULL);
+ if (iov_config == NULL) {
+ error = EINVAL;
+ goto out;
+ }
+
+ driver_config = dnvlist_take_nvlist(device_config, DRIVER_CONFIG_NAME,
+ NULL);
+ if (driver_config == NULL) {
+ error = EINVAL;
+ goto out;
+ }
+
+ error = pci_iov_schema_validate_required(iov_schema, iov_config);
+ if (error != 0)
+ goto out;
+
+ error = pci_iov_schema_validate_required(driver_schema, driver_config);
+ if (error != 0)
+ goto out;
+
+ error = pci_iov_schema_validate_types(iov_schema, iov_config);
+ if (error != 0)
+ goto out;
+
+ error = pci_iov_schema_validate_types(driver_schema, driver_config);
+ if (error != 0)
+ goto out;
+
+out:
+ /* Note that these functions handle NULL pointers safely. */
+ nvlist_move_nvlist(device_config, IOV_CONFIG_NAME, iov_config);
+ nvlist_move_nvlist(device_config, DRIVER_CONFIG_NAME, driver_config);
+ nvlist_move_nvlist(config, config_device, device_config);
+
+ return (error);
+}
+
+static int
+pci_iov_schema_validate_vfs(const nvlist_t *schema, nvlist_t *config,
+ uint16_t num_vfs)
+{
+ char device[VF_MAX_NAME];
+ int i, error;
+
+ for (i = 0; i < num_vfs; i++) {
+ snprintf(device, sizeof(device), VF_PREFIX"%d", i);
+
+ error = pci_iov_schema_validate_device(schema, config,
+ VF_SCHEMA_NAME, device);
+ if (error != 0)
+ return (error);
+ }
+
+ return (0);
+}
+
+/*
+ * Validate that the device node only has IOV and DRIVER subnodes.
+ */
+static int
+pci_iov_schema_validate_device_subsystems(const nvlist_t *config)
+{
+ void *cookie;
+ const char *name;
+ int type;
+
+ cookie = NULL;
+ while ((name = nvlist_next(config, &type, &cookie)) != NULL) {
+ if (strcasecmp(name, IOV_CONFIG_NAME) == 0)
+ continue;
+ else if (strcasecmp(name, DRIVER_CONFIG_NAME) == 0)
+ continue;
+
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+/*
+ * Validate that the string is a valid device node name. It must either be "PF"
+ * or "VF-n", where n is an integer in the range [0, num_vfs).
+ */
+static int
+pci_iov_schema_validate_dev_name(const char *name, uint16_t num_vfs)
+{
+ const char *number_start;
+ char *endp;
+ u_long vf_num;
+
+ if (strcasecmp(PF_CONFIG_NAME, name) == 0)
+ return (0);
+
+ /* Ensure that we start with "VF-" */
+ if (strncasecmp(name, VF_PREFIX, VF_PREFIX_LEN) != 0)
+ return (EINVAL);
+
+ number_start = name + VF_PREFIX_LEN;
+
+ /* Filter out name == "VF-" (no number) */
+ if (number_start[0] == '\0')
+ return (EINVAL);
+
+ /* Disallow leading whitespace or +/- */
+ if (!isdigit(number_start[0]))
+ return (EINVAL);
+
+ vf_num = strtoul(number_start, &endp, 10);
+ if (*endp != '\0')
+ return (EINVAL);
+
+ /* Disallow leading zeros on VF-[1-9][0-9]* */
+ if (vf_num != 0 && number_start[0] == '0')
+ return (EINVAL);
+
+ /* Disallow leading zeros on VF-0 */
+ if (vf_num == 0 && number_start[1] != '\0')
+ return (EINVAL);
+
+ if (vf_num >= num_vfs)
+ return (EINVAL);
+
+ return (0);
+}
+
+/*
+ * Validate that there are no device nodes in config other than the ones for
+ * the PF and the VFs. This includes validating that all config nodes of the
+ * form VF-n specify a VF number that is < num_vfs.
+ */
+static int
+pci_iov_schema_validate_device_names(const nvlist_t *config, uint16_t num_vfs)
+{
+ const nvlist_t *device;
+ void *cookie;
+ const char *name;
+ int type, error;
+
+ cookie = NULL;
+ while ((name = nvlist_next(config, &type, &cookie)) != NULL) {
+ error = pci_iov_schema_validate_dev_name(name, num_vfs);
+ if (error != 0)
+ return (error);
+
+ /*
+ * Note that as this is a valid PF/VF node, we know that
+ * pci_iov_schema_validate_device() has already checked that
+ * the PF/VF node is an nvlist.
+ */
+ device = nvlist_get_nvlist(config, name);
+ error = pci_iov_schema_validate_device_subsystems(device);
+ if (error != 0)
+ return (error);
+ }
+
+ return (0);
+}
+
+int
+pci_iov_schema_validate_config(const nvlist_t *schema, nvlist_t *config)
+{
+ int error;
+ uint16_t num_vfs;
+
+ error = pci_iov_schema_validate_device(schema, config, PF_CONFIG_NAME,
+ PF_CONFIG_NAME);
+ if (error != 0)
+ return (error);
+
+ num_vfs = pci_iov_config_get_num_vfs(config);
+
+ error = pci_iov_schema_validate_vfs(schema, config, num_vfs);
+ if (error != 0)
+ return (error);
+
+ return (pci_iov_schema_validate_device_names(config, num_vfs));
+}
+
+/*
+ * Return value of the num_vfs parameter. config must have already been
+ * validated, which guarantees that the parameter exists.
+ */
+uint16_t
+pci_iov_config_get_num_vfs(const nvlist_t *config)
+{
+ const nvlist_t *pf, *iov;
+
+ pf = nvlist_get_nvlist(config, PF_CONFIG_NAME);
+ iov = nvlist_get_nvlist(pf, IOV_CONFIG_NAME);
+ return (nvlist_get_number(iov, "num_vfs"));
+}
+
+/* Allocate a new empty schema node. */
+nvlist_t *
+pci_iov_schema_alloc_node(void)
+{
+
+ return (nvlist_create(NV_FLAG_IGNORE_CASE));
+}
Index: sys/dev/pci/pci_pci.c
===================================================================
--- sys/dev/pci/pci_pci.c
+++ sys/dev/pci/pci_pci.c
@@ -64,6 +64,9 @@
static int pcib_ari_maxslots(device_t dev);
static int pcib_ari_maxfuncs(device_t dev);
static int pcib_try_enable_ari(device_t pcib, device_t dev);
+static int pcib_ari_enabled(device_t pcib);
+static void pcib_ari_decode_rid(device_t pcib, uint16_t rid,
+ int *bus, int *slot, int *func);
static device_method_t pcib_methods[] = {
/* Device interface */
@@ -104,6 +107,8 @@
DEVMETHOD(pcib_power_for_sleep, pcib_power_for_sleep),
DEVMETHOD(pcib_get_rid, pcib_ari_get_rid),
DEVMETHOD(pcib_try_enable_ari, pcib_try_enable_ari),
+ DEVMETHOD(pcib_ari_enabled, pcib_ari_enabled),
+ DEVMETHOD(pcib_decode_rid, pcib_ari_decode_rid),
DEVMETHOD_END
};
@@ -1867,6 +1872,24 @@
return (PCI_FUNCMAX);
}
+static void
+pcib_ari_decode_rid(device_t pcib, uint16_t rid, int *bus, int *slot,
+ int *func)
+{
+ struct pcib_softc *sc;
+
+ sc = device_get_softc(pcib);
+
+ *bus = PCI_RID2BUS(rid);
+ if (sc->flags & PCIB_ENABLE_ARI) {
+ *slot = PCIE_ARI_RID2SLOT(rid);
+ *func = PCIE_ARI_RID2FUNC(rid);
+ } else {
+ *slot = PCI_RID2SLOT(rid);
+ *func = PCI_RID2FUNC(rid);
+ }
+}
+
/*
* Since we are a child of a PCI bus, its parent must support the pcib interface.
*/
@@ -1998,6 +2021,16 @@
return (PCIB_POWER_FOR_SLEEP(bus, dev, pstate));
}
+static int
+pcib_ari_enabled(device_t pcib)
+{
+ struct pcib_softc *sc;
+
+ sc = device_get_softc(pcib);
+
+ return ((sc->flags & PCIB_ENABLE_ARI) != 0);
+}
+
static uint16_t
pcib_ari_get_rid(device_t pcib, device_t dev)
{
Index: sys/dev/pci/pci_private.h
===================================================================
--- sys/dev/pci/pci_private.h
+++ sys/dev/pci/pci_private.h
@@ -51,6 +51,8 @@
void pci_add_children(device_t dev, int domain, int busno,
size_t dinfo_size);
void pci_add_child(device_t bus, struct pci_devinfo *dinfo);
+device_t pci_add_iov_child(device_t bus, device_t pf, size_t dinfo_size,
+ uint16_t rid, uint16_t vid, uint16_t did);
void pci_add_resources(device_t bus, device_t dev, int force,
uint32_t prefetchmask);
int pci_attach_common(device_t dev);
@@ -139,4 +141,26 @@
*/
void pci_cfg_save(device_t, struct pci_devinfo *, int);
+int pci_mapsize(uint64_t testval);
+void pci_read_bar(device_t dev, int reg, pci_addr_t *mapp,
+ pci_addr_t *testvalp, int *bar64);
+struct pci_map *pci_add_bar(device_t dev, int reg, pci_addr_t value,
+ pci_addr_t size);
+
+struct resource *pci_alloc_multi_resource(device_t dev, device_t child,
+ int type, int *rid, u_long start, u_long end, u_long count,
+ u_long num, u_int flags);
+
+int pci_iov_attach_method(device_t bus, device_t dev,
+ struct nvlist *pf_schema, struct nvlist *vf_schema);
+int pci_iov_detach_method(device_t bus, device_t dev);
+
+device_t pci_create_iov_child_method(device_t bus, device_t pf,
+ uint16_t rid, uint16_t vid, uint16_t did);
+
+struct resource *pci_vf_alloc_mem_resource(device_t dev, device_t child,
+ int *rid, u_long start, u_long end, u_long count,
+ u_int flags);
+int pci_vf_release_mem_resource(device_t dev, device_t child,
+ int rid, struct resource *r);
#endif /* _PCI_PRIVATE_H_ */
Index: sys/dev/pci/pci_user.c
===================================================================
--- sys/dev/pci/pci_user.c
+++ sys/dev/pci/pci_user.c
@@ -492,7 +492,7 @@
static int
pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
{
- device_t pcidev, brdev;
+ device_t pcidev;
void *confdata;
const char *name;
struct devlist *devlist_head;
@@ -922,18 +922,12 @@
io->pi_sel.pc_bus, io->pi_sel.pc_dev,
io->pi_sel.pc_func);
if (pcidev) {
- brdev = device_get_parent(
- device_get_parent(pcidev));
-
#ifdef PRE7_COMPAT
if (cmd == PCIOCWRITE || cmd == PCIOCWRITE_OLD)
#else
if (cmd == PCIOCWRITE)
#endif
- PCIB_WRITE_CONFIG(brdev,
- io->pi_sel.pc_bus,
- io->pi_sel.pc_dev,
- io->pi_sel.pc_func,
+ pci_write_config(pcidev,
io->pi_reg,
io->pi_data,
io->pi_width);
@@ -940,19 +934,13 @@
#ifdef PRE7_COMPAT
else if (cmd == PCIOCREAD_OLD)
io_old->pi_data =
- PCIB_READ_CONFIG(brdev,
- io->pi_sel.pc_bus,
- io->pi_sel.pc_dev,
- io->pi_sel.pc_func,
+ pci_read_config(pcidev,
io->pi_reg,
io->pi_width);
#endif
else
io->pi_data =
- PCIB_READ_CONFIG(brdev,
- io->pi_sel.pc_bus,
- io->pi_sel.pc_dev,
- io->pi_sel.pc_func,
+ pci_read_config(pcidev,
io->pi_reg,
io->pi_width);
error = 0;
Index: sys/dev/pci/pcib_if.m
===================================================================
--- sys/dev/pci/pcib_if.m
+++ sys/dev/pci/pcib_if.m
@@ -39,6 +39,13 @@
{
return (PCI_INVALID_IRQ);
}
+
+ static int
+ pcib_null_ari_enabled(device_t pcib)
+ {
+
+ return (0);
+ }
};
#
@@ -182,3 +189,21 @@
device_t dev;
};
+#
+# Return non-zero if PCI ARI is enabled, or zero otherwise
+#
+METHOD int ari_enabled {
+ device_t pcib;
+} DEFAULT pcib_null_ari_enabled;
+
+#
+# Decode a PCI Routing Identifier (RID) into PCI bus/slot/function
+#
+METHOD void decode_rid {
+ device_t pcib;
+ uint16_t rid;
+ int *bus;
+ int *slot;
+ int *func;
+} DEFAULT pcib_decode_rid;
+
Index: sys/dev/pci/pcib_private.h
===================================================================
--- sys/dev/pci/pcib_private.h
+++ sys/dev/pci/pcib_private.h
@@ -170,5 +170,7 @@
int pcib_release_msix(device_t pcib, device_t dev, int irq);
int pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, uint32_t *data);
uint16_t pcib_get_rid(device_t pcib, device_t dev);
+void pcib_decode_rid(device_t pcib, uint16_t rid, int *bus,
+ int *slot, int *func);
#endif
Index: sys/dev/pci/pcib_support.c
===================================================================
--- sys/dev/pci/pcib_support.c
+++ sys/dev/pci/pcib_support.c
@@ -66,3 +66,13 @@
return (PCI_RID(bus, slot, func));
}
+void
+pcib_decode_rid(device_t pcib, uint16_t rid, int *bus, int *slot,
+ int *func)
+{
+
+ *bus = PCI_RID2BUS(rid);
+ *slot = PCI_RID2SLOT(rid);
+ *func = PCI_RID2FUNC(rid);
+}
+
Index: sys/dev/pci/pcireg.h
===================================================================
--- sys/dev/pci/pcireg.h
+++ sys/dev/pci/pcireg.h
@@ -68,6 +68,10 @@
#define PCI_RID2SLOT(rid) (((rid) >> PCI_RID_SLOT_SHIFT) & PCI_SLOTMAX)
#define PCI_RID2FUNC(rid) (((rid) >> PCI_RID_FUNC_SHIFT) & PCI_FUNCMAX)
+#define PCIE_ARI_RID2SLOT(rid) (0)
+#define PCIE_ARI_RID2FUNC(rid) \
+ (((rid) >> PCI_RID_FUNC_SHIFT) & PCIE_ARI_FUNCMAX)
+
#define PCIE_ARI_SLOT(func) (((func) >> PCI_RID_SLOT_SHIFT) & PCI_SLOTMAX)
#define PCIE_ARI_FUNC(func) (((func) >> PCI_RID_FUNC_SHIFT) & PCI_FUNCMAX)
@@ -920,3 +924,21 @@
#define PCIR_SERIAL_LOW 0x04
#define PCIR_SERIAL_HIGH 0x08
+/* SR-IOV definitions */
+#define PCIR_SRIOV_CTL 0x08
+#define PCIM_SRIOV_VF_EN 0x01
+#define PCIM_SRIOV_VF_MSE 0x08 /* Memory space enable. */
+#define PCIM_SRIOV_ARI_EN 0x10
+#define PCIR_SRIOV_TOTAL_VFS 0x0E
+#define PCIR_SRIOV_NUM_VFS 0x10
+#define PCIR_SRIOV_VF_OFF 0x14
+#define PCIR_SRIOV_VF_STRIDE 0x16
+#define PCIR_SRIOV_VF_DID 0x1A
+#define PCIR_SRIOV_PAGE_CAP 0x1C
+#define PCIR_SRIOV_PAGE_SIZE 0x20
+
+#define PCI_SRIOV_BASE_PAGE_SHIFT 12
+
+#define PCIR_SRIOV_BARS 0x24
+#define PCIR_SRIOV_BAR(x) (PCIR_SRIOV_BARS + (x) * 4)
+
Index: sys/dev/pci/pcivar.h
===================================================================
--- sys/dev/pci/pcivar.h
+++ sys/dev/pci/pcivar.h
@@ -50,7 +50,7 @@
struct pci_map {
pci_addr_t pm_value; /* Raw BAR value */
pci_addr_t pm_size;
- uint8_t pm_reg;
+ uint16_t pm_reg;
STAILQ_ENTRY(pci_map) pm_link;
};
@@ -143,6 +143,12 @@
uint8_t pcix_location; /* Offset of PCI-X capability registers. */
};
+struct pcicfg_vf {
+ int index;
+};
+
+#define PCICFG_VF 0x0001 /* Device is an SR-IOV Virtual Function */
+
/* config header information common to all header types */
typedef struct pcicfg {
struct device *dev; /* device which owns this */
@@ -179,6 +185,9 @@
uint8_t slot; /* config space slot address */
uint8_t func; /* config space function number */
+ uint32_t flags; /* flags defined above */
+ size_t devinfo_size; /* Size of devinfo for this bus type. */
+
struct pcicfg_pp pp; /* Power management */
struct pcicfg_vpd vpd; /* Vital product data */
struct pcicfg_msi msi; /* PCI MSI */
@@ -186,6 +195,8 @@
struct pcicfg_ht ht; /* HyperTransport */
struct pcicfg_pcie pcie; /* PCI Express */
struct pcicfg_pcix pcix; /* PCI-X */
+ struct pcicfg_iov *iov; /* SR-IOV */
+ struct pcicfg_vf vf; /* SR-IOV Virtual Function */
} pcicfgregs;
/* additional type 1 device config header information (PCI to PCI bridge) */
Index: sys/dev/pci/schema_private.h
===================================================================
--- sys/dev/pci/schema_private.h
+++ sys/dev/pci/schema_private.h
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2014 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 unmodified, 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 ``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 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 _SCHEMA_PRIVATE_H_
+#define _SCHEMA_PRIVATE_H_
+
+int pci_iov_validate_schema(const nvlist_t *schema);
+
+int pci_iov_schema_validate_config(const nvlist_t *, nvlist_t *);
+uint16_t pci_iov_config_get_num_vfs(const nvlist_t *);
+
+#endif
Index: sys/i386/conf/GENERIC
===================================================================
--- sys/i386/conf/GENERIC
+++ sys/i386/conf/GENERIC
@@ -91,6 +91,7 @@
device acpi
device eisa
device pci
+options PCI_IOV # PCI SR-IOV support
# Floppy drives
device fdc
Index: sys/kern/subr_bus.c
===================================================================
--- sys/kern/subr_bus.c
+++ sys/kern/subr_bus.c
@@ -2679,6 +2679,25 @@
}
/**
+ * @brief Set the devclass of a device and mark the devclass fixed.
+ * @see device_set_devclass()
+ */
+int
+device_set_devclass_fixed(device_t dev, const char *classname)
+{
+ int error;
+
+ if (classname == NULL)
+ return (EINVAL);
+
+ error = device_set_devclass(dev, classname);
+ if (error)
+ return (error);
+ dev->flags |= DF_FIXEDCLASS;
+ return (0);
+}
+
+/**
* @brief Set the driver of a device
*
* @retval 0 success
Index: sys/kern/subr_dnvlist.c
===================================================================
--- sys/kern/subr_dnvlist.c
+++ sys/kern/subr_dnvlist.c
@@ -1,128 +0,0 @@
-/*-
- * Copyright (c) 2013 The FreeBSD Foundation
- * All rights reserved.
- *
- * This software was developed by Pawel Jakub Dawidek under sponsorship from
- * the FreeBSD Foundation.
- *
- * 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 AUTHORS 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 AUTHORS 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$");
-
-#ifdef _KERNEL
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/kernel.h>
-#include <sys/systm.h>
-#include <sys/malloc.h>
-
-#include <machine/stdarg.h>
-
-#else
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-#endif
-
-#include <sys/nv.h>
-#include <sys/nv_impl.h>
-
-#include <sys/dnv.h>
-
-#define DNVLIST_GET(ftype, type) \
-ftype \
-dnvlist_get_##type(const nvlist_t *nvl, const char *name, ftype defval) \
-{ \
- \
- if (nvlist_exists_##type(nvl, name)) \
- return (nvlist_get_##type(nvl, name)); \
- else \
- return (defval); \
-}
-
-DNVLIST_GET(bool, bool)
-DNVLIST_GET(uint64_t, number)
-DNVLIST_GET(const char *, string)
-DNVLIST_GET(const nvlist_t *, nvlist)
-#ifndef _KERNEL
-DNVLIST_GET(int, descriptor)
-#endif
-
-#undef DNVLIST_GET
-
-const void *
-dnvlist_get_binary(const nvlist_t *nvl, const char *name, size_t *sizep,
- const void *defval, size_t defsize)
-{
- const void *value;
-
- if (nvlist_exists_binary(nvl, name))
- value = nvlist_get_binary(nvl, name, sizep);
- else {
- if (sizep != NULL)
- *sizep = defsize;
- value = defval;
- }
- return (value);
-}
-
-#define DNVLIST_TAKE(ftype, type) \
-ftype \
-dnvlist_take_##type(nvlist_t *nvl, const char *name, ftype defval) \
-{ \
- \
- if (nvlist_exists_##type(nvl, name)) \
- return (nvlist_take_##type(nvl, name)); \
- else \
- return (defval); \
-}
-
-DNVLIST_TAKE(bool, bool)
-DNVLIST_TAKE(uint64_t, number)
-DNVLIST_TAKE(char *, string)
-DNVLIST_TAKE(nvlist_t *, nvlist)
-#ifndef _KERNEL
-DNVLIST_TAKE(int, descriptor)
-#endif
-
-#undef DNVLIST_TAKE
-
-void *
-dnvlist_take_binary(nvlist_t *nvl, const char *name, size_t *sizep,
- void *defval, size_t defsize)
-{
- void *value;
-
- if (nvlist_exists_binary(nvl, name))
- value = nvlist_take_binary(nvl, name, sizep);
- else {
- if (sizep != NULL)
- *sizep = defsize;
- value = defval;
- }
- return (value);
-}
-
Index: sys/kern/subr_nvlist.c
===================================================================
--- sys/kern/subr_nvlist.c
+++ sys/kern/subr_nvlist.c
@@ -1,1475 +0,0 @@
-/*-
- * Copyright (c) 2009-2013 The FreeBSD Foundation
- * All rights reserved.
- *
- * This software was developed by Pawel Jakub Dawidek under sponsorship from
- * the FreeBSD Foundation.
- *
- * 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 AUTHORS 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 AUTHORS 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/endian.h>
-#include <sys/queue.h>
-
-#ifdef _KERNEL
-
-#include <sys/errno.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/malloc.h>
-#include <sys/systm.h>
-
-#include <machine/stdarg.h>
-
-#else
-#include <sys/socket.h>
-
-#include <errno.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdint.h>
-#define _WITH_DPRINTF
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "msgio.h"
-#endif
-
-#ifdef HAVE_PJDLOG
-#include <pjdlog.h>
-#endif
-
-#include <sys/nv.h>
-#include <sys/nv_impl.h>
-#include <sys/nvlist_impl.h>
-#include <sys/nvpair_impl.h>
-
-#ifndef HAVE_PJDLOG
-#ifdef _KERNEL
-#define PJDLOG_ASSERT(...) MPASS(__VA_ARGS__)
-#define PJDLOG_RASSERT(expr, ...) KASSERT(expr, (__VA_ARGS__))
-#define PJDLOG_ABORT(...) panic(__VA_ARGS__)
-#else
-#include <assert.h>
-#define PJDLOG_ASSERT(...) assert(__VA_ARGS__)
-#define PJDLOG_RASSERT(expr, ...) assert(expr)
-#define PJDLOG_ABORT(...) do { \
- fprintf(stderr, "%s:%u: ", __FILE__, __LINE__); \
- fprintf(stderr, __VA_ARGS__); \
- fprintf(stderr, "\n"); \
- abort(); \
-} while (0)
-#endif
-#endif
-
-#define NV_FLAG_PRIVATE_MASK (NV_FLAG_BIG_ENDIAN)
-#define NV_FLAG_PUBLIC_MASK (NV_FLAG_IGNORE_CASE)
-#define NV_FLAG_ALL_MASK (NV_FLAG_PRIVATE_MASK | NV_FLAG_PUBLIC_MASK)
-
-#define NVLIST_MAGIC 0x6e766c /* "nvl" */
-struct nvlist {
- int nvl_magic;
- int nvl_error;
- int nvl_flags;
- nvpair_t *nvl_parent;
- struct nvl_head nvl_head;
-};
-
-#define NVLIST_ASSERT(nvl) do { \
- PJDLOG_ASSERT((nvl) != NULL); \
- PJDLOG_ASSERT((nvl)->nvl_magic == NVLIST_MAGIC); \
-} while (0)
-
-#ifdef _KERNEL
-MALLOC_DEFINE(M_NVLIST, "nvlist", "kernel nvlist");
-#endif
-
-#define NVPAIR_ASSERT(nvp) nvpair_assert(nvp)
-
-#define NVLIST_HEADER_MAGIC 0x6c
-#define NVLIST_HEADER_VERSION 0x00
-struct nvlist_header {
- uint8_t nvlh_magic;
- uint8_t nvlh_version;
- uint8_t nvlh_flags;
- uint64_t nvlh_descriptors;
- uint64_t nvlh_size;
-} __packed;
-
-nvlist_t *
-nvlist_create(int flags)
-{
- nvlist_t *nvl;
-
- PJDLOG_ASSERT((flags & ~(NV_FLAG_PUBLIC_MASK)) == 0);
-
- nvl = nv_malloc(sizeof(*nvl));
- nvl->nvl_error = 0;
- nvl->nvl_flags = flags;
- nvl->nvl_parent = NULL;
- TAILQ_INIT(&nvl->nvl_head);
- nvl->nvl_magic = NVLIST_MAGIC;
-
- return (nvl);
-}
-
-void
-nvlist_destroy(nvlist_t *nvl)
-{
- nvpair_t *nvp;
- int serrno;
-
- if (nvl == NULL)
- return;
-
- SAVE_ERRNO(serrno);
-
- NVLIST_ASSERT(nvl);
-
- while ((nvp = nvlist_first_nvpair(nvl)) != NULL) {
- nvlist_remove_nvpair(nvl, nvp);
- nvpair_free(nvp);
- }
- nvl->nvl_magic = 0;
- nv_free(nvl);
-
- RESTORE_ERRNO(serrno);
-}
-
-void
-nvlist_set_error(nvlist_t *nvl, int error)
-{
-
- PJDLOG_ASSERT(error != 0);
-
- /*
- * Check for error != 0 so that we don't do the wrong thing if somebody
- * tries to abuse this API when asserts are disabled.
- */
- if (nvl != NULL && error != 0 && nvl->nvl_error == 0)
- nvl->nvl_error = error;
-}
-
-int
-nvlist_error(const nvlist_t *nvl)
-{
-
- if (nvl == NULL)
- return (ENOMEM);
-
- NVLIST_ASSERT(nvl);
-
- return (nvl->nvl_error);
-}
-
-nvpair_t *
-nvlist_get_nvpair_parent(const nvlist_t *nvl)
-{
-
- NVLIST_ASSERT(nvl);
-
- return (nvl->nvl_parent);
-}
-
-const nvlist_t *
-nvlist_get_parent(const nvlist_t *nvl, void **cookiep)
-{
- nvpair_t *nvp;
-
- NVLIST_ASSERT(nvl);
-
- nvp = nvl->nvl_parent;
- if (cookiep != NULL)
- *cookiep = nvp;
- if (nvp == NULL)
- return (NULL);
-
- return (nvpair_nvlist(nvp));
-}
-
-void
-nvlist_set_parent(nvlist_t *nvl, nvpair_t *parent)
-{
-
- NVLIST_ASSERT(nvl);
-
- nvl->nvl_parent = parent;
-}
-
-bool
-nvlist_empty(const nvlist_t *nvl)
-{
-
- NVLIST_ASSERT(nvl);
- PJDLOG_ASSERT(nvl->nvl_error == 0);
-
- return (nvlist_first_nvpair(nvl) == NULL);
-}
-
-int
-nvlist_flags(const nvlist_t *nvl)
-{
-
- NVLIST_ASSERT(nvl);
- PJDLOG_ASSERT(nvl->nvl_error == 0);
- PJDLOG_ASSERT((nvl->nvl_flags & ~(NV_FLAG_PUBLIC_MASK)) == 0);
-
- return (nvl->nvl_flags);
-}
-
-static void
-nvlist_report_missing(int type, const char *name)
-{
-
- PJDLOG_ABORT("Element '%s' of type %s doesn't exist.",
- name, nvpair_type_string(type));
-}
-
-static nvpair_t *
-nvlist_find(const nvlist_t *nvl, int type, const char *name)
-{
- nvpair_t *nvp;
-
- NVLIST_ASSERT(nvl);
- PJDLOG_ASSERT(nvl->nvl_error == 0);
- PJDLOG_ASSERT(type == NV_TYPE_NONE ||
- (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
-
- for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
- nvp = nvlist_next_nvpair(nvl, nvp)) {
- if (type != NV_TYPE_NONE && nvpair_type(nvp) != type)
- continue;
- if ((nvl->nvl_flags & NV_FLAG_IGNORE_CASE) != 0) {
- if (strcasecmp(nvpair_name(nvp), name) != 0)
- continue;
- } else {
- if (strcmp(nvpair_name(nvp), name) != 0)
- continue;
- }
- break;
- }
-
- if (nvp == NULL)
- RESTORE_ERRNO(ENOENT);
-
- return (nvp);
-}
-
-bool
-nvlist_exists_type(const nvlist_t *nvl, const char *name, int type)
-{
-
- NVLIST_ASSERT(nvl);
- PJDLOG_ASSERT(nvl->nvl_error == 0);
- PJDLOG_ASSERT(type == NV_TYPE_NONE ||
- (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
-
- return (nvlist_find(nvl, type, name) != NULL);
-}
-
-void
-nvlist_free_type(nvlist_t *nvl, const char *name, int type)
-{
- nvpair_t *nvp;
-
- NVLIST_ASSERT(nvl);
- PJDLOG_ASSERT(nvl->nvl_error == 0);
- PJDLOG_ASSERT(type == NV_TYPE_NONE ||
- (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
-
- nvp = nvlist_find(nvl, type, name);
- if (nvp != NULL)
- nvlist_free_nvpair(nvl, nvp);
- else
- nvlist_report_missing(type, name);
-}
-
-nvlist_t *
-nvlist_clone(const nvlist_t *nvl)
-{
- nvlist_t *newnvl;
- nvpair_t *nvp, *newnvp;
-
- NVLIST_ASSERT(nvl);
-
- if (nvl->nvl_error != 0) {
- RESTORE_ERRNO(nvl->nvl_error);
- return (NULL);
- }
-
- newnvl = nvlist_create(nvl->nvl_flags & NV_FLAG_PUBLIC_MASK);
- for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
- nvp = nvlist_next_nvpair(nvl, nvp)) {
- newnvp = nvpair_clone(nvp);
- if (newnvp == NULL)
- break;
- nvlist_move_nvpair(newnvl, newnvp);
- }
- if (nvp != NULL) {
- nvlist_destroy(newnvl);
- return (NULL);
- }
- return (newnvl);
-}
-
-#ifndef _KERNEL
-static bool
-nvlist_dump_error_check(const nvlist_t *nvl, int fd, int level)
-{
-
- if (nvlist_error(nvl) != 0) {
- dprintf(fd, "%*serror: %d\n", level * 4, "",
- nvlist_error(nvl));
- return (true);
- }
-
- return (false);
-}
-
-/*
- * Dump content of nvlist.
- */
-void
-nvlist_dump(const nvlist_t *nvl, int fd)
-{
- const nvlist_t *tmpnvl;
- nvpair_t *nvp, *tmpnvp;
- void *cookie;
- int level;
-
- level = 0;
- if (nvlist_dump_error_check(nvl, fd, level))
- return;
-
- nvp = nvlist_first_nvpair(nvl);
- while (nvp != NULL) {
- dprintf(fd, "%*s%s (%s):", level * 4, "", nvpair_name(nvp),
- nvpair_type_string(nvpair_type(nvp)));
- switch (nvpair_type(nvp)) {
- case NV_TYPE_NULL:
- dprintf(fd, " null\n");
- break;
- case NV_TYPE_BOOL:
- dprintf(fd, " %s\n", nvpair_get_bool(nvp) ?
- "TRUE" : "FALSE");
- break;
- case NV_TYPE_NUMBER:
- dprintf(fd, " %ju (%jd) (0x%jx)\n",
- (uintmax_t)nvpair_get_number(nvp),
- (intmax_t)nvpair_get_number(nvp),
- (uintmax_t)nvpair_get_number(nvp));
- break;
- case NV_TYPE_STRING:
- dprintf(fd, " [%s]\n", nvpair_get_string(nvp));
- break;
- case NV_TYPE_NVLIST:
- dprintf(fd, "\n");
- tmpnvl = nvpair_get_nvlist(nvp);
- if (nvlist_dump_error_check(tmpnvl, fd, level + 1))
- break;
- tmpnvp = nvlist_first_nvpair(tmpnvl);
- if (tmpnvp != NULL) {
- nvl = tmpnvl;
- nvp = tmpnvp;
- level++;
- continue;
- }
- break;
- case NV_TYPE_DESCRIPTOR:
- dprintf(fd, " %d\n", nvpair_get_descriptor(nvp));
- break;
- case NV_TYPE_BINARY:
- {
- const unsigned char *binary;
- unsigned int ii;
- size_t size;
-
- binary = nvpair_get_binary(nvp, &size);
- dprintf(fd, " %zu ", size);
- for (ii = 0; ii < size; ii++)
- dprintf(fd, "%02hhx", binary[ii]);
- dprintf(fd, "\n");
- break;
- }
- default:
- PJDLOG_ABORT("Unknown type: %d.", nvpair_type(nvp));
- }
-
- while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
- cookie = NULL;
- nvl = nvlist_get_parent(nvl, &cookie);
- if (nvl == NULL)
- return;
- nvp = cookie;
- level--;
- }
- }
-}
-
-void
-nvlist_fdump(const nvlist_t *nvl, FILE *fp)
-{
-
- fflush(fp);
- nvlist_dump(nvl, fileno(fp));
-}
-#endif
-
-/*
- * The function obtains size of the nvlist after nvlist_pack().
- */
-size_t
-nvlist_size(const nvlist_t *nvl)
-{
- const nvlist_t *tmpnvl;
- const nvpair_t *nvp, *tmpnvp;
- void *cookie;
- size_t size;
-
- NVLIST_ASSERT(nvl);
- PJDLOG_ASSERT(nvl->nvl_error == 0);
-
- size = sizeof(struct nvlist_header);
- nvp = nvlist_first_nvpair(nvl);
- while (nvp != NULL) {
- size += nvpair_header_size();
- size += strlen(nvpair_name(nvp)) + 1;
- if (nvpair_type(nvp) == NV_TYPE_NVLIST) {
- size += sizeof(struct nvlist_header);
- size += nvpair_header_size() + 1;
- tmpnvl = nvpair_get_nvlist(nvp);
- PJDLOG_ASSERT(tmpnvl->nvl_error == 0);
- tmpnvp = nvlist_first_nvpair(tmpnvl);
- if (tmpnvp != NULL) {
- nvl = tmpnvl;
- nvp = tmpnvp;
- continue;
- }
- } else {
- size += nvpair_size(nvp);
- }
-
- while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
- cookie = NULL;
- nvl = nvlist_get_parent(nvl, &cookie);
- if (nvl == NULL)
- goto out;
- nvp = cookie;
- }
- }
-
-out:
- return (size);
-}
-
-#ifndef _KERNEL
-static int *
-nvlist_xdescriptors(const nvlist_t *nvl, int *descs, int level)
-{
- const nvpair_t *nvp;
-
- NVLIST_ASSERT(nvl);
- PJDLOG_ASSERT(nvl->nvl_error == 0);
- PJDLOG_ASSERT(level < 3);
-
- for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
- nvp = nvlist_next_nvpair(nvl, nvp)) {
- switch (nvpair_type(nvp)) {
- case NV_TYPE_DESCRIPTOR:
- *descs = nvpair_get_descriptor(nvp);
- descs++;
- break;
- case NV_TYPE_NVLIST:
- descs = nvlist_xdescriptors(nvpair_get_nvlist(nvp),
- descs, level + 1);
- break;
- }
- }
-
- return (descs);
-}
-#endif
-
-#ifndef _KERNEL
-int *
-nvlist_descriptors(const nvlist_t *nvl, size_t *nitemsp)
-{
- size_t nitems;
- int *fds;
-
- nitems = nvlist_ndescriptors(nvl);
- fds = nv_malloc(sizeof(fds[0]) * (nitems + 1));
- if (fds == NULL)
- return (NULL);
- if (nitems > 0)
- nvlist_xdescriptors(nvl, fds, 0);
- fds[nitems] = -1;
- if (nitemsp != NULL)
- *nitemsp = nitems;
- return (fds);
-}
-#endif
-
-static size_t
-nvlist_xndescriptors(const nvlist_t *nvl, int level)
-{
-#ifndef _KERNEL
- const nvpair_t *nvp;
- size_t ndescs;
-
- NVLIST_ASSERT(nvl);
- PJDLOG_ASSERT(nvl->nvl_error == 0);
- PJDLOG_ASSERT(level < 3);
-
- ndescs = 0;
- for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
- nvp = nvlist_next_nvpair(nvl, nvp)) {
- switch (nvpair_type(nvp)) {
- case NV_TYPE_DESCRIPTOR:
- ndescs++;
- break;
- case NV_TYPE_NVLIST:
- ndescs += nvlist_xndescriptors(nvpair_get_nvlist(nvp),
- level + 1);
- break;
- }
- }
-
- return (ndescs);
-#else
- return (0);
-#endif
-}
-
-size_t
-nvlist_ndescriptors(const nvlist_t *nvl)
-{
-
- return (nvlist_xndescriptors(nvl, 0));
-}
-
-static unsigned char *
-nvlist_pack_header(const nvlist_t *nvl, unsigned char *ptr, size_t *leftp)
-{
- struct nvlist_header nvlhdr;
-
- NVLIST_ASSERT(nvl);
-
- nvlhdr.nvlh_magic = NVLIST_HEADER_MAGIC;
- nvlhdr.nvlh_version = NVLIST_HEADER_VERSION;
- nvlhdr.nvlh_flags = nvl->nvl_flags;
-#if BYTE_ORDER == BIG_ENDIAN
- nvlhdr.nvlh_flags |= NV_FLAG_BIG_ENDIAN;
-#endif
- nvlhdr.nvlh_descriptors = nvlist_ndescriptors(nvl);
- nvlhdr.nvlh_size = *leftp - sizeof(nvlhdr);
- PJDLOG_ASSERT(*leftp >= sizeof(nvlhdr));
- memcpy(ptr, &nvlhdr, sizeof(nvlhdr));
- ptr += sizeof(nvlhdr);
- *leftp -= sizeof(nvlhdr);
-
- return (ptr);
-}
-
-void *
-nvlist_xpack(const nvlist_t *nvl, int64_t *fdidxp, size_t *sizep)
-{
- unsigned char *buf, *ptr;
- size_t left, size;
- const nvlist_t *tmpnvl;
- nvpair_t *nvp, *tmpnvp;
- void *cookie;
-
- NVLIST_ASSERT(nvl);
-
- if (nvl->nvl_error != 0) {
- RESTORE_ERRNO(nvl->nvl_error);
- return (NULL);
- }
-
- size = nvlist_size(nvl);
- buf = nv_malloc(size);
- if (buf == NULL)
- return (NULL);
-
- ptr = buf;
- left = size;
-
- ptr = nvlist_pack_header(nvl, ptr, &left);
-
- nvp = nvlist_first_nvpair(nvl);
- while (nvp != NULL) {
- NVPAIR_ASSERT(nvp);
-
- nvpair_init_datasize(nvp);
- ptr = nvpair_pack_header(nvp, ptr, &left);
- if (ptr == NULL) {
- nv_free(buf);
- return (NULL);
- }
- switch (nvpair_type(nvp)) {
- case NV_TYPE_NULL:
- ptr = nvpair_pack_null(nvp, ptr, &left);
- break;
- case NV_TYPE_BOOL:
- ptr = nvpair_pack_bool(nvp, ptr, &left);
- break;
- case NV_TYPE_NUMBER:
- ptr = nvpair_pack_number(nvp, ptr, &left);
- break;
- case NV_TYPE_STRING:
- ptr = nvpair_pack_string(nvp, ptr, &left);
- break;
- case NV_TYPE_NVLIST:
- tmpnvl = nvpair_get_nvlist(nvp);
- ptr = nvlist_pack_header(tmpnvl, ptr, &left);
- if (ptr == NULL)
- goto out;
- tmpnvp = nvlist_first_nvpair(tmpnvl);
- if (tmpnvp != NULL) {
- nvl = tmpnvl;
- nvp = tmpnvp;
- continue;
- }
- ptr = nvpair_pack_nvlist_up(ptr, &left);
- break;
-#ifndef _KERNEL
- case NV_TYPE_DESCRIPTOR:
- ptr = nvpair_pack_descriptor(nvp, ptr, fdidxp, &left);
- break;
-#endif
- case NV_TYPE_BINARY:
- ptr = nvpair_pack_binary(nvp, ptr, &left);
- break;
- default:
- PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp));
- }
- if (ptr == NULL) {
- nv_free(buf);
- return (NULL);
- }
- while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
- cookie = NULL;
- nvl = nvlist_get_parent(nvl, &cookie);
- if (nvl == NULL)
- goto out;
- nvp = cookie;
- ptr = nvpair_pack_nvlist_up(ptr, &left);
- if (ptr == NULL)
- goto out;
- }
- }
-
-out:
- if (sizep != NULL)
- *sizep = size;
- return (buf);
-}
-
-void *
-nvlist_pack(const nvlist_t *nvl, size_t *sizep)
-{
-
- NVLIST_ASSERT(nvl);
-
- if (nvl->nvl_error != 0) {
- RESTORE_ERRNO(nvl->nvl_error);
- return (NULL);
- }
-
- if (nvlist_ndescriptors(nvl) > 0) {
- RESTORE_ERRNO(EOPNOTSUPP);
- return (NULL);
- }
-
- return (nvlist_xpack(nvl, NULL, sizep));
-}
-
-static bool
-nvlist_check_header(struct nvlist_header *nvlhdrp)
-{
-
- if (nvlhdrp->nvlh_magic != NVLIST_HEADER_MAGIC) {
- RESTORE_ERRNO(EINVAL);
- return (false);
- }
- if ((nvlhdrp->nvlh_flags & ~NV_FLAG_ALL_MASK) != 0) {
- RESTORE_ERRNO(EINVAL);
- return (false);
- }
-#if BYTE_ORDER == BIG_ENDIAN
- if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) == 0) {
- nvlhdrp->nvlh_size = le64toh(nvlhdrp->nvlh_size);
- nvlhdrp->nvlh_descriptors = le64toh(nvlhdrp->nvlh_descriptors);
- }
-#else
- if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0) {
- nvlhdrp->nvlh_size = be64toh(nvlhdrp->nvlh_size);
- nvlhdrp->nvlh_descriptors = be64toh(nvlhdrp->nvlh_descriptors);
- }
-#endif
- return (true);
-}
-
-const unsigned char *
-nvlist_unpack_header(nvlist_t *nvl, const unsigned char *ptr, size_t nfds,
- bool *isbep, size_t *leftp)
-{
- struct nvlist_header nvlhdr;
-
- if (*leftp < sizeof(nvlhdr))
- goto failed;
-
- memcpy(&nvlhdr, ptr, sizeof(nvlhdr));
-
- if (!nvlist_check_header(&nvlhdr))
- goto failed;
-
- if (nvlhdr.nvlh_size != *leftp - sizeof(nvlhdr))
- goto failed;
-
- /*
- * nvlh_descriptors might be smaller than nfds in embedded nvlists.
- */
- if (nvlhdr.nvlh_descriptors > nfds)
- goto failed;
-
- if ((nvlhdr.nvlh_flags & ~NV_FLAG_ALL_MASK) != 0)
- goto failed;
-
- nvl->nvl_flags = (nvlhdr.nvlh_flags & NV_FLAG_PUBLIC_MASK);
-
- ptr += sizeof(nvlhdr);
- if (isbep != NULL)
- *isbep = (((int)nvlhdr.nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0);
- *leftp -= sizeof(nvlhdr);
-
- return (ptr);
-failed:
- RESTORE_ERRNO(EINVAL);
- return (NULL);
-}
-
-nvlist_t *
-nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds)
-{
- const unsigned char *ptr;
- nvlist_t *nvl, *retnvl, *tmpnvl;
- nvpair_t *nvp;
- size_t left;
- bool isbe;
-
- left = size;
- ptr = buf;
-
- tmpnvl = NULL;
- nvl = retnvl = nvlist_create(0);
- if (nvl == NULL)
- goto failed;
-
- ptr = nvlist_unpack_header(nvl, ptr, nfds, &isbe, &left);
- if (ptr == NULL)
- goto failed;
-
- while (left > 0) {
- ptr = nvpair_unpack(isbe, ptr, &left, &nvp);
- if (ptr == NULL)
- goto failed;
- switch (nvpair_type(nvp)) {
- case NV_TYPE_NULL:
- ptr = nvpair_unpack_null(isbe, nvp, ptr, &left);
- break;
- case NV_TYPE_BOOL:
- ptr = nvpair_unpack_bool(isbe, nvp, ptr, &left);
- break;
- case NV_TYPE_NUMBER:
- ptr = nvpair_unpack_number(isbe, nvp, ptr, &left);
- break;
- case NV_TYPE_STRING:
- ptr = nvpair_unpack_string(isbe, nvp, ptr, &left);
- break;
- case NV_TYPE_NVLIST:
- ptr = nvpair_unpack_nvlist(isbe, nvp, ptr, &left, nfds,
- &tmpnvl);
- nvlist_set_parent(tmpnvl, nvp);
- break;
-#ifndef _KERNEL
- case NV_TYPE_DESCRIPTOR:
- ptr = nvpair_unpack_descriptor(isbe, nvp, ptr, &left,
- fds, nfds);
- break;
-#endif
- case NV_TYPE_BINARY:
- ptr = nvpair_unpack_binary(isbe, nvp, ptr, &left);
- break;
- case NV_TYPE_NVLIST_UP:
- if (nvl->nvl_parent == NULL)
- goto failed;
- nvl = nvpair_nvlist(nvl->nvl_parent);
- continue;
- default:
- PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp));
- }
- if (ptr == NULL)
- goto failed;
- nvlist_move_nvpair(nvl, nvp);
- if (tmpnvl != NULL) {
- nvl = tmpnvl;
- tmpnvl = NULL;
- }
- }
-
- return (retnvl);
-failed:
- nvlist_destroy(retnvl);
- return (NULL);
-}
-
-nvlist_t *
-nvlist_unpack(const void *buf, size_t size)
-{
-
- return (nvlist_xunpack(buf, size, NULL, 0));
-}
-
-#ifndef _KERNEL
-int
-nvlist_send(int sock, const nvlist_t *nvl)
-{
- size_t datasize, nfds;
- int *fds;
- void *data;
- int64_t fdidx;
- int serrno, ret;
-
- if (nvlist_error(nvl) != 0) {
- errno = nvlist_error(nvl);
- return (-1);
- }
-
- fds = nvlist_descriptors(nvl, &nfds);
- if (fds == NULL)
- return (-1);
-
- ret = -1;
- data = NULL;
- fdidx = 0;
-
- data = nvlist_xpack(nvl, &fdidx, &datasize);
- if (data == NULL)
- goto out;
-
- if (buf_send(sock, data, datasize) == -1)
- goto out;
-
- if (nfds > 0) {
- if (fd_send(sock, fds, nfds) == -1)
- goto out;
- }
-
- ret = 0;
-out:
- serrno = errno;
- free(fds);
- free(data);
- errno = serrno;
- return (ret);
-}
-
-nvlist_t *
-nvlist_recv(int sock)
-{
- struct nvlist_header nvlhdr;
- nvlist_t *nvl, *ret;
- unsigned char *buf;
- size_t nfds, size, i;
- int serrno, *fds;
-
- if (buf_recv(sock, &nvlhdr, sizeof(nvlhdr)) == -1)
- return (NULL);
-
- if (!nvlist_check_header(&nvlhdr))
- return (NULL);
-
- nfds = (size_t)nvlhdr.nvlh_descriptors;
- size = sizeof(nvlhdr) + (size_t)nvlhdr.nvlh_size;
-
- buf = malloc(size);
- if (buf == NULL)
- return (NULL);
-
- memcpy(buf, &nvlhdr, sizeof(nvlhdr));
-
- ret = NULL;
- fds = NULL;
-
- if (buf_recv(sock, buf + sizeof(nvlhdr), size - sizeof(nvlhdr)) == -1)
- goto out;
-
- if (nfds > 0) {
- fds = malloc(nfds * sizeof(fds[0]));
- if (fds == NULL)
- goto out;
- if (fd_recv(sock, fds, nfds) == -1)
- goto out;
- }
-
- nvl = nvlist_xunpack(buf, size, fds, nfds);
- if (nvl == NULL) {
- for (i = 0; i < nfds; i++)
- close(fds[i]);
- goto out;
- }
-
- ret = nvl;
-out:
- serrno = errno;
- free(buf);
- free(fds);
- errno = serrno;
-
- return (ret);
-}
-
-nvlist_t *
-nvlist_xfer(int sock, nvlist_t *nvl)
-{
-
- if (nvlist_send(sock, nvl) < 0) {
- nvlist_destroy(nvl);
- return (NULL);
- }
- nvlist_destroy(nvl);
- return (nvlist_recv(sock));
-}
-#endif
-
-nvpair_t *
-nvlist_first_nvpair(const nvlist_t *nvl)
-{
-
- NVLIST_ASSERT(nvl);
-
- return (TAILQ_FIRST(&nvl->nvl_head));
-}
-
-nvpair_t *
-nvlist_next_nvpair(const nvlist_t *nvl, const nvpair_t *nvp)
-{
- nvpair_t *retnvp;
-
- NVLIST_ASSERT(nvl);
- NVPAIR_ASSERT(nvp);
- PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
-
- retnvp = nvpair_next(nvp);
- PJDLOG_ASSERT(retnvp == NULL || nvpair_nvlist(retnvp) == nvl);
-
- return (retnvp);
-
-}
-
-nvpair_t *
-nvlist_prev_nvpair(const nvlist_t *nvl, const nvpair_t *nvp)
-{
- nvpair_t *retnvp;
-
- NVLIST_ASSERT(nvl);
- NVPAIR_ASSERT(nvp);
- PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
-
- retnvp = nvpair_prev(nvp);
- PJDLOG_ASSERT(nvpair_nvlist(retnvp) == nvl);
-
- return (retnvp);
-}
-
-const char *
-nvlist_next(const nvlist_t *nvl, int *typep, void **cookiep)
-{
- nvpair_t *nvp;
-
- NVLIST_ASSERT(nvl);
- PJDLOG_ASSERT(cookiep != NULL);
-
- if (*cookiep == NULL)
- nvp = nvlist_first_nvpair(nvl);
- else
- nvp = nvlist_next_nvpair(nvl, *cookiep);
- if (nvp == NULL)
- return (NULL);
- if (typep != NULL)
- *typep = nvpair_type(nvp);
- *cookiep = nvp;
- return (nvpair_name(nvp));
-}
-
-bool
-nvlist_exists(const nvlist_t *nvl, const char *name)
-{
-
- return (nvlist_find(nvl, NV_TYPE_NONE, name) != NULL);
-}
-
-#define NVLIST_EXISTS(type, TYPE) \
-bool \
-nvlist_exists_##type(const nvlist_t *nvl, const char *name) \
-{ \
- \
- return (nvlist_find(nvl, NV_TYPE_##TYPE, name) != NULL); \
-}
-
-NVLIST_EXISTS(null, NULL)
-NVLIST_EXISTS(bool, BOOL)
-NVLIST_EXISTS(number, NUMBER)
-NVLIST_EXISTS(string, STRING)
-NVLIST_EXISTS(nvlist, NVLIST)
-#ifndef _KERNEL
-NVLIST_EXISTS(descriptor, DESCRIPTOR)
-#endif
-NVLIST_EXISTS(binary, BINARY)
-
-#undef NVLIST_EXISTS
-
-void
-nvlist_add_nvpair(nvlist_t *nvl, const nvpair_t *nvp)
-{
- nvpair_t *newnvp;
-
- NVPAIR_ASSERT(nvp);
-
- if (nvlist_error(nvl) != 0) {
- RESTORE_ERRNO(nvlist_error(nvl));
- return;
- }
- if (nvlist_exists(nvl, nvpair_name(nvp))) {
- nvl->nvl_error = EEXIST;
- RESTORE_ERRNO(nvlist_error(nvl));
- return;
- }
-
- newnvp = nvpair_clone(nvp);
- if (newnvp == NULL) {
- nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
- RESTORE_ERRNO(nvlist_error(nvl));
- return;
- }
-
- nvpair_insert(&nvl->nvl_head, newnvp, nvl);
-}
-
-void
-nvlist_add_stringf(nvlist_t *nvl, const char *name, const char *valuefmt, ...)
-{
- va_list valueap;
-
- va_start(valueap, valuefmt);
- nvlist_add_stringv(nvl, name, valuefmt, valueap);
- va_end(valueap);
-}
-
-void
-nvlist_add_stringv(nvlist_t *nvl, const char *name, const char *valuefmt,
- va_list valueap)
-{
- nvpair_t *nvp;
-
- if (nvlist_error(nvl) != 0) {
- RESTORE_ERRNO(nvlist_error(nvl));
- return;
- }
-
- nvp = nvpair_create_stringv(name, valuefmt, valueap);
- if (nvp == NULL) {
- nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
- RESTORE_ERRNO(nvl->nvl_error);
- } else
- nvlist_move_nvpair(nvl, nvp);
-}
-
-void
-nvlist_add_null(nvlist_t *nvl, const char *name)
-{
- nvpair_t *nvp;
-
- if (nvlist_error(nvl) != 0) {
- RESTORE_ERRNO(nvlist_error(nvl));
- return;
- }
-
- nvp = nvpair_create_null(name);
- if (nvp == NULL) {
- nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
- RESTORE_ERRNO(nvl->nvl_error);
- } else
- nvlist_move_nvpair(nvl, nvp);
-}
-
-void
-nvlist_add_bool(nvlist_t *nvl, const char *name, bool value)
-{
- nvpair_t *nvp;
-
- if (nvlist_error(nvl) != 0) {
- RESTORE_ERRNO(nvlist_error(nvl));
- return;
- }
-
- nvp = nvpair_create_bool(name, value);
- if (nvp == NULL) {
- nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
- RESTORE_ERRNO(nvl->nvl_error);
- } else
- nvlist_move_nvpair(nvl, nvp);
-}
-
-void
-nvlist_add_number(nvlist_t *nvl, const char *name, uint64_t value)
-{
- nvpair_t *nvp;
-
- if (nvlist_error(nvl) != 0) {
- RESTORE_ERRNO(nvlist_error(nvl));
- return;
- }
-
- nvp = nvpair_create_number(name, value);
- if (nvp == NULL) {
- nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
- RESTORE_ERRNO(nvl->nvl_error);
- } else
- nvlist_move_nvpair(nvl, nvp);
-}
-
-void
-nvlist_add_string(nvlist_t *nvl, const char *name, const char *value)
-{
- nvpair_t *nvp;
-
- if (nvlist_error(nvl) != 0) {
- RESTORE_ERRNO(nvlist_error(nvl));
- return;
- }
-
- nvp = nvpair_create_string(name, value);
- if (nvp == NULL) {
- nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
- RESTORE_ERRNO(nvl->nvl_error);
- } else
- nvlist_move_nvpair(nvl, nvp);
-}
-
-void
-nvlist_add_nvlist(nvlist_t *nvl, const char *name, const nvlist_t *value)
-{
- nvpair_t *nvp;
-
- if (nvlist_error(nvl) != 0) {
- RESTORE_ERRNO(nvlist_error(nvl));
- return;
- }
-
- nvp = nvpair_create_nvlist(name, value);
- if (nvp == NULL) {
- nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
- RESTORE_ERRNO(nvl->nvl_error);
- } else
- nvlist_move_nvpair(nvl, nvp);
-}
-
-#ifndef _KERNEL
-void
-nvlist_add_descriptor(nvlist_t *nvl, const char *name, int value)
-{
- nvpair_t *nvp;
-
- if (nvlist_error(nvl) != 0) {
- errno = nvlist_error(nvl);
- return;
- }
-
- nvp = nvpair_create_descriptor(name, value);
- if (nvp == NULL)
- nvl->nvl_error = errno = (errno != 0 ? errno : ENOMEM);
- else
- nvlist_move_nvpair(nvl, nvp);
-}
-#endif
-
-void
-nvlist_add_binary(nvlist_t *nvl, const char *name, const void *value,
- size_t size)
-{
- nvpair_t *nvp;
-
- if (nvlist_error(nvl) != 0) {
- RESTORE_ERRNO(nvlist_error(nvl));
- return;
- }
-
- nvp = nvpair_create_binary(name, value, size);
- if (nvp == NULL) {
- nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
- RESTORE_ERRNO(nvl->nvl_error);
- } else
- nvlist_move_nvpair(nvl, nvp);
-}
-
-void
-nvlist_move_nvpair(nvlist_t *nvl, nvpair_t *nvp)
-{
-
- NVPAIR_ASSERT(nvp);
- PJDLOG_ASSERT(nvpair_nvlist(nvp) == NULL);
-
- if (nvlist_error(nvl) != 0) {
- nvpair_free(nvp);
- RESTORE_ERRNO(nvlist_error(nvl));
- return;
- }
- if (nvlist_exists(nvl, nvpair_name(nvp))) {
- nvpair_free(nvp);
- nvl->nvl_error = EEXIST;
- RESTORE_ERRNO(nvl->nvl_error);
- return;
- }
-
- nvpair_insert(&nvl->nvl_head, nvp, nvl);
-}
-
-void
-nvlist_move_string(nvlist_t *nvl, const char *name, char *value)
-{
- nvpair_t *nvp;
-
- if (nvlist_error(nvl) != 0) {
- nv_free(value);
- RESTORE_ERRNO(nvlist_error(nvl));
- return;
- }
-
- nvp = nvpair_move_string(name, value);
- if (nvp == NULL) {
- nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
- RESTORE_ERRNO(nvl->nvl_error);
- } else
- nvlist_move_nvpair(nvl, nvp);
-}
-
-void
-nvlist_move_nvlist(nvlist_t *nvl, const char *name, nvlist_t *value)
-{
- nvpair_t *nvp;
-
- if (nvlist_error(nvl) != 0) {
- if (value != NULL && nvlist_get_nvpair_parent(value) != NULL)
- nvlist_destroy(value);
- RESTORE_ERRNO(nvlist_error(nvl));
- return;
- }
-
- nvp = nvpair_move_nvlist(name, value);
- if (nvp == NULL) {
- nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
- RESTORE_ERRNO(nvl->nvl_error);
- } else
- nvlist_move_nvpair(nvl, nvp);
-}
-
-#ifndef _KERNEL
-void
-nvlist_move_descriptor(nvlist_t *nvl, const char *name, int value)
-{
- nvpair_t *nvp;
-
- if (nvlist_error(nvl) != 0) {
- close(value);
- errno = nvlist_error(nvl);
- return;
- }
-
- nvp = nvpair_move_descriptor(name, value);
- if (nvp == NULL)
- nvl->nvl_error = errno = (errno != 0 ? errno : ENOMEM);
- else
- nvlist_move_nvpair(nvl, nvp);
-}
-#endif
-
-void
-nvlist_move_binary(nvlist_t *nvl, const char *name, void *value, size_t size)
-{
- nvpair_t *nvp;
-
- if (nvlist_error(nvl) != 0) {
- nv_free(value);
- RESTORE_ERRNO(nvlist_error(nvl));
- return;
- }
-
- nvp = nvpair_move_binary(name, value, size);
- if (nvp == NULL) {
- nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
- RESTORE_ERRNO(nvl->nvl_error);
- } else
- nvlist_move_nvpair(nvl, nvp);
-}
-
-const nvpair_t *
-nvlist_get_nvpair(const nvlist_t *nvl, const char *name)
-{
-
- return (nvlist_find(nvl, NV_TYPE_NONE, name));
-}
-
-#define NVLIST_GET(ftype, type, TYPE) \
-ftype \
-nvlist_get_##type(const nvlist_t *nvl, const char *name) \
-{ \
- const nvpair_t *nvp; \
- \
- nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name); \
- if (nvp == NULL) \
- nvlist_report_missing(NV_TYPE_##TYPE, name); \
- return (nvpair_get_##type(nvp)); \
-}
-
-NVLIST_GET(bool, bool, BOOL)
-NVLIST_GET(uint64_t, number, NUMBER)
-NVLIST_GET(const char *, string, STRING)
-NVLIST_GET(const nvlist_t *, nvlist, NVLIST)
-#ifndef _KERNEL
-NVLIST_GET(int, descriptor, DESCRIPTOR)
-#endif
-
-#undef NVLIST_GET
-
-const void *
-nvlist_get_binary(const nvlist_t *nvl, const char *name, size_t *sizep)
-{
- nvpair_t *nvp;
-
- nvp = nvlist_find(nvl, NV_TYPE_BINARY, name);
- if (nvp == NULL)
- nvlist_report_missing(NV_TYPE_BINARY, name);
-
- return (nvpair_get_binary(nvp, sizep));
-}
-
-#define NVLIST_TAKE(ftype, type, TYPE) \
-ftype \
-nvlist_take_##type(nvlist_t *nvl, const char *name) \
-{ \
- nvpair_t *nvp; \
- ftype value; \
- \
- nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name); \
- if (nvp == NULL) \
- nvlist_report_missing(NV_TYPE_##TYPE, name); \
- value = (ftype)(intptr_t)nvpair_get_##type(nvp); \
- nvlist_remove_nvpair(nvl, nvp); \
- nvpair_free_structure(nvp); \
- return (value); \
-}
-
-NVLIST_TAKE(bool, bool, BOOL)
-NVLIST_TAKE(uint64_t, number, NUMBER)
-NVLIST_TAKE(char *, string, STRING)
-NVLIST_TAKE(nvlist_t *, nvlist, NVLIST)
-#ifndef _KERNEL
-NVLIST_TAKE(int, descriptor, DESCRIPTOR)
-#endif
-
-#undef NVLIST_TAKE
-
-void *
-nvlist_take_binary(nvlist_t *nvl, const char *name, size_t *sizep)
-{
- nvpair_t *nvp;
- void *value;
-
- nvp = nvlist_find(nvl, NV_TYPE_BINARY, name);
- if (nvp == NULL)
- nvlist_report_missing(NV_TYPE_BINARY, name);
-
- value = (void *)(intptr_t)nvpair_get_binary(nvp, sizep);
- nvlist_remove_nvpair(nvl, nvp);
- nvpair_free_structure(nvp);
- return (value);
-}
-
-void
-nvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp)
-{
-
- NVLIST_ASSERT(nvl);
- NVPAIR_ASSERT(nvp);
- PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
-
- nvpair_remove(&nvl->nvl_head, nvp, nvl);
-}
-
-void
-nvlist_free(nvlist_t *nvl, const char *name)
-{
-
- nvlist_free_type(nvl, name, NV_TYPE_NONE);
-}
-
-#define NVLIST_FREE(type, TYPE) \
-void \
-nvlist_free_##type(nvlist_t *nvl, const char *name) \
-{ \
- \
- nvlist_free_type(nvl, name, NV_TYPE_##TYPE); \
-}
-
-NVLIST_FREE(null, NULL)
-NVLIST_FREE(bool, BOOL)
-NVLIST_FREE(number, NUMBER)
-NVLIST_FREE(string, STRING)
-NVLIST_FREE(nvlist, NVLIST)
-#ifndef _KERNEL
-NVLIST_FREE(descriptor, DESCRIPTOR)
-#endif
-NVLIST_FREE(binary, BINARY)
-
-#undef NVLIST_FREE
-
-void
-nvlist_free_nvpair(nvlist_t *nvl, nvpair_t *nvp)
-{
-
- NVLIST_ASSERT(nvl);
- NVPAIR_ASSERT(nvp);
- PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
-
- nvlist_remove_nvpair(nvl, nvp);
- nvpair_free(nvp);
-}
-
Index: sys/kern/subr_nvpair.c
===================================================================
--- sys/kern/subr_nvpair.c
+++ sys/kern/subr_nvpair.c
@@ -1,1111 +0,0 @@
-/*-
- * Copyright (c) 2009-2013 The FreeBSD Foundation
- * All rights reserved.
- *
- * This software was developed by Pawel Jakub Dawidek under sponsorship from
- * the FreeBSD Foundation.
- *
- * 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 AUTHORS 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 AUTHORS 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/endian.h>
-#include <sys/queue.h>
-
-#ifdef _KERNEL
-
-#include <sys/errno.h>
-#include <sys/lock.h>
-#include <sys/malloc.h>
-#include <sys/systm.h>
-
-#include <machine/stdarg.h>
-
-#else
-#include <errno.h>
-#include <fcntl.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "common_impl.h"
-#endif
-
-#ifdef HAVE_PJDLOG
-#include <pjdlog.h>
-#endif
-
-#include <sys/nv.h>
-#include <sys/nv_impl.h>
-#include <sys/nvlist_impl.h>
-#include <sys/nvpair_impl.h>
-
-#ifndef HAVE_PJDLOG
-#ifdef _KERNEL
-#define PJDLOG_ASSERT(...) MPASS(__VA_ARGS__)
-#define PJDLOG_RASSERT(expr, ...) KASSERT(expr, (__VA_ARGS__))
-#define PJDLOG_ABORT(...) panic(__VA_ARGS__)
-#else
-#include <assert.h>
-#define PJDLOG_ASSERT(...) assert(__VA_ARGS__)
-#define PJDLOG_RASSERT(expr, ...) assert(expr)
-#define PJDLOG_ABORT(...) abort()
-#endif
-#endif
-
-#define NVPAIR_MAGIC 0x6e7670 /* "nvp" */
-struct nvpair {
- int nvp_magic;
- char *nvp_name;
- int nvp_type;
- uint64_t nvp_data;
- size_t nvp_datasize;
- nvlist_t *nvp_list;
- TAILQ_ENTRY(nvpair) nvp_next;
-};
-
-#define NVPAIR_ASSERT(nvp) do { \
- PJDLOG_ASSERT((nvp) != NULL); \
- PJDLOG_ASSERT((nvp)->nvp_magic == NVPAIR_MAGIC); \
-} while (0)
-
-struct nvpair_header {
- uint8_t nvph_type;
- uint16_t nvph_namesize;
- uint64_t nvph_datasize;
-} __packed;
-
-
-void
-nvpair_assert(const nvpair_t *nvp)
-{
-
- NVPAIR_ASSERT(nvp);
-}
-
-nvlist_t *
-nvpair_nvlist(const nvpair_t *nvp)
-{
-
- NVPAIR_ASSERT(nvp);
-
- return (nvp->nvp_list);
-}
-
-nvpair_t *
-nvpair_next(const nvpair_t *nvp)
-{
-
- NVPAIR_ASSERT(nvp);
- PJDLOG_ASSERT(nvp->nvp_list != NULL);
-
- return (TAILQ_NEXT(nvp, nvp_next));
-}
-
-nvpair_t *
-nvpair_prev(const nvpair_t *nvp)
-{
-
- NVPAIR_ASSERT(nvp);
- PJDLOG_ASSERT(nvp->nvp_list != NULL);
-
- return (TAILQ_PREV(nvp, nvl_head, nvp_next));
-}
-
-void
-nvpair_insert(struct nvl_head *head, nvpair_t *nvp, nvlist_t *nvl)
-{
-
- NVPAIR_ASSERT(nvp);
- PJDLOG_ASSERT(nvp->nvp_list == NULL);
- PJDLOG_ASSERT(!nvlist_exists(nvl, nvpair_name(nvp)));
-
- TAILQ_INSERT_TAIL(head, nvp, nvp_next);
- nvp->nvp_list = nvl;
-}
-
-static void
-nvpair_remove_nvlist(nvpair_t *nvp)
-{
- nvlist_t *nvl;
-
- /* XXX: DECONST is bad, mkay? */
- nvl = __DECONST(nvlist_t *, nvpair_get_nvlist(nvp));
- PJDLOG_ASSERT(nvl != NULL);
- nvlist_set_parent(nvl, NULL);
-}
-
-void
-nvpair_remove(struct nvl_head *head, nvpair_t *nvp, const nvlist_t *nvl)
-{
-
- NVPAIR_ASSERT(nvp);
- PJDLOG_ASSERT(nvp->nvp_list == nvl);
-
- if (nvpair_type(nvp) == NV_TYPE_NVLIST)
- nvpair_remove_nvlist(nvp);
-
- TAILQ_REMOVE(head, nvp, nvp_next);
- nvp->nvp_list = NULL;
-}
-
-nvpair_t *
-nvpair_clone(const nvpair_t *nvp)
-{
- nvpair_t *newnvp;
- const char *name;
- const void *data;
- size_t datasize;
-
- NVPAIR_ASSERT(nvp);
-
- name = nvpair_name(nvp);
-
- switch (nvpair_type(nvp)) {
- case NV_TYPE_NULL:
- newnvp = nvpair_create_null(name);
- break;
- case NV_TYPE_BOOL:
- newnvp = nvpair_create_bool(name, nvpair_get_bool(nvp));
- break;
- case NV_TYPE_NUMBER:
- newnvp = nvpair_create_number(name, nvpair_get_number(nvp));
- break;
- case NV_TYPE_STRING:
- newnvp = nvpair_create_string(name, nvpair_get_string(nvp));
- break;
- case NV_TYPE_NVLIST:
- newnvp = nvpair_create_nvlist(name, nvpair_get_nvlist(nvp));
- break;
-#ifndef _KERNEL
- case NV_TYPE_DESCRIPTOR:
- newnvp = nvpair_create_descriptor(name,
- nvpair_get_descriptor(nvp));
- break;
-#endif
- case NV_TYPE_BINARY:
- data = nvpair_get_binary(nvp, &datasize);
- newnvp = nvpair_create_binary(name, data, datasize);
- break;
- default:
- PJDLOG_ABORT("Unknown type: %d.", nvpair_type(nvp));
- }
-
- return (newnvp);
-}
-
-size_t
-nvpair_header_size(void)
-{
-
- return (sizeof(struct nvpair_header));
-}
-
-size_t
-nvpair_size(const nvpair_t *nvp)
-{
-
- NVPAIR_ASSERT(nvp);
-
- return (nvp->nvp_datasize);
-}
-
-unsigned char *
-nvpair_pack_header(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
-{
- struct nvpair_header nvphdr;
- size_t namesize;
-
- NVPAIR_ASSERT(nvp);
-
- nvphdr.nvph_type = nvp->nvp_type;
- namesize = strlen(nvp->nvp_name) + 1;
- PJDLOG_ASSERT(namesize > 0 && namesize <= UINT16_MAX);
- nvphdr.nvph_namesize = namesize;
- nvphdr.nvph_datasize = nvp->nvp_datasize;
- PJDLOG_ASSERT(*leftp >= sizeof(nvphdr));
- memcpy(ptr, &nvphdr, sizeof(nvphdr));
- ptr += sizeof(nvphdr);
- *leftp -= sizeof(nvphdr);
-
- PJDLOG_ASSERT(*leftp >= namesize);
- memcpy(ptr, nvp->nvp_name, namesize);
- ptr += namesize;
- *leftp -= namesize;
-
- return (ptr);
-}
-
-unsigned char *
-nvpair_pack_null(const nvpair_t *nvp, unsigned char *ptr,
- size_t *leftp __unused)
-{
-
- NVPAIR_ASSERT(nvp);
- PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NULL);
-
- return (ptr);
-}
-
-unsigned char *
-nvpair_pack_bool(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
-{
- uint8_t value;
-
- NVPAIR_ASSERT(nvp);
- PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL);
-
- value = (uint8_t)nvp->nvp_data;
-
- PJDLOG_ASSERT(*leftp >= sizeof(value));
- memcpy(ptr, &value, sizeof(value));
- ptr += sizeof(value);
- *leftp -= sizeof(value);
-
- return (ptr);
-}
-
-unsigned char *
-nvpair_pack_number(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
-{
- uint64_t value;
-
- NVPAIR_ASSERT(nvp);
- PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER);
-
- value = (uint64_t)nvp->nvp_data;
-
- PJDLOG_ASSERT(*leftp >= sizeof(value));
- memcpy(ptr, &value, sizeof(value));
- ptr += sizeof(value);
- *leftp -= sizeof(value);
-
- return (ptr);
-}
-
-unsigned char *
-nvpair_pack_string(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
-{
-
- NVPAIR_ASSERT(nvp);
- PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
-
- PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
- memcpy(ptr, (const void *)(intptr_t)nvp->nvp_data, nvp->nvp_datasize);
- ptr += nvp->nvp_datasize;
- *leftp -= nvp->nvp_datasize;
-
- return (ptr);
-}
-
-unsigned char *
-nvpair_pack_nvlist_up(unsigned char *ptr, size_t *leftp)
-{
- struct nvpair_header nvphdr;
- size_t namesize;
- const char *name = "";
-
- namesize = 1;
- nvphdr.nvph_type = NV_TYPE_NVLIST_UP;
- nvphdr.nvph_namesize = namesize;
- nvphdr.nvph_datasize = 0;
- PJDLOG_ASSERT(*leftp >= sizeof(nvphdr));
- memcpy(ptr, &nvphdr, sizeof(nvphdr));
- ptr += sizeof(nvphdr);
- *leftp -= sizeof(nvphdr);
-
- PJDLOG_ASSERT(*leftp >= namesize);
- memcpy(ptr, name, namesize);
- ptr += namesize;
- *leftp -= namesize;
-
- return (ptr);
-}
-
-#ifndef _KERNEL
-unsigned char *
-nvpair_pack_descriptor(const nvpair_t *nvp, unsigned char *ptr, int64_t *fdidxp,
- size_t *leftp)
-{
- int64_t value;
-
- NVPAIR_ASSERT(nvp);
- PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
-
- value = (int64_t)nvp->nvp_data;
- if (value != -1) {
- /*
- * If there is a real descriptor here, we change its number
- * to position in the array of descriptors send via control
- * message.
- */
- PJDLOG_ASSERT(fdidxp != NULL);
-
- value = *fdidxp;
- (*fdidxp)++;
- }
-
- PJDLOG_ASSERT(*leftp >= sizeof(value));
- memcpy(ptr, &value, sizeof(value));
- ptr += sizeof(value);
- *leftp -= sizeof(value);
-
- return (ptr);
-}
-#endif
-
-unsigned char *
-nvpair_pack_binary(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
-{
-
- NVPAIR_ASSERT(nvp);
- PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
-
- PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
- memcpy(ptr, (const void *)(intptr_t)nvp->nvp_data, nvp->nvp_datasize);
- ptr += nvp->nvp_datasize;
- *leftp -= nvp->nvp_datasize;
-
- return (ptr);
-}
-
-void
-nvpair_init_datasize(nvpair_t *nvp)
-{
-
- NVPAIR_ASSERT(nvp);
-
- if (nvp->nvp_type == NV_TYPE_NVLIST) {
- if (nvp->nvp_data == 0) {
- nvp->nvp_datasize = 0;
- } else {
- nvp->nvp_datasize =
- nvlist_size((const nvlist_t *)(intptr_t)nvp->nvp_data);
- }
- }
-}
-
-const unsigned char *
-nvpair_unpack_header(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
- size_t *leftp)
-{
- struct nvpair_header nvphdr;
-
- if (*leftp < sizeof(nvphdr))
- goto failed;
-
- memcpy(&nvphdr, ptr, sizeof(nvphdr));
- ptr += sizeof(nvphdr);
- *leftp -= sizeof(nvphdr);
-
-#if NV_TYPE_FIRST > 0
- if (nvphdr.nvph_type < NV_TYPE_FIRST)
- goto failed;
-#endif
- if (nvphdr.nvph_type > NV_TYPE_LAST &&
- nvphdr.nvph_type != NV_TYPE_NVLIST_UP) {
- goto failed;
- }
-
-#if BYTE_ORDER == BIG_ENDIAN
- if (!isbe) {
- nvphdr.nvph_namesize = le16toh(nvphdr.nvph_namesize);
- nvphdr.nvph_datasize = le64toh(nvphdr.nvph_datasize);
- }
-#else
- if (isbe) {
- nvphdr.nvph_namesize = be16toh(nvphdr.nvph_namesize);
- nvphdr.nvph_datasize = be64toh(nvphdr.nvph_datasize);
- }
-#endif
-
- if (nvphdr.nvph_namesize > NV_NAME_MAX)
- goto failed;
- if (*leftp < nvphdr.nvph_namesize)
- goto failed;
- if (nvphdr.nvph_namesize < 1)
- goto failed;
- if (strnlen((const char *)ptr, nvphdr.nvph_namesize) !=
- (size_t)(nvphdr.nvph_namesize - 1)) {
- goto failed;
- }
-
- memcpy(nvp->nvp_name, ptr, nvphdr.nvph_namesize);
- ptr += nvphdr.nvph_namesize;
- *leftp -= nvphdr.nvph_namesize;
-
- if (*leftp < nvphdr.nvph_datasize)
- goto failed;
-
- nvp->nvp_type = nvphdr.nvph_type;
- nvp->nvp_data = 0;
- nvp->nvp_datasize = nvphdr.nvph_datasize;
-
- return (ptr);
-failed:
- RESTORE_ERRNO(EINVAL);
- return (NULL);
-}
-
-const unsigned char *
-nvpair_unpack_null(bool isbe __unused, nvpair_t *nvp, const unsigned char *ptr,
- size_t *leftp __unused)
-{
-
- PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NULL);
-
- if (nvp->nvp_datasize != 0) {
- RESTORE_ERRNO(EINVAL);
- return (NULL);
- }
-
- return (ptr);
-}
-
-const unsigned char *
-nvpair_unpack_bool(bool isbe __unused, nvpair_t *nvp, const unsigned char *ptr,
- size_t *leftp)
-{
- uint8_t value;
-
- PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL);
-
- if (nvp->nvp_datasize != sizeof(value)) {
- RESTORE_ERRNO(EINVAL);
- return (NULL);
- }
- if (*leftp < sizeof(value)) {
- RESTORE_ERRNO(EINVAL);
- return (NULL);
- }
-
- memcpy(&value, ptr, sizeof(value));
- ptr += sizeof(value);
- *leftp -= sizeof(value);
-
- if (value != 0 && value != 1) {
- RESTORE_ERRNO(EINVAL);
- return (NULL);
- }
-
- nvp->nvp_data = (uint64_t)value;
-
- return (ptr);
-}
-
-const unsigned char *
-nvpair_unpack_number(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
- size_t *leftp)
-{
-
- PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER);
-
- if (nvp->nvp_datasize != sizeof(uint64_t)) {
- RESTORE_ERRNO(EINVAL);
- return (NULL);
- }
- if (*leftp < sizeof(uint64_t)) {
- RESTORE_ERRNO(EINVAL);
- return (NULL);
- }
-
- if (isbe)
- nvp->nvp_data = be64dec(ptr);
- else
- nvp->nvp_data = le64dec(ptr);
- ptr += sizeof(uint64_t);
- *leftp -= sizeof(uint64_t);
-
- return (ptr);
-}
-
-const unsigned char *
-nvpair_unpack_string(bool isbe __unused, nvpair_t *nvp,
- const unsigned char *ptr, size_t *leftp)
-{
-
- PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
-
- if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
- RESTORE_ERRNO(EINVAL);
- return (NULL);
- }
-
- if (strnlen((const char *)ptr, nvp->nvp_datasize) !=
- nvp->nvp_datasize - 1) {
- RESTORE_ERRNO(EINVAL);
- return (NULL);
- }
-
- nvp->nvp_data = (uint64_t)(uintptr_t)nv_strdup((const char *)ptr);
- if (nvp->nvp_data == 0)
- return (NULL);
-
- ptr += nvp->nvp_datasize;
- *leftp -= nvp->nvp_datasize;
-
- return (ptr);
-}
-
-const unsigned char *
-nvpair_unpack_nvlist(bool isbe __unused, nvpair_t *nvp,
- const unsigned char *ptr, size_t *leftp, size_t nfds, nvlist_t **child)
-{
- nvlist_t *value;
-
- PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST);
-
- if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
- RESTORE_ERRNO(EINVAL);
- return (NULL);
- }
-
- value = nvlist_create(0);
- if (value == NULL)
- return (NULL);
-
- ptr = nvlist_unpack_header(value, ptr, nfds, NULL, leftp);
- if (ptr == NULL)
- return (NULL);
-
- nvp->nvp_data = (uint64_t)(uintptr_t)value;
- *child = value;
-
- return (ptr);
-}
-
-#ifndef _KERNEL
-const unsigned char *
-nvpair_unpack_descriptor(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
- size_t *leftp, const int *fds, size_t nfds)
-{
- int64_t idx;
-
- PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
-
- if (nvp->nvp_datasize != sizeof(idx)) {
- errno = EINVAL;
- return (NULL);
- }
- if (*leftp < sizeof(idx)) {
- errno = EINVAL;
- return (NULL);
- }
-
- if (isbe)
- idx = be64dec(ptr);
- else
- idx = le64dec(ptr);
-
- if (idx < 0) {
- errno = EINVAL;
- return (NULL);
- }
-
- if ((size_t)idx >= nfds) {
- errno = EINVAL;
- return (NULL);
- }
-
- nvp->nvp_data = (uint64_t)fds[idx];
-
- ptr += sizeof(idx);
- *leftp -= sizeof(idx);
-
- return (ptr);
-}
-#endif
-
-const unsigned char *
-nvpair_unpack_binary(bool isbe __unused, nvpair_t *nvp,
- const unsigned char *ptr, size_t *leftp)
-{
- void *value;
-
- PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
-
- if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
- RESTORE_ERRNO(EINVAL);
- return (NULL);
- }
-
- value = nv_malloc(nvp->nvp_datasize);
- if (value == NULL)
- return (NULL);
-
- memcpy(value, ptr, nvp->nvp_datasize);
- ptr += nvp->nvp_datasize;
- *leftp -= nvp->nvp_datasize;
-
- nvp->nvp_data = (uint64_t)(uintptr_t)value;
-
- return (ptr);
-}
-
-const unsigned char *
-nvpair_unpack(bool isbe, const unsigned char *ptr, size_t *leftp,
- nvpair_t **nvpp)
-{
- nvpair_t *nvp, *tmp;
-
- nvp = nv_calloc(1, sizeof(*nvp) + NV_NAME_MAX);
- if (nvp == NULL)
- return (NULL);
- nvp->nvp_name = (char *)(nvp + 1);
-
- ptr = nvpair_unpack_header(isbe, nvp, ptr, leftp);
- if (ptr == NULL)
- goto failed;
- tmp = nv_realloc(nvp, sizeof(*nvp) + strlen(nvp->nvp_name) + 1);
- if (tmp == NULL)
- goto failed;
- nvp = tmp;
-
- /* Update nvp_name after realloc(). */
- nvp->nvp_name = (char *)(nvp + 1);
- nvp->nvp_data = 0x00;
- nvp->nvp_magic = NVPAIR_MAGIC;
- *nvpp = nvp;
- return (ptr);
-failed:
- nv_free(nvp);
- return (NULL);
-}
-
-int
-nvpair_type(const nvpair_t *nvp)
-{
-
- NVPAIR_ASSERT(nvp);
-
- return (nvp->nvp_type);
-}
-
-const char *
-nvpair_name(const nvpair_t *nvp)
-{
-
- NVPAIR_ASSERT(nvp);
-
- return (nvp->nvp_name);
-}
-
-static nvpair_t *
-nvpair_allocv(const char *name, int type, uint64_t data, size_t datasize)
-{
- nvpair_t *nvp;
- size_t namelen;
-
- PJDLOG_ASSERT(type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST);
-
- namelen = strlen(name);
- if (namelen >= NV_NAME_MAX) {
- RESTORE_ERRNO(ENAMETOOLONG);
- return (NULL);
- }
-
- nvp = nv_calloc(1, sizeof(*nvp) + namelen + 1);
- if (nvp != NULL) {
- nvp->nvp_name = (char *)(nvp + 1);
- memcpy(nvp->nvp_name, name, namelen);
- nvp->nvp_name[namelen + 1] = '\0';
- nvp->nvp_type = type;
- nvp->nvp_data = data;
- nvp->nvp_datasize = datasize;
- nvp->nvp_magic = NVPAIR_MAGIC;
- }
-
- return (nvp);
-};
-
-nvpair_t *
-nvpair_create_stringf(const char *name, const char *valuefmt, ...)
-{
- va_list valueap;
- nvpair_t *nvp;
-
- va_start(valueap, valuefmt);
- nvp = nvpair_create_stringv(name, valuefmt, valueap);
- va_end(valueap);
-
- return (nvp);
-}
-
-nvpair_t *
-nvpair_create_stringv(const char *name, const char *valuefmt, va_list valueap)
-{
- nvpair_t *nvp;
- char *str;
- int len;
-
- len = nv_vasprintf(&str, valuefmt, valueap);
- if (len < 0)
- return (NULL);
- nvp = nvpair_create_string(name, str);
- if (nvp == NULL)
- nv_free(str);
- return (nvp);
-}
-
-nvpair_t *
-nvpair_create_null(const char *name)
-{
-
- return (nvpair_allocv(name, NV_TYPE_NULL, 0, 0));
-}
-
-nvpair_t *
-nvpair_create_bool(const char *name, bool value)
-{
-
- return (nvpair_allocv(name, NV_TYPE_BOOL, value ? 1 : 0,
- sizeof(uint8_t)));
-}
-
-nvpair_t *
-nvpair_create_number(const char *name, uint64_t value)
-{
-
- return (nvpair_allocv(name, NV_TYPE_NUMBER, value, sizeof(value)));
-}
-
-nvpair_t *
-nvpair_create_string(const char *name, const char *value)
-{
- nvpair_t *nvp;
- size_t size;
- char *data;
-
- if (value == NULL) {
- RESTORE_ERRNO(EINVAL);
- return (NULL);
- }
-
- data = nv_strdup(value);
- if (data == NULL)
- return (NULL);
- size = strlen(value) + 1;
-
- nvp = nvpair_allocv(name, NV_TYPE_STRING, (uint64_t)(uintptr_t)data,
- size);
- if (nvp == NULL)
- nv_free(data);
-
- return (nvp);
-}
-
-nvpair_t *
-nvpair_create_nvlist(const char *name, const nvlist_t *value)
-{
- nvlist_t *nvl;
- nvpair_t *nvp;
-
- if (value == NULL) {
- RESTORE_ERRNO(EINVAL);
- return (NULL);
- }
-
- nvl = nvlist_clone(value);
- if (nvl == NULL)
- return (NULL);
-
- nvp = nvpair_allocv(name, NV_TYPE_NVLIST, (uint64_t)(uintptr_t)nvl, 0);
- if (nvp == NULL)
- nvlist_destroy(nvl);
- else
- nvlist_set_parent(nvl, nvp);
-
- return (nvp);
-}
-
-#ifndef _KERNEL
-nvpair_t *
-nvpair_create_descriptor(const char *name, int value)
-{
- nvpair_t *nvp;
-
- if (value < 0 || !fd_is_valid(value)) {
- errno = EBADF;
- return (NULL);
- }
-
- value = fcntl(value, F_DUPFD_CLOEXEC, 0);
- if (value < 0)
- return (NULL);
-
- nvp = nvpair_allocv(name, NV_TYPE_DESCRIPTOR, (uint64_t)value,
- sizeof(int64_t));
- if (nvp == NULL)
- close(value);
-
- return (nvp);
-}
-#endif
-
-nvpair_t *
-nvpair_create_binary(const char *name, const void *value, size_t size)
-{
- nvpair_t *nvp;
- void *data;
-
- if (value == NULL || size == 0) {
- RESTORE_ERRNO(EINVAL);
- return (NULL);
- }
-
- data = nv_malloc(size);
- if (data == NULL)
- return (NULL);
- memcpy(data, value, size);
-
- nvp = nvpair_allocv(name, NV_TYPE_BINARY, (uint64_t)(uintptr_t)data,
- size);
- if (nvp == NULL)
- nv_free(data);
-
- return (nvp);
-}
-
-nvpair_t *
-nvpair_move_string(const char *name, char *value)
-{
- nvpair_t *nvp;
- int serrno;
-
- if (value == NULL) {
- RESTORE_ERRNO(EINVAL);
- return (NULL);
- }
-
- nvp = nvpair_allocv(name, NV_TYPE_STRING, (uint64_t)(uintptr_t)value,
- strlen(value) + 1);
- if (nvp == NULL) {
- SAVE_ERRNO(serrno);
- nv_free(value);
- RESTORE_ERRNO(serrno);
- }
-
- return (nvp);
-}
-
-nvpair_t *
-nvpair_move_nvlist(const char *name, nvlist_t *value)
-{
- nvpair_t *nvp;
-
- if (value == NULL || nvlist_get_nvpair_parent(value) != NULL) {
- RESTORE_ERRNO(EINVAL);
- return (NULL);
- }
-
- if (nvlist_error(value) != 0) {
- RESTORE_ERRNO(nvlist_error(value));
- nvlist_destroy(value);
- return (NULL);
- }
-
- nvp = nvpair_allocv(name, NV_TYPE_NVLIST, (uint64_t)(uintptr_t)value,
- 0);
- if (nvp == NULL)
- nvlist_destroy(value);
- else
- nvlist_set_parent(value, nvp);
-
- return (nvp);
-}
-
-#ifndef _KERNEL
-nvpair_t *
-nvpair_move_descriptor(const char *name, int value)
-{
- nvpair_t *nvp;
- int serrno;
-
- if (value < 0 || !fd_is_valid(value)) {
- errno = EBADF;
- return (NULL);
- }
-
- nvp = nvpair_allocv(name, NV_TYPE_DESCRIPTOR, (uint64_t)value,
- sizeof(int64_t));
- if (nvp == NULL) {
- serrno = errno;
- close(value);
- errno = serrno;
- }
-
- return (nvp);
-}
-#endif
-
-nvpair_t *
-nvpair_move_binary(const char *name, void *value, size_t size)
-{
- nvpair_t *nvp;
- int serrno;
-
- if (value == NULL || size == 0) {
- RESTORE_ERRNO(EINVAL);
- return (NULL);
- }
-
- nvp = nvpair_allocv(name, NV_TYPE_BINARY, (uint64_t)(uintptr_t)value,
- size);
- if (nvp == NULL) {
- SAVE_ERRNO(serrno);
- nv_free(value);
- RESTORE_ERRNO(serrno);
- }
-
- return (nvp);
-}
-
-bool
-nvpair_get_bool(const nvpair_t *nvp)
-{
-
- NVPAIR_ASSERT(nvp);
-
- return (nvp->nvp_data == 1);
-}
-
-uint64_t
-nvpair_get_number(const nvpair_t *nvp)
-{
-
- NVPAIR_ASSERT(nvp);
-
- return (nvp->nvp_data);
-}
-
-const char *
-nvpair_get_string(const nvpair_t *nvp)
-{
-
- NVPAIR_ASSERT(nvp);
- PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
-
- return ((const char *)(intptr_t)nvp->nvp_data);
-}
-
-const nvlist_t *
-nvpair_get_nvlist(const nvpair_t *nvp)
-{
-
- NVPAIR_ASSERT(nvp);
- PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST);
-
- return ((const nvlist_t *)(intptr_t)nvp->nvp_data);
-}
-
-#ifndef _KERNEL
-int
-nvpair_get_descriptor(const nvpair_t *nvp)
-{
-
- NVPAIR_ASSERT(nvp);
- PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
-
- return ((int)nvp->nvp_data);
-}
-#endif
-
-const void *
-nvpair_get_binary(const nvpair_t *nvp, size_t *sizep)
-{
-
- NVPAIR_ASSERT(nvp);
- PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
-
- if (sizep != NULL)
- *sizep = nvp->nvp_datasize;
- return ((const void *)(intptr_t)nvp->nvp_data);
-}
-
-void
-nvpair_free(nvpair_t *nvp)
-{
-
- NVPAIR_ASSERT(nvp);
- PJDLOG_ASSERT(nvp->nvp_list == NULL);
-
- nvp->nvp_magic = 0;
- switch (nvp->nvp_type) {
-#ifndef _KERNEL
- case NV_TYPE_DESCRIPTOR:
- close((int)nvp->nvp_data);
- break;
-#endif
- case NV_TYPE_NVLIST:
- nvlist_destroy((nvlist_t *)(intptr_t)nvp->nvp_data);
- break;
- case NV_TYPE_STRING:
- nv_free((char *)(intptr_t)nvp->nvp_data);
- break;
- case NV_TYPE_BINARY:
- nv_free((void *)(intptr_t)nvp->nvp_data);
- break;
- }
- nv_free(nvp);
-}
-
-void
-nvpair_free_structure(nvpair_t *nvp)
-{
-
- NVPAIR_ASSERT(nvp);
- PJDLOG_ASSERT(nvp->nvp_list == NULL);
-
- nvp->nvp_magic = 0;
- nv_free(nvp);
-}
-
-const char *
-nvpair_type_string(int type)
-{
-
- switch (type) {
- case NV_TYPE_NULL:
- return ("NULL");
- case NV_TYPE_BOOL:
- return ("BOOL");
- case NV_TYPE_NUMBER:
- return ("NUMBER");
- case NV_TYPE_STRING:
- return ("STRING");
- case NV_TYPE_NVLIST:
- return ("NVLIST");
- case NV_TYPE_DESCRIPTOR:
- return ("DESCRIPTOR");
- case NV_TYPE_BINARY:
- return ("BINARY");
- default:
- return ("<UNKNOWN>");
- }
-}
-
Index: sys/modules/ixl/Makefile
===================================================================
--- sys/modules/ixl/Makefile
+++ sys/modules/ixl/Makefile
@@ -5,7 +5,7 @@
.PATH: ${.CURDIR}/../../dev/ixl
KMOD = if_ixl
-SRCS = device_if.h bus_if.h pci_if.h opt_bdg.h
+SRCS = device_if.h bus_if.h pci_if.h pci_iov_if.h opt_bdg.h
SRCS += opt_inet.h opt_inet6.h
SRCS += if_ixl.c ixl_txrx.c i40e_osdep.c
Index: sys/sys/bus.h
===================================================================
--- sys/sys/bus.h
+++ sys/sys/bus.h
@@ -465,6 +465,7 @@
void device_set_desc(device_t dev, const char* desc);
void device_set_desc_copy(device_t dev, const char* desc);
int device_set_devclass(device_t dev, const char *classname);
+int device_set_devclass_fixed(device_t dev, const char *classname);
int device_set_driver(device_t dev, driver_t *driver);
void device_set_flags(device_t dev, u_int32_t flags);
void device_set_softc(device_t dev, void *softc);
Index: sys/sys/iov.h
===================================================================
--- sys/sys/iov.h
+++ sys/sys/iov.h
@@ -0,0 +1,257 @@
+/*-
+ * 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 _SYS_IOV_H_
+#define _SYS_IOV_H_
+
+#include <sys/ioccom.h>
+
+#define PF_CONFIG_NAME "PF"
+#define VF_SCHEMA_NAME "VF"
+
+#define VF_PREFIX "VF-"
+#define VF_PREFIX_LEN 3
+#define VF_NUM_LEN 5 /* The maximum VF num is 65535. */
+#define VF_MAX_NAME (VF_PREFIX_LEN + VF_NUM_LEN + 1)
+
+#define DRIVER_CONFIG_NAME "DRIVER"
+#define IOV_CONFIG_NAME "IOV"
+
+#define TYPE_SCHEMA_NAME "TYPE"
+#define DEFAULT_SCHEMA_NAME "DEFAULT"
+#define REQUIRED_SCHEMA_NAME "REQUIRED"
+
+/*
+ * Because each PF device is expected to expose a unique set of possible
+ * configurations, the SR-IOV infrastructure dynamically queries the PF
+ * driver for its capabilities. These capabilities are exposed to userland
+ * with a configuration schema. The schema is exported from the kernel as a
+ * packed nvlist. See nv(3) for the details of the nvlist API. The expected
+ * format of the nvlist is:
+ *
+ * BASIC RULES
+ * 1) All keys are case-insensitive.
+ * 2) No keys that are not specified below may exist at any level of the
+ * schema.
+ * 3) All keys are mandatory unless explicitly documented as optional. If a
+ * key is mandatory then the associated value is also mandatory.
+ * 4) Order of keys is irrelevant.
+ *
+ * TOP LEVEL
+ * 1) There must be a top-level key with the name PF_CONFIG_NAME. The value
+ * associated with this key is a nvlist that follows the device schema
+ * node format. The parameters in this node specify the configuration
+ * parameters that may be applied to a PF.
+ * 2) There must be a top-level key with the name VF_SCHEMA_NAME. The value
+ * associated with this key is a nvlist that follows the device schema
+ * node format. The parameters in this node specify the configuration
+ * parameters that may be applied to a VF.
+ *
+ * DEVICE SCHEMA NODE
+ * 1) There must be a key with the name DRIVER_CONFIG_NAME. The value
+ * associated with this key is a nvlist that follows the device/subsystem
+ * schema node format. The parameters in this node specify the
+ * configuration parameters that are specific to a particular device
+ * driver.
+ * 2) There must be a key with the name IOV_CONFIG_NAME. The value associated
+ * with this key is an nvlist that follows the device/subsystem schema node
+ * format. The parameters in this node specify the configuration
+ * parameters that are applied by the SR-IOV infrastructure.
+ *
+ * DEVICE/SUBSYSTEM SCHEMA NODE
+ * 1) All keys in the device/subsystem schema node are optional.
+ * 2) Each key specifies the name of a valid configuration parameter that may
+ * be applied to the device/subsystem combination specified by this node.
+ * The value associated with the key specifies the format of valid
+ * configuration values, and must be a nvlist in parameter schema node
+ * format.
+ *
+ * PARAMETER SCHEMA NODE
+ * 1) The parameter schema node must contain a key with the name
+ * TYPE_SCHEMA_NAME. The value associated with this key must be a string.
+ * This string specifies the type of value that the parameter specified by
+ * this node must take. The string must have one of the following values:
+ * - "bool" - The configuration value must be a boolean.
+ * - "mac-addr" - The configuration value must be a binary value. In
+ * addition, the value must be exactly 6 bytes long and
+ * the value must not be a multicast or broadcast mac.
+ * - "uint8_t" - The configuration value must be a integer value in
+ * the range [0, UINT8_MAX].
+ * - "uint16_t" - The configuration value must be a integer value in
+ * the range [0, UINT16_MAX].
+ * - "uint32_t" - The configuration value must be a integer value in
+ * the range [0, UINT32_MAX].
+ * - "uint64_t" - The configuration value must be a integer value in
+ * the range [0, UINT64_MAX].
+ * 2) The parameter schema may contain a key with the name
+ * REQUIRED_SCHEMA_NAME. This key is optional. If this key is present, the
+ * value associated with it must have a boolean type. If the value is true,
+ * then the parameter specified by this schema is a required parameter. All
+ * valid configurations must include all required parameters.
+ * 3) The parameter schema may contain a key with the name DEFAULT_SCHEMA_NAME.
+ * This key is optional. This key must not be present if the parameter
+ * specified by this schema is required. If this key is present, the value
+ * associated with the parent key must follow all restrictions specified by
+ * the type specified by this schema. If a configuration does not supply a
+ * value for the parameter specified by this schema, then the kernel will
+ * apply the value associated with this key in its place.
+ *
+ * The following is an example of a valid schema, as printed by nvlist_dump.
+ * Keys are printed followed by the type of the value in parantheses. The
+ * value is displayed following a colon. The indentation level reflects the
+ * level of nesting of nvlists. String values are displayed between []
+ * brackets. Binary values are shown with the length of the binary value (in
+ * bytes) followed by the actual binary values.
+ *
+ * PF (NVLIST):
+ * IOV (NVLIST):
+ * num_vfs (NVLIST):
+ * type (STRING): [uint16_t]
+ * required (BOOL): TRUE
+ * device (NVLIST):
+ * type (STRING): [string]
+ * required (BOOL): TRUE
+ * DRIVER (NVLIST):
+ * VF (NVLIST):
+ * IOV (NVLIST):
+ * passthrough (NVLIST):
+ * type (STRING): [bool]
+ * default (BOOL): FALSE
+ * DRIVER (NVLIST):
+ * mac-addr (NVLIST):
+ * type (STRING): [mac-addr]
+ * default (BINARY): 6 000000000000
+ * vlan (NVLIST):
+ * type (STRING): [uint16_t]
+ * spoof-check (NVLIST):
+ * type (STRING): [bool]
+ * default (BOOL): TRUE
+ * allow-set-mac (NVLIST):
+ * type (STRING): [bool]
+ * default (BOOL): FALSE
+ */
+struct pci_iov_schema
+{
+ void *schema;
+ size_t len;
+ int error;
+};
+
+/*
+ * SR-IOV configuration is passed to the kernel as a packed nvlist. See nv(3)
+ * for the details of the nvlist API. The expected format of the nvlist is:
+ *
+ * BASIC RULES
+ * 1) All keys are case-insensitive.
+ * 2) No keys that are not specified below may exist at any level of the
+ * config nvlist.
+ * 3) Unless otherwise specified, all keys are optional. It should go without
+ * saying a key being mandatory is transitive: that is, if a key is
+ * specified to contain a sub-nodes that contains a mandatory key, then
+ * the outer key is implicitly mandatory. If a key is mandatory then the
+ * associated value is also mandatory.
+ * 4) Order of keys is irrelevant.
+ *
+ * TOP LEVEL OF CONFIG NVLIST
+ * 1) All keys specified in this section are mandatory.
+ * 2) There must be a top-level key with the name PF_CONFIG_NAME. The value
+ * associated is an nvlist that follows the "device node" format. The
+ * parameters in this node specify parameters that apply to the PF.
+ * 3) For every VF being configured (this is set via the "num_vfs" parameter
+ * in the PF section), there must be a top-level key whose name is VF_PREFIX
+ * immediately followed by the index of the VF as a decimal integer. For
+ * example, this would be VF-0 for the first VF. VFs are numbered starting
+ * from 0. The value associated with this key follows the "device node"
+ * format. The parameters in this node specify configuration that applies
+ * to the VF specified in the key. Leading zeros are not permitted in VF
+ * index. Configuration for the second VF must be specified in a node with
+ * the key VF-1. VF-01 is not a valid key.
+ *
+ * DEVICE NODES
+ * 1) All keys specified in this section are mandatory.
+ * 2) The device node must contain a key with the name DRIVER_CONFIG_NAME. The
+ * value associated with this key is an nvlist following the subsystem node
+ * format. The parameters in this key specify configuration that is specific
+ * to a particular device driver.
+ * 3) The device node must contain a key with the name IOV_CONFIG_NAME. The
+ * value associated with this key is an nvlist following the subsystem node
+ * format. The parameters in this key specify configuration that is consumed
+ * by the SR-IOV infrastructure.
+ *
+ * SUBSYSTEM NODES
+ * 1) A subsystem node specifies configuration parameters that apply to a
+ * particular subsystem (driver or infrastructure) of a particular device
+ * (PF or individual VF).
+ * Note: We will refer to the section of the configuration schema that
+ * specifies the parameters for this subsystem and device
+ * configuration as the device/subystem schema.
+ * 2) The subsystem node must contain only keys that correspond to parameters
+ * that are specified in the device/subsystem schema.
+ * 3) Every parameter specified as required in the device/subsystem schema is
+ * a mandatory key in the subsystem node.
+ * Note: All parameters that are not required in device/subsystem schema are
+ * optional keys. In particular, any parameter specified to have a
+ * default value in the device/subsystem schema is optional. The
+ * kernel is responsible for applying default values.
+ * 4) The value of every parameter in the device node must conform to the
+ * restrictions of the type specified for that parameter in the device/
+ * subsystem schema.
+ *
+ * The following is an example of a valid configuration, when validated against
+ * the schema example given above.
+ *
+ * PF (NVLIST):
+ * driver (NVLIST):
+ * iov (NVLIST):
+ * num_vfs (NUMBER): 3 (3) (0x3)
+ * device (STRING): [ix0]
+ * VF-0 (NVLIST):
+ * driver (NVLIST):
+ * vlan (NUMBER): 1000 (1000) (0x3e8)
+ * iov (NVLIST):
+ * passthrough (BOOL): TRUE
+ * VF-1 (NVLIST):
+ * driver (NVLIST):
+ * iov (NVLIST):
+ * VF-2 (NVLIST):
+ * driver (NVLIST):
+ * mac-addr (BINARY): 6 020102030405
+ * iov (NVLIST):
+ */
+struct pci_iov_arg
+{
+ void *config;
+ size_t len;
+};
+
+#define IOV_CONFIG _IOW('p', 10, struct pci_iov_arg)
+#define IOV_DELETE _IO('p', 11)
+#define IOV_GET_SCHEMA _IOWR('p', 12, struct pci_iov_schema)
+
+#endif
+
Index: sys/sys/iov_schema.h
===================================================================
--- sys/sys/iov_schema.h
+++ sys/sys/iov_schema.h
@@ -0,0 +1,52 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SYS_IOV_SCHEMA_H_
+#define _SYS_IOV_SCHEMA_H_
+
+#define IOV_SCHEMA_HASDEFAULT (1 << 0)
+#define IOV_SCHEMA_REQUIRED (1 << 1)
+
+nvlist_t *pci_iov_schema_alloc_node(void);
+
+void pci_iov_schema_add_bool(nvlist_t *schema, const char *name,
+ uint32_t flags, int defaultVal);
+void pci_iov_schema_add_string(nvlist_t *schema, const char *name,
+ uint32_t flags, const char *defaultVal);
+void pci_iov_schema_add_uint8(nvlist_t *schema, const char *name,
+ uint32_t flags, uint8_t defaultVal);
+void pci_iov_schema_add_uint16(nvlist_t *schema, const char *name,
+ uint32_t flags, uint16_t defaultVal);
+void pci_iov_schema_add_uint32(nvlist_t *schema, const char *name,
+ uint32_t flags, uint32_t defaultVal);
+void pci_iov_schema_add_uint64(nvlist_t *schema, const char *name,
+ uint32_t flags, uint64_t defaultVal);
+void pci_iov_schema_add_unicast_mac(nvlist_t *schema, const char *name,
+ uint32_t flags, const uint8_t * defaultVal);
+
+#endif
Index: sys/sys/nv.h
===================================================================
--- sys/sys/nv.h
+++ sys/sys/nv.h
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2009-2013 The FreeBSD Foundation
+ * Copyright (c) 2013-2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
* All rights reserved.
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
@@ -59,11 +60,20 @@
#define NV_TYPE_NVLIST 5
#define NV_TYPE_DESCRIPTOR 6
#define NV_TYPE_BINARY 7
+#define NV_TYPE_BOOL_ARRAY 8
+#define NV_TYPE_NUMBER_ARRAY 9
+#define NV_TYPE_STRING_ARRAY 10
+#define NV_TYPE_NVLIST_ARRAY 11
+#define NV_TYPE_DESCRIPTOR_ARRAY 12
/*
* Perform case-insensitive lookups of provided names.
*/
#define NV_FLAG_IGNORE_CASE 0x01
+/*
+ * Names don't have to be unique.
+ */
+#define NV_FLAG_NO_UNIQUE 0x02
#if defined(_KERNEL) && defined(MALLOC_DECLARE)
MALLOC_DECLARE(M_NVLIST);
@@ -87,16 +97,21 @@
size_t nvlist_size(const nvlist_t *nvl);
void *nvlist_pack(const nvlist_t *nvl, size_t *sizep);
-nvlist_t *nvlist_unpack(const void *buf, size_t size);
+nvlist_t *nvlist_unpack(const void *buf, size_t size, int flags);
int nvlist_send(int sock, const nvlist_t *nvl);
-nvlist_t *nvlist_recv(int sock);
-nvlist_t *nvlist_xfer(int sock, nvlist_t *nvl);
+nvlist_t *nvlist_recv(int sock, int flags);
+nvlist_t *nvlist_xfer(int sock, nvlist_t *nvl, int flags);
const char *nvlist_next(const nvlist_t *nvl, int *typep, void **cookiep);
const nvlist_t *nvlist_get_parent(const nvlist_t *nvl, void **cookiep);
+const nvlist_t *nvlist_get_array_next(const nvlist_t *nvl);
+bool nvlist_in_array(const nvlist_t *nvl);
+
+const nvlist_t *nvlist_get_pararr(const nvlist_t *nvl, void **cookiep);
+
/*
* The nvlist_exists functions check if the given name (optionally of the given
* type) exists on nvlist.
@@ -110,10 +125,15 @@
bool nvlist_exists_number(const nvlist_t *nvl, const char *name);
bool nvlist_exists_string(const nvlist_t *nvl, const char *name);
bool nvlist_exists_nvlist(const nvlist_t *nvl, const char *name);
+bool nvlist_exists_binary(const nvlist_t *nvl, const char *name);
+bool nvlist_exists_bool_array(const nvlist_t *nvl, const char *name);
+bool nvlist_exists_number_array(const nvlist_t *nvl, const char *name);
+bool nvlist_exists_string_array(const nvlist_t *nvl, const char *name);
+bool nvlist_exists_nvlist_array(const nvlist_t *nvl, const char *name);
#ifndef _KERNEL
bool nvlist_exists_descriptor(const nvlist_t *nvl, const char *name);
+bool nvlist_exists_descriptor_array(const nvlist_t *nvl, const char *name);
#endif
-bool nvlist_exists_binary(const nvlist_t *nvl, const char *name);
/*
* The nvlist_add functions add the given name/value pair.
@@ -130,10 +150,15 @@
void nvlist_add_stringv(nvlist_t *nvl, const char *name, const char *valuefmt, va_list valueap) __printflike(3, 0);
#endif
void nvlist_add_nvlist(nvlist_t *nvl, const char *name, const nvlist_t *value);
+void nvlist_add_binary(nvlist_t *nvl, const char *name, const void *value, size_t size);
+void nvlist_add_bool_array(nvlist_t *nvl, const char *name, const bool *value, size_t nitems);
+void nvlist_add_number_array(nvlist_t *nvl, const char *name, const uint64_t *value, size_t nitems);
+void nvlist_add_string_array(nvlist_t *nvl, const char *name, const char * const *value, size_t nitems);
+void nvlist_add_nvlist_array(nvlist_t *nvl, const char *name, const nvlist_t * const *value, size_t nitems);
#ifndef _KERNEL
void nvlist_add_descriptor(nvlist_t *nvl, const char *name, int value);
+void nvlist_add_descriptor_array(nvlist_t *nvl, const char *name, const int *value, size_t nitems);
#endif
-void nvlist_add_binary(nvlist_t *nvl, const char *name, const void *value, size_t size);
/*
* The nvlist_move functions add the given name/value pair.
@@ -142,10 +167,15 @@
void nvlist_move_string(nvlist_t *nvl, const char *name, char *value);
void nvlist_move_nvlist(nvlist_t *nvl, const char *name, nvlist_t *value);
+void nvlist_move_binary(nvlist_t *nvl, const char *name, void *value, size_t size);
+void nvlist_move_bool_array(nvlist_t *nvl, const char *name, bool *value, size_t nitems);
+void nvlist_move_string_array(nvlist_t *nvl, const char *name, char **value, size_t nitems);
+void nvlist_move_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **value, size_t nitems);
+void nvlist_move_number_array(nvlist_t *nvl, const char *name, uint64_t *value, size_t nitems);
#ifndef _KERNEL
void nvlist_move_descriptor(nvlist_t *nvl, const char *name, int value);
+void nvlist_move_descriptor_array(nvlist_t *nvl, const char *name, int *value, size_t nitems);
#endif
-void nvlist_move_binary(nvlist_t *nvl, const char *name, void *value, size_t size);
/*
* The nvlist_get functions returns value associated with the given name.
@@ -153,14 +183,19 @@
* not be freed by the caller.
*/
-bool nvlist_get_bool(const nvlist_t *nvl, const char *name);
-uint64_t nvlist_get_number(const nvlist_t *nvl, const char *name);
-const char *nvlist_get_string(const nvlist_t *nvl, const char *name);
-const nvlist_t *nvlist_get_nvlist(const nvlist_t *nvl, const char *name);
+bool nvlist_get_bool(const nvlist_t *nvl, const char *name);
+uint64_t nvlist_get_number(const nvlist_t *nvl, const char *name);
+const char *nvlist_get_string(const nvlist_t *nvl, const char *name);
+const nvlist_t *nvlist_get_nvlist(const nvlist_t *nvl, const char *name);
+const void *nvlist_get_binary(const nvlist_t *nvl, const char *name, size_t *sizep);
+const bool *nvlist_get_bool_array(const nvlist_t *nvl, const char *name, size_t *nitemsp);
+const uint64_t *nvlist_get_number_array(const nvlist_t *nvl, const char *name, size_t *nitemsp);
+const char * const *nvlist_get_string_array(const nvlist_t *nvl, const char *name, size_t *nitemsp);
+const nvlist_t * const *nvlist_get_nvlist_array(const nvlist_t *nvl, const char *name, size_t *nitemsp);
#ifndef _KERNEL
-int nvlist_get_descriptor(const nvlist_t *nvl, const char *name);
+int nvlist_get_descriptor(const nvlist_t *nvl, const char *name);
+const int *nvlist_get_descriptor_array(const nvlist_t *nvl, const char *name, size_t *nitemsp);
#endif
-const void *nvlist_get_binary(const nvlist_t *nvl, const char *name, size_t *sizep);
/*
* The nvlist_take functions returns value associated with the given name and
@@ -168,14 +203,19 @@
* The caller is responsible for freeing received data.
*/
-bool nvlist_take_bool(nvlist_t *nvl, const char *name);
-uint64_t nvlist_take_number(nvlist_t *nvl, const char *name);
-char *nvlist_take_string(nvlist_t *nvl, const char *name);
-nvlist_t *nvlist_take_nvlist(nvlist_t *nvl, const char *name);
+bool nvlist_take_bool(nvlist_t *nvl, const char *name);
+uint64_t nvlist_take_number(nvlist_t *nvl, const char *name);
+char *nvlist_take_string(nvlist_t *nvl, const char *name);
+nvlist_t *nvlist_take_nvlist(nvlist_t *nvl, const char *name);
+void *nvlist_take_binary(nvlist_t *nvl, const char *name, size_t *sizep);
+bool *nvlist_take_bool_array(nvlist_t *nvl, const char *name, size_t *nitemsp);
+uint64_t *nvlist_take_number_array(nvlist_t *nvl, const char *name, size_t *nitemsp);
+char **nvlist_take_string_array(nvlist_t *nvl, const char *name, size_t *nitemsp);
+nvlist_t **nvlist_take_nvlist_array(nvlist_t *nvl, const char *name, size_t *nitemsp);
#ifndef _KERNEL
int nvlist_take_descriptor(nvlist_t *nvl, const char *name);
+int *nvlist_take_descriptor_array(nvlist_t *nvl, const char *name, size_t *nitemsp);
#endif
-void *nvlist_take_binary(nvlist_t *nvl, const char *name, size_t *sizep);
/*
* The nvlist_free functions removes the given name/value pair from the nvlist
@@ -190,10 +230,16 @@
void nvlist_free_number(nvlist_t *nvl, const char *name);
void nvlist_free_string(nvlist_t *nvl, const char *name);
void nvlist_free_nvlist(nvlist_t *nvl, const char *name);
+void nvlist_free_binary(nvlist_t *nvl, const char *name);
+void nvlist_free_bool_array(nvlist_t *nvl, const char *name);
+void nvlist_free_number_array(nvlist_t *nvl, const char *name);
+void nvlist_free_string_array(nvlist_t *nvl, const char *name);
+void nvlist_free_nvlist_array(nvlist_t *nvl, const char *name);
+void nvlist_free_binary_array(nvlist_t *nvl, const char *name);
#ifndef _KERNEL
void nvlist_free_descriptor(nvlist_t *nvl, const char *name);
+void nvlist_free_descriptor_array(nvlist_t *nvl, const char *name);
#endif
-void nvlist_free_binary(nvlist_t *nvl, const char *name);
__END_DECLS
Index: sys/sys/nv_impl.h
===================================================================
--- sys/sys/nv_impl.h
+++ sys/sys/nv_impl.h
@@ -1,131 +0,0 @@
-/*-
- * Copyright (c) 2013 The FreeBSD Foundation
- * All rights reserved.
- *
- * This software was developed by Pawel Jakub Dawidek under sponsorship from
- * the FreeBSD Foundation.
- *
- * 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 AUTHORS 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 AUTHORS 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 _NV_IMPL_H_
-#define _NV_IMPL_H_
-
-#ifndef _NVPAIR_T_DECLARED
-#define _NVPAIR_T_DECLARED
-struct nvpair;
-
-typedef struct nvpair nvpair_t;
-#endif
-
-#define NV_TYPE_NVLIST_UP 255
-
-#define NV_TYPE_FIRST NV_TYPE_NULL
-#define NV_TYPE_LAST NV_TYPE_BINARY
-
-#define NV_FLAG_BIG_ENDIAN 0x80
-
-#ifdef _KERNEL
-#define nv_malloc(size) malloc((size), M_NVLIST, M_NOWAIT)
-#define nv_calloc(n, size) malloc((n) * (size), M_NVLIST, \
- M_NOWAIT | M_ZERO)
-#define nv_realloc(buf, size) realloc((buf), (size), M_NVLIST, \
- M_NOWAIT)
-#define nv_free(buf) free((buf), M_NVLIST)
-#define nv_strdup(buf) strdup((buf), M_NVLIST)
-#define nv_vasprintf(ptr, ...) vasprintf(ptr, M_NVLIST, __VA_ARGS__)
-
-#define SAVE_ERRNO(var) ((void)(var))
-#define RESTORE_ERRNO(var) ((void)(var))
-
-#define ERRNO_OR_DEFAULT(default) (default)
-
-#else
-
-#define nv_malloc(size) malloc((size))
-#define nv_calloc(n, size) calloc((n), (size))
-#define nv_realloc(buf, size) realloc((buf), (size))
-#define nv_free(buf) free((buf))
-#define nv_strdup(buf) strdup((buf))
-#define nv_vasprintf(ptr, ...) vasprintf(ptr, __VA_ARGS__)
-
-#define SAVE_ERRNO(var) (var) = errno
-#define RESTORE_ERRNO(var) errno = (var)
-
-#define ERRNO_OR_DEFAULT(default) (errno == 0 ? (default) : errno)
-
-#endif
-
-int *nvlist_descriptors(const nvlist_t *nvl, size_t *nitemsp);
-size_t nvlist_ndescriptors(const nvlist_t *nvl);
-
-nvpair_t *nvlist_first_nvpair(const nvlist_t *nvl);
-nvpair_t *nvlist_next_nvpair(const nvlist_t *nvl, const nvpair_t *nvp);
-nvpair_t *nvlist_prev_nvpair(const nvlist_t *nvl, const nvpair_t *nvp);
-
-void nvlist_add_nvpair(nvlist_t *nvl, const nvpair_t *nvp);
-
-void nvlist_move_nvpair(nvlist_t *nvl, nvpair_t *nvp);
-
-void nvlist_set_parent(nvlist_t *nvl, nvpair_t *parent);
-
-const nvpair_t *nvlist_get_nvpair(const nvlist_t *nvl, const char *name);
-
-nvpair_t *nvlist_take_nvpair(nvlist_t *nvl, const char *name);
-
-/* Function removes the given nvpair from the nvlist. */
-void nvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp);
-
-void nvlist_free_nvpair(nvlist_t *nvl, nvpair_t *nvp);
-
-int nvpair_type(const nvpair_t *nvp);
-const char *nvpair_name(const nvpair_t *nvp);
-
-nvpair_t *nvpair_clone(const nvpair_t *nvp);
-
-nvpair_t *nvpair_create_null(const char *name);
-nvpair_t *nvpair_create_bool(const char *name, bool value);
-nvpair_t *nvpair_create_number(const char *name, uint64_t value);
-nvpair_t *nvpair_create_string(const char *name, const char *value);
-nvpair_t *nvpair_create_stringf(const char *name, const char *valuefmt, ...) __printflike(2, 3);
-nvpair_t *nvpair_create_stringv(const char *name, const char *valuefmt, va_list valueap) __printflike(2, 0);
-nvpair_t *nvpair_create_nvlist(const char *name, const nvlist_t *value);
-nvpair_t *nvpair_create_descriptor(const char *name, int value);
-nvpair_t *nvpair_create_binary(const char *name, const void *value, size_t size);
-
-nvpair_t *nvpair_move_string(const char *name, char *value);
-nvpair_t *nvpair_move_nvlist(const char *name, nvlist_t *value);
-nvpair_t *nvpair_move_descriptor(const char *name, int value);
-nvpair_t *nvpair_move_binary(const char *name, void *value, size_t size);
-
-bool nvpair_get_bool(const nvpair_t *nvp);
-uint64_t nvpair_get_number(const nvpair_t *nvp);
-const char *nvpair_get_string(const nvpair_t *nvp);
-const nvlist_t *nvpair_get_nvlist(const nvpair_t *nvp);
-int nvpair_get_descriptor(const nvpair_t *nvp);
-const void *nvpair_get_binary(const nvpair_t *nvp, size_t *sizep);
-
-void nvpair_free(nvpair_t *nvp);
-
-#endif /* !_NV_IMPL_H_ */
Index: sys/sys/nvlist_impl.h
===================================================================
--- sys/sys/nvlist_impl.h
+++ sys/sys/nvlist_impl.h
@@ -1,49 +0,0 @@
-/*-
- * Copyright (c) 2013 The FreeBSD Foundation
- * All rights reserved.
- *
- * This software was developed by Pawel Jakub Dawidek under sponsorship from
- * the FreeBSD Foundation.
- *
- * 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 AUTHORS 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 AUTHORS 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 _NVLIST_IMPL_H_
-#define _NVLIST_IMPL_H_
-
-#ifndef _KERNEL
-#include <stdint.h>
-#endif
-
-#include "nv.h"
-
-void *nvlist_xpack(const nvlist_t *nvl, int64_t *fdidxp, size_t *sizep);
-nvlist_t *nvlist_xunpack(const void *buf, size_t size, const int *fds,
- size_t nfds);
-
-nvpair_t *nvlist_get_nvpair_parent(const nvlist_t *nvl);
-const unsigned char *nvlist_unpack_header(nvlist_t *nvl,
- const unsigned char *ptr, size_t nfds, bool *isbep, size_t *leftp);
-
-#endif /* !_NVLIST_IMPL_H_ */
Index: sys/sys/nvpair_impl.h
===================================================================
--- sys/sys/nvpair_impl.h
+++ sys/sys/nvpair_impl.h
@@ -1,94 +0,0 @@
-/*-
- * Copyright (c) 2009-2013 The FreeBSD Foundation
- * All rights reserved.
- *
- * This software was developed by Pawel Jakub Dawidek under sponsorship from
- * the FreeBSD Foundation.
- *
- * 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 AUTHORS 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 AUTHORS 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 _NVPAIR_IMPL_H_
-#define _NVPAIR_IMPL_H_
-
-#include <sys/queue.h>
-
-#ifndef _KERNEL
-#include <stdint.h>
-#endif
-
-#include "nv.h"
-
-TAILQ_HEAD(nvl_head, nvpair);
-
-void nvpair_assert(const nvpair_t *nvp);
-nvlist_t *nvpair_nvlist(const nvpair_t *nvp);
-nvpair_t *nvpair_next(const nvpair_t *nvp);
-nvpair_t *nvpair_prev(const nvpair_t *nvp);
-void nvpair_insert(struct nvl_head *head, nvpair_t *nvp, nvlist_t *nvl);
-void nvpair_remove(struct nvl_head *head, nvpair_t *nvp, const nvlist_t *nvl);
-size_t nvpair_header_size(void);
-size_t nvpair_size(const nvpair_t *nvp);
-const unsigned char *nvpair_unpack(bool isbe, const unsigned char *ptr,
- size_t *leftp, nvpair_t **nvpp);
-void nvpair_free_structure(nvpair_t *nvp);
-void nvpair_init_datasize(nvpair_t *nvp);
-const char *nvpair_type_string(int type);
-
-/* Pack functions. */
-unsigned char *nvpair_pack_header(const nvpair_t *nvp, unsigned char *ptr,
- size_t *leftp);
-unsigned char *nvpair_pack_null(const nvpair_t *nvp, unsigned char *ptr,
- size_t *leftp);
-unsigned char *nvpair_pack_bool(const nvpair_t *nvp, unsigned char *ptr,
- size_t *leftp);
-unsigned char *nvpair_pack_number(const nvpair_t *nvp, unsigned char *ptr,
- size_t *leftp);
-unsigned char *nvpair_pack_string(const nvpair_t *nvp, unsigned char *ptr,
- size_t *leftp);
-unsigned char *nvpair_pack_descriptor(const nvpair_t *nvp, unsigned char *ptr,
- int64_t *fdidxp, size_t *leftp);
-unsigned char *nvpair_pack_binary(const nvpair_t *nvp, unsigned char *ptr,
- size_t *leftp);
-unsigned char *nvpair_pack_nvlist_up(unsigned char *ptr, size_t *leftp);
-
-/* Unpack data functions. */
-const unsigned char *nvpair_unpack_header(bool isbe, nvpair_t *nvp,
- const unsigned char *ptr, size_t *leftp);
-const unsigned char *nvpair_unpack_null(bool isbe, nvpair_t *nvp,
- const unsigned char *ptr, size_t *leftp);
-const unsigned char *nvpair_unpack_bool(bool isbe, nvpair_t *nvp,
- const unsigned char *ptr, size_t *leftp);
-const unsigned char *nvpair_unpack_number(bool isbe, nvpair_t *nvp,
- const unsigned char *ptr, size_t *leftp);
-const unsigned char *nvpair_unpack_string(bool isbe, nvpair_t *nvp,
- const unsigned char *ptr, size_t *leftp);
-const unsigned char *nvpair_unpack_nvlist(bool isbe, nvpair_t *nvp,
- const unsigned char *ptr, size_t *leftp, size_t nvlist, nvlist_t **child);
-const unsigned char *nvpair_unpack_descriptor(bool isbe, nvpair_t *nvp,
- const unsigned char *ptr, size_t *leftp, const int *fds, size_t nfds);
-const unsigned char *nvpair_unpack_binary(bool isbe, nvpair_t *nvp,
- const unsigned char *ptr, size_t *leftp);
-
-#endif /* !_NVPAIR_IMPL_H_ */
Index: usr.sbin/Makefile
===================================================================
--- usr.sbin/Makefile
+++ usr.sbin/Makefile
@@ -35,6 +35,7 @@
i2c \
ifmcstat \
iostat \
+ iovctl \
kldxref \
mailwrapper \
makefs \
Index: usr.sbin/iovctl/Makefile
===================================================================
--- usr.sbin/iovctl/Makefile
+++ usr.sbin/iovctl/Makefile
@@ -0,0 +1,20 @@
+# $FreeBSD$
+
+PROG= iovctl
+SRCS= iovctl.c parse.c validate.c
+DPADD+= ${LIBNV} ${LIBUCL} ${LIBM}
+LDADD+= -lnv -lucl -lm
+
+USEPRIVATELIB=
+
+CFLAGS+=-I${.CURDIR}/../../contrib/libucl/include
+
+WARNS?=6
+
+MAN= \
+ iovctl.8 \
+ iovctl.conf.5 \
+
+.include <bsd.own.mk>
+.include <bsd.prog.mk>
+
Index: usr.sbin/iovctl/iovctl.h
===================================================================
--- usr.sbin/iovctl/iovctl.h
+++ 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
+
Index: usr.sbin/iovctl/iovctl.8
===================================================================
--- usr.sbin/iovctl/iovctl.8
+++ usr.sbin/iovctl/iovctl.8
@@ -0,0 +1,123 @@
+.\"
+.\" Copyright (c) 2014 Sandvine Inc.
+.\" 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$
+.\"
+.Dd July 8, 2015
+.Dt IOVCTL 8
+.Os
+.Sh NAME
+.Nm iovctl
+.Nd "PCI SR-IOV configuration utility"
+.Sh SYNOPSIS
+.Nm
+.Fl C
+.Op Fl f Ar config-file
+.Op Fl n
+.Nm
+.Fl D
+.Op Fl f Ar config-file | Fl d Ar device
+.Op Fl n
+.Nm
+.Fl S
+.Op Fl f Ar config-file | Fl d Ar device
+.Sh DESCRIPTION
+The
+.Nm
+utility creates or destroys PCI Single-Root I/O Virtualization
+.Pq SR-IOV
+Virtual Functions
+.Pq VFs .
+When invoked with the
+.Fl C
+flag,
+.Nm
+creates VFs as children of the Physical Function
+.Pq PF
+configured in the specified configuration file.
+When invoked with the
+.Fl D
+flag,
+.Nm
+destroys all VFs that are children of the specified device.
+Available PF devices can be seen in
+.Pa /dev/iov/ .
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl C
+Enable SR-IOV on the specified PF device and create VF children.
+This operation will fail if the PF already has VF children.
+This option must be used in conjunction with the
+.Fl f
+option.
+.It Fl d Ar device
+Specify the PF device to use for the given operation.
+.Ar device
+may either be the name of a PF device, or a full path name to a node in
+.Pa /dev/iov/ .
+This option may not be used with the
+.Fl C
+option.
+.It Fl D
+Delete all VF children of the specified PF device.
+This operation will fail if SR-IOV is not currently enabled on the specified
+device.
+.It Fl f Ar config-file
+Specify the pathname of the configuration file.
+For the
+.Fl C
+option, this file will be used to specify all configuration values.
+For the
+.Fl D
+and
+.Fl S
+options, this file will only be used to specify the name of the PF device.
+.Pp
+See
+.Xr iovctl.conf
+for a description of the config file format and documentation of the
+configuration parameters that apply to all PF drivers.
+See the PF driver manual page for configuration parameters specific to
+particular hardware.
+.It Fl n
+Perform a dry-run.
+Perform all validation of the specified action and print what would be done,
+but do not perform the actual creation or destruction of VFs.
+This option may not be used with the
+.Fl S
+flag.
+.It Fl S
+Read the configuration schema from the specified device and print its contents
+to stdout.
+This action may be used to discover the configuration parameters supported on
+a given PF device.
+.El
+.Sh SEE ALSO
+.Xr iovctl.conf 5 ,
+.Xr rc.conf 5
+.Sh AUTHORS
+This manual page was written by
+.An Ryan Stone Aq Mt rstone@FreeBSD.org .
Index: usr.sbin/iovctl/iovctl.c
===================================================================
--- usr.sbin/iovctl/iovctl.c
+++ 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 <sys/dnv.h>
+#include <sys/nv.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.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, NV_FLAG_IGNORE_CASE);
+ 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);
+}
Index: usr.sbin/iovctl/iovctl.conf.5
===================================================================
--- usr.sbin/iovctl/iovctl.conf.5
+++ usr.sbin/iovctl/iovctl.conf.5
@@ -0,0 +1,171 @@
+.\"
+.\" Copyright (c) 2014 Sandvine Inc.
+.\" 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$
+.\"
+.Dd July 8, 2015
+.Dt IOVCTL.CONF 5
+.Os
+.Sh NAME
+.Nm iovctl.conf
+.Nd IOVCTL configuration file
+.Sh DESCRIPTION
+The
+.Nm
+file is the configuration file for the
+.Xr iovctl 8
+program.
+This file specifies configuration parameters for a single Physical Function
+.Pq PF
+device.
+To configure SR-IOV on multiple PF devices, use one configuration file for each
+PF.
+The locations of all
+.Xr iovctl 9
+configuration files are specified in
+.Xr rc.conf 5 .
+.Pp
+The
+.Nm
+file uses UCL format.
+UCL syntax is documented at the official UCL website:
+http://github.com/vstakhov/libucl.
+.Pp
+There are three types of sections in the
+.Nm
+file.
+A section is a key at the top level of the file with a list as its value.
+The list may contain the keys specified in the
+.Sx OPTIONS
+section of this manual page.
+Individual PF driver implementations may specify additional device-specific
+configuration keys that they will accept.
+The order in which sections appear in
+.Nm
+is ignored.
+No two sections may have the same key.
+For example, two sections for VF-1 must not be defined.
+.Pp
+The first section type is the PF section.
+This section always has the key "PF"; therefore, only one such section may be
+defined.
+This section defines configuration parameters that apply to the PF as a whole.
+.Pp
+The second section type is the VF section.
+This section has the key "VF-" followed by a VF index.
+VF indices start at 0 and always increment by 1.
+Valid VF indices are in the range of 0 to
+.Pq num_vfs - 1 .
+The VF index must be given as a decimal integer with no leading zeros.
+This section defines configuration parameters that apply to a single VF.
+.Pp
+The third section type is the default section.
+This section always has the key "DEFAULT"; therefore, only one such section may
+be specified.
+This section defines default configuration parameters that apply to all VFs.
+All configuration keys that are valid to be applied to a VF are valid in this
+section.
+An individual VF section may override a default specified in this section by
+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 section may appear before or after the PF section.
+.Pp
+The following option types are supported:
+.Bl -tag -width indent
+.It boolean
+Accepts a boolean value of true or false.
+.It mac-addr
+Accepts a unicast MAC address specified as a string of the form
+xx:xx:xx:xx:xx:xx, where xx is one or two hexadecimal digits.
+.It string
+Accepts any string value.
+.It uint8_t
+Accepts any integer in the range 0 to 255, inclusive.
+.It uint16_t
+Accepts any integer in the range 0 to 65535, inclusive.
+.It uint32_t
+Accepts any integer in the range 0 to
+.Pq 2**32 - 1 ,
+inclusive.
+.It uint64_t
+Accepts any integer in the range 0 to
+.Pq 2**64 - 1 ,
+inclusive.
+.El
+.Sh OPTIONS
+The following parameters are accepted by all PF drivers:
+.Bl -tag -width indent
+.It device Pq string
+This parameter specifies the name of the PF device.
+This parameter is required to be specified.
+.It num_vfs Pq uint16_t
+This parameter specifies the number of VF children to create.
+This parameter may not be zero.
+The maximum value of this parameter is device-specific.
+.El
+.Pp
+The following parameters are accepted by all VFs:
+.Bl -tag -width indent
+.It passthrough Pq boolean
+This parameter controls whether the VF is reserved for the use of the
+.Xr bhyve 8
+hypervisor as a PCI passthrough device.
+If this parameter is set to true, then the VF will be reserved as a PCI
+passthrough device and it will not be accessible from the host OS.
+The default value of this parameter is false.
+.El
+.Pp
+See the PF driver manual page for configuration parameters specific to
+particular hardware.
+.Sh EXAMPLES
+This sample file will create 3 VFs as children of the ix0 device.
+VF-1 and VF-2 are set as
+.Xr bhyve 8
+passthrough devices through the use of the default section.
+VF-0 is not configured as a passthrough device as it explicitly overrides the
+default.
+VF-0 also sets a device-specific parameter named mac-addr.
+.Bd -literal .offset ident
+PF {
+ device : "ix0";
+ num_vfs : 3;
+}
+
+DEFAULT {
+ passthrough : true;
+}
+
+VF-0 {
+ mac-addr : "02:56:48:7e:d9:f7";
+ passthrough : false;
+}
+.Ed
+.Sh SEE ALSO
+.Xr iovctl 8 ,
+.Xr rc.conf 5
+.Sh AUTHORS
+This manual page was written by
+.An Ryan Stone Aq Mt rstone@FreeBSD.org .
Index: usr.sbin/iovctl/parse.c
===================================================================
--- usr.sbin/iovctl/parse.c
+++ 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 <sys/nv.h>
+#include <net/ethernet.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.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);
+}
Index: usr.sbin/iovctl/validate.c
===================================================================
--- usr.sbin/iovctl/validate.c
+++ 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/iov.h>
+#include <sys/dnv.h>
+#include <sys/nv.h>
+
+#include <err.h>
+#include <regex.h>
+#include <stdlib.h>
+
+#include "iovctl.h"
+
+/*
+ * Returns a writeable pointer to the configuration for the given device.
+ * If no configuration exists, a new nvlist with empty driver and iov
+ * sections is allocated and returned.
+ *
+ * Returning a writeable pointer requires removing the configuration from config
+ * using nvlist_take. It is the responsibility of the caller to re-insert the
+ * nvlist in config with nvlist_move_nvlist.
+ */
+static nvlist_t *
+find_config(nvlist_t *config, const char * device)
+{
+ nvlist_t *subsystem, *empty_driver, *empty_iov;
+
+ subsystem = dnvlist_take_nvlist(config, device, NULL);
+
+ if (subsystem != NULL)
+ return (subsystem);
+
+ empty_driver = nvlist_create(NV_FLAG_IGNORE_CASE);
+ if (empty_driver == NULL)
+ err(1, "Could not allocate config nvlist");
+
+ empty_iov = nvlist_create(NV_FLAG_IGNORE_CASE);
+ if (empty_iov == NULL)
+ err(1, "Could not allocate config nvlist");
+
+ subsystem = nvlist_create(NV_FLAG_IGNORE_CASE);
+ if (subsystem == NULL)
+ err(1, "Could not allocate config nvlist");
+
+ nvlist_move_nvlist(subsystem, DRIVER_CONFIG_NAME, empty_driver);
+ nvlist_move_nvlist(subsystem, IOV_CONFIG_NAME, empty_iov);
+
+ return (subsystem);
+}
+
+static uint16_t
+parse_vf_num(const char *key, regmatch_t *matches)
+{
+ u_long vf_num;
+
+ vf_num = strtoul(key + matches[1].rm_so, NULL, 10);
+
+ if (vf_num > UINT16_MAX)
+ errx(1, "VF number %lu is too large to be valid",
+ vf_num);
+
+ return (vf_num);
+}
+
+/*
+ * Apply the default values specified in device_defaults to the specified
+ * subsystem in the given device_config.
+ *
+ * This function assumes that the values specified in device_defaults have
+ * already been validated.
+ */
+static void
+apply_subsystem_defaults(nvlist_t *device_config, const char *subsystem,
+ const nvlist_t *device_defaults)
+{
+ nvlist_t *config;
+ const nvlist_t *defaults;
+ const char *name;
+ void *cookie;
+ size_t len;
+ const void *bin;
+ int type;
+
+ config = nvlist_take_nvlist(device_config, subsystem);
+ defaults = nvlist_get_nvlist(device_defaults, subsystem);
+
+ cookie = NULL;
+ while ((name = nvlist_next(defaults, &type, &cookie)) != NULL) {
+ if (nvlist_exists(config, name))
+ continue;
+
+ switch (type) {
+ case NV_TYPE_BOOL:
+ nvlist_add_bool(config, name,
+ nvlist_get_bool(defaults, name));
+ break;
+ case NV_TYPE_NUMBER:
+ nvlist_add_number(config, name,
+ nvlist_get_number(defaults, name));
+ break;
+ case NV_TYPE_STRING:
+ nvlist_add_string(config, name,
+ nvlist_get_string(defaults, name));
+ break;
+ case NV_TYPE_NVLIST:
+ nvlist_add_nvlist(config, name,
+ nvlist_get_nvlist(defaults, name));
+ break;
+ case NV_TYPE_BINARY:
+ bin = nvlist_get_binary(defaults, name, &len);
+ nvlist_add_binary(config, name, bin, len);
+ break;
+ default:
+ errx(1, "Unexpected type '%d'", type);
+ }
+ }
+ nvlist_move_nvlist(device_config, subsystem, config);
+}
+
+/*
+ * Iterate over every subsystem in the given VF device and apply default values
+ * for parameters that were not configured with a value.
+ *
+ * This function assumes that the values specified in defaults have already been
+ * validated.
+ */
+static void
+apply_defaults(nvlist_t *vf, const nvlist_t *defaults)
+{
+
+ apply_subsystem_defaults(vf, DRIVER_CONFIG_NAME, defaults);
+ apply_subsystem_defaults(vf, IOV_CONFIG_NAME, defaults);
+}
+
+/*
+ * Validate that all required parameters have been configured in the specified
+ * subsystem.
+ */
+static void
+validate_subsystem(const nvlist_t *device, const nvlist_t *device_schema,
+ const char *subsystem_name, const char *config_name)
+{
+ const nvlist_t *subsystem, *schema, *config;
+ const char *name;
+ void *cookie;
+ int type;
+
+ subsystem = nvlist_get_nvlist(device, subsystem_name);
+ schema = nvlist_get_nvlist(device_schema, subsystem_name);
+
+ cookie = NULL;
+ while ((name = nvlist_next(schema, &type, &cookie)) != NULL) {
+ config = nvlist_get_nvlist(schema, name);
+
+ if (dnvlist_get_bool(config, REQUIRED_SCHEMA_NAME, false)) {
+ if (!nvlist_exists(subsystem, name))
+ errx(1,
+ "Required parameter '%s' not found in '%s'",
+ name, config_name);
+ }
+ }
+}
+
+/*
+ * Validate that all required parameters have been configured in all subsystems
+ * in the device.
+ */
+static void
+validate_device(const nvlist_t *device, const nvlist_t *schema,
+ const char *config_name)
+{
+
+ validate_subsystem(device, schema, DRIVER_CONFIG_NAME, config_name);
+ validate_subsystem(device, schema, IOV_CONFIG_NAME, config_name);
+}
+
+static uint16_t
+get_num_vfs(const nvlist_t *pf)
+{
+ const nvlist_t *iov;
+
+ iov = nvlist_get_nvlist(pf, IOV_CONFIG_NAME);
+ return (nvlist_get_number(iov, "num_vfs"));
+}
+
+/*
+ * Validates the configuration that has been parsed into config using the given
+ * config schema. Note that the parser is required to not insert configuration
+ * keys that are not valid in the schema, and to not insert configuration values
+ * that are of the incorrect type. Therefore this function will not validate
+ * either condition. This function is only responsible for inserting config
+ * file defaults in individual VF sections and removing the DEFAULT_SCHEMA_NAME
+ * subsystem from config, validating that all required parameters in the schema
+ * are present in each PF and VF subsystem, and that there is no VF subsystem
+ * section whose number exceeds num_vfs.
+ */
+void
+validate_config(nvlist_t *config, const nvlist_t *schema, const regex_t *vf_pat)
+{
+ char device_name[VF_MAX_NAME];
+ regmatch_t matches[2];
+ nvlist_t *defaults, *pf, *vf;
+ const nvlist_t *vf_schema;
+ const char *key;
+ void *cookie;
+ int i, type;
+ uint16_t vf_num, num_vfs;
+
+ pf = find_config(config, PF_CONFIG_NAME);
+ validate_device(pf, nvlist_get_nvlist(schema, PF_CONFIG_NAME),
+ PF_CONFIG_NAME);
+ nvlist_move_nvlist(config, PF_CONFIG_NAME, pf);
+
+ num_vfs = get_num_vfs(pf);
+ vf_schema = nvlist_get_nvlist(schema, VF_SCHEMA_NAME);
+
+ if (num_vfs == 0)
+ errx(1, "PF.num_vfs must be at least 1");
+
+ defaults = dnvlist_take_nvlist(config, DEFAULT_SCHEMA_NAME, NULL);
+
+ for (i = 0; i < num_vfs; i++) {
+ snprintf(device_name, sizeof(device_name), VF_PREFIX"%d",
+ i);
+
+ vf = find_config(config, device_name);
+
+ if (defaults != NULL)
+ apply_defaults(vf, defaults);
+
+ validate_device(vf, vf_schema, device_name);
+ nvlist_move_nvlist(config, device_name, vf);
+ }
+ nvlist_destroy(defaults);
+
+ cookie = NULL;
+ while ((key = nvlist_next(config, &type, &cookie)) != NULL) {
+ if (regexec(vf_pat, key, nitems(matches), matches, 0) == 0) {
+ vf_num = parse_vf_num(key, matches);
+ if (vf_num >= num_vfs)
+ errx(1,
+ "VF number %d is out of bounds (num_vfs=%d)",
+ vf_num, num_vfs);
+ }
+ }
+}
+
Index: usr.sbin/pciconf/cap.c
===================================================================
--- usr.sbin/pciconf/cap.c
+++ usr.sbin/pciconf/cap.c
@@ -37,6 +37,7 @@
#include <err.h>
#include <stdio.h>
+#include <strings.h>
#include <sys/agpio.h>
#include <sys/pciio.h>
@@ -640,7 +641,7 @@
printf(" %d fatal", bitcount32(sta & mask));
printf(" %d non-fatal", bitcount32(sta & ~mask));
sta = read_config(fd, &p->pc_sel, ptr + PCIR_AER_COR_STATUS, 4);
- printf(" %d corrected", bitcount32(sta));
+ printf(" %d corrected\n", bitcount32(sta));
}
static void
@@ -656,6 +657,7 @@
if ((cap1 & PCIM_VC_CAP1_LOWPRI_EXT_COUNT) != 0)
printf(" lowpri VC0-VC%d",
(cap1 & PCIM_VC_CAP1_LOWPRI_EXT_COUNT) >> 4);
+ printf("\n");
}
static void
@@ -668,7 +670,7 @@
return;
low = read_config(fd, &p->pc_sel, ptr + PCIR_SERIAL_LOW, 4);
high = read_config(fd, &p->pc_sel, ptr + PCIR_SERIAL_HIGH, 4);
- printf(" %08x%08x", high, low);
+ printf(" %08x%08x\n", high, low);
}
static void
@@ -680,7 +682,7 @@
if (ver < 1)
return;
val = read_config(fd, &p->pc_sel, ptr + 4, 4);
- printf(" ID %d", val & 0xffff);
+ printf(" ID %d\n", val & 0xffff);
}
static void
@@ -692,9 +694,71 @@
if (ver < 1)
return;
val = read_config(fd, &p->pc_sel, ptr + 8, 4);
- printf(" lane errors %#x", val);
+ printf(" lane errors %#x\n", val);
}
+static const char *
+check_enabled(int value)
+{
+
+ return (value ? "enabled" : "disabled");
+}
+
+static void
+ecap_sriov(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver)
+{
+ const char *comma, *enabled;
+ uint16_t iov_ctl, total_vfs, num_vfs, vf_offset, vf_stride, vf_did;
+ uint32_t page_caps, page_size, page_shift, size;
+ int i;
+
+ printf("SR-IOV %d ", ver);
+
+ iov_ctl = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_CTL, 2);
+ printf("IOV %s, Memory Space %s, ARI %s\n",
+ check_enabled(iov_ctl & PCIM_SRIOV_VF_EN),
+ check_enabled(iov_ctl & PCIM_SRIOV_VF_MSE),
+ check_enabled(iov_ctl & PCIM_SRIOV_ARI_EN));
+
+ total_vfs = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_TOTAL_VFS, 2);
+ num_vfs = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_NUM_VFS, 2);
+ printf(" ");
+ printf("%d VFs configured out of %d supported\n", num_vfs, total_vfs);
+
+ vf_offset = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_VF_OFF, 2);
+ vf_stride = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_VF_STRIDE, 2);
+ printf(" ");
+ printf("First VF RID Offset 0x%04x, VF RID Stride 0x%04x\n", vf_offset,
+ vf_stride);
+
+ vf_did = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_VF_DID, 2);
+ printf(" VF Device ID 0x%04x\n", vf_did);
+
+ page_caps = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_PAGE_CAP, 4);
+ page_size = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_PAGE_SIZE, 4);
+ printf(" ");
+ printf("Page Sizes: ");
+ comma = "";
+ while (page_caps != 0) {
+ page_shift = ffs(page_caps) - 1;
+
+ if (page_caps & page_size)
+ enabled = " (enabled)";
+ else
+ enabled = "";
+
+ size = (1 << (page_shift + PCI_SRIOV_BASE_PAGE_SHIFT));
+ printf("%s%d%s", comma, size, enabled);
+ comma = ", ";
+
+ page_caps &= ~(1 << page_shift);
+ }
+ printf("\n");
+
+ for (i = 0; i <= PCIR_MAX_BAR_0; i++)
+ print_bar(fd, p, "iov bar ", ptr + PCIR_SRIOV_BAR(i));
+}
+
struct {
uint16_t id;
const char *name;
@@ -708,7 +772,6 @@
{ PCIZ_ACS, "ACS" },
{ PCIZ_ARI, "ARI" },
{ PCIZ_ATS, "ATS" },
- { PCIZ_SRIOV, "SRIOV" },
{ PCIZ_MULTICAST, "Multicast" },
{ PCIZ_RESIZE_BAR, "Resizable BAR" },
{ PCIZ_DPA, "DPA" },
@@ -747,6 +810,9 @@
case PCIZ_SEC_PCIE:
ecap_sec_pcie(fd, p, ptr, PCI_EXTCAP_VER(ecap));
break;
+ case PCIZ_SRIOV:
+ ecap_sriov(fd, p, ptr, PCI_EXTCAP_VER(ecap));
+ break;
default:
name = "unknown";
for (i = 0; ecap_names[i].name != NULL; i++)
@@ -754,10 +820,9 @@
name = ecap_names[i].name;
break;
}
- printf("%s %d", name, PCI_EXTCAP_VER(ecap));
+ printf("%s %d\n", name, PCI_EXTCAP_VER(ecap));
break;
}
- printf("\n");
ptr = PCI_EXTCAP_NEXTPTR(ecap);
if (ptr == 0)
break;
Index: usr.sbin/pciconf/pciconf.h
===================================================================
--- usr.sbin/pciconf/pciconf.h
+++ usr.sbin/pciconf/pciconf.h
@@ -37,6 +37,7 @@
void list_errors(int fd, struct pci_conf *p);
uint8_t pci_find_cap(int fd, struct pci_conf *p, uint8_t id);
uint16_t pcie_find_cap(int fd, struct pci_conf *p, uint16_t id);
+void print_bar(int fd, struct pci_conf *p, const char *label, uint16_t bar);
uint32_t read_config(int fd, struct pcisel *sel, long reg, int width);
#endif
Index: usr.sbin/pciconf/pciconf.c
===================================================================
--- usr.sbin/pciconf/pciconf.c
+++ usr.sbin/pciconf/pciconf.c
@@ -263,10 +263,7 @@
static void
list_bars(int fd, struct pci_conf *p)
{
- struct pci_bar_io bar;
- uint64_t base;
- const char *type;
- int i, range, max;
+ int i, max;
switch (p->pc_hdr & PCIM_HDRTYPE) {
case PCIM_HDRTYPE_NORMAL:
@@ -282,40 +279,50 @@
return;
}
- for (i = 0; i <= max; i++) {
- bar.pbi_sel = p->pc_sel;
- bar.pbi_reg = PCIR_BAR(i);
- if (ioctl(fd, PCIOCGETBAR, &bar) < 0)
- continue;
- if (PCI_BAR_IO(bar.pbi_base)) {
- type = "I/O Port";
+ for (i = 0; i <= max; i++)
+ print_bar(fd, p, "bar ", PCIR_BAR(i));
+}
+
+void
+print_bar(int fd, struct pci_conf *p, const char *label, uint16_t bar_offset)
+{
+ uint64_t base;
+ const char *type;
+ struct pci_bar_io bar;
+ int range;
+
+ bar.pbi_sel = p->pc_sel;
+ bar.pbi_reg = bar_offset;
+ if (ioctl(fd, PCIOCGETBAR, &bar) < 0)
+ return;
+ if (PCI_BAR_IO(bar.pbi_base)) {
+ type = "I/O Port";
+ range = 32;
+ base = bar.pbi_base & PCIM_BAR_IO_BASE;
+ } else {
+ if (bar.pbi_base & PCIM_BAR_MEM_PREFETCH)
+ type = "Prefetchable Memory";
+ else
+ type = "Memory";
+ switch (bar.pbi_base & PCIM_BAR_MEM_TYPE) {
+ case PCIM_BAR_MEM_32:
range = 32;
- base = bar.pbi_base & PCIM_BAR_IO_BASE;
- } else {
- if (bar.pbi_base & PCIM_BAR_MEM_PREFETCH)
- type = "Prefetchable Memory";
- else
- type = "Memory";
- switch (bar.pbi_base & PCIM_BAR_MEM_TYPE) {
- case PCIM_BAR_MEM_32:
- range = 32;
- break;
- case PCIM_BAR_MEM_1MB:
- range = 20;
- break;
- case PCIM_BAR_MEM_64:
- range = 64;
- break;
- default:
- range = -1;
- }
- base = bar.pbi_base & ~((uint64_t)0xf);
+ break;
+ case PCIM_BAR_MEM_1MB:
+ range = 20;
+ break;
+ case PCIM_BAR_MEM_64:
+ range = 64;
+ break;
+ default:
+ range = -1;
}
- printf(" bar [%02x] = type %s, range %2d, base %#jx, ",
- PCIR_BAR(i), type, range, (uintmax_t)base);
- printf("size %ju, %s\n", (uintmax_t)bar.pbi_length,
- bar.pbi_enabled ? "enabled" : "disabled");
+ base = bar.pbi_base & ~((uint64_t)0xf);
}
+ printf(" %s[%02x] = type %s, range %2d, base %#jx, ",
+ label, bar_offset, type, range, (uintmax_t)base);
+ printf("size %ju, %s\n", (uintmax_t)bar.pbi_length,
+ bar.pbi_enabled ? "enabled" : "disabled");
}
static void

File Metadata

Mime Type
text/plain
Expires
Fri, Apr 24, 1:51 AM (12 m, 57 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
32054962
Default Alt Text
D4767.diff (465 KB)

Event Timeline