merge: branch 'bg/route-options-rh1373698'

https://bugzilla.redhat.com/show_bug.cgi?id=1373698
This commit is contained in:
Beniamino Galvani 2017-03-06 15:20:44 +01:00
commit 468127ca69
36 changed files with 1819 additions and 394 deletions

View file

@ -395,26 +395,20 @@ finish:
/*
* nmc_parse_and_build_route:
* @family: AF_INET or AF_INET6
* @first: the route destination in the form of "address/prefix"
(/prefix is optional)
* @second: (allow-none): next hop address, if third is not NULL. Otherwise it could be
either next hop address or metric. (It can be NULL when @third is NULL).
* @third: (allow-none): route metric
* @str: route string to be parsed
* @error: location to store GError
*
* Parse route from strings and return an #NMIPRoute
* Parse route from string and return an #NMIPRoute
*
* Returns: %TRUE on success, %FALSE on failure
* Returns: a new #NMIPRoute or %NULL on error
*/
NMIPRoute *
nmc_parse_and_build_route (int family,
const char *first,
const char *second,
const char *third,
const char *str,
GError **error)
{
int max_prefix = (family == AF_INET) ? 32 : 128;
char *dest = NULL, *plen = NULL;
char *plen = NULL;
const char *next_hop = NULL;
const char *canon_dest;
long int prefix = max_prefix;
@ -423,13 +417,27 @@ nmc_parse_and_build_route (int family,
gboolean success = FALSE;
GError *local = NULL;
gint64 metric = -1;
guint i, len;
gs_strfreev char **routev = NULL;
gs_free char *value = NULL;
gs_free char *dest = NULL;
gs_unref_hashtable GHashTable *attrs = NULL;
GHashTable *tmp_attrs;
g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE);
g_return_val_if_fail (first != NULL, FALSE);
g_return_val_if_fail (second || !third, FALSE);
g_return_val_if_fail (str, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
dest = g_strdup (first);
value = g_strdup (str);
routev = nmc_strsplit_set (g_strstrip (value), " \t", 0);
len = g_strv_length (routev);
if (len < 1) {
g_set_error (error, 1, 0, _("'%s' is not valid (the format is: ip[/prefix] [next-hop] [metric] [attr=val] [attr=val])"),
str);
goto finish;
}
dest = g_strdup (routev[0]);
plen = strchr (dest, '/'); /* prefix delimiter */
if (plen)
*plen++ = '\0';
@ -443,26 +451,50 @@ nmc_parse_and_build_route (int family,
}
}
if (second) {
if (third || nm_utils_ipaddr_valid (family, second))
next_hop = second;
else {
/* 'second' can be a metric */
if (!nmc_string_to_uint (second, TRUE, 0, G_MAXUINT32, &tmp_ulong)) {
g_set_error (error, 1, 0, _("the second component of route ('%s') is neither "
"a next hop address nor a metric"), second);
for (i = 1; i < len; i++) {
if (nm_utils_ipaddr_valid (family, routev[i])) {
if (metric != -1 || attrs) {
g_set_error (error, 1, 0, _("the next hop ('%s') must be first"), routev[i]);
goto finish;
}
next_hop = routev[i];
} else if (nmc_string_to_uint (routev[i], TRUE, 0, G_MAXUINT32, &tmp_ulong)) {
if (attrs) {
g_set_error (error, 1, 0, _("the metric ('%s') must be before attributes"), routev[i]);
goto finish;
}
metric = tmp_ulong;
}
}
} else if (strchr (routev[i], '=')) {
GHashTableIter iter;
char *iter_key;
GVariant *iter_value;
if (third) {
if (!nmc_string_to_uint (third, TRUE, 0, G_MAXUINT32, &tmp_ulong)) {
g_set_error (error, 1, 0, _("invalid metric '%s'"), third);
tmp_attrs = nm_utils_parse_variant_attributes (routev[i], ' ', '=', FALSE,
nm_ip_route_get_variant_attribute_spec(),
error);
if (!tmp_attrs) {
g_prefix_error (error, "invalid option '%s': ", routev[i]);
goto finish;
}
if (!attrs)
attrs = g_hash_table_new (g_str_hash, g_str_equal);
g_hash_table_iter_init (&iter, tmp_attrs);
while (g_hash_table_iter_next (&iter, (gpointer *) &iter_key, (gpointer *) &iter_value)) {
if (!nm_ip_route_attribute_validate (iter_key, iter_value, family, NULL, error)) {
g_prefix_error (error, "%s: ", iter_key);
g_hash_table_unref (tmp_attrs);
goto finish;
}
g_hash_table_insert (attrs, iter_key, iter_value);
g_hash_table_iter_steal (&iter);
}
g_hash_table_unref (tmp_attrs);
} else {
g_set_error (error, 1, 0, _("unrecognized option '%s'"), routev[i]);
goto finish;
}
metric = tmp_ulong;
}
route = nm_ip_route_new (family, dest, prefix, next_hop, metric, &local);
@ -485,10 +517,19 @@ nmc_parse_and_build_route (int family,
goto finish;
}
if (attrs) {
GHashTableIter iter;
char *name;
GVariant *variant;
g_hash_table_iter_init (&iter, attrs);
while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &variant))
nm_ip_route_set_attribute (route, name, variant);
}
success = TRUE;
finish:
g_free (dest);
return route;
}

View file

@ -31,7 +31,7 @@ gboolean print_dhcp4_config (NMDhcpConfig *dhcp4, NmCli *nmc, const char *group_
gboolean print_dhcp6_config (NMDhcpConfig *dhcp6, NmCli *nmc, const char *group_prefix, const char *one_field);
NMIPAddress *nmc_parse_and_build_address (int family, const char *ip_str, GError **error);
NMIPRoute *nmc_parse_and_build_route (int family, const char *first, const char *second, const char *third, GError **error);
NMIPRoute *nmc_parse_and_build_route (int family, const char *str, GError **error);
const char * nmc_device_state_to_string (NMDeviceState state);
const char * nmc_device_reason_to_string (NMDeviceStateReason reason);

View file

@ -3470,29 +3470,6 @@ _parse_ip_address (int family, const char *address, GError **error)
return ipaddr;
}
static NMIPRoute *
_parse_ip_route (int family, const char *route, GError **error)
{
char *value = g_strdup (route);
char **routev;
guint len;
NMIPRoute *iproute = NULL;
routev = nmc_strsplit_set (g_strstrip (value), " \t", 0);
len = g_strv_length (routev);
if (len < 1 || len > 3) {
g_set_error (error, 1, 0, _("'%s' is not valid (the format is: ip[/prefix] [next-hop] [metric])"),
route);
goto finish;
}
iproute = nmc_parse_and_build_route (family, routev[0], routev[1], len >= 2 ? routev[2] : NULL, error);
finish:
g_free (value);
g_strfreev (routev);
return iproute;
}
DEFINE_GETTER (nmc_property_ipv4_get_method, NM_SETTING_IP_CONFIG_METHOD)
DEFINE_GETTER (nmc_property_ipv4_get_dns, NM_SETTING_IP_CONFIG_DNS)
DEFINE_GETTER (nmc_property_ipv4_get_dns_search, NM_SETTING_IP_CONFIG_DNS_SEARCH)
@ -3536,8 +3513,21 @@ nmc_property_ipvx_get_routes (NMSetting *setting, NmcPropertyGetType get_type)
num_routes = nm_setting_ip_config_get_num_routes (s_ip);
for (i = 0; i < num_routes; i++) {
gs_free char *attr_str = NULL;
gs_strfreev char **attr_names = NULL;
gs_unref_hashtable GHashTable *hash = g_hash_table_new (g_str_hash, g_str_equal);
int j;
route = nm_setting_ip_config_get_route (s_ip, i);
attr_names = nm_ip_route_get_attribute_names (route);
for (j = 0; attr_names && attr_names[j]; j++) {
g_hash_table_insert (hash, attr_names[j],
nm_ip_route_get_attribute (route, attr_names[j]));
}
attr_str = nm_utils_format_variant_attributes (hash, ' ', '=');
if (get_type == NMC_PROPERTY_GET_PARSABLE) {
if (printable->len > 0)
g_string_append (printable, ", ");
@ -3550,7 +3540,10 @@ nmc_property_ipvx_get_routes (NMSetting *setting, NmcPropertyGetType get_type)
g_string_append_printf (printable, " %s", nm_ip_route_get_next_hop (route));
if (nm_ip_route_get_metric (route) != -1)
g_string_append_printf (printable, " %u", (guint32) nm_ip_route_get_metric (route));
if (attr_str)
g_string_append_printf (printable, " %s", attr_str);
} else {
if (printable->len > 0)
g_string_append (printable, "; ");
@ -3567,6 +3560,8 @@ nmc_property_ipvx_get_routes (NMSetting *setting, NmcPropertyGetType get_type)
if (nm_ip_route_get_metric (route) != -1)
g_string_append_printf (printable, ", mt = %u", (guint32) nm_ip_route_get_metric (route));
if (attr_str)
g_string_append_printf (printable, " %s", attr_str);
g_string_append (printable, " }");
}
@ -3858,7 +3853,7 @@ nmc_property_ipv4_set_gateway (NMSetting *setting, const char *prop, const char
static NMIPRoute *
_parse_ipv4_route (const char *route, GError **error)
{
return _parse_ip_route (AF_INET, route, error);
return nmc_parse_and_build_route (AF_INET, route, error);
}
static gboolean
@ -4201,7 +4196,7 @@ nmc_property_ipv6_set_gateway (NMSetting *setting, const char *prop, const char
static NMIPRoute *
_parse_ipv6_route (const char *route, GError **error)
{
return _parse_ip_route (AF_INET6, route, error);
return nmc_parse_and_build_route (AF_INET6, route, error);
}
static gboolean

View file

@ -428,6 +428,31 @@ read_one_ip_address_or_route (KeyfileReaderInfo *info,
return result;
}
static void
fill_route_attributes (GKeyFile *kf, NMIPRoute *route, const char *setting, const char *key, int family)
{
gs_free char *value = NULL;
gs_unref_hashtable GHashTable *hash = NULL;
GHashTableIter iter;
char *name;
GVariant *variant;
value = nm_keyfile_plugin_kf_get_string (kf, setting, key, NULL);
if (!value || !value[0])
return;
hash = nm_utils_parse_variant_attributes (value, ',', '=', TRUE,
nm_ip_route_get_variant_attribute_spec (),
NULL);
if (hash) {
g_hash_table_iter_init (&iter, hash);
while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &variant)) {
if (nm_ip_route_attribute_validate (name, variant, family, NULL, NULL))
nm_ip_route_set_attribute (route, name, g_variant_ref (variant));
}
}
}
static void
ip_address_or_route_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
{
@ -454,6 +479,7 @@ ip_address_or_route_parser (KeyfileReaderInfo *info, NMSetting *setting, const c
for (key_basename = key_names; *key_basename; key_basename++) {
char *key_name;
gpointer item;
char options_key[128];
/* -1 means no suffix */
if (i >= 0)
@ -463,6 +489,11 @@ ip_address_or_route_parser (KeyfileReaderInfo *info, NMSetting *setting, const c
item = read_one_ip_address_or_route (info, key, setting_name, key_name, ipv6, routes,
gateway ? NULL : &gateway, setting);
if (item && routes) {
nm_sprintf_buf (options_key, "%s_options", key_name);
fill_route_attributes (info->keyfile, item, setting_name, options_key, ipv6 ? AF_INET6 : AF_INET);
}
g_free (key_name);
if (info->error) {

View file

@ -138,7 +138,7 @@ write_ip_values (GKeyFile *file,
int family, i;
const char *addr, *gw;
guint32 plen, metric;
char key_name[30], *key_name_idx;
char key_name[64], *key_name_idx;
if (!array->len)
return;
@ -188,6 +188,23 @@ write_ip_values (GKeyFile *file,
sprintf (key_name_idx, "%d", i + 1);
nm_keyfile_plugin_kf_set_string (file, setting_name, key_name, output->str);
if (is_route) {
gs_free char *attributes = NULL;
gs_strfreev char **names = NULL;
gs_unref_hashtable GHashTable *hash = g_hash_table_new (g_str_hash, g_str_equal);
int j;
names = nm_ip_route_get_attribute_names (array->pdata[i]);
for (j = 0; names && names[j]; j++)
g_hash_table_insert (hash, names[j], nm_ip_route_get_attribute (array->pdata[i], names[j]));
attributes = nm_utils_format_variant_attributes (hash, ',', '=');
if (attributes) {
g_strlcat (key_name, "_options", sizeof (key_name));
nm_keyfile_plugin_kf_set_string (file, setting_name, key_name, attributes);
}
}
}
g_string_free (output, TRUE);
}

View file

@ -1182,6 +1182,157 @@ nm_ip_route_set_attribute (NMIPRoute *route, const char *name, GVariant *value)
g_hash_table_remove (route->attributes, name);
}
#define ATTR_SPEC_PTR(name, type, v4, v6, str_type) \
&(NMVariantAttributeSpec) { name, type, v4, v6, str_type }
static const NMVariantAttributeSpec * const ip_route_attribute_spec[] = {
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_PREF_SRC, G_VARIANT_TYPE_STRING, TRUE, TRUE, 'a'),
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_SRC, G_VARIANT_TYPE_STRING, FALSE, TRUE, 'p'),
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_TOS, G_VARIANT_TYPE_BYTE, TRUE, TRUE, 0 ),
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_WINDOW, G_VARIANT_TYPE_UINT32, TRUE, TRUE, 0 ),
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_CWND, G_VARIANT_TYPE_UINT32, TRUE, TRUE, 0 ),
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_INITCWND, G_VARIANT_TYPE_UINT32, TRUE, TRUE, 0 ),
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_INITRWND, G_VARIANT_TYPE_UINT32, TRUE, TRUE, 0 ),
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_MTU, G_VARIANT_TYPE_UINT32, TRUE, TRUE, 0 ),
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW, G_VARIANT_TYPE_BOOLEAN, TRUE, TRUE, 0 ),
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, G_VARIANT_TYPE_BOOLEAN, TRUE, TRUE, 0 ),
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, G_VARIANT_TYPE_BOOLEAN, TRUE, TRUE, 0 ),
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITRWND, G_VARIANT_TYPE_BOOLEAN, TRUE, TRUE, 0 ),
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, G_VARIANT_TYPE_BOOLEAN, TRUE, TRUE, 0 ),
NULL,
};
/**
* nm_ip_route_get_variant_attribute_spec:
*
* Returns: the specifiers for route attributes
*
* Since: 1.8
*/
const NMVariantAttributeSpec *const *
nm_ip_route_get_variant_attribute_spec (void)
{
return ip_route_attribute_spec;
}
/**
* nm_ip_route_attribute_validate:
* @name: the attribute name
* @value: the attribute value
* @family: IP address family of the route
* @known: (out): on return, whether the attribute name is a known one
* @error: (allow-none): return location for a #GError, or %NULL
*
* Validates a route attribute, i.e. checks that the attribute is a known one
* and the value is of the correct type and well-formed.
*
* Returns: %TRUE if the attribute is valid, %FALSE otherwise
*
* Since: 1.8
*/
gboolean
nm_ip_route_attribute_validate (const char *name,
GVariant *value,
int family,
gboolean *known,
GError **error)
{
const NMVariantAttributeSpec *const *iter;
const NMVariantAttributeSpec *spec = NULL;
g_return_val_if_fail (name, FALSE);
g_return_val_if_fail (value, FALSE);
g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE);
g_return_val_if_fail (!error || !*error, FALSE);
for (iter = ip_route_attribute_spec; *iter; iter++) {
if (nm_streq (name, (*iter)->name)) {
spec = *iter;
break;
}
}
if (!spec) {
NM_SET_OUT (known, FALSE);
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_FAILED,
_("unknown attribute"));
return FALSE;
}
NM_SET_OUT (known, TRUE);
if (!g_variant_is_of_type (value, spec->type)) {
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_FAILED,
_("invalid attribute type'%s'"),
g_variant_get_type_string (value));
return FALSE;
}
if ( (family == AF_INET && !spec->v4)
|| (family == AF_INET6 && !spec->v6)) {
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_FAILED,
family == AF_INET ?
_("attribute is not valid for a IPv4 route") :
_("attribute is not valid for a IPv6 route"));
return FALSE;
}
if (spec->type == G_VARIANT_TYPE_STRING) {
const char *string = g_variant_get_string (value, NULL);
gs_free char *string_free = NULL;
char *sep;
switch (spec->str_type) {
case 'a': /* IP address */
if (!nm_utils_ipaddr_valid (family, string)) {
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_FAILED,
family == AF_INET ?
_("'%s' is not a valid IPv4 address") :
_("'%s' is not a valid IPv6 address"),
string);
return FALSE;
}
break;
case 'p': /* IP address + optional prefix */
string_free = g_strdup (string);
sep = strchr (string_free, '/');
if (sep) {
*sep = 0;
if (_nm_utils_ascii_str_to_int64 (sep + 1, 10, 1, family == AF_INET ? 32 : 128, -1) < 0) {
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_FAILED,
_("invalid prefix %s"), sep + 1);
return FALSE;
}
}
if (!nm_utils_ipaddr_valid (family, string_free)) {
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_FAILED,
family == AF_INET ?
_("'%s' is not a valid IPv4 address") :
_("'%s' is not a valid IPv6 address"),
string_free);
return FALSE;
}
break;
default:
break;
}
}
return TRUE;
}
/*****************************************************************************/
G_DEFINE_ABSTRACT_TYPE (NMSettingIPConfig, nm_setting_ip_config, NM_TYPE_SETTING)

