Skip site navigation (1)Skip section navigation (2)
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>