On 01/08/2015 07:09 PM, Stuart Haslam wrote:
Create a new linux-generic pktio type ODP_PKTIO_TYPE_LOOPBACK which
will be used when the "loop" device is opened. A queue is used to
connect the pktio output queue to the input queue. Packets sent to the
loopback device are classified before making it to the input queue.

I like that idea to create fully virtual loop dev. But how classifier works for hardware case loop back device?
Is it always on?


I'm a not sure if separate queue is needed. There are in/out and you added loop. In general loop should emulate in/out queue. Need to check what should other API do with that queue, like: odp_pktio_inq_remdef(loop).

1500 as default MTU is better to set up to some define. Like if_ether.h: ETH_DATA_LEN

btw, can you please review v7 patch for odp_pktio_inq_remdef() ?

BR,
Maxim.

A random MAC address is assigned when the device is opened, and the
other control functions (MTU/promisc) are just dummies.

As this doesn't need root access, the odp_pktio_run script is modified
to use the "loop" device when not root. The veth method is still used
when running as root (on linux-generic) so that the socket code
actually gets tested.

Signed-off-by: Stuart Haslam <[email protected]>
---
(This code contribution is provided under the terms of agreement LES-LTM-21309)

  .../linux-generic/include/odp_packet_io_internal.h |   3 +
  platform/linux-generic/odp_packet_io.c             | 116 ++++++++++++++++-----
  test/validation/odp_pktio_run                      |  11 +-
  3 files changed, 99 insertions(+), 31 deletions(-)

diff --git a/platform/linux-generic/include/odp_packet_io_internal.h 
b/platform/linux-generic/include/odp_packet_io_internal.h
index 465127b..ea97a88 100644
--- a/platform/linux-generic/include/odp_packet_io_internal.h
+++ b/platform/linux-generic/include/odp_packet_io_internal.h
@@ -34,6 +34,7 @@ typedef enum {
        ODP_PKTIO_TYPE_SOCKET_BASIC = 0x1,
        ODP_PKTIO_TYPE_SOCKET_MMSG,
        ODP_PKTIO_TYPE_SOCKET_MMAP,
+       ODP_PKTIO_TYPE_LOOPBACK,
  } odp_pktio_type_t;
