diff --git a/elements/analysis/recordtimestamp.cc b/elements/analysis/recordtimestamp.cc index 02f3e8692a4b5b2f49ac0af96f1963a166fc80ca..83c8dd6a5c0aee11492b1f6ee26549289e2ef193 100644 --- a/elements/analysis/recordtimestamp.cc +++ b/elements/analysis/recordtimestamp.cc @@ -22,6 +22,11 @@ #include <click/args.hh> #include <click/error.hh> +#include <click/hashtable.hh> + +#if HAVE_DPDK +#include "../elements/userlevel/todpdkdevice.hh" +#endif CLICK_DECLS @@ -32,13 +37,43 @@ RecordTimestamp::RecordTimestamp() : RecordTimestamp::~RecordTimestamp() { } + +inline uint16_t +RecordTimestamp::calc_latency(uint16_t port __rte_unused, uint16_t qidx, + struct rte_mbuf **pkts, uint16_t nb_pkts, void *ptr) +{ + RecordTimestamp* rt = ((RecordTimestamp*)ptr); + for (unsigned i = 0; i < nb_pkts; i++) { + + unsigned char *data = rte_pktmbuf_mtod(pkts[i], unsigned char *); + uint64_t n = (*(reinterpret_cast<const uint64_t *>(data + rt->_offset))); + if (rt->_sample > 1) { + if (n % rt->_sample == 0) + n = n / rt->_sample; + else + continue; + } + + //click_chatter("Record qidx%d %p{element} -> %d",qidx, rt, n); + rt->_timestamps[n] = TimestampT::now_steady(); + } + return nb_pkts; + +} + int RecordTimestamp::configure(Vector<String> &conf, ErrorHandler *errh) { uint32_t n = 0; Element *e = NULL; +#if HAVE_DPDK + ToDPDKDevice* _tx_dev; + int _tx_dev_id = 0; +#endif if (Args(conf, this, errh) .read("COUNTER", e) .read("N", n) - .read("OFFSET", _offset) + .read("TXDEV", ElementCastArg("ToDPDKDevice"), _tx_dev) + .read("TXDEV_QID", _tx_dev_id) + .read_or_set("OFFSET", _offset, -1) .read_or_set("DYNAMIC", _dynamic, false) .read_or_set("NET_ORDER", _net_order, false) .read_or_set("SAMPLE", _sample, false) @@ -56,6 +91,26 @@ int RecordTimestamp::configure(Vector<String> &conf, ErrorHandler *errh) { if (_np) { _net_order = _np->has_net_order(); } +#if HAVE_DPDK + if (_tx_dev) { + if (_dynamic || _offset < 0) + return errh->error("TXDEV is only compatible with OFFSET given and non-dynamic mode"); + + if (_net_order) + return errh->error("TXDEV is only compatible with non-net order"); + + _timestamps.resize(_timestamps.size() == 0? _timestamps.capacity():_timestamps.size() * 2, Timestamp::uninitialized_t()); + DPDKDevice::all_initialized.post(new Router::FctFuture([this,_tx_dev,_tx_dev_id](ErrorHandler* errh) { + if (rte_eth_add_tx_callback(_tx_dev->port_id(), _tx_dev_id, calc_latency, this) == 0) { + return errh->error("Port %d/%d Callback could not be set %d: %s", _tx_dev->port_id(), _tx_dev_id, rte_errno, rte_strerror(rte_errno)); + } + return 0; + },this)); + } else +#endif + + if (ninputs() != 1 or noutputs() !=1) + return errh->error("You need to pass either TXDEV or use the element in path."); return 0; } @@ -71,8 +126,7 @@ RecordTimestamp::rmaction(Packet *p) { else return; } - assert(i < ULLONG_MAX); - while (i >= (unsigned)_timestamps.size()) { + while (unlikely(i >= (unsigned)_timestamps.size())) { if (!_dynamic && i >= (unsigned)_timestamps.capacity()) { click_chatter("Fatal error: DYNAMIC is not set and record timestamp reserved capacity is too small. Use N to augment the capacity."); assert(false); @@ -99,6 +153,8 @@ void RecordTimestamp::push_batch(int, PacketBatch *batch) { } #endif + CLICK_ENDDECLS + ELEMENT_REQUIRES(userlevel) EXPORT_ELEMENT(RecordTimestamp) diff --git a/elements/analysis/recordtimestamp.hh b/elements/analysis/recordtimestamp.hh index 1f2b2d37fe233ad581637e844bef35eaac5896c3..fecc632a96206248294cc72c6573479fa2c17f93 100644 --- a/elements/analysis/recordtimestamp.hh +++ b/elements/analysis/recordtimestamp.hh @@ -5,10 +5,15 @@ #include <click/batchelement.hh> #include <click/timestamp.hh> #include <click/tsctimestamp.hh> +#include <click/hashtable.hh> #include "numberpacket.hh" CLICK_DECLS +#if HAVE_DPDK +struct rte_mbuf; +class ToDPDKDevice; +#endif class NumberPacket; #define TimestampT TSCTimestamp #define TimestampUnread TSCTimestamp(1) @@ -70,7 +75,7 @@ public: ~RecordTimestamp() CLICK_COLD; const char *class_name() const override { return "RecordTimestamp"; } - const char *port_count() const override { return PORTS_1_1; } + const char *port_count() const override { return "0-1/="; } const char *processing() const override { return PUSH; } const char *flow_code() const override { return "x/x"; } @@ -93,11 +98,16 @@ public: NumberPacket::read_number_of_packet(p, offset, net_order); } +#if HAVE_DPDK + inline static uint16_t calc_latency(uint16_t port, uint16_t qidx, + struct rte_mbuf **pkts, uint16_t nb_pkts, void *ptr); +#endif private: int _offset; bool _dynamic; bool _net_order; uint32_t _sample; + ToDPDKDevice* _tx_dev; Vector<TimestampT> _timestamps; NumberPacket *_np; }; diff --git a/elements/userlevel/todpdkdevice.hh b/elements/userlevel/todpdkdevice.hh index 7cf7ec58371b15da5301656c11e4505cd79a3aa9..7fd4452aeb21f3c3f89fbb5011f57e07c57fa56d 100644 --- a/elements/userlevel/todpdkdevice.hh +++ b/elements/userlevel/todpdkdevice.hh @@ -149,6 +149,10 @@ public: #endif void push(int port, Packet *p); + + uint16_t port_id() { + return _dev->port_id; + } protected: inline void warn_congestion(); diff --git a/include/click/dpdkdevice.hh b/include/click/dpdkdevice.hh index fb968c3bece1b2773f8f92bf92a7b68caeaf47ca..80bae930478d40e8d7419cc56aed0e674d4e2d3c 100644 --- a/include/click/dpdkdevice.hh +++ b/include/click/dpdkdevice.hh @@ -37,6 +37,7 @@ #include <click/args.hh> #include <click/etheraddress.hh> #include <click/timer.hh> +#include <click/router.hh> #if RTE_VERSION < RTE_VERSION_NUM(19,8,0,0) #define rte_ipv4_hdr ipv4_hdr @@ -232,6 +233,8 @@ public: static int get_port_numa_node(portid_t port_id); + static Router::ChildrenFuture all_initialized; + #if HAVE_FLOW_API int set_mode( String mode, int num_pools, Vector<int> vf_vlan, diff --git a/lib/dpdkdevice.cc b/lib/dpdkdevice.cc index b2411e191133e88148edfee5feb92d4efba83bf0..dc3ed6931f729025ea7beff1b1d6e78c4a05a0b6 100644 --- a/lib/dpdkdevice.cc +++ b/lib/dpdkdevice.cc @@ -1283,7 +1283,7 @@ int DPDKDevice::initialize(ErrorHandler *errh) } } #endif - + all_initialized.solve_initialize(errh); return 0; } @@ -1579,6 +1579,7 @@ HashTable<portid_t, DPDKDevice*> DPDKDevice::_devs; struct rte_mempool** DPDKDevice::_pktmbuf_pools = 0; unsigned DPDKDevice::_nr_pktmbuf_pools = 0; bool DPDKDevice::no_more_buffer_msg_printed = false; +Router::ChildrenFuture DPDKDevice::all_initialized; CLICK_ENDDECLS