diff options
Diffstat (limited to 'platform/linux-generic/pktio/netmap.c')
-rw-r--r-- | platform/linux-generic/pktio/netmap.c | 973 |
1 files changed, 0 insertions, 973 deletions
diff --git a/platform/linux-generic/pktio/netmap.c b/platform/linux-generic/pktio/netmap.c deleted file mode 100644 index 928bb00af..000000000 --- a/platform/linux-generic/pktio/netmap.c +++ /dev/null @@ -1,973 +0,0 @@ -/* Copyright (c) 2015, Linaro Limited - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifdef ODP_NETMAP - -#include <odp_posix_extensions.h> - -#include <odp/api/plat/packet_inlines.h> -#include <odp/api/packet.h> - -#include <odp_packet_io_internal.h> -#include <odp_packet_netmap.h> -#include <odp_packet_socket.h> -#include <odp_debug_internal.h> -#include <protocols/eth.h> - -#include <sys/ioctl.h> -#include <poll.h> -#include <linux/ethtool.h> -#include <linux/sockios.h> -#include <odp_classification_datamodel.h> -#include <odp_classification_inlines.h> -#include <odp_classification_internal.h> - -#include <inttypes.h> - -/* Disable netmap debug prints */ -#ifndef ND -#define ND(_fmt, ...) do {} while (0) -#define D(_fmt, ...) do {} while (0) -#define RD(lps, format, ...) do {} while (0) -#endif - -#define NETMAP_WITH_LIBS -#include <net/netmap_user.h> - -#define NM_WAIT_TIMEOUT 10 /* netmap_wait_for_link() timeout in seconds */ -#define NM_INJECT_RETRIES 10 - -static int disable_pktio; /** !0 this pktio disabled, 0 enabled */ -static int netmap_stats_reset(pktio_entry_t *pktio_entry); - -static int netmap_do_ioctl(pktio_entry_t *pktio_entry, unsigned long cmd, - int subcmd) -{ - pkt_netmap_t *pkt_nm = &pktio_entry->s.pkt_nm; - struct ethtool_value eval; - struct ifreq ifr; - int err; - int fd = pkt_nm->sockfd; - - memset(&ifr, 0, sizeof(ifr)); - snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", - pktio_entry->s.pkt_nm.if_name); - - switch (cmd) { - case SIOCSIFFLAGS: - ifr.ifr_flags = pkt_nm->if_flags & 0xffff; - break; - case SIOCETHTOOL: - eval.cmd = subcmd; - eval.data = 0; - ifr.ifr_data = (caddr_t)&eval; - break; - default: - break; - } - err = ioctl(fd, cmd, &ifr); - if (err) - goto done; - - switch (cmd) { - case SIOCGIFFLAGS: - pkt_nm->if_flags = (ifr.ifr_flags << 16) | - (0xffff & ifr.ifr_flags); - break; - case SIOCETHTOOL: - if (subcmd == ETHTOOL_GLINK) - return eval.data; - break; - default: - break; - } -done: - if (err) - ODP_ERR("ioctl err %d %lu: %s\n", err, cmd, strerror(errno)); - - return err; -} - -/** - * Map netmap rings to pktin/pktout queues - * - * @param rings Array of netmap descriptor rings - * @param num_queues Number of pktin/pktout queues - * @param num_rings Number of matching netmap rings - */ -static inline void map_netmap_rings(netmap_ring_t *rings, - unsigned num_queues, unsigned num_rings) -{ - struct netmap_ring_t *desc_ring; - unsigned rings_per_queue; - unsigned remainder; - unsigned mapped_rings; - unsigned i; - unsigned desc_id = 0; - - rings_per_queue = num_rings / num_queues; - remainder = num_rings % num_queues; - - if (remainder) - ODP_DBG("WARNING: Netmap rings mapped unevenly to queues\n"); - - for (i = 0; i < num_queues; i++) { - desc_ring = &rings[i].s; - if (i < remainder) - mapped_rings = rings_per_queue + 1; - else - mapped_rings = rings_per_queue; - - desc_ring->first = desc_id; - desc_ring->cur = desc_id; - desc_ring->last = desc_ring->first + mapped_rings - 1; - desc_ring->num = mapped_rings; - - desc_id = desc_ring->last + 1; - } -} - -static int netmap_input_queues_config(pktio_entry_t *pktio_entry, - const odp_pktin_queue_param_t *p) -{ - pkt_netmap_t *pkt_nm = &pktio_entry->s.pkt_nm; - odp_pktin_mode_t mode = pktio_entry->s.param.in_mode; - unsigned num_queues = p->num_queues; - odp_bool_t lockless; - - /* Scheduler synchronizes input queue polls. Only single thread - * at a time polls a queue */ - if (mode == ODP_PKTIN_MODE_SCHED) - lockless = 1; - else - lockless = (p->op_mode == ODP_PKTIO_OP_MT_UNSAFE); - - if (p->hash_enable && num_queues > 1) { - if (rss_conf_set_fd(pktio_entry->s.pkt_nm.sockfd, - pktio_entry->s.pkt_nm.if_name, - &p->hash_proto)) { - ODP_ERR("Failed to configure input hash\n"); - return -1; - } - } - - pkt_nm->lockless_rx = lockless; - - return 0; -} - -static int netmap_output_queues_config(pktio_entry_t *pktio_entry, - const odp_pktout_queue_param_t *p) -{ - pkt_netmap_t *pkt_nm = &pktio_entry->s.pkt_nm; - - pkt_nm->lockless_tx = (p->op_mode == ODP_PKTIO_OP_MT_UNSAFE); - - return 0; -} - -/** - * Close netmap descriptors - * - * Can be reopened using netmap_start() function. - * - * @param pktio_entry Packet IO entry - */ -static inline void netmap_close_descriptors(pktio_entry_t *pktio_entry) -{ - int i, j; - pkt_netmap_t *pkt_nm = &pktio_entry->s.pkt_nm; - - for (i = 0; i < PKTIO_MAX_QUEUES; i++) { - for (j = 0; j < NM_MAX_DESC; j++) { - if (pkt_nm->rx_desc_ring[i].s.desc[j] != NULL) { - nm_close(pkt_nm->rx_desc_ring[i].s.desc[j]); - pkt_nm->rx_desc_ring[i].s.desc[j] = NULL; - } - } - for (j = 0; j < NM_MAX_DESC; j++) { - if (pkt_nm->tx_desc_ring[i].s.desc[j] != NULL) { - nm_close(pkt_nm->tx_desc_ring[i].s.desc[j]); - pkt_nm->tx_desc_ring[i].s.desc[j] = NULL; - } - } - } - - pkt_nm->num_rx_desc_rings = 0; - pkt_nm->num_tx_desc_rings = 0; -} - -static int netmap_close(pktio_entry_t *pktio_entry) -{ - pkt_netmap_t *pkt_nm = &pktio_entry->s.pkt_nm; - - netmap_close_descriptors(pktio_entry); - - if (pkt_nm->sockfd != -1 && close(pkt_nm->sockfd) != 0) { - __odp_errno = errno; - ODP_ERR("close(sockfd): %s\n", strerror(errno)); - return -1; - } - return 0; -} - -static int netmap_link_status(pktio_entry_t *pktio_entry) -{ - if (pktio_entry->s.pkt_nm.is_virtual) - return 1; - - return link_status_fd(pktio_entry->s.pkt_nm.sockfd, - pktio_entry->s.pkt_nm.if_name); -} - -/** - * Wait for netmap link to come up - * - * @param pktio_entry Packet IO entry - * - * @retval 1 link is up - * @retval 0 link is down - * @retval <0 on failure - */ -static inline int netmap_wait_for_link(pktio_entry_t *pktio_entry) -{ - int i; - int ret; - - /* Wait for the link to come up */ - for (i = 0; i <= NM_WAIT_TIMEOUT; i++) { - ret = netmap_link_status(pktio_entry); - if (ret == -1) - return -1; - /* nm_open() causes the physical link to reset. When using a - * direct attached loopback cable there may be a small delay - * until the opposing end's interface comes back up again. In - * this case without the additional sleep pktio validation - * tests fail. */ - if (!pktio_entry->s.pkt_nm.is_virtual) - sleep(1); - if (ret == 1) - return 1; - } - ODP_DBG("%s link is down\n", pktio_entry->s.pkt_nm.if_name); - return 0; -} - -/** - * Initialize netmap capability values - * - * @param pktio_entry Packet IO entry - */ -static void netmap_init_capability(pktio_entry_t *pktio_entry) -{ - pkt_netmap_t *pkt_nm = &pktio_entry->s.pkt_nm; - odp_pktio_capability_t *capa = &pkt_nm->capa; - - memset(&pkt_nm->capa, 0, sizeof(odp_pktio_capability_t)); - - capa->max_input_queues = PKTIO_MAX_QUEUES; - if (pkt_nm->num_rx_rings < PKTIO_MAX_QUEUES) - capa->max_input_queues = pkt_nm->num_rx_rings; - if (capa->max_input_queues > NM_MAX_DESC) { - /* Have to use a single descriptor to fetch packets from all - * netmap rings */ - capa->max_input_queues = 1; - ODP_DBG("Unable to store all %" PRIu32 " rx rings (max %d)\n" - " max input queues: %u\n", pkt_nm->num_rx_rings, - NM_MAX_DESC, capa->max_input_queues); - } - - capa->max_output_queues = PKTIO_MAX_QUEUES; - if (pkt_nm->num_tx_rings < PKTIO_MAX_QUEUES) - capa->max_output_queues = pkt_nm->num_tx_rings; - if (capa->max_output_queues > NM_MAX_DESC) { - capa->max_output_queues = NM_MAX_DESC; - ODP_DBG("Unable to store all %" PRIu32 " tx rings (max %d)\n" - " max output queues: %u\n", pkt_nm->num_tx_rings, - NM_MAX_DESC, capa->max_output_queues); - } - - capa->set_op.op.promisc_mode = 1; - - odp_pktio_config_init(&capa->config); - capa->config.pktin.bit.ts_all = 1; - capa->config.pktin.bit.ts_ptp = 1; -} - -/** - * Open a netmap interface - * - * In addition to standard interfaces (with or without modified netmap drivers) - * virtual VALE and pipe interfaces are also supported. These can be used for - * example for testing packet IO functionality without any physical interfaces. - * - * To use virtual interfaces the 'netdev' device name has to begin with 'vale' - * prefix. A valid VALE device name would be e.g. 'vale0'. Pipe device names - * have to include also '{NN' (master) or '}NN' (slave) suffix. A valid pipe - * master would be e.g. 'vale0{0' and a slave to the same pipe 'vale0}0'. - * - * Netmap requires standard interface names to begin with 'netmap:' prefix. - * netmap_open() adds the prefix if it is missing. Virtual interfaces don't - * require the 'netmap:' prefix. - * - * @param id Packet IO handle - * @param pktio_entry Packet IO entry - * @param netdev Packet IO device name - * @param pool Default pool from which to allocate storage for packets - * - * @retval 0 on success - * @retval <0 on failure - */ -static int netmap_open(odp_pktio_t id ODP_UNUSED, pktio_entry_t *pktio_entry, - const char *netdev, odp_pool_t pool) -{ - int i; - int err; - int sockfd; - const char *prefix; - uint32_t mtu; - uint32_t buf_size; - pkt_netmap_t *pkt_nm = &pktio_entry->s.pkt_nm; - struct nm_desc *desc; - struct netmap_ring *ring; - odp_pktin_hash_proto_t hash_proto; - odp_pktio_stats_t cur_stats; - - if (disable_pktio) - return -1; - - if (pool == ODP_POOL_INVALID) - return -1; - - /* Init pktio entry */ - memset(pkt_nm, 0, sizeof(*pkt_nm)); - pkt_nm->sockfd = -1; - pkt_nm->pool = pool; - - /* max frame len taking into account the l2-offset */ - pkt_nm->max_frame_len = CONFIG_PACKET_MAX_SEG_LEN; - - /* allow interface to be opened with or without the 'netmap:' prefix */ - prefix = "netmap:"; - if (strncmp(netdev, "netmap:", 7) == 0) - netdev += 7; - if (strncmp(netdev, "vale", 4) == 0) { - pkt_nm->is_virtual = 1; - prefix = ""; - } - - snprintf(pkt_nm->nm_name, sizeof(pkt_nm->nm_name), "%s%s", prefix, - netdev); - snprintf(pkt_nm->if_name, sizeof(pkt_nm->if_name), "%s", netdev); - - /* Dummy open here to check if netmap module is available and to read - * capability info. */ - desc = nm_open(pkt_nm->nm_name, NULL, 0, NULL); - if (desc == NULL) { - ODP_ERR("nm_open(%s) failed\n", pkt_nm->nm_name); - goto error; - } - pkt_nm->num_rx_rings = desc->nifp->ni_rx_rings; - pkt_nm->num_tx_rings = desc->nifp->ni_tx_rings; - - netmap_init_capability(pktio_entry); - - ring = NETMAP_RXRING(desc->nifp, desc->cur_rx_ring); - buf_size = ring->nr_buf_size; - nm_close(desc); - - for (i = 0; i < PKTIO_MAX_QUEUES; i++) { - odp_ticketlock_init(&pkt_nm->rx_desc_ring[i].s.lock); - odp_ticketlock_init(&pkt_nm->tx_desc_ring[i].s.lock); - } - - if (pkt_nm->is_virtual) { - static unsigned mac; - - pkt_nm->capa.max_input_queues = 1; - pkt_nm->capa.set_op.op.promisc_mode = 0; - pkt_nm->mtu = buf_size; - pktio_entry->s.stats_type = STATS_UNSUPPORTED; - /* Set MAC address for virtual interface */ - pkt_nm->if_mac[0] = 0x2; - pkt_nm->if_mac[5] = ++mac; - - return 0; - } - - sockfd = socket(AF_INET, SOCK_DGRAM, 0); - if (sockfd == -1) { - ODP_ERR("Cannot get device control socket\n"); - goto error; - } - pkt_nm->sockfd = sockfd; - - /* Use either interface MTU (+ ethernet header length) or netmap buffer - * size as MTU, whichever is smaller. */ - mtu = mtu_get_fd(pktio_entry->s.pkt_nm.sockfd, pkt_nm->if_name); - if (mtu == 0) { - ODP_ERR("Unable to read interface MTU\n"); - goto error; - } - mtu += _ODP_ETHHDR_LEN; - pkt_nm->mtu = (mtu < buf_size) ? mtu : buf_size; - - /* Check if RSS is supported. If not, set 'max_input_queues' to 1. */ - if (rss_conf_get_supported_fd(sockfd, netdev, &hash_proto) == 0) { - ODP_DBG("RSS not supported\n"); - pkt_nm->capa.max_input_queues = 1; - } - - err = netmap_do_ioctl(pktio_entry, SIOCGIFFLAGS, 0); - if (err) - goto error; - if ((pkt_nm->if_flags & IFF_UP) == 0) - ODP_DBG("%s is down\n", pkt_nm->if_name); - - err = mac_addr_get_fd(sockfd, netdev, pkt_nm->if_mac); - if (err) - goto error; - - /* netmap uses only ethtool to get statistics counters */ - err = ethtool_stats_get_fd(pktio_entry->s.pkt_nm.sockfd, - pkt_nm->if_name, &cur_stats); - if (err) { - ODP_ERR("netmap pktio %s does not support statistics counters\n", - pkt_nm->if_name); - pktio_entry->s.stats_type = STATS_UNSUPPORTED; - } else { - pktio_entry->s.stats_type = STATS_ETHTOOL; - } - - (void)netmap_stats_reset(pktio_entry); - - return 0; - -error: - netmap_close(pktio_entry); - return -1; -} - -static int netmap_start(pktio_entry_t *pktio_entry) -{ - pkt_netmap_t *pkt_nm = &pktio_entry->s.pkt_nm; - netmap_ring_t *desc_ring; - struct nm_desc *desc_ptr; - unsigned i; - unsigned j; - unsigned num_rx_desc = 0; - uint64_t flags; - odp_pktin_mode_t in_mode = pktio_entry->s.param.in_mode; - odp_pktout_mode_t out_mode = pktio_entry->s.param.out_mode; - - /* If no pktin/pktout queues have been configured. Configure one - * for each direction. */ - if (!pktio_entry->s.num_in_queue && - in_mode != ODP_PKTIN_MODE_DISABLED) { - odp_pktin_queue_param_t param; - - odp_pktin_queue_param_init(¶m); - param.num_queues = 1; - if (odp_pktin_queue_config(pktio_entry->s.handle, ¶m)) - return -1; - } - if (!pktio_entry->s.num_out_queue && - out_mode == ODP_PKTOUT_MODE_DIRECT) { - odp_pktout_queue_param_t param; - - odp_pktout_queue_param_init(¶m); - param.num_queues = 1; - if (odp_pktout_queue_config(pktio_entry->s.handle, ¶m)) - return -1; - } - - if (pkt_nm->num_rx_desc_rings == pktio_entry->s.num_in_queue && - pkt_nm->num_tx_desc_rings == pktio_entry->s.num_out_queue) - return (netmap_wait_for_link(pktio_entry) == 1) ? 0 : -1; - - netmap_close_descriptors(pktio_entry); - - /* Map pktin/pktout queues to netmap rings */ - if (pktio_entry->s.num_in_queue) { - /* In single queue case only one netmap descriptor is - * required. */ - num_rx_desc = (pktio_entry->s.num_in_queue == 1) ? 1 : - pkt_nm->num_rx_rings; - - map_netmap_rings(pkt_nm->rx_desc_ring, - pktio_entry->s.num_in_queue, num_rx_desc); - } - if (pktio_entry->s.num_out_queue) - /* Enough to map only one netmap tx ring per pktout queue */ - map_netmap_rings(pkt_nm->tx_desc_ring, - pktio_entry->s.num_out_queue, - pktio_entry->s.num_out_queue); - - /* Use nm_open() to parse netmap flags from interface name */ - desc_ptr = nm_open(pkt_nm->nm_name, NULL, 0, NULL); - if (desc_ptr == NULL) { - ODP_ERR("nm_start(%s) failed\n", pkt_nm->nm_name); - goto error; - } - struct nm_desc base_desc = *desc_ptr; - - nm_close(desc_ptr); - - base_desc.self = &base_desc; - base_desc.mem = NULL; - base_desc.req.nr_ringid = 0; - if ((base_desc.req.nr_flags & NR_REG_MASK) == NR_REG_ALL_NIC || - (base_desc.req.nr_flags & NR_REG_MASK) == NR_REG_ONE_NIC) { - base_desc.req.nr_flags &= ~NR_REG_MASK; - if (num_rx_desc == 1) - base_desc.req.nr_flags |= NR_REG_ALL_NIC; - else - base_desc.req.nr_flags |= NR_REG_ONE_NIC; - } - - /* Only the first rx descriptor does mmap */ - desc_ring = pkt_nm->rx_desc_ring; - flags = NM_OPEN_IFNAME | NETMAP_NO_TX_POLL; - desc_ring[0].s.desc[0] = nm_open(pkt_nm->nm_name, NULL, flags, - &base_desc); - if (desc_ring[0].s.desc[0] == NULL) { - ODP_ERR("nm_start(%s) failed\n", pkt_nm->nm_name); - goto error; - } - /* Open rest of the rx descriptors (one per netmap ring) */ - flags = NM_OPEN_IFNAME | NETMAP_NO_TX_POLL | NM_OPEN_NO_MMAP; - for (i = 0; i < pktio_entry->s.num_in_queue; i++) { - for (j = desc_ring[i].s.first; j <= desc_ring[i].s.last; j++) { - if (i == 0 && j == 0) { /* First already opened */ - if (num_rx_desc > 1) - continue; - else - break; - } - base_desc.req.nr_ringid = j; - desc_ring[i].s.desc[j] = nm_open(pkt_nm->nm_name, NULL, - flags, &base_desc); - if (desc_ring[i].s.desc[j] == NULL) { - ODP_ERR("nm_start(%s) failed\n", - pkt_nm->nm_name); - goto error; - } - } - } - /* Open tx descriptors */ - desc_ring = pkt_nm->tx_desc_ring; - flags = NM_OPEN_IFNAME | NM_OPEN_NO_MMAP; - - if ((base_desc.req.nr_flags & NR_REG_MASK) == NR_REG_ALL_NIC) { - base_desc.req.nr_flags &= ~NR_REG_ALL_NIC; - base_desc.req.nr_flags |= NR_REG_ONE_NIC; - } - - for (i = 0; i < pktio_entry->s.num_out_queue; i++) { - for (j = desc_ring[i].s.first; j <= desc_ring[i].s.last; j++) { - base_desc.req.nr_ringid = j; - desc_ring[i].s.desc[j] = nm_open(pkt_nm->nm_name, NULL, - flags, &base_desc); - if (desc_ring[i].s.desc[j] == NULL) { - ODP_ERR("nm_start(%s) failed\n", - pkt_nm->nm_name); - goto error; - } - } - } - pkt_nm->num_rx_desc_rings = pktio_entry->s.num_in_queue; - pkt_nm->num_tx_desc_rings = pktio_entry->s.num_out_queue; - /* Wait for the link to come up */ - return (netmap_wait_for_link(pktio_entry) == 1) ? 0 : -1; - -error: - netmap_close_descriptors(pktio_entry); - return -1; -} - -static int netmap_stop(pktio_entry_t *pktio_entry ODP_UNUSED) -{ - return 0; -} - -/** - * Create ODP packets from netmap packets - * - * @param pktio_entry Packet IO entry - * @param pkt_tbl Array for new ODP packet handles - * @param slot_tbl Array of netmap ring slots - * @param slot_num Number of netmap ring slots - * @param ts Pointer to pktin timestamp - * - * @retval Number of created packets - */ -static inline int netmap_pkt_to_odp(pktio_entry_t *pktio_entry, - odp_packet_t pkt_tbl[], - netmap_slot_t slot_tbl[], int16_t slot_num, - odp_time_t *ts) -{ - odp_packet_t pkt; - odp_pool_t pool = pktio_entry->s.pkt_nm.pool; - odp_packet_hdr_t *pkt_hdr; - odp_packet_hdr_t parsed_hdr; - int i; - int num; - int alloc_len; - - /* Allocate maximum sized packets */ - alloc_len = pktio_entry->s.pkt_nm.mtu; - - num = packet_alloc_multi(pool, alloc_len, pkt_tbl, slot_num); - - for (i = 0; i < num; i++) { - netmap_slot_t slot; - uint16_t len; - - slot = slot_tbl[i]; - len = slot.len; - - odp_prefetch(slot.buf); - - if (odp_unlikely(len > pktio_entry->s.pkt_nm.max_frame_len)) { - ODP_ERR("RX: frame too big %" PRIu16 " %zu!\n", len, - pktio_entry->s.pkt_nm.max_frame_len); - goto fail; - } - - if (odp_unlikely(len < _ODP_ETH_LEN_MIN)) { - ODP_ERR("RX: Frame truncated: %" PRIu16 "\n", len); - goto fail; - } - - if (pktio_cls_enabled(pktio_entry)) { - if (cls_classify_packet(pktio_entry, - (const uint8_t *)slot.buf, len, - len, &pool, &parsed_hdr)) - goto fail; - } - - pkt = pkt_tbl[i]; - pkt_hdr = odp_packet_hdr(pkt); - pull_tail(pkt_hdr, alloc_len - len); - - /* For now copy the data in the mbuf, - worry about zero-copy later */ - if (odp_packet_copy_from_mem(pkt, 0, len, slot.buf) != 0) - goto fail; - - pkt_hdr->input = pktio_entry->s.handle; - - if (pktio_cls_enabled(pktio_entry)) - copy_packet_cls_metadata(&parsed_hdr, pkt_hdr); - else - packet_parse_layer(pkt_hdr, - pktio_entry->s.config.parser.layer); - - packet_set_ts(pkt_hdr, ts); - } - - return i; - -fail: - odp_packet_free_multi(&pkt_tbl[i], num - i); - return i; -} - -static inline int netmap_recv_desc(pktio_entry_t *pktio_entry, - struct nm_desc *desc, - odp_packet_t pkt_table[], int num) -{ - struct netmap_ring *ring; - odp_time_t ts_val; - odp_time_t *ts = NULL; - netmap_slot_t slot_tbl[num]; - char *buf; - uint32_t slot_id; - int i; - int ring_id = desc->cur_rx_ring; - int num_rx = 0; - int num_rings = desc->last_rx_ring - desc->first_rx_ring + 1; - - if (pktio_entry->s.config.pktin.bit.ts_all || - pktio_entry->s.config.pktin.bit.ts_ptp) - ts = &ts_val; - - for (i = 0; i < num_rings && num_rx != num; i++) { - if (ring_id > desc->last_rx_ring) - ring_id = desc->first_rx_ring; - - ring = NETMAP_RXRING(desc->nifp, ring_id); - - while (!nm_ring_empty(ring) && num_rx != num) { - slot_id = ring->cur; - buf = NETMAP_BUF(ring, ring->slot[slot_id].buf_idx); - - slot_tbl[num_rx].buf = buf; - slot_tbl[num_rx].len = ring->slot[slot_id].len; - num_rx++; - - ring->cur = nm_ring_next(ring, slot_id); - } - ring->head = ring->cur; - ring_id++; - } - desc->cur_rx_ring = ring_id; - - if (num_rx) { - if (ts != NULL) - ts_val = odp_time_global(); - return netmap_pkt_to_odp(pktio_entry, pkt_table, slot_tbl, - num_rx, ts); - } - return 0; -} - -static int netmap_recv(pktio_entry_t *pktio_entry, int index, - odp_packet_t pkt_table[], int num) -{ - struct nm_desc *desc; - pkt_netmap_t *pkt_nm = &pktio_entry->s.pkt_nm; - unsigned first_desc_id = pkt_nm->rx_desc_ring[index].s.first; - unsigned last_desc_id = pkt_nm->rx_desc_ring[index].s.last; - unsigned desc_id; - int num_desc = pkt_nm->rx_desc_ring[index].s.num; - int i; - int num_rx = 0; - int max_fd = 0; - fd_set empty_rings; - - if (odp_unlikely(pktio_entry->s.state != PKTIO_STATE_STARTED)) - return 0; - - FD_ZERO(&empty_rings); - - if (!pkt_nm->lockless_rx) - odp_ticketlock_lock(&pkt_nm->rx_desc_ring[index].s.lock); - - desc_id = pkt_nm->rx_desc_ring[index].s.cur; - - for (i = 0; i < num_desc && num_rx != num; i++) { - if (desc_id > last_desc_id) - desc_id = first_desc_id; - - desc = pkt_nm->rx_desc_ring[index].s.desc[desc_id]; - - num_rx += netmap_recv_desc(pktio_entry, desc, - &pkt_table[num_rx], num - num_rx); - - if (num_rx != num) { - FD_SET(desc->fd, &empty_rings); - if (desc->fd > max_fd) - max_fd = desc->fd; - } - desc_id++; - } - pkt_nm->rx_desc_ring[index].s.cur = desc_id; - - if (num_rx != num) { - struct timeval tout = {.tv_sec = 0, .tv_usec = 0}; - - if (select(max_fd + 1, &empty_rings, NULL, NULL, &tout) == -1) - ODP_ERR("RX: select error\n"); - } - if (!pkt_nm->lockless_rx) - odp_ticketlock_unlock(&pkt_nm->rx_desc_ring[index].s.lock); - - return num_rx; -} - -static int netmap_send(pktio_entry_t *pktio_entry, int index, - const odp_packet_t pkt_table[], int num) -{ - pkt_netmap_t *pkt_nm = &pktio_entry->s.pkt_nm; - struct pollfd polld; - struct nm_desc *desc; - struct netmap_ring *ring; - int i; - int nb_tx; - int desc_id; - odp_packet_t pkt; - uint32_t pkt_len; - unsigned slot_id; - char *buf; - - if (odp_unlikely(pktio_entry->s.state != PKTIO_STATE_STARTED)) - return 0; - - /* Only one netmap tx ring per pktout queue */ - desc_id = pkt_nm->tx_desc_ring[index].s.cur; - desc = pkt_nm->tx_desc_ring[index].s.desc[desc_id]; - ring = NETMAP_TXRING(desc->nifp, desc->cur_tx_ring); - - if (!pkt_nm->lockless_tx) - odp_ticketlock_lock(&pkt_nm->tx_desc_ring[index].s.lock); - - polld.fd = desc->fd; - polld.events = POLLOUT; - - for (nb_tx = 0; nb_tx < num; nb_tx++) { - pkt = pkt_table[nb_tx]; - pkt_len = _odp_packet_len(pkt); - - if (pkt_len > pkt_nm->mtu) { - if (nb_tx == 0) - __odp_errno = EMSGSIZE; - break; - } - for (i = 0; i < NM_INJECT_RETRIES; i++) { - if (nm_ring_empty(ring)) { - poll(&polld, 1, 0); - continue; - } - slot_id = ring->cur; - ring->slot[slot_id].flags = 0; - ring->slot[slot_id].len = pkt_len; - - buf = NETMAP_BUF(ring, ring->slot[slot_id].buf_idx); - - if (odp_packet_copy_to_mem(pkt, 0, pkt_len, buf)) { - i = NM_INJECT_RETRIES; - break; - } - ring->cur = nm_ring_next(ring, slot_id); - ring->head = ring->cur; - break; - } - if (i == NM_INJECT_RETRIES) - break; - } - /* Send pending packets */ - poll(&polld, 1, 0); - - if (!pkt_nm->lockless_tx) - odp_ticketlock_unlock(&pkt_nm->tx_desc_ring[index].s.lock); - - if (odp_unlikely(nb_tx == 0)) { - if (__odp_errno != 0) - return -1; - } else { - odp_packet_free_multi(pkt_table, nb_tx); - } - - return nb_tx; -} - -static int netmap_mac_addr_get(pktio_entry_t *pktio_entry, void *mac_addr) -{ - memcpy(mac_addr, pktio_entry->s.pkt_nm.if_mac, ETH_ALEN); - return ETH_ALEN; -} - -static uint32_t netmap_mtu_get(pktio_entry_t *pktio_entry) -{ - return pktio_entry->s.pkt_nm.mtu; -} - -static int netmap_promisc_mode_set(pktio_entry_t *pktio_entry, - odp_bool_t enable) -{ - if (pktio_entry->s.pkt_nm.is_virtual) { - __odp_errno = ENOTSUP; - return -1; - } - - return promisc_mode_set_fd(pktio_entry->s.pkt_nm.sockfd, - pktio_entry->s.pkt_nm.if_name, enable); -} - -static int netmap_promisc_mode_get(pktio_entry_t *pktio_entry) -{ - if (pktio_entry->s.pkt_nm.is_virtual) - return 0; - - return promisc_mode_get_fd(pktio_entry->s.pkt_nm.sockfd, - pktio_entry->s.pkt_nm.if_name); -} - -static int netmap_capability(pktio_entry_t *pktio_entry, - odp_pktio_capability_t *capa) -{ - *capa = pktio_entry->s.pkt_nm.capa; - return 0; -} - -static int netmap_stats(pktio_entry_t *pktio_entry, - odp_pktio_stats_t *stats) -{ - if (pktio_entry->s.stats_type == STATS_UNSUPPORTED) { - memset(stats, 0, sizeof(*stats)); - return 0; - } - - return sock_stats_fd(pktio_entry, - stats, - pktio_entry->s.pkt_nm.sockfd); -} - -static int netmap_stats_reset(pktio_entry_t *pktio_entry) -{ - if (pktio_entry->s.stats_type == STATS_UNSUPPORTED) { - memset(&pktio_entry->s.stats, 0, - sizeof(odp_pktio_stats_t)); - return 0; - } - - return sock_stats_reset_fd(pktio_entry, - pktio_entry->s.pkt_nm.sockfd); -} - -static void netmap_print(pktio_entry_t *pktio_entry) -{ - odp_pktin_hash_proto_t hash_proto; - - if (rss_conf_get_fd(pktio_entry->s.pkt_nm.sockfd, - pktio_entry->s.pkt_nm.if_name, &hash_proto)) - rss_conf_print(&hash_proto); -} - -static int netmap_init_global(void) -{ - if (getenv("ODP_PKTIO_DISABLE_NETMAP")) { - ODP_PRINT("PKTIO: netmap pktio skipped," - " enabled export ODP_PKTIO_DISABLE_NETMAP=1.\n"); - disable_pktio = 1; - } else { - ODP_PRINT("PKTIO: initialized netmap pktio," - " use export ODP_PKTIO_DISABLE_NETMAP=1 to disable.\n" - " Netmap prefixes are netmap:eth0 or vale:eth0. Refer to" - " Netmap documentation for usage information.\n"); - } - return 0; -} - -const pktio_if_ops_t netmap_pktio_ops = { - .name = "netmap", - .print = netmap_print, - .init_global = netmap_init_global, - .init_local = NULL, - .term = NULL, - .open = netmap_open, - .close = netmap_close, - .start = netmap_start, - .stop = netmap_stop, - .link_status = netmap_link_status, - .stats = netmap_stats, - .stats_reset = netmap_stats_reset, - .mtu_get = netmap_mtu_get, - .promisc_mode_set = netmap_promisc_mode_set, - .promisc_mode_get = netmap_promisc_mode_get, - .mac_get = netmap_mac_addr_get, - .capability = netmap_capability, - .pktin_ts_res = NULL, - .pktin_ts_from_ns = NULL, - .config = NULL, - .input_queues_config = netmap_input_queues_config, - .output_queues_config = netmap_output_queues_config, - .recv = netmap_recv, - .send = netmap_send -}; - -#endif /* ODP_NETMAP */ |