struct pktio_entry {
@@ -41,12 +42,14 @@ struct pktio_entry {
        int taken;                      /**< is entry taken(1) or free(0) */
        odp_queue_t inq_default;        /**< default input queue, if set */
        odp_queue_t outq_default;       /**< default out queue */
+       odp_queue_t loopq;              /**< loopback queue */
        odp_pktio_type_t type;          /**< pktio type */
        pkt_sock_t pkt_sock;            /**< using socket API for IO */
        pkt_sock_mmap_t pkt_sock_mmap;  /**< using socket mmap API for IO */
        classifier_t cls;               /**< classifier linked with this pktio*/
        char name[IFNAMSIZ];            /**< name of pktio provided to
                                           pktio_open() */
+       odp_bool_t promisc;             /**< promiscuous mode state */
  };
typedef union {
diff --git a/platform/linux-generic/odp_packet_io.c 
b/platform/linux-generic/odp_packet_io.c
index 59590d2..7335dd3 100644
--- a/platform/linux-generic/odp_packet_io.c
+++ b/platform/linux-generic/odp_packet_io.c
@@ -18,11 +18,13 @@
  #include <odp_schedule_internal.h>
  #include <odp_classification_internal.h>
  #include <odp_debug_internal.h>
+#include <odp_time.h>
#include <string.h>
  #include <sys/ioctl.h>
  #include <linux/if_arp.h>
  #include <ifaddrs.h>
+#include <stdlib.h>
static pktio_table_t *pktio_tbl; @@ -160,14 +162,28 @@ static int free_pktio_entry(odp_pktio_t id)
        return 0;
  }
+static int random_mac(void *mac_addr, size_t addr_size)
+{
+       uint32_t ethaddr_l, ethaddr_h;
+
+       srand(odp_time_cycles());
+       ethaddr_h = (rand() & 0xfeff) | 0x0200;
+       ethaddr_l = rand();
+
+       snprintf(mac_addr, addr_size, "%02x:%02x:%02x:%02x:%02x:%02x",
+                ethaddr_h >> 8, ethaddr_h & 0xff,
+                ethaddr_l >> 24, (ethaddr_l >> 16) & 0xff,
+                (ethaddr_l >> 8) & 0xff, ethaddr_l & 0xff);
+
+       return 0;
+}
+
  odp_pktio_t odp_pktio_open(const char *dev, odp_buffer_pool_t pool)
  {
        odp_pktio_t id;
        pktio_entry_t *pktio_entry;
        int res;
        int fanout = 1;
-       char loop[IFNAMSIZ] = {0};
-       char *loop_hint;
if (strlen(dev) >= IFNAMSIZ) {
                /* ioctl names limitation */
@@ -176,28 +192,6 @@ odp_pktio_t odp_pktio_open(const char *dev, 
odp_buffer_pool_t pool)
                return ODP_PKTIO_INVALID;
        }
- if (!strcmp(dev, "loop")) {
-               /* If hint with ODP_PKTIO_LOOPDEV is provided, use hint,
-                * if not try to find usable device.
-                */
-               loop_hint = getenv("ODP_PKTIO_LOOPDEV");
-               if (!loop_hint || (strlen(loop_hint) == 0)) {
-                       ODP_ERR("Set loop with ODP_PKTIO_LOOPDEV=ethX\n");
-                       return ODP_PKTIO_INVALID;
-               }
-
-               if (strlen(loop_hint) >= IFNAMSIZ) {
-                       ODP_ERR("pktio name %s is too big, limit is %d bytes\n",
-                               loop_hint, IFNAMSIZ);
-                       return ODP_PKTIO_INVALID;
-               }
-
-               memset(loop, 0, IFNAMSIZ);
-               memcpy(loop, loop_hint, strlen(loop_hint));
-               dev = loop;
-               ODP_DBG("pktio using %s as loopback device\n", loop_hint);
-       }
-
        id = alloc_lock_pktio_entry();
        if (id == ODP_PKTIO_INVALID) {
                ODP_ERR("No resources available.\n");
@@ -209,6 +203,22 @@ odp_pktio_t odp_pktio_open(const char *dev, 
odp_buffer_pool_t pool)
        if (!pktio_entry)
                return ODP_PKTIO_INVALID;
+ if (strcmp(dev, "loop") == 0) {
+               char loopq_name[ODP_QUEUE_NAME_LEN];
+               ODP_DBG("pktio opening loop devive\n");
+
+               pktio_entry->s.type = ODP_PKTIO_TYPE_LOOPBACK;
+               snprintf(loopq_name, sizeof(loopq_name), "%i-pktio_loopq",
+                        (int)id);
+               pktio_entry->s.loopq = odp_queue_create(loopq_name,
+                                                       ODP_QUEUE_TYPE_POLL,
+                                                       NULL);
+               random_mac(pktio_entry->s.pkt_sock.if_mac,
+                          sizeof(pktio_entry->s.pkt_sock.if_mac));
+
+               goto done;
+       }
+
        ODP_DBG("ODP_PKTIO_USE_FANOUT: %d\n", fanout);
        if (getenv("ODP_PKTIO_DISABLE_SOCKET_MMAP") == NULL) {
                pktio_entry->s.type = ODP_PKTIO_TYPE_SOCKET_MMAP;
@@ -271,6 +281,10 @@ int odp_pktio_close(odp_pktio_t id)
                case ODP_PKTIO_TYPE_SOCKET_MMAP:
                        res  = close_pkt_sock_mmap(&entry->s.pkt_sock_mmap);
                        break;
+               case ODP_PKTIO_TYPE_LOOPBACK:
+                       /* @todo: destroy loopback queue */
+                       res = 0;
+                       break;
                default:
                        break;
                }
@@ -284,6 +298,22 @@ int odp_pktio_close(odp_pktio_t id)
        return 0;
  }
+static int deq_loopback(pktio_entry_t *pktio_entry, odp_packet_t pkt_tbl[],
+                       unsigned len)
+{
+       int nbr, i;
+       odp_buffer_hdr_t *hdr_tbl[QUEUE_MULTI_MAX];
+       queue_entry_t *qentry;
+
+       qentry = queue_to_qentry(pktio_entry->s.loopq);
+       nbr = queue_deq_multi(qentry, hdr_tbl, len);
+
+       for (i = 0; i < nbr; ++i)
+               pkt_tbl[i] = odp_packet_from_buffer(odp_hdr_to_buf(hdr_tbl[i]));
+
+       return nbr;
+}
+
  int odp_pktio_recv(odp_pktio_t id, odp_packet_t pkt_table[], unsigned len)
  {
        pktio_entry_t *pktio_entry = get_pktio_entry(id);
@@ -307,6 +337,9 @@ int odp_pktio_recv(odp_pktio_t id, odp_packet_t 
pkt_table[], unsigned len)
                pkts = recv_pkt_sock_mmap(&pktio_entry->s.pkt_sock_mmap,
                                pkt_table, len);
                break;
+       case ODP_PKTIO_TYPE_LOOPBACK:
+               pkts = deq_loopback(pktio_entry, pkt_table, len);
+               break;
        default:
                pkts = -1;
                break;
@@ -322,6 +355,20 @@ int odp_pktio_recv(odp_pktio_t id, odp_packet_t 
pkt_table[], unsigned len)
        return pkts;
  }
+static int enq_loopback(pktio_entry_t *pktio_entry, odp_packet_t pkt_tbl[],
+                       unsigned len)
+{
+       odp_buffer_hdr_t *hdr_tbl[QUEUE_MULTI_MAX];
+       queue_entry_t *qentry;
+       unsigned i;
+
+       for (i = 0; i < len; ++i)
+               hdr_tbl[i] = odp_buf_to_hdr(odp_packet_to_buffer(pkt_tbl[i]));
+
+       qentry = queue_to_qentry(pktio_entry->s.loopq);
+       return queue_enq_multi(qentry, hdr_tbl, len) == 0 ? len : 0;
+}
+
  int odp_pktio_send(odp_pktio_t id, odp_packet_t pkt_table[], unsigned len)
  {
        pktio_entry_t *pktio_entry = get_pktio_entry(id);
@@ -344,6 +391,9 @@ int odp_pktio_send(odp_pktio_t id, odp_packet_t 
pkt_table[], unsigned len)
                pkts = send_pkt_sock_mmap(&pktio_entry->s.pkt_sock_mmap,
                                pkt_table, len);
                break;
+       case ODP_PKTIO_TYPE_LOOPBACK:
+               pkts = enq_loopback(pktio_entry, pkt_table, len);
+               break;
        default:
                pkts = -1;
        }
@@ -559,6 +609,11 @@ int odp_pktio_mtu(odp_pktio_t id)
                return -1;
        }
+ if (entry->s.type == ODP_PKTIO_TYPE_LOOPBACK) {
+               unlock_entry(entry);
+               return 1500;
+       }
+
        sockfd = sockfd_from_pktio_entry(entry);
        snprintf(ifr.ifr_name, IFNAMSIZ, "%s", entry->s.name);
@@ -594,6 +649,13 @@ int odp_pktio_promisc_mode_set(odp_pktio_t id, odp_bool_t enable)
                return -1;
        }
