Add interface_id to rtc::Network

This patch adds an interface_id property
to rtc::Network. It is an enumeration of the
interface names that are present.

This enables a local ICE agent to keep track
of which connections are using which interfaces,
something that is useful for predicting how
connections behave.

This is part 1 of https://webrtc-review.googlesource.com/c/src/+/85520

BUG: webrtc:9446
Change-Id: Ia6ec1f14ac240799fb1be49d67d82e2733e87acf
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/171061
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Jonas Oreland <jonaso@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30882}
diff --git a/rtc_base/network.cc b/rtc_base/network.cc
index 07b121b..cebd315 100644
--- a/rtc_base/network.cc
+++ b/rtc_base/network.cc
@@ -329,8 +329,14 @@
     Network* net = kv.second.net;
     auto existing = networks_map_.find(key);
     if (existing == networks_map_.end()) {
-      // This network is new. Place it in the network map.
+      if (interface_ids_by_name_.find(net->name()) ==
+          interface_ids_by_name_.end()) {
+        interface_ids_by_name_.emplace(net->name(),
+                                       next_available_interface_id_++);
+      }
+      net->set_interface_id(interface_ids_by_name_[net->name()]);
       merged_list.push_back(net);
+      // This network is new. Place it in the network map.
       networks_map_[key] = net;
       net->set_id(next_available_network_id_++);
       // Also, we might have accumulated IPAddresses from the first
diff --git a/rtc_base/network.h b/rtc_base/network.h
index fb40166..4d0a52f 100644
--- a/rtc_base/network.h
+++ b/rtc_base/network.h
@@ -207,6 +207,11 @@
 
   IPAddress default_local_ipv4_address_;
   IPAddress default_local_ipv6_address_;
+
+  std::map<std::string, uint16_t> interface_ids_by_name_;
+  // Use 16 bits to save the bandwidth consumption when sending the interface
+  // id.
+  uint16_t next_available_interface_id_ = 1;
   // We use 16 bits to save the bandwidth consumption when sending the network
   // id over the Internet. It is OK that the 16-bit integer overflows to get a
   // network id 0 because we only compare the network ids in the old and the new
@@ -415,6 +420,16 @@
   uint16_t id() const { return id_; }
   void set_id(uint16_t id) { id_ = id; }
 
+  // A unique id assigned by the network manager to each network interface name.
+  // Networks on the same network interface (as identified by the interface
+  // name) have the same interface id.
+  uint16_t interface_id() const { return interface_id_; }
+  void set_interface_id(uint16_t interface_id) {
+    RTC_DCHECK(interface_id_ == 0);
+    RTC_DCHECK(interface_id != 0);
+    interface_id_ = interface_id;
+  }
+
   int preference() const { return preference_; }
   void set_preference(int preference) { preference_ = preference; }
 
@@ -447,6 +462,7 @@
   int preference_;
   bool active_ = true;
   uint16_t id_ = 0;
+  uint16_t interface_id_ = 0;
 
   friend class NetworkManager;
 };
diff --git a/rtc_base/network_unittest.cc b/rtc_base/network_unittest.cc
index 4135864..539e390 100644
--- a/rtc_base/network_unittest.cc
+++ b/rtc_base/network_unittest.cc
@@ -380,7 +380,9 @@
   EXPECT_TRUE(SameNameAndPrefix(ipv4_network1, *list[0]));
   Network* net1 = list[0];
   uint16_t net_id1 = net1->id();
+  uint16_t net_if_id1 = net1->interface_id();
   EXPECT_EQ(1, net_id1);
+  EXPECT_EQ(1, net_if_id1);
   list.clear();
 
   // Replace ipv4_network1 with ipv4_network2.
@@ -396,8 +398,10 @@
   EXPECT_TRUE(SameNameAndPrefix(ipv4_network2, *list[0]));
   Network* net2 = list[0];
   uint16_t net_id2 = net2->id();
+  uint16_t net_if_id2 = net2->interface_id();
   // Network id will increase.
   EXPECT_LT(net_id1, net_id2);
+  EXPECT_LT(net_if_id1, net_if_id2);
   list.clear();
 
   // Add Network2 back.
@@ -416,6 +420,8 @@
               (net1 == list[1] && net2 == list[0]));
   EXPECT_TRUE((net_id1 == list[0]->id() && net_id2 == list[1]->id()) ||
               (net_id1 == list[1]->id() && net_id2 == list[0]->id()));
+  EXPECT_TRUE((net_if_id1 == list[0]->id() && net_if_id2 == list[1]->id()) ||
+              (net_if_id1 == list[1]->id() && net_if_id2 == list[0]->id()));
   list.clear();
 
   // Call MergeNetworkList() again and verify that we don't get update
@@ -433,11 +439,60 @@
   EXPECT_EQ(2U, list.size());
   EXPECT_TRUE((net1 == list[0] && net2 == list[1]) ||
               (net1 == list[1] && net2 == list[0]));
-  EXPECT_TRUE((net_id1 == list[0]->id() && net_id2 == list[1]->id()) ||
-              (net_id1 == list[1]->id() && net_id2 == list[0]->id()));
+  EXPECT_TRUE((net_if_id1 == list[0]->interface_id() &&
+               net_if_id2 == list[1]->interface_id()) ||
+              (net_if_id1 == list[1]->interface_id() &&
+               net_if_id2 == list[0]->interface_id()));
   list.clear();
 }
 
+// Verify that one interface id is generated per network name.
+TEST_F(NetworkTest, TestInterfaceId) {
+  Network ipv4_network1("test_eth0", "Test Network Adapter 1",
+                        IPAddress(0x12345600U), 24);
+  Network ipv4_network2("test_eth0", "Test Network Adapter 2",
+                        IPAddress(0xaabbcc00U), 24);
+  Network ipv4_network3("test_eth1", "Test Network Adapter 2",
+                        IPAddress(0x00010000U), 16);
+  ipv4_network1.AddIP(IPAddress(0x12345678));
+  ipv4_network2.AddIP(IPAddress(0xaabbcc01));
+  ipv4_network3.AddIP(IPAddress(0x00010004));
+  BasicNetworkManager manager;
+
+  // Add list of networks.
+  {
+    NetworkManager::NetworkList list;
+    list.push_back(new Network(ipv4_network1));
+    list.push_back(new Network(ipv4_network2));
+    list.push_back(new Network(ipv4_network3));
+    bool changed;
+    NetworkManager::Stats stats = MergeNetworkList(manager, list, &changed);
+    EXPECT_TRUE(changed);
+    EXPECT_EQ(stats.ipv6_network_count, 0);
+    EXPECT_EQ(stats.ipv4_network_count, 3);
+  }
+
+  {
+    NetworkManager::NetworkList list;
+    manager.GetNetworks(&list);
+    EXPECT_EQ(list.size(), 3U);
+
+    // There should be 2 interfaces
+    std::map<int, int> networks_per_interface;
+    for (const auto& network : list) {
+      networks_per_interface[network->interface_id()]++;
+    }
+    EXPECT_EQ(networks_per_interface.size(), 2U);
+    for (const auto& network : list) {
+      if (network->name() == "test_eth0") {
+        EXPECT_EQ(networks_per_interface[network->interface_id()], 2);
+      } else {
+        EXPECT_EQ(networks_per_interface[network->interface_id()], 1);
+      }
+    }
+  }
+}
+
 // Sets up some test IPv6 networks and appends them to list.
 // Four networks are added - public and link local, for two interfaces.
 void SetupNetworks(NetworkManager::NetworkList* list) {