Add support of auto IP generation in network emulation manager.

Bug: webrtc:10138
Change-Id: If50195ae44fb4d01fae1dd17a8d78a2a23b63b01
Reviewed-on: https://webrtc-review.googlesource.com/c/123191
Commit-Queue: Artem Titov <titovartem@webrtc.org>
Reviewed-by: Sebastian Jansson <srte@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26851}
diff --git a/test/pc/e2e/peer_connection_e2e_smoke_test.cc b/test/pc/e2e/peer_connection_e2e_smoke_test.cc
index e20ba52..54889a8 100644
--- a/test/pc/e2e/peer_connection_e2e_smoke_test.cc
+++ b/test/pc/e2e/peer_connection_e2e_smoke_test.cc
@@ -73,9 +73,9 @@
   EmulatedNetworkNode* bob_node = network_emulation_manager.CreateEmulatedNode(
       absl::make_unique<SimulatedNetwork>(BuiltInNetworkBehaviorConfig()));
   EndpointNode* alice_endpoint =
-      network_emulation_manager.CreateEndpoint(rtc::IPAddress(1));
+      network_emulation_manager.CreateEndpoint(EndpointConfig());
   EndpointNode* bob_endpoint =
-      network_emulation_manager.CreateEndpoint(rtc::IPAddress(2));
+      network_emulation_manager.CreateEndpoint(EndpointConfig());
   network_emulation_manager.CreateRoute(alice_endpoint, {alice_node},
                                         bob_endpoint);
   network_emulation_manager.CreateRoute(bob_endpoint, {bob_node},
diff --git a/test/scenario/network/network_emulation_manager.cc b/test/scenario/network/network_emulation_manager.cc
index 2d83936..1c9f249 100644
--- a/test/scenario/network/network_emulation_manager.cc
+++ b/test/scenario/network/network_emulation_manager.cc
@@ -22,12 +22,24 @@
 namespace {
 
 constexpr int64_t kPacketProcessingIntervalMs = 1;
+// uint32_t representation of 192.168.0.0 address
+constexpr uint32_t kMinIPv4Address = 0xC0A80000;
+// uint32_t representation of 192.168.255.255 address
+constexpr uint32_t kMaxIPv4Address = 0xC0A8FFFF;
 
 }  // namespace
 
+EndpointConfig::EndpointConfig() = default;
+EndpointConfig::~EndpointConfig() = default;
+EndpointConfig::EndpointConfig(EndpointConfig&) = default;
+EndpointConfig& EndpointConfig::operator=(EndpointConfig&) = default;
+EndpointConfig::EndpointConfig(EndpointConfig&&) = default;
+EndpointConfig& EndpointConfig::operator=(EndpointConfig&&) = default;
+
 NetworkEmulationManager::NetworkEmulationManager()
     : clock_(Clock::GetRealTimeClock()),
       next_node_id_(1),
+      next_ip4_address_(kMinIPv4Address),
       task_queue_("network_emulation_manager") {
   process_task_handle_ = RepeatingTaskHandle::Start(&task_queue_, [this] {
     ProcessNetworkPackets();
@@ -55,8 +67,25 @@
   return out;
 }
 
-EndpointNode* NetworkEmulationManager::CreateEndpoint(rtc::IPAddress ip) {
-  auto node = absl::make_unique<EndpointNode>(next_node_id_++, ip, clock_);
+EndpointNode* NetworkEmulationManager::CreateEndpoint(EndpointConfig config) {
+  absl::optional<rtc::IPAddress> ip = config.ip;
+  if (!ip) {
+    switch (config.generated_ip_family) {
+      case EndpointConfig::IpAddressFamily::kIpv4:
+        ip = GetNextIPv4Address();
+        RTC_CHECK(ip) << "All auto generated IPv4 addresses exhausted";
+        break;
+      case EndpointConfig::IpAddressFamily::kIpv6:
+        ip = GetNextIPv4Address();
+        RTC_CHECK(ip) << "All auto generated IPv6 addresses exhausted";
+        ip = ip->AsIPv6Address();
+        break;
+    }
+  }
+
+  bool res = used_ip_addresses_.insert(*ip).second;
+  RTC_CHECK(res) << "IP=" << ip->ToString() << " already in use";
+  auto node = absl::make_unique<EndpointNode>(next_node_id_++, *ip, clock_);
   EndpointNode* out = node.get();
   endpoints_.push_back(std::move(node));
   return out;
@@ -98,7 +127,7 @@
 TrafficRoute* NetworkEmulationManager::CreateTrafficRoute(
     std::vector<EmulatedNetworkNode*> via_nodes) {
   RTC_CHECK(!via_nodes.empty());
-  EndpointNode* endpoint = CreateEndpoint(rtc::IPAddress(next_node_id_++));
+  EndpointNode* endpoint = CreateEndpoint(EndpointConfig());
 
   // Setup a route via specified nodes.
   EmulatedNetworkNode* cur_node = via_nodes[0];
@@ -171,6 +200,22 @@
   return out;
 }
 
+absl::optional<rtc::IPAddress> NetworkEmulationManager::GetNextIPv4Address() {
+  uint32_t addresses_count = kMaxIPv4Address - kMinIPv4Address;
+  for (uint32_t i = 0; i < addresses_count; i++) {
+    rtc::IPAddress ip(next_ip4_address_);
+    if (next_ip4_address_ == kMaxIPv4Address) {
+      next_ip4_address_ = kMinIPv4Address;
+    } else {
+      next_ip4_address_++;
+    }
+    if (used_ip_addresses_.find(ip) == used_ip_addresses_.end()) {
+      return ip;
+    }
+  }
+  return absl::nullopt;
+}
+
 void NetworkEmulationManager::ProcessNetworkPackets() {
   Timestamp current_time = Now();
   for (auto& traffic : random_cross_traffics_) {
diff --git a/test/scenario/network/network_emulation_manager.h b/test/scenario/network/network_emulation_manager.h
index 4718967..3f20443 100644
--- a/test/scenario/network/network_emulation_manager.h
+++ b/test/scenario/network/network_emulation_manager.h
@@ -31,6 +31,22 @@
 namespace webrtc {
 namespace test {
 
+struct EndpointConfig {
+  enum IpAddressFamily { kIpv4, kIpv6 };
+
+  EndpointConfig();
+  ~EndpointConfig();
+  EndpointConfig(EndpointConfig&);
+  EndpointConfig& operator=(EndpointConfig&);
+  EndpointConfig(EndpointConfig&&);
+  EndpointConfig& operator=(EndpointConfig&&);
+
+  IpAddressFamily generated_ip_family = IpAddressFamily::kIpv4;
+  // If specified will be used as IP address for endpoint node. Should be unique
+  // among all created nodes.
+  absl::optional<rtc::IPAddress> ip;
+};
+
 class NetworkEmulationManager {
  public:
   NetworkEmulationManager();
@@ -39,9 +55,7 @@
   EmulatedNetworkNode* CreateEmulatedNode(
       std::unique_ptr<NetworkBehaviorInterface> network_behavior);
 
-  // TODO(titovartem) add method without IP address, where manager
-  // will provided some unique generated address.
-  EndpointNode* CreateEndpoint(rtc::IPAddress ip);
+  EndpointNode* CreateEndpoint(EndpointConfig config);
 
   void CreateRoute(EndpointNode* from,
                    std::vector<EmulatedNetworkNode*> via_nodes,
@@ -63,6 +77,7 @@
  private:
   FakeNetworkSocketServer* CreateSocketServer(
       std::vector<EndpointNode*> endpoints);
+  absl::optional<rtc::IPAddress> GetNextIPv4Address();
   void ProcessNetworkPackets();
   Timestamp Now() const;
 
@@ -71,6 +86,9 @@
 
   RepeatingTaskHandle process_task_handle_;
 
+  uint32_t next_ip4_address_;
+  std::set<rtc::IPAddress> used_ip_addresses_;
+
   // All objects can be added to the manager only when it is idle.
   std::vector<std::unique_ptr<EndpointNode>> endpoints_;
   std::vector<std::unique_ptr<EmulatedNetworkNode>> network_nodes_;
diff --git a/test/scenario/network/network_emulation_pc_unittest.cc b/test/scenario/network/network_emulation_pc_unittest.cc
index d8a2b8a..0f61e2c 100644
--- a/test/scenario/network/network_emulation_pc_unittest.cc
+++ b/test/scenario/network/network_emulation_pc_unittest.cc
@@ -108,10 +108,9 @@
       absl::make_unique<SimulatedNetwork>(BuiltInNetworkBehaviorConfig()));
   EmulatedNetworkNode* bob_node = network_manager.CreateEmulatedNode(
       absl::make_unique<SimulatedNetwork>(BuiltInNetworkBehaviorConfig()));
-  rtc::IPAddress alice_ip(1);
-  EndpointNode* alice_endpoint = network_manager.CreateEndpoint(alice_ip);
-  rtc::IPAddress bob_ip(2);
-  EndpointNode* bob_endpoint = network_manager.CreateEndpoint(bob_ip);
+  EndpointNode* alice_endpoint =
+      network_manager.CreateEndpoint(EndpointConfig());
+  EndpointNode* bob_endpoint = network_manager.CreateEndpoint(EndpointConfig());
   network_manager.CreateRoute(alice_endpoint, {alice_node}, bob_endpoint);
   network_manager.CreateRoute(bob_endpoint, {bob_node}, alice_endpoint);
 
@@ -127,7 +126,8 @@
       absl::make_unique<MockPeerConnectionObserver>();
   std::unique_ptr<rtc::FakeNetworkManager> alice_network_manager =
       absl::make_unique<rtc::FakeNetworkManager>();
-  alice_network_manager->AddInterface(rtc::SocketAddress(alice_ip, 0));
+  alice_network_manager->AddInterface(
+      rtc::SocketAddress(alice_endpoint->GetPeerLocalAddress(), 0));
 
   rtc::scoped_refptr<PeerConnectionFactoryInterface> bob_pcf;
   rtc::scoped_refptr<PeerConnectionInterface> bob_pc;
@@ -135,7 +135,8 @@
       absl::make_unique<MockPeerConnectionObserver>();
   std::unique_ptr<rtc::FakeNetworkManager> bob_network_manager =
       absl::make_unique<rtc::FakeNetworkManager>();
-  bob_network_manager->AddInterface(rtc::SocketAddress(bob_ip, 0));
+  bob_network_manager->AddInterface(
+      rtc::SocketAddress(bob_endpoint->GetPeerLocalAddress(), 0));
 
   signaling_thread->Invoke<void>(RTC_FROM_HERE, [&]() {
     alice_pcf = CreatePeerConnectionFactory(signaling_thread.get(),
diff --git a/test/scenario/network/network_emulation_unittest.cc b/test/scenario/network/network_emulation_unittest.cc
index c55b412..09932f0 100644
--- a/test/scenario/network/network_emulation_unittest.cc
+++ b/test/scenario/network/network_emulation_unittest.cc
@@ -57,6 +57,32 @@
   int received_count_ RTC_GUARDED_BY(lock_) = 0;
 };
 
+TEST(NetworkEmulationManagerTest, GeneratedIpv4AddressDoesNotCollide) {
+  NetworkEmulationManager network_manager;
+  std::set<rtc::IPAddress> ips;
+  EndpointConfig config;
+  config.generated_ip_family = EndpointConfig::IpAddressFamily::kIpv4;
+  for (int i = 0; i < 1000; i++) {
+    EndpointNode* endpoint = network_manager.CreateEndpoint(config);
+    ASSERT_EQ(endpoint->GetPeerLocalAddress().family(), AF_INET);
+    bool result = ips.insert(endpoint->GetPeerLocalAddress()).second;
+    ASSERT_TRUE(result);
+  }
+}
+
+TEST(NetworkEmulationManagerTest, GeneratedIpv6AddressDoesNotCollide) {
+  NetworkEmulationManager network_manager;
+  std::set<rtc::IPAddress> ips;
+  EndpointConfig config;
+  config.generated_ip_family = EndpointConfig::IpAddressFamily::kIpv6;
+  for (int i = 0; i < 1000; i++) {
+    EndpointNode* endpoint = network_manager.CreateEndpoint(config);
+    ASSERT_EQ(endpoint->GetPeerLocalAddress().family(), AF_INET6);
+    bool result = ips.insert(endpoint->GetPeerLocalAddress()).second;
+    ASSERT_TRUE(result);
+  }
+}
+
 TEST(NetworkEmulationManagerTest, Run) {
   NetworkEmulationManager network_manager;
 
@@ -65,9 +91,8 @@
   EmulatedNetworkNode* bob_node = network_manager.CreateEmulatedNode(
       absl::make_unique<SimulatedNetwork>(BuiltInNetworkBehaviorConfig()));
   EndpointNode* alice_endpoint =
-      network_manager.CreateEndpoint(rtc::IPAddress(1));
-  EndpointNode* bob_endpoint =
-      network_manager.CreateEndpoint(rtc::IPAddress(2));
+      network_manager.CreateEndpoint(EndpointConfig());
+  EndpointNode* bob_endpoint = network_manager.CreateEndpoint(EndpointConfig());
   network_manager.CreateRoute(alice_endpoint, {alice_node}, bob_endpoint);
   network_manager.CreateRoute(bob_endpoint, {bob_node}, alice_endpoint);