Browse Source

[master] Merged trac4059 (layer 2 DHCPv6 relays)

Francis Dupont 9 years ago
parent
commit
2d6ac9fd88
2 changed files with 64 additions and 7 deletions
  1. 7 1
      src/bin/dhcp6/dhcp6_srv.cc
  2. 57 6
      src/bin/dhcp6/tests/dhcp6_srv_unittest.cc

+ 7 - 1
src/bin/dhcp6/dhcp6_srv.cc

@@ -1043,7 +1043,13 @@ Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question) {
 
     // Initialize fields specific to relayed messages.
     if (!question->relay_info_.empty()) {
-        selector.first_relay_linkaddr_ = question->relay_info_.back().linkaddr_;
+        BOOST_REVERSE_FOREACH(Pkt6::RelayInfo relay, question->relay_info_) {
+            if (!relay.linkaddr_.isV6Zero() &&
+                !relay.linkaddr_.isV6LinkLocal()) {
+                selector.first_relay_linkaddr_ = relay.linkaddr_;
+                break;
+            }
+        }
         selector.interface_id_ =
             question->getAnyRelayOption(D6O_INTERFACE_ID,
                                         Pkt6::RELAY_GET_FIRST);

+ 57 - 6
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc

@@ -1297,8 +1297,8 @@ TEST_F(Dhcpv6SrvTest, selectSubnetRelayLinkaddr) {
     Subnet6Ptr selected = srv.selectSubnet(pkt);
     EXPECT_FALSE(selected);
 
-    // CASE 2: We have three subnets defined and we received relayed traffic.
-    // Nothing should be selected.
+    // CASE 2: We have three subnets defined and we received relayed traffic
+    // that came out of subnet 2. We should select subnet2 then
     CfgMgr::instance().clear();
     CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1);
     CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet2);
@@ -1307,20 +1307,70 @@ TEST_F(Dhcpv6SrvTest, selectSubnetRelayLinkaddr) {
     selected = srv.selectSubnet(pkt);
     EXPECT_EQ(selected, subnet2);
 
+    // Source of the packet should have no meaning. Selection is based
+    // on linkaddr field in the relay
+    pkt->setRemoteAddr(IOAddress("2001:db8:1::baca"));
+    selected = srv.selectSubnet(pkt);
+    EXPECT_EQ(selected, subnet2);
+
+    // But not when this linkaddr field is not usable.
+    Pkt6::RelayInfo relay2;
+    relay2.peeraddr_ = IOAddress("fe80::1");
+    pkt->relay_info_.clear();
+    pkt->relay_info_.push_back(relay2);
+    selected = srv.selectSubnet(pkt);
+    EXPECT_EQ(selected, subnet1);
+
     // CASE 3: We have three subnets defined and we received relayed traffic
-    // that came out of subnet 2. We should select subnet2 then
+    // that came out a layer 2 relay on subnet 2. We should select subnet2 then
     CfgMgr::instance().clear();
     CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet1);
     CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet2);
     CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet3);
     CfgMgr::instance().commit();
+    pkt->relay_info_.clear();
+    pkt->relay_info_.push_back(relay);
+    relay2.hop_count_ = 1;
+    pkt->relay_info_.push_back(relay2);
+    selected = srv.selectSubnet(pkt);
+    EXPECT_EQ(selected, subnet2);
 
-    // Source of the packet should have no meaning. Selection is based
-    // on linkaddr field in the relay
-    pkt->setRemoteAddr(IOAddress("2001:db8:1::baca"));
+    // The number of level 2 relay doesn't matter
+    pkt->relay_info_.clear();
+    Pkt6::RelayInfo relay20;
+    relay20.peeraddr_ = IOAddress("fe80::1");
+    pkt->relay_info_.push_back(relay20);
+    Pkt6::RelayInfo relay21;
+    relay21.peeraddr_ = IOAddress("fe80::1");
+    relay21.hop_count_ = 1;
+    pkt->relay_info_.push_back(relay21);
+    relay.hop_count_ = 2;
+    pkt->relay_info_.push_back(relay);
+    Pkt6::RelayInfo relay22;
+    relay22.peeraddr_ = IOAddress("fe80::1");
+    relay22.hop_count_ = 3;
+    pkt->relay_info_.push_back(relay22);
+    Pkt6::RelayInfo relay23;
+    relay23.peeraddr_ = IOAddress("fe80::1");
+    relay23.hop_count_ = 4;
+    pkt->relay_info_.push_back(relay23);
     selected = srv.selectSubnet(pkt);
     EXPECT_EQ(selected, subnet2);
 
+    // Only the inner/last relay with a usable address matters
+    pkt->relay_info_.clear();
+    pkt->relay_info_.push_back(relay20);
+    pkt->relay_info_.push_back(relay21);
+    pkt->relay_info_.push_back(relay);
+    pkt->relay_info_.push_back(relay22);
+    Pkt6::RelayInfo relay3;
+    relay3.linkaddr_ = IOAddress("2001:db8:3::1234");
+    relay3.peeraddr_ = IOAddress("fe80::1");
+    relay3.hop_count_ = 4;
+    pkt->relay_info_.push_back(relay3);
+    selected = srv.selectSubnet(pkt);
+    EXPECT_EQ(selected, subnet3);
+
     // CASE 4: We have three subnets defined and we received relayed traffic
     // that came out of undefined subnet. We should select nothing
     CfgMgr::instance().clear();
@@ -1329,6 +1379,7 @@ TEST_F(Dhcpv6SrvTest, selectSubnetRelayLinkaddr) {
     CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet3);
     CfgMgr::instance().commit();
     pkt->relay_info_.clear();
+    relay.hop_count_ = 0;
     relay.linkaddr_ = IOAddress("2001:db8:4::1234");
     pkt->relay_info_.push_back(relay);
     selected = srv.selectSubnet(pkt);