On 08.12.2015 14:24, Stuart Haslam wrote: > On Mon, Dec 07, 2015 at 01:55:31PM +0300, Ilya Maximets wrote: >> Creates a new pktio type that allows for creating and >> sending/receiving packets through TAP interface. >> It is intended for use as a simple conventional communication >> method between applications that use kernel network stack >> (ping, ssh, iperf, etc.) and ODP applications for the purpose >> of functional testing and can be used as it is with some >> of the existing example applications. >> >> To use this interface the name passed to odp_pktio_open() must >> begin with "tap:" and be in the format: >> >> tap:iface >> >> iface the name of TAP device to be created. >> >> TUN/TAP kernel module should be loaded to use this pktio. >> There should be no device named 'iface' in the system. >> The total length of the 'iface' is limited by IF_NAMESIZE. >> >> Signed-off-by: Ilya Maximets <i.maxim...@samsung.com> >> --- >> platform/linux-generic/Makefile.am | 2 + >> .../linux-generic/include/odp_packet_io_internal.h | 3 + >> platform/linux-generic/include/odp_packet_tap.h | 21 ++ >> platform/linux-generic/pktio/io_ops.c | 1 + >> platform/linux-generic/pktio/tap.c | 317 >> +++++++++++++++++++++ >> 5 files changed, 344 insertions(+) >> create mode 100644 platform/linux-generic/include/odp_packet_tap.h >> create mode 100644 platform/linux-generic/pktio/tap.c >> >> diff --git a/platform/linux-generic/Makefile.am >> b/platform/linux-generic/Makefile.am >> index 70bd8fe..4639ebc 100644 >> --- a/platform/linux-generic/Makefile.am >> +++ b/platform/linux-generic/Makefile.am >> @@ -92,6 +92,7 @@ noinst_HEADERS = \ >> ${srcdir}/include/odp_packet_io_queue.h \ >> ${srcdir}/include/odp_packet_netmap.h \ >> ${srcdir}/include/odp_packet_socket.h \ >> + ${srcdir}/include/odp_packet_tap.h \ >> ${srcdir}/include/odp_pool_internal.h \ >> ${srcdir}/include/odp_queue_internal.h \ >> ${srcdir}/include/odp_schedule_internal.h \ >> @@ -120,6 +121,7 @@ __LIB__libodp_la_SOURCES = \ >> pktio/netmap.c \ >> pktio/socket.c \ >> pktio/socket_mmap.c \ >> + pktio/tap.c \ >> odp_pool.c \ >> odp_queue.c \ >> odp_rwlock.c \ >> diff --git a/platform/linux-generic/include/odp_packet_io_internal.h >> b/platform/linux-generic/include/odp_packet_io_internal.h >> index 1a1118c..de29557 100644 >> --- a/platform/linux-generic/include/odp_packet_io_internal.h >> +++ b/platform/linux-generic/include/odp_packet_io_internal.h >> @@ -22,6 +22,7 @@ extern "C" { >> #include <odp/ticketlock.h> >> #include <odp_packet_socket.h> >> #include <odp_packet_netmap.h> >> +#include <odp_packet_tap.h> >> #include <odp_classification_datamodel.h> >> #include <odp_align_internal.h> >> #include <odp_debug_internal.h> >> @@ -78,6 +79,7 @@ struct pktio_entry { >> #ifdef HAVE_PCAP >> pkt_pcap_t pkt_pcap; /**< Using pcap for IO */ >> #endif >> + pkt_tap_t pkt_tap; /**< using TAP for IO */ >> }; >> enum { >> STATE_START = 0, >> @@ -157,6 +159,7 @@ extern const pktio_if_ops_t loopback_pktio_ops; >> #ifdef HAVE_PCAP >> extern const pktio_if_ops_t pcap_pktio_ops; >> #endif >> +extern const pktio_if_ops_t tap_pktio_ops; >> extern const pktio_if_ops_t * const pktio_if_ops[]; >> >> #ifdef __cplusplus >> diff --git a/platform/linux-generic/include/odp_packet_tap.h >> b/platform/linux-generic/include/odp_packet_tap.h >> new file mode 100644 >> index 0000000..7877586 >> --- /dev/null >> +++ b/platform/linux-generic/include/odp_packet_tap.h >> @@ -0,0 +1,21 @@ >> +/* Copyright (c) 2015, Ilya Maximets <i.maxim...@samsung.com> >> + * All rights reserved. >> + * >> + * SPDX-License-Identifier: BSD-3-Clause >> + */ >> + >> +#ifndef ODP_PACKET_TAP_H_ >> +#define ODP_PACKET_TAP_H_ >> + >> +#include <odp/pool.h> >> + >> +typedef struct { >> + int fd; /**< file descriptor for tap interface*/ >> + int skfd; /**< socket descriptor */ >> + uint32_t mtu; /**< cached mtu */ >> + unsigned char if_mac[ETH_ALEN]; /**< MAC address of pktio side (not a >> + MAC address of kernel interface)*/ >> + odp_pool_t pool; /**< pool to alloc packets from */ >> +} pkt_tap_t; >> + >> +#endif >> diff --git a/platform/linux-generic/pktio/io_ops.c >> b/platform/linux-generic/pktio/io_ops.c >> index 3b344e6..1933abc 100644 >> --- a/platform/linux-generic/pktio/io_ops.c >> +++ b/platform/linux-generic/pktio/io_ops.c >> @@ -18,6 +18,7 @@ const pktio_if_ops_t * const pktio_if_ops[] = { >> #ifdef HAVE_PCAP >> &pcap_pktio_ops, >> #endif >> + &tap_pktio_ops, >> &sock_mmap_pktio_ops, >> &sock_mmsg_pktio_ops, >> NULL >> diff --git a/platform/linux-generic/pktio/tap.c >> b/platform/linux-generic/pktio/tap.c >> new file mode 100644 >> index 0000000..b11e64f >> --- /dev/null >> +++ b/platform/linux-generic/pktio/tap.c >> @@ -0,0 +1,317 @@ >> +/* Copyright (c) 2015, Ilya Maximets <i.maxim...@samsung.com> >> + * All rights reserved. >> + * >> + * SPDX-License-Identifier: BSD-3-Clause >> + */ >> + >> +/** >> + * @file >> + * >> + * TAP pktio type >> + * >> + * This file provides a pktio interface that allows for creating and >> + * send/receive packets through TAP interface. It is intended for use >> + * as a simple conventional communication method between applications >> + * that use kernel network stack (ping, ssh, iperf, etc.) and ODP >> + * applications for the purpose of functional testing. >> + * >> + * To use this interface the name passed to odp_pktio_open() must begin >> + * with "tap:" and be in the format: >> + * >> + * tap:iface >> + * >> + * iface the name of TAP device to be created. >> + * >> + * TUN/TAP kernel module should be loaded to use this pktio. >> + * There should be no device named 'iface' in the system. >> + * The total length of the 'iface' is limited by IF_NAMESIZE. >> + */ >> + >> +#ifndef _GNU_SOURCE >> +#define _GNU_SOURCE >> +#endif >> + >> +#include <errno.h> >> +#include <fcntl.h> >> +#include <unistd.h> >> +#include <stdio.h> >> +#include <sys/ioctl.h> >> +#include <sys/socket.h> >> +#include <sys/types.h> >> +#include <linux/if_tun.h> >> + >> +#include <odp.h> >> +#include <odp_packet_socket.h> >> +#include <odp_packet_internal.h> >> +#include <odp_packet_io_internal.h> >> + >> +#define BUF_SIZE 65536 >> + >> +static int gen_random_mac(unsigned char *mac) >> +{ >> + mac[0] = 0x7a; /* not multicast and local assignment bit is set */ >> + if (odp_random_data(mac + 1, 5, false) < 5) { >> + ODP_ERR("odp_random_data failed.\n"); >> + return -1; >> + } >> + return 0; >> +} >> + >> +static int tap_pktio_open(odp_pktio_t id ODP_UNUSED, >> + pktio_entry_t *pktio_entry, >> + const char *devname, odp_pool_t pool) >> +{ >> + int fd, skfd, flags, mtu; >> + struct ifreq ifr; >> + pkt_tap_t *tap = &pktio_entry->s.pkt_tap; >> + >> + if (strncmp(devname, "tap:", 4) != 0) >> + return -1; >> + >> + /* Init pktio entry */ >> + memset(tap, 0, sizeof(*tap)); >> + tap->fd = -1; >> + tap->skfd = -1; >> + >> + if (pool == ODP_POOL_INVALID) >> + return -1; >> + >> + fd = open("/dev/net/tun", O_RDWR); >> + if (fd < 0) { >> + __odp_errno = errno; >> + ODP_ERR("failed to open /dev/net/tun: %s\n", strerror(errno)); >> + return -1; >> + } >> + >> + memset(&ifr, 0, sizeof(ifr)); >> + /* Flags: IFF_TUN - TUN device (no Ethernet headers) >> + * IFF_TAP - TAP device >> + * >> + * IFF_NO_PI - Do not provide packet information >> + */ >> + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; >> + snprintf(ifr.ifr_name, IF_NAMESIZE, "%s", devname + 4); >> + >> + if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0) { >> + __odp_errno = errno; >> + ODP_ERR("%s: creating tap device failed: %s\n", >> + ifr.ifr_name, strerror(errno)); >> + goto tap_err; >> + } >> + >> + /* Set nonblocking mode on interface. */ >> + flags = fcntl(fd, F_GETFL, 0); >> + if (flags < 0) { >> + __odp_errno = errno; >> + ODP_ERR("fcntl(F_GETFL) failed: %s\n", strerror(errno)); >> + goto tap_err; >> + } >> + >> + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { >> + __odp_errno = errno; >> + ODP_ERR("fcntl(F_SETFL) failed: %s\n", strerror(errno)); >> + goto tap_err; >> + } >> + >> + if (gen_random_mac(tap->if_mac) < 0) >> + goto tap_err; >> + >> + /* Create AF_INET socket for network interface related operations. */ >> + skfd = socket(AF_INET, SOCK_DGRAM, 0); >> + if (skfd < 0) { >> + __odp_errno = errno; >> + ODP_ERR("socket creation failed: %s\n", strerror(errno)); >> + goto tap_err; >> + } >> + >> + mtu = mtu_get_fd(skfd, devname + 4); >> + if (mtu < 0) { >> + __odp_errno = errno; >> + ODP_ERR("mtu_get_fd failed: %s\n", strerror(errno)); >> + goto sock_err; >> + } >> + >> + /* Up interface by default. */ >> + if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) { >> + __odp_errno = errno; >> + ODP_ERR("ioctl(SIOCGIFFLAGS) failed: %s\n", strerror(errno)); >> + goto sock_err; >> + } >> + >> + ifr.ifr_flags |= IFF_UP; >> + ifr.ifr_flags |= IFF_RUNNING; >> + >> + if (ioctl(skfd, SIOCSIFFLAGS, &ifr) < 0) { >> + __odp_errno = errno; >> + ODP_ERR("failed to come up: %s\n", strerror(errno)); >> + goto sock_err; >> + } >> + >> + tap->fd = fd; >> + tap->skfd = skfd; >> + tap->mtu = mtu; >> + tap->pool = pool; >> + return 0; >> +sock_err: >> + close(skfd); >> +tap_err: >> + close(fd); >> + ODP_ERR("Tap device alloc failed.\n"); >> + return -1; >> +} >> + >> +static int tap_pktio_close(pktio_entry_t *pktio_entry) >> +{ >> + int ret = 0; >> + pkt_tap_t *tap = &pktio_entry->s.pkt_tap; >> + >> + if (tap->fd != -1 && close(tap->fd) != 0) { >> + __odp_errno = errno; >> + ODP_ERR("close(tap->fd): %s\n", strerror(errno)); >> + ret = -1; >> + } >> + >> + if (tap->skfd != -1 && close(tap->skfd) != 0) { >> + __odp_errno = errno; >> + ODP_ERR("close(tap->skfd): %s\n", strerror(errno)); >> + ret = -1; >> + } >> + >> + return ret; >> +} >> + >> +static odp_packet_t pack_odp_pkt(odp_pool_t pool, >> + const void *data, >> + unsigned int len) >> +{ >> + odp_packet_t pkt; >> + >> + pkt = packet_alloc(pool, len, 1); >> + >> + if (pkt == ODP_PACKET_INVALID) >> + return pkt; >> + >> + if (odp_packet_copydata_in(pkt, 0, len, data) < 0) { >> + ODP_ERR("failed to copy packet data\n"); >> + odp_packet_free(pkt); >> + return ODP_PACKET_INVALID; >> + } >> + >> + packet_parse_l2(odp_packet_hdr(pkt)); >> + >> + return pkt; >> +} >> + >> +static int tap_pktio_recv(pktio_entry_t *pktio_entry, odp_packet_t pkts[], >> + unsigned len) >> +{ >> + ssize_t retval; >> + unsigned i; >> + uint8_t buf[BUF_SIZE]; >> + pkt_tap_t *tap = &pktio_entry->s.pkt_tap; >> + >> + for (i = 0; i < len; i++) { >> + do { >> + retval = read(tap->fd, buf, BUF_SIZE); >> + } while (retval < 0 && errno == EINTR); >> + >> + if (retval < 0) { >> + __odp_errno = errno; >> + break; >> + } >> + >> + pkts[i] = pack_odp_pkt(tap->pool, buf, retval); >> + if (pkts[i] == ODP_PACKET_INVALID) >> + break; >> + } >> + >> + return i; >> +} >> + >> +static int tap_pktio_send(pktio_entry_t *pktio_entry, odp_packet_t pkts[], >> + unsigned len) >> +{ >> + ssize_t retval; >> + unsigned i; >> + uint32_t pkt_len; >> + uint8_t buf[BUF_SIZE]; >> + pkt_tap_t *tap = &pktio_entry->s.pkt_tap; >> + >> + for (i = 0; i < len; i++) { >> + pkt_len = odp_packet_len(pkts[i]); >> + >> + if (pkt_len > tap->mtu) { >> + if (i == 0) >> + __odp_errno = EMSGSIZE; >> + break; >> + } >> + >> + if (odp_packet_copydata_out(pkts[i], 0, pkt_len, buf) < 0) { >> + ODP_ERR("failed to copy packet data\n"); >> + break; >> + } >> + >> + do { >> + retval = write(tap->fd, buf, pkt_len); >> + } while (retval < 0 && errno == EINTR); >> + >> + if (retval < 0) { >> + __odp_errno = (errno == ENOBUFS) ? EAGAIN : errno; >> + break; >> + } else if (retval != pkt_len) { >> + __odp_errno = EMSGSIZE; >> + ODP_ERR("sent partial ethernet packet\n"); >> + break; >> + } >> + >> + odp_packet_free(pkts[i]); >> + } >> + >> + return (i != 0 || len == 0) ? (int)i : -1; >> +} > > It looks like this will return -1 if an ENOBUFS error occurs the first > time around (no packets received yet). That should be a 0 return value > as -1 indicates the caller needs to take some action to recover, which > isn't required in this case. >
You talking about tap_pktio_send or tap_pktio_recv? In case of recv, -1 can't be returned, and, in case of send, ENOBUFS means nothing was sent. At least, socket_mmap returns -1 in case of ENOBUFS on send. Best regards, Ilya Maximets. _______________________________________________ lng-odp mailing list lng-odp@lists.linaro.org https://lists.linaro.org/mailman/listinfo/lng-odp