netconfig: Try to put gateway mac into ARP cache

In certain situations, it is possible for us to know the MAC of the
default gateway when DHCP finishes.  This is quite typical on many home
network and small network setups.  It is thus possible to pre-populate
the ARP cache with the gateway MAC address to save an extra round trip
at connection time.

Another advantage is during roaming.  After version 4.20, linux kernel
flushes ARP caches by default whenever netdev encounters a no carrier
condition (as is the case during roaming).  This can prevent packets
from going out after a roam for a significant amount of time due to
lost/delayed ARP responses.
This commit is contained in:
Denis Kenzior 2021-10-13 17:49:18 -05:00
parent 5d9e0401fc
commit 2135a4f845
1 changed files with 44 additions and 0 deletions

View File

@ -574,6 +574,39 @@ static struct l_rtnl_address *netconfig_get_dhcp4_address(
return ret;
}
static void netconfig_gateway_to_arp(struct netconfig *netconfig)
{
const struct l_dhcp_lease *lease;
_auto_(l_free) char *server_id = NULL;
_auto_(l_free) char *gw = NULL;
const uint8_t *server_mac;
struct in_addr in_gw;
/* Can only do this for DHCP in certain network setups */
if (netconfig->rtm_protocol != RTPROT_DHCP)
return;
lease = l_dhcp_client_get_lease(netconfig->dhcp_client);
if (!lease)
return;
server_id = l_dhcp_lease_get_server_id(lease);
gw = l_dhcp_lease_get_gateway(lease);
server_mac = l_dhcp_lease_get_server_mac(lease);
if (strcmp(server_id, gw) || !server_mac)
return;
l_debug("Gateway MAC is known, setting into ARP cache");
in_gw.s_addr = l_dhcp_lease_get_gateway_u32(lease);
if (!l_rtnl_neighbor_set_hwaddr(rtnl, netconfig->ifindex, AF_INET,
&in_gw, server_mac, ETH_ALEN,
netconfig_set_neighbor_entry_cb, NULL,
NULL))
l_debug("l_rtnl_neighbor_set_hwaddr failed");
}
static void netconfig_ifaddr_added(struct netconfig *netconfig,
const struct ifaddrmsg *ifa,
uint32_t len)
@ -861,6 +894,8 @@ static void netconfig_ipv4_ifaddr_add_cmd_cb(int error, uint16_t type,
return;
}
netconfig_gateway_to_arp(netconfig);
if (!netconfig_ipv4_routes_install(netconfig)) {
l_error("netconfig: Failed to install IPv4 routes.");
return;
@ -1372,6 +1407,15 @@ bool netconfig_configure(struct netconfig *netconfig,
bool netconfig_reconfigure(struct netconfig *netconfig)
{
/*
* Starting with kernel 4.20, ARP cache is flushed when the netdev
* detects NO CARRIER. This can result in unnecessarily long delays
* (about 1 second on some networks) due to ARP query response being
* lost or delayed. Try to force the gateway into the ARP cache
* to alleviate this
*/
netconfig_gateway_to_arp(netconfig);
if (netconfig->rtm_protocol == RTPROT_DHCP) {
/* TODO l_dhcp_client sending a DHCP inform request */
}