View file

@ -28,6 +28,7 @@
#endif
#include "nm-setting.h"
#include "nm-utils.h"
G_BEGIN_DECLS
@ -121,7 +122,28 @@ GVariant *nm_ip_route_get_attribute (NMIPRoute *route,
void nm_ip_route_set_attribute (NMIPRoute *route,
const char *name,
GVariant *value);
NM_AVAILABLE_IN_1_8
const NMVariantAttributeSpec *const *nm_ip_route_get_variant_attribute_spec (void);
NM_AVAILABLE_IN_1_8
gboolean nm_ip_route_attribute_validate (const char *name,
GVariant *value,
int family,
gboolean *known,
GError **error);
#define NM_IP_ROUTE_ATTRIBUTE_PREF_SRC "pref-src"
#define NM_IP_ROUTE_ATTRIBUTE_SRC "src"
#define NM_IP_ROUTE_ATTRIBUTE_TOS "tos"
#define NM_IP_ROUTE_ATTRIBUTE_WINDOW "window"
#define NM_IP_ROUTE_ATTRIBUTE_CWND "cwnd"
#define NM_IP_ROUTE_ATTRIBUTE_INITCWND "initcwnd"
#define NM_IP_ROUTE_ATTRIBUTE_INITRWND "initrwnd"
#define NM_IP_ROUTE_ATTRIBUTE_MTU "mtu"
#define NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW "lock-window"
#define NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND "lock-cwnd"
#define NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND "lock-initcwnd"
#define NM_IP_ROUTE_ATTRIBUTE_LOCK_INITRWND "lock-initrwnd"
#define NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU "lock-mtu"
#define NM_TYPE_SETTING_IP_CONFIG (nm_setting_ip_config_get_type ())
#define NM_SETTING_IP_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTING_IP_CONFIG, NMSettingIPConfig))

View file

@ -615,7 +615,7 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *ip4_class)
* ---end---
* ---ifcfg-rh---
* property: routes
* variable: ADDRESS1, NETMASK1, GATEWAY1, METRIC1, ...
* variable: ADDRESS1, NETMASK1, GATEWAY1, METRIC1, OPTIONS1, ...
* description: List of static routes. They are not stored in ifcfg-* file,
* but in route-* file instead.
* ---end---

View file

@ -28,6 +28,14 @@
#include "nm-setting-private.h"
#include "nm-setting-ip-config.h"
struct _NMVariantAttributeSpec {
char *name;
const GVariantType *type;
bool v4:1;
bool v6:1;
char str_type;
};
gboolean _nm_utils_string_slist_validate (GSList *list,
const char **valid_values);

View file

@ -4697,6 +4697,261 @@ _nm_utils_team_config_equal (const char *conf1,
}
#endif
static char *
attribute_escape (const char *src, char c1, char c2)
{
char *ret, *dest;
dest = ret = malloc (strlen (src) * 2 + 1);
while (*src) {
if (*src == c1 || *src == c2 || *src == '\\')
*dest++ = '\\';
*dest++ = *src++;
}
*dest++ = '\0';
return ret;
}
static char *
attribute_unescape (const char *start, const char *end)
{
char *ret, *dest;
nm_assert (start <= end);
dest = ret = g_malloc (end - start + 1);
for (; start < end && *start; start++) {
if (*start == '\\') {
start++;
if (!*start)
break;
}
*dest++ = *start;
}
*dest = '\0';
return ret;
}
/**
* nm_utils_parse_variant_attributes:
* @string: the input string
* @attr_separator: the attribute separator character
* @key_value_separator: character separating key and values
* @ignore_unknown: whether unknown attributes should be ignored
* @spec: the attribute format specifiers
* @error: (out) (allow-none): location to store the error on failure
*
* Parse attributes from a string.
*
* Returns: (transfer full): a #GHashTable mapping attribute names to #GVariant values.
*
* Since: 1.8
*/
GHashTable *
nm_utils_parse_variant_attributes (const char *string,
char attr_separator,
char key_value_separator,
gboolean ignore_unknown,
const NMVariantAttributeSpec *const *spec,
GError **error)
{
gs_unref_hashtable GHashTable *ht = NULL;
const char *ptr = string, *start = NULL, *sep;
GVariant *variant;
const NMVariantAttributeSpec * const *s;
g_return_val_if_fail (string, NULL);
g_return_val_if_fail (attr_separator, NULL);
g_return_val_if_fail (key_value_separator, NULL);
g_return_val_if_fail (!error || !*error, NULL);
ht = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref);
while (TRUE) {
gs_free char *name = NULL, *value = NULL;
if (!start)
start = ptr;
if (*ptr == '\\') {
ptr++;
if (!*ptr) {
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED,
_("unterminated escape sequence"));
return NULL;
}
goto next;
}
if (*ptr == attr_separator || *ptr == '\0') {
if (ptr == start) {
/* multiple separators */
start = NULL;
goto next;
}
/* Find the key-value separator */
for (sep = start; sep != ptr; sep++) {
if (*sep == '\\') {
sep++;
if (!*sep) {
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED,
_("unterminated escape sequence"));
return NULL;
}
}
if (*sep == key_value_separator)
break;
}
if (*sep != key_value_separator) {
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED,
_("missing key-value separator '%c'"), key_value_separator);
return NULL;
}
name = attribute_unescape (start, sep);
value = attribute_unescape (sep + 1, ptr);
for (s = spec; *s; s++) {
if (nm_streq (name, (*s)->name))
break;
}
if (!*s) {
if (ignore_unknown)
goto next;
else {
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED,
_("unknown attribute '%s'"), name);
return NULL;
}
}
if (g_variant_type_equal ((*s)->type, G_VARIANT_TYPE_UINT32)) {
gint64 num = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXUINT32, -1);
if (num == -1) {
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED,
_("invalid uint32 value '%s' for attribute '%s'"), value, name);
return NULL;
}
variant = g_variant_new_uint32 (num);
} else if (g_variant_type_equal ((*s)->type, G_VARIANT_TYPE_BYTE)) {
gint64 num = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXUINT8, -1);
if (num == -1) {
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED,
_("invalid uint8 value '%s' for attribute '%s'"), value, name);
return NULL;
}
variant = g_variant_new_byte ((guchar) num);
} else if (g_variant_type_equal ((*s)->type, G_VARIANT_TYPE_BOOLEAN)) {
gboolean b;
if (nm_streq (value, "true"))
b = TRUE;
else if (nm_streq (value, "false"))
b = FALSE;
else {
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED,
_("invalid boolean value '%s' for attribute '%s'"), value, name);
return NULL;
}
variant = g_variant_new_boolean (b);
} else if (g_variant_type_equal ((*s)->type, G_VARIANT_TYPE_STRING)) {
variant = g_variant_new_take_string (g_steal_pointer (&value));
} else {
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED,
_("unsupported attribute '%s' of type '%s'"), name,
(char *) (*s)->type);
return NULL;
}
g_hash_table_insert (ht, g_steal_pointer (&name), variant);
start = NULL;
}
next:
if (*ptr == '\0')
break;
ptr++;
}
return g_steal_pointer (&ht);
}
/*
* nm_utils_format_variant_attributes:
* @attributes: a #GHashTable mapping attribute names to #GVariant values
* @attr_separator: the attribute separator character
* @key_value_separator: character separating key and values
*
* Format attributes to a string.
*
* Returns: (transfer full): the string representing attributes, or %NULL
* in case there are no attributes
*
* Since: 1.8
*/
char *
nm_utils_format_variant_attributes (GHashTable *attributes,
char attr_separator,
char key_value_separator)
{
GString *str = NULL;
GVariant *variant;
char sep = 0;
const char *name, *value;
char *escaped;
char buf[64];
gs_free_list GList *keys = NULL;
GList *iter;
g_return_val_if_fail (attr_separator, NULL);
g_return_val_if_fail (key_value_separator, NULL);
if (!attributes || !g_hash_table_size (attributes))
return NULL;
keys = g_list_sort (g_hash_table_get_keys (attributes), (GCompareFunc) g_strcmp0);
str = g_string_new ("");
for (iter = keys; iter; iter = g_list_next (iter)) {
name = iter->data;
variant = g_hash_table_lookup (attributes, name);
value = NULL;
if (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32))
value = nm_sprintf_buf (buf, "%u", g_variant_get_uint32 (variant));
else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BYTE))
value = nm_sprintf_buf (buf, "%hhu", g_variant_get_byte (variant));
else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BOOLEAN))
value = g_variant_get_boolean (variant) ? "true" : "false";
else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING))
value = g_variant_get_string (variant, NULL);
else
continue;
if (sep)
g_string_append_c (str, sep);
escaped = attribute_escape (name, attr_separator, key_value_separator);
g_string_append (str, escaped);
g_free (escaped);
g_string_append_c (str, key_value_separator);
escaped = attribute_escape (value, attr_separator, key_value_separator);
g_string_append (str, escaped);
g_free (escaped);
sep = attr_separator;
}
return g_string_free (str, FALSE);
}
/*****************************************************************************/
/**

View file

@ -38,6 +38,8 @@
G_BEGIN_DECLS
typedef struct _NMVariantAttributeSpec NMVariantAttributeSpec;
/* SSID helpers */
gboolean nm_utils_is_empty_ssid (const guint8 *ssid, gsize len);
const char *nm_utils_escape_ssid (const guint8 *ssid, gsize len);
@ -215,6 +217,19 @@ const char **nm_utils_enum_get_values (GType type, gint from, gint to);
NM_AVAILABLE_IN_1_6
guint nm_utils_version (void);
NM_AVAILABLE_IN_1_8
GHashTable * nm_utils_parse_variant_attributes (const char *string,
char attr_separator,
char key_value_separator,
gboolean ignore_unknown,
const NMVariantAttributeSpec *const *spec,
GError **error);
NM_AVAILABLE_IN_1_8
char * nm_utils_format_variant_attributes (GHashTable *attributes,
char attr_separator,
char key_value_separator);
G_END_DECLS
#endif /* __NM_UTILS_H__ */

View file

