#ifndef CLICK_DPDKDEVICE_HH #define CLICK_DPDKDEVICE_HH /** * Prevent bug under some configurations * (like travis-ci's one) where these * macros get undefined. */ #ifndef UINT8_MAX #define UINT8_MAX 255 #endif #ifndef UINT16_MAX #define UINT16_MAX 65535 #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if RTE_VERSION < RTE_VERSION_NUM(19,8,0,0) #define rte_ipv4_hdr ipv4_hdr #define rte_ether_addr ether_addr #endif /** * Unified type for DPDK port IDs. * Until DPDK v17.05 was uint8_t * After DPDK v17.05 has been uint16_t */ #if RTE_VERSION >= RTE_VERSION_NUM(17,05,0,0) typedef uint16_t portid_t; #else typedef uint8_t portid_t; #endif CLICK_DECLS class DPDKDeviceArg; extern bool dpdk_enabled; class DPDKDevice { public: portid_t port_id; DPDKDevice() CLICK_COLD; DPDKDevice(portid_t port_id) CLICK_COLD; int add_rx_queue( unsigned &queue_id, bool promisc, unsigned n_desc, ErrorHandler *errh ) CLICK_COLD; int add_tx_queue( unsigned &queue_id, unsigned n_desc, ErrorHandler *errh ) CLICK_COLD; EtherAddress get_mac(); void set_init_mac(EtherAddress mac); void set_init_mtu(uint16_t mtu); unsigned int get_nb_txdesc(); int nbRXQueues(); int nbTXQueues(); const char *get_device_driver(); static unsigned int dev_count() { #if RTE_VERSION >= RTE_VERSION_NUM(18,05,0,0) return rte_eth_dev_count_avail(); #else return rte_eth_dev_count(); #endif } static struct rte_mempool *get_mpool(unsigned int); static int get_port_numa_node(portid_t port_id); static int initialize(ErrorHandler *errh); inline static bool is_dpdk_packet(Packet* p) { return p->buffer_destructor() == DPDKDevice::free_pkt || (p->data_packet() && is_dpdk_packet(p->data_packet())); } inline static rte_mbuf* get_pkt(unsigned numa_node); inline static rte_mbuf* get_pkt(); static void free_pkt(unsigned char *, size_t, void *pktmbuf); static int NB_MBUF; static int MBUF_DATA_SIZE; static int MBUF_SIZE; static int MBUF_CACHE_SIZE; static int RX_PTHRESH; static int RX_HTHRESH; static int RX_WTHRESH; static int TX_PTHRESH; static int TX_HTHRESH; static int TX_WTHRESH; static String MEMPOOL_PREFIX; static unsigned DEF_DEV_RXDESC; static unsigned DEF_DEV_TXDESC; static unsigned DEF_BURST_SIZE; private: enum Dir { RX, TX }; struct DevInfo { inline DevInfo() : rx_queues(0,false), tx_queues(0,false), promisc(false), n_rx_descs(0), n_tx_descs(0), init_mac(), init_mtu(0) { rx_queues.reserve(128); tx_queues.reserve(128); } const char* driver; Vector rx_queues; Vector tx_queues; bool promisc; unsigned n_rx_descs; unsigned n_tx_descs; EtherAddress init_mac; uint16_t init_mtu; }; DevInfo info; static bool _is_initialized; static HashTable _devs; static struct rte_mempool** _pktmbuf_pools; static unsigned _nr_pktmbuf_pools; static bool no_more_buffer_msg_printed; int initialize_device(ErrorHandler *errh) CLICK_COLD; int add_queue(Dir dir, unsigned &queue_id, bool promisc, unsigned n_desc, ErrorHandler *errh) CLICK_COLD; static bool alloc_pktmbufs() CLICK_COLD; static DPDKDevice* get_device(const portid_t &port_id) { return &(_devs.find_insert(port_id, DPDKDevice(port_id)).value()); } #if RTE_VERSION < RTE_VERSION_NUM(18,05,0,0) static int get_port_from_pci(uint32_t domain, uint8_t bus, uint8_t dev_id, uint8_t function) { struct rte_eth_dev_info dev_info; uint16_t count = rte_eth_dev_count(); for (portid_t port_id = 0 ; port_id < count; ++port_id) { rte_eth_dev_info_get(port_id, &dev_info); struct rte_pci_addr addr = dev_info.pci_dev->addr; if (addr.domain == domain && addr.bus == bus && addr.devid == dev_id && addr.function == function) return port_id; } return -1; } #endif friend class DPDKDeviceArg; friend class DPDKInfo; }; inline rte_mbuf* DPDKDevice::get_pkt(unsigned numa_node) { struct rte_mbuf* mbuf = rte_pktmbuf_alloc(get_mpool(numa_node)); if (unlikely(!mbuf)) { if (!DPDKDevice::no_more_buffer_msg_printed) click_chatter("No more DPDK buffer available ! Try using " "DPDKInfo to allocate more."); else DPDKDevice::no_more_buffer_msg_printed = true; } return mbuf; } inline rte_mbuf* DPDKDevice::get_pkt() { return get_pkt(rte_socket_id()); } /** @class DPDKPortArg @brief Parser class for DPDK Port, either an integer or a PCI address. */ class DPDKDeviceArg { public: static bool parse(const String &str, DPDKDevice* &result, const ArgContext &args = ArgContext()); static String unparse(DPDKDevice* dev) { return String(dev->port_id); } }; template<> struct DefaultArg : public DPDKDeviceArg {}; CLICK_ENDDECLS #endif