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 */