From c83f307b62babd936f752eb81c199704924ec2f2 Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Mon, 10 Oct 2022 14:00:29 +0200 Subject: [PATCH] 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 --- repos/os/src/server/nic_router/interface.cc | 24 ++++++++++++++------- repos/os/src/server/nic_router/interface.h | 7 +++--- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/repos/os/src/server/nic_router/interface.cc b/repos/os/src/server/nic_router/interface.cc index 7ac1f6989c..5a45fbcb97 100644 --- a/repos/os/src/server/nic_router/interface.cc +++ b/repos/os/src/server/nic_router/interface.cc @@ -759,9 +759,10 @@ void Interface::_new_dhcp_allocation(Ethernet_frame ð, } -void Interface::_handle_dhcp_request(Ethernet_frame ð, - Dhcp_packet &dhcp, - Domain &local_domain) +void Interface::_handle_dhcp_request(Ethernet_frame ð, + 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 ð, 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 ð, _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 ð, 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::Invalid) { throw Drop_packet("DHCP request while DHCP server inactive"); } diff --git a/repos/os/src/server/nic_router/interface.h b/repos/os/src/server/nic_router/interface.h index c97d9ac7e8..f866f34198 100644 --- a/repos/os/src/server/nic_router/interface.h +++ b/repos/os/src/server/nic_router/interface.h @@ -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 ð, - Dhcp_packet &dhcp, - Domain &local_domain); + void _handle_dhcp_request(Ethernet_frame ð, + Dhcp_packet &dhcp, + Domain &local_domain, + Ipv4_address_prefix const &local_intf); void _handle_ip(Ethernet_frame ð, Size_guard &size_guard,