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. 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 ;; -- 2.1.1 _______________________________________________ lng-odp mailing list [email protected] http://lists.linaro.org/mailman/listinfo/lng-odp