@ -642,6 +642,47 @@ test_setting_ip4_config_address_data (void)
g_object_unref (conn);
}
static void
test_setting_ip_route_attributes (void)
{
GVariant *variant;
gboolean res, known;
#define TEST_ATTR(name, type, value, family, exp_res, exp_known) \
variant = g_variant_new_ ## type (value); \
res = nm_ip_route_attribute_validate (name, variant, family, &known, NULL); \
g_assert (res == exp_res); \
g_assert (known == exp_known); \
g_variant_unref (variant);
TEST_ATTR ("foo", uint32, 12, AF_INET, FALSE, FALSE);
TEST_ATTR ("tos", byte, 127, AF_INET, TRUE, TRUE);
TEST_ATTR ("tos", string, "0x28", AF_INET, FALSE, TRUE);
TEST_ATTR ("cwnd", uint32, 10, AF_INET, TRUE, TRUE);
TEST_ATTR ("cwnd", string, "11", AF_INET, FALSE, TRUE);
TEST_ATTR ("lock-mtu", boolean, TRUE, AF_INET, TRUE, TRUE);
TEST_ATTR ("lock-mtu", uint32, 1, AF_INET, FALSE, TRUE);
TEST_ATTR ("src", string, "fd01::1", AF_INET6, TRUE, TRUE);
TEST_ATTR ("src", string, "fd01::1/64", AF_INET6, TRUE, TRUE);
TEST_ATTR ("src", string, "fd01::1/128", AF_INET6, TRUE, TRUE);
TEST_ATTR ("src", string, "fd01::1/129", AF_INET6, FALSE, TRUE);
TEST_ATTR ("src", string, "fd01::1/a", AF_INET6, FALSE, TRUE);
TEST_ATTR ("src", string, "abc/64", AF_INET6, FALSE, TRUE);
TEST_ATTR ("src", string, "1.2.3.4", AF_INET, FALSE, TRUE);
TEST_ATTR ("src", string, "1.2.3.4", AF_INET6, FALSE, TRUE);
TEST_ATTR ("pref-src", string, "1.2.3.4", AF_INET, TRUE, TRUE);
TEST_ATTR ("pref-src", string, "1.2.3.4", AF_INET6, FALSE, TRUE);
TEST_ATTR ("pref-src", string, "1.2.3.0/24", AF_INET, FALSE, TRUE);
TEST_ATTR ("pref-src", string, "fd01::12", AF_INET6, TRUE, TRUE);
#undef TEST_ATTR
}
static void
test_setting_gsm_apn_spaces (void)
{
@ -5412,6 +5453,97 @@ test_nm_in_strset (void)
#undef _ASSERT
}
static void
test_route_attributes_parse (void)
{
GHashTable *ht;
GError *error = NULL;
GVariant *variant;
ht = nm_utils_parse_variant_attributes ("mtu=1400 pref-src=1.2.3.4 cwnd=14",
' ', '=', FALSE,
nm_ip_route_get_variant_attribute_spec (),
&error);
g_assert_no_error (error);
g_assert (ht);
g_hash_table_unref (ht);
ht = nm_utils_parse_variant_attributes ("mtu=1400 pref-src=1.2.3.4 cwnd=14 \\",
' ', '=', FALSE,
nm_ip_route_get_variant_attribute_spec (),
&error);
g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED);
g_assert (!ht);
g_clear_error (&error);
ht = nm_utils_parse_variant_attributes ("mtu.1400 pref-src.1\\.2\\.3\\.4 ",
' ', '.', FALSE,
nm_ip_route_get_variant_attribute_spec (),
&error);
g_assert (ht);
g_assert_no_error (error);
variant = g_hash_table_lookup (ht, NM_IP_ROUTE_ATTRIBUTE_MTU);
g_assert (variant);
g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32));
g_assert_cmpuint (g_variant_get_uint32 (variant), ==, 1400);
variant = g_hash_table_lookup (ht, NM_IP_ROUTE_ATTRIBUTE_PREF_SRC);
g_assert (variant);
g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING));
g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "1.2.3.4");
g_hash_table_unref (ht);
ht = nm_utils_parse_variant_attributes ("src:fd01\\:\\:42\\/64/initrwnd:21",
'/', ':', FALSE,
nm_ip_route_get_variant_attribute_spec (),
&error);
g_assert (ht);
g_assert_no_error (error);
variant = g_hash_table_lookup (ht, NM_IP_ROUTE_ATTRIBUTE_INITRWND);
g_assert (variant);
g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32));
g_assert_cmpuint (g_variant_get_uint32 (variant), ==, 21);
variant = g_hash_table_lookup (ht, NM_IP_ROUTE_ATTRIBUTE_SRC);
g_assert (variant);
g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING));
g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "fd01::42/64");
g_hash_table_unref (ht);
}
static void
test_route_attributes_format (void)
{
gs_unref_hashtable GHashTable *ht = NULL;
char *str;
ht = g_hash_table_new_full (g_str_hash, g_str_equal,
NULL, (GDestroyNotify) g_variant_unref);
str = nm_utils_format_variant_attributes (NULL, ' ', '=');
g_assert_cmpstr (str, ==, NULL);
str = nm_utils_format_variant_attributes (ht, ' ', '=');
g_assert_cmpstr (str, ==, NULL);
g_hash_table_insert (ht, NM_IP_ROUTE_ATTRIBUTE_MTU, g_variant_new_uint32 (5000));
g_hash_table_insert (ht, NM_IP_ROUTE_ATTRIBUTE_INITRWND, g_variant_new_uint32 (20));
g_hash_table_insert (ht, NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, g_variant_new_boolean (TRUE));
g_hash_table_insert (ht, NM_IP_ROUTE_ATTRIBUTE_PREF_SRC, g_variant_new_string ("aaaa:bbbb::1"));
str = nm_utils_format_variant_attributes (ht, ' ', '=');
g_assert_cmpstr (str, ==, "initrwnd=20 lock-mtu=true mtu=5000 pref-src=aaaa:bbbb::1");
g_hash_table_remove_all (ht);
g_free (str);
g_hash_table_insert (ht, NM_IP_ROUTE_ATTRIBUTE_WINDOW, g_variant_new_uint32 (30000));
g_hash_table_insert (ht, NM_IP_ROUTE_ATTRIBUTE_INITCWND, g_variant_new_uint32 (21));
g_hash_table_insert (ht, NM_IP_ROUTE_ATTRIBUTE_SRC, g_variant_new_string ("aaaa:bbbb:cccc:dddd::/64"));
str = nm_utils_format_variant_attributes (ht, '/', ':');
g_assert_cmpstr (str, ==, "initcwnd:21/src:aaaa\\:bbbb\\:cccc\\:dddd\\:\\:\\/64/window:30000");
g_hash_table_remove_all (ht);
g_free (str);
}
/*****************************************************************************/
static gboolean
@ -5467,6 +5599,7 @@ int main (int argc, char **argv)
g_test_add_func ("/core/general/test_setting_vpn_modify_during_foreach", test_setting_vpn_modify_during_foreach);
g_test_add_func ("/core/general/test_setting_ip4_config_labels", test_setting_ip4_config_labels);
g_test_add_func ("/core/general/test_setting_ip4_config_address_data", test_setting_ip4_config_address_data);
g_test_add_func ("/core/general/test_setting_ip_route_attributes", test_setting_ip_route_attributes);
g_test_add_func ("/core/general/test_setting_gsm_apn_spaces", test_setting_gsm_apn_spaces);
g_test_add_func ("/core/general/test_setting_gsm_apn_bad_chars", test_setting_gsm_apn_bad_chars);
g_test_add_func ("/core/general/test_setting_gsm_apn_underscore", test_setting_gsm_apn_underscore);
@ -5576,6 +5709,8 @@ int main (int argc, char **argv)
g_test_add_func ("/core/general/_nm_utils_team_config_equal", test_nm_utils_team_config_equal);
g_test_add_func ("/core/general/test_nm_utils_enum", test_nm_utils_enum);
g_test_add_func ("/core/general/nm-set-out", test_nm_set_out);
g_test_add_func ("/core/general/route_attributes/parse", test_route_attributes_parse);
g_test_add_func ("/core/general/route_attributes/format", test_route_attributes_format);
return g_test_run ();
}

View file

@ -1148,6 +1148,8 @@ libnm_1_8_0 {
global:
nm_connection_get_setting_dummy;
nm_device_dummy_get_type;
nm_ip_route_get_variant_attribute_spec;
nm_ip_route_attribute_validate;
nm_setting_802_1x_auth_flags_get_type;
nm_setting_802_1x_get_auth_timeout;
nm_setting_802_1x_get_ca_cert_password;
@ -1163,4 +1165,6 @@ global:
nm_setting_dummy_get_type;
nm_setting_dummy_new;
nm_setting_gsm_get_mtu;
nm_utils_format_variant_attributes;
nm_utils_parse_variant_attributes;
} libnm_1_6_0;

View file

@ -1291,6 +1291,50 @@ nmtst_setting_ip_config_add_route (NMSettingIPConfig *s_ip,
g_assert (nm_setting_ip_config_add_route (s_ip, route));
nm_ip_route_unref (route);
}
inline static void
nmtst_assert_route_attribute_string (NMIPRoute *route, const char *name, const char *value)
{
GVariant *variant;
variant = nm_ip_route_get_attribute (route, name);
g_assert (variant);
g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING));
g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, value);
}
inline static void
nmtst_assert_route_attribute_byte (NMIPRoute *route, const char *name, guchar value)
{
GVariant *variant;
variant = nm_ip_route_get_attribute (route, name);
g_assert (variant);
g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_BYTE));
g_assert_cmpint (g_variant_get_byte (variant), ==, value);
}
inline static void
nmtst_assert_route_attribute_uint32 (NMIPRoute *route, const char *name, guint32 value)
{
GVariant *variant;
variant = nm_ip_route_get_attribute (route, name);
g_assert (variant);
g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32));
g_assert_cmpint (g_variant_get_uint32 (variant), ==, value);
}
inline static void
nmtst_assert_route_attribute_boolean (NMIPRoute *route, const char *name, gboolean value)
{
GVariant *variant;
variant = nm_ip_route_get_attribute (route, name);
g_assert (variant);
g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_BOOLEAN));
g_assert_cmpint (g_variant_get_boolean (variant), ==, value);
}
#endif /* NM_SETTING_IP_CONFIG_H */
#if (defined(__NM_SIMPLE_CONNECTION_H__) && defined(__NM_SETTING_CONNECTION_H__)) || (defined(NM_CONNECTION_H))
@ -1661,6 +1705,7 @@ nmtst_assert_hwaddr_equals (gconstpointer hwaddr1, gssize hwaddr1_len, const cha
nmtst_assert_hwaddr_equals (hwaddr1, hwaddr1_len, expected, __FILE__, __LINE__)
#endif
#if defined(__NM_SIMPLE_CONNECTION_H__) && defined(__NM_SETTING_CONNECTION_H__) && defined(__NM_KEYFILE_INTERNAL_H__)
static inline NMConnection *

View file

@ -301,24 +301,21 @@ _platform_route_sync_add (const VTableIP *vtable, NMDefaultRouteManager *self, g
return FALSE;
if (vtable->vt->is_ip4) {
success = nm_platform_ip4_route_add (priv->platform,
entry->route.rx.ifindex,
entry->route.rx.rt_source,
0,
0,
entry->route.r4.gateway,
0,
entry->effective_metric,
entry->route.rx.mss);
NMPlatformIP4Route rt = entry->route.r4;
rt.network = 0;
rt.plen = 0;
rt.metric = entry->effective_metric;
success = nm_platform_ip4_route_add (priv->platform, &rt);
} else {
success = nm_platform_ip6_route_add (priv->platform,
entry->route.rx.ifindex,
entry->route.rx.rt_source,
in6addr_any,
0,
entry->route.r6.gateway,
entry->effective_metric,
entry->route.rx.mss);
NMPlatformIP6Route rt = entry->route.r6;
rt.network = in6addr_any;
rt.plen = 0;
rt.metric = entry->effective_metric;
success = nm_platform_ip6_route_add (priv->platform, &rt);
}
if (!success) {
_LOGW (vtable->vt->addr_family, "failed to add default route %s with effective metric %u",

View file

@ -412,6 +412,38 @@ nm_ip4_config_commit (const NMIP4Config *config, int ifindex, gboolean routes_fu
return TRUE;
}
static void
merge_route_attributes (NMIPRoute *s_route, NMPlatformIP4Route *r)
{
GVariant *variant;
in_addr_t addr;
#define GET_ATTR(name, field, variant_type, type) \
variant = nm_ip_route_get_attribute (s_route, name); \
if (variant && g_variant_is_of_type (variant, G_VARIANT_TYPE_ ## variant_type)) \
r->field = g_variant_get_ ## type (variant);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_TOS, tos, BYTE, byte);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_WINDOW, window, UINT32, uint32);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_CWND, cwnd, UINT32, uint32);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_INITCWND, initcwnd, UINT32, uint32);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_INITRWND, initrwnd, UINT32, uint32);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_MTU, mtu, UINT32, uint32);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW, lock_window, BOOLEAN, boolean);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, lock_cwnd, BOOLEAN, boolean);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, lock_initcwnd, BOOLEAN, boolean);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITRWND, lock_initrwnd, BOOLEAN, boolean);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, lock_mtu, BOOLEAN, boolean);
if ( (variant = nm_ip_route_get_attribute (s_route, NM_IP_ROUTE_ATTRIBUTE_PREF_SRC))
&& g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)) {
if (inet_pton (AF_INET, g_variant_get_string (variant, NULL), &addr) == 1)
r->pref_src = addr;
}
#undef GET_ATTR
}
void
nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIPConfig *setting, guint32 default_route_metric)
{
@ -492,6 +524,7 @@ nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIPConfig *setting, gu
route.metric = nm_ip_route_get_metric (s_route);
route.rt_source = NM_IP_CONFIG_SOURCE_USER;
merge_route_attributes (s_route, &route);
nm_ip4_config_add_route (config, &route);
}

View file

@ -416,6 +416,57 @@ nm_ip6_config_commit (const NMIP6Config *config, int ifindex, gboolean routes_fu
return success;
}
static void
merge_route_attributes (NMIPRoute *s_route, NMPlatformIP6Route *r)
{
GVariant *variant;
struct in6_addr addr;
#define GET_ATTR(name, field, variant_type, type) \
variant = nm_ip_route_get_attribute (s_route, name); \
if (variant && g_variant_is_of_type (variant, G_VARIANT_TYPE_ ## variant_type)) \
r->field = g_variant_get_ ## type (variant);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_TOS, tos, BYTE, byte);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_WINDOW, window, UINT32, uint32);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_CWND, cwnd, UINT32, uint32);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_INITCWND, initcwnd, UINT32, uint32);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_INITRWND, initrwnd, UINT32, uint32);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_MTU, mtu, UINT32, uint32);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW, lock_window, BOOLEAN, boolean);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, lock_cwnd, BOOLEAN, boolean);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, lock_initcwnd, BOOLEAN, boolean);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITRWND, lock_initrwnd, BOOLEAN, boolean);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, lock_mtu, BOOLEAN, boolean);
if ( (variant = nm_ip_route_get_attribute (s_route, NM_IP_ROUTE_ATTRIBUTE_PREF_SRC))
&& g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)) {
if (inet_pton (AF_INET6, g_variant_get_string (variant, NULL), &addr) == 1)
r->pref_src = addr;
}
if ( (variant = nm_ip_route_get_attribute (s_route, NM_IP_ROUTE_ATTRIBUTE_SRC))
&& g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)) {
gs_free char *string = NULL;
guint8 plen = 128;
char *sep;
string = g_variant_dup_string (variant, NULL);
sep = strchr (string, '/');
if (sep) {
*sep = 0;
plen = _nm_utils_ascii_str_to_int64 (sep + 1, 10, 1, 128, 255);
}
if ( plen <= 128
&& inet_pton (AF_INET6, string, &addr) == 1) {
r->src = addr;
r->src_plen = plen;
}
}
#undef GET_ATTR
}
void
nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIPConfig *setting, guint32 default_route_metric)
{
@ -492,6 +543,7 @@ nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIPConfig *setting, gu
route.metric = nm_ip_route_get_metric (s_route);
route.rt_source = NM_IP_CONFIG_SOURCE_USER;
merge_route_attributes (s_route, &route);
nm_ip6_config_add_route (config, &route);
}

View file

@ -162,7 +162,7 @@ nmtst_platform_ip4_route_full (const char *network, guint plen, const char *gate
}
static inline NMPlatformIP6Route *
nmtst_platform_ip6_route (const char *network, guint plen, const char *gateway)
nmtst_platform_ip6_route (const char *network, guint plen, const char *gateway, const char *pref_src)
{
static NMPlatformIP6Route route;
@ -172,6 +172,7 @@ nmtst_platform_ip6_route (const char *network, guint plen, const char *gateway)
route.network = *nmtst_inet6_from_string (network);
route.plen = plen;
route.gateway = *nmtst_inet6_from_string (gateway);
route.pref_src = *nmtst_inet6_from_string (pref_src);
return &route;
}
@ -181,7 +182,7 @@ nmtst_platform_ip6_route_full (const char *network, guint plen, const char *gate
int ifindex, NMIPConfigSource source,
guint metric, guint mss)
{
NMPlatformIP6Route *route = nmtst_platform_ip6_route (network, plen, gateway);
NMPlatformIP6Route *route = nmtst_platform_ip6_route (network, plen, gateway, NULL);
route->ifindex = ifindex;
route->rt_source = source;

View file

@ -1225,42 +1225,29 @@ ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, gu
}
static gboolean
ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
in_addr_t network, guint8 plen, in_addr_t gateway,
in_addr_t pref_src, guint32 metric, guint32 mss)
ip4_route_add (NMPlatform *platform, const NMPlatformIP4Route *route)
{
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
NMPlatformIP4Route route;
NMPlatformIP4Route rt = *route;
guint i;
guint8 scope;
g_assert (plen <= 32);
rt.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (rt.rt_source);
rt.network = nm_utils_ip4_address_clear_host_address (rt.network, rt.plen);
rt.scope_inv = nm_platform_route_scope_inv (rt.gateway ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK);
scope = gateway == 0 ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE;
memset (&route, 0, sizeof (route));
route.ifindex = ifindex;
route.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (source);
route.network = nm_utils_ip4_address_clear_host_address (network, plen);
route.plen = plen;
route.gateway = gateway;
route.metric = metric;
route.mss = mss;
route.scope_inv = nm_platform_route_scope_inv (scope);
if (gateway) {
if (rt.gateway) {
for (i = 0; i < priv->ip4_routes->len; i++) {
NMPlatformIP4Route *item = &g_array_index (priv->ip4_routes,
NMPlatformIP4Route, i);
guint32 gate = ntohl (item->network) >> (32 - item->plen);
guint32 host = ntohl (gateway) >> (32 - item->plen);
guint32 host = ntohl (rt.gateway) >> (32 - item->plen);
if (ifindex == item->ifindex && gate == host)
if (rt.ifindex == item->ifindex && gate == host)
break;
}
if (i == priv->ip4_routes->len) {
nm_log_warn (LOGD_PLATFORM, "Fake platform: failure adding ip4-route '%d: %s/%d %d': Network Unreachable",
route.ifindex, nm_utils_inet4_ntop (route.network, NULL), route.plen, route.metric);
rt.ifindex, nm_utils_inet4_ntop (rt.network, NULL), rt.plen, rt.metric);
return FALSE;
}
}
@ -1268,65 +1255,58 @@ ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
for (i = 0; i < priv->ip4_routes->len; i++) {
NMPlatformIP4Route *item = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i);
if (item->network != route.network)
if (item->network != rt.network)
continue;
if (item->plen != route.plen)
if (item->plen != rt.plen)
continue;
if (item->metric != metric)
if (item->metric != rt.metric)
continue;
if (item->ifindex != route.ifindex) {
if (item->ifindex != rt.ifindex) {
ip4_route_delete (platform, item->ifindex, item->network, item->plen, item->metric);
i--;
continue;
}
memcpy (item, &route, sizeof (route));
g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP4_ROUTE, ifindex, &route, (int) NM_PLATFORM_SIGNAL_CHANGED);
memcpy (item, &rt, sizeof (rt));
g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP4_ROUTE,
rt.ifindex, &rt, (int) NM_PLATFORM_SIGNAL_CHANGED);
return TRUE;
}
g_array_append_val (priv->ip4_routes, route);
g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP4_ROUTE, ifindex, &route, (int) NM_PLATFORM_SIGNAL_ADDED);
g_array_append_val (priv->ip4_routes, rt);
g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP4_ROUTE,
rt.ifindex, &rt, (int) NM_PLATFORM_SIGNAL_ADDED);
return TRUE;
}
static gboolean
ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
struct in6_addr network, guint8 plen, struct in6_addr gateway,
guint32 metric, guint32 mss)
ip6_route_add (NMPlatform *platform, const NMPlatformIP6Route *route)
{
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
NMPlatformIP6Route route;
NMPlatformIP6Route rt = *route;
guint i;
metric = nm_utils_ip6_route_metric_normalize (metric);
rt.metric = nm_utils_ip6_route_metric_normalize (rt.metric);
rt.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (rt.rt_source);
nm_utils_ip6_address_clear_host_address (&rt.network, &rt.network, rt.plen);
memset (&route, 0, sizeof (route));
route.ifindex = ifindex;
route.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (source);
nm_utils_ip6_address_clear_host_address (&route.network, &network, plen);
route.plen = plen;
route.gateway = gateway;
route.metric = metric;
route.mss = mss;
if (!IN6_IS_ADDR_UNSPECIFIED(&gateway)) {
if (!IN6_IS_ADDR_UNSPECIFIED (&rt.gateway)) {
for (i = 0; i < priv->ip6_routes->len; i++) {
NMPlatformIP6Route *item = &g_array_index (priv->ip6_routes,
NMPlatformIP6Route, i);
guint8 gate_bits = gateway.s6_addr[item->plen / 8] >> (8 - item->plen % 8);
guint8 gate_bits = rt.gateway.s6_addr[item->plen / 8] >> (8 - item->plen % 8);
guint8 host_bits = item->network.s6_addr[item->plen / 8] >> (8 - item->plen % 8);
if ( ifindex == item->ifindex
&& memcmp (&gateway, &item->network, item->plen / 8) == 0
if ( rt.ifindex == item->ifindex
&& memcmp (&rt.gateway, &item->network, item->plen / 8) == 0
&& gate_bits == host_bits)
break;
}
if (i == priv->ip6_routes->len) {
nm_log_warn (LOGD_PLATFORM, "Fake platform: failure adding ip6-route '%d: %s/%d %d': Network Unreachable",
route.ifindex, nm_utils_inet6_ntop (&route.network, NULL), route.plen, route.metric);
rt.ifindex, nm_utils_inet6_ntop (&rt.network, NULL), rt.plen, rt.metric);
return FALSE;
}
}
@ -1334,26 +1314,28 @@ ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
for (i = 0; i < priv->ip6_routes->len; i++) {
NMPlatformIP6Route *item = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i);
if (!IN6_ARE_ADDR_EQUAL (&item->network, &route.network))
if (!IN6_ARE_ADDR_EQUAL (&item->network, &rt.network))
continue;
if (item->plen != route.plen)
if (item->plen != rt.plen)
continue;
if (item->metric != metric)
if (item->metric != rt.metric)
continue;
if (item->ifindex != route.ifindex) {
if (item->ifindex != rt.ifindex) {
ip6_route_delete (platform, item->ifindex, item->network, item->plen, item->metric);
i--;
continue;
}
memcpy (item, &route, sizeof (route));
g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP6_ROUTE, ifindex, &route, (int) NM_PLATFORM_SIGNAL_CHANGED);
memcpy (item, &rt, sizeof (rt));
g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP6_ROUTE,
rt.ifindex, &rt, (int) NM_PLATFORM_SIGNAL_CHANGED);
return TRUE;
}
g_array_append_val (priv->ip6_routes, route);
g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP6_ROUTE, ifindex, &route, (int) NM_PLATFORM_SIGNAL_ADDED);
g_array_append_val (priv->ip6_routes, rt);
g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP6_ROUTE,
rt.ifindex, &rt, (int) NM_PLATFORM_SIGNAL_ADDED);
return TRUE;
}

