ipv6: set neighbor parameters from RAs

IPv6 router advertisement messages contain the following parameters
(RFC 4861):

 - Reachable time: 32-bit unsigned integer.  The time, in
   milliseconds, that a node assumes a neighbor is reachable after
   having received a reachability confirmation.  Used by the Neighbor
   Unreachability Detection algorithm.  A value of zero means
   unspecified (by this router).

 - Retrans Timer: 32-bit unsigned integer.  The time, in milliseconds,
   between retransmitted Neighbor Solicitation messages.  Used by
   address resolution and the Neighbor Unreachability Detection
   algorithm.   A value of zero means unspecified (by this router).

Currently NM ignores them; however, since it leaves accept_ra=1, the
kernel parses RAs and applies those parameters for us [1].

In the next commit kernel handling of RAs will be disabled, so let NM
set those neighbor-related parameters.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/ipv6/ndisc.c?h=v5.2#n1353

(cherry picked from commit 5f0c6f8d3b)
This commit is contained in:
Beniamino Galvani 2019-08-23 10:39:22 +02:00
parent 188911ae7d
commit 08fdea122d
7 changed files with 103 additions and 0 deletions

View file

@ -9667,6 +9667,18 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in
if (changed & NM_NDISC_CONFIG_HOP_LIMIT)
nm_platform_sysctl_ip_conf_set_ipv6_hop_limit_safe (nm_device_get_platform (self), nm_device_get_ip_iface (self), rdata->hop_limit);
if (changed & NM_NDISC_CONFIG_REACHABLE_TIME) {
nm_platform_sysctl_ip_neigh_set_ipv6_reachable_time (nm_device_get_platform (self),
nm_device_get_ip_iface (self),
rdata->reachable_time_ms);
}
if (changed & NM_NDISC_CONFIG_RETRANS_TIMER) {
nm_platform_sysctl_ip_neigh_set_ipv6_retrans_time (nm_device_get_platform (self),
nm_device_get_ip_iface (self),
rdata->retrans_timer_ms);
}
if (changed & NM_NDISC_CONFIG_MTU) {
if (priv->ip6_mtu != rdata->mtu) {
_LOGD (LOGD_DEVICE, "mtu: set IPv6 MTU to %u", (guint) rdata->mtu);

View file

@ -116,6 +116,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
gint32 now = nm_utils_get_monotonic_timestamp_s ();
int offset;
int hop_limit;
guint32 val;
/* Router discovery is subject to the following RFC documents:
*
@ -294,6 +295,18 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
changed |= NM_NDISC_CONFIG_HOP_LIMIT;
}
val = ndp_msgra_reachable_time (msgra);
if (val && rdata->public.reachable_time_ms != val) {
rdata->public.reachable_time_ms = val;
changed |= NM_NDISC_CONFIG_REACHABLE_TIME;
}
val = ndp_msgra_retransmit_time (msgra);
if (val && rdata->public.retrans_timer_ms != val) {
rdata->public.retrans_timer_ms = val;
changed |= NM_NDISC_CONFIG_RETRANS_TIMER;
}
/* MTU */
ndp_msg_opt_for_each_offset(offset, msg, NDP_MSG_OPT_MTU) {
guint32 mtu = ndp_msg_opt_mtu(msg, offset);

View file

@ -1039,6 +1039,14 @@ _config_changed_log (NMNDisc *ndisc, NMNDiscConfigMap changed)
config_map_to_string (changed, changedstr);
_LOGD ("neighbor discovery configuration changed [%s]:", changedstr);
_LOGD (" dhcp-level %s", dhcp_level_to_string (priv->rdata.public.dhcp_level));
if (rdata->public.hop_limit)
_LOGD (" hop limit : %d", rdata->public.hop_limit);
if (rdata->public.reachable_time_ms)
_LOGD (" reachable time : %u", (guint) rdata->public.reachable_time_ms);
if (rdata->public.retrans_timer_ms)
_LOGD (" retrans timer : %u", (guint) rdata->public.retrans_timer_ms);
for (i = 0; i < rdata->gateways->len; i++) {
NMNDiscGateway *gateway = &g_array_index (rdata->gateways, NMNDiscGateway, i);

View file

@ -112,6 +112,8 @@ typedef enum {
NM_NDISC_CONFIG_DNS_DOMAINS = 1 << 5,
NM_NDISC_CONFIG_HOP_LIMIT = 1 << 6,
NM_NDISC_CONFIG_MTU = 1 << 7,
NM_NDISC_CONFIG_REACHABLE_TIME = 1 << 8,
NM_NDISC_CONFIG_RETRANS_TIMER = 1 << 9,
} NMNDiscConfigMap;
typedef enum {
@ -137,6 +139,8 @@ typedef struct {
NMNDiscDHCPLevel dhcp_level;
guint32 mtu;
int hop_limit;
guint32 reachable_time_ms;
guint32 retrans_timer_ms;
guint gateways_n;
guint addresses_n;

View file

@ -220,6 +220,18 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in
if (changed & NM_NDISC_CONFIG_HOP_LIMIT)
nm_platform_sysctl_ip_conf_set_ipv6_hop_limit_safe (NM_PLATFORM_GET, global_opt.ifname, rdata->hop_limit);
if (changed & NM_NDISC_CONFIG_REACHABLE_TIME) {
nm_platform_sysctl_ip_neigh_set_ipv6_reachable_time (NM_PLATFORM_GET,
global_opt.ifname,
rdata->reachable_time_ms);
}
if (changed & NM_NDISC_CONFIG_RETRANS_TIMER) {
nm_platform_sysctl_ip_neigh_set_ipv6_retrans_time (NM_PLATFORM_GET,
global_opt.ifname,
rdata->retrans_timer_ms);
}
if (changed & NM_NDISC_CONFIG_MTU) {
nm_platform_sysctl_ip_conf_set_int64 (NM_PLATFORM_GET,
AF_INET6,

View file

@ -610,6 +610,54 @@ nm_platform_sysctl_ip_conf_set_ipv6_hop_limit_safe (NMPlatform *self,
return TRUE;
}
gboolean
nm_platform_sysctl_ip_neigh_set_ipv6_reachable_time (NMPlatform *self,
const char *iface,
guint value_ms)
{
char path[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE];
char str[128];
guint clamped;
_CHECK_SELF (self, klass, FALSE);
if (!value_ms)
return TRUE;
/* RFC 4861 says the value can't be greater than one hour.
* Also use a reasonable lower threshold. */
clamped = NM_CLAMP (value_ms, 100, 3600000);
nm_sprintf_buf (path, "/proc/sys/net/ipv6/neigh/%s/base_reachable_time_ms", iface);
nm_sprintf_buf (str, "%u", clamped);
if (!nm_platform_sysctl_set (self, NMP_SYSCTL_PATHID_ABSOLUTE (path), str))
return FALSE;
/* Set stale time in the same way as kernel */
nm_sprintf_buf (path, "/proc/sys/net/ipv6/neigh/%s/gc_stale_time", iface);
nm_sprintf_buf (str, "%u", clamped * 3 / 1000);
return nm_platform_sysctl_set (self, NMP_SYSCTL_PATHID_ABSOLUTE (path), str);
}
gboolean
nm_platform_sysctl_ip_neigh_set_ipv6_retrans_time (NMPlatform *self,
const char *iface,
guint value_ms)
{
char path[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE];
char str[128];
_CHECK_SELF (self, klass, FALSE);
if (!value_ms)
return TRUE;
nm_sprintf_buf (path, "/proc/sys/net/ipv6/neigh/%s/retrans_time_ms", iface);
nm_sprintf_buf (str, "%u", NM_CLAMP (value_ms, 10, 3600000));
return nm_platform_sysctl_set (self, NMP_SYSCTL_PATHID_ABSOLUTE (path), str);
}
/**
* nm_platform_sysctl_get:
* @self: platform instance

View file

@ -1353,6 +1353,12 @@ gboolean nm_platform_sysctl_ip_conf_set_int64 (NMPlatform *self,
gboolean nm_platform_sysctl_ip_conf_set_ipv6_hop_limit_safe (NMPlatform *self,
const char *iface,
int value);
gboolean nm_platform_sysctl_ip_neigh_set_ipv6_reachable_time (NMPlatform *self,
const char *iface,
guint value_ms);
gboolean nm_platform_sysctl_ip_neigh_set_ipv6_retrans_time (NMPlatform *self,
const char *iface,
guint value_ms);
int nm_platform_sysctl_ip_conf_get_rp_filter_ipv4 (NMPlatform *platform,
const char *iface,
gboolean consider_all,