Browse Source

[3274] Relay address can now be stored in Subnet structures.

Tomek Mrugalski 11 years ago
parent
commit
406df0fff2
3 changed files with 96 additions and 8 deletions
  1. 18 7
      src/lib/dhcpsrv/subnet.cc
  2. 53 1
      src/lib/dhcpsrv/subnet.h
  3. 25 0
      src/lib/dhcpsrv/tests/subnet_unittest.cc

+ 18 - 7
src/lib/dhcpsrv/subnet.cc

@@ -30,12 +30,14 @@ SubnetID Subnet::static_id_ = 1;
 Subnet::Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len,
                const Triplet<uint32_t>& t1,
                const Triplet<uint32_t>& t2,
-               const Triplet<uint32_t>& valid_lifetime)
-    :id_(generateNextID()), prefix_(prefix), prefix_len_(len), t1_(t1),
-     t2_(t2), valid_(valid_lifetime),
+               const Triplet<uint32_t>& valid_lifetime,
+               const isc::dhcp::Subnet::RelayInfo& relay)
+    :relay_(relay), id_(generateNextID()), prefix_(prefix), prefix_len_(len),
+     t1_(t1), t2_(t2), valid_(valid_lifetime),
      last_allocated_ia_(lastAddrInPrefix(prefix, len)),
      last_allocated_ta_(lastAddrInPrefix(prefix, len)),