View file

@ -1833,6 +1833,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only)
NMIPAddr gateway;
} nh;
guint32 mss;
guint32 window = 0, cwnd = 0, initcwnd = 0, initrwnd = 0, mtu = 0, lock = 0;
guint32 table;
if (!nlmsg_valid_hdr (nlh, sizeof (*rtm)))
@ -1846,8 +1847,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only)
if (!NM_IN_SET (rtm->rtm_family, AF_INET, AF_INET6))
goto errout;
if ( rtm->rtm_type != RTN_UNICAST
|| rtm->rtm_tos != 0)
if (rtm->rtm_type != RTN_UNICAST)
goto errout;
err = nlmsg_parse (nlh, sizeof (struct rtmsg), tb, RTA_MAX, policy);
@ -1941,21 +1941,34 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only)
mss = 0;
if (tb[RTA_METRICS]) {
struct nlattr *mtb[RTAX_MAX + 1];
int i;
static struct nla_policy rtax_policy[RTAX_MAX + 1] = {
[RTAX_LOCK] = { .type = NLA_U32 },
[RTAX_ADVMSS] = { .type = NLA_U32 },
[RTAX_WINDOW] = { .type = NLA_U32 },
[RTAX_CWND] = { .type = NLA_U32 },
[RTAX_INITCWND] = { .type = NLA_U32 },
[RTAX_INITRWND] = { .type = NLA_U32 },
[RTAX_MTU] = { .type = NLA_U32 },
};
err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL);
err = nla_parse_nested (mtb, RTAX_MAX, tb[RTA_METRICS], rtax_policy);
if (err < 0)
goto errout;
for (i = 1; i <= RTAX_MAX; i++) {
if (mtb[i]) {
if (i == RTAX_ADVMSS) {
if (nla_len (mtb[i]) >= sizeof (uint32_t))
mss = nla_get_u32(mtb[i]);
break;
}
}
}
if (mtb[RTAX_LOCK])
lock = nla_get_u32 (mtb[RTAX_LOCK]);
if (mtb[RTAX_ADVMSS])
mss = nla_get_u32 (mtb[RTAX_ADVMSS]);
if (mtb[RTAX_WINDOW])
window = nla_get_u32 (mtb[RTAX_WINDOW]);
if (mtb[RTAX_CWND])
cwnd = nla_get_u32 (mtb[RTAX_CWND]);
if (mtb[RTAX_INITCWND])
initcwnd = nla_get_u32 (mtb[RTAX_INITCWND]);
if (mtb[RTAX_INITRWND])
initrwnd = nla_get_u32 (mtb[RTAX_INITRWND]);
if (mtb[RTAX_MTU])
mtu = nla_get_u32 (mtb[RTAX_MTU]);
}
/*****************************************************************/
@ -1980,12 +1993,31 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only)
if (is_v4)
obj->ip4_route.scope_inv = nm_platform_route_scope_inv (rtm->rtm_scope);
if (is_v4) {
if (_check_addr_or_errout (tb, RTA_PREFSRC, addr_len))
if (_check_addr_or_errout (tb, RTA_PREFSRC, addr_len)) {
if (is_v4)
memcpy (&obj->ip4_route.pref_src, nla_data (tb[RTA_PREFSRC]), addr_len);
else
memcpy (&obj->ip6_route.pref_src, nla_data (tb[RTA_PREFSRC]), addr_len);
}
if (!is_v4 && tb[RTA_SRC]) {
_check_addr_or_errout (tb, RTA_SRC, addr_len);
memcpy (&obj->ip6_route.src, nla_data (tb[RTA_SRC]), addr_len);
obj->ip6_route.src_plen = rtm->rtm_src_len;
}
obj->ip_route.mss = mss;
obj->ip_route.window = window;
obj->ip_route.cwnd = cwnd;
obj->ip_route.initcwnd = initcwnd;
obj->ip_route.initrwnd = initrwnd;
obj->ip_route.mtu = mtu;
obj->ip_route.tos = rtm->rtm_tos;
obj->ip_route.lock_window = NM_FLAGS_HAS (lock, 1 << RTAX_WINDOW);
obj->ip_route.lock_cwnd = NM_FLAGS_HAS (lock, 1 << RTAX_CWND);
obj->ip_route.lock_initcwnd = NM_FLAGS_HAS (lock, 1 << RTAX_INITCWND);
obj->ip_route.lock_initrwnd = NM_FLAGS_HAS (lock, 1 << RTAX_INITRWND);
obj->ip_route.lock_mtu = NM_FLAGS_HAS (lock, 1 << RTAX_MTU);
if (NM_FLAGS_HAS (rtm->rtm_flags, RTM_F_CLONED)) {
/* we must not straight way reject cloned routes, because we might have cached
@ -2360,19 +2392,28 @@ _nl_msg_new_route (int nlmsg_type,
gconstpointer gateway,
guint32 metric,
guint32 mss,
gconstpointer pref_src)
gconstpointer pref_src,
gconstpointer src,
guint8 src_plen,
guint8 tos,
guint32 window,
guint32 cwnd,
guint32 initcwnd,
guint32 initrwnd,
guint32 mtu,
guint32 lock)
{
struct nl_msg *msg;
struct rtmsg rtmsg = {
.rtm_family = family,
.rtm_tos = 0,
.rtm_tos = tos,
.rtm_table = RT_TABLE_MAIN, /* omit setting RTA_TABLE attribute */
.rtm_protocol = nmp_utils_ip_config_source_coerce_to_rtprot (source),
.rtm_scope = scope,
.rtm_type = RTN_UNICAST,
.rtm_flags = 0,
.rtm_dst_len = plen,
.rtm_src_len = 0,
.rtm_src_len = src ? src_plen : 0,
};
NMIPAddr network_clean;
@ -2394,19 +2435,35 @@ _nl_msg_new_route (int nlmsg_type,
nm_utils_ipx_address_clear_host_address (family, &network_clean, network, plen);
NLA_PUT (msg, RTA_DST, addr_len, &network_clean);
if (src)
NLA_PUT (msg, RTA_SRC, addr_len, src);
NLA_PUT_U32 (msg, RTA_PRIORITY, metric);
if (pref_src)
NLA_PUT (msg, RTA_PREFSRC, addr_len, pref_src);
if (mss > 0) {
if (mss || window || cwnd || initcwnd || initrwnd || mtu || lock) {
struct nlattr *metrics;
metrics = nla_nest_start (msg, RTA_METRICS);
if (!metrics)
goto nla_put_failure;
NLA_PUT_U32 (msg, RTAX_ADVMSS, mss);
if (mss)
NLA_PUT_U32 (msg, RTAX_ADVMSS, mss);
if (window)
NLA_PUT_U32 (msg, RTAX_WINDOW, window);
if (cwnd)
NLA_PUT_U32 (msg, RTAX_CWND, cwnd);
if (initcwnd)
NLA_PUT_U32 (msg, RTAX_INITCWND, initcwnd);
if (initrwnd)
NLA_PUT_U32 (msg, RTAX_INITRWND, initrwnd);
if (mtu)
NLA_PUT_U32 (msg, RTAX_MTU, mtu);
if (lock)
NLA_PUT_U32 (msg, RTAX_LOCK, lock);
nla_nest_end(msg, metrics);
}
@ -5901,53 +5958,85 @@ ip6_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteFlags fl
return ipx_route_get_all (platform, ifindex, NMP_OBJECT_TYPE_IP6_ROUTE, flags);
}
static guint32
ip_route_get_lock_flag (NMPlatformIPRoute *route)
{
return (((guint32) route->lock_window) << RTAX_WINDOW)
| (((guint32) route->lock_cwnd) << RTAX_CWND)
| (((guint32) route->lock_initcwnd) << RTAX_INITCWND)
| (((guint32) route->lock_initrwnd) << RTAX_INITRWND)
| (((guint32) route->lock_mtu) << RTAX_MTU);
}
static gboolean
ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
in_addr_t network, guint8 plen, in_addr_t gateway,
in_addr_t pref_src, guint32 metric, guint32 mss)
ip4_route_add (NMPlatform *platform, const NMPlatformIP4Route *route)
{
NMPObject obj_id;
nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
in_addr_t network;
network = nm_utils_ip4_address_clear_host_address (route->network, route->plen);
/* FIXME: take the scope from route into account */
nlmsg = _nl_msg_new_route (RTM_NEWROUTE,
NLM_F_CREATE | NLM_F_REPLACE,
AF_INET,
ifindex,
source,
gateway ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK,
route->ifindex,
route->rt_source,
route->gateway ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK,
&network,
plen,
&gateway,
metric,
mss,
pref_src ? &pref_src : NULL);
route->plen,
&route->gateway,
route->metric,
route->mss,
route->pref_src ? &route->pref_src : NULL,
NULL,
0,
route->tos,
route->window,
route->cwnd,
route->initcwnd,
route->initrwnd,
route->mtu,
ip_route_get_lock_flag ((NMPlatformIPRoute *) route));
nmp_object_stackinit_id_ip4_route (&obj_id, ifindex, network, plen, metric);
nmp_object_stackinit_id_ip4_route (&obj_id, route->ifindex, network, route->plen, route->metric);
return do_add_addrroute (platform, &obj_id, nlmsg);
}
static gboolean
ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
struct in6_addr network, guint8 plen, struct in6_addr gateway,
guint32 metric, guint32 mss)
ip6_route_add (NMPlatform *platform, const NMPlatformIP6Route *route)
{
NMPObject obj_id;
nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
struct in6_addr network;
nm_utils_ip6_address_clear_host_address (&network, &route->network, route->plen);
/* FIXME: take the scope from route into account */
nlmsg = _nl_msg_new_route (RTM_NEWROUTE,
NLM_F_CREATE | NLM_F_REPLACE,
AF_INET6,
ifindex,
source,
!IN6_IS_ADDR_UNSPECIFIED (&gateway) ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK,
route->ifindex,
route->rt_source,
IN6_IS_ADDR_UNSPECIFIED (&route->gateway) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE,
&network,
plen,
&gateway,
metric,
mss,
NULL);
route->plen,
&route->gateway,
route->metric,
route->mss,
!IN6_IS_ADDR_UNSPECIFIED (&route->pref_src) ? &route->pref_src : NULL,
!IN6_IS_ADDR_UNSPECIFIED (&route->src) ? &route->src : NULL,
route->src_plen,
route->tos,
route->window,
route->cwnd,
route->initcwnd,
route->initrwnd,
route->mtu,
ip_route_get_lock_flag ((NMPlatformIPRoute *) route));
nmp_object_stackinit_id_ip6_route (&obj_id, ifindex, &network, plen, metric);
nmp_object_stackinit_id_ip6_route (&obj_id, route->ifindex, &network, route->plen, route->metric);
return do_add_addrroute (platform, &obj_id, nlmsg);
}
@ -6000,7 +6089,16 @@ ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, guint8 p
NULL,
metric,
0,
NULL);
NULL,
NULL,
0,
0,
0,
0,
0,
0,
0,
0);
if (!nlmsg)
return FALSE;
@ -6026,7 +6124,16 @@ ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, gu
NULL,
metric,
0,
NULL);
NULL,
NULL,
0,
0,
0,
0,
0,
0,
0,
0);
if (!nlmsg)
return FALSE;

