Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Split-Duplex: new management
authorBruno Donassolo <bruno.donassolo@inria.fr>
Fri, 18 Jun 2021 13:11:57 +0000 (15:11 +0200)
committerBruno Donassolo <bruno.donassolo@inria.fr>
Mon, 28 Jun 2021 15:47:14 +0000 (17:47 +0200)
1. Huge commit to add support to Split-Duplex in S4U.
  - New interface: s4u::SplitDuplexLink

2. Allows its creation through the C++ interface without manually creating
the link UP and DOWN.
  - NetZone::create_split_duplex_link

3. Changes in NetZone::add_route to allow the description of the
direction in C++ interface
  - LinkInRoute: wrap around Link* to indicate the direction
(UP/DOWN/NONE) for the link.
  - UP/DOWN are used to split-duplex links
  - NONE for other types (shared, wifi, fat-pipe)

4. Fix use of split-duplex links in symmetric routes in XML too.
     <route src="alice" dst="bob" symmetrical="YES">
       <link_ctn id="link1" direction="UP"/>
     </route>
  Now this code works, it will add the link1_DOWN as route to
bob->alice. In the past, it would add link1_UP for bob->alice too.

59 files changed:
MANIFEST.in
docs/source/Platform_cpp.rst
examples/cpp/clusters-multicpu/s4u-clusters-multicpu.cpp
examples/cpp/comm-serialize/s4u-comm-serialize.cpp
examples/cpp/network-factors/s4u-network-factors.cpp
examples/cpp/plugin-prodcons/s4u-plugin-prodcons.cpp
examples/platforms/griffon.cpp
examples/platforms/routing_cluster.cpp
include/simgrid/forward.h
include/simgrid/kernel/routing/DijkstraZone.hpp
include/simgrid/kernel/routing/FloydZone.hpp
include/simgrid/kernel/routing/FullZone.hpp
include/simgrid/kernel/routing/NetZoneImpl.hpp
include/simgrid/kernel/routing/RoutedZone.hpp
include/simgrid/kernel/routing/StarZone.hpp
include/simgrid/s4u/Engine.hpp
include/simgrid/s4u/Link.hpp
include/simgrid/s4u/NetZone.hpp
src/bindings/lua/lua_platf.cpp
src/kernel/EngineImpl.cpp
src/kernel/EngineImpl.hpp
src/kernel/routing/DijkstraZone.cpp
src/kernel/routing/DijkstraZone_test.cpp
src/kernel/routing/FloydZone.cpp
src/kernel/routing/FloydZone_test.cpp
src/kernel/routing/FullZone.cpp
src/kernel/routing/FullZone_test.cpp
src/kernel/routing/NetZoneImpl.cpp
src/kernel/routing/RoutedZone.cpp
src/kernel/routing/StarZone.cpp
src/kernel/routing/StarZone_test.cpp
src/kernel/routing/VivaldiZone.cpp
src/s4u/s4u_Engine.cpp
src/s4u/s4u_Link.cpp
src/s4u/s4u_Netzone.cpp
src/surf/LinkImpl.cpp [new file with mode: 0644]
src/surf/LinkImpl.hpp [new file with mode: 0644]
src/surf/LinkImplIntf.hpp [new file with mode: 0644]
src/surf/SplitDuplexLinkImpl.cpp [new file with mode: 0644]
src/surf/SplitDuplexLinkImpl.hpp [new file with mode: 0644]
src/surf/SplitDuplexLinkImpl_test.cpp [new file with mode: 0644]
src/surf/network_cm02.cpp
src/surf/network_cm02.hpp
src/surf/network_interface.cpp
src/surf/network_interface.hpp
src/surf/network_ns3.cpp
src/surf/network_ns3.hpp
src/surf/network_wifi.cpp
src/surf/network_wifi.hpp
src/surf/ptask_L07.cpp
src/surf/ptask_L07.hpp
src/surf/sg_platf.cpp
src/surf/xml/platf_private.hpp
src/surf/xml/surfxml_sax_cb.cpp
teshsuite/s4u/seal-platform/seal-platform.cpp
teshsuite/simdag/flatifier/flatifier.tesh
teshsuite/simdag/platforms/two_hosts_one_link_splitduplex.xml
tools/cmake/DefinePackages.cmake
tools/cmake/Tests.cmake

index 3245396..7296054 100644 (file)
@@ -2590,6 +2590,12 @@ include src/smpi/smpirun.in
 include src/smpi/smpitools.sh
 include src/surf/HostImpl.cpp
 include src/surf/HostImpl.hpp
+include src/surf/LinkImpl.cpp
+include src/surf/LinkImpl.hpp
+include src/surf/LinkImplIntf.hpp
+include src/surf/SplitDuplexLinkImpl.cpp
+include src/surf/SplitDuplexLinkImpl.hpp
+include src/surf/SplitDuplexLinkImpl_test.cpp
 include src/surf/cpu_cas01.cpp
 include src/surf/cpu_cas01.hpp
 include src/surf/cpu_interface.cpp
index cbbd33b..f3022b9 100644 (file)
@@ -65,15 +65,19 @@ under the hood, SimGrid creates 2 links in this case: the *1_UP*
 link and the *1_DOWN* link. As you can see, the selection of link to use
 in the <route> tag is done by the ``direction=`` parameter.
 
-Using the C++ interface, you should describe both links separately and use them
-in the route description.
+Using the C++ interface, you can use the specific function to create these 2 links. Note
+that you need to define the direction in the add_route function when adding a route containing
+a split-duplex link. Otherwise, SimGrid cannot know which link (UP/DOWN) to use.
 
 .. code-block:: cpp
 
-    Link* l_up   = zone->create_link("1_UP", "125MBps")->set_latency("24us")->seal();
-    Link* l_down = zone->create_link("1_DOWN", "125MBps")->set_latency("24us")->seal();
+    auto* link = zone->create_split_duplex_link("1", "125MBps")->set_latency("24us")->seal();
     
-    zone->add_route(S1, C1, nullptr, nullptr, {link_down});
+    zone->add_route(S1, C1, nullptr, nullptr, {{link, LinkInRoute::Direction::UP}});
+
+.. note::
+    Do not use set_sharing_policy(SharingPolicy::SPLITDUPLEX).
+    SimGrid will complain since set_sharing_policy should be used only with (SHARED and FATPIPE)
 
 
 Loading the platform
index 88f6053..9feae83 100644 (file)
@@ -110,13 +110,12 @@ create_hostzone(const sg4::NetZone* zone, const std::vector<unsigned int>& /*coo
     /* the first CPU is the gateway */
     if (i == 0)
       gateway = host;
-    /* create 2 links for a full-duplex communication */
-    sg4::Link* link_up   = host_zone->create_link("link-up-" + cpu_name, link_bw)->set_latency(link_lat)->seal();
-    sg4::Link* link_down = host_zone->create_link("link-down-" + cpu_name, link_bw)->set_latency(link_lat)->seal();
-    /* link UP, connection from CPU to outer world */
-    host_zone->add_route(host->get_netpoint(), nullptr, nullptr, nullptr, std::vector<sg4::Link*>{link_up}, false);
-    /* link DOWN, connection from outer to CPU */
-    host_zone->add_route(nullptr, host->get_netpoint(), nullptr, nullptr, std::vector<sg4::Link*>{link_down}, false);
+    /* create split-duplex link */
+    sg4::SplitDuplexLink* link = host_zone->create_split_duplex_link("link-" + cpu_name, link_bw);
+    link->set_latency(link_lat)->seal();
+    /* connecting CPU to outer world */
+    host_zone->add_route(host->get_netpoint(), nullptr, nullptr, nullptr,
+                         std::vector<sg4::LinkInRoute>{{link, sg4::LinkInRoute::Direction::UP}}, true);
   }
   /* seal newly created netzone */
   host_zone->seal();
index 6afc554..81a52d9 100644 (file)
@@ -104,14 +104,11 @@ int main(int argc, char* argv[])
   auto* receiver = zone->create_host("receiver", 1)->seal();
 
   /* create split-duplex link1 (UP/DOWN), limiting the number of concurrent flows in it for 2 */
-  auto* link_up   = zone->create_link("link1_up", 10e9)->set_latency(10e-6)->set_concurrency_limit(2)->seal();
-  auto* link_down = zone->create_link("link1_down", 10e9)->set_latency(10e-6)->set_concurrency_limit(2)->seal();
+  auto* link = zone->create_split_duplex_link("link1", 10e9)->set_latency(10e-6)->set_concurrency_limit(2)->seal();
 
   /* create routes between nodes */
-  zone->add_route(sender->get_netpoint(), receiver->get_netpoint(), nullptr, nullptr, std::vector<sg4::Link*>{link_up},
-                  false);
-  zone->add_route(receiver->get_netpoint(), sender->get_netpoint(), nullptr, nullptr,
-                  std::vector<sg4::Link*>{link_down}, false);
+  zone->add_route(sender->get_netpoint(), receiver->get_netpoint(), nullptr, nullptr,
+                  std::vector<sg4::LinkInRoute>{{link, sg4::LinkInRoute::Direction::UP}}, true);
   zone->seal();
 
   /* create actors Sender/Receiver */
index 0e2d09d..60018a1 100644 (file)
@@ -75,15 +75,15 @@ static void load_platform()
     /* create host */
     const sg4::Host* host = root->create_host(hostname, 1)->set_core_count(32)->seal();
     /* create UP/DOWN link */
-    sg4::Link* l_up   = root->create_link(hostname + "_up", BW_REMOTE)->set_latency(LATENCY)->seal();
-    sg4::Link* l_down = root->create_link(hostname + "_down", BW_REMOTE)->set_latency(LATENCY)->seal();
+    sg4::Link* l = root->create_split_duplex_link(hostname, BW_REMOTE)->set_latency(LATENCY)->seal();
 
     /* add link UP/DOWN for communications from the host */
-    root->add_route(host->get_netpoint(), nullptr, nullptr, nullptr, std::vector<sg4::Link*>{l_up}, false);
-    root->add_route(nullptr, host->get_netpoint(), nullptr, nullptr, std::vector<sg4::Link*>{l_down}, false);
+    root->add_route(host->get_netpoint(), nullptr, nullptr, nullptr,
+                    std::vector<sg4::LinkInRoute>{{l, sg4::LinkInRoute::Direction::UP}}, true);
 
     sg4::Link* loopback = root->create_link(hostname + "_loopback", BW_LOCAL)->set_latency(LATENCY)->seal();
-    root->add_route(host->get_netpoint(), host->get_netpoint(), nullptr, nullptr, std::vector<sg4::Link*>{loopback});
+    root->add_route(host->get_netpoint(), host->get_netpoint(), nullptr, nullptr,
+                    std::vector<sg4::LinkInRoute>{loopback});
   }
 
   root->seal();
index 67c2659..d9eb7d8 100644 (file)
@@ -63,11 +63,10 @@ int main(int argc, char* argv[])
     const auto* host = cluster->create_host(hostname, "1Gf");
 
     std::string linkname = std::string("cluster") + "_link_" + std::to_string(i);
-    auto* link_up        = cluster->create_link(linkname + "_UP", "1Gbps");
-    auto* link_down      = cluster->create_link(linkname + "_DOWN", "1Gbps");
+    auto* link           = cluster->create_split_duplex_link(linkname, "1Gbps");
 
-    cluster->add_route(host->get_netpoint(), nullptr, nullptr, nullptr, std::vector<sg4::Link*>{link_up}, false);
-    cluster->add_route(nullptr, host->get_netpoint(), nullptr, nullptr, std::vector<sg4::Link*>{link_down}, false);
+    cluster->add_route(host->get_netpoint(), nullptr, nullptr, nullptr,
+                       std::vector<sg4::LinkInRoute>{{link, sg4::LinkInRoute::Direction::UP}}, true);
   }
 
   auto* router = cluster->create_router("cluster_router");
index d326305..3b9207a 100644 (file)
@@ -35,13 +35,11 @@ create_cabinet(const sg4::NetZone* root, const std::string& name, const std::vec
     /* create host */
     const sg4::Host* host = cluster->create_host(hostname, "286.087kf");
     /* create UP/DOWN link */
-    sg4::Link* l_up   = cluster->create_link(hostname + "_up", "125MBps")->set_latency("24us")->seal();
-    sg4::Link* l_down = cluster->create_link(hostname + "_down", "125MBps")->set_latency("24us")->seal();
+    auto* link = cluster->create_split_duplex_link(hostname, "125MBps")->set_latency("24us")->seal();
 
-    /* add link UP and backbone for communications from the host */
-    cluster->add_route(host->get_netpoint(), nullptr, nullptr, nullptr, std::vector<sg4::Link*>{l_up, l_bb}, false);
-    /* add backbone and link DOWN for communications to the host */
-    cluster->add_route(nullptr, host->get_netpoint(), nullptr, nullptr, std::vector<sg4::Link*>{l_bb, l_down}, false);
+    /* add link and backbone for communications from the host */
+    cluster->add_route(host->get_netpoint(), nullptr, nullptr, nullptr,
+                       std::vector<sg4::LinkInRoute>{{link, sg4::LinkInRoute::Direction::UP}, l_bb}, true);
   }
 
   /* create router */
index eb97e96..0f150b1 100644 (file)
@@ -39,9 +39,11 @@ static void create_cluster(const sg4::NetZone* root, const std::string& cluster_
     }
 
     /* add link UP and backbone for communications from the host */
-    cluster->add_route(host->get_netpoint(), nullptr, nullptr, nullptr, std::vector<sg4::Link*>{l_up, l_bb}, false);
+    cluster->add_route(host->get_netpoint(), nullptr, nullptr, nullptr, std::vector<sg4::LinkInRoute>{l_up, l_bb},
+                       false);
     /* add backbone and link DOWN for communications to the host */
-    cluster->add_route(nullptr, host->get_netpoint(), nullptr, nullptr, std::vector<sg4::Link*>{l_bb, l_down}, false);
+    cluster->add_route(nullptr, host->get_netpoint(), nullptr, nullptr, std::vector<sg4::LinkInRoute>{l_bb, l_down},
+                       false);
   }
 
   /* create router */
index 32a23f4..bbfbd1c 100644 (file)
@@ -66,6 +66,7 @@ XBT_PUBLIC void intrusive_ptr_release(Io* i);
 XBT_PUBLIC void intrusive_ptr_add_ref(Io* i);
 
 class Link;
+class SplitDuplexLink;
 
 class Mailbox;
 
@@ -163,6 +164,8 @@ class CpuModel;
 class NetworkModel;
 class NetworkModelIntf;
 class LinkImpl;
+class SplitDuplexLinkImpl;
+class LinkImplIntf;
 class NetworkAction;
 class DiskImpl;
 class DiskModel;
