core: refactor NMIP6Config to use dedup-index for IPv6 routes

This commit is contained in:
Thomas Haller
2017-07-03 17:03:54 +02:00
parent 28340588d9
commit cfd1851c00
9 changed files with 363 additions and 201 deletions

View File

@@ -111,7 +111,9 @@ get_ip6_rdns_domains (NMIP6Config *ip6)
{
char **strv;
GPtrArray *domains = NULL;
int i;
guint i;
NMDedupMultiIter ipconf_iter;
const NMPlatformIP6Route *route;
g_return_val_if_fail (ip6 != NULL, NULL);
@@ -123,11 +125,8 @@ get_ip6_rdns_domains (NMIP6Config *ip6)
nm_utils_get_reverse_dns_domains_ip6 (&address->address, address->plen, domains);
}
for (i = 0; i < nm_ip6_config_get_num_routes (ip6); i++) {
const NMPlatformIP6Route *route = nm_ip6_config_get_route (ip6, i);
nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &route)
nm_utils_get_reverse_dns_domains_ip6 (&route->network, route->plen, domains);
}
/* Terminating NULL so we can use g_strfreev() to free it */
g_ptr_array_add (domains, NULL);

View File

@@ -182,6 +182,7 @@ static void
dump_ip6_to_props (NMIP6Config *ip6, GVariantBuilder *builder)
{
GVariantBuilder int_builder;
NMDedupMultiIter ipconf_iter;
guint n, i;
const NMPlatformIP6Address *addr;
const struct in6_addr *gw_bytes;
@@ -230,9 +231,7 @@ dump_ip6_to_props (NMIP6Config *ip6, GVariantBuilder *builder)
/* Static routes */
g_variant_builder_init (&int_builder, G_VARIANT_TYPE ("a(ayuayu)"));
n = nm_ip6_config_get_num_routes (ip6);
for (i = 0; i < n; i++) {
route = nm_ip6_config_get_route (ip6, i);
nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &route) {
ip = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
&route->network,
sizeof (struct in6_addr), 1);

View File

@@ -46,14 +46,22 @@ G_STATIC_ASSERT (G_MAXUINT >= 0xFFFFFFFF);
/*****************************************************************************/
static gboolean
_idx_obj_id_equal_ip4_route (const NMPlatformIP4Route *r_a,
const NMPlatformIP4Route *r_b)
gboolean
nm_ip_config_obj_id_equal_ip4_route (const NMPlatformIP4Route *r_a,
const NMPlatformIP4Route *r_b)
{
return r_a->network == r_b->network
&& r_a->plen == r_b->plen;
}
gboolean
nm_ip_config_obj_id_equal_ip6_route (const NMPlatformIP6Route *r_a,
const NMPlatformIP6Route *r_b)
{
return r_a->plen == r_b->plen
&& IN6_ARE_ADDR_EQUAL (&r_a->network, &r_b->network);
}
static guint
_idx_obj_id_hash (const NMDedupMultiIdxType *idx_type,
const NMDedupMultiObj *obj)
@@ -68,10 +76,13 @@ _idx_obj_id_hash (const NMDedupMultiIdxType *idx_type,
case NMP_OBJECT_TYPE_IP4_ROUTE:
h = 40303327;
h = NM_HASH_COMBINE (h, o->ip4_route.network);
h = NM_HASH_COMBINE (h, o->ip4_route.plen);
h = NM_HASH_COMBINE (h, o->ip_route.plen);
break;
case NMP_OBJECT_TYPE_IP6_ROUTE:
g_return_val_if_reached (0);
h = 577629323;
h = NM_HASH_COMBINE_IN6_ADDR (h, &o->ip6_route.network);
h = NM_HASH_COMBINE (h, o->ip_route.plen);
break;
default:
g_return_val_if_reached (0);
};
@@ -94,9 +105,9 @@ _idx_obj_id_equal (const NMDedupMultiIdxType *idx_type,
case NMP_OBJECT_TYPE_IP6_ADDRESS:
g_return_val_if_reached (FALSE);
case NMP_OBJECT_TYPE_IP4_ROUTE:
return _idx_obj_id_equal_ip4_route (&o_a->ip4_route, &o_b->ip4_route);
return nm_ip_config_obj_id_equal_ip4_route (&o_a->ip4_route, &o_b->ip4_route);
case NMP_OBJECT_TYPE_IP6_ROUTE:
g_return_val_if_reached (FALSE);
return nm_ip_config_obj_id_equal_ip6_route (&o_a->ip6_route, &o_b->ip6_route);
default:
g_return_val_if_reached (FALSE);
};
@@ -1300,7 +1311,7 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev
if (nm_platform_ip4_route_cmp (r_src, r_dst) != 0) {
are_equal = FALSE;
if (!_idx_obj_id_equal_ip4_route (r_src, r_dst)) {
if (!nm_ip_config_obj_id_equal_ip4_route (r_src, r_dst)) {
has_relevant_changes = TRUE;
break;
}

View File

@@ -43,6 +43,11 @@ gboolean nm_ip4_config_iter_ip4_route_next (NMDedupMultiIter *iter, const NMPlat
nm_ip4_config_iter_ip4_route_next ((iter), (route)); \
)
gboolean nm_ip_config_obj_id_equal_ip4_route (const NMPlatformIP4Route *r_a,
const NMPlatformIP4Route *r_b);
gboolean nm_ip_config_obj_id_equal_ip6_route (const NMPlatformIP6Route *r_a,
const NMPlatformIP6Route *r_b);
/*****************************************************************************/
#define NM_TYPE_IP4_CONFIG (nm_ip4_config_get_type ())

View File

@@ -29,11 +29,13 @@
#include "nm-utils/nm-dedup-multi.h"
#include "nm-utils.h"
#include "platform/nmp-object.h"
#include "platform/nm-platform.h"
#include "platform/nm-platform-utils.h"
#include "nm-route-manager.h"
#include "nm-core-internal.h"
#include "NetworkManagerUtils.h"
#include "nm-ip4-config.h"
#include "introspection/org.freedesktop.NetworkManager.IP6Config.h"
@@ -48,7 +50,6 @@ typedef struct {
gint64 route_metric;
struct in6_addr gateway;
GArray *addresses;
GArray *routes;
GArray *nameservers;
GPtrArray *domains;
GPtrArray *searches;
@@ -56,6 +57,7 @@ typedef struct {
GVariant *address_data_variant;
GVariant *addresses_variant;
NMDedupMultiIndex *multi_idx;
NMDedupMultiIdxType idx_ip6_routes;
} NMIP6ConfigPrivate;
struct _NMIP6Config {
@@ -88,6 +90,10 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMIP6Config,
/*****************************************************************************/
static void _add_route (NMIP6Config *config, const NMPObject *o_new, const NMPlatformIP6Route *new);
/*****************************************************************************/
int
nm_ip6_config_get_ifindex (const NMIP6Config *config)
{
@@ -110,6 +116,49 @@ nm_ip6_config_set_privacy (NMIP6Config *config, NMSettingIP6ConfigPrivacy privac
/*****************************************************************************/
static const NMDedupMultiHeadEntry *
_idx_ip6_routes (const NMIP6Config *self)
{
const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
return nm_dedup_multi_index_lookup_head (priv->multi_idx,
&priv->idx_ip6_routes,
NULL);
}
static const NMPlatformIP6Route *
_entry_iter_get_ip6_route (const CList *iter)
{
const NMDedupMultiEntry *e = c_list_entry (iter, NMDedupMultiEntry, lst_entries);
const NMPObject *o = e->obj;
nm_assert (o);
nm_assert (NMP_OBJECT_GET_TYPE (o) == NMP_OBJECT_TYPE_IP6_ROUTE);
return &o->ip6_route;
}
void
nm_ip6_config_iter_ip6_route_init (NMDedupMultiIter *ipconf_iter, const NMIP6Config *self)
{
g_return_if_fail (NM_IS_IP6_CONFIG (self));
nm_dedup_multi_iter_init (ipconf_iter, _idx_ip6_routes (self));
}
gboolean
nm_ip6_config_iter_ip6_route_next (NMDedupMultiIter *ipconf_iter, const NMPlatformIP6Route **out_route)
{
gboolean has_next;
has_next = nm_dedup_multi_iter_next (ipconf_iter);
if (has_next) {
nm_assert (NMP_OBJECT_GET_TYPE (ipconf_iter->current->obj) == NMP_OBJECT_TYPE_IP6_ROUTE);
NM_SET_OUT (out_route, &(((const NMPObject *) ipconf_iter->current->obj)->ip6_route));
}
return has_next;
}
/*****************************************************************************/
static void
notify_addresses (NMIP6Config *self)
{
@@ -193,15 +242,6 @@ addresses_are_duplicate (const NMPlatformIP6Address *a, const NMPlatformIP6Addre
return IN6_ARE_ADDR_EQUAL (&a->address, &b->address);
}
static gboolean
routes_are_duplicate (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b, gboolean consider_gateway_and_metric)
{
return IN6_ARE_ADDR_EQUAL (&a->network, &b->network) && a->plen == b->plen &&
( !consider_gateway_and_metric
|| ( IN6_ARE_ADDR_EQUAL (&a->gateway, &b->gateway)
&& nm_utils_ip6_route_metric_normalize (a->metric) == nm_utils_ip6_route_metric_normalize (b->metric)));
}
static gint
_addresses_sort_cmp_get_prio (const struct in6_addr *addr)
{
@@ -315,10 +355,12 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i
{
NMIP6Config *config;
NMIP6ConfigPrivate *priv;
guint i;
guint32 lowest_metric = G_MAXUINT32;
struct in6_addr old_gateway = IN6ADDR_ANY_INIT;
gboolean has_gateway = FALSE;
gboolean has_gateway;
const NMDedupMultiHeadEntry *pl_head_entry;
NMDedupMultiIter iter;
const NMPObject *plobj = NULL;
gboolean notify_nameservers = FALSE;
/* Slaves have no IP configuration */
@@ -329,47 +371,56 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i
priv = NM_IP6_CONFIG_GET_PRIVATE (config);
g_array_unref (priv->addresses);
g_array_unref (priv->routes);
priv->addresses = nm_platform_ip6_address_get_all (platform, ifindex);
priv->routes = nm_platform_ip6_route_get_all (platform, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
pl_head_entry = nm_platform_lookup_route_visible (platform,
NMP_OBJECT_TYPE_IP6_ROUTE,
ifindex,
TRUE,
TRUE);
/* Extract gateway from default route */
old_gateway = priv->gateway;
for (i = 0; i < priv->routes->len; ) {
const NMPlatformIP6Route *route = &g_array_index (priv->routes, NMPlatformIP6Route, i);
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) {
lowest_metric = G_MAXUINT32;
has_gateway = FALSE;
nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) {
const NMPlatformIP6Route *route = NMP_OBJECT_CAST_IP6_ROUTE (plobj);
if ( NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)
&& route->rt_source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) {
if (route->metric < lowest_metric) {
priv->gateway = route->gateway;
lowest_metric = route->metric;
}
has_gateway = TRUE;
/* Remove the default route from the list */
g_array_remove_index_fast (priv->routes, i);
continue;
}
i++;
}
/* we detect the route metric based on the default route. All non-default
* routes have their route metrics explicitly set. */
priv->route_metric = has_gateway ? (gint64) lowest_metric : (gint64) -1;
/* If there is a host route to the gateway, ignore that route. It is
* automatically added by NetworkManager when needed.
*/
if (has_gateway) {
for (i = 0; i < priv->routes->len; i++) {
const NMPlatformIP6Route *route = &g_array_index (priv->routes, NMPlatformIP6Route, i);
nm_dedup_multi_iter_rewind (&iter);
nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) {
const NMPlatformIP6Route *route = NMP_OBJECT_CAST_IP6_ROUTE (plobj);
if ( route->plen == 128
&& IN6_ARE_ADDR_EQUAL (&route->network, &priv->gateway)
&& IN6_IS_ADDR_UNSPECIFIED (&route->gateway)) {
g_array_remove_index (priv->routes, i);
i--;
}
if (route->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL)
continue;
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route))
continue;
if ( has_gateway
&& route->plen == 128
&& IN6_ARE_ADDR_EQUAL (&route->network, &priv->gateway)
&& IN6_IS_ADDR_UNSPECIFIED (&route->gateway)) {
/* If there is a host route to the gateway, ignore that route. It is
* automatically added by NetworkManager when needed.
*/
continue;
}
_add_route (config, plobj, NULL);
}
/* If the interface has the default route, and has IPv6 addresses, capture
@@ -403,7 +454,6 @@ nm_ip6_config_commit (const NMIP6Config *config,
gboolean routes_full_sync)
{
const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
gboolean success;
g_return_val_if_fail (ifindex > 0, FALSE);
g_return_val_if_fail (config != NULL, FALSE);
@@ -413,21 +463,24 @@ nm_ip6_config_commit (const NMIP6Config *config,
/* Routes */
{
guint i;
guint count = nm_ip6_config_get_num_routes (config);
GArray *routes = g_array_sized_new (FALSE, FALSE, sizeof (NMPlatformIP6Route), count);
const NMPlatformIP6Route *route;
const NMDedupMultiHeadEntry *head_entry;
gs_unref_array GArray *routes = NULL;
const CList *iter;
for (i = 0; i < count; i++) {
route = nm_ip6_config_get_route (config, i);
g_array_append_vals (routes, route, 1);
head_entry = _idx_ip6_routes (config);
routes = g_array_sized_new (FALSE, FALSE, sizeof (NMPlatformIP6Route), head_entry ? head_entry->len : 0);
if (head_entry) {
c_list_for_each (iter, &head_entry->lst_entries_head)
g_array_append_vals (routes, _entry_iter_get_ip6_route (iter), 1);
}
success = nm_route_manager_ip6_route_sync (route_manager, ifindex, routes, TRUE, routes_full_sync);
g_array_unref (routes);
if (!nm_route_manager_ip6_route_sync (route_manager, ifindex, routes, TRUE, routes_full_sync))
return FALSE;
}
return success;
return TRUE;
}
static void
@@ -558,7 +611,7 @@ nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIPConfig *setting, gu
route.rt_source = NM_IP_CONFIG_SOURCE_USER;
merge_route_attributes (s_route, &route);
nm_ip6_config_add_route (config, &route);
_add_route (config, NULL, &route);
}
/* DNS */
@@ -594,10 +647,12 @@ nm_ip6_config_create_setting (const NMIP6Config *config)
{
NMSettingIPConfig *s_ip6;
const struct in6_addr *gateway;
guint naddresses, nroutes, nnameservers, nsearches, noptions;
guint naddresses, nnameservers, nsearches, noptions;
const char *method = NULL;
int i;
gint64 route_metric;
NMDedupMultiIter ipconf_iter;
const NMPlatformIP6Route *route;
s_ip6 = NM_SETTING_IP_CONFIG (nm_setting_ip6_config_new ());
@@ -610,7 +665,6 @@ nm_ip6_config_create_setting (const NMIP6Config *config)
gateway = nm_ip6_config_get_gateway (config);
naddresses = nm_ip6_config_get_num_addresses (config);
nroutes = nm_ip6_config_get_num_routes (config);
nnameservers = nm_ip6_config_get_num_nameservers (config);
nsearches = nm_ip6_config_get_num_searches (config);
noptions = nm_ip6_config_get_num_dns_options (config);
@@ -661,8 +715,7 @@ nm_ip6_config_create_setting (const NMIP6Config *config)
NULL);
/* Routes */
for (i = 0; i < nroutes; i++) {
const NMPlatformIP6Route *route = nm_ip6_config_get_route (config, i);
nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, config, &route) {
NMIPRoute *s_route;
/* Ignore link-local route. */
@@ -718,6 +771,7 @@ nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, NMIPConfigMergeFl
NMIP6ConfigPrivate *dst_priv;
const NMIP6ConfigPrivate *src_priv;
guint32 i;
NMDedupMultiIter ipconf_iter;
g_return_if_fail (src != NULL);
g_return_if_fail (dst != NULL);
@@ -743,8 +797,10 @@ nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, NMIPConfigMergeFl
/* routes */
if (!NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_ROUTES)) {
for (i = 0; i < nm_ip6_config_get_num_routes (src); i++)
nm_ip6_config_add_route (dst, nm_ip6_config_get_route (src, i));
const NMPlatformIP6Route *route;
nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, src, &route)
_add_route (dst, NMP_OBJECT_UP_CAST (route), NULL);
}
if (dst_priv->route_metric == -1)
@@ -833,21 +889,6 @@ _nameservers_get_index (const NMIP6Config *self, const struct in6_addr *ns)
return -1;
}
static int
_routes_get_index (const NMIP6Config *self, const NMPlatformIP6Route *route)
{
const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
guint i;
for (i = 0; i < priv->routes->len; i++) {
const NMPlatformIP6Route *r = &g_array_index (priv->routes, NMPlatformIP6Route, i);
if (routes_are_duplicate (route, r, FALSE))
return (int) i;
}
return -1;
}
static int
_domains_get_index (const NMIP6Config *self, const char *domain)
{
@@ -905,13 +946,18 @@ _dns_options_get_index (const NMIP6Config *self, const char *option)
void
nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src)
{
NMIP6ConfigPrivate *priv_dst;
guint i;
gint idx;
const NMPlatformIP6Route *r;
NMDedupMultiIter ipconf_iter;
const struct in6_addr *dst_tmp, *src_tmp;
g_return_if_fail (src != NULL);
g_return_if_fail (dst != NULL);
priv_dst = NM_IP6_CONFIG_GET_PRIVATE (dst);
g_object_freeze_notify (G_OBJECT (dst));
/* addresses */
@@ -940,10 +986,10 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src)
/* ignore route_metric */
/* routes */
for (i = 0; i < nm_ip6_config_get_num_routes (src); i++) {
idx = _routes_get_index (dst, nm_ip6_config_get_route (src, i));
if (idx >= 0)
nm_ip6_config_del_route (dst, idx);
nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, src, &r) {
nm_dedup_multi_index_remove_obj (priv_dst->multi_idx,
&priv_dst->idx_ip6_routes,
NMP_OBJECT_UP_CAST (r));
}
/* domains */
@@ -980,12 +1026,19 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src)
void
nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src)
{
NMIP6ConfigPrivate *priv_dst;
const NMIP6ConfigPrivate *priv_src;
guint i;
gint idx;
const struct in6_addr *dst_tmp, *src_tmp;
NMDedupMultiIter ipconf_iter;
const NMPlatformIP6Route *r;
g_return_if_fail (src != NULL);
g_return_if_fail (dst != NULL);
g_return_if_fail (src);
g_return_if_fail (dst);
priv_dst = NM_IP6_CONFIG_GET_PRIVATE (dst);
priv_src = NM_IP6_CONFIG_GET_PRIVATE (src);
g_object_freeze_notify (G_OBJECT (dst));
@@ -1012,12 +1065,15 @@ nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src)
}
/* routes */
for (i = 0; i < nm_ip6_config_get_num_routes (dst); ) {
idx = _routes_get_index (src, nm_ip6_config_get_route (dst, i));
if (idx < 0)
nm_ip6_config_del_route (dst, i);
else
i++;
nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, dst, &r) {
if (nm_dedup_multi_index_lookup_obj (priv_src->multi_idx,
&priv_src->idx_ip6_routes,
NMP_OBJECT_UP_CAST (r)))
continue;
if (nm_dedup_multi_index_remove_entry (priv_dst->multi_idx,
ipconf_iter.current) != 1)
nm_assert_not_reached ();
}
/* ignore domains */
@@ -1052,7 +1108,7 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev
NMIP6ConfigPrivate *dst_priv;
const NMIP6ConfigPrivate *src_priv;
const NMPlatformIP6Address *dst_addr, *src_addr;
const NMPlatformIP6Route *dst_route, *src_route;
NMDedupMultiIter ipconf_iter_src, ipconf_iter_dst;
g_return_val_if_fail (NM_IS_IP6_CONFIG (src), FALSE);
g_return_val_if_fail (NM_IS_IP6_CONFIG (dst), FALSE);
@@ -1117,26 +1173,45 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev
}
/* routes */
num = nm_ip6_config_get_num_routes (src);
are_equal = num == nm_ip6_config_get_num_routes (dst);
if (are_equal) {
for (i = 0; i < num; i++ ) {
if (nm_platform_ip6_route_cmp (src_route = nm_ip6_config_get_route (src, i),
dst_route = nm_ip6_config_get_route (dst, i))) {
are_equal = FALSE;
if (!routes_are_duplicate (src_route, dst_route, TRUE)) {
has_relevant_changes = TRUE;
break;
}
nm_ip6_config_iter_ip6_route_init (&ipconf_iter_src, src);
nm_ip6_config_iter_ip6_route_init (&ipconf_iter_dst, dst);
are_equal = TRUE;
while (TRUE) {
gboolean has;
const NMPlatformIP6Route *r_src, *r_dst;
has = nm_ip6_config_iter_ip6_route_next (&ipconf_iter_src, &r_src);
if (has != nm_ip6_config_iter_ip6_route_next (&ipconf_iter_dst, &r_dst)) {
are_equal = FALSE;
has_relevant_changes = TRUE;
break;
}
if (!has)
break;
if (nm_platform_ip6_route_cmp (r_src, r_dst) != 0) {
are_equal = FALSE;
if (!nm_ip_config_obj_id_equal_ip6_route (r_src, r_dst)) {
has_relevant_changes = TRUE;
break;
}
}
} else
has_relevant_changes = TRUE;
}
if (!are_equal) {
nm_ip6_config_reset_routes (dst);
for (i = 0; i < num; i++)
nm_ip6_config_add_route (dst, nm_ip6_config_get_route (src, i));
const NMPlatformIP6Route *r_src;
has_minor_changes = TRUE;
nm_dedup_multi_index_dirty_set_idx (dst_priv->multi_idx, &dst_priv->idx_ip6_routes);
nm_dedup_multi_iter_rewind (&ipconf_iter_src);
while (nm_ip6_config_iter_ip6_route_next (&ipconf_iter_src, &r_src)) {
nm_dedup_multi_index_add (dst_priv->multi_idx,
&dst_priv->idx_ip6_routes,
NMP_OBJECT_UP_CAST (r_src),
NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE,
NULL,
NULL);
}
nm_dedup_multi_index_dirty_remove_idx (dst_priv->multi_idx, &dst_priv->idx_ip6_routes, FALSE);
}
/* nameservers */
@@ -1252,6 +1327,8 @@ nm_ip6_config_dump (const NMIP6Config *config, const char *detail)
const struct in6_addr *tmp;
guint32 i;
const char *str;
NMDedupMultiIter ipconf_iter;
const NMPlatformIP6Route *route;
g_return_if_fail (config != NULL);
@@ -1277,8 +1354,8 @@ nm_ip6_config_dump (const NMIP6Config *config, const char *detail)
}
/* routes */
for (i = 0; i < nm_ip6_config_get_num_routes (config); i++)
g_message (" rt: %s", nm_platform_ip6_route_to_string (nm_ip6_config_get_route (config, i), NULL, 0));
nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, config, &route)
g_message (" rt: %s", nm_platform_ip6_route_to_string (route, NULL, 0));
/* domains */
for (i = 0; i < nm_ip6_config_get_num_domains (config); i++)
@@ -1524,13 +1601,84 @@ nm_ip6_config_reset_routes (NMIP6Config *config)
{
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
if (priv->routes->len != 0) {
g_array_set_size (priv->routes, 0);
if (nm_dedup_multi_index_remove_idx (priv->multi_idx,
&priv->idx_ip6_routes) > 0) {
_notify (config, PROP_ROUTE_DATA);
_notify (config, PROP_ROUTES);
}
}
static void
_add_route (NMIP6Config *config, const NMPObject *o_new, const NMPlatformIP6Route *new)
{
NMIP6ConfigPrivate *priv;
NMPObject o_new_storage;
nm_auto_nmpobj const NMPObject *obj_old = NULL;
nm_assert (NM_IS_IP6_CONFIG (config));
priv = NM_IP6_CONFIG_GET_PRIVATE (config);
nm_assert (priv->ifindex > 0);
/* we go through extra lengths to accept a full o_new object. That one,
* can be reused by increasing the ref-count. */
if (!o_new) {
nm_assert (new);
nm_assert (new->plen > 0 && new->plen <= 128);
nmp_object_stackinit (&o_new_storage, NMP_OBJECT_TYPE_IP6_ROUTE,
(const NMPlatformObject *) new);
o_new_storage.ip6_route.ifindex = priv->ifindex;
o_new = &o_new_storage;
} else {
nm_assert (!new);
nm_assert (NMP_OBJECT_GET_TYPE (o_new) == NMP_OBJECT_TYPE_IP6_ROUTE);
nm_assert (o_new->ip6_route.plen > 0 && o_new->ip6_route.plen <= 128);
if (o_new->ip6_route.ifindex != priv->ifindex) {
nmp_object_stackinit (&o_new_storage, NMP_OBJECT_TYPE_IP6_ROUTE, &o_new->object);
o_new_storage.ip6_route.ifindex = priv->ifindex;
o_new = &o_new_storage;
}
}
if (!nm_dedup_multi_index_add (priv->multi_idx,
&priv->idx_ip6_routes,
o_new,
NM_DEDUP_MULTI_IDX_MODE_APPEND,
NULL,
&obj_old))
return;
if (obj_old) {
NMIPConfigSource old_source;
old_source = obj_old->ip_route.rt_source;
/* we want to keep the maximum rt_source. But since we expect
* that usually we already add the maxiumum right away, we first try to
* add the new route (replacing the old one). Only if we later
* find out that rt_source is now lower, we fix it.
*/
if (o_new->ip_route.rt_source < old_source) {
if (o_new != &o_new_storage) {
nmp_object_stackinit (&o_new_storage, NMP_OBJECT_TYPE_IP6_ROUTE,
&o_new->object);
o_new = &o_new_storage;
}
o_new_storage.ip_route.rt_source = old_source;
if (!nm_dedup_multi_index_add (priv->multi_idx,
&priv->idx_ip6_routes,
o_new,
NM_DEDUP_MULTI_IDX_MODE_APPEND,
NULL,
NULL))
nm_assert_not_reached ();
}
}
_notify (config, PROP_ROUTE_DATA);
_notify (config, PROP_ROUTES);
}
/**
* nm_ip6_config_add_route:
* @config: the #NMIP6Config
@@ -1544,76 +1692,70 @@ nm_ip6_config_reset_routes (NMIP6Config *config)
void
nm_ip6_config_add_route (NMIP6Config *config, const NMPlatformIP6Route *new)
{
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
NMIPConfigSource old_source;
int i;
g_return_if_fail (new != NULL);
g_return_if_fail (config);
g_return_if_fail (new);
g_return_if_fail (new->plen > 0 && new->plen <= 128);
g_return_if_fail (priv->ifindex > 0);
g_return_if_fail (NM_IP6_CONFIG_GET_PRIVATE (config)->ifindex > 0);
for (i = 0; i < priv->routes->len; i++ ) {
NMPlatformIP6Route *item = &g_array_index (priv->routes, NMPlatformIP6Route, i);
if (routes_are_duplicate (item, new, FALSE)) {
if (nm_platform_ip6_route_cmp (item, new) == 0)
return;
old_source = item->rt_source;
*item = *new;
/* Restore highest priority source */
item->rt_source = MAX (old_source, new->rt_source);
item->ifindex = priv->ifindex;
goto NOTIFY;
}
}
g_array_append_val (priv->routes, *new);
g_array_index (priv->routes, NMPlatformIP6Route, priv->routes->len - 1).ifindex = priv->ifindex;
NOTIFY:
_notify (config, PROP_ROUTE_DATA);
_notify (config, PROP_ROUTES);
_add_route (config, NULL, new);
}
void
nm_ip6_config_del_route (NMIP6Config *config, guint i)
_nmtst_ip6_config_del_route (NMIP6Config *self, guint i)
{
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
const NMPlatformIP6Route *r;
g_return_if_fail (i < priv->routes->len);
r = _nmtst_ip6_config_get_route (self, i);
g_return_if_fail (r);
g_array_remove_index (priv->routes, i);
_notify (config, PROP_ROUTE_DATA);
_notify (config, PROP_ROUTES);
if (nm_dedup_multi_index_remove_obj (priv->multi_idx,
&priv->idx_ip6_routes,
NMP_OBJECT_UP_CAST (r)) != 1)
g_return_if_reached ();
_notify (self, PROP_ROUTE_DATA);
_notify (self, PROP_ROUTES);
}
guint
nm_ip6_config_get_num_routes (const NMIP6Config *config)
nm_ip6_config_get_num_routes (const NMIP6Config *self)
{
const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
const NMDedupMultiHeadEntry *head_entry;
return priv->routes->len;
head_entry = _idx_ip6_routes (self);
nm_assert ((head_entry ? head_entry->len : 0) == c_list_length (&head_entry->lst_entries_head));
return head_entry ? head_entry->len : 0;
}
const NMPlatformIP6Route *
nm_ip6_config_get_route (const NMIP6Config *config, guint i)
_nmtst_ip6_config_get_route (const NMIP6Config *self, guint i)
{
const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
const NMDedupMultiHeadEntry *head_entry;
CList *iter;
guint j;
return &g_array_index (priv->routes, NMPlatformIP6Route, i);
head_entry = _idx_ip6_routes (self);
if (head_entry) {
j = 0;
c_list_for_each (iter, &head_entry->lst_entries_head) {
if (i == j)
return _entry_iter_get_ip6_route (iter);
j++;
}
}
g_return_val_if_reached (NULL);
}
const NMPlatformIP6Route *
nm_ip6_config_get_direct_route_for_host (const NMIP6Config *config, const struct in6_addr *host)
nm_ip6_config_get_direct_route_for_host (const NMIP6Config *self, const struct in6_addr *host)
{
const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
guint i;
NMPlatformIP6Route *best_route = NULL;
const NMPlatformIP6Route *best_route = NULL;
const NMPlatformIP6Route *item;
NMDedupMultiIter ipconf_iter;
g_return_val_if_fail (host && !IN6_IS_ADDR_UNSPECIFIED (host), NULL);
for (i = 0; i < priv->routes->len; i++) {
NMPlatformIP6Route *item = &g_array_index (priv->routes, NMPlatformIP6Route, i);
nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, self, &item) {
if (!IN6_IS_ADDR_UNSPECIFIED (&item->gateway))
continue;
@@ -1629,7 +1771,6 @@ nm_ip6_config_get_direct_route_for_host (const NMIP6Config *config, const struct
best_route = item;
}
return best_route;
}
@@ -1963,6 +2104,8 @@ nm_ip6_config_hash (const NMIP6Config *config, GChecksum *sum, gboolean dns_only
{
guint32 i;
const char *s;
NMDedupMultiIter ipconf_iter;
const NMPlatformIP6Route *route;
g_return_if_fail (config);
g_return_if_fail (sum);
@@ -1977,9 +2120,7 @@ nm_ip6_config_hash (const NMIP6Config *config, GChecksum *sum, gboolean dns_only
hash_u32 (sum, address->plen);
}
for (i = 0; i < nm_ip6_config_get_num_routes (config); i++) {
const NMPlatformIP6Route *route = nm_ip6_config_get_route (config, i);
nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, config, &route) {
hash_in6addr (sum, &route->network);
hash_u32 (sum, route->plen);
hash_in6addr (sum, &route->gateway);
@@ -2074,6 +2215,9 @@ get_property (GObject *object, guint prop_id,
{
NMIP6Config *config = NM_IP6_CONFIG (object);
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
NMDedupMultiIter ipconf_iter;
const NMPlatformIP6Route *route;
GVariantBuilder array_builder, addr_builder, route_builder;
switch (prop_id) {
case PROP_IFINDEX:
@@ -2082,7 +2226,6 @@ get_property (GObject *object, guint prop_id,
case PROP_ADDRESS_DATA:
case PROP_ADDRESSES:
{
GVariantBuilder array_builder, addr_builder;
gs_unref_array GArray *new = NULL;
const struct in6_addr *gateway;
guint naddr, i;
@@ -2144,14 +2287,8 @@ return_cached:
break;
case PROP_ROUTE_DATA:
{
GVariantBuilder array_builder, route_builder;
guint nroutes = nm_ip6_config_get_num_routes (config);
int i;
g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aa{sv}"));
for (i = 0; i < nroutes; i++) {
const NMPlatformIP6Route *route = nm_ip6_config_get_route (config, i);
nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, config, &route) {
g_variant_builder_init (&route_builder, G_VARIANT_TYPE ("a{sv}"));
g_variant_builder_add (&route_builder, "{sv}",
"dest",
@@ -2177,14 +2314,8 @@ return_cached:
break;
case PROP_ROUTES:
{
GVariantBuilder array_builder;
int nroutes = nm_ip6_config_get_num_routes (config);
int i;
g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("a(ayuayu)"));
for (i = 0; i < nroutes; i++) {
const NMPlatformIP6Route *route = nm_ip6_config_get_route (config, i);
nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, config, &route) {
/* legacy versions of nm_ip6_route_set_prefix() in libnm-util assert that the
* plen is positive. Skip the default routes not to break older clients. */
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route))
@@ -2263,8 +2394,10 @@ nm_ip6_config_init (NMIP6Config *config)
{
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
nm_ip_config_dedup_multi_idx_type_init ((NMIPConfigDedupMultiIdxType *) &priv->idx_ip6_routes,
NMP_OBJECT_TYPE_IP6_ROUTE);
priv->addresses = g_array_new (FALSE, TRUE, sizeof (NMPlatformIP6Address));
priv->routes = g_array_new (FALSE, TRUE, sizeof (NMPlatformIP6Route));
priv->nameservers = g_array_new (FALSE, TRUE, sizeof (struct in6_addr));
priv->domains = g_ptr_array_new_with_free_func (g_free);
priv->searches = g_ptr_array_new_with_free_func (g_free);
@@ -2301,8 +2434,9 @@ finalize (GObject *object)
NMIP6Config *self = NM_IP6_CONFIG (object);
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
nm_dedup_multi_index_remove_idx (priv->multi_idx, &priv->idx_ip6_routes);
g_array_unref (priv->addresses);
g_array_unref (priv->routes);
g_array_unref (priv->nameservers);
g_ptr_array_unref (priv->domains);
g_ptr_array_unref (priv->searches);

View File

@@ -26,6 +26,20 @@
#include "nm-exported-object.h"
#include "nm-setting-ip6-config.h"
#include "nm-utils/nm-dedup-multi.h"
/*****************************************************************************/
void nm_ip6_config_iter_ip6_route_init (NMDedupMultiIter *iter, const NMIP6Config *self);
gboolean nm_ip6_config_iter_ip6_route_next (NMDedupMultiIter *iter, const NMPlatformIP6Route **out_route);
#define nm_ip6_config_iter_ip6_route_for_each(iter, self, route) \
for (nm_ip6_config_iter_ip6_route_init ((iter), (self)); \
nm_ip6_config_iter_ip6_route_next ((iter), (route)); \
)
/*****************************************************************************/
#define NM_TYPE_IP6_CONFIG (nm_ip6_config_get_type ())
#define NM_IP6_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_IP6_CONFIG, NMIP6Config))
#define NM_IP6_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_IP6_CONFIG, NMIP6ConfigClass))
@@ -101,9 +115,9 @@ gboolean nm_ip6_config_has_any_dad_pending (const NMIP6Config *self,
void nm_ip6_config_reset_routes (NMIP6Config *config);
void nm_ip6_config_add_route (NMIP6Config *config, const NMPlatformIP6Route *route);
void nm_ip6_config_del_route (NMIP6Config *config, guint i);
void _nmtst_ip6_config_del_route (NMIP6Config *config, guint i);
guint nm_ip6_config_get_num_routes (const NMIP6Config *config);
const NMPlatformIP6Route *nm_ip6_config_get_route (const NMIP6Config *config, guint i);
const NMPlatformIP6Route *_nmtst_ip6_config_get_route (const NMIP6Config *config, guint i);
const NMPlatformIP6Route *nm_ip6_config_get_direct_route_for_host (const NMIP6Config *config, const struct in6_addr *host);
const NMPlatformIP6Address *nm_ip6_config_get_subnet_for_host (const NMIP6Config *config, const struct in6_addr *host);

View File

@@ -202,8 +202,10 @@ get_ip4_domains (GPtrArray *domains, NMIP4Config *ip4)
static void
get_ip6_domains (GPtrArray *domains, NMIP6Config *ip6)
{
NMDedupMultiIter ipconf_iter;
char *cidr;
int i;
const NMPlatformIP6Route *routes;
guint i;
/* Extract searches */
for (i = 0; i < nm_ip6_config_get_num_searches (ip6); i++)
@@ -223,9 +225,7 @@ get_ip6_domains (GPtrArray *domains, NMIP6Config *ip6)
g_ptr_array_add (domains, cidr);
}
for (i = 0; i < nm_ip6_config_get_num_routes (ip6); i++) {
const NMPlatformIP6Route *routes = nm_ip6_config_get_route (ip6, i);
nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &routes) {
cidr = g_strdup_printf ("%s/%u",
nm_utils_inet6_ntop (&routes->network, NULL),
routes->plen);

View File

@@ -98,7 +98,7 @@ test_subtract (void)
g_assert (nm_ip6_config_get_gateway (dst) == NULL);
g_assert_cmpuint (nm_ip6_config_get_num_routes (dst), ==, 1);
test_route = nm_ip6_config_get_route (dst, 0);
test_route = _nmtst_ip6_config_get_route (dst, 0);
g_assert (test_route != NULL);
tmp = *nmtst_inet6_from_string (expected_route_dest);
@@ -207,27 +207,27 @@ test_add_route_with_source (void)
route.rt_source = NM_IP_CONFIG_SOURCE_USER;
nm_ip6_config_add_route (a, &route);
test_route = nm_ip6_config_get_route (a, 0);
test_route = _nmtst_ip6_config_get_route (a, 0);
g_assert_cmpint (test_route->rt_source, ==, NM_IP_CONFIG_SOURCE_USER);
route.rt_source = NM_IP_CONFIG_SOURCE_VPN;
nm_ip6_config_add_route (a, &route);
test_route = nm_ip6_config_get_route (a, 0);
test_route = _nmtst_ip6_config_get_route (a, 0);
g_assert_cmpint (test_route->rt_source, ==, NM_IP_CONFIG_SOURCE_USER);
/* Test that a lower priority address source is overwritten */
nm_ip6_config_del_route (a, 0);
_nmtst_ip6_config_del_route (a, 0);
route.rt_source = NM_IP_CONFIG_SOURCE_KERNEL;
nm_ip6_config_add_route (a, &route);
test_route = nm_ip6_config_get_route (a, 0);
test_route = _nmtst_ip6_config_get_route (a, 0);
g_assert_cmpint (test_route->rt_source, ==, NM_IP_CONFIG_SOURCE_KERNEL);
route.rt_source = NM_IP_CONFIG_SOURCE_USER;
nm_ip6_config_add_route (a, &route);
test_route = nm_ip6_config_get_route (a, 0);
test_route = _nmtst_ip6_config_get_route (a, 0);
g_assert_cmpint (test_route->rt_source, ==, NM_IP_CONFIG_SOURCE_USER);
g_object_unref (a);

View File

@@ -992,6 +992,8 @@ print_vpn_config (NMVpnConnection *self)
_LOGI ("Data: No IPv4 configuration");
if (priv->ip6_config) {
const NMPlatformIP6Route *route;
_LOGI ("Data: IPv6 configuration:");
address6 = nm_ip6_config_get_address (priv->ip6_config, 0);
@@ -1003,10 +1005,7 @@ print_vpn_config (NMVpnConnection *self)
_LOGI ("Data: Internal Point-to-Point Address: %s", nm_utils_inet6_ntop (&address6->peer_address, NULL));
_LOGI ("Data: Maximum Segment Size (MSS): %d", nm_ip6_config_get_mss (priv->ip6_config));
num = nm_ip6_config_get_num_routes (priv->ip6_config);
for (i = 0; i < num; i++) {
const NMPlatformIP6Route *route = nm_ip6_config_get_route (priv->ip6_config, i);
nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, priv->ip6_config, &route) {
_LOGI ("Data: Static Route: %s/%d Next Hop: %s",
nm_utils_inet6_ntop (&route->network, NULL),
route->plen,
@@ -1578,7 +1577,6 @@ nm_vpn_connection_ip6_config_get (NMVpnConnection *self, GVariant *dict)
const char *str;
GVariant *v;
gboolean b;
guint i, n;
int ip_ifindex;
g_return_if_fail (dict && g_variant_is_of_type (dict, G_VARIANT_TYPE_VARDICT));
@@ -1669,9 +1667,11 @@ nm_vpn_connection_ip6_config_get (NMVpnConnection *self, GVariant *dict)
if ( g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_PRESERVE_ROUTES, "b", &b)
&& b) {
if (priv->ip6_config) {
n = nm_ip6_config_get_num_routes (priv->ip6_config);
for (i = 0; i < n; i++)
nm_ip6_config_add_route (config, nm_ip6_config_get_route (priv->ip6_config, i));
NMDedupMultiIter ipconf_iter;
const NMPlatformIP6Route *route;
nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, priv->ip6_config, &route)
nm_ip6_config_add_route (config, route);
}
} else if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_ROUTES, "a(ayuayu)", &iter)) {
GVariant *dest, *next_hop;