On 08.12.2015 15:35, Stuart Haslam wrote:
> 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.
> 
New version posted.

Best regards, Ilya Maximets.
_______________________________________________
lng-odp mailing list
lng-odp@lists.linaro.org
https://lists.linaro.org/mailman/listinfo/lng-odp

Reply via email to