--- /dev/null
+/* Copyright (c) 2013-2021. The SimGrid Team. All rights reserved. */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef SIMGRID_KERNEL_ROUTING_STARZONE_HPP_
+#define SIMGRID_KERNEL_ROUTING_STARZONE_HPP_
+
+#include <simgrid/kernel/routing/NetZoneImpl.hpp>
+
+#include <unordered_map>
+#include <unordered_set>
+
+namespace simgrid {
+namespace kernel {
+namespace routing {
+
+/** @ingroup ROUTING_API
+ * @brief NetZone where components are connected following a star topology
+ *
+ * Star zones have a collection of private links that interconnect their components.
+ * By default, all components inside the star zone are interconnected with no links.
+ *
+ * You can use add_route to set the links to be used during communications, 3
+ * configurations are possible:
+ * - (*(all) -> Component): links used in the outgoing communications from component (UP).
+ * - (Component -> *(all)): links used in ine ingoing communication to component (DOWN).
+ * - Loopback: links connecting the component to itself.
+ *
+ * @note: Communications between nodes inside the Star zone cannot have duplicate links.
+ * All duplicated links are automatically removed when building the route.
+ *
+ * \verbatim
+ * (outer world)
+ * |
+ * l3 /|\ l4
+ * / | \ <-- links
+ * + | +
+ * l0 / l1| \l2
+ * / | \
+ * A B C <-- netpoints
+ * \endverbatim
+ *
+ * So, a communication from the host A to the host B goes through the following links:
+ * <tt>l0, l3, l1.</tt>
+ *
+ * In the same way, a communication from host A to nodes outside this netzone will
+ * use the same links <tt> l0, l3. </tt>
+ *
+ * \verbatim
+ * (outer world)
+ * |
+ * ======+====== <-- backbone
+ * | | | |
+ * l0| l1| l2| l4| <-- links
+ * | | | |
+ * A B C D <-- netpoints
+ * \endverbatim
+ *
+ * In this case, a communication from A to B goes through the links: <tt> l0, backbone, l1. </tt>
+ * Note that the backbone only appears once in the link list.
+ */
+
+class StarZone : public NetZoneImpl {
+
+public:
+ explicit StarZone(const std::string& name);
+
+ void get_local_route(NetPoint* src, NetPoint* dst, RouteCreationArgs* route, double* latency) override;
+ void get_graph(const s_xbt_graph_t* graph, std::map<std::string, xbt_node_t, std::less<>>* nodes,
+ std::map<std::string, xbt_edge_t, std::less<>>* edges) override;
+
+ void add_route(NetPoint* src, NetPoint* dst, NetPoint* gw_src, NetPoint* gw_dst,
+ const std::vector<kernel::resource::LinkImpl*>& link_list, bool symmetrical) override;
+ void do_seal() override;
+
+private:
+ /** @brief Auxiliary method to add links to a route */
+ void add_links_to_route(const std::vector<resource::LinkImpl*>& links, RouteCreationArgs* route, double* latency,
+ std::unordered_set<resource::LinkImpl*>& added_links);
+ std::unordered_map<unsigned int, std::vector<resource::LinkImpl*>> links_up_;
+ std::unordered_map<unsigned int, std::vector<resource::LinkImpl*>> loopback_;
+ std::unordered_map<unsigned int, std::vector<resource::LinkImpl*>> links_down_;
+};
+} // namespace routing
+} // namespace kernel
+} // namespace simgrid
+
+#endif /* SIMGRID_KERNEL_ROUTING_STARZONE_HPP_ */
\ No newline at end of file
--- /dev/null
+/* Copyright (c) 2009-2021. The SimGrid Team. All rights reserved. */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "simgrid/kernel/routing/StarZone.hpp"
+#include "simgrid/kernel/routing/NetPoint.hpp"
+#include "simgrid/kernel/routing/RoutedZone.hpp"
+#include "src/surf/network_interface.hpp"
+#include "src/surf/xml/platf_private.hpp" // RouteCreationArgs and friends
+
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_route_star, surf, "Routing part of surf");
+
+namespace simgrid {
+namespace kernel {
+namespace routing {
+StarZone::StarZone(const std::string& name) : NetZoneImpl(name) {}
+
+void StarZone::add_links_to_route(const std::vector<resource::LinkImpl*>& links, RouteCreationArgs* route,
+ double* latency, std::unordered_set<resource::LinkImpl*>& added_links)
+{
+ for (auto* link : links) {
+ /* do not add duplicated links */
+ if (added_links.find(link) != added_links.end())
+ continue;
+ added_links.insert(link);
+ if (latency)
+ *latency += link->get_latency();
+ route->link_list.push_back(link);
+ }
+}
+
+void StarZone::get_local_route(NetPoint* src, NetPoint* dst, RouteCreationArgs* route, double* latency)
+{
+ XBT_VERB("StarZone getLocalRoute from '%s'[%u] to '%s'[%u]", src->get_cname(), src->id(), dst->get_cname(),
+ dst->id());
+
+ xbt_assert(((src == dst) and (loopback_.find(src->id()) != loopback_.end())) or
+ (links_up_.find(src->id()) != links_up_.end()),
+ "StarZone routing (%s - %s): no link UP from source node. Did you use add_route() to set it?",
+ src->get_cname(), dst->get_cname());
+ xbt_assert(((src == dst) and (loopback_.find(dst->id()) != loopback_.end())) or
+ (links_down_.find(dst->id()) != links_down_.end()),
+ "StarZone routing (%s - %s): no link DOWN to destination node. Did you use add_route() to set it?",
+ src->get_cname(), dst->get_cname());
+
+ std::unordered_set<resource::LinkImpl*> added_links;
+ /* loopback */
+ if ((src == dst) and (loopback_.find(src->id()) != loopback_.end())) {
+ add_links_to_route(loopback_[src->id()], route, latency, added_links);
+ return;
+ }
+
+ /* going UP */
+ add_links_to_route(links_up_[src->id()], route, latency, added_links);
+
+ /* going DOWN */
+ add_links_to_route(links_down_[dst->id()], route, latency, added_links);
+}
+
+void StarZone::get_graph(const s_xbt_graph_t* graph, std::map<std::string, xbt_node_t, std::less<>>* nodes,
+ std::map<std::string, xbt_edge_t, std::less<>>* edges)
+{
+}
+
+void StarZone::add_route(NetPoint* src, NetPoint* dst, NetPoint* gw_src, NetPoint* gw_dst,
+ const std::vector<kernel::resource::LinkImpl*>& link_list, bool symmetrical)
+{
+ const char* src_name = src ? src->get_cname() : "nullptr";
+ const char* dst_name = dst ? dst->get_cname() : "nullptr";
+
+ xbt_assert((src == dst) or (not src and dst) or (src and not dst),
+ "Cannot add route from %s to %s. In a StarZone, route must be: i) from source host to everyone, ii) from "
+ "everyone to a single host or iii) loopback, same source and destination",
+ src_name, dst_name);
+ xbt_assert((not symmetrical) or (symmetrical and src),
+ "Cannot add route from %s to %s. In a StarZone, symmetrical routes must be set from source to everyone "
+ "(not the contrary).",
+ src_name, dst_name);
+
+ /* loopback */
+ if (src == dst) {
+ loopback_[src->id()] = link_list;
+ } else {
+ /* src to everyone */
+ if (src) {
+ links_up_[src->id()] = link_list;
+ if (symmetrical) {
+ links_down_[src->id()] = link_list;
+ /* reverse it for down/symmetrical links */
+ std::reverse(links_down_[src->id()].begin(), links_down_[src->id()].end());
+ }
+ }
+ /* dst to everyone */
+ if (dst) {
+ links_down_[dst->id()] = link_list;
+ }
+ }
+ s4u::NetZone::on_route_creation(symmetrical, gw_src, gw_dst, gw_src, gw_dst, link_list);
+}
+
+void StarZone::do_seal()
+{
+ /* add default empty links if nothing was configured by user */
+ for (auto const& node : get_vertices()) {
+ if ((links_up_.find(node->id()) == links_up_.end()) and (links_down_.find(node->id()) == links_down_.end())) {
+ links_down_[node->id()] = {};
+ links_up_[node->id()] = {};
+ }
+ }
+}
+
+} // namespace routing
+} // namespace kernel
+
+namespace s4u {
+NetZone* create_star_zone(const std::string& name)
+{
+ return (new kernel::routing::StarZone(name))->get_iface();
+}
+} // namespace s4u
+
+} // namespace simgrid
--- /dev/null
+/* Copyright (c) 2017-2021. The SimGrid Team. All rights reserved. */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "catch.hpp"
+
+#include "simgrid/kernel/routing/NetPoint.hpp"
+#include "simgrid/kernel/routing/StarZone.hpp"
+#include "simgrid/s4u/Engine.hpp"
+#include "simgrid/s4u/Host.hpp"
+#include "simgrid/s4u/NetZone.hpp"
+#include "src/surf/network_interface.hpp"
+#include "src/surf/surf_interface.hpp" // create models
+#include "src/surf/xml/platf_private.hpp" // RouteCreationArgs and friends
+
+TEST_CASE("kernel::routing::StarZone: Creating Zone", "[creation]")
+{
+ int argc = 1;
+ const char* argv[] = {"test"};
+
+ simgrid::s4u::Engine e(&argc, const_cast<char**>(argv));
+
+ REQUIRE(simgrid::s4u::create_star_zone("test"));
+}
+
+// One day we may be able to test contracts and asserts with catch2
+// https://github.com/catchorg/Catch2/issues/853
+TEST_CASE("kernel::routing::StarZone: Adding routes: assert", "[.][assert]")
+{
+ int argc = 1;
+ const char* argv[] = {"test"};
+ simgrid::s4u::Engine e(&argc, const_cast<char**>(argv));
+ auto* zone = new simgrid::kernel::routing::StarZone("test");
+ auto* netpoint1 = new simgrid::kernel::routing::NetPoint("netpoint1", simgrid::kernel::routing::NetPoint::Type::Host);
+ auto* netpoint2 = new simgrid::kernel::routing::NetPoint("netpoint2", simgrid::kernel::routing::NetPoint::Type::Host);
+
+ SECTION("Source and destination hosts: nullptr") { zone->add_route(nullptr, nullptr, nullptr, nullptr, {}, false); }
+
+ SECTION("Source nullptr and symmetrical true") { zone->add_route(nullptr, netpoint2, nullptr, nullptr, {}, true); }
+
+ SECTION("Source and destination set") { zone->add_route(netpoint1, netpoint2, nullptr, nullptr, {}, false); }
+}
+
+TEST_CASE("kernel::routing::StarZone: Get routes: assert", "[.][assert]")
+{
+ /* workaround to initialize things, they must be done in this particular order */
+ int argc = 1;
+ const char* argv[] = {"test"};
+ simgrid::s4u::Engine e(&argc, const_cast<char**>(argv));
+ auto* zone = new simgrid::kernel::routing::StarZone("test");
+ surf_network_model_init_LegrandVelho();
+ surf_cpu_model_init_Cas01();
+
+ auto* host1 = zone->create_host("netpoint1", {100});
+ auto* host2 = zone->create_host("netpoint2", {100});
+ std::vector<simgrid::kernel::resource::LinkImpl*> links;
+ links.push_back(zone->create_link("link1", {100})->get_impl());
+ std::vector<simgrid::kernel::resource::LinkImpl*> links2;
+ links2.push_back(zone->create_link("link2", {100})->get_impl());
+
+ SECTION("Get route: no UP link")
+ {
+ zone->add_route(host1->get_netpoint(), nullptr, nullptr, nullptr, links, true);
+ zone->add_route(nullptr, host2->get_netpoint(), nullptr, nullptr, links2, false);
+ double lat;
+ simgrid::kernel::routing::RouteCreationArgs route;
+ zone->get_local_route(host2->get_netpoint(), host1->get_netpoint(), &route, &lat);
+ }
+
+ SECTION("Get route: no DOWN link")
+ {
+ zone->add_route(host1->get_netpoint(), nullptr, nullptr, nullptr, links, false);
+ zone->add_route(host2->get_netpoint(), nullptr, nullptr, nullptr, links2, true);
+ double lat;
+ simgrid::kernel::routing::RouteCreationArgs route;
+ zone->get_local_route(host2->get_netpoint(), host1->get_netpoint(), &route, &lat);
+ }
+}
+
+TEST_CASE("kernel::routing::StarZone: Adding routes: valid", "")
+{
+ int argc = 1;
+ const char* argv[] = {"test"};
+ simgrid::s4u::Engine e(&argc, const_cast<char**>(argv));
+ auto* zone = new simgrid::kernel::routing::StarZone("test");
+ auto* netpoint = new simgrid::kernel::routing::NetPoint("netpoint1", simgrid::kernel::routing::NetPoint::Type::Host);
+
+ SECTION("Source set, destination nullptr, symmetrical true")
+ {
+ zone->add_route(netpoint, nullptr, nullptr, nullptr, {}, true);
+ }
+
+ SECTION("Source nullptr, destination set, symmetrical false")
+ {
+ zone->add_route(nullptr, netpoint, nullptr, nullptr, {}, false);
+ }
+
+ SECTION("Source set, destination nullptr, symmetrical false")
+ {
+ zone->add_route(netpoint, nullptr, nullptr, nullptr, {}, false);
+ }
+
+ SECTION("Source == destination") { zone->add_route(netpoint, netpoint, nullptr, nullptr, {}, false); }
+}
+
+TEST_CASE("kernel::routing::StarZone: Get routes", "")
+{
+ /* workaround to initialize things, they must be done in this particular order */
+ int argc = 1;
+ const char* argv[] = {"test"};
+ simgrid::s4u::Engine e(&argc, const_cast<char**>(argv));
+ auto* zone = new simgrid::kernel::routing::StarZone("test");
+ surf_network_model_init_LegrandVelho();
+ surf_cpu_model_init_Cas01();
+
+ auto* host1 = zone->create_host("netpoint1", {100});
+ auto* host2 = zone->create_host("netpoint2", {100});
+
+ SECTION("Get route: no shared link")
+ {
+ std::vector<simgrid::kernel::resource::LinkImpl*> links;
+ links.push_back(zone->create_link("link1", {100})->set_latency(10)->get_impl());
+ std::vector<simgrid::kernel::resource::LinkImpl*> links2;
+ links2.push_back(zone->create_link("link2", {200})->set_latency(20)->get_impl());
+ zone->add_route(host1->get_netpoint(), nullptr, nullptr, nullptr, links, true);
+ zone->add_route(host2->get_netpoint(), nullptr, nullptr, nullptr, links2, true);
+ zone->seal();
+
+ double lat = 0.0;
+ simgrid::kernel::routing::RouteCreationArgs route;
+ zone->get_local_route(host1->get_netpoint(), host2->get_netpoint(), &route, &lat);
+ REQUIRE(lat == 30);
+ REQUIRE(route.link_list.size() == 2);
+ REQUIRE(route.link_list[0]->get_name() == "link1");
+ REQUIRE(route.link_list[1]->get_name() == "link2");
+ }
+
+ SECTION("Get route: shared link(backbone)")
+ {
+ auto* backbone = zone->create_link("backbone", {1000})->set_latency(100)->get_impl();
+ std::vector<simgrid::kernel::resource::LinkImpl*> links;
+ links.push_back(zone->create_link("link1", {100})->set_latency(10)->get_impl());
+ links.push_back(backbone);
+ std::vector<simgrid::kernel::resource::LinkImpl*> links2;
+ links2.push_back(zone->create_link("link2", {200})->set_latency(20)->get_impl());
+ links2.push_back(backbone);
+
+ zone->add_route(host1->get_netpoint(), nullptr, nullptr, nullptr, links, true);
+ zone->add_route(host2->get_netpoint(), nullptr, nullptr, nullptr, links2, true);
+ zone->seal();
+
+ double lat = 0.0;
+ simgrid::kernel::routing::RouteCreationArgs route;
+ zone->get_local_route(host1->get_netpoint(), host2->get_netpoint(), &route, &lat);
+ REQUIRE(lat == 130);
+ REQUIRE(route.link_list.size() == 3);
+ REQUIRE(route.link_list[0]->get_name() == "link1");
+ REQUIRE(route.link_list[1]->get_name() == "backbone");
+ REQUIRE(route.link_list[2]->get_name() == "link2");
+ }
+
+ SECTION("Get route: shared link(backbone)")
+ {
+ auto* backbone = zone->create_link("backbone", {1000})->set_latency(100)->get_impl();
+ std::vector<simgrid::kernel::resource::LinkImpl*> links;
+ links.push_back(zone->create_link("link1", {100})->set_latency(10)->get_impl());
+ links.push_back(backbone);
+ std::vector<simgrid::kernel::resource::LinkImpl*> links2;
+ links2.push_back(zone->create_link("link2", {200})->set_latency(20)->get_impl());
+ links2.push_back(backbone);
+
+ zone->add_route(host1->get_netpoint(), nullptr, nullptr, nullptr, links, true);
+ zone->add_route(host2->get_netpoint(), nullptr, nullptr, nullptr, links2, true);
+ zone->seal();
+
+ double lat = 0.0;
+ simgrid::kernel::routing::RouteCreationArgs route;
+ zone->get_local_route(host1->get_netpoint(), host2->get_netpoint(), &route, &lat);
+ REQUIRE(lat == 130);
+ REQUIRE(route.link_list.size() == 3);
+ REQUIRE(route.link_list[0]->get_name() == "link1");
+ REQUIRE(route.link_list[1]->get_name() == "backbone");
+ REQUIRE(route.link_list[2]->get_name() == "link2");
+ }
+
+ SECTION("Get route: loopback")
+ {
+ auto* backbone = zone->create_link("backbone", {1000})->set_latency(100)->get_impl();
+ std::vector<simgrid::kernel::resource::LinkImpl*> links;
+ links.push_back(zone->create_link("link1", {100})->set_latency(10)->get_impl());
+ links.push_back(backbone);
+
+ zone->add_route(host1->get_netpoint(), host1->get_netpoint(), nullptr, nullptr, links, true);
+ zone->seal();
+
+ double lat = 0.0;
+ simgrid::kernel::routing::RouteCreationArgs route;
+ zone->get_local_route(host1->get_netpoint(), host1->get_netpoint(), &route, &lat);
+ REQUIRE(lat == 110);
+ REQUIRE(route.link_list.size() == 2);
+ REQUIRE(route.link_list[0]->get_name() == "link1");
+ REQUIRE(route.link_list[1]->get_name() == "backbone");
+ }
+}
\ No newline at end of file