|
@@ -410,7 +410,7 @@ TEST_F(Dhcpv4SrvTest, initResponse) {
|
|
|
OptionPtr resp_sbnsel = response->getOption(DHO_SUBNET_SELECTION);
|
|
|
ASSERT_TRUE(resp_sbnsel);
|
|
|
OptionCustomPtr resp_custom =
|
|
|
- boost::dynamic_pointer_cast<OptionCustom>(resp_sbnsel);
|
|
|
+ boost::dynamic_pointer_cast<OptionCustom>(resp_sbnsel);
|
|
|
ASSERT_TRUE(resp_custom);
|
|
|
IOAddress subnet_addr("0.0.0.0");
|
|
|
ASSERT_NO_THROW(subnet_addr = resp_custom->readAddress());
|
|
@@ -1646,8 +1646,8 @@ TEST_F(Dhcpv4SrvTest, vendorOptionsDocsisDefinitions) {
|
|
|
ASSERT_EQ(0, rcode_);
|
|
|
}
|
|
|
|
|
|
-// Checks if client packets are classified properly
|
|
|
-TEST_F(Dhcpv4SrvTest, clientClassification) {
|
|
|
+// Checks if DOCSIS client packets are classified properly
|
|
|
+TEST_F(Dhcpv4SrvTest, docsisClientClassification) {
|
|
|
|
|
|
NakedDhcpv4Srv srv(0);
|
|
|
|
|
@@ -1674,10 +1674,77 @@ TEST_F(Dhcpv4SrvTest, clientClassification) {
|
|
|
EXPECT_FALSE(dis2->inClass(srv.VENDOR_CLASS_PREFIX + "docsis3.0"));
|
|
|
}
|
|
|
|
|
|
+// Checks if client packets are classified properly using match expressions.
|
|
|
+TEST_F(Dhcpv4SrvTest, matchClassification) {
|
|
|
+ NakedDhcpv4Srv srv(0);
|
|
|
+
|
|
|
+ // The router class matches incoming packets with foo in a host-name
|
|
|
+ // option (code 12) and sets an ip-forwarding option in the response
|
|
|
+ string config = "{ \"interfaces-config\": {"
|
|
|
+ " \"interfaces\": [ \"*\" ] }, "
|
|
|
+ "\"rebind-timer\": 2000, "
|
|
|
+ "\"renew-timer\": 1000, "
|
|
|
+ "\"valid-lifetime\": 4000, "
|
|
|
+ "\"subnet4\": [ "
|
|
|
+ "{ \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ],"
|
|
|
+ " \"subnet\": \"192.0.2.0/24\" } ], "
|
|
|
+ "\"client-classes\": [ "
|
|
|
+ "{ \"name\": \"router\","
|
|
|
+ " \"option-data\": ["
|
|
|
+ " { \"name\": \"ip-forwarding\","
|
|
|
+ " \"data\": \"true\" } ],"
|
|
|
+ " \"test\": \"option[12] == 'foo'\" } ] }";
|
|
|
+
|
|
|
+ ElementPtr json = Element::fromJSON(config);
|
|
|
+ ConstElementPtr status;
|
|
|
+
|
|
|
+ // Configure the server and make sure the config is accepted
|
|
|
+ EXPECT_NO_THROW(status = configureDhcp4Server(srv, json));
|
|
|
+ ASSERT_TRUE(status);
|
|
|
+ comment_ = config::parseAnswer(rcode_, status);
|
|
|
+ ASSERT_EQ(0, rcode_);
|
|
|
+
|
|
|
+ CfgMgr::instance().commit();
|
|
|
+
|
|
|
+ // Create packets with enough to select the subnet
|
|
|
+ Pkt4Ptr query1(new Pkt4(DHCPDISCOVER, 1234));
|
|
|
+ query1->setRemoteAddr(IOAddress("192.0.2.1"));
|
|
|
+ Pkt4Ptr query2(new Pkt4(DHCPDISCOVER, 1234));
|
|
|
+ query2->setRemoteAddr(IOAddress("192.0.2.1"));
|
|
|
+
|
|
|
+ // Create and add a host-name option to the first query
|
|
|
+ OptionStringPtr hostname(new OptionString(Option::V4, 12, "foo"));
|
|
|
+ ASSERT_TRUE(hostname);
|
|
|
+ query1->addOption(hostname);
|
|
|
+
|
|
|
+ // Classify packets
|
|
|
+ srv.classifyPacket(query1);
|
|
|
+ srv.classifyPacket(query2);
|
|
|
+
|
|
|
+ // The first packet (and only the first) should be in the router class
|
|
|
+ EXPECT_TRUE(query1->inClass("router"));
|
|
|
+ EXPECT_FALSE(query2->inClass("router"));
|
|
|
+
|
|
|
+ Dhcpv4Exchange ex1 = createExchange(query1);
|
|
|
+ Pkt4Ptr response1 = ex1.getResponse();
|
|
|
+ Dhcpv4Exchange ex2 = createExchange(query2);
|
|
|
+ Pkt4Ptr response2 = ex2.getResponse();
|
|
|
+
|
|
|
+ // Classification processing should add an ip-forwarding option
|
|
|
+ srv.classSpecificProcessing(ex1);
|
|
|
+ OptionPtr opt1 = response1->getOption(DHO_IP_FORWARDING);
|
|
|
+ EXPECT_TRUE(opt1);
|
|
|
+
|
|
|
+ // But only for the first exchange
|
|
|
+ srv.classSpecificProcessing(ex2);
|
|
|
+ OptionPtr opt2 = response2->getOption(DHO_IP_FORWARDING);
|
|
|
+ EXPECT_FALSE(opt2);
|
|
|
+}
|
|
|
+
|
|
|
// Checks if the client-class field is indeed used for subnet selection.
|
|
|
// Note that packet classification is already checked in Dhcpv4SrvTest
|
|
|
-// .clientClassification above.
|
|
|
-TEST_F(Dhcpv4SrvTest, clientClassify2) {
|
|
|
+// .*clientClassification above.
|
|
|
+TEST_F(Dhcpv4SrvTest, clientClassify) {
|
|
|
|
|
|
// This test configures 2 subnets. We actually only need the
|
|
|
// first one, but since there's still this ugly hack that picks
|