diff options
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | example/generator/odp_generator.c | 3 | ||||
-rw-r--r-- | example/ipsec/odp_ipsec.c | 3 | ||||
-rw-r--r-- | example/packet/odp_pktio.c | 3 | ||||
-rw-r--r-- | platform/linux-generic/Makefile.am | 2 | ||||
-rw-r--r-- | platform/linux-generic/include/odp_packet_io_internal.h | 3 | ||||
-rw-r--r-- | platform/linux-generic/include/odp_packet_netmap.h | 24 | ||||
-rw-r--r-- | platform/linux-generic/m4/configure.m4 | 1 | ||||
-rw-r--r-- | platform/linux-generic/m4/odp_netmap.m4 | 50 | ||||
-rw-r--r-- | platform/linux-generic/pktio/io_ops.c | 3 | ||||
-rw-r--r-- | platform/linux-generic/pktio/netmap.c | 303 | ||||
-rw-r--r-- | platform/linux-generic/pktio/socket.c | 4 | ||||
-rw-r--r-- | test/performance/odp_l2fwd.c | 3 |
13 files changed, 400 insertions, 4 deletions
diff --git a/configure.ac b/configure.ac index 15dc6cf..92f9d39 100644 --- a/configure.ac +++ b/configure.ac @@ -270,6 +270,8 @@ ODP_CFLAGS="$ODP_CFLAGS -Wmissing-declarations -Wold-style-definition -Wpointer- ODP_CFLAGS="$ODP_CFLAGS -Wcast-align -Wnested-externs -Wcast-qual -Wformat-nonliteral" ODP_CFLAGS="$ODP_CFLAGS -Wformat-security -Wundef -Wwrite-strings" ODP_CFLAGS="$ODP_CFLAGS -std=c99" +# Extra flags for example to suppress certain warning types +ODP_CFLAGS="$ODP_CFLAGS $ODP_CFLAGS_EXTRA" ########################################################################## # Default include setup diff --git a/example/generator/odp_generator.c b/example/generator/odp_generator.c index f4f6038..085902b 100644 --- a/example/generator/odp_generator.c +++ b/example/generator/odp_generator.c @@ -1114,7 +1114,8 @@ static void usage(char *progname) "\n" "Optional OPTIONS\n" " -h, --help Display help and exit.\n" - " environment variables: ODP_PKTIO_DISABLE_SOCKET_MMAP\n" + " environment variables: ODP_PKTIO_DISABLE_NETMAP\n" + " ODP_PKTIO_DISABLE_SOCKET_MMAP\n" " ODP_PKTIO_DISABLE_SOCKET_MMSG\n" " can be used to advanced pkt I/O selection for linux-generic\n" " -p, --packetsize payload length of the packets\n" diff --git a/example/ipsec/odp_ipsec.c b/example/ipsec/odp_ipsec.c index 564d65e..6f5aae8 100644 --- a/example/ipsec/odp_ipsec.c +++ b/example/ipsec/odp_ipsec.c @@ -1577,7 +1577,8 @@ static void usage(char *progname) "Optional OPTIONS\n" " -c, --count <number> CPU count.\n" " -h, --help Display help and exit.\n" - " environment variables: ODP_PKTIO_DISABLE_SOCKET_MMAP\n" + " environment variables: ODP_PKTIO_DISABLE_NETMAP\n" + " ODP_PKTIO_DISABLE_SOCKET_MMAP\n" " ODP_PKTIO_DISABLE_SOCKET_MMSG\n" " can be used to advanced pkt I/O selection for linux-generic\n" " ODP_IPSEC_USE_POLL_QUEUES\n" diff --git a/example/packet/odp_pktio.c b/example/packet/odp_pktio.c index 16d4533..de6e42b 100644 --- a/example/packet/odp_pktio.c +++ b/example/packet/odp_pktio.c @@ -700,7 +700,8 @@ static void usage(char *progname) " 1: Receive and send via queues.\n" " 2: Receive via scheduler, send via queues.\n" " -h, --help Display help and exit.\n" - " environment variables: ODP_PKTIO_DISABLE_SOCKET_MMAP\n" + " environment variables: ODP_PKTIO_DISABLE_NETMAP\n" + " ODP_PKTIO_DISABLE_SOCKET_MMAP\n" " ODP_PKTIO_DISABLE_SOCKET_MMSG\n" " can be used to advanced pkt I/O selection for linux-generic\n" "\n", NO_PATH(progname), NO_PATH(progname) diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am index 4c79730..2a71d32 100644 --- a/platform/linux-generic/Makefile.am +++ b/platform/linux-generic/Makefile.am @@ -127,6 +127,7 @@ noinst_HEADERS = \ ${srcdir}/include/odp_packet_internal.h \ ${srcdir}/include/odp_packet_io_internal.h \ ${srcdir}/include/odp_packet_io_queue.h \ + ${srcdir}/include/odp_packet_netmap.h \ ${srcdir}/include/odp_packet_socket.h \ ${srcdir}/include/odp_pool_internal.h \ ${srcdir}/include/odp_queue_internal.h \ @@ -151,6 +152,7 @@ __LIB__libodp_la_SOURCES = \ odp_packet_io.c \ pktio/io_ops.c \ pktio/loop.c \ + pktio/netmap.c \ pktio/socket.c \ pktio/socket_mmap.c \ odp_pool.c \ diff --git a/platform/linux-generic/include/odp_packet_io_internal.h b/platform/linux-generic/include/odp_packet_io_internal.h index 60aca1c..353b40d 100644 --- a/platform/linux-generic/include/odp_packet_io_internal.h +++ b/platform/linux-generic/include/odp_packet_io_internal.h @@ -21,6 +21,7 @@ extern "C" { #include <odp/spinlock.h> #include <odp/ticketlock.h> #include <odp_packet_socket.h> +#include <odp_packet_netmap.h> #include <odp_classification_datamodel.h> #include <odp_align_internal.h> #include <odp_debug_internal.h> @@ -50,6 +51,7 @@ struct pktio_entry { pkt_sock_t pkt_sock; /**< using socket API for IO */ pkt_sock_mmap_t pkt_sock_mmap; /**< using socket mmap * API for IO */ + pkt_netmap_t pkt_nm; /**< using netmap API for IO */ }; enum { STATE_START = 0, @@ -122,6 +124,7 @@ static inline void pktio_cls_enabled_set(pktio_entry_t *entry, int ena) int pktin_poll(pktio_entry_t *entry); +extern const pktio_if_ops_t netmap_pktio_ops; extern const pktio_if_ops_t sock_mmsg_pktio_ops; extern const pktio_if_ops_t sock_mmap_pktio_ops; extern const pktio_if_ops_t loopback_pktio_ops; diff --git a/platform/linux-generic/include/odp_packet_netmap.h b/platform/linux-generic/include/odp_packet_netmap.h new file mode 100644 index 0000000..23aea5b --- /dev/null +++ b/platform/linux-generic/include/odp_packet_netmap.h @@ -0,0 +1,24 @@ +/* Copyright (c) 2015, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef ODP_PACKET_NETMAP_H +#define ODP_PACKET_NETMAP_H + +#include <odp/pool.h> + +#include <linux/if_ether.h> + +/** Packet socket using netmap mmaped rings for both Rx and Tx */ +typedef struct { + odp_pool_t pool; /**< pool to alloc packets from */ + size_t max_frame_len; /**< buf_size - sizeof(pkt_hdr) */ + struct nm_desc *desc; /**< netmap meta-data for the device */ + uint32_t if_flags; /**< interface flags */ + int sockfd; /**< control socket */ + unsigned char if_mac[ETH_ALEN]; /**< eth mac address */ +} pkt_netmap_t; + +#endif diff --git a/platform/linux-generic/m4/configure.m4 b/platform/linux-generic/m4/configure.m4 index 9658274..f2d42f1 100644 --- a/platform/linux-generic/m4/configure.m4 +++ b/platform/linux-generic/m4/configure.m4 @@ -18,6 +18,7 @@ AC_LINK_IFELSE( m4_include([platform/linux-generic/m4/odp_pthread.m4]) m4_include([platform/linux-generic/m4/odp_openssl.m4]) +m4_include([platform/linux-generic/m4/odp_netmap.m4]) AC_CONFIG_FILES([platform/linux-generic/Makefile platform/linux-generic/test/Makefile diff --git a/platform/linux-generic/m4/odp_netmap.m4 b/platform/linux-generic/m4/odp_netmap.m4 new file mode 100644 index 0000000..02cd3d3 --- /dev/null +++ b/platform/linux-generic/m4/odp_netmap.m4 @@ -0,0 +1,50 @@ +########################################################################## +# Enable netmap support +########################################################################## +netmap_support=no +AC_ARG_ENABLE([netmap_support], + [ --enable-netmap-support include netmap IO support], + [if test x$enableval = xyes; then + netmap_support=yes + fi]) + +########################################################################## +# Set optional netmap path +########################################################################## +AC_ARG_WITH([netmap-path], +AC_HELP_STRING([--with-netmap-path=DIR path to netmap root directory], + [(or in the default path if not specified).]), + [NETMAP_PATH=$withval + AM_CPPFLAGS="$AM_CPPFLAGS -I$NETMAP_PATH/sys" + netmap_support=yes],[]) + +########################################################################## +# Save and set temporary compilation flags +########################################################################## +OLD_CPPFLAGS=$CPPFLAGS +CPPFLAGS="$AM_CPPFLAGS $CPPFLAGS" + +########################################################################## +# Check for netmap availability +########################################################################## +if test x$netmap_support = xyes +then + AC_CHECK_HEADERS([net/netmap_user.h], [], + [AC_MSG_FAILURE(["can't find netmap header"])]) + ODP_CFLAGS="$ODP_CFLAGS -DODP_NETMAP" +else + netmap_support=no +fi + +AM_CONDITIONAL([netmap_support], [test x$netmap_support = xyes ]) + +# Disable cast errors until the problem in netmap_user.h is fixed upstream +if test x$netmap_support = xyes +then +ODP_CFLAGS_EXTRA="$ODP_CFLAGS_EXTRA -Wno-cast-qual" +fi + +########################################################################## +# Restore old saved variables +########################################################################## +CPPFLAGS=$OLD_CPPFLAGS
\ No newline at end of file diff --git a/platform/linux-generic/pktio/io_ops.c b/platform/linux-generic/pktio/io_ops.c index 1d47e74..bd4cc48 100644 --- a/platform/linux-generic/pktio/io_ops.c +++ b/platform/linux-generic/pktio/io_ops.c @@ -12,6 +12,9 @@ * Array must be NULL terminated */ const pktio_if_ops_t * const pktio_if_ops[] = { &loopback_pktio_ops, +#ifdef ODP_NETMAP + &netmap_pktio_ops, +#endif &sock_mmap_pktio_ops, &sock_mmsg_pktio_ops, NULL diff --git a/platform/linux-generic/pktio/netmap.c b/platform/linux-generic/pktio/netmap.c new file mode 100644 index 0000000..54e7043 --- /dev/null +++ b/platform/linux-generic/pktio/netmap.c @@ -0,0 +1,303 @@ +/* Copyright (c) 2015, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifdef ODP_NETMAP + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include <odp_packet_netmap.h> +#include <odp_packet_socket.h> +#include <odp_packet_io_internal.h> +#include <odp_debug_internal.h> +#include <odp/helper/eth.h> + +#include <sys/ioctl.h> +#include <poll.h> +#include <linux/ethtool.h> +#include <linux/sockios.h> + +#define NETMAP_WITH_LIBS +#include <net/netmap_user.h> + +static struct nm_desc mmap_desc; /** Used to store the mmap address; + filled in first time, used for + subsequent calls to nm_open */ + +#define NM_INJECT_RETRIES 10 + +struct dispatch_args { + odp_packet_t *pkt_table; + unsigned nb_rx; + 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.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; + default: + break; + } +done: + if (err) + ODP_ERR("ioctl err %d %lu: %s\n", err, cmd, strerror(errno)); + + return err; +} + +static int netmap_close(pktio_entry_t *pktio_entry) +{ + pkt_netmap_t *pkt_nm = &pktio_entry->s.pkt_nm; + + if (pkt_nm->desc != NULL) + nm_close(pkt_nm->desc); + + 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_open(odp_pktio_t id ODP_UNUSED, pktio_entry_t *pktio_entry, + const char *netdev, odp_pool_t pool) +{ + char ifname[IFNAMSIZ + 7]; /* netmap:<ifname> */ + int err; + int sockfd; + pkt_netmap_t *pkt_nm = &pktio_entry->s.pkt_nm; + + if (getenv("ODP_PKTIO_DISABLE_NETMAP")) + 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 = ODP_CONFIG_PACKET_BUF_LEN_MAX - + odp_buffer_pool_headroom(pool) - + odp_buffer_pool_tailroom(pool); + + snprintf(pktio_entry->s.name, sizeof(pktio_entry->s.name), "%s", + netdev); + snprintf(ifname, sizeof(ifname), "netmap:%s", netdev); + + if (mmap_desc.mem == NULL) + pkt_nm->desc = nm_open(ifname, NULL, NETMAP_NO_TX_POLL, NULL); + else + pkt_nm->desc = nm_open(ifname, NULL, NETMAP_NO_TX_POLL | + NM_OPEN_NO_MMAP, &mmap_desc); + if (pkt_nm->desc == NULL) { + ODP_ERR("nm_open(%s) failed\n", ifname); + goto error; + } + + if (mmap_desc.mem == NULL) { + mmap_desc.mem = pkt_nm->desc->mem; + mmap_desc.memsize = pkt_nm->desc->memsize; + } + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd == -1) { + ODP_ERR("Cannot get device control socket\n"); + goto error; + } + pkt_nm->sockfd = sockfd; + + 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", pktio_entry->s.name); + + err = netmap_do_ioctl(pktio_entry, SIOCETHTOOL, ETHTOOL_SGSO); + if (err) + ODP_DBG("ETHTOOL_SGSO not supported\n"); + + err = netmap_do_ioctl(pktio_entry, SIOCETHTOOL, ETHTOOL_STSO); + if (err) + ODP_DBG("ETHTOOL_STSO not supported\n"); + + err = mac_addr_get_fd(sockfd, netdev, pkt_nm->if_mac); + if (err) + goto error; + + err = netmap_do_ioctl(pktio_entry, SIOCETHTOOL, ETHTOOL_STXCSUM); + if (err) + ODP_DBG("ETHTOOL_STXCSUM not supported\n"); + + return 0; + +error: + netmap_close(pktio_entry); + return -1; +} + +static void netmap_recv_cb(u_char *arg, const struct nm_pkthdr *hdr, + const u_char *buf) +{ + struct dispatch_args *args = (struct dispatch_args *)arg; + pkt_netmap_t *pkt_nm = &args->pktio_entry->s.pkt_nm; + odp_packet_t pkt; + size_t frame_len = (size_t)hdr->len; + + if (odp_unlikely(frame_len > pkt_nm->max_frame_len)) { + ODP_ERR("RX: frame too big %u %lu!\n", (unsigned)frame_len, + pkt_nm->max_frame_len); + return; + } + + if (odp_unlikely(frame_len < ODPH_ETH_LEN_MIN)) { + ODP_ERR("RX: Frame truncated: %u\n", (unsigned)frame_len); + return; + } + + pkt = odp_packet_alloc(pkt_nm->pool, frame_len); + if (pkt == ODP_PACKET_INVALID) + return; + + /* For now copy the data in the mbuf, + worry about zero-copy later */ + if (odp_packet_copydata_in(pkt, 0, frame_len, buf) != 0) { + odp_packet_free(pkt); + return; + } + + _odp_packet_reset_parse(pkt); + + args->pkt_table[args->nb_rx++] = pkt; +} + +static int netmap_recv(pktio_entry_t *pktio_entry, odp_packet_t pkt_table[], + unsigned num) +{ + struct dispatch_args args; + struct nm_desc *nm_desc = pktio_entry->s.pkt_nm.desc; + struct pollfd polld; + + polld.fd = nm_desc->fd; + polld.events = POLLIN; + + args.pkt_table = pkt_table; + args.nb_rx = 0; + args.pktio_entry = pktio_entry; + + nm_dispatch(nm_desc, num, netmap_recv_cb, (u_char *)&args); + if (args.nb_rx == 0) { + if (odp_unlikely(poll(&polld, 1, 0) < 0)) + ODP_ERR("RX: poll error\n"); + } + return args.nb_rx; +} + +static int netmap_send(pktio_entry_t *pktio_entry, odp_packet_t pkt_table[], + unsigned num) +{ + struct nm_desc *nm_desc = pktio_entry->s.pkt_nm.desc; + struct pollfd polld; + unsigned i, nb_tx; + uint8_t *frame; + uint32_t frame_len; + + polld.fd = nm_desc->fd; + polld.events = POLLOUT; + + for (nb_tx = 0; nb_tx < num; nb_tx++) { + frame_len = 0; + frame = odp_packet_l2_ptr(pkt_table[nb_tx], &frame_len); + for (i = 0; i < NM_INJECT_RETRIES; i++) { + if (nm_inject(nm_desc, frame, frame_len) == 0) + poll(&polld, 1, 0); + else + break; + } + if (odp_unlikely(i == NM_INJECT_RETRIES)) + break; + } + for (i = 0; i < nb_tx; i++) + odp_packet_free(pkt_table[i]); + + 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 int netmap_mtu_get(pktio_entry_t *pktio_entry) +{ + return mtu_get_fd(pktio_entry->s.pkt_nm.sockfd, pktio_entry->s.name); +} + +static int netmap_promisc_mode_set(pktio_entry_t *pktio_entry, + odp_bool_t enable) +{ + return promisc_mode_set_fd(pktio_entry->s.pkt_nm.sockfd, + pktio_entry->s.name, enable); +} + +static int netmap_promisc_mode_get(pktio_entry_t *pktio_entry) +{ + return promisc_mode_get_fd(pktio_entry->s.pkt_nm.sockfd, + pktio_entry->s.name); +} + +const pktio_if_ops_t netmap_pktio_ops = { + .init = NULL, + .term = NULL, + .open = netmap_open, + .close = netmap_close, + .start = NULL, + .stop = NULL, + .recv = netmap_recv, + .send = netmap_send, + .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 +}; + +#endif /* ODP_NETMAP */ diff --git a/platform/linux-generic/pktio/socket.c b/platform/linux-generic/pktio/socket.c index 1ced69a..a95b9a8 100644 --- a/platform/linux-generic/pktio/socket.c +++ b/platform/linux-generic/pktio/socket.c @@ -91,6 +91,7 @@ int sendmmsg(int fd, struct mmsghdr *vmessages, unsigned int vlen, int flags) /** * ODP_PACKET_SOCKET_MMSG: * ODP_PACKET_SOCKET_MMAP: + * ODP_PACKET_NETMAP: */ int mac_addr_get_fd(int fd, const char *name, unsigned char mac_dst[]) { @@ -115,6 +116,7 @@ int mac_addr_get_fd(int fd, const char *name, unsigned char mac_dst[]) /* * ODP_PACKET_SOCKET_MMSG: * ODP_PACKET_SOCKET_MMAP: + * ODP_PACKET_NETMAP: */ int mtu_get_fd(int fd, const char *name) { @@ -133,6 +135,7 @@ int mtu_get_fd(int fd, const char *name) /* * ODP_PACKET_SOCKET_MMSG: * ODP_PACKET_SOCKET_MMAP: + * ODP_PACKET_NETMAP: */ int promisc_mode_set_fd(int fd, const char *name, int enable) { @@ -162,6 +165,7 @@ int promisc_mode_set_fd(int fd, const char *name, int enable) /* * ODP_PACKET_SOCKET_MMSG: * ODP_PACKET_SOCKET_MMAP: + * ODP_PACKET_NETMAP: */ int promisc_mode_get_fd(int fd, const char *name) { diff --git a/test/performance/odp_l2fwd.c b/test/performance/odp_l2fwd.c index cb31544..812d47f 100644 --- a/test/performance/odp_l2fwd.c +++ b/test/performance/odp_l2fwd.c @@ -758,7 +758,8 @@ static void usage(char *progname) " -a, --accuracy <number> Time in seconds get print statistics\n" " (default is 1 second).\n" " -h, --help Display help and exit.\n\n" - " environment variables: ODP_PKTIO_DISABLE_SOCKET_MMAP\n" + " environment variables: ODP_PKTIO_DISABLE_NETMAP\n" + " ODP_PKTIO_DISABLE_SOCKET_MMAP\n" " ODP_PKTIO_DISABLE_SOCKET_MMSG\n" " can be used to advanced pkt I/O selection for linux-generic\n" "\n", NO_PATH(progname), NO_PATH(progname) |