core: add nm_ip6_config_subtract()

Removes anything in 'src' from 'dst'.
This commit is contained in:
Dan Williams 2013-08-15 12:44:27 -05:00
parent 04f6e09d50
commit d8c9828a4d
5 changed files with 363 additions and 23 deletions

1
.gitignore vendored
View file

@ -179,6 +179,7 @@ valgrind-*.log
/libnm-glib/tests/test-remote-settings-client
/src/tests/test-dhcp-options
/src/tests/test-ip4-config
/src/tests/test-ip6-config
/src/tests/test-policy-hosts
/src/tests/test-wifi-ap-utils
/src/dhcp-manager/tests/test-dhcp-dhclient

View file

@ -167,12 +167,6 @@ nm_ip6_config_commit (NMIP6Config *config, int ifindex, int priority)
return success;
}
static inline gboolean
ip6_addresses_equal (const struct in6_addr *a, const struct in6_addr *b)
{
return memcmp (a, b, sizeof (struct in6_addr)) == 0;
}
void
nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIP6Config *setting)
{
@ -386,6 +380,115 @@ nm_ip6_config_destination_is_direct (NMIP6Config *config, const struct in6_addr
return FALSE;
}
static gboolean
routes_are_duplicate (NMPlatformIP6Route *a, NMPlatformIP6Route *b)
{
return IN6_ARE_ADDR_EQUAL (&a->network, &b->network) && a->plen == b->plen;
}
/**
* nm_ip6_config_subtract()
* @dst: config from which to remove everything in @src
* @src: config to remove from @dst
*
* Removes everything in @src from @dst.
*
*/
void
nm_ip6_config_subtract (NMIP6Config *dst, NMIP6Config *src)
{
guint32 i, j;
const struct in6_addr *dst_tmp, *src_tmp;
g_return_if_fail (src != NULL);
g_return_if_fail (dst != NULL);
/* addresses */
for (i = 0; i < nm_ip6_config_get_num_addresses (src); i++) {
const NMPlatformIP6Address *src_addr = nm_ip6_config_get_address (src, i);
for (j = 0; j < nm_ip6_config_get_num_addresses (dst); j++) {
const NMPlatformIP6Address *dst_addr = nm_ip6_config_get_address (dst, j);
if (IN6_ARE_ADDR_EQUAL (&src_addr->address, &dst_addr->address)) {
nm_ip6_config_del_address (dst, j);
break;
}
}
}
/* ptp address */
src_tmp = nm_ip6_config_get_ptp_address (src);
dst_tmp = nm_ip6_config_get_ptp_address (dst);
if (src_tmp && dst_tmp && IN6_ARE_ADDR_EQUAL (src_tmp, dst_tmp))
nm_ip6_config_set_ptp_address (dst, NULL);
/* nameservers */
for (i = 0; i < nm_ip6_config_get_num_nameservers (src); i++) {
const struct in6_addr *src_ns = nm_ip6_config_get_nameserver (src, i);
for (j = 0; j < nm_ip6_config_get_num_nameservers (dst); j++) {
const struct in6_addr *dst_ns = nm_ip6_config_get_nameserver (dst, j);
if (IN6_ARE_ADDR_EQUAL (src_ns, dst_ns)) {
nm_ip6_config_del_nameserver (dst, j);
break;
}
}
}
/* default gateway */
src_tmp = nm_ip6_config_get_gateway (src);
dst_tmp = nm_ip6_config_get_gateway (dst);
if (src_tmp && dst_tmp && IN6_ARE_ADDR_EQUAL (src_tmp, dst_tmp))
nm_ip6_config_set_gateway (dst, NULL);
/* routes */
for (i = 0; i < nm_ip6_config_get_num_routes (src); i++) {
NMPlatformIP6Route *src_route = nm_ip6_config_get_route (src, i);
for (j = 0; j < nm_ip6_config_get_num_routes (dst); j++) {
NMPlatformIP6Route *dst_route = nm_ip6_config_get_route (dst, j);
if (routes_are_duplicate (src_route, dst_route)) {
nm_ip6_config_del_route (dst, j);
break;
}
}
}
/* domains */
for (i = 0; i < nm_ip6_config_get_num_domains (src); i++) {
const char *src_domain = nm_ip6_config_get_domain (src, i);
for (j = 0; j < nm_ip6_config_get_num_domains (dst); j++) {
const char *dst_domain = nm_ip6_config_get_domain (dst, j);
if (g_strcmp0 (src_domain, dst_domain) == 0) {
nm_ip6_config_del_domain (dst, j);
break;
}
}
}
/* dns searches */
for (i = 0; i < nm_ip6_config_get_num_searches (src); i++) {
const char *src_search = nm_ip6_config_get_search (src, i);
for (j = 0; j < nm_ip6_config_get_num_searches (dst); j++) {
const char *dst_search = nm_ip6_config_get_search (dst, j);
if (g_strcmp0 (src_search, dst_search) == 0) {
nm_ip6_config_del_search (dst, j);
break;
}
}
}
if (nm_ip6_config_get_mss (src) == nm_ip6_config_get_mss (dst))
nm_ip6_config_set_mss (dst, 0);
}
/******************************************************************/
void
@ -433,12 +536,6 @@ nm_ip6_config_reset_addresses (NMIP6Config *config)
g_array_set_size (priv->nameservers, 0);
}
static gboolean
addresses_are_duplicate (const NMPlatformIP6Address *a, const NMPlatformIP6Address *b)
{
return IN6_ARE_ADDR_EQUAL (&a->address, &b->address);
}
void
nm_ip6_config_add_address (NMIP6Config *config, const NMPlatformIP6Address *new)
{
@ -450,7 +547,8 @@ nm_ip6_config_add_address (NMIP6Config *config, const NMPlatformIP6Address *new)
for (i = 0; i < priv->addresses->len; i++ ) {
NMPlatformIP6Address *item = &g_array_index (priv->addresses, NMPlatformIP6Address, i);
if (addresses_are_duplicate (item, new)) {
if (IN6_ARE_ADDR_EQUAL (&item->address, &new->address)) {
/* Copy over old item to get new lifetime, timestamp, preferred */
memcpy (item, new, sizeof (*item));
return;
}
@ -459,6 +557,16 @@ nm_ip6_config_add_address (NMIP6Config *config, const NMPlatformIP6Address *new)
g_array_append_val (priv->addresses, *new);
}
void
nm_ip6_config_del_address (NMIP6Config *config, guint i)
{
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
g_return_if_fail (i < priv->addresses->len);
g_array_remove_index (priv->addresses, i);
}
guint
nm_ip6_config_get_num_addresses (NMIP6Config *config)
{
@ -485,12 +593,6 @@ nm_ip6_config_reset_routes (NMIP6Config *config)
g_array_set_size (priv->routes, 0);
}
static gboolean
routes_are_duplicate (NMPlatformIP6Route *a, NMPlatformIP6Route *b)
{
return IN6_ARE_ADDR_EQUAL (&a->network, &b->network) && a->plen == b->plen;
}
void
nm_ip6_config_add_route (NMIP6Config *config, NMPlatformIP6Route *new)
{
@ -511,6 +613,16 @@ nm_ip6_config_add_route (NMIP6Config *config, NMPlatformIP6Route *new)
g_array_append_val (priv->routes, *new);
}
void
nm_ip6_config_del_route (NMIP6Config *config, guint i)
{
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
g_return_if_fail (i < priv->routes->len);
g_array_remove_index (priv->routes, i);
}
guint
nm_ip6_config_get_num_routes (NMIP6Config *config)
{
@ -552,6 +664,16 @@ nm_ip6_config_add_nameserver (NMIP6Config *config, const struct in6_addr *new)
g_array_append_val (priv->nameservers, *new);
}
void
nm_ip6_config_del_nameserver (NMIP6Config *config, guint i)
{
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
g_return_if_fail (i < priv->nameservers->len);
g_array_remove_index (priv->nameservers, i);
}
guint32
nm_ip6_config_get_num_nameservers (NMIP6Config *config)
{
@ -594,6 +716,16 @@ nm_ip6_config_add_domain (NMIP6Config *config, const char *domain)
g_ptr_array_add (priv->domains, g_strdup (domain));
}
void
nm_ip6_config_del_domain (NMIP6Config *config, guint i)
{
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
g_return_if_fail (i < priv->domains->len);
g_ptr_array_remove_index (priv->domains, i);
}
guint32
nm_ip6_config_get_num_domains (NMIP6Config *config)
{
@ -636,6 +768,16 @@ nm_ip6_config_add_search (NMIP6Config *config, const char *new)
g_ptr_array_add (priv->searches, g_strdup (new));
}
void
nm_ip6_config_del_search (NMIP6Config *config, guint i)
{
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
g_return_if_fail (i < priv->searches->len);
g_ptr_array_remove_index (priv->searches, i);
}
guint32
nm_ip6_config_get_num_searches (NMIP6Config *config)
{
@ -677,7 +819,11 @@ nm_ip6_config_set_ptp_address (NMIP6Config *config, const struct in6_addr *ptp_a
{
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
priv->ptp_address = *ptp_address;
if (ptp_address)
priv->ptp_address = *ptp_address;
else
memset (&priv->ptp_address, 0, sizeof (priv->ptp_address));
}
const struct in6_addr *
@ -685,7 +831,7 @@ nm_ip6_config_get_ptp_address (NMIP6Config *config)
{
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
return &priv->ptp_address;
return IN6_IS_ADDR_UNSPECIFIED (&priv->ptp_address) ? NULL : &priv->ptp_address;
}
/******************************************************************/

View file

@ -63,6 +63,7 @@ void nm_ip6_config_update_setting (NMIP6Config *config, NMSettingIP6Config *sett
/* Utility functions */
void nm_ip6_config_merge (NMIP6Config *dst, NMIP6Config *src);
void nm_ip6_config_subtract (NMIP6Config *dst, NMIP6Config *src);
int nm_ip6_config_destination_is_direct (NMIP6Config *config, const struct in6_addr *dest, int plen);
/* Gateways */
@ -74,30 +75,35 @@ const struct in6_addr *nm_ip6_config_get_gateway (NMIP6Config *config);
/* Addresses */
void nm_ip6_config_reset_addresses (NMIP6Config *config);
void nm_ip6_config_add_address (NMIP6Config *config, const NMPlatformIP6Address *address);
void nm_ip6_config_del_address (NMIP6Config *config, guint i);
guint nm_ip6_config_get_num_addresses (NMIP6Config *config);
NMPlatformIP6Address *nm_ip6_config_get_address (NMIP6Config *config, guint i);
/* Routes */
void nm_ip6_config_reset_routes (NMIP6Config *config);
void nm_ip6_config_add_route (NMIP6Config *config, NMPlatformIP6Route *route);
void nm_ip6_config_del_route (NMIP6Config *config, guint i);
guint32 nm_ip6_config_get_num_routes (NMIP6Config *config);
NMPlatformIP6Route * nm_ip6_config_get_route (NMIP6Config *config, guint32 i);
/* Nameservers */
void nm_ip6_config_reset_nameservers (NMIP6Config *config);
void nm_ip6_config_add_nameserver (NMIP6Config *config, const struct in6_addr *nameserver);
void nm_ip6_config_del_nameserver (NMIP6Config *config, guint i);
guint32 nm_ip6_config_get_num_nameservers (NMIP6Config *config);
const struct in6_addr *nm_ip6_config_get_nameserver (NMIP6Config *config, guint i);
/* Domains */
void nm_ip6_config_reset_domains (NMIP6Config *config);
void nm_ip6_config_add_domain (NMIP6Config *config, const char *domain);
void nm_ip6_config_del_domain (NMIP6Config *config, guint i);
guint32 nm_ip6_config_get_num_domains (NMIP6Config *config);
const char * nm_ip6_config_get_domain (NMIP6Config *config, guint i);
/* Search lists */
void nm_ip6_config_reset_searches (NMIP6Config *config);
void nm_ip6_config_add_search (NMIP6Config *config, const char *search);
void nm_ip6_config_del_search (NMIP6Config *config, guint i);
guint32 nm_ip6_config_get_num_searches (NMIP6Config *config);
const char * nm_ip6_config_get_search (NMIP6Config *config, guint i);

View file

@ -14,7 +14,8 @@ noinst_PROGRAMS = \
test-dhcp-options \
test-policy-hosts \
test-wifi-ap-utils \
test-ip4-config
test-ip4-config \
test-ip6-config
####### DHCP options test #######
@ -53,14 +54,24 @@ test_ip4_config_SOURCES = \
test_ip4_config_LDADD = \
$(top_builddir)/src/libNetworkManager.la
####### ip6 config test #######
test_ip6_config_SOURCES = \
test-ip6-config.c
test_ip6_config_LDADD = \
$(top_builddir)/src/libNetworkManager.la
####### secret agent interface test #######
EXTRA_DIST = test-secret-agent.py
###########################################
check-local: test-dhcp-options test-policy-hosts test-wifi-ap-utils test-ip4-config
check-local: test-dhcp-options test-policy-hosts test-wifi-ap-utils test-ip4-config test-ip6-config
$(abs_builddir)/test-dhcp-options
$(abs_builddir)/test-policy-hosts
$(abs_builddir)/test-wifi-ap-utils
$(abs_builddir)/test-ip4-config
$(abs_builddir)/test-ip6-config

176
src/tests/test-ip6-config.c Normal file
View file

@ -0,0 +1,176 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2013 Red Hat, Inc.
*
*/
#include <glib.h>
#include <string.h>
#include <arpa/inet.h>
#include "nm-ip6-config.h"
static void
addr_init (NMPlatformIP6Address *a, const char *addr, guint plen)
{
memset (a, 0, sizeof (*a));
g_assert (inet_pton (AF_INET6, addr, (void *) &a->address) == 1);
a->plen = plen;
}
static void
route_new (NMPlatformIP6Route *route, const char *network, guint plen, const char *gw)
{
g_assert (route);
memset (route, 0, sizeof (*route));
g_assert (inet_pton (AF_INET6, network, (void *) &route->network) == 1);
route->plen = plen;
if (gw)
g_assert (inet_pton (AF_INET6, gw, (void *) &route->gateway) == 1);
}
static void
addr_to_num (const char *addr, struct in6_addr *out_addr)
{
memset (out_addr, 0, sizeof (*out_addr));
g_assert (inet_pton (AF_INET6, addr, (void *) out_addr) == 1);
}
static NMIP6Config *
build_test_config (void)
{
NMIP6Config *config;
NMPlatformIP6Address addr;
NMPlatformIP6Route route;
struct in6_addr tmp;
/* Build up the config to subtract */
config = nm_ip6_config_new ();
addr_init (&addr, "abcd:1234:4321::cdde", 64);
nm_ip6_config_add_address (config, &addr);
route_new (&route, "abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2");
nm_ip6_config_add_route (config, &route);
route_new (&route, "2001:abba::", 16, "2001:abba::2234");
nm_ip6_config_add_route (config, &route);
addr_to_num ("3001:abba::3234", &tmp);
nm_ip6_config_set_gateway (config, &tmp);
addr_to_num ("1:2:3:4::1", &tmp);
nm_ip6_config_add_nameserver (config, &tmp);
addr_to_num ("1:2:3:4::2", &tmp);
nm_ip6_config_add_nameserver (config, &tmp);
nm_ip6_config_add_domain (config, "foobar.com");
nm_ip6_config_add_domain (config, "baz.com");
nm_ip6_config_add_search (config, "blahblah.com");
nm_ip6_config_add_search (config, "beatbox.com");
addr_to_num ("1:2:3:4::5", &tmp);
nm_ip6_config_set_ptp_address (config, &tmp);
return config;
}
static void
test_subtract (void)
{
NMIP6Config *src, *dst;
NMPlatformIP6Address addr;
const NMPlatformIP6Address *test_addr;
NMPlatformIP6Route route, *test_route;
const char *expected_addr = "1122:3344:5566::7788";
guint32 expected_addr_plen = 96;
const char *expected_route_dest = "9991:8882:7773::";
guint32 expected_route_plen = 24;
const char *expected_route_next_hop = "1119:2228:3337:4446::5555";
struct in6_addr expected_ns1;
struct in6_addr expected_ns2;
const char *expected_domain = "wonderfalls.com";
const char *expected_search = "somewhere.com";
struct in6_addr tmp;
src = build_test_config ();
/* add a couple more things to the test config */
dst = build_test_config ();
addr_init (&addr, expected_addr, expected_addr_plen);
nm_ip6_config_add_address (dst, &addr);
route_new (&route, expected_route_dest, expected_route_plen, expected_route_next_hop);
nm_ip6_config_add_route (dst, &route);
addr_to_num ("2222:3333:4444::5555", &expected_ns1);
nm_ip6_config_add_nameserver (dst, &expected_ns1);
addr_to_num ("2222:3333:4444::5556", &expected_ns2);
nm_ip6_config_add_nameserver (dst, &expected_ns2);
nm_ip6_config_add_domain (dst, expected_domain);
nm_ip6_config_add_search (dst, expected_search);
nm_ip6_config_subtract (dst, src);
/* ensure what's left is what we expect */
g_assert_cmpuint (nm_ip6_config_get_num_addresses (dst), ==, 1);
test_addr = nm_ip6_config_get_address (dst, 0);
g_assert (test_addr != NULL);
addr_to_num (expected_addr, &tmp);
g_assert (memcmp (&test_addr->address, &tmp, sizeof (tmp)) == 0);
g_assert_cmpuint (test_addr->plen, ==, expected_addr_plen);
g_assert (nm_ip6_config_get_ptp_address (dst) == NULL);
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);
g_assert (test_route != NULL);
addr_to_num (expected_route_dest, &tmp);
g_assert (memcmp (&test_route->network, &tmp, sizeof (tmp)) == 0);
g_assert_cmpuint (test_route->plen, ==, expected_route_plen);
addr_to_num (expected_route_next_hop, &tmp);
g_assert (memcmp (&test_route->gateway, &tmp, sizeof (tmp)) == 0);
g_assert_cmpuint (nm_ip6_config_get_num_nameservers (dst), ==, 2);
g_assert (memcmp (nm_ip6_config_get_nameserver (dst, 0), &expected_ns1, sizeof (expected_ns1)) == 0);
g_assert (memcmp (nm_ip6_config_get_nameserver (dst, 1), &expected_ns2, sizeof (expected_ns2)) == 0);
g_assert_cmpuint (nm_ip6_config_get_num_domains (dst), ==, 1);
g_assert_cmpstr (nm_ip6_config_get_domain (dst, 0), ==, expected_domain);
g_assert_cmpuint (nm_ip6_config_get_num_searches (dst), ==, 1);
g_assert_cmpstr (nm_ip6_config_get_search (dst, 0), ==, expected_search);
g_object_unref (src);
g_object_unref (dst);
}
/*******************************************/
int
main (int argc, char **argv)
{
g_test_init (&argc, &argv, NULL);
g_type_init ();
g_test_add_func ("/ip6-config/subtract", test_subtract);
return g_test_run ();
}