45c67e8f6b
No functional changes intended.
718 lines
27 KiB
C
718 lines
27 KiB
C
/*-
|
|
* 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.
|
|
*
|
|
* offset (multi-key)
|
|
* reserve (part of) the ptr fields as an offset field
|
|
* and write an initial offset into them.
|
|
*
|
|
* The keys are:
|
|
*
|
|
* bits number of bits of ptr to use
|
|
* *initial initial offset value
|
|
*
|
|
* initial must be assigned. If bits is omitted, it
|
|
* defaults to the entire ptr field. The max offset is set
|
|
* at the same value as the initial offset. Note that the
|
|
* actual values may be increased by the kernel.
|
|
*
|
|
* This option is disabled by default (see
|
|
* nmport_enable_option() below)
|
|
*/
|
|
|
|
|
|
/* 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);
|
|
|
|
|
|
/* nmport_offset - use offsets for this port
|
|
* @initial the initial offset for all the slots
|
|
* @maxoff the maximum offset
|
|
* @bits the number of bits of slot->ptr to use for the offsets
|
|
* @mingap the minimum gap between offsets (in shared buffers)
|
|
*
|
|
* With this option the lower @bits bits of the ptr field in the netmap_slot
|
|
* can be used to specify an offset into the buffer. All offsets will be set
|
|
* to the @initial value by netmap.
|
|
*
|
|
* The offset field can be read and updated using the bitmask found in
|
|
* ring->offset_mask after a successful register. netmap_user.h contains
|
|
* some helper macros (NETMAP_ROFFSET, NETMAP_WOFFSET and NETMAP_BUF_OFFSET).
|
|
*
|
|
* For RX rings, the user writes the offset o in an empty slot before passing
|
|
* it to netmap; then, netmap will write the incoming packet at an offset o' >=
|
|
* o in the buffer. o' may be larger than o because of, e.g., alignment
|
|
* constrains. If o' > o netmap will also update the offset field in the slot.
|
|
* Note that large offsets may cause the port to split the packet over several
|
|
* slots, setting the NS_MOREFRAG flag accordingly.
|
|
*
|
|
* For TX rings, the user may prepare the packet to send at an offset o into
|
|
* the buffer and write o in the offset field. Netmap will send the packets
|
|
* starting o bytes in the buffer. Note that the address of the packet must
|
|
* comply with any alignment constraints that the port may have, or the result
|
|
* will be undefined. The user may read the alignment constraint in the new
|
|
* ring->buf_align field. It is also possible that empty slots already come
|
|
* with a non-zero offset o specified in the offset field. In this case, the
|
|
* user will have to write the packet at an offset o' >= o.
|
|
*
|
|
* The user must also declare the @maxoff offset that she is going to use. Any
|
|
* offset larger than this will be truncated.
|
|
*
|
|
* The user may also declare a @mingap (ignored if zero) if she plans to use
|
|
* offsets to share the same buffer among several slots. Netmap will guarantee
|
|
* that it will never write more than @mingap bytes for each slot, irrespective
|
|
* of the buffer length.
|
|
*/
|
|
int nmport_offset(struct nmport_d *d, uint64_t initial, uint64_t maxoff,
|
|
uint64_t bits, uint64_t mingap);
|
|
|
|
/* 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 *)((uintptr_t)((h_)->nr_options));\
|
|
(o_) != NULL;\
|
|
(o_) = (struct nmreq_option *)((uintptr_t)((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_ */
|