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 ;;