]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[659-how-configure-client-class-for-pools-in-db] Checkpoint: code done, todo new...
authorFrancis Dupont <fdupont@isc.org>
Sat, 15 Jun 2019 19:07:26 +0000 (21:07 +0200)
committerTomek Mrugalski <tomasz@isc.org>
Fri, 16 Aug 2019 15:47:34 +0000 (17:47 +0200)
src/bin/admin/tests/mysql_tests.sh.in
src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.cc
src/hooks/dhcp/mysql_cb/mysql_cb_dhcp6.cc
src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc
src/hooks/dhcp/mysql_cb/mysql_cb_impl.h
src/hooks/dhcp/mysql_cb/mysql_query_macros_dhcp.h
src/share/database/scripts/mysql/dhcpdb_create.mysql
src/share/database/scripts/mysql/upgrade_8.1_to_8.2.sh.in

index 6cf8264538765e6f961a2050b0335f088cce8fbc..d0ae3ec1e6796d96e042ad312f547d9503b1a480 100644 (file)
@@ -709,6 +709,18 @@ EOF
     qry="select subnet_prefix, client_class, interface, modification_ts, preferred_lifetime, min_preferred_lifetime, max_preferred_lifetime, rapid_commit, rebind_timer, relay, renew_timer, require_client_classes, reservation_mode, shared_network_name, subnet_id, user_context, valid_lifetime, min_valid_lifetime, max_valid_lifetime, calculate_tee_times, t1_percent, t2_percent from dhcp6_subnet"
     run_statement "dhcp6_subnet" "$qry"
 
+    # table: dhcp4_pool (should include three new columns)
+    qry="select client_class, require_client_classes, user_context from dhcp4_pool"
+    run_statement "dhcp4_pool" "$qry"
+
+    # table: dhcp6_pd_pool (should include five new columns)
+    qry="select excluded_prefix, excluded_prefix_length, client_class, require_client_classes, user_context from dhcp6_pd_pool"
+    run_statement "dhcp6_pd_pool" "$qry"
+
+    # table: dhcp6_pool (should include three new columns)
+    qry="select client_class, require_client_classes, user_context from dhcp6_pool"
+    run_statement "dhcp6_pool" "$qry"
+
     # Verify upgraded schema reports version 8.2
     version=$(${keaadmin} db-version mysql -u $db_user -p $db_password -n $db_name -d $db_scripts_dir)
     assert_str_eq "8.2" ${version} "Expected kea-admin to return %s, returned value was %s"
index 7bf180516461992afe06d0a629d64344be06ea8f..fb70995b1ba919ced77d827a5efdea56f04fcee7 100644 (file)
@@ -306,6 +306,9 @@ public:
             MySqlBinding::createInteger<uint8_t>(), // authoritative
             MySqlBinding::createInteger<uint32_t>(), // min_valid_lifetime
             MySqlBinding::createInteger<uint32_t>(), // max_valid_lifetime
+            MySqlBinding::createString(CLIENT_CLASS_BUF_LENGTH), // pool: client_class
+            MySqlBinding::createString(REQUIRE_CLIENT_CLASSES_BUF_LENGTH), // pool: require_client_classes
+            MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pool: user_context
             MySqlBinding::createString(SERVER_TAG_BUF_LENGTH) // server_tag
         };
 
@@ -482,6 +485,10 @@ public:
 
                 // {min,max}_valid_lifetime
 
+                // 3 pool fields
+
+                // server_tag at 58
+
                 // Subnet ready. Add it to the list.
                 auto ret = subnets.push_back(last_subnet);
 
@@ -494,9 +501,9 @@ public:
             }
 
             // Check for new server tags.