View file

@ -3109,14 +3109,7 @@ nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRoute
/**
* nm_platform_ip4_route_add:
* @self:
* @ifindex:
* @source:
* network:
* plen:
* gateway:
* pref_src:
* metric:
* mss:
* @route:
*
* For kernel, a gateway can be either explicitly set or left
* at zero (0.0.0.0). In addition, there is the scope of the IPv4
@ -3137,57 +3130,29 @@ nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRoute
* Returns: %TRUE in case of success.
*/
gboolean
nm_platform_ip4_route_add (NMPlatform *self,
int ifindex, NMIPConfigSource source,
in_addr_t network, guint8 plen,
in_addr_t gateway, in_addr_t pref_src,
guint32 metric, guint32 mss)
nm_platform_ip4_route_add (NMPlatform *self, const NMPlatformIP4Route *route)
{
_CHECK_SELF (self, klass, FALSE);
g_return_val_if_fail (plen <= 32, FALSE);
g_return_val_if_fail (route, FALSE);
g_return_val_if_fail (route->plen <= 32, FALSE);
if (_LOGD_ENABLED ()) {
NMPlatformIP4Route route = { 0 };
_LOGD ("route: adding or updating IPv4 route: %s", nm_platform_ip4_route_to_string (route, NULL, 0));
route.ifindex = ifindex;
route.rt_source = source;
route.network = network;
route.plen = plen;
route.gateway = gateway;
route.metric = metric;
route.mss = mss;
route.pref_src = pref_src;
_LOGD ("route: adding or updating IPv4 route: %s", nm_platform_ip4_route_to_string (&route, NULL, 0));
}
return klass->ip4_route_add (self, ifindex, source, network, plen, gateway, pref_src, metric, mss);
return klass->ip4_route_add (self, route);
}
gboolean
nm_platform_ip6_route_add (NMPlatform *self,
int ifindex, NMIPConfigSource source,
struct in6_addr network, guint8 plen, struct in6_addr gateway,
guint32 metric, guint32 mss)
nm_platform_ip6_route_add (NMPlatform *self, const NMPlatformIP6Route *route)
{
_CHECK_SELF (self, klass, FALSE);
g_return_val_if_fail (plen <= 128, FALSE);
g_return_val_if_fail (route, FALSE);
g_return_val_if_fail (route->plen <= 128, FALSE);
if (_LOGD_ENABLED ()) {
NMPlatformIP6Route route = { 0 };
_LOGD ("route: adding or updating IPv6 route: %s", nm_platform_ip6_route_to_string (route, NULL, 0));
route.ifindex = ifindex;
route.rt_source = source;
route.network = network;
route.plen = plen;
route.gateway = gateway;
route.metric = metric;
route.mss = mss;
_LOGD ("route: adding or updating IPv6 route: %s", nm_platform_ip6_route_to_string (&route, NULL, 0));
}
return klass->ip6_route_add (self, ifindex, source, network, plen, gateway, metric, mss);
return klass->ip6_route_add (self, route);
}
gboolean
@ -3900,6 +3865,7 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi
char s_pref_src[INET_ADDRSTRLEN];
char str_dev[TO_STRING_DEV_BUF_SIZE];
char str_scope[30], s_source[50];
char str_tos[32], str_window[32], str_cwnd[32], str_initcwnd[32], str_initrwnd[32], str_mtu[32];
if (!nm_utils_to_string_buffer_init_null (route, &buf, &len))
return buf;
@ -3909,16 +3875,35 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi
_to_string_dev (NULL, route->ifindex, str_dev, sizeof (str_dev));
if (route->tos)
nm_sprintf_buf (str_tos, " tos 0x%x", (unsigned) route->tos);
if (route->window)
nm_sprintf_buf (str_window, " window %s%"G_GUINT32_FORMAT, route->lock_window ? "lock " : "", route->window);
if (route->cwnd)
nm_sprintf_buf (str_cwnd, " cwnd %s%"G_GUINT32_FORMAT, route->lock_cwnd ? "lock " : "", route->cwnd);
if (route->initcwnd)
nm_sprintf_buf (str_initcwnd, " initcwnd %s%"G_GUINT32_FORMAT, route->lock_initcwnd ? "lock " : "", route->initcwnd);
if (route->initrwnd)
nm_sprintf_buf (str_initrwnd, " initrwnd %s%"G_GUINT32_FORMAT, route->lock_initrwnd ? "lock " : "", route->initrwnd);
if (route->mtu)
nm_sprintf_buf (str_mtu, " mtu %s%"G_GUINT32_FORMAT, route->lock_mtu ? "lock " : "", route->mtu);
g_snprintf (buf, len,
"%s/%d"
" via %s"
"%s"
" metric %"G_GUINT32_FORMAT
" mss %"G_GUINT32_FORMAT
" src %s" /* source */
" rt-src %s" /* protocol */
"%s" /* cloned */
"%s%s" /* scope */
"%s%s" /* pref-src */
"%s" /* tos */
"%s" /* window */
"%s" /* cwnd */
"%s" /* initcwnd */
"%s" /* initrwnd */
"%s" /* mtu */
"",
s_network,
route->plen,
@ -3931,7 +3916,13 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi
route->scope_inv ? " scope " : "",
route->scope_inv ? (nm_platform_route_scope2str (nm_platform_route_scope_inv (route->scope_inv), str_scope, sizeof (str_scope))) : "",
route->pref_src ? " pref-src " : "",
route->pref_src ? inet_ntop (AF_INET, &route->pref_src, s_pref_src, sizeof(s_pref_src)) : "");
route->pref_src ? inet_ntop (AF_INET, &route->pref_src, s_pref_src, sizeof(s_pref_src)) : "",
route->tos ? str_tos : "",
route->window ? str_window : "",
route->cwnd ? str_cwnd : "",
route->initcwnd ? str_initcwnd : "",
route->initrwnd ? str_initrwnd : "",
route->mtu ? str_mtu : "");
return buf;
}
@ -3950,25 +3941,54 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi
const char *
nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsize len)
{
char s_network[INET6_ADDRSTRLEN], s_gateway[INET6_ADDRSTRLEN];
char s_network[INET6_ADDRSTRLEN], s_gateway[INET6_ADDRSTRLEN], s_pref_src[INET6_ADDRSTRLEN];
char s_src[INET6_ADDRSTRLEN];
char str_dev[TO_STRING_DEV_BUF_SIZE], s_source[50];
char str_tos[32], str_window[32], str_cwnd[32], str_initcwnd[32], str_initrwnd[32], str_mtu[32];
if (!nm_utils_to_string_buffer_init_null (route, &buf, &len))
return buf;
inet_ntop (AF_INET6, &route->network, s_network, sizeof(s_network));
inet_ntop (AF_INET6, &route->gateway, s_gateway, sizeof(s_gateway));
inet_ntop (AF_INET6, &route->network, s_network, sizeof (s_network));
inet_ntop (AF_INET6, &route->gateway, s_gateway, sizeof (s_gateway));
inet_ntop (AF_INET6, &route->src, s_src, sizeof (s_src));
if (IN6_IS_ADDR_UNSPECIFIED (&route->pref_src))
s_pref_src[0] = 0;
else
inet_ntop (AF_INET6, &route->pref_src, s_pref_src, sizeof (s_pref_src));
_to_string_dev (NULL, route->ifindex, str_dev, sizeof (str_dev));
if (route->tos)
nm_sprintf_buf (str_tos, " tos 0x%x", (unsigned) route->tos);
if (route->window)
nm_sprintf_buf (str_window, " window %s%"G_GUINT32_FORMAT, route->lock_window ? "lock " : "", route->window);
if (route->cwnd)
nm_sprintf_buf (str_cwnd, " cwnd %s%"G_GUINT32_FORMAT, route->lock_cwnd ? "lock " : "", route->cwnd);
if (route->initcwnd)
nm_sprintf_buf (str_initcwnd, " initcwnd %s%"G_GUINT32_FORMAT, route->lock_initcwnd ? "lock " : "", route->initcwnd);
if (route->initrwnd)
nm_sprintf_buf (str_initrwnd, " initrwnd %s%"G_GUINT32_FORMAT, route->lock_initrwnd ? "lock " : "", route->initrwnd);
if (route->mtu)
nm_sprintf_buf (str_mtu, " mtu %s%"G_GUINT32_FORMAT, route->lock_mtu ? "lock " : "", route->mtu);
g_snprintf (buf, len,
"%s/%d"
" via %s"
"%s"
" metric %"G_GUINT32_FORMAT
" mss %"G_GUINT32_FORMAT
" src %s" /* source */
" rt-src %s" /* protocol */
" src %s/%u" /* source */
"%s" /* cloned */
"%s%s" /* pref-src */
"%s" /* tos */
"%s" /* window */
"%s" /* cwnd */
"%s" /* initcwnd */
"%s" /* initrwnd */
"%s" /* mtu */
"",
s_network,
route->plen,
@ -3977,7 +3997,17 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi
route->metric,
route->mss,
nmp_utils_ip_config_source_to_string (route->rt_source, s_source, sizeof (s_source)),
route->rt_cloned ? " cloned" : "");
s_src, route->src_plen,
route->rt_cloned ? " cloned" : "",
s_pref_src[0] ? " pref-src " : "",
s_pref_src[0] ? s_pref_src : "",
route->tos ? str_tos : "",
route->window ? str_window : "",
route->cwnd ? str_cwnd : "",
route->initcwnd ? str_initcwnd : "",
route->initrwnd ? str_initrwnd : "",
route->mtu ? str_mtu : "");
return buf;
}
@ -4266,6 +4296,17 @@ nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route
_CMP_FIELD (a, b, scope_inv);
_CMP_FIELD (a, b, pref_src);
_CMP_FIELD (a, b, rt_cloned);
_CMP_FIELD (a, b, tos);
_CMP_FIELD (a, b, lock_window);
_CMP_FIELD (a, b, lock_cwnd);
_CMP_FIELD (a, b, lock_initcwnd);
_CMP_FIELD (a, b, lock_initrwnd);
_CMP_FIELD (a, b, lock_mtu);
_CMP_FIELD (a, b, window);
_CMP_FIELD (a, b, cwnd);
_CMP_FIELD (a, b, initcwnd);
_CMP_FIELD (a, b, initrwnd);
_CMP_FIELD (a, b, mtu);
return 0;
}
@ -4278,9 +4319,23 @@ nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route
_CMP_FIELD (a, b, plen);
_CMP_FIELD (a, b, metric);
_CMP_FIELD_MEMCMP (a, b, gateway);
_CMP_FIELD_MEMCMP (a, b, pref_src);
_CMP_FIELD_MEMCMP (a, b, src);
_CMP_FIELD (a, b, src_plen);
_CMP_FIELD (a, b, rt_source);
_CMP_FIELD (a, b, mss);
_CMP_FIELD (a, b, rt_cloned);
_CMP_FIELD (a, b, tos);
_CMP_FIELD (a, b, lock_window);
_CMP_FIELD (a, b, lock_cwnd);
_CMP_FIELD (a, b, lock_initcwnd);
_CMP_FIELD (a, b, lock_initrwnd);
_CMP_FIELD (a, b, lock_mtu);
_CMP_FIELD (a, b, window);
_CMP_FIELD (a, b, cwnd);
_CMP_FIELD (a, b, initcwnd);
_CMP_FIELD (a, b, initrwnd);
_CMP_FIELD (a, b, mtu);
return 0;
}
@ -4411,28 +4466,27 @@ nm_platform_netns_push (NMPlatform *platform, NMPNetns **netns)
static gboolean
_vtr_v4_route_add (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, gint64 metric)
{
return nm_platform_ip4_route_add (self,
ifindex > 0 ? ifindex : route->rx.ifindex,
route->rx.rt_source,
route->r4.network,
route->rx.plen,
route->r4.gateway,
route->r4.pref_src,
metric >= 0 ? (guint32) metric : route->rx.metric,
route->rx.mss);
NMPlatformIP4Route rt = route->r4;
if (ifindex > 0)
rt.ifindex = ifindex;
if (metric >= 0)
rt.metric = metric;
return nm_platform_ip4_route_add (self, &rt);
}
static gboolean
_vtr_v6_route_add (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, gint64 metric)
{
return nm_platform_ip6_route_add (self,
ifindex > 0 ? ifindex : route->rx.ifindex,
route->rx.rt_source,
route->r6.network,
route->rx.plen,
route->r6.gateway,
metric >= 0 ? (guint32) metric : route->rx.metric,
route->rx.mss);
NMPlatformIP6Route rt = route->r6;
if (ifindex > 0)
rt.ifindex = ifindex;
if (metric >= 0)
rt.metric = metric;
return nm_platform_ip6_route_add (self, &rt);
}
static gboolean

View file

@ -324,9 +324,20 @@ typedef union {
* of platform users. This flag is internal to track those hidden
* routes. Such a route is not alive, according to nmp_object_is_alive(). */ \
bool rt_cloned:1; \
bool lock_window:1; \
bool lock_cwnd:1; \
bool lock_initcwnd:1; \
bool lock_initrwnd:1; \
bool lock_mtu:1; \
\
guint32 metric; \
guint32 mss; \
guint32 tos; \
guint32 window; \
guint32 cwnd; \
guint32 initcwnd; \
guint32 initrwnd; \
guint32 mtu; \
;
typedef struct {
@ -358,6 +369,9 @@ struct _NMPlatformIP6Route {
__NMPlatformIPRoute_COMMON;
struct in6_addr network;
struct in6_addr gateway;
struct in6_addr pref_src;
struct in6_addr src;
guint8 src_plen;
};
typedef union {
@ -667,12 +681,8 @@ typedef struct {
GArray * (*ip4_route_get_all) (NMPlatform *, int ifindex, NMPlatformGetRouteFlags flags);
GArray * (*ip6_route_get_all) (NMPlatform *, int ifindex, NMPlatformGetRouteFlags flags);
gboolean (*ip4_route_add) (NMPlatform *, int ifindex, NMIPConfigSource source,
in_addr_t network, guint8 plen, in_addr_t gateway,
in_addr_t pref_src, guint32 metric, guint32 mss);
gboolean (*ip6_route_add) (NMPlatform *, int ifindex, NMIPConfigSource source,
struct in6_addr network, guint8 plen, struct in6_addr gateway,
guint32 metric, guint32 mss);
gboolean (*ip4_route_add) (NMPlatform *, const NMPlatformIP4Route *route);
gboolean (*ip6_route_add) (NMPlatform *, const NMPlatformIP6Route *route);
gboolean (*ip4_route_delete) (NMPlatform *, int ifindex, in_addr_t network, guint8 plen, guint32 metric);
gboolean (*ip6_route_delete) (NMPlatform *, int ifindex, struct in6_addr network, guint8 plen, guint32 metric);
const NMPlatformIP4Route *(*ip4_route_get) (NMPlatform *, int ifindex, in_addr_t network, guint8 plen, guint32 metric);
@ -969,12 +979,8 @@ const NMPlatformIP4Route *nm_platform_ip4_route_get (NMPlatform *self, int ifind
const NMPlatformIP6Route *nm_platform_ip6_route_get (NMPlatform *self, int ifindex, struct in6_addr network, guint8 plen, guint32 metric);
GArray *nm_platform_ip4_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags);
GArray *nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags);
gboolean nm_platform_ip4_route_add (NMPlatform *self, int ifindex, NMIPConfigSource source,
in_addr_t network, guint8 plen, in_addr_t gateway,
in_addr_t pref_src, guint32 metric, guint32 mss);
gboolean nm_platform_ip6_route_add (NMPlatform *self, int ifindex, NMIPConfigSource source,
struct in6_addr network, guint8 plen, struct in6_addr gateway,
guint32 metric, guint32 mss);
gboolean nm_platform_ip4_route_add (NMPlatform *self, const NMPlatformIP4Route *route);
gboolean nm_platform_ip6_route_add (NMPlatform *self, const NMPlatformIP6Route *route);
gboolean nm_platform_ip4_route_delete (NMPlatform *self, int ifindex, in_addr_t network, guint8 plen, guint32 metric);
gboolean nm_platform_ip6_route_delete (NMPlatform *self, int ifindex, struct in6_addr network, guint8 plen, guint32 metric);

View file

@ -65,12 +65,12 @@ test_cleanup_internal (void)
/* Add routes and addresses */
g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr4, plen4, addr4, lifetime, preferred, 0, NULL));
g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr6, plen6, in6addr_any, lifetime, preferred, flags));
g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway4, 32, INADDR_ANY, 0, metric, mss));
g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network4, plen4, gateway4, 0, metric, mss));
g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway4, 0, metric, mss));
g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway6, 128, in6addr_any, metric, mss));
g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network6, plen6, gateway6, metric, mss));
g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway6, metric, mss));
nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway4, 32, INADDR_ANY, 0, metric, mss);
nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network4, plen4, gateway4, 0, metric, mss);
nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway4, 0, metric, mss);
nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway6, 128, in6addr_any, in6addr_any, metric, mss);
nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network6, plen6, gateway6, in6addr_any, metric, mss);
nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway6, in6addr_any, metric, mss);
addresses4 = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex);
addresses6 = nm_platform_ip6_address_get_all (NM_PLATFORM_GET, ifindex);

View file

@ -783,6 +783,54 @@ nmtstp_ip6_address_add (NMPlatform *platform,
NULL);
}
void nmtstp_ip4_route_add (NMPlatform *platform,
int ifindex,
NMIPConfigSource source,
in_addr_t network,
guint8 plen,
in_addr_t gateway,
in_addr_t pref_src,
guint32 metric,
guint32 mss)
{
NMPlatformIP4Route route = { };
route.ifindex = ifindex;
route.rt_source = source;
route.network = network;
route.plen = plen;
route.gateway = gateway;
route.pref_src = pref_src;
route.metric = metric;
route.mss = mss;
g_assert (nm_platform_ip4_route_add (platform, &route));
}
void nmtstp_ip6_route_add (NMPlatform *platform,
int ifindex,
NMIPConfigSource source,
struct in6_addr network,
guint8 plen,
struct in6_addr gateway,
struct in6_addr pref_src,
guint32 metric,
guint32 mss)
{
NMPlatformIP6Route route = { };
route.ifindex = ifindex;
route.rt_source = source;
route.network = network;
route.plen = plen;
route.gateway = gateway;
route.pref_src = pref_src;
route.metric = metric;
route.mss = mss;
g_assert (nm_platform_ip6_route_add (platform, &route));
}
/*****************************************************************************/
static void

View file

@ -167,6 +167,26 @@ void nmtstp_ip6_address_del (NMPlatform *platform,
struct in6_addr address,
int plen);
void nmtstp_ip4_route_add (NMPlatform *platform,
int ifindex,
NMIPConfigSource source,
in_addr_t network,
guint8 plen,
in_addr_t gateway,
in_addr_t pref_src,
guint32 metric,
guint32 mss);
void nmtstp_ip6_route_add (NMPlatform *platform,
int ifindex,
NMIPConfigSource source,
struct in6_addr network,
guint8 plen,
struct in6_addr gateway,
struct in6_addr pref_src,
guint32 metric,
guint32 mss);
/*****************************************************************************/
const NMPlatformLink *nmtstp_link_get_typed (NMPlatform *platform, int ifindex, const char *name, NMLinkType link_type);

View file

@ -94,7 +94,7 @@ test_ip4_route_metric0 (void)
nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, metric);
/* add the first route */
g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, INADDR_ANY, 0, metric, mss));
nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, INADDR_ANY, 0, metric, mss);
accept_signal (route_added);
nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, 0);
@ -108,7 +108,7 @@ test_ip4_route_metric0 (void)
nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, metric);
/* add the second route */
g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, INADDR_ANY, 0, 0, mss));
nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, INADDR_ANY, 0, 0, mss);
accept_signal (route_added);
nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, 0);
@ -160,27 +160,27 @@ test_ip4_route (void)
inet_pton (AF_INET, "198.51.100.1", &gateway);
/* Add route to gateway */
g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway, 32, INADDR_ANY, 0, metric, mss));
nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway, 32, INADDR_ANY, 0, metric, mss);
accept_signal (route_added);
/* Add route */
nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, metric);
g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, 0, metric, mss));
nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, 0, metric, mss);
nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, metric);
accept_signal (route_added);
/* Add route again */
g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, 0, metric, mss));
nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, 0, metric, mss);
accept_signals (route_changed, 0, 1);
/* Add default route */
nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, 0, 0, metric);
g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway, 0, metric, mss));
nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway, 0, metric, mss);
nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, 0, 0, metric);
accept_signal (route_added);
/* Add default route again */
g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway, 0, metric, mss));
nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway, 0, metric, mss);
accept_signals (route_changed, 0, 1);
/* Test route listing */
@ -222,6 +222,14 @@ test_ip4_route (void)
/* Remove route again */
g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric));
/* Remove default route */
g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, 0, 0, metric));
accept_signal (route_removed);
/* Remove route to gateway */
g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, gateway, 32, metric));
accept_signal (route_removed);
free_signal (route_added);
free_signal (route_changed);
free_signal (route_removed);
@ -238,36 +246,41 @@ test_ip6_route (void)
NMPlatformIP6Route rts[3];
struct in6_addr network;
guint8 plen = 64;
struct in6_addr gateway;
struct in6_addr gateway, pref_src;
/* Choose a high metric so that we hopefully don't conflict. */
int metric = 22987;
int mss = 1000;
inet_pton (AF_INET6, "2001:db8:a:b:0:0:0:0", &network);
inet_pton (AF_INET6, "2001:db8:c:d:1:2:3:4", &gateway);
inet_pton (AF_INET6, "::42", &pref_src);
g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, pref_src, 128, in6addr_any,
NM_PLATFORM_LIFETIME_PERMANENT, NM_PLATFORM_LIFETIME_PERMANENT, 0));
accept_signals (route_added, 0, 1);
/* Add route to gateway */
g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway, 128, in6addr_any, metric, mss));
nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway, 128, in6addr_any, in6addr_any, metric, mss);
accept_signal (route_added);
/* Add route */
g_assert (!nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, network, plen, metric));
g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, metric, mss));
nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, pref_src, metric, mss);
g_assert (nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, network, plen, metric));
accept_signal (route_added);
/* Add route again */
g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, metric, mss));
nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, pref_src, metric, mss);
accept_signals (route_changed, 0, 1);
/* Add default route */
g_assert (!nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, in6addr_any, 0, metric));
g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway, metric, mss));
nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway, in6addr_any, metric, mss);
g_assert (nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, in6addr_any, 0, metric));
accept_signal (route_added);
/* Add default route again */
g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway, metric, mss));
nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway, in6addr_any, metric, mss);
accept_signals (route_changed, 0, 1);
/* Test route listing */
@ -278,6 +291,7 @@ test_ip6_route (void)
rts[0].plen = 128;
rts[0].ifindex = ifindex;
rts[0].gateway = in6addr_any;
rts[0].pref_src = in6addr_any;
rts[0].metric = nm_utils_ip6_route_metric_normalize (metric);
rts[0].mss = mss;
rts[1].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER);
@ -285,6 +299,7 @@ test_ip6_route (void)
rts[1].plen = plen;
rts[1].ifindex = ifindex;
rts[1].gateway = gateway;
rts[1].pref_src = pref_src;
rts[1].metric = nm_utils_ip6_route_metric_normalize (metric);
rts[1].mss = mss;
rts[2].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER);
@ -292,6 +307,7 @@ test_ip6_route (void)
rts[2].plen = 0;
rts[2].ifindex = ifindex;
rts[2].gateway = gateway;
rts[2].pref_src = in6addr_any;
rts[2].metric = nm_utils_ip6_route_metric_normalize (metric);
rts[2].mss = mss;
g_assert_cmpint (routes->len, ==, 3);
@ -306,6 +322,14 @@ test_ip6_route (void)
/* Remove route again */
g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric));
/* Remove default route */
g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, in6addr_any, 0, metric));
accept_signal (route_removed);
/* Remove route to gateway */
g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, gateway, 128, metric));
accept_signal (route_removed);
free_signal (route_added);
free_signal (route_changed);
free_signal (route_removed);
@ -334,6 +358,119 @@ test_ip4_zero_gateway (void)
nm_platform_process_events (NM_PLATFORM_GET);
}
static void
test_ip4_route_options (void)
{
int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
NMPlatformIP4Route route = { };
in_addr_t network;
GArray *routes;
NMPlatformIP4Route rts[1];
inet_pton (AF_INET, "172.16.1.0", &network);
route.ifindex = ifindex;
route.rt_source = NM_IP_CONFIG_SOURCE_USER;
route.network = network;
route.plen = 24;
route.metric = 20;
route.tos = 0x28;
route.window = 10000;
route.cwnd = 16;
route.initcwnd = 30;
route.initrwnd = 50;
route.mtu = 1350;
route.lock_cwnd = TRUE;
g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, &route));
/* Test route listing */
routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex,
NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT |
NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
memset (rts, 0, sizeof (rts));
rts[0].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER);
rts[0].scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK);
rts[0].network = network;
rts[0].plen = 24;
rts[0].ifindex = ifindex;
rts[0].metric = 20;
rts[0].tos = 0x28;
rts[0].window = 10000;
rts[0].cwnd = 16;
rts[0].initcwnd = 30;
rts[0].initrwnd = 50;
rts[0].mtu = 1350;
rts[0].lock_cwnd = TRUE;
g_assert_cmpint (routes->len, ==, 1);
nmtst_platform_ip4_routes_equal ((NMPlatformIP4Route *) routes->data, rts, routes->len, TRUE);
/* Remove route */
g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, 24, 20));
g_array_unref (routes);
}
static void
test_ip6_route_options (void)
{
int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
NMPlatformIP6Route route = { };
struct in6_addr network, src;
GArray *routes;
NMPlatformIP6Route rts[3];
inet_pton (AF_INET6, "2001:db8:a:b:0:0:0:0", &network);
inet_pton (AF_INET6, "2001:db8:e:0:0:0:0:0", &src);
route.ifindex = ifindex;
route.rt_source = NM_IP_CONFIG_SOURCE_USER;
route.network = network;
route.plen = 64;
route.gateway = in6addr_any;
route.src = src;
route.src_plen = 48;
route.metric = 1024;
route.window = 20000;
route.cwnd = 8;
route.initcwnd = 22;
route.initrwnd = 33;
route.mtu = 1300;
route.lock_mtu = TRUE;
g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, &route));
/* Test route listing */
routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex,
NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT |
NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
memset (rts, 0, sizeof (rts));
rts[0].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER);
rts[0].network = network;
rts[0].plen = 64;
rts[0].ifindex = ifindex;
rts[0].gateway = in6addr_any;
rts[0].src = src;
rts[0].src_plen = 48;
rts[0].metric = 1024;
rts[0].window = 20000;
rts[0].cwnd = 8;
rts[0].initcwnd = 22;
rts[0].initrwnd = 33;
rts[0].mtu = 1300;
rts[0].lock_mtu = TRUE;
g_assert_cmpint (routes->len, ==, 1);
nmtst_platform_ip6_routes_equal ((NMPlatformIP6Route *) routes->data, rts, routes->len, TRUE);
/* Remove route */
g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, network, 64, 1024));
g_array_unref (routes);
}
/*****************************************************************************/
NMTstpSetupFunc const _nmtstp_setup_platform_func = SETUP;
@ -360,6 +497,8 @@ _nmtstp_setup_tests (void)
g_test_add_func ("/route/ip4", test_ip4_route);
g_test_add_func ("/route/ip6", test_ip6_route);
g_test_add_func ("/route/ip4_metric0", test_ip4_route_metric0);
g_test_add_func ("/route/ip4_options", test_ip4_route_options);
g_test_add_func ("/route/ip6_options", test_ip6_route_options);
if (nmtstp_is_root_test ())
g_test_add_func ("/route/ip4_zero_gateway", test_ip4_zero_gateway);

View file

@ -435,6 +435,134 @@ read_full_ip4_address (shvarFile *ifcfg,
return FALSE;
}
/*
* Use looser syntax to comprise all the possibilities.
* The validity must be checked after the match.
*/
#define IPV4_ADDR_REGEX "(?:[0-9]{1,3}\\.){3}[0-9]{1,3}"
#define IPV6_ADDR_REGEX "[0-9A-Fa-f:.]+"
/*
* NOTE: The regexes below don't describe all variants allowed by 'ip route add',
* namely destination IP without 'to' keyword is recognized just at line start.
*/
static gboolean
parse_route_options (NMIPRoute *route, int family, const char *line, GError **error)
{
GRegex *regex = NULL;
GMatchInfo *match_info = NULL;
gboolean success = FALSE;
char *metrics[] = { NM_IP_ROUTE_ATTRIBUTE_WINDOW, NM_IP_ROUTE_ATTRIBUTE_CWND,
NM_IP_ROUTE_ATTRIBUTE_INITCWND , NM_IP_ROUTE_ATTRIBUTE_INITRWND,
NM_IP_ROUTE_ATTRIBUTE_MTU , NULL };
char buffer[1024];
int i;
g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE);
for (i = 0; metrics[i]; i++) {
nm_sprintf_buf (buffer, "(?:\\s|^)%s\\s+(lock\\s+)?(\\d+)(?:$|\\s)", metrics[i]);
regex = g_regex_new (buffer, 0, 0, NULL);
g_regex_match (regex, line, 0, &match_info);
if (g_match_info_matches (match_info)) {
gs_free char *lock = g_match_info_fetch (match_info, 1);
gs_free char *str = g_match_info_fetch (match_info, 2);
gint64 num = _nm_utils_ascii_str_to_int64 (str, 10, 0, G_MAXUINT32, -1);
if (num == -1) {
g_match_info_free (match_info);
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid route %s '%s'", metrics[i], str);
goto out;
}
nm_ip_route_set_attribute (route, metrics[i],
g_variant_new_uint32 (num));
if (lock && lock[0]) {
nm_sprintf_buf (buffer, "lock-%s", metrics[i]);
nm_ip_route_set_attribute (route, buffer,
g_variant_new_boolean (TRUE));
}
}
g_clear_pointer (&regex, g_regex_unref);
g_clear_pointer (&match_info, g_match_info_free);
}
/* tos */
regex = g_regex_new ("(?:\\s|^)tos\\s+(\\S+)(?:$|\\s)", 0, 0, NULL);
g_regex_match (regex, line, 0, &match_info);
if (g_match_info_matches (match_info)) {
gs_free char *str = g_match_info_fetch (match_info, 1);
gs_free_error GError *local_error = NULL;
gint64 num = _nm_utils_ascii_str_to_int64 (str, 0, 0, G_MAXUINT8, -1);
if (num == -1) {
g_match_info_free (match_info);
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid route %s '%s'", "tos", str);
goto out;
}
nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_TOS,
g_variant_new_byte ((guchar) num));
}
g_clear_pointer (&regex, g_regex_unref);
g_clear_pointer (&match_info, g_match_info_free);
/* from */
if (family == AF_INET6) {
regex = g_regex_new ("(?:\\s|^)from\\s+(" IPV6_ADDR_REGEX "(?:/\\d{1,3})?)(?:$|\\s)", 0, 0, NULL);
g_regex_match (regex, line, 0, &match_info);
if (g_match_info_matches (match_info)) {
gs_free char *str = g_match_info_fetch (match_info, 1);
gs_free_error GError *local_error = NULL;
GVariant *variant = g_variant_new_string (str);
if (!nm_ip_route_attribute_validate (NM_IP_ROUTE_ATTRIBUTE_SRC, variant, family, NULL, &local_error)) {
g_match_info_free (match_info);
g_variant_unref (variant);
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid route from '%s': %s", str, local_error->message);
goto out;
}
nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_SRC, variant);
}
g_clear_pointer (&regex, g_regex_unref);
g_clear_pointer (&match_info, g_match_info_free);
}
if (family == AF_INET)
regex = g_regex_new ("(?:\\s|^)src\\s+(" IPV4_ADDR_REGEX ")(?:$|\\s)", 0, 0, NULL);
else
regex = g_regex_new ("(?:\\s|^)src\\s+(" IPV6_ADDR_REGEX ")(?:$|\\s)", 0, 0, NULL);
g_regex_match (regex, line, 0, &match_info);
if (g_match_info_matches (match_info)) {
gs_free char *str = g_match_info_fetch (match_info, 1);
gs_free_error GError *local_error = NULL;
GVariant *variant = g_variant_new_string (str);
if (!nm_ip_route_attribute_validate (NM_IP_ROUTE_ATTRIBUTE_PREF_SRC, variant, family,
NULL, &local_error)) {
g_match_info_free (match_info);
g_variant_unref (variant);
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid route src '%s': %s", str, local_error->message);
goto out;
}
nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_PREF_SRC, variant);
}
success = TRUE;
out:
if (regex)
g_regex_unref (regex);
if (match_info)
g_match_info_free (match_info);
return success;
}
/* Returns TRUE on missing route or valid route */
static gboolean
read_one_ip4_route (shvarFile *ifcfg,
@ -507,10 +635,20 @@ read_one_ip4_route (shvarFile *ifcfg,
metric = -1;
*out_route = nm_ip_route_new_binary (AF_INET, &dest, prefix, &next_hop, metric, error);
if (*out_route)
return TRUE;
if (!*out_route)
return FALSE;
return FALSE;
/* Options */
nm_clear_g_free (&value);
value = svGetValueStr_cp (ifcfg, numbered_tag (tag, "OPTIONS", which));
if (value) {
if (!parse_route_options (*out_route, AF_INET, value, error)) {
g_clear_pointer (out_route, nm_ip_route_unref);
return FALSE;
}
}
return TRUE;
}
static gboolean
@ -636,6 +774,12 @@ read_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError *
route = nm_ip_route_new (AF_INET, dest, prefix_int, next_hop, metric_int, error);
if (!route)
goto error;
if (!parse_route_options (route, AF_INET, *iter, error)) {
nm_ip_route_unref (route);
goto error;
}
if (!nm_setting_ip_config_add_route (s_ip4, route))
PARSE_WARNING ("duplicate IP4 route");
nm_ip_route_unref (route);
@ -729,13 +873,6 @@ error:
return success;
}
/* IPv6 address is very complex to describe completely by a regular expression,
* so don't try to, rather use looser syntax to comprise all possibilities
* NOTE: The regexes below don't describe all variants allowed by 'ip route add',
* namely destination IP without 'to' keyword is recognized just at line start.
*/
#define IPV6_ADDR_REGEX "[0-9A-Fa-f:.]+"
static gboolean
read_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **error)
{
@ -757,6 +894,7 @@ read_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **error
const char *pattern_via = "via\\s+(" IPV6_ADDR_REGEX ")"; /* IPv6 of gateway */
const char *pattern_metric = "metric\\s+(\\d+)"; /* metric */
g_return_val_if_fail (filename != NULL, FALSE);
g_return_val_if_fail (s_ip6 != NULL, FALSE);
g_return_val_if_fail (!error || !*error, FALSE);
@ -862,6 +1000,12 @@ read_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **error
g_free (next_hop);
if (!route)
goto error;
if (!parse_route_options (route, AF_INET6, *iter, error)) {
nm_ip_route_unref (route);
goto error;
}
if (!nm_setting_ip_config_add_route (s_ip6, route))
PARSE_WARNING ("duplicate IP6 route");
nm_ip_route_unref (route);

View file

@ -1867,6 +1867,61 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg)
}
}
static char *
get_route_attributes_string (NMIPRoute *route, int family)
{
gs_strfreev char **names = NULL;
GVariant *attr, *lock;
GString *str;
int i;
names = nm_ip_route_get_attribute_names (route);
if (!names || !names[0])
return NULL;
str = g_string_new ("");
for (i = 0; names[i]; i++) {
attr = nm_ip_route_get_attribute (route, names[i]);
if (!nm_ip_route_attribute_validate (names[i], attr, family, NULL, NULL))
continue;
if (NM_IN_STRSET (names[i], NM_IP_ROUTE_ATTRIBUTE_WINDOW,
NM_IP_ROUTE_ATTRIBUTE_CWND,
NM_IP_ROUTE_ATTRIBUTE_INITCWND,
NM_IP_ROUTE_ATTRIBUTE_INITRWND,
NM_IP_ROUTE_ATTRIBUTE_MTU)) {
char lock_name[256];
nm_sprintf_buf (lock_name, "lock-%s", names[i]);
lock = nm_ip_route_get_attribute (route, lock_name);
g_string_append_printf (str,
"%s %s%u",
names[i],
(lock && g_variant_get_boolean (lock)) ? "lock " : "",
g_variant_get_uint32 (attr));
} else if (strstr (names[i], "lock-")) {
/* handled above */
} else if (nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_TOS)) {
g_string_append_printf (str, "%s %u", names[i], (unsigned) g_variant_get_byte (attr));
} else if ( nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_PREF_SRC)
|| nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_SRC)) {
char *arg = nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_PREF_SRC) ? "src" : "from";
g_string_append_printf (str, "%s %s", arg, g_variant_get_string (attr, NULL));
} else {
_LOGW ("unknown route option '%s'", names[i]);
continue;
}
if (names[i + 1])
g_string_append_c (str, ' ');
}
return g_string_free (str, FALSE);
}
static gboolean
write_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError **error)
{
@ -1891,6 +1946,8 @@ write_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError
route_items = g_malloc0 (sizeof (char*) * (num + 1));
for (i = 0; i < num; i++) {
gs_free char *options = NULL;
route = nm_setting_ip_config_get_route (s_ip4, i);
dest = nm_ip_route_get_dest (route);
@ -1898,10 +1955,19 @@ write_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError
next_hop = nm_ip_route_get_next_hop (route);
metric = nm_ip_route_get_metric (route);
if (metric == -1)
route_items[i] = g_strdup_printf ("%s/%u via %s\n", dest, prefix, next_hop);
else
route_items[i] = g_strdup_printf ("%s/%u via %s metric %u\n", dest, prefix, next_hop, (guint32) metric);
options = get_route_attributes_string (route, AF_INET);
if (metric == -1) {
route_items[i] = g_strdup_printf ("%s/%u via %s%s%s\n",
dest, prefix, next_hop,
options ? " " : "",
options ?: "");
} else {
route_items[i] = g_strdup_printf ("%s/%u via %s metric %u%s%s\n",
dest, prefix, next_hop, (guint32) metric,
options ? " " : "",
options ?: "");
}
}
route_items[num] = NULL;
route_contents = g_strjoinv (NULL, route_items);
@ -1960,10 +2026,14 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
{
NMSettingIPConfig *s_ip4;
const char *value;
char *addr_key, *prefix_key, *netmask_key, *gw_key, *metric_key, *tmp;
char *tmp;
char addr_key[64];
char prefix_key[64];
char netmask_key[64];
char gw_key[64];
char *route_path = NULL;
gint32 j;
guint32 i, n, num;
gint j;
guint i, num, n;
gint64 route_metric;
gint priority;
int timeout;
@ -2003,26 +2073,21 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
svUnsetValue (ifcfg, "BOOTPROTO");
for (j = -1; j < 256; j++) {
if (j == -1) {
addr_key = g_strdup ("IPADDR");
prefix_key = g_strdup ("PREFIX");
netmask_key = g_strdup ("NETMASK");
gw_key = g_strdup ("GATEWAY");
nm_sprintf_buf (addr_key, "IPADDR");
nm_sprintf_buf (prefix_key, "PREFIX");
nm_sprintf_buf (netmask_key, "NETMASK");
nm_sprintf_buf (gw_key, "GATEWAY");
} else {
addr_key = g_strdup_printf ("IPADDR%d", j);
prefix_key = g_strdup_printf ("PREFIX%d", j);
netmask_key = g_strdup_printf ("NETMASK%d", j);
gw_key = g_strdup_printf ("GATEWAY%d", j);
nm_sprintf_buf (addr_key, "IPADDR%d", (guint) j);
nm_sprintf_buf (prefix_key, "PREFIX%u", (guint) j);
nm_sprintf_buf (netmask_key, "NETMASK%u", (guint) j);
nm_sprintf_buf (gw_key, "GATEWAY%u", (guint) j);
}
svUnsetValue (ifcfg, addr_key);
svUnsetValue (ifcfg, prefix_key);
svUnsetValue (ifcfg, netmask_key);
svUnsetValue (ifcfg, gw_key);
g_free (addr_key);
g_free (prefix_key);
g_free (netmask_key);
g_free (gw_key);
}
route_path = utils_get_route_path (svFileGetName (ifcfg));
@ -2074,15 +2139,15 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
* See https://bugzilla.redhat.com/show_bug.cgi?id=771673
* and https://bugzilla.redhat.com/show_bug.cgi?id=1105770
*/
addr_key = g_strdup ("IPADDR");
prefix_key = g_strdup ("PREFIX");
netmask_key = g_strdup ("NETMASK");
gw_key = g_strdup ("GATEWAY");
nm_sprintf_buf (addr_key, "IPADDR");
nm_sprintf_buf (prefix_key, "PREFIX");
nm_sprintf_buf (netmask_key, "NETMASK");
nm_sprintf_buf (gw_key, "GATEWAY");
} else {
addr_key = g_strdup_printf ("IPADDR%d", n);
prefix_key = g_strdup_printf ("PREFIX%d", n);
netmask_key = g_strdup_printf ("NETMASK%d", n);
gw_key = g_strdup_printf ("GATEWAY%d", n);
nm_sprintf_buf (addr_key, "IPADDR%u", n);
nm_sprintf_buf (prefix_key, "PREFIX%u", n);
nm_sprintf_buf (netmask_key, "NETMASK%u", n);
nm_sprintf_buf (gw_key, "GATEWAY%u", n);
}
svSetValueStr (ifcfg, addr_key, nm_ip_address_get_address (addr));
@ -2093,30 +2158,20 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
svUnsetValue (ifcfg, netmask_key);
svUnsetValue (ifcfg, gw_key);
g_free (addr_key);
g_free (prefix_key);
g_free (netmask_key);
g_free (gw_key);
n++;
}
/* Clear remaining IPADDR<n..255>, etc */
for (; n < 256; n++) {
addr_key = g_strdup_printf ("IPADDR%d", n);
prefix_key = g_strdup_printf ("PREFIX%d", n);
netmask_key = g_strdup_printf ("NETMASK%d", n);
gw_key = g_strdup_printf ("GATEWAY%d", n);
for (i = n; i < 256; i++) {
nm_sprintf_buf (addr_key, "IPADDR%u", i);
nm_sprintf_buf (prefix_key, "PREFIX%u", i);
nm_sprintf_buf (netmask_key, "NETMASK%u", i);
nm_sprintf_buf (gw_key, "GATEWAY%u", i);
svUnsetValue (ifcfg, addr_key);
svUnsetValue (ifcfg, prefix_key);
svUnsetValue (ifcfg, netmask_key);
svUnsetValue (ifcfg, gw_key);
g_free (addr_key);
g_free (prefix_key);
g_free (netmask_key);
g_free (gw_key);
}
svSetValueStr (ifcfg, "GATEWAY", nm_setting_ip_config_get_gateway (s_ip4));
@ -2125,15 +2180,13 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
for (i = 0; i < 254; i++) {
const char *dns;
addr_key = g_strdup_printf ("DNS%d", i + 1);
nm_sprintf_buf (addr_key, "DNS%u", i + 1);
if (i >= num)
svUnsetValue (ifcfg, addr_key);
else {
dns = nm_setting_ip_config_get_dns (s_ip4, i);
svSetValueStr (ifcfg, addr_key, dns);
}
g_free (addr_key);
}
num = nm_setting_ip_config_get_num_dns_searches (s_ip4);
@ -2212,18 +2265,24 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
NMIPRoute *route;
guint32 netmask;
gint64 metric;
char metric_key[64];
char options_key[64];
addr_key = g_strdup_printf ("ADDRESS%d", i);
netmask_key = g_strdup_printf ("NETMASK%d", i);
gw_key = g_strdup_printf ("GATEWAY%d", i);
metric_key = g_strdup_printf ("METRIC%d", i);
nm_sprintf_buf (addr_key, "ADDRESS%u", i);
nm_sprintf_buf (netmask_key, "NETMASK%u", i);
nm_sprintf_buf (gw_key, "GATEWAY%u", i);
nm_sprintf_buf (metric_key, "METRIC%u", i);
nm_sprintf_buf (options_key, "OPTIONS%u", i);
if (i >= num) {
svUnsetValue (routefile, addr_key);
svUnsetValue (routefile, netmask_key);
svUnsetValue (routefile, gw_key);
svUnsetValue (routefile, metric_key);
svUnsetValue (routefile, options_key);
} else {
gs_free char *options = NULL;
route = nm_setting_ip_config_get_route (s_ip4, i);
svSetValueStr (routefile, addr_key, nm_ip_route_get_dest (route));
@ -2244,12 +2303,11 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
svSetValueStr (routefile, metric_key, tmp);
g_free (tmp);
}
}
g_free (addr_key);
g_free (netmask_key);
g_free (gw_key);
g_free (metric_key);
options = get_route_attributes_string (route, AF_INET);
if (options)
svSetValueStr (routefile, options_key, options);
}
}
if (!svWriteFile (routefile, 0644, error)) {
svCloseFile (routefile);
@ -2371,15 +2429,13 @@ write_ip4_aliases (NMConnection *connection, char *base_ifcfg_path)
static gboolean
write_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **error)
{
char **route_items;
gs_free char *route_contents = NULL;
nm_auto_free_gstring GString *contents = NULL;
NMIPRoute *route;
guint32 i, num;
g_return_val_if_fail (filename != NULL, FALSE);
g_return_val_if_fail (s_ip6 != NULL, FALSE);
g_return_val_if_fail (error != NULL, FALSE);
g_return_val_if_fail (*error == NULL, FALSE);
g_return_val_if_fail (filename, FALSE);
g_return_val_if_fail (s_ip6, FALSE);
g_return_val_if_fail (!error || !*error, FALSE);
num = nm_setting_ip_config_get_num_routes (s_ip6);
if (num == 0) {
@ -2387,28 +2443,33 @@ write_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **erro
return TRUE;
}
route_items = g_malloc0 (sizeof (char*) * (num + 1));
contents = g_string_new ("");
for (i = 0; i < num; i++) {
gs_free char *options = NULL;
route = nm_setting_ip_config_get_route (s_ip6, i);
options = get_route_attributes_string (route, AF_INET6);
if (nm_ip_route_get_metric (route) == -1) {
route_items[i] = g_strdup_printf ("%s/%u via %s\n",
nm_ip_route_get_dest (route),
nm_ip_route_get_prefix (route),
nm_ip_route_get_next_hop (route));
} else {
route_items[i] = g_strdup_printf ("%s/%u via %s metric %u\n",
g_string_append_printf (contents, "%s/%u via %s%s%s",
nm_ip_route_get_dest (route),
nm_ip_route_get_prefix (route),
nm_ip_route_get_next_hop (route),
(guint32) nm_ip_route_get_metric (route));
options ? " " : "",
options ?: "");
} else {
g_string_append_printf (contents, "%s/%u via %s metric %u%s%s",
nm_ip_route_get_dest (route),
nm_ip_route_get_prefix (route),
nm_ip_route_get_next_hop (route),
(unsigned) nm_ip_route_get_metric (route),
options ? " " : "",
options ?: "");
}
g_string_append (contents, "\n");
}
route_items[num] = NULL;
route_contents = g_strjoinv (NULL, route_items);
g_strfreev (route_items);
if (!g_file_set_contents (filename, route_contents, -1, NULL)) {
if (!g_file_set_contents (filename, contents->str, -1, NULL)) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
"Writing route6 file '%s' failed", filename);
return FALSE;
@ -2440,9 +2501,8 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
NMSettingIPConfig *s_ip6;
NMSettingIPConfig *s_ip4;
const char *value;
char *addr_key;
char *tmp;
guint32 i, num, num4;
guint i, num, num4;
gint priority;
NMIPAddress *addr;
const char *dns;
@ -2530,7 +2590,9 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
num4 = s_ip4 ? nm_setting_ip_config_get_num_dns (s_ip4) : 0; /* from where to start with IPv6 entries */
num = nm_setting_ip_config_get_num_dns (s_ip6);
for (i = 0; i < 254; i++) {
addr_key = g_strdup_printf ("DNS%d", i + num4 + 1);
char addr_key[64];
nm_sprintf_buf (addr_key, "DNS%u", i + num4 + 1);
if (i >= num)
svUnsetValue (ifcfg, addr_key);
@ -2538,7 +2600,6 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
dns = nm_setting_ip_config_get_dns (s_ip6, i);
svSetValueStr (ifcfg, addr_key, dns);
}
g_free (addr_key);
}
/* Write out DNS domains - 'DOMAIN' key is shared for both IPv4 and IPv6 domains */

