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

Reply via email to