-            if (!out_bindings[55]->amNull() &&
-                (last_tag != out_bindings[55]->getString())) {
-                last_tag = out_bindings[55]->getString();
+            if (!out_bindings[58]->amNull() &&
+                (last_tag != out_bindings[58]->getString())) {
+                last_tag = out_bindings[58]->getString();
                 if (!last_tag.empty() && !last_subnet->hasServerTag(ServerTag(last_tag))) {
                     last_subnet->setServerTag(last_tag);
                 }
@@ -512,6 +519,35 @@ public:
                 last_pool_id = out_bindings[20]->getInteger<uint64_t>();
                 last_pool = Pool4::create(IOAddress(out_bindings[21]->getInteger<uint32_t>()),
                                           IOAddress(out_bindings[22]->getInteger<uint32_t>()));
+
+                // pool client_class
+                if (!out_bindings[55]->amNull()) {
+                    last_pool->allowClientClass(out_bindings[55]->getString());
+                }
+
+                // pool require_client_classes
+                ElementPtr require_element = out_bindings[56]->getJSON();
+                if (require_element) {
+                    if (require_element->getType() != Element::list) {
+                        isc_throw(BadValue, "invalid pool require_client_classes value "
+                                  << out_bindings[56]->getString());
+                    }
+                    for (auto i = 0; i < require_element->size(); ++i) {
+                        auto require_item = require_element->get(i);
+                        if (require_item->getType() != Element::string) {
+                            isc_throw(BadValue, "elements of pool require_client_classes list must"
+                                      "be valid strings");
+                        }
+                        last_pool->requireClientClass(require_item->stringValue());
+                    }
+                }
+
+                // pool user_context
+                ElementPtr user_context = out_bindings[57]->getJSON();
+                if (user_context) {
+                    last_pool->setContext(user_context);
+                }
+
                 last_subnet->addPool(last_pool);
             }
 
@@ -689,6 +725,9 @@ public:
             MySqlBinding::createInteger<uint32_t>(), // pool: start_address
             MySqlBinding::createInteger<uint32_t>(), // pool: end_address
             MySqlBinding::createInteger<uint32_t>(), // pool: subnet_id
+            MySqlBinding::createString(CLIENT_CLASS_BUF_LENGTH), // pool: client_class
+            MySqlBinding::createString(REQUIRE_CLIENT_CLASSES_BUF_LENGTH), // pool: require_client_classes
+            MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pool: user_context
             MySqlBinding::createTimestamp(), // pool: modification_ts
             MySqlBinding::createInteger<uint64_t>(), // pool option: option_id
             MySqlBinding::createInteger<uint8_t>(), // pool option: code
@@ -718,16 +757,46 @@ public:
 
                 last_pool = Pool4::create(IOAddress(out_bindings[1]->getInteger<uint32_t>()),
                                           IOAddress(out_bindings[2]->getInteger<uint32_t>()));
+                // pool client_class (4)
+                if (!out_bindings[4]->amNull()) {
+                    last_pool->allowClientClass(out_bindings[4]->getString());
+                }
+
+                // pool require_client_classes (5)
+                ElementPtr require_element = out_bindings[5]->getJSON();
+                if (require_element) {
+                    if (require_element->getType() != Element::list) {
+                        isc_throw(BadValue, "invalid pool require_client_classes value "
+                                  << out_bindings[5]->getString());
+                    }
+                    for (auto i = 0; i < require_element->size(); ++i) {
+                        auto require_item = require_element->get(i);
+                        if (require_item->getType() != Element::string) {
+                            isc_throw(BadValue, "elements of pool require_client_classes list must"
+                                      "be valid strings");
+                        }
+                        last_pool->requireClientClass(require_item->stringValue());
+                    }
+                }
+
+                // pool user_context (6)
+                ElementPtr user_context = out_bindings[6]->getJSON();
+                if (user_context) {
+                    last_pool->setContext(user_context);
+                }
+
+                // pool: modification_ts (7)
+
                 pools.push_back(last_pool);
                 pool_ids.push_back(last_pool_id);
             }
 