+ entry->s.promisc = enable;
+
+       if (entry->s.type == ODP_PKTIO_TYPE_LOOPBACK) {
+               unlock_entry(entry);
+               return 0;
+       }
+
        sockfd = sockfd_from_pktio_entry(entry);
        snprintf(ifr.ifr_name, IFNAMSIZ, "%s", entry->s.name);
@@ -641,6 +703,11 @@ int odp_pktio_promisc_mode(odp_pktio_t id)
                return -1;
        }
+ if (entry->s.type == ODP_PKTIO_TYPE_LOOPBACK) {
+               unlock_entry(entry);
+               return entry->s.promisc ? 1 : 0;
+       }
+
        sockfd = sockfd_from_pktio_entry(entry);
        snprintf(ifr.ifr_name, IFNAMSIZ, "%s", entry->s.name);
@@ -683,6 +750,7 @@ size_t odp_pktio_mac_addr(odp_pktio_t id, void *mac_addr,
        switch (entry->s.type) {
        case ODP_PKTIO_TYPE_SOCKET_BASIC:
        case ODP_PKTIO_TYPE_SOCKET_MMSG:
+       case ODP_PKTIO_TYPE_LOOPBACK:
                memcpy(mac_addr, entry->s.pkt_sock.if_mac,
                       ETH_ALEN);
                break;
diff --git a/test/validation/odp_pktio_run b/test/validation/odp_pktio_run
index d4d6b2c..08288e6 100755
--- a/test/validation/odp_pktio_run
+++ b/test/validation/odp_pktio_run
@@ -100,11 +100,13 @@ run_test()
run()
  {
-       if [ "$ODP_PLATFORM" != "linux-generic" ]; then
+       if [ "$ODP_PLATFORM" != "linux-generic" -o "$(id -u)" != "0" ]; then
                echo "pktio: using 'loop' device"
                $TEST_DIR/odp_pktio
                exit $?
-       elif [ "$ODP_PKTIO_IF0" = "" ]; then
+       fi
+
+       if [ "$ODP_PKTIO_IF0" = "" ]; then
                # no interfaces specified on linux-generic, use defaults
                setup_env1 clean
                export ODP_PKTIO_IF0=$IF0
@@ -120,11 +122,6 @@ if [ "$ODP_PLATFORM" = "" ]; then
        exit 1
  fi
-if [ "$(id -u)" != "0" ]; then
-       echo "pktio: error: must be run as root"
-       exit $TEST_SKIPPED
-fi
-
  case "$1" in
        setup)   setup_env1   ;;
        cleanup) cleanup_env1 ;;


_______________________________________________
lng-odp mailing list
[email protected]
http://lists.linaro.org/mailman/listinfo/lng-odp

Reply via email to