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().

> 
> Best regards, Ilya Maximets.

-- 
Stuart.
_______________________________________________
lng-odp mailing list
lng-odp@lists.linaro.org
https://lists.linaro.org/mailman/listinfo/lng-odp

Reply via email to