index 66e4164..98af529 100644 (file)
@@ -51,7 +51,7 @@ public:
    */
   void get_local_route(const NetPoint* src, const NetPoint* dst, Route* route, double* lat) override;
   void add_route(NetPoint* src, NetPoint* dst, NetPoint* gw_src, NetPoint* gw_dst,
-                 const std::vector<resource::LinkImpl*>& link_list, bool symmetrical) override;
+                 const std::vector<s4u::LinkInRoute>& link_list, bool symmetrical) override;
 };
 } // namespace routing
 } // namespace kernel
index 0277648..83539d1 100644 (file)
@@ -37,7 +37,7 @@ public:
 
   void get_local_route(const NetPoint* src, const NetPoint* dst, Route* into, double* latency) override;
   void add_route(NetPoint* src, NetPoint* dst, NetPoint* gw_src, NetPoint* gw_dst,
-                 const std::vector<resource::LinkImpl*>& link_list, bool symmetrical) override;
+                 const std::vector<s4u::LinkInRoute>& link_list, bool symmetrical) override;
 };
 } // namespace routing
 } // namespace kernel
index df8a189..35a9377 100644 (file)
@@ -31,7 +31,7 @@ public:
 
   void get_local_route(const NetPoint* src, const NetPoint* dst, Route* into, double* latency) override;
   void add_route(NetPoint* src, NetPoint* dst, NetPoint* gw_src, NetPoint* gw_dst,
-                 const std::vector<resource::LinkImpl*>& link_list, bool symmetrical) override;
+                 const std::vector<s4u::LinkInRoute>& link_list, bool symmetrical) override;
 };
 } // namespace routing
 } // namespace kernel
index 430a167..f81e948 100644 (file)
@@ -110,6 +110,10 @@ protected:
   /** @brief Get the NetZone that is represented by the netpoint */
   const NetZoneImpl* get_netzone_recursive(const NetPoint* netpoint) const;
 
+  /** @brief Get the list of LinkImpl* to add in a route, considering split-duplex links and the direction */
+  std::vector<resource::LinkImpl*> get_link_list_impl(const std::vector<s4u::LinkInRoute>& link_list,
+                                                      bool backroute) const;
+
 public:
   enum class RoutingMode {
     base,     /**< Base case: use simple link lists for routing     */
@@ -156,11 +160,12 @@ public:
   s4u::Disk* create_disk(const std::string& name, double read_bandwidth, double write_bandwidth);
   /** @brief Make a link within that NetZone */
   virtual s4u::Link* create_link(const std::string& name, const std::vector<double>& bandwidths);
+  s4u::SplitDuplexLink* create_split_duplex_link(const std::string& name, const std::vector<double>& bandwidths);
   /** @brief Make a router within that NetZone */
   NetPoint* create_router(const std::string& name);
   /** @brief Creates a new route in this NetZone */
   virtual void add_bypass_route(NetPoint* src, NetPoint* dst, NetPoint* gw_src, NetPoint* gw_dst,
-                                std::vector<resource::LinkImpl*>& link_list, bool symmetrical);
+                                const std::vector<s4u::LinkInRoute>& link_list);
 
   /** @brief Seal your netzone once you're done adding content, and before routing stuff through it */
   void seal();
@@ -169,7 +174,7 @@ public:
   virtual int add_component(kernel::routing::NetPoint* elm); /* A host, a router or a netzone, whatever */
   virtual void add_route(kernel::routing::NetPoint* src, kernel::routing::NetPoint* dst,
                          kernel::routing::NetPoint* gw_src, kernel::routing::NetPoint* gw_dst,
-                         const std::vector<kernel::resource::LinkImpl*>& link_list, bool symmetrical);
+                         const std::vector<s4u::LinkInRoute>& link_list, bool symmetrical);
   /** @brief Set parent of this Netzone */
   void set_parent(NetZoneImpl* parent);
   /** @brief Set network model for this Netzone */
@@ -197,6 +202,13 @@ public:
   virtual 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) = 0;
 
+  /*** Called on each newly created regular route (not on bypass routes) */
+  static xbt::signal<void(bool symmetrical, kernel::routing::NetPoint* src, kernel::routing::NetPoint* dst,
+                          kernel::routing::NetPoint* gw_src, kernel::routing::NetPoint* gw_dst,
+                          std::vector<kernel::resource::LinkImpl*> const& link_list)>
+      on_route_creation; // XBT_ATTRIB_DEPRECATED_v332 : should be an internal signal used by NS3.. if necessary,
+                         // callback shouldn't use LinkImpl*
+
 private:
   RoutingMode hierarchy_ = RoutingMode::base;
   std::shared_ptr<resource::NetworkModel> network_model_;
index 7fcd038..08e5c13 100644 (file)
@@ -66,7 +66,7 @@ protected:
   }
   void get_route_check_params(const NetPoint* src, const NetPoint* dst) const;
   void add_route_check_params(NetPoint* src, NetPoint* dst, NetPoint* gw_src, NetPoint* gw_dst,
-                              const std::vector<resource::LinkImpl*>& link_list, bool symmetrical) const;
+                              const std::vector<s4u::LinkInRoute>& link_list, bool symmetrical) const;
 };
 } // namespace routing
 } // namespace kernel
index 4f647d7..2b030c5 100644 (file)
@@ -69,7 +69,7 @@ public:
                  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;
+                 const std::vector<s4u::LinkInRoute>& link_list, bool symmetrical) override;
   void do_seal() override;
 
 private:
index 7f43c2f..074a242 100644 (file)
@@ -121,6 +121,11 @@ public:
   std::vector<Link*> get_all_links() const;
   std::vector<Link*> get_filtered_links(const std::function<bool(Link*)>& filter) const;
   Link* link_by_name(const std::string& name) const;
+  /**
+   * @brief Find a split-duplex link from its name.
+   * @throw std::invalid_argument if the searched link does not exist.
+   */
+  SplitDuplexLink* split_duplex_link_by_name(const std::string& name) const;
   Link* link_by_name_or_null(const std::string& name) const;
 
   Mailbox* mailbox_by_name_or_create(const std::string& name) const;
index b000853..1ab58c8 100644 (file)
@@ -34,16 +34,17 @@ class XBT_PUBLIC Link : public xbt::Extendable<Link> {
   friend kernel::resource::LinkImpl;
 #endif
 
+protected:
   // Links are created from the NetZone, and destroyed by their private implementation when the simulation ends
-  explicit Link(kernel::resource::LinkImpl* pimpl) : pimpl_(pimpl) {}
+  explicit Link(kernel::resource::LinkImplIntf* pimpl) : pimpl_(pimpl) {}
   virtual ~Link() = default;
-  // The private implementation, that never changes
-  kernel::resource::LinkImpl* const pimpl_;
+  // The implementation that never changes
+  kernel::resource::LinkImplIntf* const pimpl_;
 
 public:
   enum class SharingPolicy { WIFI = 3, SPLITDUPLEX = 2, SHARED = 1, FATPIPE = 0 };
 
-  kernel::resource::LinkImpl* get_impl() const { return pimpl_; }
+  kernel::resource::LinkImpl* get_impl() const;
 
   /** @brief Retrieve a link from its name */
   static Link* by_name(const std::string& name);
@@ -149,6 +150,54 @@ public:
   static xbt::signal<void(kernel::resource::NetworkAction&, kernel::resource::Action::State)>
       on_communication_state_change;
 };
+
+/**
+ * @beginrst
+ * A SplitDuplexLink encapsulates the :cpp:class:`links <simgrid::s4u::Link>` which
+ * compose a Split-Duplex link. Remember that a Split-Duplex link is nothing more than
+ * a pair of up/down links.
+ * @endrst
+ */
+class XBT_PUBLIC SplitDuplexLink : public Link {
+public:
+  explicit SplitDuplexLink(kernel::resource::LinkImplIntf* pimpl) : Link(pimpl) {}
+  /** @brief Get the link direction up*/
+  Link* get_link_up() const;
+  /** @brief Get the link direction down */
+  Link* get_link_down() const;
+
+  /** @brief Retrieve a link from its name */
+  static SplitDuplexLink* by_name(const std::string& name);
+};
+
+/**
+ * @beginrst
+ * Another encapsulation for using links in the :cpp:function:: NetZone::add_route
+ *
+ * When adding a route with split-duplex links, you need to specify the direction of the link
+ * so SimGrid can know exactly which physical link to insert in the route.
+ *
+ * For shared/fat-pipe links, use the Direction::NONE since they don't have
+ * the concept of UP/DOWN links.
+ * @endrst
+ */
+class XBT_PUBLIC LinkInRoute {
+public:
+  enum class Direction { UP = 2, DOWN = 1, NONE = 0 };
+
+  LinkInRoute(const Link* link) : link_(link) {}
+  LinkInRoute(const Link* link, Direction d) : link_(link), direction_(d) {}
+
+  /** @brief Get direction of this link in the route: UP or DOWN */
+  Direction get_direction() const { return direction_; }
+  /** @brief Get pointer to the link */
+  const Link* get_link() const { return link_; }
+
+private:
+  const Link* link_;
+  Direction direction_ = Direction::NONE;
+};
+
 } // namespace s4u
 } // namespace simgrid
 
index ed6afa8..bd4cc7b 100644 (file)
@@ -80,26 +80,42 @@ public:
    * @param dst Destination netzone' netpoint
    * @param gw_src Netpoint of the gateway in the source netzone
    * @param gw_dst Netpoint of the gateway in the destination netzone
-   * @param link_list List of links used in this communication
+   * @param link_list List of links and their direction used in this communication
    * @param symmetrical Bi-directional communication
    */
   void add_route(kernel::routing::NetPoint* src, kernel::routing::NetPoint* dst, kernel::routing::NetPoint* gw_src,
-                 kernel::routing::NetPoint* gw_dst, const std::vector<Link*>& link_list, bool symmetrical = true);
+                 kernel::routing::NetPoint* gw_dst, const std::vector<LinkInRoute>& link_list, bool symmetrical = true);
+
+  XBT_ATTRIB_DEPRECATED_v332("Please use add_route() method which uses s4u::LinkInRoute instead of "
+                             "LinkImpl") void add_route(kernel::routing::NetPoint* src, kernel::routing::NetPoint* dst,
+                                                        kernel::routing::NetPoint* gw_src,
+                                                        kernel::routing::NetPoint* gw_dst,
+                                                        const std::vector<kernel::resource::LinkImpl*>& link_list,
+                                                        bool symmetrical);
+
+  XBT_ATTRIB_DEPRECATED_v332("Please use add_bypass_route() method which uses s4u::LinkInRoute instead of "
+                             "LinkImpl") void add_bypass_route(kernel::routing::NetPoint* src,
+                                                               kernel::routing::NetPoint* dst,
+                                                               kernel::routing::NetPoint* gw_src,
+                                                               kernel::routing::NetPoint* gw_dst,
+                                                               std::vector<kernel::resource::LinkImpl*>& link_list,
+                                                               bool /*symmetrical*/);
 
 #ifndef DOXYGEN
-  XBT_ATTRIB_DEPRECATED_v332("Please use add_route() method which uses s4u::Link instead of LinkImpl") void add_route(
-      kernel::routing::NetPoint* src, kernel::routing::NetPoint* dst, kernel::routing::NetPoint* gw_src,
-      kernel::routing::NetPoint* gw_dst, const std::vector<kernel::resource::LinkImpl*>& link_list, bool symmetrical);
 #endif
   void add_bypass_route(kernel::routing::NetPoint* src, kernel::routing::NetPoint* dst,
                         kernel::routing::NetPoint* gw_src, kernel::routing::NetPoint* gw_dst,
-                        std::vector<kernel::resource::LinkImpl*>& link_list, bool symmetrical);
+                        const std::vector<LinkInRoute>& link_list);
 
+#ifndef DOXYGEN
   /*** Called on each newly created regular route (not on bypass routes) */
   static xbt::signal<void(bool symmetrical, kernel::routing::NetPoint* src, kernel::routing::NetPoint* dst,
                           kernel::routing::NetPoint* gw_src, kernel::routing::NetPoint* gw_dst,
                           std::vector<kernel::resource::LinkImpl*> const& link_list)>
-      on_route_creation;
+      on_route_creation; // XBT_ATTRIB_DEPRECATED_v332 : should not be used by users, used by ns3.. if necessary,
+                         // signal shouldn't use LinkImpl*
+#endif
+
   static xbt::signal<void(NetZone const&)> on_creation;
   static xbt::signal<void(NetZone const&)> on_seal;
 
@@ -133,6 +149,22 @@ public:
   s4u::Link* create_link(const std::string& name, const std::vector<std::string>& bandwidths);
   s4u::Link* create_link(const std::string& name, const std::string& bandwidth);
 
+  /**
+   * @brief Create a split-duplex link
+   *
+   * In SimGrid, split-duplex links are a composition of 2 regular (shared) links (up/down).
+   *
+   * This function eases its utilization by creating the 2 links for you. We append a suffix
+   * "_UP" and "_DOWN" to your link name to identify each of them.
+   *
+   * Both up/down links have exactly the same bandwidth
+   *
+   * @param name Name of the link
+   * @param bandwidth Speed
+   */
+  s4u::SplitDuplexLink* create_split_duplex_link(const std::string& name, const std::string& bandwidth);
+  s4u::SplitDuplexLink* create_split_duplex_link(const std::string& name, double bandwidth);
+
   kernel::resource::NetworkModelIntf* get_network_model() const;
 
   /**
@@ -146,8 +178,8 @@ public:
   NetZone* seal();
 
 private:
-  /** @brief Auxiliary function to get list of LinkImpl */
-  static std::vector<kernel::resource::LinkImpl*> get_link_list_impl(const std::vector<Link*>& link_list);
+  /** @brief Auxiliary function to convert types */
+  static std::vector<LinkInRoute> convert_to_linkInRoute(const std::vector<kernel::resource::LinkImpl*>& link_list);
 };
 
 // External constructors so that the types (and the types of their content) remain hidden