-            // Parse pool specific option.
-            if (last_pool && !out_bindings[5]->amNull() &&
-                (last_pool_option_id < out_bindings[5]->getInteger<uint64_t>())) {
-                last_pool_option_id = out_bindings[5]->getInteger<uint64_t>();
+            // Parse pool specific option (8).
+            if (last_pool && !out_bindings[8]->amNull() &&
+                (last_pool_option_id < out_bindings[8]->getInteger<uint64_t>())) {
+                last_pool_option_id = out_bindings[8]->getInteger<uint64_t>();
 
-                OptionDescriptorPtr desc = processOptionRow(Option::V4, out_bindings.begin() + 5);
+                OptionDescriptorPtr desc = processOptionRow(Option::V4, out_bindings.begin() + 8);
                 if (desc) {
                     last_pool->getCfgOption()->add(*desc, desc->space_name_);
                 }
@@ -952,6 +1021,9 @@ public:
             MySqlBinding::createInteger<uint32_t>(pool->getFirstAddress().toUint32()),
             MySqlBinding::createInteger<uint32_t>(pool->getLastAddress().toUint32()),
             MySqlBinding::createInteger<uint32_t>(static_cast<uint32_t>(subnet->getID())),
+            MySqlBinding::condCreateString(pool->getClientClass()),
+            createInputRequiredClassesBinding(pool),
+            createInputContextBinding(pool),
             MySqlBinding::createTimestamp(subnet->getModificationTime())
         };
 
@@ -2123,6 +2195,9 @@ TaggedStatementArray tagged_statements = { {
       "  p.start_address,"
       "  p.end_address,"
       "  p.subnet_id,"
+      "  p.client_class,"
+      "  p.require_client_classes,"
+      "  p.user_context,"
       "  p.modification_ts,"
       "  x.option_id,"
       "  x.code,"
index c1c828348cd8be3ca4d32db245c37d4de21104c4..17acec5c1cd6300ac97319b70575675293029799 100644 (file)
@@ -334,6 +334,14 @@ public:
             MySqlBinding::createInteger<uint32_t>(), // max_preferred_lifetime
             MySqlBinding::createInteger<uint32_t>(), // min_valid_lifetime
             MySqlBinding::createInteger<uint32_t>(), // max_valid_lifetime
+            MySqlBinding::createString(CLIENT_CLASS_BUF_LENGTH), // pool: client_class
+            MySqlBinding::createString(REQUIRE_CLIENT_CLASSES_BUF_LENGTH), // pool: require_client_classes
+            MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pool: user_context
+            MySqlBinding::createString(POOL_ADDRESS6_BUF_LENGTH), // pd pool: excluded_prefix
+            MySqlBinding::createInteger<uint8_t>(), // pd pool: excluded_prefix_length
+            MySqlBinding::createString(CLIENT_CLASS_BUF_LENGTH), // pd pool: client_class
+            MySqlBinding::createString(REQUIRE_CLIENT_CLASSES_BUF_LENGTH), // pd pool: require_client_classes
+            MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pd pool: user_context
             MySqlBinding::createString(SERVER_TAG_BUF_LENGTH) // server_tag
         };
 
@@ -373,10 +381,10 @@ public:
                 // Reset last server tag as we're now starting to process new subnet.
                 last_tag.clear();
 
-                // subnet_id
+                // subnet_id (0)
                 SubnetID subnet_id(out_bindings[0]->getInteger<uint32_t>());
 
-                // subnet_prefix
+                // subnet_prefix (1)
                 std::string subnet_prefix = out_bindings[1]->getString();
                 auto prefix_pair = Subnet6::parsePrefix(subnet_prefix);
 
@@ -385,10 +393,10 @@ public:
                                                         out_bindings[69],
                                                         out_bindings[70]);
 
-                // renew_timer
+                // renew_timer (9)
                 auto renew_timer = createTriplet(out_bindings[9]);
 
-                // rebind_timer
+                // rebind_timer (7)
                 auto rebind_timer = createTriplet(out_bindings[7]);
 
                 // valid_lifetime  (and {min,max)_valid_lifetime)
@@ -402,28 +410,28 @@ public:
                                               preferred_lifetime,
                                               valid_lifetime, subnet_id);
 
-                // client_class
+                // client_class (2)
                 if (!out_bindings[2]->amNull()) {
                     last_subnet->allowClientClass(out_bindings[2]->getString());
                 }
 
-                // interface
+                // interface (3)
                 if (!out_bindings[3]->amNull()) {
                     last_subnet->setIface(out_bindings[3]->getString());
                 }
 
-                // modification_ts
+                // modification_ts (4)
                 last_subnet->setModificationTime(out_bindings[4]->getTimestamp());
                 // 5 is preferred_lifetime
 
-                // rapid_commit
+                // rapid_commit (6)
                 if (!out_bindings[6]->amNull()) {
                     last_subnet->setRapidCommit(out_bindings[6]->getBool());
                 }
 
                 // 7 is rebind_timer
 
