l3cfg: set IPv6 sysctls during NML3Cfg commit

This commit is contained in:
Thomas Haller 2021-10-17 10:23:04 +02:00
parent 4b270448e4
commit 5c48c5d5d6
No known key found for this signature in database
GPG Key ID: 29C2366E4DFC5728
2 changed files with 219 additions and 7 deletions

View File

@ -1792,7 +1792,10 @@ nm_l3_config_data_set_ip6_mtu(NML3ConfigData *self, guint32 ip6_mtu)
NMSettingIP6ConfigPrivacy
nm_l3_config_data_get_ip6_privacy(const NML3ConfigData *self)
{
nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE));
nm_assert(!self || _NM_IS_L3_CONFIG_DATA(self, TRUE));
if (!self)
return NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN;
return self->ip6_privacy;
}
@ -1894,7 +1897,7 @@ nm_l3_config_data_set_proxy_pac_script(NML3ConfigData *self, const char *value)
gboolean
nm_l3_config_data_get_ndisc_hop_limit(const NML3ConfigData *self, int *out_val)
{
nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE));
nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE));
if (!self->ndisc_hop_limit_set) {
NM_SET_OUT(out_val, 0);
@ -1917,7 +1920,7 @@ nm_l3_config_data_set_ndisc_hop_limit(NML3ConfigData *self, int val)
gboolean
nm_l3_config_data_get_ndisc_reachable_time_msec(const NML3ConfigData *self, guint32 *out_val)
{
nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE));
nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE));
if (!self->ndisc_reachable_time_msec_set) {
NM_SET_OUT(out_val, 0);
@ -1940,7 +1943,7 @@ nm_l3_config_data_set_ndisc_reachable_time_msec(NML3ConfigData *self, guint32 va
gboolean
nm_l3_config_data_get_ndisc_retrans_timer_msec(const NML3ConfigData *self, guint32 *out_val)
{
nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE));
nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE));
if (!self->ndisc_retrans_timer_msec_set) {
NM_SET_OUT(out_val, 0);
@ -2230,7 +2233,7 @@ nm_l3_config_data_get_blacklisted_ip4_routes(const NML3ConfigData *self, gboolea
const NMPObject * my_addr_obj;
NMDedupMultiIter iter;
nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE));
nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE));
/* For IPv6 slaac, we explicitly add the device-routes (onlink).
* As we don't do that for IPv4 and manual IPv6 addresses. Add them here

View File

@ -259,6 +259,25 @@ typedef struct _NML3CfgPrivate {
gint8 commit_reentrant_count;
/* The value that was set before we touched the sysctl (this only is
* meaningful if "ip6_privacy_set" is true. At the end, we want to restore
* this value. */
NMSettingIP6ConfigPrivacy ip6_privacy_initial : 4;
/* The value that we set the last time. This is cached so that we don't
* repeatedly try to commit the same value. */
NMSettingIP6ConfigPrivacy ip6_privacy_set_before : 4;
guint32 ndisc_retrans_timer_msec;
guint32 ndisc_reachable_time_msec;
int ndisc_hop_limit;
/* Whether "self" set the ip6_privacy sysctl (and whether it needs to be reset). */
bool ip6_privacy_set : 1;
bool ndisc_reachable_time_msec_set : 1;
bool ndisc_retrans_timer_msec_set : 1;
bool ndisc_hop_limit_set : 1;
bool commit_type_update_sticky : 1;
bool acd_is_pending : 1;
@ -3654,6 +3673,193 @@ out_prune:
}
/*****************************************************************************/
static const char *
ip6_privacy_to_str(NMSettingIP6ConfigPrivacy ip6_privacy)
{
switch (ip6_privacy) {
case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED:
return "0";
case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR:
return "1";
case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR:
return "2";
case NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN:
break;
}
return nm_assert_unreachable_val("0");
}
static void
_l3_commit_ndisc_params(NML3Cfg *self, NML3CfgCommitType commit_type)
{
const NML3ConfigData *l3cd;
gboolean retrans_set = FALSE;
gboolean reachable_set = FALSE;
gboolean hop_limit_set = FALSE;
guint32 reachable;
guint32 retrans;
int hop_limit;
const char * ifname;
if (commit_type < NM_L3_CFG_COMMIT_TYPE_UPDATE) {
self->priv.p->ndisc_reachable_time_msec_set = FALSE;
self->priv.p->ndisc_retrans_timer_msec_set = FALSE;
self->priv.p->ndisc_hop_limit_set = FALSE;
return;
}
l3cd = self->priv.p->combined_l3cd_commited;
if (l3cd) {
reachable_set = nm_l3_config_data_get_ndisc_reachable_time_msec(l3cd, &reachable);
retrans_set = nm_l3_config_data_get_ndisc_retrans_timer_msec(l3cd, &retrans);
hop_limit = nm_l3_config_data_get_ndisc_hop_limit(l3cd, &hop_limit);
}
ifname = nm_l3cfg_get_ifname(self, TRUE);
if (reachable_set
&& (!self->priv.p->ndisc_reachable_time_msec_set
|| self->priv.p->ndisc_reachable_time_msec != reachable)) {
self->priv.p->ndisc_reachable_time_msec = reachable;
self->priv.p->ndisc_reachable_time_msec_set = TRUE;
if (ifname) {
nm_platform_sysctl_ip_neigh_set_ipv6_reachable_time(self->priv.platform,
ifname,
reachable);
}
}
if (retrans_set
&& (!self->priv.p->ndisc_retrans_timer_msec_set
|| self->priv.p->ndisc_reachable_time_msec != retrans)) {
self->priv.p->ndisc_retrans_timer_msec = retrans;
self->priv.p->ndisc_retrans_timer_msec_set = TRUE;
if (ifname) {
nm_platform_sysctl_ip_neigh_set_ipv6_retrans_time(self->priv.platform, ifname, retrans);
}
}
if (hop_limit_set
&& (!self->priv.p->ndisc_hop_limit_set || self->priv.p->ndisc_hop_limit != hop_limit)) {
self->priv.p->ndisc_hop_limit = hop_limit;
self->priv.p->ndisc_hop_limit_set = TRUE;
if (ifname) {
nm_platform_sysctl_ip_conf_set_ipv6_hop_limit_safe(self->priv.platform,
ifname,
hop_limit);
}
}
// FIXME: restore values if necessary
}
static void
_l3_commit_ip6_privacy(NML3Cfg *self, NML3CfgCommitType commit_type)
{
NMSettingIP6ConfigPrivacy ip6_privacy;
NMSettingIP6ConfigPrivacy ip6_privacy_set_before;
const char * ifname;
if (commit_type < NM_L3_CFG_COMMIT_TYPE_UPDATE)
ip6_privacy = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN;
else
ip6_privacy = nm_l3_config_data_get_ip6_privacy(self->priv.p->combined_l3cd_commited);
if (ip6_privacy == NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN) {
if (!self->priv.p->ip6_privacy_set) {
/* Nothing to set. But do we need to reset a previous value? */
return;
}
self->priv.p->ip6_privacy_set = FALSE;
ip6_privacy = self->priv.p->ip6_privacy_initial;
ifname = nm_l3cfg_get_ifname(self, TRUE);
_LOGT("commit-ip6-privacy: reset initial value %d (was %d)%s%s",
(int) ip6_privacy,
(int) self->priv.p->ip6_privacy_set_before,
NM_PRINT_FMT_QUOTED2(ifname, ", ifname ", ifname, " (skip, no interface)"));
if (ip6_privacy == NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN)
return;
if (!ifname)
return;
goto set;
}
nm_assert(NM_IN_SET(ip6_privacy,
NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED,
NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR,
NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR));
if (self->priv.p->ip6_privacy_set && self->priv.p->ip6_privacy_set_before == ip6_privacy
&& commit_type < NM_L3_CFG_COMMIT_TYPE_REAPPLY) {
/* Already set. We leave this alone except during reapply. */
return;
}
ip6_privacy_set_before = self->priv.p->ip6_privacy_set_before;
self->priv.p->ip6_privacy_set_before = ip6_privacy;
if (!self->priv.p->ip6_privacy_set) {
gint64 s = G_MININT64;
self->priv.p->ip6_privacy_set = TRUE;
ifname = nm_l3cfg_get_ifname(self, TRUE);
if (ifname) {
s = nm_platform_sysctl_ip_conf_get_int_checked(self->priv.platform,
AF_INET6,
ifname,
"use_tempaddr",
10,
G_MININT32,
G_MAXINT32,
G_MININT64);
if (s != G_MININT64)
s = NM_CLAMP(s, 0, 2);
}
switch (s) {
case 0:
self->priv.p->ip6_privacy_initial = NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED;
break;
case 1:
self->priv.p->ip6_privacy_initial = NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR;
break;
case 2:
self->priv.p->ip6_privacy_initial = NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR;
break;
default:
nm_assert_not_reached();
/* fall-through */
case G_MININT64:
self->priv.p->ip6_privacy_initial = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN;
break;
}
_LOGT("commit-ip6-privacy: set value %d (initial value was %d)%s%s",
(int) ip6_privacy,
(int) self->priv.p->ip6_privacy_initial,
NM_PRINT_FMT_QUOTED2(ifname, ", ifname ", ifname, " (skip, no interface)"));
if (!ifname)
return;
/* The first time, we always set the value, and don't skip it based on what we
* read. */
goto set;
}
ifname = nm_l3cfg_get_ifname(self, TRUE);
_LOGT("commit-ip6-privacy: set value %d (after %d, initial value was %d)%s%s",
(int) ip6_privacy,
(int) ip6_privacy_set_before,
(int) self->priv.p->ip6_privacy_initial,
NM_PRINT_FMT_QUOTED2(ifname, ", ifname ", ifname, " (skip, no interface)"));
if (!ifname)
return;
set:
nm_assert(ifname);
self->priv.p->ip6_privacy_set_before = ip6_privacy;
nm_platform_sysctl_ip_conf_set(self->priv.platform,
AF_INET6,
ifname,
"use_tempaddr",
ip6_privacy_to_str(ip6_privacy));
}
static gboolean
_l3_commit_one(NML3Cfg * self,
@ -3709,6 +3915,11 @@ _l3_commit_one(NML3Cfg * self,
addr_family);
}
if (!IS_IPv4) {
_l3_commit_ip6_privacy(self, commit_type);
_l3_commit_ndisc_params(self, commit_type);
}
if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_NONE)
route_table_sync = NM_IP_ROUTE_TABLE_SYNC_MODE_ALL;
@ -3725,9 +3936,7 @@ _l3_commit_one(NML3Cfg * self,
} else
_obj_state_zombie_lst_get_prune_lists(self, addr_family, &addresses_prune, &routes_prune);
/* FIXME(l3cfg): need to honor and set nm_l3_config_data_get_ip6_privacy(). */
/* FIXME(l3cfg): need to honor and set nm_l3_config_data_get_ndisc_*(). */
/* FIXME(l3cfg): need to honor and set nm_l3_config_data_get_ip6_mtu(). */
/* FIXME(l3cfg): need to honor and set nm_l3_config_data_get_mtu(). */
nm_platform_ip_address_sync(self->priv.platform,