On Tue, Dec 08, 2015 at 03:25:01PM +0300, Ilya Maximets wrote: > > > On 08.12.2015 15:16, Stuart Haslam wrote: > > On Tue, Dec 08, 2015 at 02:51:40PM +0300, Ilya Maximets wrote: > >> 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? > > > > tap_pktio_send > > > >> 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. > > > > So it does, I think that's a bug and ENOBUFS should be filtered out by > > SOCK_ERR_REPORT(). > > > > I agree. Would you prepare that patch?
Will do. > OK, I think, I can change this function and use SOCK_ERR_REPORT() macro here > like in other pktios. > OK, sounds good. -- Stuart. _______________________________________________ lng-odp mailing list lng-odp@lists.linaro.org https://lists.linaro.org/mailman/listinfo/lng-odp