Skip to content

Commit

Permalink
Nethuns Traffic Generator added.
Browse files Browse the repository at this point in the history
  • Loading branch information
awgn committed Jan 1, 2024
1 parent 4b9d570 commit 9085166
Show file tree
Hide file tree
Showing 11 changed files with 963 additions and 0 deletions.
28 changes: 28 additions & 0 deletions tools/nethuns-gen/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Copyright 2021 Larthia, University of Pisa. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.

cmake_minimum_required(VERSION 3.10)

project (nethuns-gen)

include(/usr/local/share/nethuns/Nethuns.cmake)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing -fomit-frame-pointer -fno-stack-protector -Wall -Wextra -Wno-unused-local-typedef -std=c++20 -pipe")

#
# Compiler options...
#

include_directories(${NETHUNS_INCLUDE_DIRS} . ../src)

link_directories(/usr/local/lib)

add_executable(nethuns-gen src/main.cpp
src/options.cpp
src/generator.cpp
src/packets.cpp)

target_link_libraries(nethuns-gen ${NETHUNS_LIBRARY_DIRS} -pthread)
62 changes: 62 additions & 0 deletions tools/nethuns-gen/hdr/affinity.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#pragma once

#include <pthread.h>
#include <sched.h>

#ifdef __APPLE__
#include <sys/types.h> // this header cannot be included in C++ apps
#include <sys/sysctl.h>
#include <mach/mach_init.h>
#include <mach/thread_act.h>
#endif

#include <stdexcept>

namespace this_thread {

#if defined (__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
static inline void
affinity(int core)
{
cpu_set_t cpuset;
CPU_ZERO(&cpuset); CPU_SET(core, &cpuset);

pthread_t pth = pthread_self();
if ( ::pthread_setaffinity_np(pth, sizeof(cpuset), &cpuset) != 0)
throw std::runtime_error("this_thread::affinity: pthread_setaffinity_np error on core " + std::to_string(core));
}

#elif defined(__APPLE__)

[[maybe_unused]] static inline void
affinity(int core)
{
thread_port_t mach_thread;
thread_affinity_policy_data_t policy = { core };
mach_thread = pthread_mach_thread_np(pthread_self());
if (thread_policy_set(mach_thread, THREAD_AFFINITY_POLICY, (thread_policy_t)&policy, 1) != 0)
throw std::runtime_error("this_thread::affinity: thread_policy_set");

policy.affinity_tag = -1;

mach_msg_type_number_t policy_count = THREAD_AFFINITY_POLICY_COUNT;
boolean_t get_default = false;

if (thread_policy_get(mach_thread, THREAD_AFFINITY_POLICY, (thread_policy_t)&policy, &policy_count, &get_default) != 0)
throw std::runtime_error("this_thread::affinity: thread_policy_get");

if (static_cast<int>(policy.affinity_tag) != core)
throw std::runtime_error("this_thread::affinity: couldn't set thread affinity");
}

#else

static inline void
affinity(int core)
{
throw std::runtime_error("this_thread::affinity: not supported on this platform");
}

#endif

}
64 changes: 64 additions & 0 deletions tools/nethuns-gen/hdr/generator.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#pragma once

#include <nethuns/nethuns.h>

#include <cstddef>
#include <string>
#include <limits>
#include <vector>
#include <filesystem>
#include <optional>
#include <atomic>

#include "hdr/netaddr.hpp"

struct generator
{
std::string source;
std::string dev;
std::optional<int> cpu = std::nullopt;

int amp = 1;
int speed = 1;

std::size_t max_packets = std::numeric_limits<size_t>::max();
std::size_t pkt_rate = std::numeric_limits<size_t>::max();
std::size_t loops = std::numeric_limits<size_t>::max();
std::optional<uint16_t> pktlen = std::nullopt;

std::optional<netaddr> randomize_src_ip = std::nullopt;
std::optional<netaddr> randomize_dst_ip = std::nullopt;
std::vector<netaddr> randomize_prefix;

std::string mac_source;
std::string mac_dest;

bool mac_consistency = false;
bool fix_checksums = false;
bool verbose = false;

bool is_pcap_file() const {
std::filesystem::path p(source);
return p.extension() == ".pcap" || p.extension() == ".pcapng";
}

bool has_rate_limiter() const {
return pkt_rate != std::numeric_limits<size_t>::max();
}

bool has_speed_control() const {
return speed > 0;
}

bool has_randomizer() const {
return randomize_src_ip || randomize_dst_ip || !randomize_prefix.empty();
}
};

