diff options
-rw-r--r-- | example/Makefile.am | 3 | ||||
-rw-r--r-- | platform/linux-dpdk/Makefile.am | 5 | ||||
-rw-r--r-- | platform/linux-dpdk/include/odp_packet_dpdk.h | 30 | ||||
-rw-r--r-- | platform/linux-dpdk/include/odp_packet_internal.h | 2 | ||||
-rw-r--r-- | platform/linux-dpdk/include/odp_packet_io_internal.h | 85 | ||||
-rw-r--r-- | platform/linux-dpdk/odp_init.c | 4 | ||||
-rw-r--r-- | platform/linux-dpdk/odp_packet_dpdk.c | 269 | ||||
-rw-r--r-- | platform/linux-dpdk/test/Makefile.am | 2 | ||||
-rw-r--r-- | test/validation/Makefile.am | 4 |
9 files changed, 344 insertions, 60 deletions
diff --git a/example/Makefile.am b/example/Makefile.am index 96dad93e0..39d9b0198 100644 --- a/example/Makefile.am +++ b/example/Makefile.am @@ -1,2 +1 @@ -#SUBDIRS = classifier generator ipsec packet time timer -SUBDIRS = generator ipsec packet time timer +SUBDIRS = classifier generator ipsec packet time timer diff --git a/platform/linux-dpdk/Makefile.am b/platform/linux-dpdk/Makefile.am index cfc3c18dd..506d7cff2 100644 --- a/platform/linux-dpdk/Makefile.am +++ b/platform/linux-dpdk/Makefile.am @@ -95,6 +95,7 @@ odpplatinclude_HEADERS = \ noinst_HEADERS = \ $(srcdir)/include/odp_buffer_internal.h \ + $(top_srcdir)/platform/linux-generic/include/odp_classification_internal.h \ $(top_srcdir)/platform/linux-generic/include/odp_debug_internal.h \ $(srcdir)/include/odp_packet_dpdk.h \ $(srcdir)/include/odp_packet_internal.h \ @@ -118,6 +119,7 @@ subdirheaders_HEADERS = \ __LIB__libodp_la_SOURCES = \ ../linux-generic/odp_barrier.c \ odp_buffer.c \ + ../linux-generic/odp_classification.c \ ../linux-generic/odp_cpu.c \ ../linux-generic/odp_cpumask.c \ ../linux-generic/odp_cpumask_task.c \ @@ -130,7 +132,8 @@ __LIB__libodp_la_SOURCES = \ odp_packet.c \ odp_packet_dpdk.c \ odp_packet_flags.c \ - odp_packet_io.c \ + ../linux-generic/odp_packet_io.c \ + ../linux-generic/pktio/loop.c \ odp_pool.c \ ../linux-generic/odp_queue.c \ ../../helper/ring.c \ diff --git a/platform/linux-dpdk/include/odp_packet_dpdk.h b/platform/linux-dpdk/include/odp_packet_dpdk.h index 49a0fc817..676bc801b 100644 --- a/platform/linux-dpdk/include/odp_packet_dpdk.h +++ b/platform/linux-dpdk/include/odp_packet_dpdk.h @@ -54,35 +54,5 @@ #define RTE_TEST_RX_DESC_DEFAULT 128 #define RTE_TEST_TX_DESC_DEFAULT 512 -/** Packet socket using dpdk mmaped rings for both Rx and Tx */ -typedef struct { - odp_pool_t pool; - - /********************************/ - char ifname[32]; - uint8_t min_rx_burst; - uint8_t portid; - uint16_t queueid; - odp_bool_t vdev_sysc_promisc; /**< promiscuous mode defined with - system call */ -} pkt_dpdk_t; - -/** - * Configure an interface to work in dpdk mode - */ -int setup_pkt_dpdk(pkt_dpdk_t * const pkt_dpdk, const char *netdev, - odp_pool_t pool); - -/** - * Switch interface from dpdk mode to normal mode - */ -int close_pkt_dpdk(pkt_dpdk_t * const pkt_dpdk); - -/** - * Receive packets using dpdk - */ -int recv_pkt_dpdk(pkt_dpdk_t * const pkt_dpdk, odp_packet_t pkt_table[], - unsigned len); - int odp_init_dpdk(const char *cmdline); #endif diff --git a/platform/linux-dpdk/include/odp_packet_internal.h b/platform/linux-dpdk/include/odp_packet_internal.h index 48a736c63..0dbc617ea 100644 --- a/platform/linux-dpdk/include/odp_packet_internal.h +++ b/platform/linux-dpdk/include/odp_packet_internal.h @@ -207,7 +207,7 @@ static inline int packet_parse_full(odp_packet_hdr_t *pkt_hdr) return _odp_packet_parse(pkt_hdr); } -static inline uint32_t packet_hdr_len(odp_packet_hdr_t* pkt_hdr) +static inline uint32_t packet_len(odp_packet_hdr_t* pkt_hdr) { return rte_pktmbuf_pkt_len(&pkt_hdr->buf_hdr.mb); } diff --git a/platform/linux-dpdk/include/odp_packet_io_internal.h b/platform/linux-dpdk/include/odp_packet_io_internal.h index 8e6b156ef..a2a41dc80 100644 --- a/platform/linux-dpdk/include/odp_packet_io_internal.h +++ b/platform/linux-dpdk/include/odp_packet_io_internal.h @@ -19,45 +19,63 @@ extern "C" { #endif #include <odp/spinlock.h> +#include <odp/ticketlock.h> #include <odp_packet_socket.h> #include <odp_classification_datamodel.h> #include <odp_align_internal.h> +#include <odp_debug_internal.h> #include <odp/config.h> #include <odp/hints.h> #include <odp_packet_dpdk.h> -/** - * Packet IO types - */ +#define PKTIO_NAME_LEN 256 -typedef enum { - ODP_PKTIO_TYPE_DPDK = 0x1, - ODP_PKTIO_TYPE_LOOPBACK, -} odp_pktio_type_t; +/* Forward declaration */ +struct pktio_if_ops; +struct pkt_dpdk_t; +typedef struct { + odp_queue_t loopq; /**< loopback queue for "loop" device */ + odp_bool_t promisc; /**< promiscuous mode state */ +} pkt_loop_t; + +/** Packet socket using dpdk mmaped rings for both Rx and Tx */ +typedef struct { + odp_pool_t pool; + + /********************************/ + char ifname[32]; + uint8_t min_rx_burst; + uint8_t portid; + uint16_t queueid; + odp_bool_t vdev_sysc_promisc; /**< promiscuous mode defined with + system call */ +} pkt_dpdk_t; struct pktio_entry { - odp_spinlock_t lock; /**< entry spinlock */ - odp_ticketlock_t rxl; /**< RX ticket lock */ - odp_ticketlock_t txl; /**< TX ticket lock */ + const struct pktio_if_ops *ops; /**< Implementation specific methods */ + /* These two locks together lock the whole pktio device */ + odp_ticketlock_t rxl; /**< RX ticketlock */ + odp_ticketlock_t txl; /**< TX ticketlock */ int taken; /**< is entry taken(1) or free(0) */ int cls_enabled; /**< is classifier enabled */ odp_pktio_t handle; /**< pktio handle */ 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_dpdk_t pkt_dpdk; /**< using DPDK API for IO */ + union { + pkt_loop_t pkt_loop; /**< Using loopback for IO */ + pkt_dpdk_t pkt_dpdk; /**< using DPDK API for IO */ + }; enum { STATE_START = 0, STATE_STOP } state; classifier_t cls; /**< classifier linked with this pktio*/ - char name[IFNAMSIZ]; /**< name of pktio provided to + char name[PKTIO_NAME_LEN]; /**< name of pktio provided to pktio_open() */ - odp_bool_t promisc; /**< promiscuous mode state */ + odp_pktio_t id; odp_pktio_param_t param; }; @@ -71,6 +89,29 @@ typedef struct { pktio_entry_t entries[ODP_CONFIG_PKTIO_ENTRIES]; } pktio_table_t; +int is_free(pktio_entry_t *entry); + +typedef struct pktio_if_ops { + int (*init)(void); + int (*term)(void); + int (*open)(odp_pktio_t pktio, pktio_entry_t *pktio_entry, + const char *devname, odp_pool_t pool); + int (*close)(pktio_entry_t *pktio_entry); + int (*start)(pktio_entry_t *pktio_entry); + int (*stop)(pktio_entry_t *pktio_entry); + int (*recv)(pktio_entry_t *pktio_entry, odp_packet_t pkt_table[], + unsigned len); + int (*send)(pktio_entry_t *pktio_entry, odp_packet_t pkt_table[], + unsigned len); + int (*mtu_get)(pktio_entry_t *pktio_entry); + int (*promisc_mode_set)(pktio_entry_t *pktio_entry, int enable); + int (*promisc_mode_get)(pktio_entry_t *pktio_entry); + int (*mac_get)(pktio_entry_t *pktio_entry, void *mac_addr); +} pktio_if_ops_t; + +int _odp_packet_cls_enq(pktio_entry_t *pktio_entry, const uint8_t *base, + uint16_t buf_len, odp_packet_t *pkt_ret); + extern void *pktio_entry_ptr[]; static inline int pktio_to_id(odp_pktio_t pktio) @@ -92,8 +133,22 @@ static inline pktio_entry_t *get_pktio_entry(odp_pktio_t pktio) return pktio_entry_ptr[pktio_to_id(pktio)]; } +static inline int pktio_cls_enabled(pktio_entry_t *entry) +{ + return entry->s.cls_enabled; +} + +static inline void pktio_cls_enabled_set(pktio_entry_t *entry, int ena) +{ + entry->s.cls_enabled = ena; +} + int pktin_poll(pktio_entry_t *entry); +extern const pktio_if_ops_t loopback_pktio_ops; +extern const pktio_if_ops_t dpdk_pktio_ops; +extern const pktio_if_ops_t * const pktio_if_ops[]; + #ifdef __cplusplus } #endif diff --git a/platform/linux-dpdk/odp_init.c b/platform/linux-dpdk/odp_init.c index 7fc5ecd5e..1a0c22823 100644 --- a/platform/linux-dpdk/odp_init.c +++ b/platform/linux-dpdk/odp_init.c @@ -294,12 +294,10 @@ int odp_init_global(const odp_init_t *params, return -1; } -#if 0 /* for now classification is disabled */ if (odp_classification_init_global()) { ODP_ERR("ODP classification init failed.\n"); return -1; } -#endif return 0; } @@ -308,12 +306,10 @@ int odp_term_global(void) { int rc = 0; -#if 0 /* for now classification is disabled */ if (odp_classification_term_global()) { ODP_ERR("ODP classificatio term failed.\n"); rc = -1; } -#endif if (odp_crypto_term_global()) { ODP_ERR("ODP crypto term failed.\n"); diff --git a/platform/linux-dpdk/odp_packet_dpdk.c b/platform/linux-dpdk/odp_packet_dpdk.c index 3a24b0334..d130ac0e2 100644 --- a/platform/linux-dpdk/odp_packet_dpdk.c +++ b/platform/linux-dpdk/odp_packet_dpdk.c @@ -26,10 +26,23 @@ #include <odp/system_info.h> #include <odp_debug_internal.h> +#include <odp_packet_io_internal.h> #include <odp_packet_dpdk.h> #include <net/if.h> #include <math.h> +/* Ops for all implementation of pktio. + * Order matters. The first implementation to setup successfully + * will be picked. + * Array must be NULL terminated */ +const pktio_if_ops_t * const pktio_if_ops[] = { + &loopback_pktio_ops, + &dpdk_pktio_ops, + NULL +}; + +extern pktio_table_t *pktio_tbl; + /* Test if s has only digits or not. Dpdk pktio uses only digits.*/ static int _dpdk_netdev_is_valid(const char *s) { @@ -58,8 +71,8 @@ static void _dpdk_print_port_mac(uint8_t portid) eth_addr.addr_bytes[5]); } -int setup_pkt_dpdk(pkt_dpdk_t * const pkt_dpdk, const char *netdev, - odp_pool_t pool) +static int setup_pkt_dpdk(odp_pktio_t pktio ODP_UNUSED, pktio_entry_t *pktio_entry, + const char *netdev, odp_pool_t pool) { uint8_t portid = 0; uint16_t nbrxq, nbtxq; @@ -70,6 +83,7 @@ int setup_pkt_dpdk(pkt_dpdk_t * const pkt_dpdk, const char *netdev, uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT; uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT; struct rte_eth_dev_info dev_info; + pkt_dpdk_t * const pkt_dpdk = &pktio_entry->s.pkt_dpdk; struct rte_eth_conf port_conf = { .rxmode = { @@ -162,17 +176,82 @@ int setup_pkt_dpdk(pkt_dpdk_t * const pkt_dpdk, const char *netdev, return 0; } -int close_pkt_dpdk(pkt_dpdk_t * const pkt_dpdk) +static int close_pkt_dpdk(pktio_entry_t *pktio_entry) { + pkt_dpdk_t * const pkt_dpdk = &pktio_entry->s.pkt_dpdk; + rte_eth_dev_close(pkt_dpdk->portid); return 0; } -int recv_pkt_dpdk(pkt_dpdk_t * const pkt_dpdk, odp_packet_t pkt_table[], +static int start_pkt_dpdk(pktio_entry_t *pktio_entry) +{ + int ret; + + ret = rte_eth_dev_start(pktio_entry->s.pkt_dpdk.portid); + if (ret < 0) { + ODP_ERR("rte_eth_dev_start:err=%d, port=%u\n", + ret, pktio_entry->s.pkt_dpdk.portid); + return ret; + } + return 0; +} + +static int stop_pkt_dpdk(pktio_entry_t *pktio_entry) +{ + rte_eth_dev_stop(pktio_entry->s.pkt_dpdk.portid); + return 0; +} + +static unsigned rte_mempool_available(const struct rte_mempool *mp) +{ +#if RTE_MEMPOOL_CACHE_MAX_SIZE > 0 + return rte_ring_count(mp->ring) + mp->local_cache[rte_lcore_id()].len; +#else + return rte_ring_count(mp->ring); +#endif +} + +static void _odp_pktio_send_completion(pktio_entry_t *pktio_entry ODP_UNUSED) +{ + int i; + struct rte_mbuf* dummy; + pool_entry_t *pool_entry = + get_pool_entry(_odp_typeval(pktio_entry->s.pkt_dpdk.pool)); + struct rte_mempool *rte_mempool = pool_entry->s.rte_mempool; + pkt_dpdk_t * pkt_dpdk = &pktio_entry->s.pkt_dpdk; + + rte_eth_tx_burst(pkt_dpdk->portid, pkt_dpdk->queueid, &dummy, 0); + + for (i = 0; i < ODP_CONFIG_PKTIO_ENTRIES; ++i) { + pktio_entry_t *entry = &pktio_tbl->entries[i]; + + if (rte_mempool_available(rte_mempool) != 0) + return; + + if (entry == pktio_entry) + continue; + + if (odp_ticketlock_trylock(&entry->s.txl)) { + if (!is_free(entry) && + entry->s.ops == &dpdk_pktio_ops) { + pkt_dpdk = &entry->s.pkt_dpdk; + rte_eth_tx_burst(pkt_dpdk->portid, + pkt_dpdk->queueid, &dummy, 0); + } + odp_ticketlock_unlock(&entry->s.txl); + } + } + + return; +} + +static int recv_pkt_dpdk(pktio_entry_t *pktio_entry, odp_packet_t pkt_table[], unsigned len) { uint16_t nb_rx, i = 0; odp_packet_t *saved_pkt_table; + pkt_dpdk_t * const pkt_dpdk = &pktio_entry->s.pkt_dpdk; uint8_t min = pkt_dpdk->min_rx_burst; if (odp_unlikely(min > len)) { @@ -187,6 +266,17 @@ int recv_pkt_dpdk(pkt_dpdk_t * const pkt_dpdk, odp_packet_t pkt_table[], (struct rte_mbuf **)pkt_table, (uint16_t)RTE_MAX(len, min)); + if (nb_rx == 0) { + pool_entry_t *pool_entry = + get_pool_entry(_odp_typeval(pkt_dpdk->pool)); + struct rte_mempool *rte_mempool = + pool_entry->s.rte_mempool; + if (rte_mempool_available(rte_mempool) == 0) + _odp_pktio_send_completion(pktio_entry); + } + for (i = 0; i < nb_rx; ++i) + _odp_packet_reset_parse(pkt_table[i]); + if (odp_unlikely(min > len)) { memcpy(saved_pkt_table, pkt_table, len * sizeof(odp_packet_t)); @@ -198,3 +288,174 @@ int recv_pkt_dpdk(pkt_dpdk_t * const pkt_dpdk, odp_packet_t pkt_table[], return nb_rx; } + +static int send_pkt_dpdk(pktio_entry_t *pktio_entry, odp_packet_t pkt_table[], + unsigned len) +{ + int pkts; + pkt_dpdk_t * const pkt_dpdk = &pktio_entry->s.pkt_dpdk; + + pkts = rte_eth_tx_burst(pkt_dpdk->portid, pkt_dpdk->queueid, + (struct rte_mbuf **)pkt_table, len); + if (pkts) { + return pkts; + } else { + if (!rte_errno) + rte_errno = -1; + return -1; + } +} + +static int _dpdk_vdev_mtu(uint8_t port_id) +{ + struct rte_eth_dev_info dev_info = {0}; + struct ifreq ifr; + int ret; + int sockfd; + + rte_eth_dev_info_get(port_id, &dev_info); + if_indextoname(dev_info.if_index, ifr.ifr_name); + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + ret = ioctl(sockfd, SIOCGIFMTU, &ifr); + close(sockfd); + if (ret < 0) { + ODP_DBG("ioctl SIOCGIFMTU error\n"); + return -1; + } + + return ifr.ifr_mtu; +} + +static int mtu_get_pkt_dpdk(pktio_entry_t *pktio_entry) +{ + uint16_t mtu; + int ret; + + ret = rte_eth_dev_get_mtu(pktio_entry->s.pkt_dpdk.portid, + &mtu); + if (ret < 0) + return -2; + + /* some dpdk PMD vdev does not support getting mtu size, + * try to use system call if dpdk cannot get mtu value. + */ + if (mtu == 0) + mtu = _dpdk_vdev_mtu(pktio_entry->s.pkt_dpdk.portid); + return mtu; +} + +static int _dpdk_vdev_promisc_mode_set(uint8_t port_id, int enable) +{ + struct rte_eth_dev_info dev_info = {0}; + struct ifreq ifr; + int ret; + int sockfd; + + rte_eth_dev_info_get(port_id, &dev_info); + if_indextoname(dev_info.if_index, ifr.ifr_name); + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + + ret = ioctl(sockfd, SIOCGIFFLAGS, &ifr); + if (ret < 0) { + close(sockfd); + ODP_DBG("ioctl SIOCGIFFLAGS error\n"); + return -1; + } + + if (enable) + ifr.ifr_flags |= IFF_PROMISC; + else + ifr.ifr_flags &= ~(IFF_PROMISC); + + ret = ioctl(sockfd, SIOCSIFFLAGS, &ifr); + if (ret < 0) { + close(sockfd); + ODP_DBG("ioctl SIOCSIFFLAGS error\n"); + return -1; + } + + ret = ioctl(sockfd, SIOCGIFMTU, &ifr); + if (ret < 0) { + close(sockfd); + ODP_DBG("ioctl SIOCGIFMTU error\n"); + return -1; + } + + ODP_DBG("vdev promisc set to %d\n", enable); + close(sockfd); + return 0; +} + +static int promisc_mode_set_pkt_dpdk(pktio_entry_t *pktio_entry, int enable) +{ + uint8_t portid = pktio_entry->s.pkt_dpdk.portid; + if (enable) + rte_eth_promiscuous_enable(portid); + else + rte_eth_promiscuous_disable(portid); + + if (pktio_entry->s.pkt_dpdk.vdev_sysc_promisc) { + int ret = _dpdk_vdev_promisc_mode_set(portid, enable); + if (ret < 0) + ODP_DBG("vdev promisc mode fail\n"); + } + + return 0; +} + +static int _dpdk_vdev_promisc_mode(uint8_t port_id) +{ + struct rte_eth_dev_info dev_info = {0}; + struct ifreq ifr; + int ret; + int sockfd; + + rte_eth_dev_info_get(port_id, &dev_info); + if_indextoname(dev_info.if_index, ifr.ifr_name); + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + ret = ioctl(sockfd, SIOCGIFFLAGS, &ifr); + close(sockfd); + if (ret < 0) { + ODP_DBG("ioctl SIOCGIFFLAGS error\n"); + return -1; + } + + if (ifr.ifr_flags & IFF_PROMISC) { + ODP_DBG("promisc is 1\n"); + return 1; + } else + return 0; +} + +static int promisc_mode_get_pkt_dpdk(pktio_entry_t *pktio_entry) +{ + uint8_t portid = pktio_entry->s.pkt_dpdk.portid; + if (pktio_entry->s.pkt_dpdk.vdev_sysc_promisc) + return _dpdk_vdev_promisc_mode(portid); + else + return rte_eth_promiscuous_get(portid); + +} + +static int mac_get_pkt_dpdk(pktio_entry_t *pktio_entry, void *mac_addr) +{ + rte_eth_macaddr_get(pktio_entry->s.pkt_dpdk.portid, + (struct ether_addr *)mac_addr); + return ETH_ALEN; +} + + +const pktio_if_ops_t dpdk_pktio_ops = { + .init = NULL, + .term = NULL, + .open = setup_pkt_dpdk, + .close = close_pkt_dpdk, + .start = start_pkt_dpdk, + .stop = stop_pkt_dpdk, + .recv = recv_pkt_dpdk, + .send = send_pkt_dpdk, + .mtu_get = mtu_get_pkt_dpdk, + .promisc_mode_set = promisc_mode_set_pkt_dpdk, + .promisc_mode_get = promisc_mode_get_pkt_dpdk, + .mac_get = mac_get_pkt_dpdk +}; diff --git a/platform/linux-dpdk/test/Makefile.am b/platform/linux-dpdk/test/Makefile.am index 3eda00df9..dc09cdb40 100644 --- a/platform/linux-dpdk/test/Makefile.am +++ b/platform/linux-dpdk/test/Makefile.am @@ -6,7 +6,7 @@ ODP_MODULES = pktio if test_vald TESTS = pktio/pktio_run \ ${top_builddir}/test/validation/buffer/buffer_main$(EXEEXT) \ -## ${top_builddir}/test/validation/classification/classification_main$(EXEEXT) \ + ${top_builddir}/test/validation/classification/classification_main$(EXEEXT) \ ${top_builddir}/test/validation/cpumask/cpumask_main$(EXEEXT) \ ${top_builddir}/test/validation/crypto/crypto_main$(EXEEXT) \ ${top_builddir}/test/validation/errno/errno_main$(EXEEXT) \ diff --git a/test/validation/Makefile.am b/test/validation/Makefile.am index 3817136a3..197ff8960 100644 --- a/test/validation/Makefile.am +++ b/test/validation/Makefile.am @@ -1,5 +1,5 @@ ODP_MODULES = buffer \ -## classification \ + classification \ config \ cpumask \ crypto \ @@ -23,4 +23,4 @@ ODP_MODULES = buffer \ SUBDIRS = common $(ODP_MODULES) #The tests will need to retain the deprecated test implementation -AM_CFLAGS += -Wno-deprecated-declarations +AM_CFLAGS += -Wno-deprecated-declarations
\ No newline at end of file |