-                // relay
+                // relay (8)
                 ElementPtr relay_element = out_bindings[8]->getJSON();
                 if (relay_element) {
                     if (relay_element->getType() != Element::list) {
@@ -441,7 +449,7 @@ public:
 
                 // 9 is renew_timer
 
-                // require_client_classes
+                // require_client_classes (10)
                 ElementPtr require_element = out_bindings[10]->getJSON();
                 if (require_element) {
                     if (require_element->getType() != Element::list) {
@@ -458,18 +466,18 @@ public:
                     }
                 }
 
-                // reservation_mode
+                // reservation_mode (11)
                 if (!out_bindings[11]->amNull()) {
                     last_subnet->setHostReservationMode(static_cast<Subnet4::HRMode>
                         (out_bindings[11]->getInteger<uint8_t>()));
                 }
 
-                // shared_network_name
+                // shared_network_name (12)
                 if (!out_bindings[12]->amNull()) {
                     last_subnet->setSharedNetworkName(out_bindings[12]->getString());
                 }
 
-                // user_context
+                // user_context (13)
                 ElementPtr user_context = out_bindings[13]->getJSON();
                 if (user_context) {
                     last_subnet->setContext(user_context);
@@ -477,22 +485,22 @@ public:
 
                 // 14 is valid_lifetime
 
-                // calculate_tee_times
+                // calculate_tee_times (65)
                 if (!out_bindings[65]->amNull()) {
                     last_subnet->setCalculateTeeTimes(out_bindings[65]->getBool());
                 }
 
-                // t1_percent
+                // t1_percent (66)
                 if (!out_bindings[66]->amNull()) {
                     last_subnet->setT1Percent(out_bindings[66]->getFloat());
                 }
 
-                // t2_percent
+                // t2_percent (67)
                 if (!out_bindings[67]->amNull()) {
                     last_subnet->setT2Percent(out_bindings[67]->getFloat());
                 }
 
-                // interface_id
+                // interface_id (68)
                 if (!out_bindings[68]->amNull()) {
                     auto iface_id_data = out_bindings[68]->getBlob();
                     if (!iface_id_data.empty()) {
@@ -506,6 +514,10 @@ public:
 
                 // 71 and 72 are {min,max}_valid_lifetime
 
+                // 8 pool and pd pool fields
+
+                // server_tag (81 / last)
+
                 // Subnet ready. Add it to the list.
                 auto ret = subnets.push_back(last_subnet);
 
@@ -518,15 +530,15 @@ public:
             }
 
             // Check for new server tags.
-            if (!out_bindings[73]->amNull() &&
-                (last_tag != out_bindings[73]->getString())) {
-                last_tag = out_bindings[73]->getString();
+            if (!out_bindings[81]->amNull() &&
+                (last_tag != out_bindings[81]->getString())) {
+                last_tag = out_bindings[81]->getString();
                 if (!last_tag.empty() && !last_subnet->hasServerTag(ServerTag(last_tag))) {
                     last_subnet->setServerTag(last_tag);
                 }
             }
 
-            // Pool is between 15 and 19
+            // Pool is between 15 and 19 with extra between 73 and 75
 
             // If the row contains information about the pool and it
             // appears to be new pool entry (checked by comparing pool
@@ -540,10 +552,38 @@ public:
                 last_pool = Pool6::create(Lease::TYPE_NA,
                                           IOAddress(out_bindings[16]->getString()),
                                           IOAddress(out_bindings[17]->getString()));
+                // pool client_class (73)
+                if (!out_bindings[73]->amNull()) {
+                    last_pool->allowClientClass(out_bindings[73]->getString());
+                }
+
+                // pool require_client_classes (74)
+                ElementPtr require_element = out_bindings[74]->getJSON();
+                if (require_element) {
+                    if (require_element->getType() != Element::list) {
+                        isc_throw(BadValue, "invalid pool require_client_classes value "
+                                  << out_bindings[74]->getString());
+                    }
+                    for (auto i = 0; i < require_element->size(); ++i) {
+                        auto require_item = require_element->get(i);
+                        if (require_item->getType() != Element::string) {
+                            isc_throw(BadValue, "elements of pool require_client_classes list must"
+                                      "be valid strings");
+                        }
+                        last_pool->requireClientClass(require_item->stringValue());
+                    }
+                }
+
+                // pool user_context (75)
+                ElementPtr user_context = out_bindings[75]->getJSON();
+                if (user_context) {
+                    last_pool->setContext(user_context);
+                }
+
                 last_subnet->addPool(last_pool);
             }
 
-            // Pd Pool is between 20 and 25
+            // Pd Pool is between 20 and 25 with extra between 76 and 80
 
             // If the row contains information about the pd pool and
             // it appears to be new pd pool entry (checked by
@@ -555,10 +595,45 @@ public:
                 (out_bindings[23]->getInteger<uint8_t>() != 0) &&
                 (out_bindings[20]->getInteger<uint64_t>() > last_pd_pool_id)) {
                 last_pd_pool_id = out_bindings[20]->getInteger<uint64_t>();
-                last_pd_pool = Pool6::create(Lease::TYPE_PD,
-                                             IOAddress(out_bindings[21]->getString()),
+
+                // excluded_prefix (76) and excluded_prefix_length (77)
+                IOAddress excluded_prefix = IOAddress::IPV6_ZERO_ADDRESS();
+                if (!out_bindings[76]->amNull()) {
+                    excluded_prefix = IOAddress(out_bindings[76]->getString());
+                }
+                last_pd_pool = Pool6::create(IOAddress(out_bindings[21]->getString()),
                                              out_bindings[22]->getInteger<uint8_t>(),
-                                             out_bindings[23]->getInteger<uint8_t>());
+                                             out_bindings[23]->getInteger<uint8_t>(),
+                                             excluded_prefix,
+                                             out_bindings[77]->getInteger<uint8_t>());
+                // pd pool client_class (78)
+                if (!out_bindings[78]->amNull()) {
+                    last_pd_pool->allowClientClass(out_bindings[78]->getString());
+                }
+
+                // pd pool require_client_classes (79)
+                ElementPtr require_element = out_bindings[79]->getJSON();
+                if (require_element) {
+                    if (require_element->getType() != Element::list) {
+                        isc_throw(BadValue, "invalid pd pool require_client_classes value "
+                                  << out_bindings[79]->getString());
+                    }
+                    for (auto i = 0; i < require_element->size(); ++i) {
+                        auto require_item = require_element->get(i);
+                        if (require_item->getType() != Element::string) {
+                            isc_throw(BadValue, "elements of pd pool require_client_classes list must"
+                                      "be valid strings");
+                        }
+                        last_pd_pool->requireClientClass(require_item->stringValue());
+                    }
+                }
+
+                // pd pool user_context (80)
+                ElementPtr user_context = out_bindings[80]->getJSON();
+                if (user_context) {
+                    last_pd_pool->setContext(user_context);
+                }
+
                 last_subnet->addPool(last_pd_pool);
             }
 
@@ -746,6 +821,9 @@ public:
             MySqlBinding::createString(POOL_ADDRESS6_BUF_LENGTH), // pool: start_address
             MySqlBinding::createString(POOL_ADDRESS6_BUF_LENGTH), // pool: end_address
             MySqlBinding::createInteger<uint32_t>(), // pool: subnet_id
+            MySqlBinding::createString(CLIENT_CLASS_BUF_LENGTH), // pool: client_class
+            MySqlBinding::createString(REQUIRE_CLIENT_CLASSES_BUF_LENGTH), // pool: require_client_classes
+            MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pool: user_context
             MySqlBinding::createTimestamp(), // pool: modification_ts
             MySqlBinding::createInteger<uint64_t>(), // pool option: option_id
             MySqlBinding::createInteger<uint16_t>(), // pool option: code
@@ -777,16 +855,46 @@ public:
                 last_pool = Pool6::create(Lease::TYPE_NA,
                                           IOAddress(out_bindings[1]->getString()),
                                           IOAddress(out_bindings[2]->getString()));
+                // pool client_class (4)
+                if (!out_bindings[4]->amNull()) {
+                    last_pool->allowClientClass(out_bindings[4]->getString());
+                }
+
+                // pool require_client_classes (5)
+                ElementPtr require_element = out_bindings[5]->getJSON();
+                if (require_element) {
+                    if (require_element->getType() != Element::list) {
+                        isc_throw(BadValue, "invalid pool require_client_classes value "
+                                  << out_bindings[5]->getString());
+                    }
+                    for (auto i = 0; i < require_element->size(); ++i) {
+                        auto require_item = require_element->get(i);
+                        if (require_item->getType() != Element::string) {
+                            isc_throw(BadValue, "elements of pool require_client_classes list must"
+                                      "be valid strings");
+                        }
+                        last_pool->requireClientClass(require_item->stringValue());
+                    }
+                }
+
+                // pool user_context (6)
+                ElementPtr user_context = out_bindings[6]->getJSON();
+                if (user_context) {
+                    last_pool->setContext(user_context);
+                }
+
+                // pool: modification_ts (7)
+
                 pools.push_back(last_pool);
                 pool_ids.push_back(last_pool_id);
             }
 
-            // Parse pool specific option.
-            if (last_pool && !out_bindings[5]->amNull() &&
-                (last_pool_option_id < out_bindings[5]->getInteger<uint64_t>())) {
-                last_pool_option_id = out_bindings[5]->getInteger<uint64_t>();
+            // Parse pool specific option (8).
+            if (last_pool && !out_bindings[8]->amNull() &&
+                (last_pool_option_id < out_bindings[8]->getInteger<uint64_t>())) {
+                last_pool_option_id = out_bindings[8]->getInteger<uint64_t>();
 
-                OptionDescriptorPtr desc = processOptionRow(Option::V6, out_bindings.begin() + 5);
+                OptionDescriptorPtr desc = processOptionRow(Option::V6, out_bindings.begin() + 8);
                 if (desc) {
                     last_pool->getCfgOption()->add(*desc, desc->space_name_);
                 }
@@ -817,6 +925,11 @@ public:
             MySqlBinding::createInteger<uint8_t>(), // pd pool: prefix_length
             MySqlBinding::createInteger<uint8_t>(), // pd pool: delegated_prefix_length
             MySqlBinding::createInteger<uint32_t>(), // pd pool: subnet_id
+            MySqlBinding::createString(POOL_ADDRESS6_BUF_LENGTH), // pd pool: excluded_prefix
+            MySqlBinding::createInteger<uint8_t>(), // pd pool: excluded_prefix_length
+            MySqlBinding::createString(CLIENT_CLASS_BUF_LENGTH), // pd pool: client_class
+            MySqlBinding::createString(REQUIRE_CLIENT_CLASSES_BUF_LENGTH), // pd pool: require_client_classes
+            MySqlBinding::createString(USER_CONTEXT_BUF_LENGTH), // pd pool: user_context
             MySqlBinding::createTimestamp(), // pd pool: modification_ts
             MySqlBinding::createInteger<uint64_t>(), // pd pool option: option_id
             MySqlBinding::createInteger<uint16_t>(), // pd pool option: code
@@ -845,20 +958,58 @@ public:
 
                 last_pd_pool_id = out_bindings[0]->getInteger<uint64_t>();
 
-                last_pd_pool = Pool6::create(Lease::TYPE_PD,
-                                             IOAddress(out_bindings[1]->getString()),
+                // excluded_prefix (5) and excluded_prefix_length (6)
+                IOAddress excluded_prefix = IOAddress::IPV6_ZERO_ADDRESS();
+                if (!out_bindings[5]->amNull()) {
+                    excluded_prefix = IOAddress(out_bindings[5]->getString());
+                }
+
+                last_pd_pool = Pool6::create(IOAddress(out_bindings[1]->getString()),
                                              out_bindings[2]->getInteger<uint8_t>(),
-                                             out_bindings[3]->getInteger<uint8_t>());
+                                             out_bindings[3]->getInteger<uint8_t>(),
+                                             excluded_prefix,
+                                             out_bindings[6]->getInteger<uint8_t>());
+
+                // pd pool client_class (7)
+                if (!out_bindings[7]->amNull()) {
+                    last_pd_pool->allowClientClass(out_bindings[7]->getString());
+                }
+
+                // pd pool require_client_classes (8)
+                ElementPtr require_element = out_bindings[8]->getJSON();
+                if (require_element) {
+                    if (require_element->getType() != Element::list) {
+                        isc_throw(BadValue, "invalid pd pool require_client_classes value "
+                                  << out_bindings[8]->getString());
+                    }
+                    for (auto i = 0; i < require_element->size(); ++i) {
+                        auto require_item = require_element->get(i);
+                        if (require_item->getType() != Element::string) {
+                            isc_throw(BadValue, "elements of pd pool require_client_classes list must"
+                                      "be valid strings");
+                        }
+                        last_pd_pool->requireClientClass(require_item->stringValue());
+                    }
+                }
+
+                // pool user_context (9)
+                ElementPtr user_context = out_bindings[9]->getJSON();
+                if (user_context) {
+                    last_pd_pool->setContext(user_context);
+                }
+
+                // pd pool user_context (10)
+
                 pd_pools.push_back(last_pd_pool);
                 pd_pool_ids.push_back(last_pd_pool_id);
             }
 
-            // Parse pool specific option between 6 and 19
-            if (last_pd_pool && !out_bindings[6]->amNull() &&
-                (last_pd_pool_option_id < out_bindings[6]->getInteger<uint64_t>())) {
-                last_pd_pool_option_id = out_bindings[6]->getInteger<uint64_t>();
+            // Parse pd pool specific option between 11 and 24
+            if (last_pd_pool && !out_bindings[11]->amNull() &&
+                (last_pd_pool_option_id < out_bindings[11]->getInteger<uint64_t>())) {
+                last_pd_pool_option_id = out_bindings[11]->getInteger<uint64_t>();
 
-                OptionDescriptorPtr desc = processOptionRow(Option::V6, out_bindings.begin() + 6);
+                OptionDescriptorPtr desc = processOptionRow(Option::V6, out_bindings.begin() + 11);
                 if (desc) {
                     last_pd_pool->getCfgOption()->add(*desc, desc->space_name_);
                 }
@@ -1104,6 +1255,9 @@ public:
             MySqlBinding::createString(pool->getFirstAddress().toText()),
             MySqlBinding::createString(pool->getLastAddress().toText()),
             MySqlBinding::createInteger<uint32_t>(static_cast<uint32_t>(subnet->getID())),
+            MySqlBinding::condCreateString(pool->getClientClass()),
+            createInputRequiredClassesBinding(pool),
+            createInputContextBinding(pool),
             MySqlBinding::createTimestamp(subnet->getModificationTime())
         };
 
@@ -1133,11 +1287,28 @@ public:
                        const Subnet6Ptr& subnet) {
         int plen = prefixLengthFromRange(pd_pool->getFirstAddress(),
                                          pd_pool->getLastAddress());
+
+        // Extract excluded prefix components.
+        Optional<std::string> xprefix_txt;
+        uint8_t xlen = 0;
+        const Option6PDExcludePtr& xopt = pd_pool->getPrefixExcludeOption();
+        if (xopt) {
+            const IOAddress& prefix = pd_pool->getFirstAddress();
+            const IOAddress& xprefix = xopt->getExcludedPrefix(prefix, plen);
+            xprefix_txt = xprefix.toText();
+            xlen = xopt->getExcludedPrefixLength();
+        }
+
         MySqlBindingCollection in_bindings = {
             MySqlBinding::createString(pd_pool->getFirstAddress().toText()),
             MySqlBinding::createInteger<uint8_t>(static_cast<uint8_t>(plen)),
             MySqlBinding::createInteger<uint8_t>(pd_pool->getLength()),
             MySqlBinding::createInteger<uint32_t>(static_cast<uint32_t>(subnet->getID())),
+            MySqlBinding::condCreateString(xprefix_txt),
+            MySqlBinding::createInteger<uint8_t>(xlen),
+            MySqlBinding::condCreateString(pd_pool->getClientClass()),
+            createInputRequiredClassesBinding(pd_pool),
+            createInputContextBinding(pd_pool),
             MySqlBinding::createTimestamp(subnet->getModificationTime())
         };
 
@@ -2453,6 +2624,9 @@ TaggedStatementArray tagged_statements = { {
       "  p.start_address,"
       "  p.end_address,"
       "  p.subnet_id,"
+      "  p.client_class,"
+      "  p.require_client_classes,"
+      "  p.user_context,"
       "  p.modification_ts,"
       "  x.option_id,"
       "  x.code,"
@@ -2481,6 +2655,11 @@ TaggedStatementArray tagged_statements = { {
       "  p.prefix_length,"
       "  p.delegated_prefix_length,"
       "  p.subnet_id,"
+      "  p.excluded_prefix,"
+      "  p.excluded_prefix_length,"
+      "  p.client_class,"
+      "  p.require_client_classes,"
+      "  p.user_context,"
       "  p.modification_ts,"
       "  x.option_id,"
       "  x.code,"
index d2ec66a266a92fcb92eb473ff743264bacde6c5d..b3a9a32a5e60ee3db7135ab64772ae5512f46ac7 100644 (file)
@@ -932,22 +932,6 @@ MySqlConfigBackendImpl::createInputRelayBinding(const NetworkPtr& network) {
             MySqlBinding::condCreateString(relay_element->str()));
 }
 
-MySqlBindingPtr
-MySqlConfigBackendImpl::createInputRequiredClassesBinding(const NetworkPtr& network) {
-    // Create JSON list of required classes.
-    ElementPtr required_classes_element = Element::createList();
-    const auto& required_classes = network->getRequiredClasses();
-    for (auto required_class = required_classes.cbegin();
-         required_class != required_classes.cend();
-         ++required_class) {
-        required_classes_element->add(Element::create(*required_class));
-    }
-
-    return (required_classes_element ?
-            MySqlBinding::createString(required_classes_element->str()) :
-            MySqlBinding::createNull());
-}
-
 MySqlBindingPtr
 MySqlConfigBackendImpl::createOptionValueBinding(const OptionDescriptorPtr& option) {
     OptionPtr opt = option->option_;
index 461c7670a22fe8b0bec773c3d2f5cfec0868a66a..d2e3c6f987ae7e06d21b1e442c720566c3bcbda3 100644 (file)
@@ -575,11 +575,26 @@ public:
 
     /// @brief Creates input binding for 'require_client_classes' parameter.
     ///
-    /// @param network Pointer to a shared network or subnet for which binding
-    /// should be created.
+    /// @tparam T of pointer to objects with getRequiredClasses
+    /// method, e.g. shared network, subnet, pool or prefix delegation pool.
+    /// @param object Pointer to an object with getRequiredClasses method
     /// @return Pointer to the binding (possibly null binding if there are no
     /// required classes specified).
-    db::MySqlBindingPtr createInputRequiredClassesBinding(const NetworkPtr& network);
+    template<typename T>
+    db::MySqlBindingPtr createInputRequiredClassesBinding(const T& object) {
+        // Create JSON list of required classes.
+        data::ElementPtr required_classes_element = data::Element::createList();
+        const auto& required_classes = object->getRequiredClasses();
+        for (auto required_class = required_classes.cbegin();
+             required_class != required_classes.cend();
+             ++required_class) {
+            required_classes_element->add(data::Element::create(*required_class));
+        }
+
+        return (required_classes_element ?
+                db::MySqlBinding::createString(required_classes_element->str()) :
+                db::MySqlBinding::createNull());
+    }
 
     /// @brief Creates input binding for user context parameter.
     ///
index 7eb8a8a8e02e590f0741b6298b961d86fab89ebc..9670890ede7ad7e44e67646bea6fd735fc1be49f 100644 (file)
@@ -106,6 +106,9 @@ namespace {
     "  s.authoritative," \
     "  s.min_valid_lifetime," \
     "  s.max_valid_lifetime," \
+    "  p.client_class," \
+    "  p.require_client_classes," \
+    "  p.user_context," \
     "  srv.tag " \
     "FROM dhcp4_subnet AS s " \
     server_join \
@@ -217,6 +220,14 @@ namespace {
     "  s.max_preferred_lifetime," \
     "  s.min_valid_lifetime," \
     "  s.max_valid_lifetime," \
+    "  p.client_class," \
+    "  p.require_client_classes," \
+    "  p.user_context," \
+    "  d.excluded_prefix," \
+    "  d.excluded_prefix_length," \
+    "  d.client_class," \
+    "  d.require_client_classes," \
+    "  d.user_context," \
     "  srv.tag " \
     "FROM dhcp6_subnet AS s " \
     server_join \
@@ -518,8 +529,11 @@ namespace {
     "  start_address," \
     "  end_address," \
     "  subnet_id," \
+    "  client_class," \
+    "  require_client_classes," \
+    "  user_context," \
     "  modification_ts" \
-    ") VALUES (?, ?, ?, ?)"
+    ") VALUES (?, ?, ?, ?, ?, ?, ?)"
 #endif
 
 #ifndef MYSQL_INSERT_PD_POOL
@@ -529,8 +543,13 @@ namespace {
     "  prefix_length," \
     "  delegated_prefix_length," \
     "  subnet_id," \
+    "  excluded_prefix," \
+    "  excluded_prefix_length," \
+    "  client_class," \
+    "  require_client_classes," \
+    "  user_context," \
     "  modification_ts" \
-    ") VALUES (?, ?, ?, ?, ?)"
+    ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
 #endif
 
 #ifndef MYSQL_INSERT_SHARED_NETWORK_SERVER
index 7fae77ac53d79be47420d0ff2b04c52c3c1eda9b..d2d71c176ad31385ad57e8548d18a133b8f77dcd 100644 (file)
@@ -2476,6 +2476,24 @@ END
 $$
 DELIMITER ;
 
+# add missing fields in pools.
+ALTER TABLE dhcp4_pool
+    ADD COLUMN client_class VARCHAR(128) DEFAULT NULL,
+    ADD COLUMN require_client_classes LONGTEXT,
+    ADD COLUMN user_context LONGTEXT;
+
+ALTER TABLE dhcp6_pd_pool
+    ADD COLUMN excluded_prefix VARCHAR(45) DEFAULT NULL,
+    ADD COLUMN excluded_prefix_length TINYINT(3) NOT NULL,
+    ADD COLUMN client_class VARCHAR(128) DEFAULT NULL,
+    ADD COLUMN require_client_classes LONGTEXT,
+    ADD COLUMN user_context LONGTEXT;
+
+ALTER TABLE dhcp6_pool
+    ADD COLUMN client_class VARCHAR(128) DEFAULT NULL,
+    ADD COLUMN require_client_classes LONGTEXT,
+    ADD COLUMN user_context LONGTEXT;
+
 # Update the schema version number
 UPDATE schema_version
 SET version = '8', minor = '2';
index fed3be3aecdbe7ac5a1c97f979bac185c716d140..dbdc5a02da51b5cb40d56a8b0bf5ed2d3224c49c 100644 (file)
@@ -117,6 +117,24 @@ END
 $$
 DELIMITER ;
 
+# add missing fields in pools.
+ALTER TABLE dhcp4_pool
+    ADD COLUMN client_class VARCHAR(128) DEFAULT NULL,
+    ADD COLUMN require_client_classes LONGTEXT,
+    ADD COLUMN user_context LONGTEXT;
+
+ALTER TABLE dhcp6_pd_pool
+    ADD COLUMN excluded_prefix VARCHAR(45) DEFAULT NULL,
+    ADD COLUMN excluded_prefix_length TINYINT(3) NOT NULL,
+    ADD COLUMN client_class VARCHAR(128) DEFAULT NULL,
+    ADD COLUMN require_client_classes LONGTEXT,
+    ADD COLUMN user_context LONGTEXT;
+
+ALTER TABLE dhcp6_pool
+    ADD COLUMN client_class VARCHAR(128) DEFAULT NULL,
+    ADD COLUMN require_client_classes LONGTEXT,
+    ADD COLUMN user_context LONGTEXT;
+
 # Update the schema version number
 UPDATE schema_version
 SET version = '8', minor = '2';