svn commit: r364936 - in head: lib lib/libnetmap share/mk
Vincenzo Maffione
vmaffione at FreeBSD.org
Fri Aug 28 20:03:56 UTC 2020
Author: vmaffione
Date: Fri Aug 28 20:03:54 2020
New Revision: 364936
URL: https://svnweb.freebsd.org/changeset/base/364936
Log:
lib: add libnetmap
This changeset introduces the new libnetmap library for writing
netmap applications.
Before libnetmap, applications could either use the kernel API
directly (e.g. NIOCREGIF/NIOCCTRL) or the simple header-only-library
netmap_user.h (e.g. nm_open(), nm_close(), nm_mmap() etc.)
The new library offers more functionalities than netmap_user.h:
- Support for complex netmap options, such as external memory
allocators or per-buffer offsets. This opens the way to future
extensions.
- More flexibility in the netmap port bind options, such as
non-numeric names for pipes, or the ability to specify the netmap
allocator that must be used for a given port.
- Automatic tracking of the netmap memory regions in use across the
open ports.
At the moment there is no man page, but the libnetmap.h header file
has in-depth documentation.
Reviewed by: hrs
MFC after: 2 weeks
Differential Revision: https://reviews.freebsd.org/D26171
Added:
head/lib/libnetmap/
head/lib/libnetmap/Makefile (contents, props changed)
head/lib/libnetmap/libnetmap.h (contents, props changed)
head/lib/libnetmap/nmctx-pthreads.c (contents, props changed)
head/lib/libnetmap/nmctx.c (contents, props changed)
head/lib/libnetmap/nmport.c (contents, props changed)
head/lib/libnetmap/nmreq.c (contents, props changed)
Modified:
head/lib/Makefile
head/share/mk/bsd.libnames.mk
head/share/mk/src.libnames.mk
Modified: head/lib/Makefile
==============================================================================
--- head/lib/Makefile Fri Aug 28 19:59:02 2020 (r364935)
+++ head/lib/Makefile Fri Aug 28 20:03:54 2020 (r364936)
@@ -71,6 +71,7 @@ SUBDIR= ${SUBDIR_BOOTSTRAP} \
libmt \
lib80211 \
libnetbsd \
+ libnetmap \
libnv \
libopenbsd \
libopie \
Added: head/lib/libnetmap/Makefile
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/lib/libnetmap/Makefile Fri Aug 28 20:03:54 2020 (r364936)
@@ -0,0 +1,16 @@
+#
+# $FreeBSD$
+#
+
+.include <src.opts.mk>
+
+PACKAGE= lib${LIB}
+LIB= netmap
+SRCS= nmctx.c nmport.c \
+ nmctx-pthreads.c nmreq.c
+INCS= libnetmap.h
+#MAN= libnetmap.3
+CFLAGS+= -I${SRCTOP}/sys/net -I${.CURDIR}
+WARNS?= 2
+
+.include <bsd.lib.mk>
Added: head/lib/libnetmap/libnetmap.h
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/lib/libnetmap/libnetmap.h Fri Aug 28 20:03:54 2020 (r364936)
@@ -0,0 +1,660 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (C) 2018 Universita` di Pisa
+ * 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 LIBNETMAP_H_
+#define LIBNETMAP_H_
+/* if thread-safety is not needed, define LIBNETMAP_NOTHREADSAFE before including
+ * this file.
+ */
+
+/* NOTE: we include net/netmap_user.h without defining NETMAP_WITH_LIBS, which
+ * is deprecated. If you still need it, please define NETMAP_WITH_LIBS and
+ * include net/netmap_user.h before including this file.
+ */
+#include <net/netmap_user.h>
+
+struct nmctx;
+struct nmport_d;
+struct nmem_d;
+
+/*
+ * A port open specification (portspec for brevity) has the following syntax
+ * (square brackets delimit optional parts):
+ *
+ * subsystem:vpname[mode][options]
+ *
+ * The "subsystem" is denoted by a prefix, possibly followed by an identifier.
+ * There can be several kinds of subsystems, each one selected by a unique
+ * prefix. Currently defined subsystems are:
+ *
+ * netmap (no id allowed)
+ * the standard subsystem
+ *
+ * vale (followed by a possibly empty id)
+ * the vpname is connected to a VALE switch identified by
+ * the id (an empty id selects the default switch)
+ *
+ * The "vpname" has the following syntax:
+ *
+ * identifier or
+ * identifier1{identifier2 or
+ * identifier1}identifier2
+ *
+ * Identifiers are sequences of alphanumeric characters. The part that begins
+ * with either '{' or '}', when present, denotes a netmap pipe opened in the
+ * same memory region as the subsystem:indentifier1 port.
+ *
+ * The "mode" can be one of the following:
+ *
+ * ^ bind all host (sw) ring pairs
+ * ^NN bind individual host ring pair
+ * * bind host and NIC ring pairs
+ * -NN bind individual NIC ring pair
+ * @NN open the port in the NN memory region
+ * a suffix starting with / and the following flags,
+ * in any order:
+ * x exclusive access
+ * z zero copy monitor (both tx and rx)
+ * t monitor tx side (copy monitor)
+ * r monitor rx side (copy monitor)
+ * R bind only RX ring(s)
+ * T bind only TX ring(s)
+ *
+ * The "options" start at the first '@' character not followed by a number.
+ * Each option starts with '@' and has the following syntax:
+ *
+ * option (flag option)
+ * option=value (single key option)
+ * option:key1=value1,key2=value2,... (multi-key option)
+ *
+ * For multi-key options, the keys can be assigned in any order, but they
+ * cannot be assigned more than once. It is not necessary to assign all the
+ * option keys: unmentioned keys will receive default values. Some multi-key
+ * options define a default key and also accept the single-key syntax, by
+ * assigning the value to this key.
+ *
+ * NOTE: Options may be silently ignored if the port is already open by some
+ * other process.
+ *
+ * The currently available options are (default keys, when defined, are marked
+ * with '*'):
+ *
+ * share (single-key)
+ * open the port in the same memory region used by the
+ * given port name (the port name must be given in
+ * subsystem:vpname form)
+ *
+ * conf (multi-key)
+ * specify the rings/slots numbers (effective only on
+ * ports that are created by the open operation itself,
+ * and ignored otherwise).
+ *
+ * The keys are:
+ *
+ * *rings number of tx and rx rings
+ * tx-rings number of tx rings
+ * rx-rings number of rx rings
+ * host-rings number of tx and rx host rings
+ * host-tx-rings number of host tx rings
+ * host-rx-rings number of host rx rings
+ * slots number of slots in each tx and rx
+ * ring
+ * tx-slots number of slots in each tx ring
+ * rx-slots number of slots in each rx ring
+ *
+ * (more specific keys override the less specific ones)
+ * All keys default to zero if not assigned, and the
+ * corresponding value will be chosen by netmap.
+ *
+ * extmem (multi-key)
+ * open the port in the memory region obtained by
+ * mmap()ing the given file.
+ *
+ * The keys are:
+ *
+ * *file the file to mmap
+ * if-num number of pre-allocated netmap_if's
+ * if-size size of each netmap_if
+ * ring-num number of pre-allocated netmap_ring's
+ * ring-size size of each netmap_ring
+ * buf-num number of pre-allocated buffers
+ * buf-size size of each buffer
+ *
+ * file must be assigned. The other keys default to zero,
+ * causing netmap to take the corresponding values from
+ * the priv_{if,ring,buf}_{num,size} sysctls.
+ *
+ */
+
+
+/* nmport manipulation */
+
+/* struct nmport_d - describes a netmap port */
+struct nmport_d {
+ /* see net/netmap.h for the definition of these fields */
+ struct nmreq_header hdr;
+ struct nmreq_register reg;
+
+ /* all the fields below should be considered read-only */
+
+ /* if the same context is used throughout the program, d1->mem ==
+ * d2->mem iff d1 and d2 are using the memory region (i.e., zero
+ * copy is possible between the two ports)
+ */
+ struct nmem_d *mem;
+
+ /* the nmctx used when this nmport_d was created */
+ struct nmctx *ctx;
+
+ int register_done; /* nmport_register() has been called */
+ int mmap_done; /* nmport_mmap() has been called */
+ /* pointer to the extmem option contained in the hdr options, if any */
+ struct nmreq_opt_extmem *extmem;
+
+ /* the fields below are compatible with nm_open() */
+ int fd; /* "/dev/netmap", -1 if not open */
+ struct netmap_if *nifp; /* pointer to the netmap_if */
+ uint16_t first_tx_ring;
+ uint16_t last_tx_ring;
+ uint16_t first_rx_ring;
+ uint16_t last_rx_ring;
+ uint16_t cur_tx_ring; /* used by nmport_inject */
+ uint16_t cur_rx_ring;
+
+ /* LIFO list of cleanup functions (used internally) */
+ struct nmport_cleanup_d *clist;
+};
+
+/* nmport_open - opens a port from a portspec
+ * @portspec the port opening specification
+ *
+ * If successful, the function returns a new nmport_d describing a netmap
+ * port, opened according to the port specification, ready to be used for rx
+ * and/or tx.
+ *
+ * The rings available for tx are in the [first_tx_ring, last_tx_ring]
+ * interval, and similarly for rx. One or both intervals may be empty.
+ *
+ * When done using it, the nmport_d descriptor must be closed using
+ * nmport_close().
+ *
+ * In case of error, NULL is returned, errno is set to some error, and an
+ * error message is sent through the error() method of the current context.
+ */
+struct nmport_d * nmport_open(const char *portspec);
+
+/* nport_close - close a netmap port
+ * @d the port we want to close
+ *
+ * Undoes the actions performed by the nmport_open that created d, then
+ * frees the descriptor.
+ */
+void nmport_close(struct nmport_d *d);
+
+/* nmport_inject - sends a packet
+ * @d the port through which we want to send
+ * @buf base address of the packet
+ * @size its size in bytes
+ *
+ * Sends a packet using the cur_tx_ring and updates the index
+ * to use all available tx rings in turn. Note: the packet is copied.
+ *
+ * Returns 0 on success an -1 on error.
+ */
+int nmport_inject(struct nmport_d *d, const void *buf, size_t size);
+
+/*
+ * the functions below can be used to split the functionality of
+ * nmport_open when special features (e.g., extra buffers) are needed
+ *
+ * The relation among the functions is as follows:
+ *
+ * |nmport_new
+ * |nmport_prepare = |
+ * | |nmport_parse
+ * nmport_open =|
+ * | |nmport_register
+ * |nmport_open_desc =|
+ * |nmport_mmap
+ *
+ */
+
+/* nmport_new - create a new nmport_d
+ *
+ * Creates a new nmport_d using the malloc() method of the current default
+ * context. Returns NULL on error, setting errno to an error value.
+ */
+struct nmport_d *nmport_new(void);
+
+/* nmport_parse - fills the nmport_d netmap-register request
+ * @d the nmport to be filled
+ * @portspec the port opening specification
+ *
+ * This function parses the portspec and initizalizes the @d->hdr and @d->reg
+ * fields. It may need to allocate a list of options. If an extmem option is
+ * found, it may also mmap() the corresponding file.
+ *
+ * It returns 0 on success. On failure it returns -1, sets errno to an error
+ * value and sends an error message to the error() method of the context used
+ * when @d was created. Moreover, *@d is left unchanged.
+ */
+int nmport_parse(struct nmport_d *d, const char *portspec);
+
+/* nmport_register - registers the port with netmap
+ * @d the nmport to be registered
+ *
+ * This function obtains a netmap file descriptor and registers the port with
+ * netmap. The @d->hdr and @d->reg data structures must have been previously
+ * initialized (via nmport_parse() or otherwise).
+ *
+ * It returns 0 on success. On failure it returns -1, sets errno to an error
+ * value and sends an error message to the error() method of the context used
+ * when @d was created. Moreover, *@d is left unchanged.
+ */
+int nmport_register(struct nmport_d *);
+
+/* nmport_mmap - maps the port resources into the process memory
+ * @d the nmport to be mapped
+ *
+ * The port must have been previously been registered using nmport_register.
+ *
+ * Note that if extmem is used (either via an option or by calling an
+ * nmport_extmem_* function before nmport_register()), no new mmap() is issued.
+ *
+ * It returns 0 on success. On failure it returns -1, sets errno to an error
+ * value and sends an error message to the error() method of the context used
+ * when @d was created. Moreover, *@d is left unchanged.
+ */
+int nmport_mmap(struct nmport_d *);
+
+/* the following functions undo the actions of nmport_new(), nmport_parse(),
+ * nmport_register() and nmport_mmap(), respectively.
+ */
+void nmport_delete(struct nmport_d *);
+void nmport_undo_parse(struct nmport_d *);
+void nmport_undo_register(struct nmport_d *);
+void nmport_undo_mmap(struct nmport_d *);
+
+/* nmport_prepare - create a port descriptor, but do not open it
+ * @portspec the port opening specification
+ *
+ * This functions creates a new nmport_d and initializes it according to
+ * @portspec. It is equivalent to nmport_new() followed by nmport_parse().
+ *
+ * It returns 0 on success. On failure it returns -1, sets errno to an error
+ * value and sends an error message to the error() method of the context used
+ * when @d was created. Moreover, *@d is left unchanged.
+ */
+struct nmport_d *nmport_prepare(const char *portspec);
+
+/* nmport_open_desc - open an initialized port descriptor
+ * @d the descriptor we want to open
+ *
+ * Registers the port with netmap and maps the rings and buffers into the
+ * process memory. It is equivalent to nmport_register() followed by
+ * nmport_mmap().
+ *
+ * It returns 0 on success. On failure it returns -1, sets errno to an error
+ * value and sends an error message to the error() method of the context used
+ * when @d was created. Moreover, *@d is left unchanged.
+ */
+int nmport_open_desc(struct nmport_d *d);
+
+/* the following functions undo the actions of nmport_prepare()
+ * and nmport_open_desc(), respectively.
+ */
+void nmport_undo_prepare(struct nmport_d *);
+void nmport_undo_open_desc(struct nmport_d *);
+
+/* nmport_clone - copy an nmport_d
+ * @d the nmport_d we want to copy
+ *
+ * Copying an nmport_d by hand should be avoided, since adjustments are needed
+ * and some part of the state cannot be easily duplicated. This function
+ * creates a copy of @d in a safe way. The returned nmport_d contains
+ * nmreq_header and nmreq_register structures equivalent to those contained in
+ * @d, except for the option list, which is ignored. The returned nmport_d is
+ * already nmport_prepare()d, but it must still be nmport_open_desc()ed. The
+ * new nmport_d uses the same nmctx as @d.
+ *
+ * If extmem was used for @d, then @d cannot be nmport_clone()d until it has
+ * been nmport_register()ed.
+ *
+ * In case of error, the function returns NULL, sets errno to an error value
+ * and sends an error message to the nmctx error() method.
+ */
+struct nmport_d *nmport_clone(struct nmport_d *);
+
+/* nmport_extmem - use extmem for this port
+ * @d the port we want to use the extmem for
+ * @base the base address of the extmem region
+ * @size the size in bytes of the extmem region
+ *
+ * the memory that contains the netmap ifs, rings and buffers is usually
+ * allocated by netmap and later mmap()ed by the applications. It is sometimes
+ * useful to reverse this process, by having the applications allocate some
+ * memory (through mmap() or otherwise) and then let netmap use it. The extmem
+ * option can be used to implement this latter strategy. The option can be
+ * passed through the portspec using the '@extmem:...' syntax, or
+ * programmatically by calling nmport_extmem() or nmport_extmem_from_file()
+ * between nmport_parse() and nmport_register() (or between nmport_prepare()
+ * and nmport_open_desc()).
+ *
+ * It returns 0 on success. On failure it returns -1, sets errno to an error
+ * value and sends an error message to the error() method of the context used
+ * when @d was created. Moreover, *@d is left unchanged.
+ */
+int nmport_extmem(struct nmport_d *d, void *base, size_t size);
+
+/* nmport_extmem_from_file - use the extmem obtained by mapping a file
+ * @d the port we want to use the extmem for
+ * @fname path of the file we want to map
+ *
+ * This works like nmport_extmem, but the extmem memory is obtained by
+ * mmap()ping @fname. nmport_close() will also automatically munmap() the file.
+ *
+ * It returns 0 on success. On failure it returns -1, sets errno to an error
+ * value and sends an error message to the error() method of the context used
+ * when @d was created. Moreover, *@d is left unchanged.
+ */
+int nmport_extmem_from_file(struct nmport_d *d, const char *fname);
+
+/* nmport_extmem_getinfo - opbtai a pointer to the extmem configuration
+ * @d the port we want to obtain the pointer from
+ *
+ * Returns a pointer to the nmreq_pools_info structure containing the
+ * configuration of the extmem attached to port @d, or NULL if no extmem
+ * is attached. This can be used to set the desired configuration before
+ * registering the port, or to read the actual configuration after
+ * registration.
+ */
+struct nmreq_pools_info* nmport_extmem_getinfo(struct nmport_d *d);
+
+
+/* enable/disable options
+ *
+ * These functions can be used to disable options that the application cannot
+ * or doesn't want to handle, or to enable options that require special support
+ * from the application and are, therefore, disabled by default. Disabled
+ * options will cause an error if encountered during option parsing.
+ *
+ * If the option is unknown, nmport_disable_option is a NOP, while
+ * nmport_enable_option returns -1 and sets errno to EOPNOTSUPP.
+ *
+ * These functions are not threadsafe and are meant to be used at the beginning
+ * of the program.
+ */
+void nmport_disable_option(const char *opt);
+int nmport_enable_option(const char *opt);
+
+/* nmreq manipulation
+ *
+ * nmreq_header_init - initialize an nmreq_header
+ * @hdr the nmreq_header to initialize
+ * @reqtype the kind of netmap request
+ * @body the body of the request
+ *
+ * Initialize the nr_version, nr_reqtype and nr_body fields of *@hdr.
+ * The other fields are set to zero.
+ */
+void nmreq_header_init(struct nmreq_header *hdr, uint16_t reqtype, void *body);
+
+/*
+ * These functions allow for finer grained parsing of portspecs. They are used
+ * internally by nmport_parse().
+ */
+
+/* nmreq_header_decode - initialize an nmreq_header
+ * @ppspec: (in/out) pointer to a pointer to the portspec
+ * @hdr: pointer to the nmreq_header to be initialized
+ * @ctx: pointer to the nmctx to use (for errors)
+ *
+ * This function fills the @hdr the nr_name field with the port name extracted
+ * from *@pifname. The other fields of *@hdr are unchanged. The @pifname is
+ * updated to point at the first char past the port name.
+ *
+ * Returns 0 on success. In case of error, -1 is returned with errno set to
+ * EINVAL, @pifname is unchanged, *@hdr is also unchanged, and an error message
+ * is sent through @ctx->error().
+ */
+int nmreq_header_decode(const char **ppspec, struct nmreq_header *hdr,
+ struct nmctx *ctx);
+
+/* nmreq_regiter_decode - initialize an nmreq_register
+ * @pmode: (in/out) pointer to a pointer to an opening mode
+ * @reg: pointer to the nmreq_register to be initialized
+ * @ctx: pointer to the nmctx to use (for errors)
+ *
+ * This function fills the nr_mode, nr_ringid, nr_flags and nr_mem_id fields of
+ * the structure pointed by @reg, according to the opening mode specified by
+ * *@pmode. The other fields of *@reg are unchanged. The @pmode is updated to
+ * point at the first char past the opening mode.
+ *
+ * If a '@' is encountered followed by something which is not a number, parsing
+ * stops (without error) and @pmode is left pointing at the '@' char. The
+ * nr_mode, nr_ringid and nr_flags fields are still updated, but nr_mem_id is
+ * not touched and the interpretation of the '@' field is left to the caller.
+ *
+ * Returns 0 on success. In case of error, -1 is returned with errno set to
+ * EINVAL, @pmode is unchanged, *@reg is also unchanged, and an error message
+ * is sent through @ctx->error().
+ */
+int nmreq_register_decode(const char **pmode, struct nmreq_register *reg,
+ struct nmctx *ctx);
+
+/* nmreq_options_decode - parse the "options" part of the portspec
+ * @opt: pointer to the option list
+ * @parsers: list of option parsers
+ * @token: token to pass to each parser
+ * @ctx: pointer to the nmctx to use (for errors and malloc/free)
+ *
+ * This function parses each option in @opt. Each option is matched (based on
+ * the "option" prefix) to a corresponding parser in @parsers. The function
+ * checks that the syntax is appropriate for the parser and it assigns all the
+ * keys mentioned in the option. It then passes control to the parser, to
+ * interpret the keys values.
+ *
+ * Returns 0 on success. In case of error, -1 is returned, errno is set to an
+ * error value and a message is sent to @ctx->error(). The effects of partially
+ * interpreted options may not be undone.
+ */
+struct nmreq_opt_parser;
+int nmreq_options_decode(const char *opt, struct nmreq_opt_parser *parsers,
+ void *token, struct nmctx *ctx);
+
+struct nmreq_parse_ctx;
+/* type of the option-parsers callbacks */
+typedef int (*nmreq_opt_parser_cb)(struct nmreq_parse_ctx *);
+
+#define NMREQ_OPT_MAXKEYS 16 /* max nr of recognized keys per option */
+
+/* struct nmreq_opt_key - describes an option key */
+struct nmreq_opt_key {
+ const char *key; /* the key name */
+ int id; /* its position in the parse context */
+ unsigned int flags;
+#define NMREQ_OPTK_ALLOWEMPTY (1U << 0) /* =value may be omitted */
+#define NMREQ_OPTK_MUSTSET (1U << 1) /* the key is mandatory */
+#define NMREQ_OPTK_DEFAULT (1U << 2) /* this is the default key */
+};
+
+/* struct nmreq_opt_parser - describes an option parser */
+struct nmreq_opt_parser {
+ const char *prefix; /* matches one option prefix */
+ nmreq_opt_parser_cb parse; /* the parse callback */
+ int default_key; /* which option is the default if the
+ parser is multi-key (-1 if none) */
+ int nr_keys;
+ unsigned int flags;
+#define NMREQ_OPTF_DISABLED (1U << 0)
+#define NMREQ_OPTF_ALLOWEMPTY (1U << 1) /* =value can be omitted */
+
+ struct nmreq_opt_parser *next; /* list of options */
+
+ /* recognized keys */
+ struct nmreq_opt_key keys[NMREQ_OPT_MAXKEYS];
+} __attribute__((aligned(16)));
+
+/* struct nmreq_parse_ctx - the parse context received by the parse callback */
+struct nmreq_parse_ctx {
+ struct nmctx *ctx; /* the nmctx for errors and malloc/free */
+ void *token; /* the token passed to nmreq_options_parse */
+
+ /* the value (i.e., the part after the = sign) of each recognized key
+ * is assigned to the corresponding entry in this array, based on the
+ * key id. Unassigned keys are left at NULL.
+ */
+ const char *keys[NMREQ_OPT_MAXKEYS];
+};
+
+/* nmreq_get_mem_id - get the mem_id of the given port
+ * @portname pointer to a pointer to the portname
+ * @ctx pointer to the nmctx to use (for errors)
+ *
+ * *@portname must point to a substem:vpname porname, possibly followed by
+ * something else.
+ *
+ * If successful, returns the mem_id of *@portname and moves @portname past the
+ * subsystem:vpname part of the input. In case of error it returns -1, sets
+ * errno to an error value and sends an error message to ctx->error().
+ */
+int32_t nmreq_get_mem_id(const char **portname, struct nmctx *ctx);
+
+/* option list manipulation */
+void nmreq_push_option(struct nmreq_header *, struct nmreq_option *);
+void nmreq_remove_option(struct nmreq_header *, struct nmreq_option *);
+struct nmreq_option *nmreq_find_option(struct nmreq_header *, uint32_t);
+void nmreq_free_options(struct nmreq_header *);
+const char* nmreq_option_name(uint32_t);
+#define nmreq_foreach_option(h_, o_) \
+ for ((o_) = (struct nmreq_option *)((h_)->nr_options);\
+ (o_) != NULL;\
+ (o_) = (struct nmreq_option *)((o_)->nro_next))
+
+/* nmctx manipulation */
+
+/* the nmctx serves a few purposes:
+ *
+ * - maintain a list of all memory regions open by the program, so that two
+ * ports that are using the same region (as identified by the mem_id) will
+ * point to the same nmem_d instance.
+ *
+ * - allow the user to specify how to lock accesses to the above list, if
+ * needed (lock() callback)
+ *
+ * - allow the user to specify how error messages should be delivered (error()
+ * callback)
+ *
+ * - select the verbosity of the library (verbose field); if verbose==0, no
+ * errors are sent to the error() callback
+ *
+ * - allow the user to override the malloc/free functions used by the library
+ * (malloc() and free() callbacks)
+ *
+ */
+typedef void (*nmctx_error_cb)(struct nmctx *, const char *);
+typedef void *(*nmctx_malloc_cb)(struct nmctx *,size_t);
+typedef void (*nmctx_free_cb)(struct nmctx *,void *);
+typedef void (*nmctx_lock_cb)(struct nmctx *, int);
+
+struct nmctx {
+ int verbose;
+ nmctx_error_cb error;
+ nmctx_malloc_cb malloc;
+ nmctx_free_cb free;
+ nmctx_lock_cb lock;
+
+ struct nmem_d *mem_descs;
+};
+
+/* nmctx_get - obtain a pointer to the current default context */
+struct nmctx *nmctx_get(void);
+
+/* nmctx_set_default - change the default context
+ * @ctx pointer to the new context
+ *
+ * Returns a pointer to the previous default context.
+ */
+struct nmctx *nmctx_set_default(struct nmctx *ctx);
+
+/* internal functions and data structures */
+
+/* struct nmem_d - describes a memory region currently used */
+struct nmem_d {
+ uint16_t mem_id; /* the region netmap identifier */
+ int refcount; /* how many nmport_d's point here */
+ void *mem; /* memory region base address */
+ size_t size; /* memory region size */
+ int is_extmem; /* was it obtained via extmem? */
+
+ /* pointers for the circular list implementation.
+ * The list head is the mem_descs filed in the nmctx
+ */
+ struct nmem_d *next;
+ struct nmem_d *prev;
+};
+
+/* a trick to force the inclusion of libpthread only if requested. If
+ * LIBNETMAP_NOTHREADSAFE is defined, no pthread symbol is imported.
+ *
+ * There is no need to actually call this function: the ((used)) attribute is
+ * sufficient to include it in the image.
+ */
+static __attribute__((used)) void libnetmap_init(void)
+{
+#ifndef LIBNETMAP_NOTHREADSAFE
+ extern int nmctx_threadsafe;
+ /* dummy assignment to link-in the nmctx-pthread.o object. The proper
+ * inizialization is performed only once in the library constructor
+ * defined there.
+ */
+ nmctx_threadsafe = 1;
+#endif /* LIBNETMAP_NOTHREADSAFE */
+}
+
+/* nmctx_set_threadsafe - install a threadsafe default context
+ *
+ * called by the constructor in nmctx-pthread.o to initialize a lock and install
+ * the lock() callback in the default context.
+ */
+void nmctx_set_threadsafe(void);
+
+/* nmctx_ferror - format and send an error message */
+void nmctx_ferror(struct nmctx *, const char *, ...);
+/* nmctx_malloc - allocate memory */
+void *nmctx_malloc(struct nmctx *, size_t);
+/* nmctx_free - free memory allocated via nmctx_malloc */
+void nmctx_free(struct nmctx *, void *);
+/* nmctx_lock - lock the list of nmem_d */
+void nmctx_lock(struct nmctx *);
+/* nmctx_unlock - unlock the list of nmem_d */
+void nmctx_unlock(struct nmctx *);
+
+#endif /* LIBNETMAP_H_ */
Added: head/lib/libnetmap/nmctx-pthreads.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/lib/libnetmap/nmctx-pthreads.c Fri Aug 28 20:03:54 2020 (r364936)
@@ -0,0 +1,47 @@
+/* $FreeBSD$ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <net/netmap_user.h>
+#include <pthread.h>
+#include "libnetmap.h"
+
+struct nmctx_pthread {
+ struct nmctx up;
+ pthread_mutex_t mutex;
+};
+
+static struct nmctx_pthread nmctx_pthreadsafe;
+
+static void
+nmctx_pthread_lock(struct nmctx *ctx, int lock)
+{
+ struct nmctx_pthread *ctxp =
+ (struct nmctx_pthread *)ctx;
+ if (lock) {
+ pthread_mutex_lock(&ctxp->mutex);
+ } else {
+ pthread_mutex_unlock(&ctxp->mutex);
+ }
+}
+
+void __attribute__ ((constructor))
+nmctx_set_threadsafe(void)
+{
+ struct nmctx *old;
+
+ pthread_mutex_init(&nmctx_pthreadsafe.mutex, NULL);
+ old = nmctx_set_default(&nmctx_pthreadsafe.up);
+ nmctx_pthreadsafe.up = *old;
+ nmctx_pthreadsafe.up.lock = nmctx_pthread_lock;
+}
+
+int nmctx_threadsafe;
Added: head/lib/libnetmap/nmctx.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/lib/libnetmap/nmctx.c Fri Aug 28 20:03:54 2020 (r364936)
@@ -0,0 +1,111 @@
+/* $FreeBSD$ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <net/netmap_user.h>
+#define LIBNETMAP_NOTHREADSAFE
+#include "libnetmap.h"
+
+static void
+nmctx_default_error(struct nmctx *ctx, const char *errmsg)
+{
+ fprintf(stderr, "%s\n", errmsg);
+}
+
+static void *
+nmctx_default_malloc(struct nmctx *ctx, size_t sz)
+{
+ (void)ctx;
+ return malloc(sz);
+}
+
+static void
+nmctx_default_free(struct nmctx *ctx, void *p)
+{
+ (void)ctx;
+ free(p);
+}
+
+static struct nmctx nmctx_global = {
+ .verbose = 1,
+ .error = nmctx_default_error,
+ .malloc = nmctx_default_malloc,
+ .free = nmctx_default_free,
+ .lock = NULL,
+};
+
+static struct nmctx *nmctx_default = &nmctx_global;
+
+struct nmctx *
+nmctx_get(void)
+{
+ return nmctx_default;
+}
+
+struct nmctx *
+nmctx_set_default(struct nmctx *ctx)
+{
+ struct nmctx *old = nmctx_default;
+ nmctx_default = ctx;
+ return old;
+}
+
+#define MAXERRMSG 1000
+void
+nmctx_ferror(struct nmctx *ctx, const char *fmt, ...)
+{
+ char errmsg[MAXERRMSG];
+ va_list ap;
+ int rv;
+
+ if (!ctx->verbose)
+ return;
+
+ va_start(ap, fmt);
+ rv = vsnprintf(errmsg, MAXERRMSG, fmt, ap);
+ va_end(ap);
+
+ if (rv > 0) {
+ if (rv < MAXERRMSG) {
+ ctx->error(ctx, errmsg);
+ } else {
+ ctx->error(ctx, "error message too long");
+ }
+ } else {
+ ctx->error(ctx, "internal error");
+ }
+}
+
+void *
+nmctx_malloc(struct nmctx *ctx, size_t sz)
+{
+ return ctx->malloc(ctx, sz);
+}
+
+void
+nmctx_free(struct nmctx *ctx, void *p)
+{
+ ctx->free(ctx, p);
+}
+
+void
+nmctx_lock(struct nmctx *ctx)
+{
+ if (ctx->lock != NULL)
+ ctx->lock(ctx, 1);
+}
+
+void
+nmctx_unlock(struct nmctx *ctx)
+{
+ if (ctx->lock != NULL)
+ ctx->lock(ctx, 0);
+}
Added: head/lib/libnetmap/nmport.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/lib/libnetmap/nmport.c Fri Aug 28 20:03:54 2020 (r364936)
@@ -0,0 +1,810 @@
+/* $FreeBSD$ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <net/netmap_user.h>
+#define LIBNETMAP_NOTHREADSAFE
+#include "libnetmap.h"
+
+struct nmport_cleanup_d {
+ struct nmport_cleanup_d *next;
+ void (*cleanup)(struct nmport_cleanup_d *, struct nmport_d *);
+};
+
+static void
+nmport_push_cleanup(struct nmport_d *d, struct nmport_cleanup_d *c)
+{
+ c->next = d->clist;
+ d->clist = c;
+}
+
+static void
+nmport_pop_cleanup(struct nmport_d *d)
+{
+ struct nmport_cleanup_d *top;
+
+ top = d->clist;
+ d->clist = d->clist->next;
+ (*top->cleanup)(top, d);
+ nmctx_free(d->ctx, top);
+}
+
+void nmport_do_cleanup(struct nmport_d *d)
+{
+ while (d->clist != NULL) {
+ nmport_pop_cleanup(d);
+ }
+}
+
+static struct nmport_d *
+nmport_new_with_ctx(struct nmctx *ctx)
+{
+ struct nmport_d *d;
+
+ /* allocate a descriptor */
+ d = nmctx_malloc(ctx, sizeof(*d));
+ if (d == NULL) {
+ nmctx_ferror(ctx, "cannot allocate nmport descriptor");
+ goto out;
+ }
+ memset(d, 0, sizeof(*d));
+
+ nmreq_header_init(&d->hdr, NETMAP_REQ_REGISTER, &d->reg);
+
+ d->ctx = ctx;
+ d->fd = -1;
+
+out:
+ return d;
+}
+
+struct nmport_d *
+nmport_new(void)
+{
+ struct nmctx *ctx = nmctx_get();
+ return nmport_new_with_ctx(ctx);
+}
+
+
+void
+nmport_delete(struct nmport_d *d)
+{
+ nmctx_free(d->ctx, d);
+}
+
+void
+nmport_extmem_cleanup(struct nmport_cleanup_d *c, struct nmport_d *d)
+{
+ (void)c;
+
+ if (d->extmem == NULL)
+ return;
+
+ nmreq_remove_option(&d->hdr, &d->extmem->nro_opt);
+ nmctx_free(d->ctx, d->extmem);
+ d->extmem = NULL;
+}
+
+
+int
+nmport_extmem(struct nmport_d *d, void *base, size_t size)
+{
+ struct nmctx *ctx = d->ctx;
+ struct nmport_cleanup_d *clnup = NULL;
+
+ if (d->register_done) {
+ nmctx_ferror(ctx, "%s: cannot set extmem of an already registered port", d->hdr.nr_name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (d->extmem != NULL) {
+ nmctx_ferror(ctx, "%s: extmem already in use", d->hdr.nr_name);
+ errno = EINVAL;
+ return -1;
+ }
+
+ clnup = (struct nmport_cleanup_d *)nmctx_malloc(ctx, sizeof(*clnup));
+ if (clnup == NULL) {
+ nmctx_ferror(ctx, "failed to allocate cleanup descriptor");
+ errno = ENOMEM;
+ return -1;
+ }
+
+ d->extmem = nmctx_malloc(ctx, sizeof(*d->extmem));
+ if (d->extmem == NULL) {
+ nmctx_ferror(ctx, "%s: cannot allocate extmem option", d->hdr.nr_name);
+ nmctx_free(ctx, clnup);
+ errno = ENOMEM;
+ return -1;
+ }
+ memset(d->extmem, 0, sizeof(*d->extmem));
+ d->extmem->nro_usrptr = (uintptr_t)base;
+ d->extmem->nro_opt.nro_reqtype = NETMAP_REQ_OPT_EXTMEM;
+ d->extmem->nro_info.nr_memsize = size;
+ nmreq_push_option(&d->hdr, &d->extmem->nro_opt);
+
+ clnup->cleanup = nmport_extmem_cleanup;
+ nmport_push_cleanup(d, clnup);
+
+ return 0;
+}
+
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-head
mailing list