index 56eb196..f7edcdb 100644 (file)
@@ -347,13 +347,13 @@ int console_add_route(lua_State *L) {
   boost::split(names, str, boost::is_any_of(", \t\r\n"));
   if (names.empty()) {
     /* unique name */
-    route.link_list.push_back(simgrid::s4u::Link::by_name(lua_tostring(L, -1))->get_impl());
+    route.link_list.emplace_back(simgrid::s4u::LinkInRoute(simgrid::s4u::Link::by_name(lua_tostring(L, -1))));
   } else {
     // Several names separated by , \t\r\n
     for (auto const& name : names) {
       if (name.length() > 0) {
-        simgrid::kernel::resource::LinkImpl* link = simgrid::s4u::Link::by_name(name)->get_impl();
-        route.link_list.push_back(link);
+        simgrid::s4u::LinkInRoute link(simgrid::s4u::Link::by_name(name));
+        route.link_list.emplace_back(link);
       }
     }
   }
@@ -413,13 +413,13 @@ int console_add_ASroute(lua_State *L) {
   boost::split(names, str, boost::is_any_of(", \t\r\n"));
   if (names.empty()) {
     /* unique name with no comma */
-    ASroute.link_list.push_back(simgrid::s4u::Link::by_name(lua_tostring(L, -1))->get_impl());
+    ASroute.link_list.emplace_back(simgrid::s4u::LinkInRoute(simgrid::s4u::Link::by_name(lua_tostring(L, -1))));
   } else {
     // Several names separated by , \t\r\n
     for (auto const& name : names) {
       if (name.length() > 0) {
-        simgrid::kernel::resource::LinkImpl* link = simgrid::s4u::Link::by_name(name)->get_impl();
-        ASroute.link_list.push_back(link);
+        simgrid::s4u::LinkInRoute link(simgrid::s4u::Link::by_name(name));
+        ASroute.link_list.emplace_back(link);
       }
     }
   }
index 2ff94ab..fecdfb9 100644 (file)
@@ -123,6 +123,11 @@ void EngineImpl::add_model(std::shared_ptr<resource::Model> model, const std::ve
   models_prio_[model_name] = std::move(model);
 }
 
+void EngineImpl::add_split_duplex_link(const std::string& name, std::unique_ptr<resource::SplitDuplexLinkImpl> link)
+{
+  split_duplex_links_[name] = std::move(link);
+}
+
 /** Wake up all actors waiting for a Surf action to finish */
 void EngineImpl::wake_all_waiting_actors() const
 {
index db00760..79fa656 100644 (file)
@@ -19,6 +19,7 @@
 #include "src/kernel/activity/SleepImpl.hpp"
 #include "src/kernel/activity/SynchroRaw.hpp"
 #include "src/kernel/actor/ActorImpl.hpp"
+#include "src/surf/SplitDuplexLinkImpl.hpp"
 
 #include <boost/intrusive/list.hpp>
 #include <map>
@@ -34,6 +35,9 @@ namespace kernel {
 class EngineImpl {
   std::map<std::string, s4u::Host*, std::less<>> hosts_;
   std::map<std::string, resource::LinkImpl*, std::less<>> links_;
+  /* save split-duplex links separately, keep links_ with only LinkImpl* seen by the user
+   * members of a split-duplex are saved in the links_ */
+  std::map<std::string, std::unique_ptr<resource::SplitDuplexLinkImpl>> split_duplex_links_;
   std::unordered_map<std::string, routing::NetPoint*> netpoints_;
   std::unordered_map<std::string, activity::MailboxImpl*> mailboxes_;
 
@@ -117,6 +121,7 @@ public:
   actor::ActorImpl* get_actor_by_pid(aid_t pid);
   void add_actor(aid_t pid, actor::ActorImpl* actor) { actor_list_[pid] = actor; }
   void remove_actor(aid_t pid) { actor_list_.erase(pid); }
+  void add_split_duplex_link(const std::string& name, std::unique_ptr<resource::SplitDuplexLinkImpl> link);
 
 #if SIMGRID_HAVE_MC
   xbt_dynar_t get_actors_vector() const { return actors_vector_; }
index bb224b6..e7b9d2c 100644 (file)
@@ -206,14 +206,16 @@ void DijkstraZone::get_local_route(const NetPoint* src, const NetPoint* dst, Rou
 }
 
 void DijkstraZone::add_route(NetPoint* src, NetPoint* dst, NetPoint* gw_src, NetPoint* gw_dst,
-                             const std::vector<resource::LinkImpl*>& link_list_, bool symmetrical)
+                             const std::vector<s4u::LinkInRoute>& link_list, bool symmetrical)
 {
-  add_route_check_params(src, dst, gw_src, gw_dst, link_list_, symmetrical);
+  add_route_check_params(src, dst, gw_src, gw_dst, link_list, symmetrical);
 
-  new_edge(src->id(), dst->id(), new_extended_route(get_hierarchy(), gw_src, gw_dst, link_list_, true));
+  new_edge(src->id(), dst->id(),
+           new_extended_route(get_hierarchy(), gw_src, gw_dst, get_link_list_impl(link_list, false), true));
 
   if (symmetrical)
-    new_edge(dst->id(), src->id(), new_extended_route(get_hierarchy(), gw_dst, gw_src, link_list_, false));
+    new_edge(dst->id(), src->id(),
+             new_extended_route(get_hierarchy(), gw_dst, gw_src, get_link_list_impl(link_list, true), false));
 }
 
 void DijkstraZone::new_edge(int src_id, int dst_id, Route* route)
index 9689c18..d222e96 100644 (file)
@@ -31,6 +31,6 @@ TEST_CASE("kernel::routing::DijkstraZone: mix new routes and hosts", "")
     std::string cpu_name          = "CPU" + std::to_string(i);
     const simgrid::s4u::Host* cpu = zone->create_host(cpu_name, 1e9)->seal();
     REQUIRE_NOTHROW(zone->add_route(cpu->get_netpoint(), nic->get_netpoint(), nullptr, nullptr,
-                                    std::vector<simgrid::s4u::Link*>{link}, true));
+                                    std::vector<simgrid::s4u::LinkInRoute>{link}, true));
   }
 }
index e48a460..6674f5b 100644 (file)
@@ -69,13 +69,13 @@ void FloydZone::get_local_route(const NetPoint* src, const NetPoint* dst, Route*
 }
 
 void FloydZone::add_route(NetPoint* src, NetPoint* dst, NetPoint* gw_src, NetPoint* gw_dst,
-                          const std::vector<resource::LinkImpl*>& link_list_, bool symmetrical)
+                          const std::vector<s4u::LinkInRoute>& link_list, bool symmetrical)
 {
   /* set the size of table routing */
   unsigned int table_size = get_table_size();
   init_tables(table_size);
 
-  add_route_check_params(src, dst, gw_src, gw_dst, link_list_, symmetrical);
+  add_route_check_params(src, dst, gw_src, gw_dst, link_list, symmetrical);
 
   /* Check that the route does not already exist */
   if (gw_dst && gw_src) // netzone route (to adapt the error message, if any)
@@ -87,8 +87,8 @@ void FloydZone::add_route(NetPoint* src, NetPoint* dst, NetPoint* gw_src, NetPoi
                "The route between %s and %s already exists (Rq: routes are symmetrical by default).", src->get_cname(),
                dst->get_cname());
 
-  link_table_[src->id()][dst->id()] =
-      std::unique_ptr<Route>(new_extended_route(get_hierarchy(), gw_src, gw_dst, link_list_, true));
+  link_table_[src->id()][dst->id()] = std::unique_ptr<Route>(
+      new_extended_route(get_hierarchy(), gw_src, gw_dst, get_link_list_impl(link_list, false), true));
   predecessor_table_[src->id()][dst->id()] = src->id();
   cost_table_[src->id()][dst->id()]        = link_table_[src->id()][dst->id()]->link_list_.size();
 
@@ -115,8 +115,8 @@ void FloydZone::add_route(NetPoint* src, NetPoint* dst, NetPoint* gw_src, NetPoi
       XBT_DEBUG("Load NetzoneRoute from \"%s(%s)\" to \"%s(%s)\"", dst->get_cname(), gw_src->get_cname(),
                 src->get_cname(), gw_dst->get_cname());
 
-    link_table_[dst->id()][src->id()] =
-        std::unique_ptr<Route>(new_extended_route(get_hierarchy(), gw_src, gw_dst, link_list_, false));
+    link_table_[dst->id()][src->id()] = std::unique_ptr<Route>(
+        new_extended_route(get_hierarchy(), gw_src, gw_dst, get_link_list_impl(link_list, true), false));
     predecessor_table_[dst->id()][src->id()] = dst->id();
     cost_table_[dst->id()][src->id()] =
         link_table_[dst->id()][src->id()]->link_list_.size(); /* count of links, old model assume 1 */
index 7727d39..d47351c 100644 (file)
@@ -30,6 +30,6 @@ TEST_CASE("kernel::routing::FloydZone: mix new routes and hosts", "")
     std::string cpu_name          = "CPU" + std::to_string(i);
     const simgrid::s4u::Host* cpu = zone->create_host(cpu_name, 1e9)->seal();
     REQUIRE_NOTHROW(zone->add_route(cpu->get_netpoint(), nic->get_netpoint(), nullptr, nullptr,
-                                    std::vector<simgrid::s4u::Link*>{link}, true));
+                                    std::vector<simgrid::s4u::LinkInRoute>{link}, true));
   }
 }
index 9dc19a1..dcbf949 100644 (file)
@@ -55,7 +55,7 @@ void FullZone::get_local_route(const NetPoint* src, const NetPoint* dst, Route*
 }
 
 void FullZone::add_route(NetPoint* src, NetPoint* dst, NetPoint* gw_src, NetPoint* gw_dst,
-                         const std::vector<resource::LinkImpl*>& link_list, bool symmetrical)
+                         const std::vector<s4u::LinkInRoute>& link_list, bool symmetrical)
 {
   add_route_check_params(src, dst, gw_src, gw_dst, link_list, symmetrical);
 
@@ -72,8 +72,8 @@ void FullZone::add_route(NetPoint* src, NetPoint* dst, NetPoint* gw_src, NetPoin
                dst->get_cname());
 
   /* Add the route to the base */
-  routing_table_[src->id()][dst->id()] =
-      std::unique_ptr<Route>(new_extended_route(get_hierarchy(), gw_src, gw_dst, link_list, true));
+  routing_table_[src->id()][dst->id()] = std::unique_ptr<Route>(
+      new_extended_route(get_hierarchy(), gw_src, gw_dst, get_link_list_impl(link_list, false), true));
 
   if (symmetrical && src != dst) {
     if (gw_dst && gw_src) {
@@ -91,8 +91,8 @@ void FullZone::add_route(NetPoint* src, NetPoint* dst, NetPoint* gw_src, NetPoin
                  "The route between %s and %s already exists. You should not declare the reverse path as symmetrical.",
                  dst->get_cname(), src->get_cname());
 
-    routing_table_[dst->id()][src->id()] =
-        std::unique_ptr<Route>(new_extended_route(get_hierarchy(), gw_src, gw_dst, link_list, false));
+    routing_table_[dst->id()][src->id()] = std::unique_ptr<Route>(
+        new_extended_route(get_hierarchy(), gw_src, gw_dst, get_link_list_impl(link_list, true), false));
   }
 }
 } // namespace routing
index f630fdc..f67e156 100644 (file)
@@ -30,6 +30,6 @@ TEST_CASE("kernel::routing::FullZone: mix new routes and hosts", "[bug]")
     std::string cpu_name          = "CPU" + std::to_string(i);
     const simgrid::s4u::Host* cpu = zone->create_host(cpu_name, 1e9)->seal();
     REQUIRE_NOTHROW(zone->add_route(cpu->get_netpoint(), nic->get_netpoint(), nullptr, nullptr,
-                                    std::vector<simgrid::s4u::Link*>{link}, true));
+                                    std::vector<simgrid::s4u::LinkInRoute>{link}, true));
   }
 }
index d5dc99f..d357d6a 100644 (file)
@@ -11,6 +11,7 @@
 #include "src/kernel/EngineImpl.hpp"
 #include "src/kernel/resource/DiskImpl.hpp"
 #include "src/surf/HostImpl.hpp"
+#include "src/surf/SplitDuplexLinkImpl.hpp"
 #include "src/surf/cpu_interface.hpp"
 #include "src/surf/network_interface.hpp"
 #include "surf/surf.hpp"
@@ -64,6 +65,11 @@ static void surf_config_models_setup()
   disk_model->model_init_preparse();
 }
 