-     last_allocated_pd_(lastAddrInPrefix(prefix, len)) {
+     last_allocated_pd_(lastAddrInPrefix(prefix, len))
+      {
     if ((prefix.isV6() && len > 128) ||
         (prefix.isV4() && len > 32)) {
         isc_throw(BadValue,
@@ -43,6 +45,10 @@ Subnet::Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len,
     }
 }
 
+Subnet::RelayInfo::RelayInfo(const isc::asiolink::IOAddress& addr)
+    :addr_(addr) {
+}
+
 bool
 Subnet::inRange(const isc::asiolink::IOAddress& addr) const {
     IOAddress first = firstAddrInPrefix(prefix_, prefix_len_);
@@ -66,6 +72,11 @@ Subnet::addOption(const OptionPtr& option, bool persistent,
 }
 
 void
+Subnet::setRelay(const isc::dhcp::Subnet::RelayInfo& relay) {
+    relay_ = relay;
+}
+
+void
 Subnet::delOptions() {
     option_spaces_.clearItems();
 }
@@ -179,8 +190,8 @@ Subnet4::Subnet4(const isc::asiolink::IOAddress& prefix, uint8_t length,
                  const Triplet<uint32_t>& t1,
                  const Triplet<uint32_t>& t2,
                  const Triplet<uint32_t>& valid_lifetime)
-    :Subnet(prefix, length, t1, t2, valid_lifetime),
-    siaddr_(IOAddress("0.0.0.0")) {
+:Subnet(prefix, length, t1, t2, valid_lifetime,
+        RelayInfo(IOAddress("0.0.0.0"))), siaddr_(IOAddress("0.0.0.0")) {
     if (!prefix.isV4()) {
         isc_throw(BadValue, "Non IPv4 prefix " << prefix.toText()
                   << " specified in subnet4");
@@ -331,7 +342,7 @@ Subnet6::Subnet6(const isc::asiolink::IOAddress& prefix, uint8_t length,
                  const Triplet<uint32_t>& t2,
                  const Triplet<uint32_t>& preferred_lifetime,
                  const Triplet<uint32_t>& valid_lifetime)
-    :Subnet(prefix, length, t1, t2, valid_lifetime),
+:Subnet(prefix, length, t1, t2, valid_lifetime, RelayInfo(IOAddress("::"))),
      preferred_(preferred_lifetime){
     if (!prefix.isV6()) {
         isc_throw(BadValue, "Non IPv6 prefix " << prefix

+ 53 - 1
src/lib/dhcpsrv/subnet.h

@@ -166,6 +166,23 @@ public:
     /// Type of the index #2 - option persistency flag.
     typedef OptionContainer::nth_index<2>::type OptionContainerPersistIndex;
 
+    /// @brief Holds optional information about relay.
+    ///
+    /// In some cases it is beneficial to have additional information about
+    /// a relay configured in the subnet. For now, the structure holds only
+    /// IP address, but there may potentially be additional parameters added
+    /// later, e.g. relay interface-id or relay-id.
+    struct RelayInfo {
+
+        /// @brief default and the only constructor
+        ///
+        /// @param addr an IP address of the relay (may be :: or 0.0.0.0)
+        RelayInfo(const isc::asiolink::IOAddress& addr);
+
+        /// @brief IP address of the relay
+        isc::asiolink::IOAddress addr_;
+    };
+
     /// @brief checks if specified address is in range
     bool inRange(const isc::asiolink::IOAddress& addr) const;
 
@@ -375,6 +392,33 @@ public:
         static_id_ = 1;
     }
 
+    /// @brief Sets address of the relay
+    ///
+    /// In some situations where there are shared subnets (i.e. two different
+    /// subnets are available on the same physical link), there is only one
+    /// relay that handles incoming requests from clients. In such a case,
+    /// the usual subnet selection criteria based on relay belonging to the
+    /// subnet being selected are no longer sufficient and we need to explicitly
+    /// specify a relay. One notable example of such uncommon, but valid
+    /// scenario is a cable network, where there is only one CMTS (one relay),
+    /// but there are 2 distinct subnets behind it: one for cable modems
+    /// and another one for CPEs and other user equipment behind modems.
+    /// From manageability perspective, it is essential that modems get addresses
+    /// from different subnet, so users won't tinker with their modems.
+    ///
+    /// Setting this parameter is not needed in most deployments.
+    ///
+    /// @params relay IP address of the relay
+    void setRelay(const isc::dhcp::Subnet::RelayInfo& relay);
+
+    /// @brief Relay information
+    ///
+    /// See @ref RelayInfo for detailed description. This structure is public,
+    /// so its fields are easily accessible. Making it protected would bring in
+    /// the issue of returning references that may become stale after its parent
+    /// subnet object disappears.
+    RelayInfo relay_;
+
 protected:
     /// @brief Returns all pools (non-const variant)
     ///
@@ -393,10 +437,18 @@ protected:
     /// This subnet-id has unique value that is strictly monotonously increasing
     /// for each subnet, until it is explicitly reset back to 1 during
     /// reconfiguration process.
+    ///
+    /// @param prefix subnet prefix
+    /// @param len prefix length for the subnet
+    /// @param t1 T1 (renewal-time) timer, expressed in seconds
+    /// @param t2 T2 (rebind-time) timer, expressed in seconds
+    /// @param valid_lifetime valid lifetime of leases in this subnet (in seconds)
+    /// @param relay optional relay information (currently with address only)
     Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len,
            const Triplet<uint32_t>& t1,
            const Triplet<uint32_t>& t2,
-           const Triplet<uint32_t>& valid_lifetime);
+           const Triplet<uint32_t>& valid_lifetime,
+           const isc::dhcp::Subnet::RelayInfo& relay);
 
     /// @brief virtual destructor
     ///

+ 25 - 0
src/lib/dhcpsrv/tests/subnet_unittest.cc

@@ -49,6 +49,8 @@ TEST(Subnet4Test, in_range) {
     EXPECT_EQ(2000, subnet.getT2());
     EXPECT_EQ(3000, subnet.getValid());
 
+    EXPECT_EQ("0.0.0.0", subnet.relay_.addr_.toText());
+
     EXPECT_FALSE(subnet.inRange(IOAddress("192.0.0.0")));
     EXPECT_TRUE(subnet.inRange(IOAddress("192.0.2.0")));
     EXPECT_TRUE(subnet.inRange(IOAddress("192.0.2.1")));
@@ -58,6 +60,17 @@ TEST(Subnet4Test, in_range) {
     EXPECT_FALSE(subnet.inRange(IOAddress("255.255.255.255")));
 }
 
+// Checks whether the relay field has sane default and if it can
+// be changed, stored and retrieved
+TEST(Subnet4Test, relay) {
+    Subnet4 subnet(IOAddress("192.0.2.1"), 24, 1000, 2000, 3000);
+
+    EXPECT_EQ("0.0.0.0", subnet.relay_.addr_.toText());
+
+    subnet.setRelay(IOAddress("192.0.123.45"));
+    EXPECT_EQ("192.0.123.45", subnet.relay_.addr_.toText());
+}
+
 // Checks whether siaddr field can be set and retrieved correctly.
 TEST(Subnet4Test, siaddr) {
     Subnet4 subnet(IOAddress("192.0.2.1"), 24, 1000, 2000, 3000);
@@ -291,6 +304,18 @@ TEST(Subnet6Test, in_range) {
     EXPECT_FALSE(subnet.inRange(IOAddress("::")));
 }
 
+// Checks whether the relay field has sane default and if it can
+// be changed, stored and retrieved
+TEST(Subnet6Test, relay) {
+    Subnet6 subnet(IOAddress("2001:db8:1::"), 64, 1000, 2000, 3000, 4000);
+
+    EXPECT_EQ("::", subnet.relay_.addr_.toText());
+
+    subnet.setRelay(IOAddress("2001:ffff::1"));
+
+    EXPECT_EQ("2001:ffff::1", subnet.relay_.addr_.toText());
+}
+
 TEST(Subnet6Test, Pool6InSubnet6) {
 
     Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));