From 057b63979e0c3c345321dbc1fdfc1068dd55cdca Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 16 Aug 2017 13:57:01 +0200 Subject: [PATCH] core: move setting NDisc addresses/routes to NMIP6Config Add an utility function for resetting addresses/routes of NMIP6Config from NMNDisc data. For one, this de-duplicates code in device and nm-iface-helper. Also, we no longer first reset (delete) all addresses and add them anew. Instead, we first mark all entries as dirty for deletion, merge (append) the new entires, and delete the remaining dirty entires. This saves a extra work, in the expected case where NMIP6Config already contains several of the new entries. --- src/devices/nm-device.c | 49 ++++--------------- src/ndisc/nm-ndisc.h | 10 ++-- src/nm-iface-helper.c | 50 ++++--------------- src/nm-ip6-config.c | 104 ++++++++++++++++++++++++++++++++++++++++ src/nm-ip6-config.h | 12 +++++ 5 files changed, 140 insertions(+), 85 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 740f270fa2..40d0b1d665 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -7420,49 +7420,18 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in } if (changed & NM_NDISC_CONFIG_ADDRESSES) { - /* Rebuild address list from neighbor discovery cache. */ - nm_ip6_config_reset_addresses (priv->ac_ip6_config); - - /* ndisc->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 < rdata->addresses_n; i++) { - const NMNDiscAddress *discovered_address = &rdata->addresses[i]; - NMPlatformIP6Address address; - - memset (&address, 0, sizeof (address)); - address.address = discovered_address->address; - address.plen = system_support ? 64 : 128; - address.timestamp = discovered_address->timestamp; - address.lifetime = discovered_address->lifetime; - address.preferred = discovered_address->preferred; - if (address.preferred > address.lifetime) - address.preferred = address.lifetime; - address.addr_source = NM_IP_CONFIG_SOURCE_NDISC; - address.n_ifa_flags = ifa_flags; - - nm_ip6_config_add_address (priv->ac_ip6_config, &address); - } + nm_ip6_config_reset_addresses_ndisc (priv->ac_ip6_config, + rdata->addresses, + rdata->addresses_n, + system_support ? 64 : 128, + ifa_flags); } if (changed & NM_NDISC_CONFIG_ROUTES) { - /* Rebuild route list from neighbor discovery cache. */ - nm_ip6_config_reset_routes (priv->ac_ip6_config); - - for (i = 0; i < rdata->routes_n; i++) { - const NMNDiscRoute *discovered_route = &rdata->routes[i]; - const NMPlatformIP6Route route = { - .network = discovered_route->network, - .plen = discovered_route->plen, - .gateway = discovered_route->gateway, - .rt_source = NM_IP_CONFIG_SOURCE_NDISC, - .metric = nm_device_get_ip6_route_metric (self), - }; - - nm_ip6_config_add_route (priv->ac_ip6_config, &route); - } + nm_ip6_config_reset_routes_ndisc (priv->ac_ip6_config, + rdata->routes, + rdata->routes_n, + nm_device_get_ip6_route_metric (self)); } if (changed & NM_NDISC_CONFIG_DNS_SERVERS) { diff --git a/src/ndisc/nm-ndisc.h b/src/ndisc/nm-ndisc.h index 7c67289d1e..db19db0021 100644 --- a/src/ndisc/nm-ndisc.h +++ b/src/ndisc/nm-ndisc.h @@ -69,22 +69,24 @@ typedef struct { NMNDiscPreference preference; } NMNDiscGateway; -typedef struct { +struct _NMNDiscAddress { struct in6_addr address; guint8 dad_counter; guint32 timestamp; guint32 lifetime; guint32 preferred; -} NMNDiscAddress; +}; +typedef struct _NMNDiscAddress NMNDiscAddress; -typedef struct { +struct _NMNDiscRoute { struct in6_addr network; guint8 plen; struct in6_addr gateway; guint32 timestamp; guint32 lifetime; NMNDiscPreference preference; -} NMNDiscRoute; +}; +typedef struct _NMNDiscRoute NMNDiscRoute; typedef struct { struct in6_addr address; diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c index c695d591f6..ff422de66c 100644 --- a/src/nm-iface-helper.c +++ b/src/nm-iface-helper.c @@ -156,7 +156,6 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in NMIP6Config *existing; int system_support; guint32 ifa_flags = 0x00; - int i; /* * Check, whether kernel is recent enough, to help user space handling RA. @@ -194,49 +193,18 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in } if (changed & NM_NDISC_CONFIG_ADDRESSES) { - /* Rebuild address list from neighbor discovery cache. */ - nm_ip6_config_reset_addresses (ndisc_config); - - /* ndisc->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 < rdata->addresses_n; i++) { - const NMNDiscAddress *discovered_address = &rdata->addresses[i]; - NMPlatformIP6Address address; - - memset (&address, 0, sizeof (address)); - address.address = discovered_address->address; - address.plen = system_support ? 64 : 128; - address.timestamp = discovered_address->timestamp; - address.lifetime = discovered_address->lifetime; - address.preferred = discovered_address->preferred; - if (address.preferred > address.lifetime) - address.preferred = address.lifetime; - address.addr_source = NM_IP_CONFIG_SOURCE_NDISC; - address.n_ifa_flags = ifa_flags; - - nm_ip6_config_add_address (ndisc_config, &address); - } + nm_ip6_config_reset_addresses_ndisc (ndisc_config, + rdata->addresses, + rdata->addresses_n, + system_support ? 64 : 128, + ifa_flags); } if (changed & NM_NDISC_CONFIG_ROUTES) { - /* Rebuild route list from neighbor discovery cache. */ - nm_ip6_config_reset_routes (ndisc_config); - - for (i = 0; i < rdata->routes_n; i++) { - const NMNDiscRoute *discovered_route = &rdata->routes[i]; - const NMPlatformIP6Route route = { - .network = discovered_route->network, - .plen = discovered_route->plen, - .gateway = discovered_route->gateway, - .rt_source = NM_IP_CONFIG_SOURCE_NDISC, - .metric = global_opt.priority_v6, - }; - - nm_ip6_config_add_route (ndisc_config, &route); - } + nm_ip6_config_reset_routes_ndisc (ndisc_config, + rdata->routes, + rdata->routes_n, + global_opt.priority_v6); } if (changed & NM_NDISC_CONFIG_DHCP_LEVEL) { diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 3d42fb7b8a..9f9e345637 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -35,6 +35,7 @@ #include "nm-core-internal.h" #include "NetworkManagerUtils.h" #include "nm-ip4-config.h" +#include "ndisc/nm-ndisc.h" #include "introspection/org.freedesktop.NetworkManager.IP6Config.h" @@ -1189,6 +1190,8 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev dst_priv = NM_IP6_CONFIG_GET_PRIVATE (dst); src_priv = NM_IP6_CONFIG_GET_PRIVATE (src); + g_return_val_if_fail (src_priv->ifindex > 0, FALSE); + g_object_freeze_notify (G_OBJECT (dst)); /* ifindex */ @@ -1520,6 +1523,58 @@ nm_ip6_config_get_route_metric (const NMIP6Config *self) /*****************************************************************************/ +void +nm_ip6_config_reset_addresses_ndisc (NMIP6Config *self, + const NMNDiscAddress *addresses, + guint addresses_n, + guint8 plen, + guint32 ifa_flags) +{ + NMIP6ConfigPrivate *priv; + guint i; + gboolean changed = FALSE; + + g_return_if_fail (NM_IS_IP6_CONFIG (self)); + + priv = NM_IP6_CONFIG_GET_PRIVATE (self); + + g_return_if_fail (priv->ifindex > 0); + + nm_dedup_multi_index_dirty_set_idx (priv->multi_idx, &priv->idx_ip6_addresses); + + for (i = 0; i < addresses_n; i++) { + const NMNDiscAddress *ndisc_addr = &addresses[i]; + NMPObject obj; + NMPlatformIP6Address *a; + + nmp_object_stackinit (&obj, NMP_OBJECT_TYPE_IP6_ADDRESS, NULL); + a = NMP_OBJECT_CAST_IP6_ADDRESS (&obj); + a->ifindex = priv->ifindex; + a->address = ndisc_addr->address; + a->plen = plen; + a->timestamp = ndisc_addr->timestamp; + a->lifetime = ndisc_addr->lifetime; + a->preferred = MIN (ndisc_addr->lifetime, ndisc_addr->preferred); + a->addr_source = NM_IP_CONFIG_SOURCE_NDISC; + a->n_ifa_flags = ifa_flags; + + if (_nm_ip_config_add_obj (priv->multi_idx, + &priv->idx_ip6_addresses_, + priv->ifindex, + &obj, + NULL, + FALSE, + TRUE)) + changed = TRUE; + } + + if (nm_dedup_multi_index_dirty_remove_idx (priv->multi_idx, &priv->idx_ip6_addresses, FALSE) > 0) + changed = TRUE; + + if (changed) + _notify_addresses (self); +} + void nm_ip6_config_reset_addresses (NMIP6Config *self) { @@ -1698,6 +1753,55 @@ nm_ip6_config_has_any_dad_pending (const NMIP6Config *self, /*****************************************************************************/ +void +nm_ip6_config_reset_routes_ndisc (NMIP6Config *self, + const NMNDiscRoute *routes, + guint routes_n, + guint32 metric) +{ + NMIP6ConfigPrivate *priv; + guint i; + gboolean changed = FALSE; + + g_return_if_fail (NM_IS_IP6_CONFIG (self)); + + priv = NM_IP6_CONFIG_GET_PRIVATE (self); + + g_return_if_fail (priv->ifindex > 0); + + nm_dedup_multi_index_dirty_set_idx (priv->multi_idx, &priv->idx_ip6_routes); + + for (i = 0; i < routes_n; i++) { + const NMNDiscRoute *ndisc_route = &routes[i]; + NMPObject obj; + NMPlatformIP6Route *r; + + nmp_object_stackinit (&obj, NMP_OBJECT_TYPE_IP6_ROUTE, NULL); + r = NMP_OBJECT_CAST_IP6_ROUTE (&obj); + r->ifindex = priv->ifindex; + r->network = ndisc_route->network; + r->plen = ndisc_route->plen; + r->gateway = ndisc_route->gateway; + r->rt_source = NM_IP_CONFIG_SOURCE_NDISC; + r->metric = metric; + + if (_nm_ip_config_add_obj (priv->multi_idx, + &priv->idx_ip6_routes_, + priv->ifindex, + &obj, + NULL, + FALSE, + TRUE)) + changed = TRUE; + } + + if (nm_dedup_multi_index_dirty_remove_idx (priv->multi_idx, &priv->idx_ip6_routes, FALSE) > 0) + changed = TRUE; + + if (changed) + _notify_routes (self); +} + void nm_ip6_config_reset_routes (NMIP6Config *self) { diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index 6e7b112110..eb2aae170d 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -191,6 +191,18 @@ gboolean nm_ip6_config_equal (const NMIP6Config *a, const NMIP6Config *b); void nm_ip6_config_set_privacy (NMIP6Config *self, NMSettingIP6ConfigPrivacy privacy); +struct _NMNDiscAddress; +void nm_ip6_config_reset_addresses_ndisc (NMIP6Config *self, + const struct _NMNDiscAddress *addresses, + guint addresses_n, + guint8 plen, + guint32 ifa_flags); +struct _NMNDiscRoute; +void nm_ip6_config_reset_routes_ndisc (NMIP6Config *self, + const struct _NMNDiscRoute *routes, + guint routes_n, + guint32 metric); + /*****************************************************************************/ /* Testing-only functions */