+xbt::signal<void(bool symmetrical, kernel::routing::NetPoint* src, kernel::routing::NetPoint* dst,
+                 kernel::routing::NetPoint* gw_src, kernel::routing::NetPoint* gw_dst,
+                 std::vector<kernel::resource::LinkImpl*> const& link_list)>
+    NetZoneImpl::on_route_creation;
+
 NetZoneImpl::NetZoneImpl(const std::string& name) : piface_(this), name_(name)
 {
   /* workaroud: first netzoneImpl will be the root netzone.
@@ -161,6 +167,17 @@ s4u::Link* NetZoneImpl::create_link(const std::string& name, const std::vector<d
   return network_model_->create_link(name, bandwidths)->get_iface();
 }
 
+s4u::SplitDuplexLink* NetZoneImpl::create_split_duplex_link(const std::string& name,
+                                                            const std::vector<double>& bandwidths)
+{
+  auto* link_up                  = network_model_->create_link(name + "_UP", bandwidths);
+  auto* link_down                = network_model_->create_link(name + "_DOWN", bandwidths);
+  auto link                      = std::make_unique<resource::SplitDuplexLinkImpl>(name, link_up, link_down);
+  auto* link_iface               = link->get_iface();
+  EngineImpl::get_instance()->add_split_duplex_link(name, std::move(link));
+  return link_iface;
+}
+
 s4u::Disk* NetZoneImpl::create_disk(const std::string& name, double read_bandwidth, double write_bandwidth)
 {
   xbt_assert(disk_model_,
@@ -184,27 +201,64 @@ int NetZoneImpl::add_component(NetPoint* elm)
   return vertices_.size() - 1; // The rank of the newly created object
 }
 
+std::vector<resource::LinkImpl*> NetZoneImpl::get_link_list_impl(const std::vector<s4u::LinkInRoute>& link_list,
+                                                                 bool backroute) const
+{
+  std::vector<resource::LinkImpl*> links;
+
+  for (const auto& link : link_list) {
+    resource::LinkImpl* link_impl;
+    if (link.get_link()->get_sharing_policy() == s4u::Link::SharingPolicy::SPLITDUPLEX) {
+      const auto* sd_link = dynamic_cast<const s4u::SplitDuplexLink*>(link.get_link());
+      xbt_assert(sd_link,
+                 "Add_route: cast to SpliDuplexLink impossible. This should not happen, please contact SimGrid team");
+      switch (link.get_direction()) {
+        case s4u::LinkInRoute::Direction::UP:
+          if (backroute)
+            link_impl = sd_link->get_link_down()->get_impl();
+          else
+            link_impl = sd_link->get_link_up()->get_impl();
+          break;
+        case s4u::LinkInRoute::Direction::DOWN:
+          if (backroute)
+            link_impl = sd_link->get_link_up()->get_impl();
+          else
+            link_impl = sd_link->get_link_down()->get_impl();
+          break;
+        case s4u::LinkInRoute::Direction::NONE:
+        default:
+          throw std::invalid_argument("Invalid add_route. Split-Duplex link without a direction: " +
+                                      link.get_link()->get_name());
+      }
+    } else {
+      link_impl = link.get_link()->get_impl();
+    }
+    links.push_back(link_impl);
+  }
+  return links;
+}
+
 void NetZoneImpl::add_route(NetPoint* /*src*/, NetPoint* /*dst*/, NetPoint* /*gw_src*/, NetPoint* /*gw_dst*/,
-                            const std::vector<resource::LinkImpl*>& /*link_list_*/, bool /*symmetrical*/)
+                            const std::vector<s4u::LinkInRoute>& /*link_list_*/, bool /*symmetrical*/)
 {
   xbt_die("NetZone '%s' does not accept new routes (wrong class).", get_cname());
 }
 
 void NetZoneImpl::add_bypass_route(NetPoint* src, NetPoint* dst, NetPoint* gw_src, NetPoint* gw_dst,
-                                   std::vector<resource::LinkImpl*>& link_list_, bool /* symmetrical */)
+                                   const std::vector<s4u::LinkInRoute>& link_list)
 {
   /* Argument validity checks */
   if (gw_dst) {
     XBT_DEBUG("Load bypassNetzoneRoute from %s@%s to %s@%s", src->get_cname(), gw_src->get_cname(), dst->get_cname(),
               gw_dst->get_cname());
-    xbt_assert(not link_list_.empty(), "Bypass route between %s@%s and %s@%s cannot be empty.", src->get_cname(),
+    xbt_assert(not link_list.empty(), "Bypass route between %s@%s and %s@%s cannot be empty.", src->get_cname(),
                gw_src->get_cname(), dst->get_cname(), gw_dst->get_cname());
     xbt_assert(bypass_routes_.find({src, dst}) == bypass_routes_.end(),
                "The bypass route between %s@%s and %s@%s already exists.", src->get_cname(), gw_src->get_cname(),
                dst->get_cname(), gw_dst->get_cname());
   } else {
     XBT_DEBUG("Load bypassRoute from %s to %s", src->get_cname(), dst->get_cname());
-    xbt_assert(not link_list_.empty(), "Bypass route between %s and %s cannot be empty.", src->get_cname(),
+    xbt_assert(not link_list.empty(), "Bypass route between %s and %s cannot be empty.", src->get_cname(),
                dst->get_cname());
     xbt_assert(bypass_routes_.find({src, dst}) == bypass_routes_.end(),
                "The bypass route between %s and %s already exists.", src->get_cname(), dst->get_cname());
@@ -212,7 +266,8 @@ void NetZoneImpl::add_bypass_route(NetPoint* src, NetPoint* dst, NetPoint* gw_sr
 
   /* Build a copy that will be stored in the dict */
   auto* newRoute = new BypassRoute(gw_src, gw_dst);
-  newRoute->links.insert(newRoute->links.end(), begin(link_list_), end(link_list_));
+  auto converted_list = get_link_list_impl(link_list, false);
+  newRoute->links.insert(newRoute->links.end(), begin(converted_list), end(converted_list));
 
   /* Store it */
   bypass_routes_.insert({{src, dst}, newRoute});
index 3c28dce..7bbddf9 100644 (file)
@@ -149,7 +149,7 @@ void RoutedZone::get_route_check_params(const NetPoint* src, const NetPoint* dst
              src->get_cname(), dst->get_cname(), src_as->get_cname(), dst_as->get_cname(), get_cname());
 }
 void RoutedZone::add_route_check_params(NetPoint* src, NetPoint* dst, NetPoint* gw_src, NetPoint* gw_dst,
-                                        const std::vector<resource::LinkImpl*>& link_list, bool symmetrical) const
+                                        const std::vector<s4u::LinkInRoute>& link_list, bool symmetrical) const
 {
   const char* srcName = src->get_cname();
   const char* dstName = dst->get_cname();
@@ -165,7 +165,8 @@ void RoutedZone::add_route_check_params(NetPoint* src, NetPoint* dst, NetPoint*
     xbt_assert(not dst->is_netzone(),
                "When defining a route, dst cannot be a netzone such as '%s'. Did you meant to have a NetzoneRoute?",
                dstName);
-    s4u::NetZone::on_route_creation(symmetrical, src, dst, gw_src, gw_dst, link_list);
+    s4u::NetZone::on_route_creation(symmetrical, src, dst, gw_src, gw_dst, get_link_list_impl(link_list, false));
+    NetZoneImpl::on_route_creation(symmetrical, src, dst, gw_src, gw_dst, get_link_list_impl(link_list, false));
   } else {
     XBT_DEBUG("Load NetzoneRoute from %s@%s to %s@%s", srcName, gw_src->get_cname(), dstName, gw_dst->get_cname());
     xbt_assert(src->is_netzone(), "When defining a NetzoneRoute, src must be a netzone but '%s' is not", srcName);
@@ -195,7 +196,8 @@ void RoutedZone::add_route_check_params(NetPoint* src, NetPoint* dst, NetPoint*
                "Invalid NetzoneRoute from %s@%s to %s@%s: gw_dst %s belongs to %s, not to %s.", srcName,
                gw_src->get_cname(), dstName, gw_dst->get_cname(), gw_dst->get_cname(),
                gw_dst->get_englobing_zone()->get_cname(), dst->get_cname());
-    s4u::NetZone::on_route_creation(symmetrical, gw_src, gw_dst, gw_src, gw_dst, link_list);
+    s4u::NetZone::on_route_creation(symmetrical, gw_src, gw_dst, gw_src, gw_dst, get_link_list_impl(link_list, false));
+    NetZoneImpl::on_route_creation(symmetrical, gw_src, gw_dst, gw_src, gw_dst, get_link_list_impl(link_list, false));
   }
 }
 } // namespace routing
index b91248d..dad133f 100644 (file)
@@ -135,32 +135,31 @@ void StarZone::check_add_route_param(const NetPoint* src, const NetPoint* dst, c
 }
 
 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 std::vector<s4u::LinkInRoute>& link_list, bool symmetrical)
 {
   check_add_route_param(src, dst, gw_src, gw_dst, symmetrical);
 
-  s4u::NetZone::on_route_creation(symmetrical, src, dst, gw_src, gw_dst, link_list_);
-
   /* loopback */
   if (src == dst) {
-    routes_[src->id()].loopback = link_list_;
+    routes_[src->id()].loopback = get_link_list_impl(link_list, false);
   } else {
     /* src to everyone */
     if (src) {
       auto& route        = routes_[src->id()];
-      route.links_up     = link_list_;
+      route.links_up     = get_link_list_impl(link_list, false);
       route.gateway      = gw_src;
       route.links_up_set = true;
       if (symmetrical) {
+        auto links_down = get_link_list_impl(link_list, true);
         /* reverse it for down/symmetrical links */
-        route.links_down.assign(link_list_.rbegin(), link_list_.rend());
+        route.links_down.assign(links_down.rbegin(), links_down.rend());
         route.links_down_set = true;
       }
     }
     /* dst to everyone */
     if (dst) {
       auto& route          = routes_[dst->id()];
-      route.links_down     = link_list_;
+      route.links_down     = get_link_list_impl(link_list, false);
       route.gateway        = gw_dst;
       route.links_down_set = true;
     }
index d8d5206..ef27bf5 100644 (file)
@@ -19,6 +19,21 @@ TEST_CASE("kernel::routing::StarZone: Creating Zone", "[creation]")
   REQUIRE(simgrid::s4u::create_star_zone("test"));
 }
 
+TEST_CASE("kernel::routing::StarZone: Create links: exceptions", "")
+{
+  simgrid::s4u::Engine e("test");
+  auto* zone = simgrid::s4u::create_star_zone("test");
+  SECTION("create_link: invalid bandwidth")
+  {
+    REQUIRE_THROWS_AS(zone->create_link("link", "speed"), std::invalid_argument);
+  }
+
+  SECTION("split-duplex create_link: invalid bandwidth")
+  {
+    REQUIRE_THROWS_AS(zone->create_split_duplex_link("link", "speed"), std::invalid_argument);
+  }
+}
+
 TEST_CASE("kernel::routing::StarZone: Adding routes (hosts): exception", "")
 {
   simgrid::s4u::Engine e("test");
@@ -95,10 +110,10 @@ TEST_CASE("kernel::routing::StarZone: Get routes: assert", "[.][assert]")
 
   const auto* host1 = zone->create_host("netpoint1", {100});
   const 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());
+  std::vector<simgrid::s4u::LinkInRoute> links;
+  links.emplace_back(zone->create_link("link1", {100}));
+  std::vector<simgrid::s4u::LinkInRoute> links2;
+  links2.emplace_back(zone->create_link("link2", {100}));
 
   SECTION("Get route: no UP link")
   {
@@ -165,10 +180,10 @@ TEST_CASE("kernel::routing::StarZone: Get routes (hosts)", "")
 
   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());
+    std::vector<simgrid::s4u::LinkInRoute> links;
+    links.emplace_back(zone->create_link("link1", {100})->set_latency(10));
+    std::vector<simgrid::s4u::LinkInRoute> links2;
+    links2.emplace_back(zone->create_link("link2", {200})->set_latency(20));
     zone->add_route(host1->get_netpoint(), nullptr, nullptr, nullptr, links, true);
     zone->add_route(host2->get_netpoint(), nullptr, nullptr, nullptr, links2, true);
     zone->seal();
@@ -186,13 +201,13 @@ TEST_CASE("kernel::routing::StarZone: Get routes (hosts)", "")
 
   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);
+    auto* backbone = zone->create_link("backbone", {1000})->set_latency(100);
+    std::vector<simgrid::s4u::LinkInRoute> links;
+    links.emplace_back(zone->create_link("link1", {100})->set_latency(10));
+    links.emplace_back(backbone);
+    std::vector<simgrid::s4u::LinkInRoute> links2;
+    links2.emplace_back(zone->create_link("link2", {200})->set_latency(20));
+    links2.emplace_back(backbone);
 
     zone->add_route(host1->get_netpoint(), nullptr, nullptr, nullptr, links, true);
     zone->add_route(host2->get_netpoint(), nullptr, nullptr, nullptr, links2, true);
@@ -210,10 +225,10 @@ TEST_CASE("kernel::routing::StarZone: Get routes (hosts)", "")
 
   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);
+    auto* backbone = zone->create_link("backbone", {1000})->set_latency(100);
+    std::vector<simgrid::s4u::LinkInRoute> links;
+    links.emplace_back(zone->create_link("link1", {100})->set_latency(10));
+    links.emplace_back(backbone);
 
     zone->add_route(host1->get_netpoint(), host1->get_netpoint(), nullptr, nullptr, links, true);
     zone->seal();
@@ -243,10 +258,10 @@ TEST_CASE("kernel::routing::StarZone: Get routes (netzones)", "")
 
   SECTION("Get route: netzone")
   {
-    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());
+    std::vector<simgrid::s4u::LinkInRoute> links;
+    links.emplace_back(zone->create_link("link1", {100})->set_latency(10));
+    std::vector<simgrid::s4u::LinkInRoute> links2;
+    links2.emplace_back(zone->create_link("link2", {200})->set_latency(20));
     zone->add_route(subzone1->get_netpoint(), nullptr, router1, nullptr, links, true);
     zone->add_route(subzone2->get_netpoint(), nullptr, router2, nullptr, links2, true);
     zone->seal();
@@ -272,7 +287,7 @@ TEST_CASE("kernel::routing::StarZone: mix new routes and hosts", "")
   for (int i = 0; i < 10; i++) {
     std::string cpu_name          = "CPU" + std::to_string(i);
     const simgrid::s4u::Host* cpu = zone->create_host(cpu_name, 1e9)->seal();
-    REQUIRE_NOTHROW(
-        zone->add_route(cpu->get_netpoint(), nullptr, nullptr, nullptr, std::vector<simgrid::s4u::Link*>{link}, true));
+    REQUIRE_NOTHROW(zone->add_route(cpu->get_netpoint(), nullptr, nullptr, nullptr,
+                                    std::vector<simgrid::s4u::LinkInRoute>{link}, true));
   }
 }
index aa2a15d..8ac7639 100644 (file)
@@ -66,8 +66,8 @@ void VivaldiZone::set_peer_link(NetPoint* netpoint, double bw_in, double bw_out)
   std::string link_down      = "link_" + netpoint->get_name() + "_DOWN";
   const auto* linkUp         = create_link(link_up, std::vector<double>{bw_out})->seal();
   const auto* linkDown       = create_link(link_down, std::vector<double>{bw_in})->seal();
-  add_route(netpoint, nullptr, nullptr, nullptr, {linkUp->get_impl()}, false);
-  add_route(nullptr, netpoint, nullptr, nullptr, {linkDown->get_impl()}, false);
+  add_route(netpoint, nullptr, nullptr, nullptr, std::vector<s4u::LinkInRoute>{linkUp}, false);
+  add_route(nullptr, netpoint, nullptr, nullptr, std::vector<s4u::LinkInRoute>{linkDown}, false);
 }
 
 void VivaldiZone::get_local_route(const NetPoint* src, const NetPoint* dst, Route* route, double* lat)
index d70eb6e..47b512e 100644 (file)
@@ -236,6 +236,14 @@ Link* Engine::link_by_name(const std::string& name) const
   return link->second->get_iface();
 }
 
+SplitDuplexLink* Engine::split_duplex_link_by_name(const std::string& name) const
+{
+  auto link = pimpl->split_duplex_links_.find(name);
+  if (link == pimpl->split_duplex_links_.end())
+    throw std::invalid_argument(std::string("Link not found: ") + name);
+  return link->second->get_iface();
+}
+
 /** @brief Find a link from its name (or nullptr if that link does not exist) */
 Link* Engine::link_by_name_or_null(const std::string& name) const
 {
index 0f88869..65d544b 100644 (file)
@@ -10,7 +10,7 @@
 #include "simgrid/s4u/Link.hpp"
 #include "simgrid/sg_config.hpp"
 #include "simgrid/simix.hpp"
-#include "src/kernel/lmm/maxmin.hpp"
+#include "src/surf/SplitDuplexLinkImpl.hpp"
 #include "src/surf/network_interface.hpp"
 #include "src/surf/network_wifi.hpp"
 #include "xbt/log.h"
@@ -35,6 +35,14 @@ Link* Link::by_name(const std::string& name)
   return Engine::get_instance()->link_by_name(name);
 }
 
