Date: Sun, 20 Sep 2020 14:53:26 -0700 From: Adrian Chadd <adrian@freebsd.org> To: Vincenzo Maffione <vmaffione@freebsd.org>, freebsd-current <freebsd-current@freebsd.org> Subject: Re: svn commit: r364936 - in head: lib lib/libnetmap share/mk Message-ID: <CAJ-Vmo=867GrRcgJqZ7oC=3FqLcM0jPdN4xouqxnwjeBQOZiPA@mail.gmail.com> In-Reply-To: <202008282003.07SK3tuD093523@repo.freebsd.org> References: <202008282003.07SK3tuD093523@repo.freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
hi! This code fails compilation on mips32 + gcc, as it assumes uint64_t and pointer casts are the same underlying size. === /usr/local/bin/mips-unknown-freebsd13.0-gcc9 --sysroot=/usr/home/adrian/work/freebsd/head-embedded/obj/mips_ap/usr/home/adrian/work/freebsd/head-embedded/src/mips.mips/tmp -B/usr/local/mips-unknown-freebsd13.0/bin/ -O -pipe -fno-common -G0 -EB -mabi=32 -msoft-float -march=mips32 -I/usr/home/adrian/work/freebsd/head-embedded/src/sys/net -I/usr/home/adrian/work/freebsd/head-embedded/src/lib/libnetmap -g -MD -MF.depend.nmport.o -MTnmport.o -std=gnu99 -Wno-format-zero-length -Wsystem-headers -Werror -Wall -Wno-format-y2k -Wno-uninitialized -Wno-pointer-sign -Wno-error=address -Wno-error=array-bounds -Wno-error=attributes -Wno-error=bool-compare -Wno-error=cast-align -Wno-error=clobbered -Wno-error=deprecated-declarations -Wno-error=enum-compare -Wno-error=extra -Wno-error=inline -Wno-error=logical-not-parentheses -Wno-error=strict-aliasing -Wno-error=uninitialized -Wno-error=unused-but-set-variable -Wno-error=unused-function -Wno-error=unused-value -Wno-error=empty-body -Wno-error=maybe-uninitialized -Wno-error=nonnull-compare -Wno-error=redundant-decls -Wno-error=shift-negative-value -Wno-error=tautological-compare -Wno-error=unused-const-variable -Wno-error=bool-operation -Wno-error=deprecated -Wno-error=expansion-to-defined -Wno-error=format-overflow -Wno-error=format-truncation -Wno-error=implicit-fallthrough -Wno-error=int-in-bool-context -Wno-error=memset-elt-size -Wno-error=noexcept-type -Wno-error=nonnull -Wno-error=pointer-compare -Wno-error=stringop-overflow -Wno-error=aggressive-loop-optimizations -Wno-error=cast-function-type -Wno-error=catch-value -Wno-error=multistatement-macros -Wno-error=restrict -Wno-error=sizeof-pointer-memaccess -Wno-error=stringop-truncation -Wno-error=empty-body -Wno-error=overflow -Wno-address-of-packed-member -c /usr/home/adrian/work/freebsd/head-embedded/src/lib/libnetmap/nmport.c -o nmport.o In file included from /usr/home/adrian/work/freebsd/head-embedded/src/lib/libnetmap/nmport.c:46: /usr/home/adrian/work/freebsd/head-embedded/src/lib/libnetmap/nmport.c: In function 'nmport_register': /usr/home/adrian/work/freebsd/head-embedded/src/lib/libnetmap/libnetmap.h:557:14: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast] 557 | for ((o_) = (struct nmreq_option *)((h_)->nr_options);\ | ^ /usr/home/adrian/work/freebsd/head-embedded/src/lib/libnetmap/nmport.c:547:3: note: in expansion of macro 'nmreq_foreach_option' 547 | nmreq_foreach_option(&d->hdr, o) { | ^~~~~~~~~~~~~~~~~~~~ /usr/home/adrian/work/freebsd/head-embedded/src/lib/libnetmap/libnetmap.h:559:14: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast] 559 | (o_) = (struct nmreq_option *)((o_)->nro_next)) | ^ /usr/home/adrian/work/freebsd/head-embedded/src/lib/libnetmap/nmport.c:547:3: note: in expansion of macro 'nmreq_foreach_option' 547 | nmreq_foreach_option(&d->hdr, o) { | ^~~~~~~~~~~~~~~~~~~~ /usr/home/adrian/work/freebsd/head-embedded/src/lib/libnetmap/nmport.c: In function 'nmport_mmap': /usr/home/adrian/work/freebsd/head-embedded/src/lib/libnetmap/nmport.c:617:13: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast] 617 | m->mem = (void *)d->extmem->nro_usrptr; | ^ cc1: all warnings being treated as errors *** [nmport.o] Error code 1 === Are you able to fix this? pretty please? :) -adrian On Fri, 28 Aug 2020 at 13:04, Vincenzo Maffione <vmaffione@freebsd.org> wrote: > 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 *** >
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAJ-Vmo=867GrRcgJqZ7oC=3FqLcM0jPdN4xouqxnwjeBQOZiPA>