Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ flows:
number_of_packets: 10000

algorithm: basic
multipath-type: ECMP
simulation_time: 100000
10 changes: 5 additions & 5 deletions configuration_examples/topology_examples/bus_topology.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ devices:
type: host
bus:
type: switch
ecn:
ecn:
min: 0.2
max: 0.3
probability: 1.0
Expand Down Expand Up @@ -42,28 +42,28 @@ links:
latency: 1ns
throughput: 1Gbps
ingress_buffer_size: 4096B
egress_buffer_size: 4096B
egress_buffer_size: 4096B
link5:
from: receiver1
to: bus
latency: 1ns
throughput: 1Gbps
ingress_buffer_size: 4096B
egress_buffer_size: 4096B
egress_buffer_size: 4096B
link6:
from: bus
to: receiver1
latency: 1ns
throughput: 1Gbps
ingress_buffer_size: 4096B
egress_buffer_size: 4096B
egress_buffer_size: 4096B
link7:
from: receiver2
to: bus
latency: 1ns
throughput: 1Gbps
ingress_buffer_size: 4096B
egress_buffer_size: 4096B
egress_buffer_size: 4096B
link8:
from: bus
to: receiver2
Expand Down
5 changes: 3 additions & 2 deletions source/device/host.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

#include <spdlog/fmt/fmt.h>

#include "link/i_link.hpp"
#include "logger/logger.hpp"
#include "utils/validation.hpp"