+kernel::resource::LinkImpl* Link::get_impl() const
+{
+  xbt_assert(
+      get_sharing_policy() != SharingPolicy::SPLITDUPLEX,
+      "Impossible to get a LinkImpl* from a Split-Duplex link. You should call this method to each UP/DOWN member");
+  return dynamic_cast<kernel::resource::LinkImpl*>(pimpl_);
+}
+
 Link* Link::by_name_or_null(const std::string& name)
 {
   return Engine::get_instance()->link_by_name_or_null(name);
@@ -96,7 +104,7 @@ Link* Link::set_sharing_policy(Link::SharingPolicy policy)
 {
   if (policy == SharingPolicy::SPLITDUPLEX)
     throw std::invalid_argument(std::string("Impossible to set split-duplex for the link: ") + get_name() +
-                                std::string(". You should create a link-up and link-down to emulate this behavior"));
+                                std::string(". Use NetZone::create_split_duplex_link."));
 
   kernel::actor::simcall([this, policy] { pimpl_->set_sharing_policy(policy); });
   return this;
@@ -185,6 +193,21 @@ Link* Link::set_properties(const std::unordered_map<std::string, std::string>& p
   return this;
 }
 
+Link* SplitDuplexLink::get_link_up() const
+{
+  return dynamic_cast<kernel::resource::SplitDuplexLinkImpl*>(pimpl_)->get_link_up();
+}
+
+Link* SplitDuplexLink::get_link_down() const
+{
+  return dynamic_cast<kernel::resource::SplitDuplexLinkImpl*>(pimpl_)->get_link_down();
+}
+
+SplitDuplexLink* SplitDuplexLink::by_name(const std::string& name)
+{
+  return Engine::get_instance()->split_duplex_link_by_name(name);
+}
+
 } // namespace s4u
 } // namespace simgrid
 
index d9d23ef..428c19f 100644 (file)
@@ -100,33 +100,41 @@ int NetZone::add_component(kernel::routing::NetPoint* elm)
   return pimpl_->add_component(elm);
 }
 
-std::vector<kernel::resource::LinkImpl*> NetZone::get_link_list_impl(const std::vector<Link*>& link_list)
+std::vector<LinkInRoute> NetZone::convert_to_linkInRoute(const std::vector<kernel::resource::LinkImpl*>& link_list)
 {
-  std::vector<kernel::resource::LinkImpl*> links;
-  for (const auto& link : link_list) {
-    links.push_back(link->get_impl());
+  std::vector<LinkInRoute> links;
+  for (const auto* link : link_list) {
+    links.emplace_back(LinkInRoute(link->get_iface()));
   }
   return links;
 }
 
 void NetZone::add_route(kernel::routing::NetPoint* src, kernel::routing::NetPoint* dst,
                         kernel::routing::NetPoint* gw_src, kernel::routing::NetPoint* gw_dst,
-                        const std::vector<Link*>& link_list, bool symmetrical)
+                        const std::vector<LinkInRoute>& link_list, bool symmetrical)
 {
-  pimpl_->add_route(src, dst, gw_src, gw_dst, NetZone::get_link_list_impl(link_list), symmetrical);
+  pimpl_->add_route(src, dst, gw_src, gw_dst, link_list, symmetrical);
 }
 
 void NetZone::add_route(kernel::routing::NetPoint* src, kernel::routing::NetPoint* dst,
                         kernel::routing::NetPoint* gw_src, kernel::routing::NetPoint* gw_dst,
                         const std::vector<kernel::resource::LinkImpl*>& link_list, bool symmetrical)
 {
-  pimpl_->add_route(src, dst, gw_src, gw_dst, link_list, symmetrical);
+  pimpl_->add_route(src, dst, gw_src, gw_dst, convert_to_linkInRoute(link_list), symmetrical);
+}
+
+void NetZone::add_bypass_route(kernel::routing::NetPoint* src, kernel::routing::NetPoint* dst,
+                               kernel::routing::NetPoint* gw_src, kernel::routing::NetPoint* gw_dst,
+                               std::vector<kernel::resource::LinkImpl*>& link_list, bool /*symmetrical*/)
+{
+  pimpl_->add_bypass_route(src, dst, gw_src, gw_dst, convert_to_linkInRoute(link_list));
 }
