nic_router: consider DHCP client optimization

Some DHCP clients (Debian VM in Sculpt) persistently store the last lease they
obtained and try to directly DHCP REQUEST it on a new startup whithout doing
DHCP DISCOVER beforehand. In case the NIC router doesn't know about the lease
anymore (timeout, new router instance), the router used to just ignore the DHCP
REQUEST. This led to significant delays in the network startup of the client
(delayed retries until give-up and DHCP DISCOVER). With this commit, the router
answers such packets with a DHCP NAK instead, causing the client to directly
switch to DHCP DISCOVER.

Fixes #4634
This commit is contained in:
Martin Stein 2022-10-10 14:00:29 +02:00 committed by Christian Helmuth
parent 5dfd0274b9
commit c83f307b62
2 changed files with 20 additions and 11 deletions

View File

@ -759,9 +759,10 @@ void Interface::_new_dhcp_allocation(Ethernet_frame &eth,
}
void Interface::_handle_dhcp_request(Ethernet_frame &eth,
Dhcp_packet &dhcp,
Domain &local_domain)
void Interface::_handle_dhcp_request(Ethernet_frame &eth,
Dhcp_packet &dhcp,
Domain &local_domain,
Ipv4_address_prefix const &local_intf)
{
try {
/* try to get the DHCP server config of this interface */
@ -776,9 +777,6 @@ void Interface::_handle_dhcp_request(Ethernet_frame &eth,
Dhcp_allocation &allocation =
_dhcp_allocations.find_by_mac(dhcp.client_mac());
Ipv4_address_prefix const &local_intf =
local_domain.ip_config().interface();
switch (msg_type) {
case Dhcp_packet::Message_type::DISCOVER:
@ -861,7 +859,14 @@ void Interface::_handle_dhcp_request(Ethernet_frame &eth,
_new_dhcp_allocation(eth, dhcp, dhcp_srv, local_domain);
return;
case Dhcp_packet::Message_type::REQUEST: throw Drop_packet("DHCP REQUEST from client without offered/acked IP");
case Dhcp_packet::Message_type::REQUEST:
_send_dhcp_reply(dhcp_srv, eth.src(), dhcp.client_mac(),
Ipv4_address { },
Dhcp_packet::Message_type::NAK,
dhcp.xid(), local_intf);
return;
case Dhcp_packet::Message_type::DECLINE: throw Drop_packet("DHCP DECLINE from client without offered/acked IP");
case Dhcp_packet::Message_type::RELEASE: throw Drop_packet("DHCP RELEASE from client without offered/acked IP");
case Dhcp_packet::Message_type::NAK: throw Drop_packet("DHCP NAK from client");
@ -1238,7 +1243,10 @@ void Interface::_handle_ip(Ethernet_frame &eth,
switch (dhcp.op()) {
case Dhcp_packet::REQUEST:
try { _handle_dhcp_request(eth, dhcp, local_domain); }
try {
_handle_dhcp_request(
eth, dhcp, local_domain, local_intf);
}
catch (Pointer<Dhcp_server>::Invalid) {
throw Drop_packet("DHCP request while DHCP server inactive");
}

View File

@ -227,9 +227,10 @@ class Net::Interface : private Interface_list::Element
void _send_arp_reply(Ethernet_frame &request_eth,
Arp_packet &request_arp);
void _handle_dhcp_request(Ethernet_frame &eth,
Dhcp_packet &dhcp,
Domain &local_domain);
void _handle_dhcp_request(Ethernet_frame &eth,
Dhcp_packet &dhcp,
Domain &local_domain,
Ipv4_address_prefix const &local_intf);
void _handle_ip(Ethernet_frame &eth,
Size_guard &size_guard,