struct generator_stats
{
std::atomic_size_t packets = 0;
std::atomic_size_t bytes = 0;
std::atomic_size_t errors = 0;
std::atomic_size_t discarded = 0;
};
38 changes: 38 additions & 0 deletions tools/nethuns-gen/hdr/netaddr.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#pragma once

#include <nethuns/nethuns.h>

#include <string>

struct netaddr
{
uint32_t addr;
uint32_t mask;

netaddr()
: addr(0)
, mask(0)
{}

netaddr(const char *str) {
auto pos = std::string{str}.find('/');
if (pos == std::string::npos) {
throw std::runtime_error("invalid prefix");
}
auto addr_str = std::string{str}.substr(0, pos);
auto prefix_str = std::string{str}.substr(pos + 1);

addr = inet_addr(addr_str.c_str());
mask = htonl(~((1ul << (32 - std::stoi(prefix_str))) - 1));
}

auto to_string() const -> std::string {
char addr_buf[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &addr, addr_buf, INET_ADDRSTRLEN);

char mask_buf[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &mask, mask_buf, INET_ADDRSTRLEN);

return std::string{addr_buf} + "/" + std::string{mask_buf};
}
};
25 changes: 25 additions & 0 deletions tools/nethuns-gen/hdr/options.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once
#include <vector>

#include "hdr/generator.hpp"

struct options {
std::vector<generator> generators;
};

constexpr unsigned int bitfield(bool first) {
return (first ? 1u : 0u);
}

template <typename ...Bools>
constexpr unsigned int bitfield(bool first, Bools... rest) {
return (first ? 1u : 0u) | bitfield(rest...) << 1;
}

void validate_options(const options& opt);

options
parse_opt(int argc, char **argv);

int
run(const options& opt);
55 changes: 55 additions & 0 deletions tools/nethuns-gen/hdr/packet.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#pragma once

#include <memory>
#include <cstdint>
#include <string>
#include <optional>
#include <map>

struct packet
{
std::shared_ptr<uint8_t[]> data_;
std::size_t len_;

template <std::size_t N>
static inline auto from_hex_stream(const char (&str)[N]) -> packet {
auto pkt = std::make_shared<uint8_t[]>(N/2);
for (std::size_t i = 0; i < N/2; ++i) {
pkt[i] = std::stoi(std::string(str + i*2, 2), nullptr, 16);
}
return { .data_ = pkt, .len_ = N/2 };
}

template <std::size_t N>
static inline auto from_c_string(const char (&str)[N]) -> packet {
auto pkt = std::make_shared<uint8_t[]>(N);
memcpy(pkt.get(), str, N);
return { .data_ = pkt, .len_ = N };
}

static auto builder(const std::string &name, std::optional<uint16_t> len) -> packet
{
auto it = catalog_.find(name);
if (it == catalog_.end()) {
throw std::runtime_error("packet '" + name + "'not found!");
}

return it->second(len);
}

void resize(uint16_t size) {
if (size < len_) {
len_ = size;
} else {
auto new_data = std::make_shared<uint8_t[]>(size);
memcpy(new_data.get(), data_.get(), len_);
bzero(new_data.get() + len_, size - len_);
data_ = new_data;
len_ = size;
}
}

private:
static std::map<std::string, std::function<packet(std::optional<uint16_t>)>> catalog_;

};
30 changes: 30 additions & 0 deletions tools/nethuns-gen/hdr/rate_limiter.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#pragma once
#include <chrono>

template <int MAX_PERIOD = 16>
struct rate_limiter
{
int period_ = 0;

template <typename TimePoint>
auto wait(TimePoint deadline, size_t pktnum) -> void
{
if ((pktnum & ((1 << period_) - 1)) == 0) {
auto spinning = false;
while (std::chrono::steady_clock::now() < deadline)
{
spinning = true;
}

if (spinning) {
if (period_ > 0) {
--period_;
}
} else {
if (period_ < MAX_PERIOD) {
++period_;
}
}
}
}
};
Loading

0 comments on commit 9085166

Please sign in to comment.