Commit b35c5666 authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰

[5132] parser updated, unit-tests implemented

parent 123d69f2
......@@ -718,6 +718,16 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
}
}
\"flex-id\" {
switch(driver.ctx_) {
case isc::dhcp::Parser4Context::HOST_RESERVATION_IDENTIFIERS:
case isc::dhcp::Parser4Context::RESERVATIONS:
return isc::dhcp::Dhcp4Parser::make_FLEX_ID(driver.loc_);
default:
return isc::dhcp::Dhcp4Parser::make_STRING("flex-id", driver.loc_);
}
}
\"hostname\" {
switch(driver.ctx_) {
case isc::dhcp::Parser4Context::RESERVATIONS:
......
......@@ -122,6 +122,7 @@ using namespace std;
CIRCUIT_ID "circuit-id"
CLIENT_ID "client-id"
HOSTNAME "hostname"
FLEX_ID "flex-id"
RELAY "relay"
IP_ADDRESS "ip-address"
......@@ -631,6 +632,7 @@ host_reservation_identifier: duid_id
| hw_address_id
| circuit_id
| client_id
| flex_id
;
duid_id : DUID {
......@@ -653,6 +655,11 @@ client_id : CLIENT_ID {
ctx.stack_.back()->add(client);
};
flex_id: FLEX_ID {
ElementPtr flex_id(new StringElement("flex-id", ctx.loc2pos(@1)));
ctx.stack_.back()->add(flex_id);
}
hooks_libraries: HOOKS_LIBRARIES {
ElementPtr l(new ListElement(ctx.loc2pos(@1)));
ctx.stack_.back()->set("hooks-libraries", l);
......@@ -1241,6 +1248,7 @@ reservation_param: duid
| reservation_client_classes
| client_id_value
| circuit_id_value
| flex_id_value
| ip_address
| hw_address
| hostname
......@@ -1315,6 +1323,13 @@ circuit_id_value: CIRCUIT_ID {
ctx.leave();
};
flex_id_value: FLEX_ID {
ctx.enter(ctx.NO_KEYWORD);
} COLON STRING {
ElementPtr hw(new StringElement($4, ctx.loc2pos(@4)));
ctx.stack_.back()->set("flex-id", hw);
ctx.leave();
};
hostname: HOSTNAME {
ctx.enter(ctx.NO_KEYWORD);
......
......@@ -42,6 +42,7 @@ TEST_F(Dhcpv4SrvTest, Hooks) {
int hook_index_lease4_release = -1;
int hook_index_pkt4_send = -1;
int hook_index_buffer4_send = -1;
int hook_index_host4_identifier= -1;
// check if appropriate indexes are set
EXPECT_NO_THROW(hook_index_buffer4_receive = ServerHooks::getServerHooks()
......@@ -56,6 +57,8 @@ TEST_F(Dhcpv4SrvTest, Hooks) {
.getIndex("pkt4_send"));
EXPECT_NO_THROW(hook_index_buffer4_send = ServerHooks::getServerHooks()
.getIndex("buffer4_send"));
EXPECT_NO_THROW(hook_index_host4_identifier = ServerHooks::getServerHooks()
.getIndex("host4_identifier"));
EXPECT_TRUE(hook_index_buffer4_receive > 0);
EXPECT_TRUE(hook_index_pkt4_receive > 0);
......@@ -63,6 +66,7 @@ TEST_F(Dhcpv4SrvTest, Hooks) {
EXPECT_TRUE(hook_index_lease4_release > 0);
EXPECT_TRUE(hook_index_pkt4_send > 0);
EXPECT_TRUE(hook_index_buffer4_send > 0);
EXPECT_TRUE(hook_index_host4_identifier > 0);
}
// A dummy MAC address, padded with 0s
......@@ -111,6 +115,7 @@ public:
HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("lease4_renew");
HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("lease4_release");
HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("lease4_decline");
HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("host4_identifier");
HooksManager::getSharedCalloutManager().reset();
delete srv_;
......@@ -542,6 +547,24 @@ public:
return (lease4_decline_callout(callout_handle));
}
/// @brief Test host4_identifier by setting identifier to "foo"
///
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
host4_identifier_foo_callout(CalloutHandle& handle) {
callback_name_ = string("host4_identifier");
std::vector<uint8_t> id(3);
id[0] = 0x66; // f
id[1] = 0x6f; // o
id[2] = 0x6f; // o
handle.setArgument("id_value", id);
handle.setArgument("id_type", Host::IDENT_FLEX);
return (0);
}
/// resets buffers used to store data received by callouts
void resetCalloutBuffers() {
callback_name_ = string("");
......@@ -1702,6 +1725,74 @@ TEST_F(HooksDhcpv4SrvTest, HooksDeclineDrop) {
}
// Checks if callout installed on host4_identifier can generate an
// identifier and whether that identifier is actually used.
TEST_F(HooksDhcpv4SrvTest, host4_identifier) {
IfaceMgrTestConfig test_config(true);
IfaceMgr::instance().openSockets4();
// Configure a subnet with host reservation. The reservation is based on
// flexible identifier value of 'foo'. That's exactly what the
// host4_identifier_foo_callout sets.
string config = "{ \"interfaces-config\": {"
" \"interfaces\": [ \"*\" ]"
"},"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"host-reservation-identifiers\": [ \"flex-id\" ], "
"\"subnet4\": [ { "
" \"pools\": [ { \"pool\": \"192.0.2.0/25\" } ],"
" \"subnet\": \"192.0.2.0/24\", "
" \"interface\": \"eth0\", "
" \"reservations\": ["
" {"
" \"flex-id\": \"'foo'\","
" \"ip-address\": \"192.0.2.201\""
" }"
" ]"
"} ],"
"\"valid-lifetime\": 4000 }";
ConstElementPtr json;
EXPECT_NO_THROW(json = parseDHCP4(config));
ASSERT_TRUE(json);
ConstElementPtr status;
// Configure the server and make sure the config is accepted
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
ASSERT_TRUE(status);
comment_ = parseAnswer(rcode_, status);
ASSERT_EQ(0, rcode_);
CfgMgr::instance().commit();
// Install host4_identifier_foo_callout
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
"host4_identifier", host4_identifier_foo_callout));
// Let's create a simple DISCOVER
Pkt4Ptr sol = generateSimpleDiscover();
// Simulate that we have received that traffic
srv_->fakeReceive(sol);
// Server will now process to run its normal loop, but instead of calling
// IfaceMgr::receive4(), it will read all packets from the list set by
// fakeReceive()
// In particular, it should call registered pkt4_receive callback.
srv_->run();
// check that the server did send a response
ASSERT_EQ(1, srv_->fake_sent_.size());
// Make sure that we received a response
Pkt4Ptr adv = srv_->fake_sent_.front();
ASSERT_TRUE(adv);
// Make sure the address offered is the one that was reserved.
EXPECT_EQ("192.0.2.201", adv->getYiaddr().toText());
}
// Verifies that libraries are unloaded by server destruction
// The callout libraries write their library index number to a marker
// file upon load and unload, making it simple to test whether or not
......
......@@ -713,8 +713,12 @@ CfgHosts::toElement4() const {
const std::vector<uint8_t>& bin = (*host)->getIdentifier();
std::string client_id = util::encode::encodeHex(bin);
map->set("client-id", Element::create(client_id));
} else if (id_type == Host::IDENT_FLEX) {
const std::vector<uint8_t>& bin = (*host)->getIdentifier();
std::string flex = util::encode::encodeHex(bin);
map->set("flex-id", Element::create(flex));
} else {
isc_throw(ToElementError, "invalid DUID type: " << id_type);
isc_throw(ToElementError, "invalid identifier type: " << id_type);
}
// Set the reservation
const IOAddress& address = (*host)->getIPv4Reservation();
......
......@@ -160,7 +160,8 @@ Host::getIdentifierType(const std::string& identifier_name) {
} else if (identifier_name == "client-id") {
return (IDENT_CLIENT_ID);
} else if (identifier_name == "flex-id") {
return (IDENT_FLEX);
} else {
isc_throw(isc::BadValue, "invalid client identifier type '"
<< identifier_name << "'");
......@@ -205,7 +206,7 @@ Host::getIdentifierAsText(const IdentifierType& type, const uint8_t* value,
s << "client-id";
break;
case IDENT_FLEX:
s << "flex";
s << "flex-id";
default:
// This should never happen actually, unless we add new identifier
// and forget to add a case for it above.
......@@ -231,6 +232,9 @@ Host::getIdentifierName(const IdentifierType& type) {
case Host::IDENT_CLIENT_ID:
return ("client-id");
case Host::IDENT_FLEX:
return ("flex-id");
default:
;
}
......
......@@ -42,6 +42,7 @@ getSupportedParams4(const bool identifiers_only = false) {
identifiers_set.insert("duid");
identifiers_set.insert("circuit-id");
identifiers_set.insert("client-id");
identifiers_set.insert("flex-id");
}
// Copy identifiers and add all other parameters.
if (params_set.empty()) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment