summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libnm-core/nm-keyfile.c112
-rw-r--r--libnm-core/nm-setting-ip-config.c351
-rw-r--r--libnm-core/nm-setting-ip-config.h17
-rw-r--r--libnm-core/tests/test-general.c1
-rw-r--r--libnm-core/tests/test-setting.c95
-rw-r--r--libnm/libnm.ver5
6 files changed, 578 insertions, 3 deletions
diff --git a/libnm-core/nm-keyfile.c b/libnm-core/nm-keyfile.c
index 2b77a84463..a541bd556c 100644
--- a/libnm-core/nm-keyfile.c
+++ b/libnm-core/nm-keyfile.c
@@ -541,6 +541,7 @@ typedef struct {
typedef enum {
BUILD_LIST_TYPE_ADDRESSES,
BUILD_LIST_TYPE_ROUTES,
+ BUILD_LIST_TYPE_ROUTING_RULES,
} BuildListType;
static int
@@ -661,6 +662,12 @@ _build_list_create (GKeyFile *keyfile,
else
continue;
break;
+ case BUILD_LIST_TYPE_ROUTING_RULES:
+ if (_build_list_match_key_w_name (s_key, "routing-rule", &key_idx))
+ key_type = 0;
+ else
+ continue;
+ break;
default:
nm_assert_not_reached ();
break;
@@ -760,6 +767,63 @@ ip_address_or_route_parser (KeyfileReaderInfo *info, NMSetting *setting, const c
}
static void
+ip_routing_rule_parser_full (KeyfileReaderInfo *info,
+ const NMMetaSettingInfo *setting_info,
+ const NMSettInfoProperty *property_info,
+ const ParseInfoProperty *pip,
+ NMSetting *setting)
+{
+ const char *setting_name = nm_setting_get_name (setting);
+ gboolean is_ipv6 = nm_streq (setting_name, "ipv6");
+ gs_strfreev char **keys = NULL;
+ gs_free BuildListData *build_list = NULL;
+ gsize i_build_list, build_list_len = 0;
+
+ build_list = _build_list_create (info->keyfile,
+ setting_name,
+ BUILD_LIST_TYPE_ROUTING_RULES,
+ &build_list_len,
+ &keys);
+ if (!build_list)
+ return;
+
+ for (i_build_list = 0; i_build_list < build_list_len; i_build_list++) {
+ nm_auto_unref_ip_routing_rule NMIPRoutingRule *rule = NULL;
+ gs_free char *value = NULL;
+ gs_free_error GError *local = NULL;
+
+ if (_build_list_data_is_shadowed (build_list, build_list_len, i_build_list))
+ continue;
+
+ value = nm_keyfile_plugin_kf_get_string (info->keyfile,
+ setting_name,
+ build_list[i_build_list].s_key,
+ NULL);
+ if (!value)
+ continue;
+
+ rule = nm_ip_routing_rule_from_string (value,
+ ( NM_IP_ROUTING_RULE_AS_STRING_FLAGS_VALIDATE
+ | ( is_ipv6
+ ? NM_IP_ROUTING_RULE_AS_STRING_FLAGS_AF_INET6
+ : NM_IP_ROUTING_RULE_AS_STRING_FLAGS_AF_INET)),
+ NULL,
+ &local);
+ if (!rule) {
+ handle_warn (info, property_info->name, NM_KEYFILE_WARN_SEVERITY_WARN,
+ _("invalid value for \"%s\": %s"),
+ build_list[i_build_list].s_key,
+ local->message);
+ if (info->error)
+ return;
+ continue;
+ }
+
+ nm_setting_ip_config_add_routing_rule (NM_SETTING_IP_CONFIG (setting), rule);
+ }
+}
+
+static void
ip_dns_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
{
int addr_family;
@@ -1963,6 +2027,40 @@ bridge_vlan_writer (KeyfileWriterInfo *info,
}
static void
+ip_routing_rule_writer_full (KeyfileWriterInfo *info,
+ const NMMetaSettingInfo *setting_info,
+ const NMSettInfoProperty *property_info,
+ const ParseInfoProperty *pip,
+ NMSetting *setting)
+{
+ const char *setting_name = nm_setting_get_name (setting);
+ NMSettingIPConfig *s_ip = NM_SETTING_IP_CONFIG (setting);
+ guint i, j, n;
+ char key_name_full[100] = "routing-rule";
+ char *key_name_num = &key_name_full[NM_STRLEN ("routing-rule")];
+
+ n = nm_setting_ip_config_get_num_routing_rules (s_ip);
+ j = 0;
+ for (i = 0; i < n; i++) {
+ NMIPRoutingRule *rule = nm_setting_ip_config_get_routing_rule (s_ip, i);
+ gs_free char *str = NULL;
+
+ str = nm_ip_routing_rule_to_string (rule,
+ NM_IP_ROUTING_RULE_AS_STRING_FLAGS_NONE,
+ NULL,
+ NULL);
+ if (!str)
+ continue;
+
+ sprintf (key_name_num, "%u", ++j);
+ nm_keyfile_plugin_kf_set_string (info->keyfile,
+ setting_name,
+ key_name_full,
+ str);
+ }
+}
+
+static void
qdisc_writer (KeyfileWriterInfo *info,
NMSetting *setting,
const char *key,
@@ -2463,6 +2561,13 @@ static const ParseInfoSetting *const parse_infos[_NM_META_SETTING_TYPE_NUM] = {
.parser = ip_address_or_route_parser,
.writer = route_writer,
),
+ PARSE_INFO_PROPERTY (NM_SETTING_IP_CONFIG_ROUTING_RULES,
+ .parser_no_check_key = TRUE,
+ .parser_full = ip_routing_rule_parser_full,
+ .writer_full = ip_routing_rule_writer_full,
+ .has_parser_full = TRUE,
+ .has_writer_full = TRUE,
+ ),
),
),
PARSE_INFO_SETTING (NM_META_SETTING_TYPE_IP6_CONFIG,
@@ -2491,6 +2596,13 @@ static const ParseInfoSetting *const parse_infos[_NM_META_SETTING_TYPE_NUM] = {
.parser = ip_address_or_route_parser,
.writer = route_writer,
),
+ PARSE_INFO_PROPERTY (NM_SETTING_IP_CONFIG_ROUTING_RULES,
+ .parser_no_check_key = TRUE,
+ .parser_full = ip_routing_rule_parser_full,
+ .writer_full = ip_routing_rule_writer_full,
+ .has_parser_full = TRUE,
+ .has_writer_full = TRUE,
+ ),
),
),
PARSE_INFO_SETTING (NM_META_SETTING_TYPE_SERIAL,
diff --git a/libnm-core/nm-setting-ip-config.c b/libnm-core/nm-setting-ip-config.c
index b4b50e51c1..53d55c57cd 100644
--- a/libnm-core/nm-setting-ip-config.c
+++ b/libnm-core/nm-setting-ip-config.c
@@ -3533,6 +3533,7 @@ typedef struct {
int dns_priority;
GPtrArray *addresses; /* array of NMIPAddress */
GPtrArray *routes; /* array of NMIPRoute */
+ GPtrArray *routing_rules;
gint64 route_metric;
guint32 route_table;
char *gateway;
@@ -4434,6 +4435,225 @@ nm_setting_ip_config_get_route_table (NMSettingIPConfig *setting)
return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->route_table;
}
+/*****************************************************************************/
+
+static void
+_routing_rules_notify (NMSettingIPConfig *setting)
+{
+ _nm_setting_emit_property_changed (NM_SETTING (setting));
+}
+
+/**
+ * nm_setting_ip_config_get_num_routing_rules:
+ * @setting: the #NMSettingIPConfig
+ *
+ * Returns: the number of configured routing rules
+ *
+ * Since: 1.18
+ **/
+guint
+nm_setting_ip_config_get_num_routing_rules (NMSettingIPConfig *setting)
+{
+ NMSettingIPConfigPrivate *priv;
+
+ g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), 0);
+
+ priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
+ return priv->routing_rules ? priv->routing_rules->len : 0u;
+}
+
+/**
+ * nm_setting_ip_config_get_routing_rule:
+ * @setting: the #NMSettingIPConfig
+ * @idx: index number of the routing_rule to return
+ *
+ * Returns: (transfer none): the routing rule at index @idx
+ *
+ * Since: 1.18
+ **/
+NMIPRoutingRule *
+nm_setting_ip_config_get_routing_rule (NMSettingIPConfig *setting, guint idx)
+{
+ NMSettingIPConfigPrivate *priv;
+
+ g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), NULL);
+
+ priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
+
+ g_return_val_if_fail (priv->routing_rules && idx < priv->routing_rules->len, NULL);
+
+ return priv->routing_rules->pdata[idx];
+}
+
+/**
+ * nm_setting_ip_config_add_routing_rule:
+ * @setting: the #NMSettingIPConfig
+ * @routing_rule: the #NMIPRoutingRule to add. The address family
+ * of the added rule must be compatible with the setting.
+ *
+ * Appends a new routing-rule and associated information to the setting. The
+ * given routing rules gets sealed and the reference count is incremented.
+ * The function does not check whether an identical rule already exists
+ * and always appends the rule to the end of the list.
+ *
+ * Since: 1.18
+ **/
+void
+nm_setting_ip_config_add_routing_rule (NMSettingIPConfig *setting,
+ NMIPRoutingRule *routing_rule)
+{
+ NMSettingIPConfigPrivate *priv;
+
+ g_return_if_fail (NM_IS_SETTING_IP_CONFIG (setting));
+ g_return_if_fail (NM_IS_IP_ROUTING_RULE (routing_rule, TRUE));
+ g_return_if_fail (_ip_routing_rule_get_addr_family (routing_rule) == NM_SETTING_IP_CONFIG_GET_FAMILY (setting));
+
+ priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
+
+ if (!priv->routing_rules)
+ priv->routing_rules = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_routing_rule_unref);
+
+ nm_ip_routing_rule_seal (routing_rule);
+ g_ptr_array_add (priv->routing_rules, nm_ip_routing_rule_ref (routing_rule));
+ _routing_rules_notify (setting);
+}
+
+/**
+ * nm_setting_ip_config_remove_routing_rule:
+ * @setting: the #NMSettingIPConfig
+ * @idx: index number of the routing_rule
+ *
+ * Removes the routing_rule at index @idx.
+ *
+ * Since: 1.18
+ **/
+void
+nm_setting_ip_config_remove_routing_rule (NMSettingIPConfig *setting,
+ guint idx)
+{
+ NMSettingIPConfigPrivate *priv;
+
+ g_return_if_fail (NM_IS_SETTING_IP_CONFIG (setting));
+
+ priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
+ g_return_if_fail (priv->routing_rules && idx < priv->routing_rules->len);
+
+ g_ptr_array_remove_index (priv->routing_rules, idx);
+ _routing_rules_notify (setting);
+}
+
+/**
+ * nm_setting_ip_config_clear_routing_rules:
+ * @setting: the #NMSettingIPConfig
+ *
+ * Removes all configured routing rules.
+ *
+ * Since: 1.18
+ **/
+void
+nm_setting_ip_config_clear_routing_rules (NMSettingIPConfig *setting)
+{
+ NMSettingIPConfigPrivate *priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
+
+ g_return_if_fail (NM_IS_SETTING_IP_CONFIG (setting));
+
+ if ( priv->routing_rules
+ && priv->routing_rules->len > 0) {
+ g_ptr_array_set_size (priv->routing_rules, 0);
+ _routing_rules_notify (setting);
+ }
+}
+
+static GVariant *
+_routing_rules_dbus_only_synth (const NMSettInfoSetting *sett_info,
+ guint property_idx,
+ NMConnection *connection,
+ NMSetting *setting,
+ NMConnectionSerializationFlags flags)
+{
+ NMSettingIPConfig *self = NM_SETTING_IP_CONFIG (setting);
+ NMSettingIPConfigPrivate *priv;
+ GVariantBuilder builder;
+ gboolean any = FALSE;
+ guint i;
+
+ priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (self);
+
+ if ( !priv->routing_rules
+ || priv->routing_rules->len == 0)
+ return NULL;
+
+ for (i = 0; i < priv->routing_rules->len; i++) {
+ GVariant *variant;
+
+ variant = nm_ip_routing_rule_to_dbus (priv->routing_rules->pdata[i]);
+ if (!variant)
+ continue;
+
+ if (!any) {
+ any = TRUE;
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
+ }
+ g_variant_builder_add (&builder, "@a{sv}", variant);
+ }
+
+ return any ? g_variant_builder_end (&builder) : NULL;
+}
+
+static gboolean
+_routing_rules_dbus_only_set (NMSetting *setting,
+ GVariant *connection_dict,
+ const char *property,
+ GVariant *value,
+ NMSettingParseFlags parse_flags,
+ GError **error)
+{
+ GVariantIter iter_rules;
+ GVariant *rule_var;
+ guint i_rule;
+ gboolean success = FALSE;
+ gboolean rules_changed = FALSE;
+
+ nm_assert (g_variant_is_of_type (value, G_VARIANT_TYPE ("aa{sv}")));
+
+ g_variant_iter_init (&iter_rules, value);
+
+ i_rule = 0;
+ while (g_variant_iter_next (&iter_rules, "@a{sv}", &rule_var)) {
+ _nm_unused gs_unref_variant GVariant *rule_var_unref = rule_var;
+ nm_auto_unref_ip_routing_rule NMIPRoutingRule *rule = NULL;
+ gs_free_error GError *local = NULL;
+
+ i_rule++;
+
+ rule = nm_ip_routing_rule_from_dbus (rule_var,
+ NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT),
+ &local);
+ if (!rule) {
+ if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)) {
+ g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_PROPERTY,
+ _("rule #%u is invalid: %s"),
+ i_rule,
+ local->message);
+ goto out;
+ }
+ continue;
+ }
+
+ nm_setting_ip_config_add_routing_rule (NM_SETTING_IP_CONFIG (setting), rule);
+ rules_changed = TRUE;
+ }
+
+ success = TRUE;
+
+out:
+ if (rules_changed)
+ _routing_rules_notify (NM_SETTING_IP_CONFIG (setting));
+ return success;
+}
+
+/*****************************************************************************/
+
/**
* nm_setting_ip_config_get_ignore_auto_routes:
* @setting: the #NMSettingIPConfig
@@ -4720,6 +4940,33 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
}
}
+ if (priv->routing_rules) {
+ for (i = 0; i < priv->routing_rules->len; i++) {
+ NMIPRoutingRule *rule = priv->routing_rules->pdata[i];
+ gs_free_error GError *local = NULL;
+
+ if (_ip_routing_rule_get_addr_family (rule) != NM_SETTING_IP_CONFIG_GET_FAMILY (setting)) {
+ g_set_error (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("%u. rule has wrong address-family"),
+ i + 1);
+ g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_IP_CONFIG_ROUTING_RULES);
+ return FALSE;
+ }
+ if (!nm_ip_routing_rule_validate (rule, &local)) {
+ g_set_error (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("%u. rule is invalid: %s"),
+ i + 1,
+ local->message);
+ g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_IP_CONFIG_ROUTES);
+ return FALSE;
+ }
+ }
+ }
+
if (priv->gateway && priv->never_default) {
g_set_error (error,
NM_CONNECTION_ERROR,
@@ -4774,6 +5021,24 @@ compare_property (const NMSettInfoSetting *sett_info,
return TRUE;
}
+ if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_IP_CONFIG_ROUTING_RULES)) {
+ if (other) {
+ guint n;
+
+ a_priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
+ b_priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (other);
+
+ n = (a_priv->routing_rules) ? a_priv->routing_rules->len : 0u;
+ if (n != (b_priv->routing_rules ? b_priv->routing_rules->len : 0u))
+ return FALSE;
+ for (i = 0; i < n; i++) {
+ if (nm_ip_routing_rule_cmp (a_priv->routing_rules->pdata[i], b_priv->routing_rules->pdata[i]) != 0)
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+
return NM_SETTING_CLASS (nm_setting_ip_config_parent_class)->compare_property (sett_info,
property_idx,
setting,
@@ -4781,6 +5046,72 @@ compare_property (const NMSettInfoSetting *sett_info,
flags);
}
+static void
+duplicate_copy_properties (const NMSettInfoSetting *sett_info,
+ NMSetting *src,
+ NMSetting *dst)
+{
+ NMSettingIPConfigPrivate *priv_src = NM_SETTING_IP_CONFIG_GET_PRIVATE (src);
+ NMSettingIPConfigPrivate *priv_dst = NM_SETTING_IP_CONFIG_GET_PRIVATE (dst);
+ guint i;
+ gboolean changed = FALSE;
+
+ NM_SETTING_CLASS (nm_setting_ip_config_parent_class)->duplicate_copy_properties (sett_info,
+ src,
+ dst);
+
+ if ( priv_dst->routing_rules
+ && priv_dst->routing_rules->len > 0) {
+ changed = TRUE;
+ g_ptr_array_set_size (priv_dst->routing_rules, 0);
+ }
+ if ( priv_src->routing_rules
+ && priv_src->routing_rules->len > 0) {
+ changed = TRUE;
+ if (!priv_dst->routing_rules)
+ priv_dst->routing_rules = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_routing_rule_unref);
+ for (i = 0; i < priv_src->routing_rules->len; i++) {
+ g_ptr_array_add (priv_dst->routing_rules,
+ nm_ip_routing_rule_ref (priv_src->routing_rules->pdata[i]));
+ }
+ }
+ if (changed)
+ _routing_rules_notify (NM_SETTING_IP_CONFIG (dst));
+}
+
+static void
+enumerate_values (const NMSettInfoProperty *property_info,
+ NMSetting *setting,
+ NMSettingValueIterFn func,
+ gpointer user_data)
+{
+ if (nm_streq (property_info->name, NM_SETTING_IP_CONFIG_ROUTING_RULES)) {
+ NMSettingIPConfigPrivate *priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
+ nm_auto_unset_gvalue GValue value = G_VALUE_INIT;
+ GPtrArray *ptr = NULL;
+ guint i;
+
+ if (priv->routing_rules && priv->routing_rules->len > 0) {
+ ptr = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_routing_rule_unref);
+ for (i = 0; i < priv->routing_rules->len; i++)
+ g_ptr_array_add (ptr, nm_ip_routing_rule_ref (priv->routing_rules->pdata[i]));
+ }
+ g_value_init (&value, G_TYPE_PTR_ARRAY);
+ g_value_take_boxed (&value, ptr);
+ func (setting,
+ property_info->name,
+ &value,
+ 0,
+ user_data);
+ return;
+ }
+
+ NM_SETTING_CLASS (nm_setting_ip_config_parent_class)->enumerate_values (property_info,
+ setting,
+ func,
+ user_data);
+}
+
/*****************************************************************************/
static gboolean
@@ -4813,6 +5144,18 @@ _nm_sett_info_property_override_create_array_ip_config (void)
ip_gateway_set,
NULL);
+ /* ---dbus---
+ * property: routing-rules
+ * format: array of 'a{sv}'
+ * description: Array of dictionaries for routing rules.
+ * ---end---
+ */
+ _properties_override_add_dbus_only (properties_override,
+ NM_SETTING_IP_CONFIG_ROUTING_RULES,
+ G_VARIANT_TYPE ("aa{sv}"),
+ _routing_rules_dbus_only_synth,
+ _routing_rules_dbus_only_set);
+
return properties_override;
}
@@ -5020,6 +5363,8 @@ finalize (GObject *object)
g_ptr_array_unref (priv->dns_options);
g_ptr_array_unref (priv->addresses);
g_ptr_array_unref (priv->routes);
+ if (priv->routing_rules)
+ g_ptr_array_unref (priv->routing_rules);
G_OBJECT_CLASS (nm_setting_ip_config_parent_class)->finalize (object);
}
@@ -5036,8 +5381,10 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *klass)
object_class->set_property = set_property;
object_class->finalize = finalize;
- setting_class->verify = verify;
- setting_class->compare_property = compare_property;
+ setting_class->verify = verify;
+ setting_class->compare_property = compare_property;
+ setting_class->duplicate_copy_properties = duplicate_copy_properties;
+ setting_class->enumerate_values = enumerate_values;
/**
* NMSettingIPConfig:method:
diff --git a/libnm-core/nm-setting-ip-config.h b/libnm-core/nm-setting-ip-config.h
index 0522ea1991..09b80f72a9 100644
--- a/libnm-core/nm-setting-ip-config.h
+++ b/libnm-core/nm-setting-ip-config.h
@@ -334,6 +334,9 @@ char *nm_ip_routing_rule_to_string (const NMIPRoutingRule *self,
#define NM_SETTING_IP_CONFIG_DAD_TIMEOUT "dad-timeout"
#define NM_SETTING_IP_CONFIG_DHCP_TIMEOUT "dhcp-timeout"
+/* these are not real GObject properties. */
+#define NM_SETTING_IP_CONFIG_ROUTING_RULES "routing-rules"
+
#define NM_SETTING_DNS_OPTION_DEBUG "debug"
#define NM_SETTING_DNS_OPTION_NDOTS "ndots"
#define NM_SETTING_DNS_OPTION_TIMEOUT "timeout"
@@ -436,6 +439,20 @@ gint64 nm_setting_ip_config_get_route_metric (NMSettingIPConfig
NM_AVAILABLE_IN_1_10
guint32 nm_setting_ip_config_get_route_table (NMSettingIPConfig *setting);
+NM_AVAILABLE_IN_1_18
+guint nm_setting_ip_config_get_num_routing_rules (NMSettingIPConfig *setting);
+NM_AVAILABLE_IN_1_18
+NMIPRoutingRule *nm_setting_ip_config_get_routing_rule (NMSettingIPConfig *setting,
+ guint idx);
+NM_AVAILABLE_IN_1_18
+void nm_setting_ip_config_add_routing_rule (NMSettingIPConfig *setting,
+ NMIPRoutingRule *routing_rule);
+NM_AVAILABLE_IN_1_18
+void nm_setting_ip_config_remove_routing_rule (NMSettingIPConfig *setting,
+ guint idx);
+NM_AVAILABLE_IN_1_18
+void nm_setting_ip_config_clear_routing_rules (NMSettingIPConfig *setting);
+
gboolean nm_setting_ip_config_get_ignore_auto_routes (NMSettingIPConfig *setting);
gboolean nm_setting_ip_config_get_ignore_auto_dns (NMSettingIPConfig *setting);
diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c
index 6d5eeb2810..98e5837176 100644
--- a/libnm-core/tests/test-general.c
+++ b/libnm-core/tests/test-general.c
@@ -2710,6 +2710,7 @@ test_connection_diff_a_only (void)
{ NM_SETTING_IP_CONFIG_ROUTES, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_IP_CONFIG_ROUTE_METRIC, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_IP_CONFIG_ROUTE_TABLE, NM_SETTING_DIFF_RESULT_IN_A },
+ { NM_SETTING_IP_CONFIG_ROUTING_RULES, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID, NM_SETTING_DIFF_RESULT_IN_A },
diff --git a/libnm-core/tests/test-setting.c b/libnm-core/tests/test-setting.c
index f9d87eb6c2..bd6b4e7fd2 100644
--- a/libnm-core/tests/test-setting.c
+++ b/libnm-core/tests/test-setting.c
@@ -2362,7 +2362,16 @@ test_roundtrip_conversion (gconstpointer test_data)
NMSettingConnection *s_con = NULL;
NMSettingWired *s_eth = NULL;
NMSettingWireGuard *s_wg = NULL;
+ union {
+ struct {
+ NMSettingIPConfig *s_6;
+ NMSettingIPConfig *s_4;
+ };
+ NMSettingIPConfig *s_x[2];
+ } s_ip;
+ int is_ipv4;
guint i;
+ gboolean success;
switch (MODE) {
case 0:
@@ -2549,6 +2558,89 @@ test_roundtrip_conversion (gconstpointer test_data)
_rndt_wg_peers_assert_equal (s_wg, wg_peers, TRUE, TRUE, FALSE);
break;
+ case 3:
+ con = nmtst_create_minimal_connection (ID, UUID, NM_SETTING_WIRED_SETTING_NAME, &s_con);
+ g_object_set (s_con,
+ NM_SETTING_CONNECTION_INTERFACE_NAME,
+ INTERFACE_NAME,
+ NULL);
+ nmtst_connection_normalize (con);
+
+ s_eth = NM_SETTING_WIRED (nm_connection_get_setting (con, NM_TYPE_SETTING_WIRED));
+ g_assert (NM_IS_SETTING_WIRED (s_eth));
+
+ g_object_set (s_eth,
+ NM_SETTING_WIRED_MTU,
+ ETH_MTU,
+ NULL);
+
+ s_ip.s_4 = NM_SETTING_IP_CONFIG (nm_connection_get_setting (con, NM_TYPE_SETTING_IP4_CONFIG));
+ g_assert (NM_IS_SETTING_IP4_CONFIG (s_ip.s_4));
+
+ s_ip.s_6 = NM_SETTING_IP_CONFIG (nm_connection_get_setting (con, NM_TYPE_SETTING_IP6_CONFIG));
+ g_assert (NM_IS_SETTING_IP6_CONFIG (s_ip.s_6));
+
+ for (is_ipv4 = 0; is_ipv4 < 2; is_ipv4++) {
+ g_assert (NM_IS_SETTING_IP_CONFIG (s_ip.s_x[is_ipv4]));
+ for (i = 0; i < 3; i++) {
+ char addrstr[NM_UTILS_INET_ADDRSTRLEN];
+
+ nm_auto_unref_ip_routing_rule NMIPRoutingRule *rr = NULL;
+
+ rr = nm_ip_routing_rule_new (is_ipv4 ? AF_INET : AF_INET6);
+ nm_ip_routing_rule_set_priority (rr, i + 1);
+ if (i > 0) {
+ if (is_ipv4)
+ nm_sprintf_buf (addrstr, "192.168.%u.0", i);
+ else
+ nm_sprintf_buf (addrstr, "1:2:3:%x::", 10 + i);
+ nm_ip_routing_rule_set_from (rr, addrstr, is_ipv4 ? 24 + i : 64 + i);
+ }
+ nm_ip_routing_rule_set_table (rr, 1000 + i);
+
+ success = nm_ip_routing_rule_validate (rr, &error);
+ nmtst_assert_success (success, error);
+
+ nm_setting_ip_config_add_routing_rule (s_ip.s_x[is_ipv4], rr);
+ }
+ }
+
+ g_ptr_array_add (kf_data_arr,
+ g_strdup_printf ("[connection]\n"
+ "id=%s\n"
+ "uuid=%s\n"
+ "type=ethernet\n"
+ "interface-name=%s\n"
+ "permissions=\n"
+ "\n"
+ "[ethernet]\n"
+ "mac-address-blacklist=\n"
+ "%s" /* mtu */
+ "\n"
+ "[ipv4]\n"
+ "dns-search=\n"
+ "method=auto\n"
+ "routing-rule1=priority 1 from 0.0.0.0/0 table 1000\n"
+ "routing-rule2=priority 2 from 192.168.1.0/25 table 1001\n"
+ "routing-rule3=priority 3 from 192.168.2.0/26 table 1002\n"
+ "\n"
+ "[ipv6]\n"
+ "addr-gen-mode=stable-privacy\n"
+ "dns-search=\n"
+ "method=auto\n"
+ "routing-rule1=priority 1 from ::/0 table 1000\n"
+ "routing-rule2=priority 2 from 1:2:3:b::/65 table 1001\n"
+ "routing-rule3=priority 3 from 1:2:3:c::/66 table 1002\n"
+ "",
+ ID,
+ UUID,
+ INTERFACE_NAME,
+ (ETH_MTU != 0)
+ ? nm_sprintf_bufa (100, "mtu=%u\n", ETH_MTU)
+ : ""));
+
+ break;
+
default:
g_assert_not_reached ();
}
@@ -2951,9 +3043,10 @@ main (int argc, char **argv)
g_test_add_func ("/libnm/settings/team-port/sycn_from_config_full", test_team_port_full_config);
#endif
- g_test_add_data_func ("/libnm/settings/roundtrip-conversion/general/0", GINT_TO_POINTER (0), test_roundtrip_conversion);
+ g_test_add_data_func ("/libnm/settings/roundtrip-conversion/general/0", GINT_TO_POINTER (0), test_roundtrip_conversion);
g_test_add_data_func ("/libnm/settings/roundtrip-conversion/wireguard/1", GINT_TO_POINTER (1), test_roundtrip_conversion);
g_test_add_data_func ("/libnm/settings/roundtrip-conversion/wireguard/2", GINT_TO_POINTER (2), test_roundtrip_conversion);
+ g_test_add_data_func ("/libnm/settings/roundtrip-conversion/general/3", GINT_TO_POINTER (3), test_roundtrip_conversion);
g_test_add_data_func ("/libnm/settings/routing-rule/1", GINT_TO_POINTER (0), test_routing_rule);
diff --git a/libnm/libnm.ver b/libnm/libnm.ver
index 20adc91c78..ac8c7b97cf 100644
--- a/libnm/libnm.ver
+++ b/libnm/libnm.ver
@@ -1595,4 +1595,9 @@ global:
nm_setting_bridge_port_remove_vlan_by_vid;
nm_setting_bridge_remove_vlan;
nm_setting_bridge_remove_vlan_by_vid;
+ nm_setting_ip_config_add_routing_rule;
+ nm_setting_ip_config_clear_routing_rules;
+ nm_setting_ip_config_get_num_routing_rules;
+ nm_setting_ip_config_get_routing_rule;
+ nm_setting_ip_config_remove_routing_rule;
} libnm_1_16_0;