+
 void NetZone::add_bypass_route(kernel::routing::NetPoint* src, kernel::routing::NetPoint* dst,
                                kernel::routing::NetPoint* gw_src, kernel::routing::NetPoint* gw_dst,
-                               std::vector<kernel::resource::LinkImpl*>& link_list, bool symmetrical)
+                               const std::vector<LinkInRoute>& link_list)
 {
-  pimpl_->add_bypass_route(src, dst, gw_src, gw_dst, link_list, symmetrical);
+  pimpl_->add_bypass_route(src, dst, gw_src, gw_dst, link_list);
 }
 
 void NetZone::extract_xbt_graph(const s_xbt_graph_t* graph, std::map<std::string, xbt_node_t, std::less<>>* nodes,
@@ -180,6 +188,24 @@ s4u::Link* NetZone::create_link(const std::string& name, const std::string& band
   return create_link(name, std::vector<std::string>{bandwidth});
 }
 
+s4u::SplitDuplexLink* NetZone::create_split_duplex_link(const std::string& name, const std::string& bandwidth)
+{
+  double speed;
+  try {
+    speed = xbt_parse_get_bandwidth("", 0, bandwidth, "");
+  } catch (const simgrid::ParseError&) {
+    throw std::invalid_argument(std::string("Impossible to create split-duplex link: ") + name +
+                                std::string(". Invalid bandwidth: ") + bandwidth);
+  }
+  return create_split_duplex_link(name, speed);
+}
+
+s4u::SplitDuplexLink* NetZone::create_split_duplex_link(const std::string& name, double bandwidth)
+{
+  return kernel::actor::simcall(
+      [this, &name, &bandwidth] { return pimpl_->create_split_duplex_link(name, std::vector<double>{bandwidth}); });
+}
+
 s4u::Link* NetZone::create_link(const std::string& name, const std::vector<std::string>& bandwidths)
 {
   std::vector<double> bw;
diff --git a/src/surf/LinkImpl.cpp b/src/surf/LinkImpl.cpp
new file mode 100644 (file)
index 0000000..3bef2d1
--- /dev/null
@@ -0,0 +1,137 @@
+/* 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. */
+
+#include "src/surf/LinkImpl.hpp"
+#include "simgrid/s4u/Engine.hpp"
+#include "surf/surf.hpp"
+
+#include <numeric>
+
+XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(res_network);
+
+/*********
+ * Model *
+ *********/
+
+namespace simgrid {
+namespace kernel {
+namespace resource {
+
+LinkImpl::LinkImpl(const std::string& name) : LinkImplIntf(name), piface_(this)
+{
+  if (name != "__loopback__")
+    xbt_assert(not s4u::Link::by_name_or_null(name), "Link '%s' declared several times in the platform.", name.c_str());
+
+  s4u::Engine::get_instance()->link_register(name, &piface_);
+  XBT_DEBUG("Create link '%s'", name.c_str());
+}
+
+/** @brief Fire the required callbacks and destroy the object
+ *
+ * Don't delete directly a Link, call l->destroy() instead.
+ */
+void LinkImpl::destroy()
+{
+  s4u::Link::on_destruction(this->piface_);
+  delete this;
+}
+
+bool LinkImpl::is_used() const
+{
+  return get_model()->get_maxmin_system()->constraint_used(get_constraint());
+}
+
+void LinkImpl::set_sharing_policy(s4u::Link::SharingPolicy policy)
+{
+  lmm::Constraint::SharingPolicy ct_policy = lmm::Constraint::SharingPolicy::SHARED;
+  if (policy == s4u::Link::SharingPolicy::FATPIPE)
+    ct_policy = lmm::Constraint::SharingPolicy::FATPIPE;
+  get_constraint()->set_sharing_policy(ct_policy);
+  sharing_policy_ = policy;
+}
+s4u::Link::SharingPolicy LinkImpl::get_sharing_policy() const
+{
+  return sharing_policy_;
+}
+
+void LinkImpl::latency_check(double latency) const
+{
+  static double last_warned_latency = sg_surf_precision;
+  if (latency != 0.0 && latency < last_warned_latency) {
+    XBT_WARN("Latency for link %s is smaller than surf/precision (%g < %g)."
+             " For more accuracy, consider setting \"--cfg=surf/precision:%g\".",
+             get_cname(), latency, sg_surf_precision, latency);
+    last_warned_latency = latency;
+  }
+}
+
+void LinkImpl::turn_on()
+{
+  if (not is_on()) {
+    Resource::turn_on();
+    s4u::Link::on_state_change(piface_);
+  }
+}
+
+void LinkImpl::turn_off()
+{
+  if (is_on()) {
+    Resource::turn_off();
+    s4u::Link::on_state_change(piface_);
+
+    const kernel::lmm::Element* elem = nullptr;
+    double now                       = surf_get_clock();
+    while (const auto* var = get_constraint()->get_variable(&elem)) {
+      Action* action = var->get_id();
+      if (action->get_state() == Action::State::INITED || action->get_state() == Action::State::STARTED) {
+        action->set_finish_time(now);
+        action->set_state(Action::State::FAILED);
+      }
+    }
+  }
+}
+
+void LinkImpl::seal()
+{
+  if (is_sealed())
+    return;
+
+  xbt_assert(this->get_model(), "Cannot seal Link(%s) without setting the Network model first", this->get_cname());
+  Resource::seal();
+  s4u::Link::on_creation(piface_);
+}
+
+void LinkImpl::on_bandwidth_change() const
+{
+  s4u::Link::on_bandwidth_change(piface_);
+}
+
+void LinkImpl::set_bandwidth_profile(profile::Profile* profile)
+{
+  if (profile) {
+    xbt_assert(bandwidth_.event == nullptr, "Cannot set a second bandwidth profile to Link %s", get_cname());
+    bandwidth_.event = profile->schedule(&profile::future_evt_set, this);
+  }
+}
+
+void LinkImpl::set_latency_profile(profile::Profile* profile)
+{
+  if (profile) {
+    xbt_assert(latency_.event == nullptr, "Cannot set a second latency profile to Link %s", get_cname());
+    latency_.event = profile->schedule(&profile::future_evt_set, this);
+  }
+}
+
+void LinkImpl::set_concurrency_limit(int limit) const
+{
+  if (limit != -1) {
+    get_constraint()->reset_concurrency_maximum();
+  }
+  get_constraint()->set_concurrency_limit(limit);
+}
+
+} // namespace resource
+} // namespace kernel
+} // namespace simgrid
\ No newline at end of file
diff --git a/src/surf/LinkImpl.hpp b/src/surf/LinkImpl.hpp
new file mode 100644 (file)
index 0000000..5883775
--- /dev/null
@@ -0,0 +1,81 @@
+/* Copyright (c) 2004-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_RESOURCE_LINKIMPL_HPP
+#define SIMGRID_KERNEL_RESOURCE_LINKIMPL_HPP
+
+#include "src/surf/LinkImplIntf.hpp"
+
+/***********
+ * Classes *
+ ***********/
+
+namespace simgrid {
+namespace kernel {
+namespace resource {
+/************
+ * Resource *
+ ************/
+/** @ingroup SURF_network_interface
+ * @brief SURF network link interface class
+ * @details A Link represents the link between two [hosts](@ref simgrid::surf::HostImpl)
+ */
+class LinkImpl : public LinkImplIntf {
+  s4u::Link piface_;
+  s4u::Link::SharingPolicy sharing_policy_ = s4u::Link::SharingPolicy::SHARED;
+
+protected:
+  explicit LinkImpl(const std::string& name);
+  LinkImpl(const LinkImpl&) = delete;
+  LinkImpl& operator=(const LinkImpl&) = delete;
+  ~LinkImpl() override                 = default; // Use destroy() instead of this destructor.
+
+public:
+  void destroy(); // Must be called instead of the destructor
+
+  void latency_check(double latency) const;
+
+  /** @brief Public interface */
+  const s4u::Link* get_iface() const { return &piface_; }
+  s4u::Link* get_iface() { return &piface_; }
+
+  /** @brief Get the bandwidth in bytes per second of current Link */
+  double get_bandwidth() const override { return bandwidth_.peak * bandwidth_.scale; }
+
+  /** @brief Get the latency in seconds of current Link */
+  double get_latency() const override { return latency_.peak * latency_.scale; }
+
+  /** @brief The sharing policy */
+  virtual void set_sharing_policy(s4u::Link::SharingPolicy policy) override;
+  virtual s4u::Link::SharingPolicy get_sharing_policy() const override;
+
+  /** @brief Check if the Link is used */
+  bool is_used() const override;
+
+  void turn_on() override;
+  void turn_off() override;
+
+  void seal() override;
+
+  void on_bandwidth_change() const;
+
+  /* setup the profile file with bandwidth events (peak speed changes due to external load).
+   * Profile must contain percentages (value between 0 and 1). */
+  virtual void set_bandwidth_profile(kernel::profile::Profile* profile) override;
+  /* setup the profile file with latency events (peak latency changes due to external load).
+   * Profile must contain absolute values */
+  virtual void set_latency_profile(kernel::profile::Profile* profile) override;
+
+  void set_concurrency_limit(int limit) const override;
+
+  Metric latency_   = {0.0, 1, nullptr};
+  Metric bandwidth_ = {1.0, 1, nullptr};
+};
+
+} // namespace resource
+} // namespace kernel
+} // namespace simgrid
+
+#endif /* SIMGRID_KERNEL_RESOURCE_LINKIMPL_HPP */
diff --git a/src/surf/LinkImplIntf.hpp b/src/surf/LinkImplIntf.hpp
new file mode 100644 (file)
index 0000000..c9d3dac
--- /dev/null
@@ -0,0 +1,58 @@
+/* Copyright (c) 2004-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_RESOURCE_LINKIMPLINTF_HPP
+#define SIMGRID_KERNEL_RESOURCE_LINKIMPLINTF_HPP
+
+#include "simgrid/kernel/resource/Resource.hpp"
+#include "simgrid/s4u/Link.hpp"
+#include <xbt/PropertyHolder.hpp>
+
+/***********
+ * Classes *
+ ***********/
+
+namespace simgrid {
+namespace kernel {
+namespace resource {
+/************
+ * Resource *
+ ************/
+/** @ingroup SURF_interface
+ * @brief SURF network link interface class
+ * @details A Link represents the link between two [hosts](@ref simgrid::surf::HostImpl)
+ */
+class LinkImplIntf : public Resource_T<LinkImplIntf>, public xbt::PropertyHolder {
+public:
+  using Resource_T::Resource_T;
+  /** @brief Get the bandwidth in bytes per second of current Link */
+  virtual double get_bandwidth() const = 0;
+  /** @brief Update the bandwidth in bytes per second of current Link */
+  virtual void set_bandwidth(double value) = 0;
+
+  /** @brief Get the latency in seconds of current Link */
+  virtual double get_latency() const = 0;
+  /** @brief Update the latency in seconds of current Link */
+  virtual void set_latency(double value) = 0;
+
+  /** @brief The sharing policy */
+  virtual void set_sharing_policy(s4u::Link::SharingPolicy policy) = 0;
+  virtual s4u::Link::SharingPolicy get_sharing_policy() const      = 0;
+
+  /* setup the profile file with bandwidth events (peak speed changes due to external load).
+   * Profile must contain percentages (value between 0 and 1). */
+  virtual void set_bandwidth_profile(kernel::profile::Profile* profile) = 0;
+  /* setup the profile file with latency events (peak latency changes due to external load).
+   * Profile must contain absolute values */
+  virtual void set_latency_profile(kernel::profile::Profile* profile) = 0;
+  /** @brief Set the concurrency limit for this link */
+  virtual void set_concurrency_limit(int limit) const = 0;
+};
+
+} // namespace resource
+} // namespace kernel
+} // namespace simgrid
+
+#endif /* SIMGRID_KERNEL_RESOURCE_LINKIMPLINTF_HPP */
diff --git a/src/surf/SplitDuplexLinkImpl.cpp b/src/surf/SplitDuplexLinkImpl.cpp
new file mode 100644 (file)
index 0000000..329955a
--- /dev/null
@@ -0,0 +1,99 @@
+/* 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. */
+
+#include "src/surf/SplitDuplexLinkImpl.hpp"
+
+XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(res_network);
+
+/*********
+ * Model *
+ *********/
+
+namespace simgrid {
+namespace kernel {
+namespace resource {
+
+SplitDuplexLinkImpl::SplitDuplexLinkImpl(const std::string& name, LinkImpl* link_up, LinkImpl* link_down)
+    : LinkImplIntf(name), piface_(this), link_up_(link_up), link_down_(link_down)
+{
+}
+
+bool SplitDuplexLinkImpl::is_used() const
+{
+  xbt_die("Impossible to call is_used() in split-duplex links. Call it for each individual link.");
+}
+
+void SplitDuplexLinkImpl::set_sharing_policy(s4u::Link::SharingPolicy policy)
+{
+  xbt_die("Impossible to change sharing policy of split-duplex links");
+}
+
+s4u::Link::SharingPolicy SplitDuplexLinkImpl::get_sharing_policy() const
+{
+  return sharing_policy_;
+}
+
+void SplitDuplexLinkImpl::set_bandwidth(double value)
+{
+  link_up_->set_bandwidth(value);
+  link_down_->set_bandwidth(value);
+}
+
+void SplitDuplexLinkImpl::set_latency(double value)
+{
+  link_up_->set_latency(value);
+  link_down_->set_latency(value);
+}
+
+void SplitDuplexLinkImpl::turn_on()
+{
+  link_up_->turn_on();
+  link_down_->turn_on();
+}
+
+void SplitDuplexLinkImpl::turn_off()
+{
+  link_up_->turn_off();
+  link_down_->turn_off();
+}
+
+void SplitDuplexLinkImpl::apply_event(profile::Event* event, double value)
+{
+  link_up_->apply_event(event, value);
+  link_down_->apply_event(event, value);
+}
+
+void SplitDuplexLinkImpl::seal()
+{
+  if (is_sealed())
+    return;
+
+  link_up_->seal();
+  link_down_->seal();
+
+  Resource::seal();
+}
+
+void SplitDuplexLinkImpl::set_bandwidth_profile(profile::Profile* profile)
+{
+  link_up_->set_bandwidth_profile(profile);
+  link_down_->set_bandwidth_profile(profile);
+}
+
+void SplitDuplexLinkImpl::set_latency_profile(profile::Profile* profile)
+{
+  link_up_->set_latency_profile(profile);
+  link_down_->set_latency_profile(profile);
+}
+
+void SplitDuplexLinkImpl::set_concurrency_limit(int limit) const
+{
+  link_up_->set_concurrency_limit(limit);
+  link_down_->set_concurrency_limit(limit);
+}
+
+} // namespace resource
+} // namespace kernel
+} // namespace simgrid
\ No newline at end of file
diff --git a/src/surf/SplitDuplexLinkImpl.hpp b/src/surf/SplitDuplexLinkImpl.hpp
new file mode 100644 (file)
index 0000000..3158718
--- /dev/null
@@ -0,0 +1,81 @@
+/* Copyright (c) 2004-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_RESOURCE_SDLINKIMPL_HPP
+#define SIMGRID_KERNEL_RESOURCE_SDLINKIMPL_HPP
+
+#include "src/surf/LinkImpl.hpp"
+#include "src/surf/LinkImplIntf.hpp"
+
+/***********
+ * Classes *
+ ***********/
+
+namespace simgrid {
+namespace kernel {
+namespace resource {
+/************
+ * Resource *
+ ************/
+/** @ingroup SURF_network_interface
+ * @brief SURF network link interface class
+ * @details A Link represents the link between two [hosts](@ref simgrid::surf::HostImpl)
+ */
+class SplitDuplexLinkImpl : public LinkImplIntf {
+  s4u::SplitDuplexLink piface_;
+  s4u::Link::SharingPolicy sharing_policy_ = s4u::Link::SharingPolicy::SPLITDUPLEX;
+  LinkImpl* link_up_;
+  LinkImpl* link_down_;
+
+protected:
+  SplitDuplexLinkImpl(const LinkImpl&) = delete;
+  SplitDuplexLinkImpl& operator=(const LinkImpl&) = delete;
+
+public:
+  SplitDuplexLinkImpl(const std::string& name, LinkImpl* link_up, LinkImpl* link_down);
+  /** @brief Public interface */
+  const s4u::SplitDuplexLink* get_iface() const { return &piface_; }
+  s4u::SplitDuplexLink* get_iface() { return &piface_; }
+
+  /** @brief Get the bandwidth in bytes per second of current Link */
+  double get_bandwidth() const override { return link_up_->get_bandwidth(); }
+  void set_bandwidth(double value) override;
+
+  /** @brief Get the latency in seconds of current Link */
+  double get_latency() const override { return link_up_->get_latency(); }
+  void set_latency(double value) override;
+
+  /** @brief The sharing policy */
+  virtual void set_sharing_policy(s4u::Link::SharingPolicy policy) override;
+  virtual s4u::Link::SharingPolicy get_sharing_policy() const override;
+
+  /** @brief Get link composing this split-duplex link */
+  s4u::Link* get_link_up() const { return link_up_->get_iface(); }
+  s4u::Link* get_link_down() const { return link_down_->get_iface(); }
+
+  /** @brief Check if the Link is used */
+  bool is_used() const override;
+
+  void turn_on() override;
+  void turn_off() override;
+
+  void seal() override;
+
+  void apply_event(profile::Event* event, double value) override;
+
+  /* setup the profile file with bandwidth events (peak speed changes due to external load).
+   * Profile must contain percentages (value between 0 and 1). */
+  void set_bandwidth_profile(kernel::profile::Profile* profile) override;
+  /* setup the profile file with latency events (peak latency changes due to external load).
+   * Profile must contain absolute values */
+  void set_latency_profile(kernel::profile::Profile* profile) override;
+  void set_concurrency_limit(int limit) const override;
+};
+
+} // namespace resource
+} // namespace kernel
+} // namespace simgrid
+
+#endif /* SIMGRID_KERNEL_RESOURCE_SDLINKIMPL_HPP */
diff --git a/src/surf/SplitDuplexLinkImpl_test.cpp b/src/surf/SplitDuplexLinkImpl_test.cpp
new file mode 100644 (file)
index 0000000..25abf74
--- /dev/null
@@ -0,0 +1,75 @@
+/* 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/s4u/Engine.hpp"
+#include "simgrid/s4u/Link.hpp"
+#include "src/surf/SplitDuplexLinkImpl.hpp"
+
+TEST_CASE("SplitDuplexLink: create", "")
+{
+  simgrid::s4u::Engine e("test");
+  auto* zone = simgrid::s4u::create_star_zone("test");
+
+  SECTION("create string")
+  {
+    simgrid::s4u::Link* link_up;
+    simgrid::s4u::Link* link_down;
+    simgrid::s4u::SplitDuplexLink* link;
+    REQUIRE_NOTHROW(link = zone->create_split_duplex_link("link", "100GBps"));
+    REQUIRE(simgrid::s4u::SplitDuplexLink::by_name("link") == link);
+    REQUIRE_NOTHROW(link_up = simgrid::s4u::Link::by_name("link_UP"));
+    REQUIRE_NOTHROW(link_down = simgrid::s4u::Link::by_name("link_DOWN"));
+    REQUIRE(link_up->get_bandwidth() == 100e9);
+    REQUIRE(link_down->get_bandwidth() == 100e9);
+    REQUIRE(link_up == link->get_link_up());
+    REQUIRE(link_down == link->get_link_down());
+  }
+
+  SECTION("create double") { REQUIRE_NOTHROW(zone->create_split_duplex_link("link", 10e6)); }
+}
+
+TEST_CASE("SplitDuplexLink: sets", "")
+{
+  simgrid::s4u::Engine e("test");
+  auto* zone      = simgrid::s4u::create_star_zone("test");
+  auto* link      = zone->create_split_duplex_link("link", 100e6);
+  auto* link_up   = link->get_link_up();
+  auto* link_down = link->get_link_down();
+
+  SECTION("bandwidth")
+  {
+    double bw = 1e3;
+    link->set_bandwidth(bw);
+    REQUIRE(link_up->get_bandwidth() == bw);
+    REQUIRE(link_down->get_bandwidth() == bw);
+  }
+
+  SECTION("latency")
+  {
+    double lat = 1e-9;
+    link->set_latency(lat);
+    REQUIRE(link_up->get_latency() == lat);
+    REQUIRE(link_down->get_latency() == lat);
+  }
+
+  SECTION("turn on/off")
+  {
+    link->turn_off();
+    REQUIRE(not link_up->is_on());
+    REQUIRE(not link_down->is_on());
+    link->turn_on();
+    REQUIRE(link_up->is_on());
+    REQUIRE(link_down->is_on());
+  }
+
+  SECTION("concurrency_limit")
+  {
+    link->set_concurrency_limit(3);
+    REQUIRE(link_up->get_impl()->get_constraint()->get_concurrency_limit() == 3);
+    REQUIRE(link_down->get_impl()->get_constraint()->get_concurrency_limit() == 3);
+  }
+}
\ No newline at end of file
index d63c108..5b1f916 100644 (file)
@@ -87,9 +87,9 @@ NetworkCm02Model::NetworkCm02Model(const std::string& name) : NetworkModel(name)
   }
 
   set_maxmin_system(new lmm::System(select));
-  loopback_ = create_link("__loopback__", std::vector<double>{config::get_value<double>("network/loopback-bw")})
-                  ->set_sharing_policy(s4u::Link::SharingPolicy::FATPIPE)
-                  ->set_latency(config::get_value<double>("network/loopback-lat"));
+  loopback_ = create_link("__loopback__", std::vector<double>{config::get_value<double>("network/loopback-bw")});
+  loopback_->set_sharing_policy(s4u::Link::SharingPolicy::FATPIPE);
+  loopback_->set_latency(config::get_value<double>("network/loopback-lat"));
   loopback_->seal();
 }
 
@@ -130,12 +130,16 @@ void NetworkCm02Model::set_bw_factor_cb(const std::function<NetworkFactorCb>& cb
 LinkImpl* NetworkCm02Model::create_link(const std::string& name, const std::vector<double>& bandwidths)
 {
   xbt_assert(bandwidths.size() == 1, "Non-WIFI links must use only 1 bandwidth.");
-  return (new NetworkCm02Link(name, bandwidths[0], get_maxmin_system()))->set_model(this);
+  auto link = new NetworkCm02Link(name, bandwidths[0], get_maxmin_system());
+  link->set_model(this);
+  return link;
 }
 
 LinkImpl* NetworkCm02Model::create_wifi_link(const std::string& name, const std::vector<double>& bandwidths)
 {
-  return (new NetworkWifiLink(name, bandwidths, get_maxmin_system()))->set_model(this);
+  auto link = new NetworkWifiLink(name, bandwidths, get_maxmin_system());
+  link->set_model(this);
+  return link;
 }
 
 void NetworkCm02Model::update_actions_state_lazy(double now, double /*delta*/)
@@ -495,7 +499,7 @@ void NetworkCm02Link::set_bandwidth(double value)
   }
 }
 
-LinkImpl* NetworkCm02Link::set_latency(double value)
+void NetworkCm02Link::set_latency(double value)
 {
   latency_check(value);
 
@@ -528,7 +532,6 @@ LinkImpl* NetworkCm02Link::set_latency(double value)
     if (not action->is_suspended())
       get_model()->get_maxmin_system()->update_variable_penalty(action->get_variable(), action->sharing_penalty_);
   }
