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 parsed and classified before making it to the input queue. A fixed MAC address is used and the other control functions (MTU and promisc mode) are essentially 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 | 119 ++++++++++++++++----- test/validation/odp_pktio_run | 11 +- 3 files changed, 100 insertions(+), 33 deletions(-) diff --git a/platform/linux-generic/include/odp_packet_io_internal.h b/platform/linux-generic/include/odp_packet_io_internal.h index 7d9fc3d..1b5641f 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 for "loop" device */ 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 cd109d2..c03f47c 100644 --- a/platform/linux-generic/odp_packet_io.c +++ b/platform/linux-generic/odp_packet_io.c @@ -25,6 +25,11 @@ #include <ifaddrs.h> #include <errno.h> +/* MTU to be reported for the "loop" interface */ +#define PKTIO_LOOP_MTU 1500 +/* MAC address for the "loop" interface */ +static const char pktio_loop_mac[] = {0x02, 0xe9, 0x34, 0x80, 0x73, 0x01}; + static pktio_table_t *pktio_tbl; /* pktio pointer entries ( for inlines) */ @@ -189,15 +194,32 @@ static int init_socket(pktio_entry_t *entry, const char *dev, close_pkt_sock(&entry->s.pkt_sock); } - return fd; + if (fd == -1) + return -1; + + return 0; +} + +static int init_loop(pktio_entry_t *entry, odp_pktio_t id) +{ + char loopq_name[ODP_QUEUE_NAME_LEN]; + + entry->s.type = ODP_PKTIO_TYPE_LOOPBACK; + snprintf(loopq_name, sizeof(loopq_name), "%i-pktio_loopq", (int)id); + entry->s.loopq = odp_queue_create(loopq_name, + ODP_QUEUE_TYPE_POLL, NULL); + + if (entry->s.loopq == ODP_QUEUE_INVALID) + return -1; + + return 0; } static odp_pktio_t setup_pktio_entry(const char *dev, odp_buffer_pool_t pool) { odp_pktio_t id; pktio_entry_t *pktio_entry; - char loop[IFNAMSIZ] = {0}; - char *loop_hint; + int ret; if (strlen(dev) >= IFNAMSIZ) { /* ioctl names limitation */ @@ -206,28 +228,6 @@ static odp_pktio_t setup_pktio_entry(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"); @@ -239,7 +239,12 @@ static odp_pktio_t setup_pktio_entry(const char *dev, odp_buffer_pool_t pool) if (!pktio_entry) return ODP_PKTIO_INVALID; - if (init_socket(pktio_entry, dev, pool) == -1) { + if (strcmp(dev, "loop") == 0) + ret = init_loop(pktio_entry, id); + else + ret = init_socket(pktio_entry, dev, pool); + + if (ret != 0) { unlock_entry_classifier(pktio_entry); free_pktio_entry(id); id = ODP_PKTIO_INVALID; @@ -289,6 +294,9 @@ 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: + res = odp_queue_destroy(entry->s.loopq); + break; default: break; } @@ -332,6 +340,24 @@ odp_pktio_t odp_pktio_lookup(const char *dev) return id; } +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])); + _odp_packet_parse(pkt_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); @@ -355,6 +381,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; @@ -370,6 +399,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); @@ -392,6 +435,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; } @@ -607,6 +653,11 @@ int odp_pktio_mtu(odp_pktio_t id) return -1; } + if (entry->s.type == ODP_PKTIO_TYPE_LOOPBACK) { + unlock_entry(entry); + return PKTIO_LOOP_MTU; + } + sockfd = sockfd_from_pktio_entry(entry); snprintf(ifr.ifr_name, IFNAMSIZ, "%s", entry->s.name); @@ -642,6 +693,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); @@ -689,6 +747,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); @@ -706,6 +769,7 @@ int odp_pktio_promisc_mode(odp_pktio_t id) return 0; } + size_t odp_pktio_mac_addr(odp_pktio_t id, void *mac_addr, size_t addr_size) { @@ -738,6 +802,9 @@ size_t odp_pktio_mac_addr(odp_pktio_t id, void *mac_addr, memcpy(mac_addr, entry->s.pkt_sock_mmap.if_mac, ETH_ALEN); break; + case ODP_PKTIO_TYPE_LOOPBACK: + memcpy(mac_addr, pktio_loop_mac, ETH_ALEN); + break; default: ODP_ABORT("Wrong socket type %d\n", entry->s.type); } 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