View file

@ -6,3 +6,4 @@ ADDRESS1=44.55.66.77
NETMASK1=255.255.255.255
GATEWAY1=192.168.1.7
METRIC1=3
OPTIONS1="mtu lock 9000 cwnd 12 src 1.1.1.1 tos 0x28 window 30000 initcwnd lock 13 initrwnd 14"

View file

@ -3,5 +3,5 @@
21.31.41.0/24 via 9.9.9.9 metric 1
via 8.8.8.8 to 32.42.52.62
43.53.0.0/16 metric 3 via 7.7.7.7 dev eth2
43.53.0.0/16 metric 3 via 7.7.7.7 dev eth2 cwnd 14 mtu lock 9000 initrwnd 20 window lock 10000 initcwnd lock 42 src 1.2.3.4

View file

@ -5,3 +5,5 @@ default via dead::beaf
# routes without "via" are valid
abbe::cafe/64 metric 777
aaaa::cccc/64 from 1111::2222/48 via 3333::4444 src 5555::6666 mtu lock 1450 cwnd 13

View file

@ -1127,6 +1127,15 @@ test_read_wired_static_routes (void)
g_assert_cmpint (nm_ip_route_get_prefix (ip4_route), ==, 32);
g_assert_cmpstr (nm_ip_route_get_next_hop (ip4_route), ==, "192.168.1.7");
g_assert_cmpint (nm_ip_route_get_metric (ip4_route), ==, 3);
nmtst_assert_route_attribute_byte (ip4_route, NM_IP_ROUTE_ATTRIBUTE_TOS, 0x28);
nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_WINDOW, 30000);
nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_CWND, 12);
nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_INITCWND, 13);
nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_INITRWND, 14);
nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_MTU, 9000);
nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, TRUE);
nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, TRUE);
nmtst_assert_route_attribute_string (ip4_route, NM_IP_ROUTE_ATTRIBUTE_PREF_SRC, "1.1.1.1");
g_object_unref (connection);
}
@ -1188,6 +1197,14 @@ test_read_wired_static_routes_legacy (void)
g_assert_cmpint (nm_ip_route_get_prefix (ip4_route), ==, 16);
g_assert_cmpstr (nm_ip_route_get_next_hop (ip4_route), ==, "7.7.7.7");
g_assert_cmpint (nm_ip_route_get_metric (ip4_route), ==, 3);
nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_WINDOW, 10000);
nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_CWND, 14);
nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_INITCWND, 42);
nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_INITRWND, 20);
nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_MTU, 9000);
nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW, TRUE);
nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, TRUE);
nmtst_assert_route_attribute_string (ip4_route, NM_IP_ROUTE_ATTRIBUTE_PREF_SRC, "1.2.3.4");
g_object_unref (connection);
}
@ -1328,7 +1345,7 @@ test_read_wired_ipv6_manual (void)
g_assert_cmpint (nm_ip_address_get_prefix (ip6_addr), ==, 96);
/* Routes */
g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip6), ==, 2);
g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip6), ==, 3);
/* Route #1 */
ip6_route = nm_setting_ip_config_get_route (s_ip6, 0);
g_assert (ip6_route);
@ -1343,6 +1360,17 @@ test_read_wired_ipv6_manual (void)
g_assert_cmpint (nm_ip_route_get_prefix (ip6_route), ==, 64);
g_assert_cmpstr (nm_ip_route_get_next_hop (ip6_route), ==, NULL);
g_assert_cmpint (nm_ip_route_get_metric (ip6_route), ==, 777);
/* Route #3 */
ip6_route = nm_setting_ip_config_get_route (s_ip6, 2);
g_assert (ip6_route);
g_assert_cmpstr (nm_ip_route_get_dest (ip6_route), ==, "aaaa::cccc");
g_assert_cmpint (nm_ip_route_get_prefix (ip6_route), ==, 64);
g_assert_cmpstr (nm_ip_route_get_next_hop (ip6_route), ==, "3333::4444");
nmtst_assert_route_attribute_uint32 (ip6_route, NM_IP_ROUTE_ATTRIBUTE_CWND, 13);
nmtst_assert_route_attribute_uint32 (ip6_route, NM_IP_ROUTE_ATTRIBUTE_MTU, 1450);
nmtst_assert_route_attribute_boolean (ip6_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, TRUE);
nmtst_assert_route_attribute_string (ip6_route, NM_IP_ROUTE_ATTRIBUTE_SRC, "1111::2222/48");
nmtst_assert_route_attribute_string (ip6_route, NM_IP_ROUTE_ATTRIBUTE_PREF_SRC, "5555::6666");
/* DNS Addresses */
g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip6), ==, 2);
@ -3867,6 +3895,12 @@ test_write_wired_static (void)
route6 = nm_ip_route_new (AF_INET6, "::", 128, "2222:aaaa::9999", 1, &error);
g_assert_no_error (error);
nm_ip_route_set_attribute (route6, NM_IP_ROUTE_ATTRIBUTE_TOS, g_variant_new_byte (0xb8));
nm_ip_route_set_attribute (route6, NM_IP_ROUTE_ATTRIBUTE_CWND, g_variant_new_uint32 (100));
nm_ip_route_set_attribute (route6, NM_IP_ROUTE_ATTRIBUTE_MTU, g_variant_new_uint32 (1280));
nm_ip_route_set_attribute (route6, NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, g_variant_new_boolean (TRUE));
nm_ip_route_set_attribute (route6, NM_IP_ROUTE_ATTRIBUTE_SRC, g_variant_new_string ("2222::bbbb/32"));
nm_ip_route_set_attribute (route6, NM_IP_ROUTE_ATTRIBUTE_PREF_SRC, g_variant_new_string ("::42"));
nm_setting_ip_config_add_route (s_ip6, route6);
nm_ip_route_unref (route6);

View file

@ -34,6 +34,7 @@ routes8=1.1.1.8/18,0.0.0.0,
routes9=1.1.1.9/19,0.0.0.0,0
routes10=1.1.1.10/20,,0
routes11=1.1.1.11/21,,21
routes11_options=cwnd=10,lock-cwnd=true,mtu=1430,pref-src=7.7.7.7
ignore-auto-routes=false
ignore-auto-dns=false
@ -58,5 +59,6 @@ route3=6:7:8:9:0:1:2:3/126,,1
route4=7:8:9:0:1:2:3:4/125/::,5
route5=8:9:0:1:2:3:4:5/124,6
route6=8:9:0:1:2:3:4:6/123,,
route6_options=src=abce::/63
ignore-auto-routes=false
ignore-auto-dns=false

View file

@ -224,6 +224,7 @@ test_read_valid_wired_connection (void)
NMSettingWired *s_wired;
NMSettingIPConfig *s_ip4;
NMSettingIPConfig *s_ip6;
NMIPRoute *route;
gs_free_error GError *error = NULL;
const char *mac;
char expected_mac_address[ETH_ALEN] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 };
@ -318,6 +319,15 @@ test_read_valid_wired_connection (void)
check_ip_route (s_ip4, 10, "1.1.1.10", 20, NULL, -1);
check_ip_route (s_ip4, 11, "1.1.1.11", 21, NULL, 21);
/* Route attributes */
route = nm_setting_ip_config_get_route (s_ip4, 11);
g_assert (route);
nmtst_assert_route_attribute_uint32 (route, NM_IP_ROUTE_ATTRIBUTE_CWND, 10);
nmtst_assert_route_attribute_uint32 (route, NM_IP_ROUTE_ATTRIBUTE_MTU, 1430);
nmtst_assert_route_attribute_boolean (route, NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, TRUE);
nmtst_assert_route_attribute_string (route, NM_IP_ROUTE_ATTRIBUTE_PREF_SRC, "7.7.7.7");
/* ===== IPv6 SETTING ===== */
s_ip6 = nm_connection_get_setting_ip6_config (connection);
g_assert (s_ip6);
@ -357,6 +367,11 @@ test_read_valid_wired_connection (void)
check_ip_route (s_ip6, 4, "7:8:9:0:1:2:3:4", 125, NULL, 5);
check_ip_route (s_ip6, 5, "8:9:0:1:2:3:4:5", 124, NULL, 6);
check_ip_route (s_ip6, 6, "8:9:0:1:2:3:4:6", 123, NULL, -1);
/* Route attributes */
route = nm_setting_ip_config_get_route (s_ip6, 6);
g_assert (route);
nmtst_assert_route_attribute_string (route, NM_IP_ROUTE_ATTRIBUTE_SRC, "abce::/63");
}
static void
@ -402,6 +417,7 @@ test_write_wired_connection (void)
NMSettingWired *s_wired;
NMSettingIPConfig *s_ip4;
NMSettingIPConfig *s_ip6;
NMIPRoute *rt;
const char *mac = "99:88:77:66:55:44";
const char *dns1 = "4.2.2.1";
const char *dns2 = "4.2.2.2";
@ -429,6 +445,7 @@ test_write_wired_connection (void)
const char *route6_4 = "5:6:7:8:9:0:1:2";
const char *route6_4_nh = "::";
guint64 timestamp = 0x12345678L;
GError *error = NULL;
connection = nm_simple_connection_new ();
@ -473,7 +490,14 @@ test_write_wired_connection (void)
add_one_ip_route (s_ip4, route1, route1_nh, 24, 3);
add_one_ip_route (s_ip4, route2, route2_nh, 8, 1);
add_one_ip_route (s_ip4, route3, route3_nh, 7, -1);
add_one_ip_route (s_ip4, route4, route4_nh, 6, 4);
rt = nm_ip_route_new (AF_INET, route4, 6, route4_nh, 4, &error);
g_assert_no_error (error);
nm_ip_route_set_attribute (rt, NM_IP_ROUTE_ATTRIBUTE_CWND, g_variant_new_uint32 (10));
nm_ip_route_set_attribute (rt, NM_IP_ROUTE_ATTRIBUTE_MTU, g_variant_new_uint32 (1492));
nm_ip_route_set_attribute (rt, NM_IP_ROUTE_ATTRIBUTE_PREF_SRC, g_variant_new_string ("1.2.3.4"));
g_assert (nm_setting_ip_config_add_route (s_ip4, rt));
nm_ip_route_unref (rt);
/* DNS servers */
nm_setting_ip_config_add_dns (s_ip4, dns1);

View file

@ -37,8 +37,8 @@ build_test_config (void)
config = nm_ip6_config_new (1);
nm_ip6_config_add_address (config, nmtst_platform_ip6_address ("abcd:1234:4321::cdde", "1:2:3:4::5", 64));
nm_ip6_config_add_route (config, nmtst_platform_ip6_route ("abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2"));
nm_ip6_config_add_route (config, nmtst_platform_ip6_route ("2001:abba::", 16, "2001:abba::2234"));
nm_ip6_config_add_route (config, nmtst_platform_ip6_route ("abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2", NULL));
nm_ip6_config_add_route (config, nmtst_platform_ip6_route ("2001:abba::", 16, "2001:abba::2234", NULL));
nm_ip6_config_set_gateway (config, nmtst_inet6_from_string ("3001:abba::3234"));
@ -74,7 +74,7 @@ test_subtract (void)
/* add a couple more things to the test config */
dst = build_test_config ();
nm_ip6_config_add_address (dst, nmtst_platform_ip6_address (expected_addr, NULL, expected_addr_plen));
nm_ip6_config_add_route (dst, nmtst_platform_ip6_route (expected_route_dest, expected_route_plen, expected_route_next_hop));
nm_ip6_config_add_route (dst, nmtst_platform_ip6_route (expected_route_dest, expected_route_plen, expected_route_next_hop, NULL));
expected_ns1 = *nmtst_inet6_from_string ("2222:3333:4444::5555");
nm_ip6_config_add_nameserver (dst, &expected_ns1);
@ -139,7 +139,7 @@ test_compare_with_source (void)
nm_ip6_config_add_address (b, &addr);
/* Route */
route = *nmtst_platform_ip6_route ("abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2");
route = *nmtst_platform_ip6_route ("abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2", NULL);
route.rt_source = NM_IP_CONFIG_SOURCE_USER;
nm_ip6_config_add_route (a, &route);
@ -203,7 +203,7 @@ test_add_route_with_source (void)
a = nm_ip6_config_new (1);
/* Test that a higher priority source is not overwritten */
route = *nmtst_platform_ip6_route ("abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2");
route = *nmtst_platform_ip6_route ("abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2", NULL);
route.rt_source = NM_IP_CONFIG_SOURCE_USER;
nm_ip6_config_add_route (a, &route);

View file

@ -75,16 +75,15 @@ setup_dev1_ip4 (int ifindex)
/* Add some route outside of route manager. The route manager
* should get rid of it upon sync. */
if (!nm_platform_ip4_route_add (NM_PLATFORM_GET,
route.ifindex,
NM_IP_CONFIG_SOURCE_USER,
nmtst_inet4_from_string ("9.0.0.0"),
8,
INADDR_ANY,
0,
10,
route.mss))
g_assert_not_reached ();
nmtstp_ip4_route_add (NM_PLATFORM_GET,
route.ifindex,
NM_IP_CONFIG_SOURCE_USER,
nmtst_inet4_from_string ("9.0.0.0"),
8,
INADDR_ANY,
0,
10,
route.mss);
route.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER);
inet_pton (AF_INET, "6.6.6.0", &route.network);
@ -421,15 +420,15 @@ setup_dev1_ip6 (int ifindex)
/* Add some route outside of route manager. The route manager
* should get rid of it upon sync. */
if (!nm_platform_ip6_route_add (NM_PLATFORM_GET,
ifindex,
NM_IP_CONFIG_SOURCE_USER,
*nmtst_inet6_from_string ("2001:db8:8088::"),
48,
in6addr_any,
10,
0))
g_assert_not_reached ();
nmtstp_ip6_route_add (NM_PLATFORM_GET,
ifindex,
NM_IP_CONFIG_SOURCE_USER,
*nmtst_inet6_from_string ("2001:db8:8088::"),
48,
in6addr_any,
in6addr_any,
10,
0);
route = nmtst_platform_ip6_route_full ("2001:db8:8086::",
48,