-  return this;
 }
 
 /**********
index 172a267..c962616 100644 (file)
@@ -77,7 +77,7 @@ public:
   NetworkCm02Link(const std::string& name, double bandwidth, lmm::System* system);
   void apply_event(kernel::profile::Event* event, double value) override;
   void set_bandwidth(double value) override;
-  LinkImpl* set_latency(double value) override;
+  void set_latency(double value) override;
 };
 
 /**********
index 2983342..16f5397 100644 (file)
@@ -54,126 +54,6 @@ double NetworkModel::next_occurring_event_full(double now)
   return minRes;
 }
 
-/************
- * Resource *
- ************/
-
-LinkImpl::LinkImpl(const std::string& name) : Resource_T(name), piface_(this)
-{
-  if (name != "__loopback__")
-    xbt_assert(not s4u::Link::by_name_or_null(name), "Link '%s' declared several times in the platform.", name.c_str());
-
-  s4u::Engine::get_instance()->link_register(name, &piface_);
-  XBT_DEBUG("Create link '%s'", name.c_str());
-}
-
-/** @brief Fire the required callbacks and destroy the object
- *
- * Don't delete directly a Link, call l->destroy() instead.
- */
-void LinkImpl::destroy()
-{
-  s4u::Link::on_destruction(this->piface_);
-  delete this;
-}
-
-bool LinkImpl::is_used() const
-{
-  return get_model()->get_maxmin_system()->constraint_used(get_constraint());
-}
-
-LinkImpl* LinkImpl::set_sharing_policy(s4u::Link::SharingPolicy policy)
-{
-  lmm::Constraint::SharingPolicy ct_policy = lmm::Constraint::SharingPolicy::SHARED;
-  if (policy == s4u::Link::SharingPolicy::FATPIPE)
-    ct_policy = lmm::Constraint::SharingPolicy::FATPIPE;
-  get_constraint()->set_sharing_policy(ct_policy);
-  sharing_policy_ = policy;
-  return this;
-}
-s4u::Link::SharingPolicy LinkImpl::get_sharing_policy() const
-{
-  return sharing_policy_;
-}
-
-void LinkImpl::latency_check(double latency) const
-{
-  static double last_warned_latency = sg_surf_precision;
-  if (latency != 0.0 && latency < last_warned_latency) {
-    XBT_WARN("Latency for link %s is smaller than surf/precision (%g < %g)."
-        " For more accuracy, consider setting \"--cfg=surf/precision:%g\".",
-        get_cname(), latency, sg_surf_precision, latency);
-    last_warned_latency = latency;
-  }
-}
-
-void LinkImpl::turn_on()
-{
-  if (not is_on()) {
-    Resource::turn_on();
-    s4u::Link::on_state_change(piface_);
-  }
-}
-
-void LinkImpl::turn_off()
-{
-  if (is_on()) {
-    Resource::turn_off();
-    s4u::Link::on_state_change(piface_);
-
-    const kernel::lmm::Element* elem = nullptr;
-    double now                       = surf_get_clock();
-    while (const auto* var = get_constraint()->get_variable(&elem)) {
-      Action* action = var->get_id();
-      if (action->get_state() == Action::State::INITED || action->get_state() == Action::State::STARTED) {
-        action->set_finish_time(now);
-        action->set_state(Action::State::FAILED);
-      }
-    }
-  }
-}
-
-void LinkImpl::seal()
-{
-  if (is_sealed())
-    return;
-
-  xbt_assert(this->get_model(), "Cannot seal Link(%s) without setting the Network model first", this->get_cname());
-  Resource::seal();
-  s4u::Link::on_creation(piface_);
-}
-
-void LinkImpl::on_bandwidth_change() const
-{
-  s4u::Link::on_bandwidth_change(piface_);
-}
-
-LinkImpl* LinkImpl::set_bandwidth_profile(profile::Profile* profile)
-{
-  if (profile) {
-    xbt_assert(bandwidth_.event == nullptr, "Cannot set a second bandwidth profile to Link %s", get_cname());
-    bandwidth_.event = profile->schedule(&profile::future_evt_set, this);
-  }
-  return this;
-}
-
-LinkImpl* LinkImpl::set_latency_profile(profile::Profile* profile)
-{
-  if (profile) {
-    xbt_assert(latency_.event == nullptr, "Cannot set a second latency profile to Link %s", get_cname());
-    latency_.event = profile->schedule(&profile::future_evt_set, this);
-  }
-  return this;
-}
-
-void LinkImpl::set_concurrency_limit(int limit) const
-{
-  if (limit != -1) {
-    get_constraint()->reset_concurrency_maximum();
-  }
-  get_constraint()->set_concurrency_limit(limit);
-}
-
 /**********
  * Action *
  **********/
index 3917de1..1f712a6 100644 (file)
@@ -11,6 +11,7 @@
 #include "simgrid/kernel/resource/Resource.hpp"
 #include "simgrid/s4u/Link.hpp"
 #include "src/kernel/lmm/maxmin.hpp"
+#include "src/surf/LinkImpl.hpp"
 #include <xbt/PropertyHolder.hpp>
 
 #include <list>
@@ -93,69 +94,6 @@ public:
   LinkImpl* loopback_ = nullptr;
 };
 
-/************
- * Resource *
- ************/
-/** @ingroup SURF_network_interface
- * @brief SURF network link interface class
- * @details A Link represents the link between two [hosts](@ref simgrid::surf::HostImpl)
- */
-class LinkImpl : public Resource_T<LinkImpl>, public xbt::PropertyHolder {
-  s4u::Link piface_;
-  s4u::Link::SharingPolicy sharing_policy_ = s4u::Link::SharingPolicy::SHARED;
-
-protected:
-  explicit LinkImpl(const std::string& name);
-  LinkImpl(const LinkImpl&) = delete;
-  LinkImpl& operator=(const LinkImpl&) = delete;
-  ~LinkImpl() override                 = default; // Use destroy() instead of this destructor.
-
-public:
-  void destroy(); // Must be called instead of the destructor
-
-  void latency_check(double latency) const;
-
-  /** @brief Public interface */
-  const s4u::Link* get_iface() const { return &piface_; }
-  s4u::Link* get_iface() { return &piface_; }
-
-  /** @brief Get the bandwidth in bytes per second of current Link */
-  double get_bandwidth() const { return bandwidth_.peak * bandwidth_.scale; }
-  /** @brief Update the bandwidth in bytes per second of current Link */
-  virtual void set_bandwidth(double value) = 0;
-
-  /** @brief Get the latency in seconds of current Link */
-  double get_latency() const { return latency_.peak * latency_.scale; }
-  /** @brief Update the latency in seconds of current Link */
-  virtual LinkImpl* set_latency(double value) = 0;
-
-  /** @brief The sharing policy */
-  virtual LinkImpl* set_sharing_policy(s4u::Link::SharingPolicy policy);
-  virtual s4u::Link::SharingPolicy get_sharing_policy() const;
-
-  /** @brief Check if the Link is used */
-  bool is_used() const override;
-
-  void turn_on() override;
-  void turn_off() override;
-
-  void seal() override;
-
-  void on_bandwidth_change() const;
-
-  /* setup the profile file with bandwidth events (peak speed changes due to external load).
-   * Profile must contain percentages (value between 0 and 1). */
-  virtual LinkImpl* set_bandwidth_profile(kernel::profile::Profile* profile);
-  /* setup the profile file with latency events (peak latency changes due to external load).
-   * Profile must contain absolute values */
-  virtual LinkImpl* set_latency_profile(kernel::profile::Profile* profile);
-
-  void set_concurrency_limit(int limit) const;
-
-  Metric latency_   = {0.0, 1, nullptr};
-  Metric bandwidth_ = {1.0, 1, nullptr};
-};
-
 /**********
  * Action *
  **********/
index 1180f02..81839ef 100644 (file)
@@ -330,19 +330,23 @@ NetworkNS3Model::NetworkNS3Model(const std::string& name) : NetworkModel(name)
     ns3::GlobalRouteManager::InitializeRoutes();
   });
   routing::on_cluster_creation.connect(&clusterCreation_cb);
-  s4u::NetZone::on_route_creation.connect(&routeCreation_cb);
+  routing::NetZoneImpl::on_route_creation.connect(&routeCreation_cb);
   s4u::NetZone::on_seal.connect(&zoneCreation_cb);
 }
 
 LinkImpl* NetworkNS3Model::create_link(const std::string& name, const std::vector<double>& bandwidths)
 {
   xbt_assert(bandwidths.size() == 1, "ns-3 links must use only 1 bandwidth.");
-  return (new LinkNS3(name, bandwidths[0]))->set_model(this);
+  auto* link = new LinkNS3(name, bandwidths[0]);
+  link->set_model(this);
+  return link;
 }
 
 LinkImpl* NetworkNS3Model::create_wifi_link(const std::string& name, const std::vector<double>& bandwidths)
 {
-  return create_link(name, bandwidths)->set_sharing_policy(s4u::Link::SharingPolicy::WIFI);
+  auto* link = create_link(name, bandwidths);
+  link->set_sharing_policy(s4u::Link::SharingPolicy::WIFI);
+  return link;
 }
 
 Action* NetworkNS3Model::communicate(s4u::Host* src, s4u::Host* dst, double size, double rate)
@@ -455,28 +459,24 @@ void LinkNS3::apply_event(profile::Event*, double)
   THROW_UNIMPLEMENTED;
 }
 
-LinkImpl* LinkNS3::set_bandwidth_profile(profile::Profile* profile)
+void LinkNS3::set_bandwidth_profile(profile::Profile* profile)
 {
   xbt_assert(profile == nullptr, "The ns-3 network model doesn't support bandwidth profiles");
-  return this;
 }
 
-LinkImpl* LinkNS3::set_latency_profile(profile::Profile* profile)
+void LinkNS3::set_latency_profile(profile::Profile* profile)
 {
   xbt_assert(profile == nullptr, "The ns-3 network model doesn't support latency profiles");
-  return this;
 }
 
-LinkImpl* LinkNS3::set_latency(double latency)
+void LinkNS3::set_latency(double latency)
 {
   latency_.peak = latency;
-  return this;
 }
 
-LinkImpl* LinkNS3::set_sharing_policy(s4u::Link::SharingPolicy policy)
+void LinkNS3::set_sharing_policy(s4u::Link::SharingPolicy policy)
 {
   sharing_policy_ = policy;
-  return this;
 }
 /**********
  * Action *
index 7db4a38..c0a8e11 100644 (file)
@@ -36,10 +36,10 @@ public:
 
   void apply_event(profile::Event* event, double value) override;
   void set_bandwidth(double) override { THROW_UNIMPLEMENTED; }
-  LinkImpl* set_latency(double) override;
-  LinkImpl* set_bandwidth_profile(profile::Profile* profile) override;
-  LinkImpl* set_latency_profile(profile::Profile* profile) override;
-  LinkImpl* set_sharing_policy(s4u::Link::SharingPolicy policy) override;
+  void set_latency(double) override;
+  void set_bandwidth_profile(profile::Profile* profile) override;
+  void set_latency_profile(profile::Profile* profile) override;
+  void set_sharing_policy(s4u::Link::SharingPolicy policy) override;
   s4u::Link::SharingPolicy get_sharing_policy() const override { return sharing_policy_; }
 };
 
index 655941c..c82d321 100644 (file)
@@ -91,10 +91,9 @@ bool NetworkWifiLink::toggle_decay_model(){
   return use_decay_model_;
 }
 
-LinkImpl* NetworkWifiLink::set_latency(double value)
+void NetworkWifiLink::set_latency(double value)
 {
   xbt_assert(value == 0, "Latency cannot be set for WiFi Links.");
-  return this;
 }
 } // namespace resource
 } // namespace kernel
index 9a8d5e8..6f5ad35 100644 (file)
@@ -51,7 +51,7 @@ public:
   s4u::Link::SharingPolicy get_sharing_policy() const override;
   void apply_event(kernel::profile::Event*, double) override { THROW_UNIMPLEMENTED; }
   void set_bandwidth(double) override { THROW_UNIMPLEMENTED; }
-  LinkImpl* set_latency(double) override;
+  void set_latency(double) override;
   void refresh_decay_bandwidths();
   bool toggle_decay_model();
   int get_host_count() const;
index 169d528..cf9f2a1 100644 (file)
@@ -62,9 +62,9 @@ NetworkL07Model::NetworkL07Model(const std::string& name, HostL07Model* hmodel,
 {
   set_maxmin_system(sys);
   loopback_ =
-      create_link("__loopback__", std::vector<double>{simgrid::config::get_value<double>("network/loopback-bw")})
-          ->set_sharing_policy(s4u::Link::SharingPolicy::FATPIPE)
-          ->set_latency(simgrid::config::get_value<double>("network/loopback-lat"));
+      create_link("__loopback__", std::vector<double>{simgrid::config::get_value<double>("network/loopback-bw")});
+  loopback_->set_sharing_policy(s4u::Link::SharingPolicy::FATPIPE);
+  loopback_->set_latency(simgrid::config::get_value<double>("network/loopback-lat"));
   loopback_->seal();
 }
 
@@ -241,7 +241,9 @@ kernel::resource::CpuImpl* CpuL07Model::create_cpu(s4u::Host* host, const std::v
 kernel::resource::LinkImpl* NetworkL07Model::create_link(const std::string& name, const std::vector<double>& bandwidths)
 {
   xbt_assert(bandwidths.size() == 1, "Non WIFI link must have only 1 bandwidth.");
-  return (new LinkL07(name, bandwidths[0], get_maxmin_system()))->set_model(this);
+  auto link = new LinkL07(name, bandwidths[0], get_maxmin_system());
+  link->set_model(this);
+  return link;
 }
 
 kernel::resource::LinkImpl* NetworkL07Model::create_wifi_link(const std::string& name,
@@ -362,7 +364,7 @@ void LinkL07::set_bandwidth(double value)
   get_model()->get_maxmin_system()->update_constraint_bound(get_constraint(), bandwidth_.peak * bandwidth_.scale);
 }
 
-kernel::resource::LinkImpl* LinkL07::set_latency(double value)
+void LinkL07::set_latency(double value)
 {
   latency_check(value);
   const kernel::lmm::Element* elem = nullptr;
@@ -372,7 +374,6 @@ kernel::resource::LinkImpl* LinkL07::set_latency(double value)
     auto* action = static_cast<L07Action*>(var->get_id());
     action->updateBound();
   }
-  return this;
 }
 LinkL07::~LinkL07() = default;
 
index f153895..d211954 100644 (file)
@@ -113,7 +113,7 @@ public:
   bool is_used() const override;
   void apply_event(kernel::profile::Event* event, double value) override;
   void set_bandwidth(double value) override;
-  LinkImpl* set_latency(double value) override;
+  void set_latency(double value) override;
 };
 
 /**********
index d015d71..0774f2a 100644 (file)
@@ -114,27 +114,26 @@ simgrid::kernel::routing::NetPoint* sg_platf_new_router(const std::string& name,
   return netpoint;
 }
 
-static void sg_platf_new_link(const simgrid::kernel::routing::LinkCreationArgs* args, const std::string& link_name)
+static void sg_platf_set_link_properties(simgrid::s4u::Link* link,
+                                         const simgrid::kernel::routing::LinkCreationArgs* args)
 {
-  current_routing->create_link(link_name, args->bandwidths)
-      ->set_properties(args->properties)
-      ->get_impl() // this call to get_impl saves some simcalls but can be removed
-      ->set_sharing_policy(args->policy)
+  link->set_properties(args->properties)
       ->set_state_profile(args->state_trace)
       ->set_latency_profile(args->latency_trace)
       ->set_bandwidth_profile(args->bandwidth_trace)
-      ->set_latency(args->latency)
-      ->seal();
+      ->set_latency(args->latency);
 }
 
-void sg_platf_new_link(const simgrid::kernel::routing::LinkCreationArgs* link)
+void sg_platf_new_link(const simgrid::kernel::routing::LinkCreationArgs* args)
 {
-  if (link->policy == simgrid::s4u::Link::SharingPolicy::SPLITDUPLEX) {
-    sg_platf_new_link(link, link->id + "_UP");
-    sg_platf_new_link(link, link->id + "_DOWN");
+  simgrid::s4u::Link* link;
+  if (args->policy == simgrid::s4u::Link::SharingPolicy::SPLITDUPLEX) {
+    link = current_routing->create_split_duplex_link(args->id, args->bandwidths);
   } else {
-    sg_platf_new_link(link, link->id);
+    link = current_routing->create_link(args->id, args->bandwidths)->set_sharing_policy(args->policy);
   }
+  sg_platf_set_link_properties(link, args);
+  link->seal();
 }
 
 void sg_platf_new_disk(const simgrid::kernel::routing::DiskCreationArgs* disk)
@@ -295,7 +294,7 @@ static void sg_platf_new_cluster_flat(simgrid::kernel::routing::ClusterCreationA
                            ->seal();
 
       zone->add_route(host->get_netpoint(), host->get_netpoint(), nullptr, nullptr,
-                      std::vector<simgrid::s4u::Link*>{loopback});
+                      std::vector<simgrid::s4u::LinkInRoute>{loopback});
     }
 
     // add a limiter link (shared link to account for maximal bandwidth of the node)
@@ -308,25 +307,22 @@ static void sg_platf_new_cluster_flat(simgrid::kernel::routing::ClusterCreationA
     }
 
     // create link
-    simgrid::s4u::Link* link_up;
-    simgrid::s4u::Link* link_down;
+    simgrid::s4u::Link* link;
     if (cluster->sharing_policy == simgrid::s4u::Link::SharingPolicy::SPLITDUPLEX) {
-      link_up = zone->create_link(link_id + "_UP", std::vector<double>{cluster->bw})->set_latency(cluster->lat)->seal();
-      link_down =
-          zone->create_link(link_id + "_DOWN", std::vector<double>{cluster->bw})->set_latency(cluster->lat)->seal();
+      link = zone->create_split_duplex_link(link_id, cluster->bw)->set_latency(cluster->lat)->seal();
     } else {
-      link_up   = zone->create_link(link_id, std::vector<double>{cluster->bw})->set_latency(cluster->lat)->seal();
-      link_down = link_up;
+      link = zone->create_link(link_id, std::vector<double>{cluster->bw})->set_latency(cluster->lat)->seal();
     }
 
     /* adding routes */
