diff --git a/src/include/pmd.h b/src/include/pmd.h index 76f08906..0b8dc9b4 100644 --- a/src/include/pmd.h +++ b/src/include/pmd.h @@ -15,6 +15,7 @@ #include "ether.h" #include "packet.h" #include "packet_pool.h" +#include "utils.h" namespace juggler { namespace dpdk { @@ -58,14 +59,20 @@ class PmdRing { port_id_(port_id), ring_id_(ring_id), ndesc_(ndesc), - ppool_(nullptr) {} + ppool_(nullptr), + machnet_testing_(std::getenv("MACHNET_TESTING_ENABLED") != nullptr && + std::string(std::getenv("MACHNET_TESTING_ENABLED")) == + "1") {} PmdRing(const PmdPort *port, uint8_t port_id, uint16_t ring_id, uint16_t ndesc, uint32_t nmbufs, uint32_t mbuf_sz) : pmd_port_(port), port_id_(port_id), ring_id_(ring_id), ndesc_(ndesc), - ppool_(std::unique_ptr(new PacketPool(nmbufs, mbuf_sz))) {} + ppool_(std::unique_ptr(new PacketPool(nmbufs, mbuf_sz))), + machnet_testing_(std::getenv("MACHNET_TESTING_ENABLED") != nullptr && + std::string(std::getenv("MACHNET_TESTING_ENABLED")) == + "1") {} rte_mempool *GetPacketMemPool() const { return ppool_.get()->GetMemPool(); } @@ -75,6 +82,10 @@ class PmdRing { const uint16_t ring_id_; const uint16_t ndesc_; const std::unique_ptr ppool_; + + public: + const bool machnet_testing_; + juggler::utils::FastRand fast_rand_; }; /* @@ -103,6 +114,25 @@ class TxRing : public PmdRing { void Init(); + /// @brief Drops a random packet from the given array of packets. + /// @param pkts Array of packet pointers. + /// @param nb_pkts Number of packets in the array. + inline void pkt_idx_to_drop(Packet **pkts, uint16_t *nb_pkts) { + static constexpr uint32_t kBillion = 1000000000; + // the value below is picked randomly as probability. + static constexpr float kDropProb = 0.000001; + if (fast_rand_.next_u32() % kBillion < kDropProb * kBillion) { + int random_packet = fast_rand_.next_u32() % *nb_pkts; + LOG(INFO) << "Dropping random packet: " << random_packet << " from " + << *nb_pkts << " packets."; + Packet::Free(pkts[random_packet]); + for (int i = random_packet; i < *nb_pkts - 1; i++) { + pkts[i] = pkts[i + 1]; + } + *nb_pkts = *nb_pkts - 1; + } + } + /** * @brief Tries to send a burst of packets through this TX ring. * @@ -138,7 +168,11 @@ class TxRing : public PmdRing { * @param pkts Array of packet pointers to send. * @param nb_pkts Number of packets to send. */ - void SendPackets(Packet **pkts, uint16_t nb_pkts) const { + void SendPackets(Packet **pkts, uint16_t nb_pkts) { + if (machnet_testing_) { + pkt_idx_to_drop(pkts, &nb_pkts); + } + uint16_t nb_remaining = nb_pkts; do { @@ -156,7 +190,7 @@ class TxRing : public PmdRing { * * @param batch Pointer to the PacketBatch. */ - void SendPackets(PacketBatch *batch) const { + void SendPackets(PacketBatch *batch) { SendPackets(batch->pkts(), batch->GetSize()); batch->Clear(); } diff --git a/src/include/utils.h b/src/include/utils.h index 40e66d74..eb8d684f 100644 --- a/src/include/utils.h +++ b/src/include/utils.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -466,6 +467,34 @@ class ChronoTimer { std::chrono::time_point start_time_; }; +// Derived from eRPC +class SlowRand { + std::random_device rand_dev_; // Non-pseudorandom seed for twister + std::mt19937_64 mt_; + std::uniform_int_distribution dist_; + + public: + SlowRand() : mt_(rand_dev_()), dist_(0, UINT64_MAX) {} + + inline uint64_t next_u64() { return dist_(mt_); } +}; + +class FastRand { + public: + uint64_t seed_; + + /// Create a FastRand using a seed from SlowRand + FastRand() { + SlowRand slow_rand; + seed_ = slow_rand.next_u64(); + } + + inline uint32_t next_u32() { + seed_ = seed_ * 1103515245 + 12345; + return static_cast(seed_ >> 32); + } +}; + } // namespace utils } // namespace juggler