# Let's pick VoIP phones. Those that send their class identifiers
# as Aastra, should belong to VoIP class. For a list of all options,
-# see www.iana.org/assignments/bootp-dhcp-parameters/
+# see www.iana.org/assignments/bootp-dhcp-parameters/.
+# In this particular class, we want to set specific values
+# of certain DHCPv4 fields. If the incoming packet matches the
+# test, those fields will be set in outgoing responses.
{
"name": "VoIP",
- "test": "substring(option[60].hex,0,6) == 'Aastra'"
+ "test": "substring(option[60].hex,0,6) == 'Aastra'",
+ "next-server": "192.0.2.254",
+ "server-hostname": "hal9000",
+ "boot-file-name": "/dev/null"
}
],
# to that class are allowed for that subnet.
"subnet4": [
{
-# This one is for VoIP devices only.
+# This one is for VoIP devices only.
"pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ],
"subnet": "192.0.2.0/24",
"client-class": "VoIP",
"data": "10.1.1.202,10.1.1.203"
}
]
+ },
+# This reservation is for a client that needs specific DHCPv4 fields to be
+# set. Three supported fields are next-server, server-hostname and
+# boot-file-name
+ {
+ "client-id": "01:0a:0b:0c:0d:0e:of",
+ "ip-address": "192.0.2.205",
+ "next-server": "192.0.2.1",
+ "server-hostname": "hal9000",
+ "boot-file-name": "/dev/null"
}
]
}
}
}
+\"echo-client-id\" {
+ switch(driver.ctx_) {
+ case isc::dhcp::Parser4Context::SUBNET4:
+ return isc::dhcp::Dhcp4Parser::make_ECHO_CLIENT_ID(driver.loc_);
+ default:
+ return isc::dhcp::Dhcp4Parser::make_STRING("echo-client-id", driver.loc_);
+ }
+}
+
+\"match-client-id\" {
+ switch(driver.ctx_) {
+ case isc::dhcp::Parser4Context::SUBNET4:
+ return isc::dhcp::Dhcp4Parser::make_MATCH_CLIENT_ID(driver.loc_);
+ default:
+ return isc::dhcp::Dhcp4Parser::make_STRING("match-client-id", driver.loc_);
+ }
+}
+
+\"next-server\" {
+ switch(driver.ctx_) {
+ case isc::dhcp::Parser4Context::SUBNET4:
+ case isc::dhcp::Parser4Context::RESERVATIONS:
+ case isc::dhcp::Parser4Context::CLIENT_CLASSES:
+ return isc::dhcp::Dhcp4Parser::make_NEXT_SERVER(driver.loc_);
+ default:
+ return isc::dhcp::Dhcp4Parser::make_STRING("next-server", driver.loc_);
+ }
+}
+
+\"server-hostname\" {
+ switch(driver.ctx_) {
+ case isc::dhcp::Parser4Context::SUBNET4:
+ case isc::dhcp::Parser4Context::RESERVATIONS:
+ case isc::dhcp::Parser4Context::CLIENT_CLASSES:
+ return isc::dhcp::Dhcp4Parser::make_SERVER_HOSTNAME(driver.loc_);
+ default:
+ return isc::dhcp::Dhcp4Parser::make_STRING("server-hostname", driver.loc_);
+ }
+}
+
+\"boot-file-name\" {
+ switch(driver.ctx_) {
+ case isc::dhcp::Parser4Context::SUBNET4:
+ case isc::dhcp::Parser4Context::RESERVATIONS:
+ case isc::dhcp::Parser4Context::CLIENT_CLASSES:
+ return isc::dhcp::Dhcp4Parser::make_BOOT_FILE_NAME(driver.loc_);
+ default:
+ return isc::dhcp::Dhcp4Parser::make_STRING("boot-file-name", driver.loc_);
+ }
+}
+
+
{JSONString} {
// A string has been matched. It contains the actual string and single quotes.
INTERFACES_CONFIG "interfaces-config"
INTERFACES "interfaces"
+ ECHO_CLIENT_ID "echo-client-id"
+ MATCH_CLIENT_ID "match-client-id"
+ NEXT_SERVER "next-server"
+ SERVER_HOSTNAME "server-hostname"
+ BOOT_FILE_NAME "boot-file-name"
+
LEASE_DATABASE "lease-database"
HOSTS_DATABASE "hosts-database"
TYPE "type"
| version
| control_socket
| dhcp_ddns
+ | echo_client_id
+ | match_client_id
+ | next_server
| unknown_map_entry
;
ctx.stack_.back()->set("decline-probation-period", dpp);
};
+echo_client_id: ECHO_CLIENT_ID COLON BOOLEAN {
+ ElementPtr echo(new BoolElement($3, ctx.loc2pos(@1)));
+ ctx.stack_.back()->set("echo-client-id", echo);
+};
+
+match_client_id: MATCH_CLIENT_ID COLON BOOLEAN {
+ ElementPtr match(new BoolElement($3, ctx.loc2pos(@1)));
+ ctx.stack_.back()->set("match-client-id", match);
+};
+
+
interfaces_config: INTERFACES_CONFIG {
ElementPtr i(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.back()->set("interfaces-config", i);
| hw_address
| hostname
| option_data_list
+ | next_server
+ | server_hostname
+ | boot_file_name
| unknown_map_entry
;
+next_server: NEXT_SERVER {
+ ctx.enter(ctx.NO_KEYWORD);
+} COLON STRING {
+ ElementPtr next_server(new StringElement($4, ctx.loc2pos(@1)));
+ ctx.stack_.back()->set("next-server", next_server);
+ ctx.leave();
+};
+
+server_hostname: SERVER_HOSTNAME {
+ ctx.enter(ctx.NO_KEYWORD);
+} COLON STRING {
+ ElementPtr srv(new StringElement($4, ctx.loc2pos(@1)));
+ ctx.stack_.back()->set("server-hostname", srv);
+ ctx.leave();
+};
+
+boot_file_name: BOOT_FILE_NAME {
+ ctx.enter(ctx.NO_KEYWORD);
+} COLON STRING {
+ ElementPtr bootfile(new StringElement($4, ctx.loc2pos(@1)));
+ ctx.stack_.back()->set("boot-file-name", bootfile);
+ ctx.leave();
+};
+
ip_address: IP_ADDRESS {
+ ctx.enter(ctx.NO_KEYWORD);
} COLON STRING {
ElementPtr addr(new StringElement($4, ctx.loc2pos(@1)));
ctx.stack_.back()->set("ip-address", addr);
+ ctx.leave();
};
duid: DUID {
client_class_param: client_class_name
| client_class_test
| option_data_list
+ | next_server
+ | server_hostname
+ | boot_file_name
| unknown_map_entry
;