namespace sim {

Host::Host(Id a_id) : RoutingModule(a_id) {}
Host::Host(Id a_id, std::unique_ptr<IHasher> a_hasher)
: RoutingModule(a_id, std::move(a_hasher)) {}

bool Host::notify_about_arrival(TimeNs arrival_time) {
return m_process_scheduler.notify_about_arriving(arrival_time,
Expand Down
2 changes: 1 addition & 1 deletion source/device/host.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class Host : public IHost,
public RoutingModule,
public std::enable_shared_from_this<Host> {
public:
Host(Id id);
Host(Id id, std::unique_ptr<IHasher> a_hasher = nullptr);
~Host() = default;

bool notify_about_arrival(TimeNs arrive_time) final;
Expand Down
5 changes: 3 additions & 2 deletions source/device/routing_module.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#include "utils/loop_iterator.hpp"

namespace sim {

class RoutingModule : public virtual IRoutingDevice {
public:
RoutingModule(Id a_id = "", std::unique_ptr<IHasher> a_hasher = nullptr);
Expand All @@ -16,7 +16,8 @@ class RoutingModule : public virtual IRoutingDevice {
Id get_id() const final;
bool add_inlink(std::shared_ptr<ILink> link) final;
bool add_outlink(std::shared_ptr<ILink> link) final;
bool update_routing_table(Id dest_id, std::shared_ptr<ILink> link, size_t paths_count = 1) final;
bool update_routing_table(Id dest_id, std::shared_ptr<ILink> link,
size_t paths_count = 1) final;
// returns next inlink and moves inlinks set iterator forward
std::shared_ptr<ILink> next_inlink() final;
std::shared_ptr<ILink> get_link_to_destination(Packet packet) const final;
Expand Down
8 changes: 3 additions & 5 deletions source/device/switch.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
#include "device/switch.hpp"

#include <iostream>

#include "link/i_link.hpp"
#include "logger/logger.hpp"
#include "utils/validation.hpp"

namespace sim {

Switch::Switch(Id a_id, ECN&& a_ecn)
: RoutingModule(a_id), m_ecn(std::move(a_ecn)) {}
Switch::Switch(Id a_id, ECN&& a_ecn, std::unique_ptr<IHasher> a_hasher)
: RoutingModule(a_id, std::move(a_hasher)), m_ecn(std::move(a_ecn)) {}

bool Switch::notify_about_arrival(TimeNs arrival_time) {
return m_process_scheduler.notify_about_arriving(arrival_time,
Expand Down
3 changes: 2 additions & 1 deletion source/device/switch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ class Switch : public ISwitch,
public RoutingModule,
public std::enable_shared_from_this<Switch> {
public:
Switch(Id a_id, ECN&& a_ecn = ECN(1.0, 1.0, 0.0));
Switch(Id a_id, ECN&& a_ecn = ECN(1.0, 1.0, 0.0),
std::unique_ptr<IHasher> a_hasher = nullptr);
~Switch() = default;

bool notify_about_arrival(TimeNs arrival_time) final;
Expand Down
24 changes: 21 additions & 3 deletions source/parser/identifiable_parser/identifiable_parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,18 @@
namespace sim {

template <typename T>
class Parser {
class Parser {
public:
// Parses object and return shared_ptr to it
static std::shared_ptr<T> parse_object(const YAML::Node& key_node,
const YAML::Node& value_node);

// Parses object, construct it with additional arguments and return
// shared_ptr to it
template <typename... Args>
static std::shared_ptr<T> parse_object(const YAML::Node& key_node,
const YAML::Node& value_node,
Args&&... args);
};

template <typename T>
Expand All @@ -24,7 +31,18 @@ class IdentifieableParser {
public:
static std::shared_ptr<T> parse_and_registrate(
const YAML::Node& key_node, const YAML::Node& value_node) {
std::shared_ptr<T> object = Parser<T>::parse_object(key_node, value_node);
std::shared_ptr<T> object =
Parser<T>::parse_object(key_node, value_node);
registrate(object);
return object;
}

template <typename... Args>
static std::shared_ptr<T> parse_and_registrate(const YAML::Node& key_node,
const YAML::Node& value_node,
Args&&... args) {
std::shared_ptr<T> object = Parser<T>::parse_object(
key_node, value_node, std::forward<Args>(args)...);
registrate(object);
return object;
}
Expand All @@ -40,4 +58,4 @@ class IdentifieableParser {
}
};

} // namespace sim
} // namespace sim
18 changes: 14 additions & 4 deletions source/parser/identifiable_parser/parse_host.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
#include <memory>

#include "device/host.hpp"
#include "identifiable_parser.hpp"
#include "utils/hasher.hpp"

namespace sim {

template <>
std::shared_ptr<Host> Parser<Host>::parse_object(
const YAML::Node& key_node, const YAML::Node& value_node) {
(void)value_node;
std::shared_ptr<Host> Parser<Host>::parse_object(const YAML::Node& key_node,
const YAML::Node&) {
return std::make_shared<Host>(key_node.as<Id>());
}

} // namespace sim
template <>
template <>
std::shared_ptr<Host> Parser<Host>::parse_object(
const YAML::Node& key_node, const YAML::Node&,
std::unique_ptr<IHasher>&& hasher) {
return std::make_shared<Host>(key_node.as<Id>(), std::move(hasher));
}

} // namespace sim
23 changes: 21 additions & 2 deletions source/parser/identifiable_parser/parse_switch.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include "device/ecn.hpp"
#include "device/switch.hpp"
#include "identifiable_parser.hpp"

Expand All @@ -17,6 +18,24 @@ std::shared_ptr<Switch> Parser<Switch>::parse_object(
if (ecn_node) {
return std::make_shared<Switch>(id, parse_ecn(ecn_node));
}
return std::make_shared<Switch>(id);
ECN default_ecn = ECN(1.0, 1.0, 0.0);
return std::make_shared<Switch>(id, std::move(default_ecn));
}
} // namespace sim

template <>
template <>
std::shared_ptr<Switch> Parser<Switch>::parse_object(
const YAML::Node& key_node, const YAML::Node& value_node,
std::unique_ptr<IHasher>&& hasher) {
Id id = key_node.as<Id>();
const YAML::Node& ecn_node = value_node["ecn"];
if (ecn_node) {
return std::make_shared<Switch>(id, parse_ecn(ecn_node),
std::move(hasher));
}
ECN default_ecn = ECN(1.0, 1.0, 0.0);
return std::make_shared<Switch>(id, std::move(default_ecn),
std::move(hasher));
}

} // namespace sim
27 changes: 27 additions & 0 deletions source/parser/parse_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@

#include <spdlog/fmt/fmt.h>

#include <memory>
#include <stdexcept>

#include "logger/logger.hpp"
#include "utils/hasher.hpp"

static std::pair<uint32_t, std::string> parse_value_unit(
const std::string &value_with_unit) {
const size_t unit_pos = value_with_unit.find_first_not_of("0123456789");
Expand Down Expand Up @@ -41,3 +45,26 @@ SizeByte parse_buffer_size(const std::string &buffer_size) {
}
throw std::runtime_error("Unsupported buffer size unit: " + unit);
}

std::unique_ptr<sim::IHasher> parse_hasher(const std::string &multipath_type) {
if (multipath_type == "ECMP") {
return std::make_unique<sim::BaseHasher>();
} else if (multipath_type == "RPS") {
return std::make_unique<sim::RandomHasher>();
} else {
throw std::runtime_error("Unsupported multipath type: " +
multipath_type);
}
}

uint32_t parse_with_default(
const YAML::Node &node, std::string_view field_name,
std::function<uint32_t(const std::string &)> value_parser,
uint32_t default_value) {
if (!node[field_name]) {
LOG_WARN(fmt::format("{} does not set ; use default value {}",
field_name, default_value));
return default_value;
}
return value_parser(node[field_name].as<std::string>());
}
8 changes: 8 additions & 0 deletions source/parser/parse_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,21 @@

#include "logger/logger.hpp"
#include "types.hpp"
#include "utils/hasher.hpp"

SpeedGbps parse_speed(const std::string& throughput);
TimeNs parse_latency(const std::string& latency);
SizeByte parse_buffer_size(const std::string& buffer_size);

std::unique_ptr<sim::IHasher> parse_hasher(const std::string& multipath_type);

// Parses node[field_name] using value_parser if node contains field_name;
// Returns default_value otherwise
uint32_t parse_with_default(
const YAML::Node& node, std::string_view field_name,
std::function<uint32_t(const std::string&)> value_parser,
uint32_t default_value);

template <typename T>
T parse_with_default(const YAML::Node& node, std::string_view field_name,
std::function<T(const std::string&)> value_parser,
Expand Down
25 changes: 17 additions & 8 deletions source/parser/parser.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
#include "parser/parser.hpp"

#include <memory>
#include <stdexcept>

#include "identifiable_parser/flow/parse_tcp_flow.hpp"
#include "identifiable_parser/identifiable_parser.hpp"
#include "logger/logger.hpp"
#include "parser/parse_utils.hpp"
#include "utils/hasher.hpp"

namespace sim {

Expand All @@ -18,7 +21,7 @@ std::pair<SimulatorVariant, TimeNs> YamlParser::build_simulator_from_config(
path.parent_path() / parse_topology_config_path(simulation_config);
const YAML::Node topology_config = YAML::LoadFile(m_topology_config_path);

process_devices(topology_config);
process_devices(topology_config, simulation_config);
process_links(topology_config);

process_flows(simulation_config);
Expand All @@ -33,27 +36,33 @@ TimeNs YamlParser::parse_simulation_time(const YAML::Node &config) {
return TimeNs(config["simulation_time"].as<uint32_t>());
}

void YamlParser::process_devices(const YAML::Node &config) {
if (!config["devices"]) {
void YamlParser::process_devices(const YAML::Node &topology_config,
const YAML::Node &simulation_config) {
if (!topology_config["devices"]) {
LOG_WARN("No devices specified in the topology config");
return;
}
for (auto it = config["devices"].begin(); it != config["devices"].end();
for (auto it = topology_config["devices"].begin(); it != topology_config["devices"].end();
++it) {
const YAML::Node key_node = it->first;
const YAML::Node val_node = it->second;

auto device_name = key_node.as<Id>();
auto device_type = val_node["type"].as<std::string>();

std::unique_ptr<sim::IHasher> default_hasher =
std::make_unique<sim::BaseHasher>();
auto parsed_hasher = parse_with_default<std::unique_ptr<sim::IHasher>>(
simulation_config, "multipath-type", parse_hasher, std::move(default_hasher));

if (device_type == "host") {
std::visit(
[&key_node, &val_node](auto &sim) {
[&key_node, &val_node, &parsed_hasher](auto &sim) {
using SimType = std::decay_t<decltype(sim)>;
using HostType = typename SimType::Host_T;
std::shared_ptr<HostType> ptr =
IdentifieableParser<HostType>::parse_and_registrate(
key_node, val_node);
key_node, val_node, std::move(parsed_hasher));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may move field parsed_hasher more than one time. Please, change the architecture

if (!sim.add_host(ptr)) {
throw std::runtime_error("Can not add host with id " +
ptr.get()->get_id());
Expand All @@ -62,12 +71,12 @@ void YamlParser::process_devices(const YAML::Node &config) {
m_simulator);
} else if (device_type == "switch") {
std::visit(
[&key_node, &val_node](auto &simulator) {
[&key_node, &val_node, &parsed_hasher](auto &simulator) {
using SimType = std::decay_t<decltype(simulator)>;
using SwitchType = typename SimType::Switch_T;
std::shared_ptr<SwitchType> ptr =
IdentifieableParser<SwitchType>::parse_and_registrate(
key_node, val_node);
key_node, val_node, std::move(parsed_hasher));
if (!simulator.add_switch(ptr)) {
throw std::runtime_error("Can not add switch with id " +
ptr.get()->get_id());
Expand Down
4 changes: 3 additions & 1 deletion source/parser/parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ class YamlParser {
const YAML::Node& config);
static std::string parse_algorithm(const YAML::Node& config);
static TimeNs parse_simulation_time(const YAML::Node& config);
static std::string parse_multipath_type(const YAML::Node& config);

void process_devices(const YAML::Node& config);
void process_devices(const YAML::Node& topology_config,
const YAML::Node& simulation_config);
void process_links(const YAML::Node& config);
void process_flows(const YAML::Node& config);

Expand Down