[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Minios-devel] [UNIKRAFT PATCH v3] lib/uknetdev: Unikraft Network API
Hi Razvan,we are almost there. A few comments and could you run checkpatch on your source files (basically over 80 characters): support/scripts/checkpatch.pl -f [PATH-TO-SOURCE/HEADER_FILE] Next version does make it in. Thanks, Simon On 24.07.2018 10:50, Razvan Cojocaru wrote: Introduces the Unikraft Network API, that acts as a generalised interface between network drivers and network stack implementations (or low level networking applications). Using the function definitions in netdev_core.h, the driver should implement the functions in uk_netdev_opts and fill in the fields from uk_netdev and uk_netdev_data. The user-facing part of the API is in netdev.h. The network stack glue code can use these functions to configure network devices, as well as send/receive packets. Inspired from from DPDK RTE Ethernet API. Signed-off-by: Razvan Cojocaru <razvan.cojocaru93@xxxxxxxxx> --- lib/Config.uk | 1 + lib/Makefile.uk | 1 + lib/uknetdev/Config.uk | 12 + lib/uknetdev/Makefile.uk | 6 + lib/uknetdev/include/uk/netdev.h | 427 ++++++++++++++++++++++++++++++++++ lib/uknetdev/include/uk/netdev_core.h | 295 +++++++++++++++++++++++ lib/uknetdev/netdev.c | 246 ++++++++++++++++++++ 7 files changed, 988 insertions(+) create mode 100644 lib/uknetdev/Config.uk create mode 100644 lib/uknetdev/Makefile.uk create mode 100644 lib/uknetdev/include/uk/netdev.h create mode 100644 lib/uknetdev/include/uk/netdev_core.h create mode 100644 lib/uknetdev/netdev.c diff --git a/lib/Config.uk b/lib/Config.uk index e438603..003bd4f 100644 --- a/lib/Config.uk +++ b/lib/Config.uk @@ -37,3 +37,4 @@ source "lib/uklock/Config.uk" source "lib/ukmpi/Config.uk" source "lib/ukswrand/Config.uk" source "lib/ukbus/Config.uk" +source "lib/uknetdev/Config.uk" diff --git a/lib/Makefile.uk b/lib/Makefile.uk index 40c65d0..bcf22f3 100644 --- a/lib/Makefile.uk +++ b/lib/Makefile.uk @@ -19,3 +19,4 @@ $(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/vfscore)) $(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/uklock)) $(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/ukmpi)) $(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/ukbus)) +$(eval $(call _import_lib,$(CONFIG_UK_BASE)/lib/uknetdev)) diff --git a/lib/uknetdev/Config.uk b/lib/uknetdev/Config.uk new file mode 100644 index 0000000..bb427e1 --- /dev/null +++ b/lib/uknetdev/Config.uk @@ -0,0 +1,12 @@ +menuconfig LIBUKNETDEV + bool "uknetdev: Network driver interface" + default n + select LIBUKALLOC + +if LIBUKNETDEV +config LIBUKNETDEV_NAME + bool "Network device names" + default n + help + Support driver-defined names for network devices. +endif diff --git a/lib/uknetdev/Makefile.uk b/lib/uknetdev/Makefile.uk new file mode 100644 index 0000000..4b845a4 --- /dev/null +++ b/lib/uknetdev/Makefile.uk @@ -0,0 +1,6 @@ +$(eval $(call addlib_s,libuknetdev,$(CONFIG_LIBUKNETDEV))) + +CINCLUDES-$(CONFIG_LIBUKNETDEV) += -I$(LIBUKNETDEV_BASE)/include +CXXINCLUDES-$(CONFIG_LIBUKNETDEV) += -I$(LIBUKNETDEV_BASE)/include + +LIBUKBUS_SRCS-y += $(LIBUKNETDEV_BASE)/netdev.c diff --git a/lib/uknetdev/include/uk/netdev.h b/lib/uknetdev/include/uk/netdev.h new file mode 100644 index 0000000..ecc9444 --- /dev/null +++ b/lib/uknetdev/include/uk/netdev.h @@ -0,0 +1,427 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Authors: Simon Kuenzer <simon.kuenzer@xxxxxxxxx> + * Razvan Cojocaru <razvan.cojocaru93@xxxxxxxxx> + * + * Copyright (c) 2010-2017 Intel Corporation + * Copyright (c) 2018, NEC Europe Ltd., NEC Corporation. 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. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + * + * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. + */ +/* Taken and adapted from DPDK rte_ethdev.h */ + +#ifndef __UK_NETDEV__ +#define __UK_NETDEV__ + +/** + * Unikraft Network API + * + * The Unikraft NET API provides a generalized interface between Unikraft + * drivers and network stack implementations or low-level network applications. + * + * Most NET API functions take as parameter a reference to the corresponding + * Unikraft Network Device (struct uk_netdev) which can be obtained with a call + * to uk_netdev_get(). The network application should store this reference and + * use it for all subsequent API calls. + * + * The functions exported by the Unikraft NET API to setup a device + * designated by its ID must be invoked in the following order: + * - uk_netdev_configure() + * - uk_netdev_tx_queue_setup() + * - uk_netdev_rx_queue_setup() + * - uk_netdev_start() + * If the network application wants to change configurations (call queue_setup + * or configure again), it must call uk_netdev_stop() first to stop the + * device and then do the reconfiguration before calling uk_netdev_start() + * again. The transmit and receive functions should not be invoked when the + * device is stopped. + * In order to clean up all of the information stored in the configuration + * phase, uk_netdev_close() can be called, but only on a stopped device. + * + * There are 3 states in which a network device can be found: + * - UK_NETDEV_UNCONFIGURED + * - UK_NETDEV_CONFIGURED + * - UK_NETDEV_RUNNING + */ + + +#include <sys/types.h> +#include <stdint.h> +#include <stdio.h> +#include <errno.h> +#include <uk/list.h> +#include "netdev_core.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Get the number of available Unikraft Network devices. + * + * @return + * - (unsigned int): number of network devices. + */ +unsigned int uk_netdev_count(void); + +/** + * Get a reference to a Unikraft Network Device, based on its ID. + * This reference should be saved by the application and used for subsequent + * API calls. + * + * @param id + * The identifier of the Unikraft network device to configure. + * @return + * - NULL: device not found in list + * - (struct uk_netdev *): reference to be passed to API calls + */ +struct uk_netdev *uk_netdev_get(unsigned int id); + +/** + * Configure an Unikraft network device. + * This function must be invoked first before any other function in the + * Unikraft NET API. This function can also be re-invoked when a device is + * in the stopped state. + * + * @param dev + * The Unikraft Network Device. + * @param conf + * The pointer to the configuration data to be used for the Unikraft + * network device. + * + * Embedding all configuration information in a single data structure + * is the more flexible method that allows the addition of new features + * without changing the syntax of the API. + * @return + * - 0: Success, device configured. + * - <0: Error code returned by the driver configuration function. + */ +int uk_netdev_configure(struct uk_netdev *dev, + const struct uk_netdev_conf *conf); + +/** + * Start a Network device. + * + * The device start step is the last one and consists of setting the configured + * offload features and in starting the transmit and the receive units of the + * device. + * On success, all basic functions exported by the Unikraft NET API (link + * status, receive/transmit, and so on) can be invoked. + * + * @param dev + * The Unikraft Network Device. + * @return + * - 0: Success, Unikraft network device started. + * - <0: Error code of the driver device start function. + */ +int uk_netdev_start(struct uk_netdev *dev); + +/** + * Stop an Unikraft network device, and bring it to the UK_NETDEV_CONFIGURED + * state. + * The device can be restarted with a call to uk_netdev_start(). + * + * @param dev + * The Unikraft Network Device. + */ +void uk_netdev_stop(struct uk_netdev *dev); + +/** + * Close a stopped Unikraft network device. + * The function frees all resources except for needed by the + * UK_NETDEV_UNCONFIGURED state. + * + * @param dev + * The Unikraft Network Device. + */ +void uk_netdev_close(struct uk_netdev *dev); + +/** + * Set the MAC address. + * + * @param dev + * The Unikraft Network Device. + * @param mac_addr + * New MAC address. + * @return + * - (0) if successful. + * - (-ENOTSUP) if hardware doesn't support. + * - (-EINVAL) if MAC address is invalid. + */ +int uk_netdev_mac_addr_set(struct uk_netdev *dev, + const struct uk_hwaddr *mac_addr); + +/** + * Returns the MAC address of the Unikraft network device. + * + * @param dev + * The Unikraft Network Device. + * @return + * - (NULL) no MAC address available + * - MAC address + */ +const struct uk_hwaddr *uk_netdev_mac_addr_get(struct uk_netdev *dev); + +/** + * Enable receipt in promiscuous mode for an Unikraft network device. + * + * @param dev + * The Unikraft Network Device. + * @return + * - (0) if successful. + * - (-ENOTSUP) if driver doesn't support promiscuous mode. + */ +int uk_netdev_promiscuous_enable(struct uk_netdev *dev); + +/** + * Disable receipt in promiscuous mode for an Unikraft network device. + * + * @param dev + * The Unikraft Network Device. + * @return + * - (0) if successful. + * - (-ENOTSUP) if driver doesn't support promiscuous mode. + */ +int uk_netdev_promiscuous_disable(struct uk_netdev *dev); + +/** + * Return the value of promiscuous mode for an Unikraft network device. + * + * @param dev + * The Unikraft Network Device. + * @return + * - (1) if promiscuous is enabled + * - (0) if promiscuous is disabled. + * - (-1) on error + */ +int uk_netdev_promiscuous_get(struct uk_netdev *dev); + +/** + * Extra configuration query interface. + * The user can query the driver for any additional information, using a + * number of pre-defined configuration types. + * + * If the driver doesn't support the provided data type, it must return NULL. + * + * This allows the driver to provide configuration data without the need of + * parsing it in a pre-determined way, eliminating the need for utility + * functions in the API, or parsing the data multiple times both by driver + * and user. + * + * @param dev + * The Unikraft Network Device. + * @param econf + * Extra configuration data type. + * @return + * - (NULL) if configuration unavailable or data type unsupported + * - configuration in format specified by *econf* + */ +static inline const void *uk_netdev_extra_conf_get(struct uk_netdev *dev, + enum uk_netdev_extra_conf_type econf) +{ + if (!dev->dev_ops->econf_get) + return NULL; /* driver does not provide + any extra configuration */ + return dev->dev_ops->econf_get(dev, econf); +} + +/** + * Change the MTU of an Unikraft network device. + * + * @param dev + * The Unikraft Network Device. + * @param mtu + * A uint16_t for the MTU to be applied. + * @return + * - (0) if successful. + * - (-ENOTSUP) if operation is not supported. + * - (-EIO) if device is removed. + * - (-EINVAL) if *mtu* invalid. + * - (-EBUSY) if operation is not allowed when the device is running + */ +int uk_netdev_mtu_set(struct uk_netdev *dev, uint16_t mtu); + +/** + * Returns the MTU of an Unikraft network device. + * + * @param dev + * The Unikraft Network Device. + * @return + * - (>0) MTU of the uk_netdev + * - (-ENOTSUP) driver did not set a MTU. + */ +int uk_netdev_mtu_get(struct uk_netdev *dev); + +/** + * Returns the name of the Unikraft network device. + * If name is not defined by driver, returns NULL + * + * @param dev + * The Unikraft Network Device. + * @return + * - NULL if no name defined or names unsupported. + * - String if name is available. + */ +const char *uk_netdev_name_get(struct uk_netdev *dev); + +/** + * Set the name of the Unikraft network device. + * Should only be called by the driver. + * The name is copied into a pre-allocated buffer in the uk_netdev. + * If the len param is smaller than the name string length, a substring + * of the provided name will be saved. + * + * @param dev + * The Unikraft Network Device. + * @param name + * String containing the name. + * @param len + * Length of the string. + * @return + * - (0): success. + * - (-ENOTSUP): names not supported. + * - (-EINVAL): name too long or invalid string. + */ +int uk_netdev_name_set(struct uk_netdev *dev, const char *name, size_t len); + +/** + * Allocate and set up a receive queue for an Unikraft network device. + * + * The function handles setup of receive callback for interrupt-based modes. + * + * @param dev + * The Unikraft Network Device. + * @param rx_queue_id + * The index of the receive queue to set up. + * The value must be in the range [0, nb_rx_queue - 1] previously supplied + * to uk_netdev_eth_dev_configure(). + * @param rx_conf + * The pointer to the configuration data to be used for the receive queue. + * NULL value is allowed, in which case default RX configuration + * will be used. + * The *rx_conf* structure contains an *rx_thresh* structure with the values + * of the Prefetch, Host, and Write-Back threshold registers of the receive + * ring. + * In addition it contains the hardware offloads features to activate using + * the DEV_RX_OFFLOAD_* flags. + * @return + * - 0: Success, receive queue correctly set up. + * - -EIO: if device is removed. Hum, -ENOMEM could happen here, too, right (Unable to allocate the receive ring descriptors)? + */ +int uk_netdev_rx_queue_setup(struct uk_netdev *dev, uint16_t rx_queue_id, + const struct uk_netdev_rxqueue_conf *rx_conf); + +/** + * Allocate and set up a transmit queue for an Unikraft network device. + * + * @param dev + * The Unikraft Network Device. + * @param tx_queue_id + * The index of the transmit queue to set up. + * The value must be in the range [0, nb_tx_queue - 1] previously supplied + * to uk_netdev_configure(). + * @param tx_conf + * The pointer to the configuration data to be used for the transmit queue. + * NULL value is allowed, in which case default TX configuration + * will be used. + * @return + * - 0: Success, the transmit queue is correctly set up. + * - -ENOMEM: Unable to allocate the transmit ring descriptors. -EIO does not happen here? Actually, I think we can ignore -EIO for now. It is okay to assume that we cannot remove devices. + */ +int uk_netdev_tx_queue_setup(struct uk_netdev *dev, uint16_t tx_queue_id, + const struct uk_netdev_txqueue_conf *tx_conf); + +/** + * Enable interrupts for an RX queue. + * + * @param dev + * The Unikraft Network Device. + * @return + * - 0: Success, interrupts enabled. + * - (-ENOTSUP): Driver does not support interrupt enable. + */ +int uk_netdev_rx_enable_intr(struct uk_netdev *dev, + uint16_t rx_queue_id); + +/** + * Disable interrupts for an RX queue. + * + * @param dev + * The Unikraft Network Device. + * @return + * - 0: Success, interrupts enabled. + * - (-ENOTSUP): Driver does not support interrupt disable. + */ +int uk_netdev_rx_disable_intr(struct uk_netdev *dev, + uint16_t rx_queue_id); + +/** + * Basic RX function. + * + * @param dev + * The Unikraft Network Device. + * @param pkt + * The buffer in which the received packet will be placed. + * @param queue_id + * The index of the receive queue from which to retrieve input packets. + * @return + * - 0: No new packets + * - >0: Length of the received packet + */ +int uk_netdev_rx(struct uk_netdev *dev, uint16_t queue_id, + struct uk_netdev_mbuf *pkt); + +/** + * Basic TX function. + * + * @param dev + * The Unikraft Network Device. + * @param queue_id + * The index of the transmit queue through which output packets must be + * sent. + * @param pkt + * The buffer containing the packet to be sent. + * @return + */ +int uk_netdev_tx(struct uk_netdev *dev, uint16_t queue_id, + struct uk_netdev_mbuf *pkt); Can we set *pkt also to const?Btw, can I free the packet buffer when the funciton returns? Does it return when the transmission is done? Maybe one sentence about this should be in the description. + +/** + * Add a new Unikraft network device in the device list. + * Should be called by the driver in the configuration step. + * + * @param dev + * The Unikraft Network Device. + */ +void uk_netdev_register(struct uk_netdev *dev); + +#ifdef __cplusplus +} +#endif + +#endif //__UK_NETDEV__ diff --git a/lib/uknetdev/include/uk/netdev_core.h b/lib/uknetdev/include/uk/netdev_core.h new file mode 100644 index 0000000..c8fe527 --- /dev/null +++ b/lib/uknetdev/include/uk/netdev_core.h @@ -0,0 +1,295 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Authors: Razvan Cojocaru <razvan.cojocaru93@xxxxxxxxx> + * + * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2018, NEC Europe Ltd., NEC Corporation. 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. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + * + * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. + */ +/* Taken and adapted from DPDK rte_ethdev_core.h */ + +#ifndef __UK_NETDEV_CORE__ +#define __UK_NETDEV_CORE__ + +/** + * Unikraft Network Device internal header. + * + * This header contains internal data types. But they are still part of the + * public API because they are used by inline functions in the published API. + * + * The device data and operations are separated. This split allows the + * function pointer and driver data to be per-process, while the actual + * configuration data for the device is shared. + */ + + +#include <uk/config.h> + + +#define UK_NETDEV_NAME_MAX_LEN 64 +#define UK_HWADDR_LEN 6 /**< Length of Ethernet address. */ + + +struct uk_hwaddr { + uint8_t addr_bytes[UK_HWADDR_LEN]; /**< Addr bytes in tx order */ +} __packed; + +/** + * A structure used to hold a single packet. + */ +struct uk_netdev_mbuf { + void *payload; /**< Address of packet buffer. */ + uint32_t len; /**< Total packet length. */ +}; + +/** + * A set of values to describe the possible states of an eth device. + */ +enum uk_netdev_state { + UK_NETDEV_UNCONFIGURED = 0, + UK_NETDEV_CONFIGURED, + UK_NETDEV_RUNNING, +}; + +/** + * A structure used to configure an Unikraft network device. + */ +struct uk_netdev_conf { +}; + +/** + * Generic type enum used by the extra configuration query interface. + * + * The purpose of this generic type is to allow drivers to define extra + * configurations such as IP information, without the need to parse this data. + * This prevents the need to introduce any additional parsing logic inside + * uknetdev API. + * + * This list is extensible in the future without needing the drivers to adopt + * any or all of the data types. + */ +enum uk_netdev_extra_conf_type { + IPv4ADDR_INT, /**< IPv4 address as network-order raw int (4 bytes) */ + IPv4ADDR_STR, /**< IPv4 address as null-terminated string */ + IPv4MASK_INT, /**< IPv4 mask as network-order raw int (4 bytes) */ + IPv4MASK_STR, /**< IPv4 mask as null-terminated string */ + IPv4GW_INT, /**< IPv4 gateway as network-order raw int (4 bytes) */ + IPv4GW_STR, /**< IPv4 gateway as null-terminated string */ + IPv4DNS0_INT, /**< IPv4 DNS as network-order raw int (4 bytes) */ + IPv4DNS0_STR, /**< IPv4 DNS as null-terminated string */ +}; + +UK_TAILQ_HEAD(uk_netdev_list, struct uk_netdev); + +#define UK_NETDEV_LIST_FOREACH(b) \ + UK_TAILQ_FOREACH(b, &uk_netdev_list, next) + +/** + * Function type used for queue callbacks, such as RX/TX packets. + * + * @param dev + * The Unikraft Network Device. + * @param queue + * The queue on the Unikraft network device on which the event is triggered. + */ +typedef void (*uk_netdev_queue_event_t)(struct uk_netdev *dev, + uint16_t queue_id); + +/** + * A structure used to configure an Unikraft network device RX queue. + */ +struct uk_netdev_rxqueue_conf { + uk_netdev_queue_event_t rx_cb; +}; Could we add struct uk_alloc *a that shall be used as allocator for the descriptor rings (and potentially receiver buffers)? DPDK does this similarly to ensure NUMA affinity. We may want this paramter later for performance tuning. + +/** + * A structure used to configure an Unikraft network device TX queue. + */ +struct uk_netdev_txqueue_conf { +}; Could we add struct uk_alloc *a that shall be used as allocator for the descriptor rings? + + +typedef int (*uk_netdev_configure_t)(struct uk_netdev *dev, + const struct uk_netdev_conf *conf); +/**< @internal Unikraft network device configuration. */ + +typedef int (*uk_netdev_start_t)(struct uk_netdev *dev); +/**< @internal Function used to start a configured Unikraft network device. */ + +typedef void (*uk_netdev_stop_t)(struct uk_netdev *dev); +/**< @internal Function used to stop a configured Unikraft network device. */ + +typedef void (*uk_netdev_close_t)(struct uk_netdev *dev); +/**< @internal Function used to close a configured Unikraft network device. */ + +typedef int (*uk_netdev_mac_addr_set_t)(struct uk_netdev *dev, + const struct uk_hwaddr *mac_addr); +/**< @internal Set the MAC address */ + +typedef int (*uk_netdev_mtu_set_t)(struct uk_netdev *dev, uint16_t mtu); +/**< @internal Set MTU. */ + +typedef int (*uk_netdev_mtu_get_t)(struct uk_netdev *dev); +/**< @internal Get MTU. */ + +typedef int (*uk_netdev_promiscuous_enable_t)(struct uk_netdev *dev); +/**< @internal Function used to enable the RX promiscuous mode of an + * Unikraft network device. + */ + +typedef int (*uk_netdev_promiscuous_disable_t)(struct uk_netdev *dev); +/**< @internal Function used to disable the RX promiscuous mode of an + * Unikraft network device. + */ + +typedef const void *(*uk_netdev_econf_get_t)(struct uk_netdev *dev, + enum uk_netdev_extra_conf_type econf); +/**< @internal Read any extra configuration provided by the driver */ + +typedef int (*uk_netdev_rx_queue_setup_t)(struct uk_netdev *dev, + uint16_t rx_queue_id, const struct uk_netdev_rxqueue_conf *rx_conf); +/**< @internal Set up a receive queue of an Unikraft network device. */ + +typedef int (*uk_netdev_tx_queue_setup_t)(struct uk_netdev *dev, + uint16_t tx_queue_id, const struct uk_netdev_txqueue_conf *tx_conf); +/**< @internal Setup a transmit queue of an Unikraft network device. */ + +typedef void (*uk_netdev_queue_release_t)(void *queue); +/**< @internal Release memory resources allocated by given RX/TX queue. */ + +typedef int (*uk_netdev_rx_enable_intr_t)(struct uk_netdev *dev, + uint16_t rx_queue_id); +/**< @internal Enable interrupt of a receive queue of an + * Unikraft network device. + */ + +typedef int (*uk_netdev_rx_disable_intr_t)(struct uk_netdev *dev, + uint16_t rx_queue_id); +/**< @internal Disable interrupt of a receive queue of an + * Unikraft network device. + */ + +typedef int (*uk_netdev_rx_t)(struct uk_netdev *dev, uint16_t queue_id, + struct uk_netdev_mbuf *pkt); +/**< @internal Retrieve one input packet from an Unikraft network device. */ + +typedef int (*uk_netdev_tx_t)(struct uk_netdev *dev, uint16_t queue_id, + struct uk_netdev_mbuf *pkt); const for *pkt? +/**< @internal Send one output packet to an Unikraft network device. */ + + +/** + * @internal A structure containing the functions exported by a driver. + */ +struct uk_netdev_ops { + uk_netdev_configure_t dev_configure; /**< Configure device. */ + uk_netdev_start_t dev_start; /**< Start device. */ + uk_netdev_stop_t dev_stop; /**< Stop device. */ + uk_netdev_close_t dev_close; /**< Close device. */ + + uk_netdev_mac_addr_set_t mac_addr_set; /**< Set a MAC address. */ + uk_netdev_mtu_set_t mtu_set; /**< Set MTU. */ + uk_netdev_econf_get_t econf_get; /**< Return additional config. */ + + /** Promiscuous ON. */ + uk_netdev_promiscuous_enable_t promiscuous_enable; + /** Promiscuous OFF. */ + uk_netdev_promiscuous_disable_t promiscuous_disable; + + /** Set up device RX queue. */ + uk_netdev_rx_queue_setup_t rx_queue_setup; + /** Release RX queue. */ + uk_netdev_queue_release_t rx_queue_release; + + /** Set up device TX queue. */ + uk_netdev_tx_queue_setup_t tx_queue_setup; + /** Release TX queue. */ + uk_netdev_queue_release_t tx_queue_release; + + uk_netdev_rx_enable_intr_t rx_enable_intr; /**< Enable RX interrupts*/ + uk_netdev_rx_disable_intr_t rx_disable_intr;/**< Disable RX interrupts*/ +}; + +/** + * @internal + * The data part, with no function pointers, associated with each + * network device. + * + * This structure is safe to place in shared memory to be common among different + * processes in a multi-process configuration. + */ +struct uk_netdev_data { +#ifdef CONFIG_LIBUKNETDEV_NAME + char name[UK_NETDEV_NAME_MAX_LEN]; /**< Network device name */ +#else + const char *name; /**< Network device name */ +#endif + uint16_t id; /**< Device [external] port identifier. */ + + struct uk_hwaddr mac_addr; /**< Device Ethernet Link address. */ + uint16_t mtu; /**< Maximum Transmission Unit. */ + + uint8_t promiscuous : 1; /**< RX promiscuous mode ON(1) / OFF(0). */ + + enum uk_netdev_state state; /**< Flag indicating the device state */ + uint8_t rx_queue_state; + /**< Queues state: STARTED(1) / STOPPED(0) */ + uint8_t tx_queue_state; + /**< Queues state: STARTED(1) / STOPPED(0) */ +}; + +/** + * @internal + * The generic data structure associated with each network device. + * + * Pointers to all the function callbacks registered by the driver, along + * with the pointer to where all the data elements for the particular device + * are stored in shared memory. This split allows the function pointer and + * driver data to be per-process, while the actual configuration data for + * the device is shared. + * + * Packet RX/TX functions are added directly to this structure for performance + * reasons, in order to prevent another indirection layer to dev_ops. + */ +struct uk_netdev { + UK_TAILQ_ENTRY(struct uk_netdev) next; + + uk_netdev_rx_t rx_pkt; /**< Pointer to receive function. */ + uk_netdev_tx_t tx_pkt; /**< Pointer to transmit function. */ + + /**< Pointer to device data */ + struct uk_netdev_data *data; + /**< Functions exported by driver */ + const struct uk_netdev_ops *dev_ops; + + /** User-supplied function called from driver on new packet RX */ + uk_netdev_queue_event_t rx_cb; +}; + +#endif //__UK_NETDEV_CORE__ diff --git a/lib/uknetdev/netdev.c b/lib/uknetdev/netdev.c new file mode 100644 index 0000000..0e8d04c --- /dev/null +++ b/lib/uknetdev/netdev.c @@ -0,0 +1,246 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Authors: Simon Kuenzer <simon.kuenzer@xxxxxxxxx> + * Razvan Cojocaru <razvan.cojocaru93@xxxxxxxxx> + * + * Copyright (c) 2017-2018, NEC Europe Ltd., NEC Corporation. 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. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + * + * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. + */ + +#include <string.h> +#include <uk/netdev.h> +#include <uk/alloc.h> +#include <uk/assert.h> +#include <uk/print.h> +#include <uk/plat/ctors.h> + +#define UK_NETDEV_CTOR_PRIO (102U) + +struct uk_netdev_list uk_netdev_list; +static uint16_t netdev_count; + +/* This library does not have any dependency to another library for + * initialization, except a libc -> We use priority 1 + */ +static void _uk_netdev_ctor(void) __constructor_prio(UK_NETDEV_CTOR_PRIO); + +void uk_netdev_register(struct uk_netdev *dev) +{ + UK_ASSERT(dev != NULL); + + uk_printd(DLVL_INFO, "Register netdev%u: %p\n", + netdev_count, dev); + dev->data->id = netdev_count; + UK_TAILQ_INSERT_TAIL(&uk_netdev_list, dev, next); + + ++netdev_count; +} + +unsigned int uk_netdev_count(void) +{ + return netdev_count; +} + +struct uk_netdev *uk_netdev_get(unsigned int id) +{ + struct uk_netdev *n; + + UK_NETDEV_LIST_FOREACH(n) { + if (n->data->id == id) + return n; + } + return NULL; +} + +int uk_netdev_configure(struct uk_netdev *dev, + const struct uk_netdev_conf *eth_conf) +{ + UK_ASSERT(dev); + uk_printd(DLVL_INFO, "Configure device 0x%p\n", dev); + + return dev->dev_ops->dev_configure(dev, eth_conf); +} + +int uk_netdev_rx_queue_setup(struct uk_netdev *dev, uint16_t rx_queue_id, + const struct uk_netdev_rxqueue_conf *rx_conf) +{ + UK_ASSERT(dev); + UK_ASSERT(rx_conf); + + uk_printd(DLVL_INFO, "Configure device 0x%p: Setting up callback for " + "rx_queue %u: 0x%p\n", dev, rx_queue_id, rx_conf->rx_cb); Strings of messages are the only exception for beign over 80 characters. It makes 'grep'ing for a output line easier: uk_printd(DLVL_INFO,"Configure device 0x%p: Setting up callback for rx_queue %u: 0x%p\n", dev, rx_queue_id, rx_conf->rx_cb); + dev->rx_cb = rx_conf->rx_cb; + + return dev->dev_ops->rx_queue_setup(dev, rx_queue_id, rx_conf); +} + +int uk_netdev_tx_queue_setup(struct uk_netdev *dev, uint16_t tx_queue_id, + const struct uk_netdev_txqueue_conf *tx_conf) +{ + UK_ASSERT(dev); + return dev->dev_ops->tx_queue_setup(dev, tx_queue_id, tx_conf); +} + +int uk_netdev_start(struct uk_netdev *dev) +{ + UK_ASSERT(dev); + return dev->dev_ops->dev_start(dev); +} + +void uk_netdev_stop(struct uk_netdev *dev) +{ + UK_ASSERT(dev); + dev->dev_ops->dev_stop(dev); +} + +int uk_netdev_mac_addr_set(struct uk_netdev *dev, + const struct uk_hwaddr *mac_addr) +{ + int rc; + + UK_ASSERT(dev); + if (dev->dev_ops->mac_addr_set == NULL) + return -ENOTSUP; + rc = dev->dev_ops->mac_addr_set(dev, mac_addr); + if (rc >= 0) + memcpy(&dev->data->mac_addr, mac_addr, sizeof(struct uk_hwaddr)); + return rc; +} + +const struct uk_hwaddr *uk_netdev_mac_addr_get(struct uk_netdev *dev) +{ + UK_ASSERT(dev); + return &dev->data->mac_addr; +} + +const char *uk_netdev_name_get(struct uk_netdev *dev) +{ + UK_ASSERT(dev); +#ifdef CONFIG_LIBUKNETDEV_NAME + return dev->data->name; +#else + return NULL; +#endif +} + +int uk_netdev_name_set(struct uk_netdev *dev, const char *name, size_t len) { + UK_ASSERT(dev); +#ifdef CONFIG_LIBUKNETDEV_NAME + if (len >= UK_NETDEV_NAME_MAX_LEN) + return -EINVAL; + strncpy(dev->data->name, name, len); + dev->data->name[len] = '\0'; + return 0; +#else + return -ENOTSUP; +#endif +} + +int uk_netdev_mtu_set(struct uk_netdev *dev, uint16_t mtu) +{ + int rc; + + UK_ASSERT(dev); + if (dev->dev_ops->mtu_set == NULL) + return -ENOTSUP; + rc = dev->dev_ops->mtu_set(dev, mtu); + if (rc >= 0) + dev->data->mtu = mtu; + return rc; +} + +int uk_netdev_mtu_get(struct uk_netdev *dev) +{ + UK_ASSERT(dev); + return dev->data->mtu; +} + +int uk_netdev_promiscuous_enable(struct uk_netdev *dev) +{ + UK_ASSERT(dev); + if (!dev->dev_ops->promiscuous_enable) + return -ENOTSUP; + else + return dev->dev_ops->promiscuous_enable(dev); +} + +int uk_netdev_promiscuous_disable(struct uk_netdev *dev) +{ + UK_ASSERT(dev); + if (!dev->dev_ops->promiscuous_disable) + return -ENOTSUP; + else + return dev->dev_ops->promiscuous_disable(dev); +} + +int uk_netdev_promiscuous_get(struct uk_netdev *dev) +{ + UK_ASSERT(dev); + return dev->data->promiscuous; +} + +int uk_netdev_rx_enable_intr(struct uk_netdev *dev, + uint16_t rx_queue_id) +{ + UK_ASSERT(dev); + if (!dev->dev_ops->rx_enable_intr) + return -ENOTSUP; + return dev->dev_ops->rx_enable_intr(dev, rx_queue_id); +} + +int uk_netdev_rx_disable_intr(struct uk_netdev *dev, + uint16_t rx_queue_id) +{ + UK_ASSERT(dev); + if (!dev->dev_ops->rx_disable_intr) + return -ENOTSUP; + return dev->dev_ops->rx_disable_intr(dev, rx_queue_id); +} + +int uk_netdev_rx(struct uk_netdev *dev, uint16_t queue_id, + struct uk_netdev_mbuf *pkt) +{ + UK_ASSERT(dev); + UK_ASSERT(pkt); + return dev->rx_pkt(dev, queue_id, pkt); +} + +int uk_netdev_tx(struct uk_netdev *dev, uint16_t queue_id, + struct uk_netdev_mbuf *pkt) +{ + UK_ASSERT(dev); + UK_ASSERT(pkt); + return dev->tx_pkt(dev, queue_id, pkt); +} + +static void _uk_netdev_ctor(void) +{ + UK_TAILQ_INIT(&uk_netdev_list); + netdev_count = 0; +} Thanks, Simon _______________________________________________ Minios-devel mailing list Minios-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/minios-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |