This looks very useful, no more headaches figuring out what system loopback device to use.
On Thu, Jan 8, 2015 at 6:09 PM, Stuart Haslam <[email protected]> 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. > 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"); typo devive > + > + 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 _______________________________________________ lng-odp mailing list [email protected] http://lists.linaro.org/mailman/listinfo/lng-odp
