core/rdisc: limit the number of autoconf addresses to 'max_addresses'

NetworkManager uses the sysctl value 'max_addresses' as the kernel does.
There is however a difference in what addresses are taken into account.
The kernel counts all addresses on the interface (including temporary,
private addresses and user configured ones).
NM instead only limits the number of public autoconf addresses to
'max_addresses'. This is because it is difficult for NM to count all
addresses (which can come from different sources) and it is not
necessarily a more logical behavior. Only be aware, that NM uses
the same config value as the kernel, but counts differently.

Especially, the kernel might reach the limit earlier then NM in the
presence of temporary addresses or addresses not from SLAAC.

Note, that the kernel uses 'max_addresses' only to limit public, autoconf
addresses. So this limit does not affect NM adding as many addresses as
it wants.

Signed-off-by: Thomas Haller <thaller@redhat.com>
This commit is contained in:
Thomas Haller 2014-01-06 21:05:00 +01:00
parent 616fdb35ea
commit 84dc64c8af
7 changed files with 38 additions and 7 deletions

View file

@ -477,6 +477,21 @@ restore_ip6_properties (NMDevice *self)
}
}
static gint32
sysctl_get_ipv6_max_addresses (const char *dev)
{
gint32 max_addresses = 16;
char *path;
g_return_val_if_fail (dev && *dev, max_addresses);
path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/max_addresses", dev);
max_addresses = nm_platform_sysctl_get_int32 (path, max_addresses);
g_free (path);
return max_addresses;
}
/*
* Get driver info from SIOCETHTOOL ioctl() for 'iface'
* Returns driver and firmware versions to 'driver_version and' 'firmware_version'
@ -3320,6 +3335,11 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *device
/* Rebuild address list from router discovery cache. */
nm_ip6_config_reset_addresses (priv->ac_ip6_config);
/* rdisc->addresses contains at most max_addresses entries.
* This is different from what the kernel does, which
* also counts static and temporary addresses when checking
* max_addresses.
**/
for (i = 0; i < rdisc->addresses->len; i++) {
NMRDiscAddress *discovered_address = &g_array_index (rdisc->addresses, NMRDiscAddress, i);
NMPlatformIP6Address address;
@ -3428,7 +3448,8 @@ addrconf6_start (NMDevice *self)
priv->ac_ip6_config = NULL;
}
priv->rdisc = nm_lndp_rdisc_new (nm_device_get_ip_ifindex (self), ip_iface);
priv->rdisc = nm_lndp_rdisc_new (nm_device_get_ip_ifindex (self), ip_iface,
sysctl_get_ipv6_max_addresses (ip_iface));
if (!priv->rdisc) {
nm_log_err (LOGD_IP6, "(%s): failed to start router discovery.", ip_iface);
return FALSE;

View file

@ -36,7 +36,7 @@ G_DEFINE_TYPE (NMFakeRDisc, nm_fake_rdisc, NM_TYPE_RDISC)
/******************************************************************/
NMRDisc *
nm_fake_rdisc_new (int ifindex, const char *ifname)
nm_fake_rdisc_new (int ifindex, const char *ifname, gint32 max_addresses)
{
NMRDisc *rdisc = g_object_new (NM_TYPE_FAKE_RDISC, NULL);
@ -44,6 +44,7 @@ nm_fake_rdisc_new (int ifindex, const char *ifname)
rdisc->ifindex = ifindex;
rdisc->ifname = g_strdup (ifname);
rdisc->max_addresses = max_addresses;
return rdisc;
}

View file

@ -44,6 +44,6 @@ typedef struct {
GType nm_fake_rdisc_get_type (void);
NMRDisc *nm_fake_rdisc_new (int ifindex, const char *ifname);
NMRDisc *nm_fake_rdisc_new (int ifindex, const char *ifname, gint32 max_addressses);
#endif /* NM_FAKE_RDISC_H */

View file

@ -48,7 +48,7 @@ G_DEFINE_TYPE (NMLNDPRDisc, nm_lndp_rdisc, NM_TYPE_RDISC)
/******************************************************************/
NMRDisc *
nm_lndp_rdisc_new (int ifindex, const char *ifname)
nm_lndp_rdisc_new (int ifindex, const char *ifname, gint32 max_addresses)
{
NMRDisc *rdisc;
NMLNDPRDiscPrivate *priv;
@ -59,6 +59,7 @@ nm_lndp_rdisc_new (int ifindex, const char *ifname)
rdisc->ifindex = ifindex;
rdisc->ifname = g_strdup (ifname);
rdisc->max_addresses = max_addresses;
priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc);
error = ndp_open (&priv->ndp);
@ -113,6 +114,13 @@ add_address (NMRDisc *rdisc, const NMRDiscAddress *new)
}
}
/* we create at most max_addresses autoconf addresses. This is different from
* what the kernel does, because it considers *all* addresses (including
* static and other temporary addresses).
**/
if (rdisc->max_addresses && rdisc->addresses->len >= rdisc->max_addresses)
return FALSE;
g_array_insert_val (rdisc->addresses, i, *new);
return TRUE;
}

View file

@ -44,6 +44,6 @@ typedef struct {
GType nm_lndp_rdisc_get_type (void);
NMRDisc *nm_lndp_rdisc_new (int ifindex, const char *ifname);
NMRDisc *nm_lndp_rdisc_new (int ifindex, const char *ifname, gint32 max_addresses);
#endif /* NM_LNDP_RDISC_H */

View file

@ -106,6 +106,7 @@ typedef struct {
int ifindex;
char *ifname;
GBytes *lladdr;
gint32 max_addresses;
NMRDiscDHCPLevel dhcp_level;
GArray *gateways;

View file

@ -12,7 +12,7 @@ main (int argc, char **argv)
{
GMainLoop *loop;
NMRDisc *rdisc;
NMRDisc *(*new) (int ifindex, const char *ifname) = nm_lndp_rdisc_new;
NMRDisc *(*new) (int ifindex, const char *ifname, gint32 max_addresses) = nm_lndp_rdisc_new;
int ifindex = 1;
char ifname[IF_NAMESIZE];
char mac[6] = { 0x02, 0xaa, 0xbb, 0xcc, 0xdd, 0xee };
@ -34,7 +34,7 @@ main (int argc, char **argv)
}
}
rdisc = new (ifindex, ifname);
rdisc = new (ifindex, ifname, 0);
if (!rdisc)
return EXIT_FAILURE;