-    std::vector<simgrid::s4u::Link*> links_up{limiter, link_up, backbone};
-    std::vector<simgrid::s4u::Link*> links_down{backbone, link_down, limiter};
-    links_up.erase(std::remove(links_up.begin(), links_up.end(), nullptr), links_up.end());
-    links_down.erase(std::remove(links_down.begin(), links_down.end(), nullptr), links_down.end());
-
-    zone->add_route(host->get_netpoint(), nullptr, nullptr, nullptr, links_up, false);
-    zone->add_route(nullptr, host->get_netpoint(), nullptr, nullptr, links_down, false);
+    std::vector<simgrid::s4u::LinkInRoute> links;
+    if (limiter)
+      links.push_back(limiter);
+    links.push_back(simgrid::s4u::LinkInRoute(link, simgrid::s4u::LinkInRoute::Direction::UP));
+    if (backbone)
+      links.push_back(backbone);
+
+    zone->add_route(host->get_netpoint(), nullptr, nullptr, nullptr, links, true);
   }
 
   // Add a router.
@@ -359,22 +355,22 @@ void sg_platf_new_tag_cluster(simgrid::kernel::routing::ClusterCreationArgs* clu
 static void sg_platf_cluster_set_hostlink(simgrid::kernel::routing::StarZone* zone,
                                           simgrid::kernel::routing::NetPoint* netpoint,
                                           const simgrid::s4u::Link* link_up, const simgrid::s4u::Link* link_down,
-                                          simgrid::kernel::resource::LinkImpl* backbone)
+                                          simgrid::s4u::Link* backbone)
 {
   XBT_DEBUG("Push Host_link for host '%s' to position %u", netpoint->get_cname(), netpoint->id());
   if (backbone) {
-    zone->add_route(netpoint, nullptr, nullptr, nullptr, {link_up->get_impl(), backbone}, false);
-    zone->add_route(nullptr, netpoint, nullptr, nullptr, {backbone, link_down->get_impl()}, false);
+    zone->add_route(netpoint, nullptr, nullptr, nullptr, {link_up, backbone}, false);
+    zone->add_route(nullptr, netpoint, nullptr, nullptr, {backbone, link_down}, false);
   } else {
-    zone->add_route(netpoint, nullptr, nullptr, nullptr, {link_up->get_impl()}, false);
-    zone->add_route(nullptr, netpoint, nullptr, nullptr, {link_down->get_impl()}, false);
+    zone->add_route(netpoint, nullptr, nullptr, nullptr, {link_up}, false);
+    zone->add_route(nullptr, netpoint, nullptr, nullptr, {link_down}, false);
   }
 }
 
 /** @brief Add a link connecting a host to the rest of its StarZone */
 static void sg_platf_build_hostlink(simgrid::kernel::routing::StarZone* zone,
                                     const simgrid::kernel::routing::HostLinkCreationArgs* hostlink,
-                                    simgrid::kernel::resource::LinkImpl* backbone)
+                                    simgrid::s4u::Link* backbone)
 {
   simgrid::kernel::routing::NetPoint* netpoint = simgrid::s4u::Host::by_name(hostlink->id)->get_netpoint();
   xbt_assert(netpoint, "Host '%s' not found!", hostlink->id.c_str());
@@ -390,7 +386,7 @@ static void sg_platf_build_hostlink(simgrid::kernel::routing::StarZone* zone,
 /** @brief Create a cabinet (set of hosts) inside a Cluster(StarZone) */
 static void sg_platf_build_cabinet(simgrid::kernel::routing::StarZone* zone,
                                    const simgrid::kernel::routing::CabinetCreationArgs* args,
-                                   simgrid::kernel::resource::LinkImpl* backbone)
+                                   simgrid::s4u::Link* backbone)
 {
   for (int const& radical : args->radicals) {
     std::string id   = args->prefix + std::to_string(radical) + args->suffix;
@@ -410,11 +406,11 @@ static void sg_platf_zone_cluster_populate(const simgrid::kernel::routing::Clust
   auto* zone = dynamic_cast<simgrid::kernel::routing::StarZone*>(current_routing);
   xbt_assert(zone, "Host_links are only valid for Cluster(Star)");
 
-  simgrid::kernel::resource::LinkImpl* backbone = nullptr;
+  simgrid::s4u::Link* backbone = nullptr;
   /* create backbone */
   if (cluster->backbone) {
     sg_platf_new_link(cluster->backbone.get());
-    backbone = simgrid::s4u::Link::by_name(cluster->backbone->id)->get_impl();
+    backbone = simgrid::s4u::Link::by_name(cluster->backbone->id);
   }
 
   /* create host_links for hosts */
@@ -448,8 +444,7 @@ void sg_platf_new_route(simgrid::kernel::routing::RouteCreationArgs* route)
 
 void sg_platf_new_bypass_route(simgrid::kernel::routing::RouteCreationArgs* route)
 {
-  current_routing->add_bypass_route(route->src, route->dst, route->gw_src, route->gw_dst, route->link_list,
-                                    route->symmetrical);
+  current_routing->add_bypass_route(route->src, route->dst, route->gw_src, route->gw_dst, route->link_list);
 }
 
 void sg_platf_new_actor(simgrid::kernel::routing::ActorCreationArgs* actor)
index 044ed0a..763f963 100644 (file)
@@ -80,7 +80,7 @@ public:
   NetPoint* dst    = nullptr;
   NetPoint* gw_src = nullptr;
   NetPoint* gw_dst = nullptr;
-  std::vector<resource::LinkImpl*> link_list;
+  std::vector<simgrid::s4u::LinkInRoute> link_list;
 };
 
 enum class ClusterTopology { DRAGONFLY = 3, FAT_TREE = 2, FLAT = 1, TORUS = 0 };
index 58eefa2..1a0edf9 100644 (file)
@@ -28,8 +28,7 @@
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_parse, surf, "Logging specific to the SURF parsing module");
 
 std::string surf_parsed_filename; // Currently parsed file (for the error messages)
-std::vector<simgrid::kernel::resource::LinkImpl*>
-    parsed_link_list; /* temporary store of current link list of a route */
+std::vector<simgrid::s4u::LinkInRoute> parsed_link_list; /* temporary store of current link list of a route */
 
 /* Helping functions */
 void surf_parse_assert(bool cond, const std::string& msg)
@@ -482,17 +481,20 @@ void ETag_surfxml_link(){
 
 void STag_surfxml_link___ctn()
 {
-  simgrid::kernel::resource::LinkImpl* link = nullptr;
+  simgrid::s4u::Link* link;
+  simgrid::s4u::LinkInRoute::Direction direction = simgrid::s4u::LinkInRoute::Direction::NONE;
   switch (A_surfxml_link___ctn_direction) {
   case AU_surfxml_link___ctn_direction:
   case A_surfxml_link___ctn_direction_NONE:
-    link = simgrid::s4u::Link::by_name(std::string(A_surfxml_link___ctn_id))->get_impl();
+    link = simgrid::s4u::Link::by_name(std::string(A_surfxml_link___ctn_id));
     break;
   case A_surfxml_link___ctn_direction_UP:
-    link = simgrid::s4u::Link::by_name(std::string(A_surfxml_link___ctn_id) + "_UP")->get_impl();
+    link      = simgrid::s4u::SplitDuplexLink::by_name(std::string(A_surfxml_link___ctn_id));
+    direction = simgrid::s4u::LinkInRoute::Direction::UP;
     break;
   case A_surfxml_link___ctn_direction_DOWN:
-    link = simgrid::s4u::Link::by_name(std::string(A_surfxml_link___ctn_id) + "_DOWN")->get_impl();
+    link      = simgrid::s4u::SplitDuplexLink::by_name(std::string(A_surfxml_link___ctn_id));
+    direction = simgrid::s4u::LinkInRoute::Direction::DOWN;
     break;
   default:
     surf_parse_error(std::string("Invalid direction for link ") + A_surfxml_link___ctn_id);
@@ -510,7 +512,7 @@ void STag_surfxml_link___ctn()
       dirname = "";
   }
   surf_parse_assert(link != nullptr, std::string("No such link: '") + A_surfxml_link___ctn_id + "'" + dirname);
-  parsed_link_list.push_back(link);
+  parsed_link_list.emplace_back(simgrid::s4u::LinkInRoute(link, direction));
 }
 
 void ETag_surfxml_backbone()
index 512362d..0701900 100644 (file)
@@ -70,7 +70,7 @@ static sg4::NetZone* create_zone(const sg4::NetZone* root, const std::string& id
     auto* host           = zone->create_host(hostname, 1e9);
     host->create_disk("disk-" + hostname, 1e9, 1e6);
     auto* link = zone->create_link("link-" + hostname, 1e9);
-    zone->add_route(host->get_netpoint(), router, nullptr, nullptr, std::vector<sg4::Link*>{link});
+    zone->add_route(host->get_netpoint(), router, nullptr, nullptr, std::vector<sg4::LinkInRoute>{link});
   }
   return zone;
 }
@@ -87,7 +87,7 @@ int main(int argc, char* argv[])
   auto* zoneB = create_zone(root, "B");
   auto* link  = root->create_link("root-link", 1e10);
   root->add_route(zoneA->get_netpoint(), zoneB->get_netpoint(), e.netpoint_by_name("routerA"),
-                  e.netpoint_by_name("routerB"), std::vector<sg4::Link*>{link});
+                  e.netpoint_by_name("routerB"), std::vector<sg4::LinkInRoute>{link});
 
   std::vector<sg4::Host*> host_list = e.get_all_hosts();
   /* create the sender actor running on first host */
index aa134d7..8935cba 100644 (file)
@@ -1490,3 +1490,28 @@ $ ${bindir:=.}/flatifier ../platforms/cluster_torus_noncontiguous_rad.xml "--log
 >   </route>
 > </AS>
 > </platform>
+$ ${bindir:=.}/flatifier ../platforms/two_hosts_one_link_splitduplex.xml "--log=root.fmt:[%10.6r]%e[%i:%a@%h]%e%m%n"
+> <?xml version='1.0'?>
+> <!DOCTYPE platform SYSTEM "https://simgrid.org/simgrid.dtd">
+> <platform version="4">
+> <AS id="AS0" routing="Full">
+>   <host id="alice" speed="500000000"/>
+>   <host id="bob" speed="1000000000"/>
+>   <link id="__loopback__" bandwidth="10000000000" latency="0.000000000" sharing_policy="FATPIPE"/>
+>   <link id="link1_DOWN" bandwidth="125000000" latency="0.000050000"/>
+>   <link id="link1_UP" bandwidth="125000000" latency="0.000050000"/>
+>   <route src="alice" dst="alice">
+>   <link_ctn id="__loopback__"/>
+>   </route>
+>   <route src="alice" dst="bob">
+>   <link_ctn id="link1_UP"/>
+>   </route>
+>   <route src="bob" dst="alice">
+>   <link_ctn id="link1_DOWN"/>
+>   </route>
+>   <route src="bob" dst="bob">
+>   <link_ctn id="__loopback__"/>
+>   </route>
+> </AS>
+> </platform>
+
index 7e766ff..f121533 100644 (file)
@@ -7,11 +7,8 @@
 
     <link id="link1" bandwidth="125MBps" latency="50us" sharing_policy="SPLITDUPLEX"/>
 
-    <route src="alice" dst="bob" symmetrical="NO">
+    <route src="alice" dst="bob" symmetrical="YES">
       <link_ctn id="link1" direction="UP"/>
     </route>
-    <route src="bob" dst="alice" symmetrical="NO">
-      <link_ctn id="link1" direction="DOWN"/>
-    </route>
   </zone>
 </platform>
index 9cb8960..50b5d46 100644 (file)
@@ -41,6 +41,9 @@ set(EXTRA_DIST
   src/surf/network_cm02.hpp
   src/surf/network_constant.hpp
   src/surf/network_interface.hpp
+  src/surf/LinkImpl.hpp
+  src/surf/LinkImplIntf.hpp
+  src/surf/SplitDuplexLinkImpl.hpp
   src/surf/network_ns3.hpp
   src/surf/network_smpi.hpp
   src/surf/network_ib.hpp
@@ -348,6 +351,8 @@ set(SURF_SRC
   src/surf/network_cm02.cpp
   src/surf/network_constant.cpp
   src/surf/network_interface.cpp
+  src/surf/LinkImpl.cpp
+  src/surf/SplitDuplexLinkImpl.cpp
   src/surf/network_wifi.cpp
   src/surf/sg_platf.cpp
   src/surf/surf_c_bindings.cpp
index 2c6ea4c..fb4291c 100644 (file)
@@ -132,6 +132,7 @@ set(UNIT_TESTS  src/xbt/unit-tests_main.cpp
                 src/kernel/routing/FullZone_test.cpp
                 src/kernel/routing/StarZone_test.cpp
                 src/kernel/routing/TorusZone_test.cpp
+                src/surf/SplitDuplexLinkImpl_test.cpp
                 src/xbt/config_test.cpp
                 src/xbt/dict_test.cpp
                 src/xbt/dynar_test.cpp