Commit d16905df authored by Dan Winship's avatar Dan Winship

libnm-core, libnm, core: add AddressData and RouteData properties

Add AddressData and RouteData properties to NMSettingIPConfig and
NMIP[46]Config. These are like the existing "addresses" and "routes"
properties, but using strings and containing additional attributes,
like NMIPAddress and NMIPRoute.

This only affects the D-Bus representations; there are no API changes
to NMSettingIP{,4,6}Config or NMIP{4,6}Config as a result of this; the
additional information is just added to the existing 'addresses' and
'routes' properties.

NMSettingIP4Config and NMSettingIP6Config now always generate both
old-style data ('addresses', 'address-labels', 'routes') and new-style
data ('address-data', 'gateway', 'route-data') when serializing to
D-Bus, for backward compatibility. When deserializing, they will fill
in the 'addresses' and 'routes' properties from the new-style data if
it is present (ignoring the old-style data), or from the old-style
data if the new-style isn't present.

The daemon-side NMIP4Config and NMIP6Config always emit changes for
both 'Addresses'/'Routes' and 'AddressData'/'RouteData'. The
libnm-side classes initially listen for changes on both properties,
but start ignoring the 'Addresses' and 'Routes' properties once they
know the daemon is also providing 'AddressData' and 'RouteData'.
parent f17699f4
......@@ -37,4 +37,9 @@
#define DBUS_TYPE_G_IP6_ROUTE (dbus_g_type_get_struct ("GValueArray", DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_UINT, DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_UINT, G_TYPE_INVALID))
#define DBUS_TYPE_G_ARRAY_OF_IP6_ROUTE (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_IP6_ROUTE))
#define DBUS_TYPE_NM_IP_ADDRESS (dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_UINT, DBUS_TYPE_G_MAP_OF_STRING, G_TYPE_INVALID))
#define DBUS_TYPE_NM_IP_ADDRESSES (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_NM_IP_ADDRESS))
#define DBUS_TYPE_NM_IP_ROUTE (dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_UINT, DBUS_TYPE_G_MAP_OF_STRING, G_TYPE_INVALID))
#define DBUS_TYPE_NM_IP_ROUTES (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_NM_IP_ROUTE))
#endif /* __NM_DBUS_GLIB_TYPES_H__ */
......@@ -2,20 +2,42 @@
<node name="/" xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
<interface name="org.freedesktop.NetworkManager.IP4Config">
<property name="Addresses" type="aau" access="read">
<tp:docstring>
Array of arrays of IPv4 address/prefix/gateway. All 3
elements of each array are in network byte order. Essentially:
[(addr, prefix, gateway), (addr, prefix, gateway), ...]
Deprecated: use AddressData and Gateway
</tp:docstring>
</property>
<property name="AddressData" type="aa{sv}" access="read">
<tp:docstring>
Array of IP address data objects. All addresses will include
"address" (an IP address string), and "prefix" (a uint). Some
addresses may include additional attributes.
</tp:docstring>
</property>
<property name="Gateway" type="s" access="read">
<tp:docstring>The gateway in use.</tp:docstring>
</property>
<property name="Addresses" type="aau" access="read">
<tp:docstring>Array of tuples of IPv4 address/prefix/gateway. All 3
elements of each tuple are in network byte order. Essentially:
[(addr, prefix, gateway), (addr, prefix, gateway), ...]
<property name="Routes" type="aau" access="read">
<tp:docstring>
Arrays of IPv4 route/prefix/next-hop/metric. All 4 elements of
each tuple are in network byte order. 'route' and 'next hop'
are IPv4 addresses, while prefix and metric are simple
unsigned integers. Essentially: [(route, prefix, next-hop,
metric), (route, prefix, next-hop, metric), ...]
Deprecated: use RouteData
</tp:docstring>
</property>
<property name="Routes" type="aau" access="read">
<tp:docstring>Tuples of IPv4 route/prefix/next-hop/metric. All 4 elements
of each tuple are in network byte order. 'route' and 'next hop' are IPv4
addresses, while prefix and metric are simple unsigned integers. Essentially:
[(route, prefix, next-hop, metric), (route, prefix, next-hop, metric), ...]
<property name="RouteData" type="aa{sv}" access="read">
<tp:docstring>
Array of IP route data objects. All routes will include "dest"
(an IP address string) and "prefix" (a uint). Some routes may
include "next-hop" (an IP address string), "metric" (a uint),
and additional attributes.
</tp:docstring>
</property>
<property name="Nameservers" type="au" access="read">
......
......@@ -2,14 +2,37 @@
<node name="/" xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
<interface name="org.freedesktop.NetworkManager.IP6Config">
<property name="Addresses" type="a(ayuay)" access="read">
<tp:docstring>
Array of tuples of IPv6 address/prefix/gateway.
Deprecated: use AddressData and Gateway.
</tp:docstring>
</property>
<property name="AddressData" type="aa{sv}" access="read">
<tp:docstring>
Array of IP address data objects. All addresses will include
"address" (an IP address string), and "prefix" (a uint). Some
addresses may include additional attributes.
</tp:docstring>
</property>
<property name="Gateway" type="s" access="read">
<tp:docstring>The gateway in use.</tp:docstring>
</property>
<property name="Addresses" type="a(ayuay)" access="read">
<tp:docstring>Tuples of IPv6 address/prefix/gateway.</tp:docstring>
</property>
<property name="Routes" type="a(ayuayu)" access="read">
<tp:docstring>Tuples of IPv6 route/prefix/next-hop/metric.</tp:docstring>
<tp:docstring>
Tuples of IPv6 route/prefix/next-hop/metric.
Deprecated: use RouteData
</tp:docstring>
</property>
<property name="RouteData" type="aa{sv}" access="read">
<tp:docstring>
Array of IP route data objects. All routes will include "dest"
(an IP address string) and "prefix" (a uint). Some routes may
include "next-hop" (an IP address string), "metric" (a uint),
and additional attributes.
</tp:docstring>
</property>
<property name="Nameservers" type="aay" access="read">
<tp:docstring>The nameservers in use.</tp:docstring>
......
......@@ -472,6 +472,7 @@ nm_ip_address_set_attribute (NMIPAddress *address, const char *name, GVariant *v
{
g_return_if_fail (address != NULL);
g_return_if_fail (name != NULL && *name != '\0');
g_return_if_fail (strcmp (name, "address") != 0 && strcmp (name, "prefix") != 0);
if (!address->attributes) {
address->attributes = g_hash_table_new_full (g_str_hash, g_str_equal,
......@@ -1009,6 +1010,8 @@ nm_ip_route_set_attribute (NMIPRoute *route, const char *name, GVariant *value)
{
g_return_if_fail (route != NULL);
g_return_if_fail (name != NULL && *name != '\0');
g_return_if_fail ( strcmp (name, "dest") != 0 && strcmp (name, "prefix") != 0
&& strcmp (name, "next-hop") != 0 && strcmp (name, "metric") != 0);
if (!route->attributes) {
route->attributes = g_hash_table_new_full (g_str_hash, g_str_equal,
......
......@@ -269,9 +269,14 @@ ip4_addresses_set (NMSetting *setting,
char **labels, *gateway = NULL;
int i;
addrs = nm_utils_ip4_addresses_from_variant (value, &gateway);
s_ip4 = g_variant_lookup_value (connection_dict, NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_VARIANT_TYPE_SETTING);
/* If 'address-data' is set then ignore 'addresses' */
if (g_variant_lookup (s_ip4, "address-data", "aa{sv}", NULL)) {
g_variant_unref (s_ip4);
return;
}
addrs = nm_utils_ip4_addresses_from_variant (value, &gateway);
if (g_variant_lookup (s_ip4, "address-labels", "^as", &labels)) {
for (i = 0; i < addrs->len && labels[i]; i++)
......@@ -319,16 +324,95 @@ ip4_address_labels_get (NMSetting *setting,
}
static GVariant *
ip4_routes_to_dbus (const GValue *prop_value)
ip4_address_data_get (NMSetting *setting,
NMConnection *connection,
const char *property)
{
GPtrArray *addrs;
GVariant *ret;
g_object_get (setting, NM_SETTING_IP_CONFIG_ADDRESSES, &addrs, NULL);
ret = nm_utils_ip_addresses_to_variant (addrs);
g_ptr_array_unref (addrs);
return ret;
}
static void
ip4_address_data_set (NMSetting *setting,
GVariant *connection_dict,
const char *property,
GVariant *value)
{
GPtrArray *addrs;
addrs = nm_utils_ip_addresses_from_variant (value, AF_INET);
g_object_set (setting, NM_SETTING_IP_CONFIG_ADDRESSES, addrs, NULL);
g_ptr_array_unref (addrs);
}
static GVariant *
ip4_routes_get (NMSetting *setting,
const char *property)
{
GPtrArray *routes;
GVariant *ret;
g_object_get (setting, property, &routes, NULL);
ret = nm_utils_ip4_routes_to_variant (routes);
g_ptr_array_unref (routes);
return ret;
}
static void
ip4_routes_set (NMSetting *setting,
GVariant *connection_dict,
const char *property,
GVariant *value)
{
GPtrArray *routes;
GVariant *s_ip4;
s_ip4 = g_variant_lookup_value (connection_dict, NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_VARIANT_TYPE_SETTING);
/* If 'route-data' is set then ignore 'routes' */
if (g_variant_lookup (s_ip4, "route-data", "aa{sv}", NULL)) {
g_variant_unref (s_ip4);
return;
}
g_variant_unref (s_ip4);
routes = nm_utils_ip4_routes_from_variant (value);
g_object_set (setting, property, routes, NULL);
g_ptr_array_unref (routes);
}
static GVariant *
ip4_route_data_get (NMSetting *setting,
NMConnection *connection,
const char *property)
{
return nm_utils_ip4_routes_to_variant (g_value_get_boxed (prop_value));
GPtrArray *routes;
GVariant *ret;
g_object_get (setting, NM_SETTING_IP_CONFIG_ROUTES, &routes, NULL);
ret = nm_utils_ip_routes_to_variant (routes);
g_ptr_array_unref (routes);
return ret;
}
static void
ip4_routes_from_dbus (GVariant *dbus_value,
GValue *prop_value)
ip4_route_data_set (NMSetting *setting,
GVariant *connection_dict,
const char *property,
GVariant *value)
{
g_value_take_boxed (prop_value, nm_utils_ip4_routes_from_variant (dbus_value));
GPtrArray *routes;
routes = nm_utils_ip_routes_from_variant (value, AF_INET);
g_object_set (setting, NM_SETTING_IP_CONFIG_ROUTES, routes, NULL);
g_ptr_array_unref (routes);
}
......@@ -381,9 +465,23 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *ip4_class)
ip4_address_labels_get,
NULL);
_nm_setting_class_transform_property (setting_class,
NM_SETTING_IP_CONFIG_ROUTES,
G_VARIANT_TYPE ("aau"),
ip4_routes_to_dbus,
ip4_routes_from_dbus);
_nm_setting_class_add_dbus_only_property (setting_class,
"address-data",
G_VARIANT_TYPE ("aa{sv}"),
ip4_address_data_get,
ip4_address_data_set);
_nm_setting_class_override_property (setting_class,
NM_SETTING_IP_CONFIG_ROUTES,
G_VARIANT_TYPE ("aau"),
ip4_routes_get,
ip4_routes_set,
NULL);
_nm_setting_class_add_dbus_only_property (setting_class,
"route-data",
G_VARIANT_TYPE ("aa{sv}"),
ip4_route_data_get,
ip4_route_data_set);
}
......@@ -214,9 +214,14 @@ ip6_addresses_set (NMSetting *setting,
GVariant *s_ip6;
char *gateway = NULL;
addrs = nm_utils_ip6_addresses_from_variant (value, &gateway);
s_ip6 = g_variant_lookup_value (connection_dict, NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_VARIANT_TYPE_SETTING);
/* If 'address-data' is set then ignore 'addresses' */
if (g_variant_lookup (s_ip6, "address-data", "aa{sv}", NULL)) {
g_variant_unref (s_ip6);
return;
}
addrs = nm_utils_ip6_addresses_from_variant (value, &gateway);
if (gateway && !g_variant_lookup (s_ip6, "gateway", "s", NULL)) {
g_object_set (setting,
......@@ -232,16 +237,95 @@ ip6_addresses_set (NMSetting *setting,
}
static GVariant *
ip6_routes_to_dbus (const GValue *prop_value)
ip6_address_data_get (NMSetting *setting,
NMConnection *connection,
const char *property)
{
GPtrArray *addrs;
GVariant *ret;
g_object_get (setting, NM_SETTING_IP_CONFIG_ADDRESSES, &addrs, NULL);
ret = nm_utils_ip_addresses_to_variant (addrs);
g_ptr_array_unref (addrs);
return ret;
}
static void
ip6_address_data_set (NMSetting *setting,
GVariant *connection_dict,
const char *property,
GVariant *value)
{
GPtrArray *addrs;
addrs = nm_utils_ip_addresses_from_variant (value, AF_INET6);
g_object_set (setting, NM_SETTING_IP_CONFIG_ADDRESSES, addrs, NULL);
g_ptr_array_unref (addrs);
}
static GVariant *
ip6_routes_get (NMSetting *setting,
const char *property)
{
GPtrArray *routes;
GVariant *ret;
g_object_get (setting, property, &routes, NULL);
ret = nm_utils_ip6_routes_to_variant (routes);
g_ptr_array_unref (routes);
return ret;
}
static void
ip6_routes_set (NMSetting *setting,
GVariant *connection_dict,
const char *property,
GVariant *value)
{
GPtrArray *routes;
GVariant *s_ip6;
s_ip6 = g_variant_lookup_value (connection_dict, NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_VARIANT_TYPE_SETTING);
/* If 'route-data' is set then ignore 'routes' */
if (g_variant_lookup (s_ip6, "route-data", "aa{sv}", NULL)) {
g_variant_unref (s_ip6);
return;
}
g_variant_unref (s_ip6);
routes = nm_utils_ip6_routes_from_variant (value);
g_object_set (setting, property, routes, NULL);
g_ptr_array_unref (routes);
}
static GVariant *
ip6_route_data_get (NMSetting *setting,
NMConnection *connection,
const char *property)
{
return nm_utils_ip6_routes_to_variant (g_value_get_boxed (prop_value));
GPtrArray *routes;
GVariant *ret;
g_object_get (setting, NM_SETTING_IP_CONFIG_ROUTES, &routes, NULL);
ret = nm_utils_ip_routes_to_variant (routes);
g_ptr_array_unref (routes);
return ret;
}
static void
ip6_routes_from_dbus (GVariant *dbus_value,
GValue *prop_value)
ip6_route_data_set (NMSetting *setting,
GVariant *connection_dict,
const char *property,
GVariant *value)
{
g_value_take_boxed (prop_value, nm_utils_ip6_routes_from_variant (dbus_value));
GPtrArray *routes;
routes = nm_utils_ip_routes_from_variant (value, AF_INET6);
g_object_set (setting, NM_SETTING_IP_CONFIG_ROUTES, routes, NULL);
g_ptr_array_unref (routes);
}
static void
......@@ -324,9 +408,22 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *ip6_class)
ip6_addresses_set,
NULL);
_nm_setting_class_transform_property (setting_class,
NM_SETTING_IP_CONFIG_ROUTES,
G_VARIANT_TYPE ("a(ayuayu)"),
ip6_routes_to_dbus,
ip6_routes_from_dbus);
_nm_setting_class_add_dbus_only_property (setting_class,
"address-data",
G_VARIANT_TYPE ("aa{sv}"),
ip6_address_data_get,
ip6_address_data_set);
_nm_setting_class_override_property (setting_class,
NM_SETTING_IP_CONFIG_ROUTES,
G_VARIANT_TYPE ("a(ayuayu)"),
ip6_routes_get,
ip6_routes_set,
NULL);
_nm_setting_class_add_dbus_only_property (setting_class,
"route-data",
G_VARIANT_TYPE ("aa{sv}"),
ip6_route_data_get,
ip6_route_data_set);
}
......@@ -1711,6 +1711,245 @@ nm_utils_ip6_routes_from_variant (GVariant *value)
return routes;
}
/**
* nm_utils_ip_addresses_to_variant:
* @addresses: (element-type NMIPAddress): an array of #NMIPAddress objects
*
* Utility function to convert a #GPtrArray of #NMIPAddress objects representing
* IPv4 or IPv6 addresses into a #GVariant of type 'aa{sv}' representing an
* array of new-style NetworkManager IP addresses. All addresses will include
* "address" (an IP address string), and "prefix" (a uint). Some addresses may
* include additional attributes.
*
* Returns: (transfer none): a new floating #GVariant representing @addresses.
**/
GVariant *
nm_utils_ip_addresses_to_variant (GPtrArray *addresses)
{
GVariantBuilder builder;
int i;
g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
if (addresses) {
for (i = 0; i < addresses->len; i++) {
NMIPAddress *addr = addresses->pdata[i];
GVariantBuilder addr_builder;
char **names;
int n;
g_variant_builder_init (&addr_builder, G_VARIANT_TYPE ("a{sv}"));
g_variant_builder_add (&addr_builder, "{sv}",
"address",
g_variant_new_string (nm_ip_address_get_address (addr)));
g_variant_builder_add (&addr_builder, "{sv}",
"prefix",
g_variant_new_uint32 (nm_ip_address_get_prefix (addr)));
names = nm_ip_address_get_attribute_names (addr);
for (n = 0; names[n]; n++) {
g_variant_builder_add (&addr_builder, "{sv}",
names[n],
nm_ip_address_get_attribute (addr, names[n]));
}
g_strfreev (names);
g_variant_builder_add (&builder, "a{sv}", &addr_builder);
}
}
return g_variant_builder_end (&builder);
}
/**
* nm_utils_ip_addresses_from_variant:
* @value: a #GVariant of type 'aa{sv}'
* @family: an IP address family
*
* Utility function to convert a #GVariant representing a list of new-style
* NetworkManager IPv4 or IPv6 addresses (as described in the documentation for
* nm_utils_ip_addresses_to_variant()) into a #GPtrArray of #NMIPAddress
* objects.
*
* Returns: (transfer full) (element-type NMIPAddress): a newly allocated
* #GPtrArray of #NMIPAddress objects
**/
GPtrArray *
nm_utils_ip_addresses_from_variant (GVariant *value,
int family)
{
GPtrArray *addresses;
GVariantIter iter, attrs_iter;
GVariant *addr_var;
const char *ip;
guint32 prefix;
const char *attr_name;
GVariant *attr_val;
NMIPAddress *addr;
GError *error = NULL;
g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("aa{sv}")), NULL);
g_variant_iter_init (&iter, value);
addresses = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_address_unref);
while (g_variant_iter_next (&iter, "@a{sv}", &addr_var)) {
if ( !g_variant_lookup (addr_var, "address", "&s", &ip)
|| !g_variant_lookup (addr_var, "prefix", "u", &prefix)) {
g_warning ("Ignoring invalid address");
g_variant_unref (addr_var);
continue;
}
addr = nm_ip_address_new (family, ip, prefix, &error);
if (!addr) {
g_warning ("Ignoring invalid address: %s", error->message);
g_clear_error (&error);
g_variant_unref (addr_var);
continue;
}
g_variant_iter_init (&attrs_iter, addr_var);
while (g_variant_iter_next (&attrs_iter, "{&sv}", &attr_name, &attr_val)) {
if ( strcmp (attr_name, "address") != 0
&& strcmp (attr_name, "prefix") != 0)
nm_ip_address_set_attribute (addr, attr_name, attr_val);
g_variant_unref (attr_val);
}
g_ptr_array_add (addresses, addr);
}
return addresses;
}
/**
* nm_utils_ip_routes_to_variant:
* @routes: (element-type NMIPRoute): an array of #NMIPRoute objects
*
* Utility function to convert a #GPtrArray of #NMIPRoute objects representing
* IPv4 or IPv6 routes into a #GVariant of type 'aa{sv}' representing an array
* of new-style NetworkManager IP routes (which are tuples of destination,
* prefix, next hop, metric, and additional attributes).
*
* Returns: (transfer none): a new floating #GVariant representing @routes.
**/
GVariant *
nm_utils_ip_routes_to_variant (GPtrArray *routes)
{
GVariantBuilder builder;
int i;
g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
if (routes) {
for (i = 0; i < routes->len; i++) {
NMIPRoute *route = routes->pdata[i];
GVariantBuilder route_builder;
char **names;
int n;
g_variant_builder_init (&route_builder, G_VARIANT_TYPE ("a{sv}"));
g_variant_builder_add (&route_builder, "{sv}",
"dest",
g_variant_new_string (nm_ip_route_get_dest (route)));
g_variant_builder_add (&route_builder, "{sv}",
"prefix",
g_variant_new_uint32 (nm_ip_route_get_prefix (route)));
if (nm_ip_route_get_next_hop (route)) {
g_variant_builder_add (&route_builder, "{sv}",
"next-hop",
g_variant_new_string (nm_ip_route_get_next_hop (route)));
}
if (nm_ip_route_get_metric (route)) {
g_variant_builder_add (&route_builder, "{sv}",
"metric",
g_variant_new_uint32 (nm_ip_route_get_metric (route)));
}
names = nm_ip_route_get_attribute_names (route);
for (n = 0; names[n]; n++) {
g_variant_builder_add (&route_builder, "{sv}",
names[n],
nm_ip_route_get_attribute (route, names[n]));
}
g_strfreev (names);
g_variant_builder_add (&builder, "a{sv}", &route_builder);
}
}
return g_variant_builder_end (&builder);
}
/**
* nm_utils_ip_routes_from_variant:
* @value: a #GVariant of type 'aa{sv}'
* @family: an IP address family
*
* Utility function to convert a #GVariant representing a list of new-style
* NetworkManager IPv4 or IPv6 addresses (which are tuples of destination,
* prefix, next hop, metric, and additional attributes) into a #GPtrArray of
* #NMIPRoute objects.
*
* Returns: (transfer full) (element-type NMIPRoute): a newly allocated
* #GPtrArray of #NMIPRoute objects
**/
GPtrArray *
nm_utils_ip_routes_from_variant (GVariant *value,
int family)
{
GPtrArray *routes;
GVariantIter iter, attrs_iter;
GVariant *route_var;
const char *dest, *next_hop;
guint32 prefix, metric;
const char *attr_name;
GVariant *attr_val;
NMIPRoute *route;
GError *error = NULL;
g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("aa{sv}")), NULL);
g_variant_iter_init (&iter, value);
routes = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_route_unref);
while (g_variant_iter_next (&iter, "@a{sv}", &route_var)) {
if ( !g_variant_lookup (route_var, "dest", "&s", &dest)
|| !g_variant_lookup (route_var, "prefix", "u", &prefix)) {
g_warning ("Ignoring invalid address");
g_variant_unref (route_var);
continue;
}
if (!g_variant_lookup (route_var, "next-hop", "&s", &next_hop))
next_hop = NULL;
if (!g_variant_lookup (route_var, "metric", "u", &metric))
metric = 0;
route = nm_ip_route_new (family, dest, prefix, next_hop, metric, &error);
if (!route) {
g_warning ("Ignoring invalid route: %s", error->message);
g_clear_error (&error);
g_variant_unref (route_var);
continue;
}
g_variant_iter_init (&attrs_iter, route_var);
while (g_variant_iter_next (&attrs_iter, "{&sv}", &attr_name, &attr_val)) {
if ( strcmp (attr_name, "dest") != 0
&& strcmp (attr_name, "prefix") != 0
&& strcmp (attr_name, "next-hop") != 0
&& strcmp (attr_name, "metric") != 0)
nm_ip_route_set_attribute (route, attr_name, attr_val);
g_variant_unref (attr_val);
}
g_ptr_array_add (routes, route);
}
return routes;
}
/**
* nm_utils_uuid_generate:
*
......
......@@ -117,6 +117,13 @@ GPtrArray *nm_utils_ip6_addresses_from_variant (GVariant *value,
GVariant *nm_utils_ip6_routes_to_variant (GPtrArray *routes);
GPtrArray *nm_utils_ip6_routes_from_variant (GVariant *value);
GVariant *nm_utils_ip_addresses_to_variant (GPtrArray *addresses);
GPtrArray *nm_utils_ip_addresses_from_variant (GVariant *value,
int family);
GVariant *nm_utils_ip_routes_to_variant (GPtrArray *routes);
GPtrArray *nm_utils_ip_routes_from_variant (GVariant *value,
int family);
char *nm_utils_uuid_generate (void);
char *nm_utils_uuid_generate_from_string (const char *s);
......
......@@ -329,7 +329,7 @@ test_setting_ip4_config_labels (void)
GPtrArray *addrs;
char **labels;
NMConnection *conn;
GVariant *dict, *setting_dict, *value;
GVariant *dict, *dict2, *setting_dict, *value;
GError *error = NULL;
s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new ();
......@@ -395,7 +395,9 @@ test_setting_ip4_config_labels (void)
label = nm_ip_address_get_attribute (addr, "label");
g_assert (label == NULL);
/* The labels should appear in the D-Bus serialization */
/* The labels should appear in the D-Bus serialization under both
* 'address-labels' and 'address-data'.
*/
conn = nmtst_create_minimal_connection ("label test", NULL, NM_SETTING_WIRED_SETTING_NAME, NULL);
nm_connection_add_setting (conn, NM_SETTING (s_ip4));
dict = nm_connection_to_dbus (conn, NM_CONNECTION_SERIALIZE_ALL);
......@@ -403,19 +405,41 @@ test_setting_ip4_config_labels (void)
setting_dict = g_variant_lookup_value (dict, NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_VARIANT_TYPE_SETTING);
g_assert (setting_dict != NULL);
value = g_variant_lookup_value (setting_dict, "address-labels", G_VARIANT_TYPE_STRING_ARRAY);
g_assert (value != NULL);
g_variant_get (value, "^as", &labels);
g_assert_cmpint (g_strv_length (labels), ==, 2);
g_assert_cmpstr (labels[0], ==, "eth0:1");
g_assert_cmpstr (labels[1], ==, "");
g_variant_unref (setting_dict);
g_variant_unref (value);
g_strfreev (labels);
/* And should be deserialized */
value = g_variant_lookup_value (setting_dict, "address-data", G_VARIANT_TYPE ("aa{sv}"));
addrs = nm_utils_ip_addresses_from_variant (value, AF_INET);
g_variant_unref (value);
g_assert (addrs != NULL);
g_assert_cmpint (addrs->len, ==, 2);
addr = addrs->pdata[0];
label = nm_ip_address_get_attribute (addr, "label");
g_assert (label != NULL);
g_assert_cmpstr (g_variant_get_string (label, NULL), ==, "eth0:1");
addr = addrs->pdata[1];
label = nm_ip_address_get_attribute (addr, "label");
g_assert (label == NULL);