summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBeniamino Galvani <bgalvani@redhat.com>2015-12-01 17:45:27 +0100
committerBeniamino Galvani <bgalvani@redhat.com>2015-12-01 17:45:27 +0100
commit193bf9291831729f0f75e018104423ffa4e5f8aa (patch)
treec8c75adce9b2f6d451253537fd25cd3a570540ea
parent604711488d92962868fbf960c7d201f6b6842a2f (diff)
parent818f7f57243feb31ac9089d1f787e70ff9dc63a6 (diff)
downloadNetworkManager-193bf9291831729f0f75e018104423ffa4e5f8aa.tar.gz
merge: branch 'bg/device-creation-ip-tunnel-bgo758047'
Add support for creating IP tunnel interfaces. https://bugzilla.gnome.org/show_bug.cgi?id=758047
-rw-r--r--clients/cli/connections.c130
-rw-r--r--clients/cli/nmcli-completion2
-rw-r--r--clients/cli/settings.c195
-rw-r--r--introspection/Makefile.am6
-rw-r--r--introspection/nm-device-ip-tunnel.xml (renamed from introspection/nm-device-gre.xml)55
-rw-r--r--libnm-core/Makefile.libnm-core2
-rw-r--r--libnm-core/nm-connection.c21
-rw-r--r--libnm-core/nm-connection.h2
-rw-r--r--libnm-core/nm-core-internal.h1
-rw-r--r--libnm-core/nm-core-types.h1
-rw-r--r--libnm-core/nm-dbus-interface.h33
-rw-r--r--libnm-core/nm-setting-ip-tunnel.c724
-rw-r--r--libnm-core/nm-setting-ip-tunnel.h95
-rw-r--r--libnm-core/nm-utils.c52
-rw-r--r--libnm-core/nm-utils.h3
-rw-r--r--libnm-core/tests/test-general.c21
-rw-r--r--libnm-glib/nm-device.c1
-rw-r--r--libnm-util/NetworkManager.h2
-rw-r--r--libnm/Makefile.am2
-rw-r--r--libnm/NetworkManager.h1
-rw-r--r--libnm/libnm.ver26
-rw-r--r--libnm/nm-device-ip-tunnel.c544
-rw-r--r--libnm/nm-device-ip-tunnel.h90
-rw-r--r--libnm/nm-device.c3
-rw-r--r--libnm/nm-types.h1
-rw-r--r--po/POTFILES.in3
-rw-r--r--src/Makefile.am4
-rw-r--r--src/devices/nm-device-gre.c287
-rw-r--r--src/devices/nm-device-gre.h53
-rw-r--r--src/devices/nm-device-ip-tunnel.c971
-rw-r--r--src/devices/nm-device-ip-tunnel.h60
-rw-r--r--src/devices/nm-device.c2
-rw-r--r--src/nm-types.h6
-rw-r--r--src/platform/nm-linux-platform.c403
-rw-r--r--src/platform/nm-platform.c328
-rw-r--r--src/platform/nm-platform.h63
-rw-r--r--src/platform/nmp-object.c27
-rw-r--r--src/platform/nmp-object.h21
-rw-r--r--src/platform/tests/test-common.c134
-rw-r--r--src/platform/tests/test-common.h13
-rw-r--r--src/platform/tests/test-link.c114
-rw-r--r--src/tests/Makefile.am2
42 files changed, 4119 insertions, 385 deletions
diff --git a/clients/cli/connections.c b/clients/cli/connections.c
index bb07552f9c..659815a2f6 100644
--- a/clients/cli/connections.c
+++ b/clients/cli/connections.c
@@ -116,6 +116,7 @@ extern NmcOutputField nmc_fields_setting_team[];
extern NmcOutputField nmc_fields_setting_team_port[];
extern NmcOutputField nmc_fields_setting_dcb[];
extern NmcOutputField nmc_fields_setting_tun[];
+extern NmcOutputField nmc_fields_setting_ip_tunnel[];
/* Available settings for 'connection show <con>' - profile part */
static NmcOutputField nmc_fields_settings_names[] = {
@@ -145,6 +146,7 @@ static NmcOutputField nmc_fields_settings_names[] = {
SETTING_FIELD (NM_SETTING_TEAM_PORT_SETTING_NAME, nmc_fields_setting_team_port + 1), /* 23 */
SETTING_FIELD (NM_SETTING_DCB_SETTING_NAME, nmc_fields_setting_dcb + 1), /* 24 */
SETTING_FIELD (NM_SETTING_TUN_SETTING_NAME, nmc_fields_setting_tun + 1), /* 25 */
+ SETTING_FIELD (NM_SETTING_IP_TUNNEL_SETTING_NAME, nmc_fields_setting_ip_tunnel + 1), /* 26 */
{NULL, NULL, 0, NULL, NULL, FALSE, FALSE, 0}
};
#define NMC_FIELDS_SETTINGS_NAMES_ALL_X NM_SETTING_CONNECTION_SETTING_NAME","\
@@ -171,7 +173,8 @@ static NmcOutputField nmc_fields_settings_names[] = {
NM_SETTING_TEAM_SETTING_NAME","\
NM_SETTING_TEAM_PORT_SETTING_NAME"," \
NM_SETTING_DCB_SETTING_NAME"," \
- NM_SETTING_TUN_SETTING_NAME
+ NM_SETTING_TUN_SETTING_NAME"," \
+ NM_SETTING_IP_TUNNEL_SETTING_NAME
#define NMC_FIELDS_SETTINGS_NAMES_ALL NMC_FIELDS_SETTINGS_NAMES_ALL_X
/* Active connection data */
@@ -2757,6 +2760,14 @@ static const NameItem nmc_tun_settings [] = {
{ NULL, NULL, NULL, FALSE }
};
+static const NameItem nmc_ip_tunnel_settings [] = {
+ { NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL, TRUE },
+ { NM_SETTING_IP_TUNNEL_SETTING_NAME, NULL, NULL, TRUE },
+ { NM_SETTING_IP4_CONFIG_SETTING_NAME, NULL, NULL, FALSE },
+ { NM_SETTING_IP6_CONFIG_SETTING_NAME, NULL, NULL, FALSE },
+ { NULL, NULL, NULL, FALSE }
+};
+
/* Available connection types */
static const NameItem nmc_valid_connection_types[] = {
{ NM_SETTING_GENERIC_SETTING_NAME, NULL, nmc_generic_settings },
@@ -2779,6 +2790,7 @@ static const NameItem nmc_valid_connection_types[] = {
{ "team-slave", NULL, nmc_team_slave_settings },
{ "bridge-slave", NULL, nmc_bridge_slave_settings },
{ NM_SETTING_TUN_SETTING_NAME, NULL, nmc_tun_settings },
+ { NM_SETTING_IP_TUNNEL_SETTING_NAME, NULL, nmc_ip_tunnel_settings },
{ NULL, NULL, NULL }
};
@@ -4383,6 +4395,31 @@ do_questionnaire_tun (char **user, char **group,
}
}
+static void
+do_questionnaire_ip_tunnel (char **local)
+{
+ gboolean once_more;
+
+ /* Ask for optional 'ip-tunnel' arguments. */
+ if (!want_provide_opt_args (_("IP Tunnel"), 1))
+ return;
+
+ if (!*local) {
+ do {
+ *local = nmc_readline (_("Local endpoint [none]: "));
+ if (!*local)
+ break;
+ once_more = !nm_utils_ipaddr_valid (AF_INET, *local)
+ && !nm_utils_ipaddr_valid (AF_INET6, *local);
+ if (once_more) {
+ g_print (_("Error: 'local': '%s' is not valid; must be an IP address\n"),
+ *local);
+ g_free (*local);
+ }
+ } while (once_more);
+ }
+}
+
static gboolean
read_connection_properties (NMConnection *connection,
int argc,
@@ -4594,6 +4631,7 @@ complete_connection_by_type (NMConnection *connection,
NMSettingOlpcMesh *s_olpc_mesh;
NMSettingAdsl *s_adsl;
NMSettingTun *s_tun;
+ NMSettingIPTunnel *s_ip_tunnel;
const char *slave_type;
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
@@ -5813,6 +5851,96 @@ cleanup_tun:
g_free (multi_queue);
if (!success)
return FALSE;
+
+ } else if (!strcmp (con_type, NM_SETTING_IP_TUNNEL_SETTING_NAME)) {
+ /* Build up the settings required for 'ip-tunnel' */
+ const char *mode_c = NULL, *local_c = NULL, *remote_c = NULL;
+ char *mode_ask = NULL, *remote_ask = NULL, *local = NULL;
+ gboolean success = FALSE;
+ NMIPTunnelMode mode_enum;
+ nmc_arg_t exp_args[] = { {"mode", TRUE, &mode_c, !ask},
+ {"local", TRUE, &local_c, FALSE},
+ {"remote", TRUE, &remote_c, !ask},
+ {NULL} };
+
+ if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
+ return FALSE;
+
+ if (!mode_c && ask)
+ mode_c = mode_ask = nmc_readline (_("Tunnel mode: "));
+ if (!mode_c) {
+ g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: 'mode' is required."));
+ goto cleanup_tunnel;
+ }
+
+ if (!remote_c && ask)
+ remote_c = remote_ask = nmc_readline (_("Remote endpoint: "));
+ if (!remote_c) {
+ g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: 'remote' is required."));
+ goto cleanup_tunnel;
+ }
+
+ if (!nm_utils_enum_from_str (nm_ip_tunnel_mode_get_type (),
+ mode_c, (int *) &mode_enum, NULL)) {
+ gs_free const char **values = NULL;
+ gs_free char *values_str = NULL;
+
+ values = nm_utils_enum_get_values (nm_ip_tunnel_mode_get_type (),
+ NM_IP_TUNNEL_MODE_UKNOWN + 1,
+ G_MAXINT);
+ values_str = g_strjoinv (",", (char **) values);
+ g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: 'mode': '%s' is not valid, use one of %s"),
+ mode_c, values_str);
+ goto cleanup_tunnel;
+ }
+
+ if ( !nm_utils_ipaddr_valid (AF_INET, remote_c)
+ && !nm_utils_ipaddr_valid (AF_INET6, remote_c)) {
+ g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: 'remote': '%s' is not valid; must be an IP address"),
+ remote_c);
+ goto cleanup_tunnel;
+ }
+
+ local = g_strdup (local_c);
+ if (ask)
+ do_questionnaire_ip_tunnel (&local);
+
+ if ( local
+ && !nm_utils_ipaddr_valid (AF_INET, local)
+ && !nm_utils_ipaddr_valid (AF_INET6, local)) {
+ g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: 'local': '%s' is not valid; must be an IP address"),
+ local);
+ goto cleanup_tunnel;
+ }
+
+ /* Add 'tunnel' setting */
+ s_ip_tunnel = (NMSettingIPTunnel *) nm_setting_ip_tunnel_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_ip_tunnel));
+
+ /* Set 'tunnel' properties */
+ g_object_set (s_ip_tunnel, NM_SETTING_IP_TUNNEL_MODE, mode_enum, NULL);
+ g_object_set (s_ip_tunnel, NM_SETTING_IP_TUNNEL_REMOTE, remote_c, NULL);
+ if (local)
+ g_object_set (s_ip_tunnel, NM_SETTING_IP_TUNNEL_LOCAL, local, NULL);
+
+ /* Set default values for IPv6 tunnels */
+ if (nm_utils_ipaddr_valid (AF_INET6, remote_c)) {
+ g_object_set (s_ip_tunnel, NM_SETTING_IP_TUNNEL_TOS, 64, NULL);
+ g_object_set (s_ip_tunnel, NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT, 4, NULL);
+ }
+
+ success = TRUE;
+cleanup_tunnel:
+ g_free (remote_ask);
+ g_free (mode_ask);
+ if (!success)
+ return FALSE;
+
} else if (!strcmp (con_type, NM_SETTING_GENERIC_SETTING_NAME)) {
/* Add 'generic' setting */
s_generic = (NMSettingGeneric *) nm_setting_generic_new ();
diff --git a/clients/cli/nmcli-completion b/clients/cli/nmcli-completion
index 1827551b0c..2424fc6d7c 100644
--- a/clients/cli/nmcli-completion
+++ b/clients/cli/nmcli-completion
@@ -401,7 +401,7 @@ _nmcli_compl_ARGS()
# user friendly. Only complete them, if the current word already starts with an "8".
_nmcli_list "802-3-ethernet 802-11-wireless 802-11-olpc-mesh"
else
- _nmcli_list "ethernet wifi wimax gsm cdma infiniband bluetooth vpn olpc-mesh vlan bond bridge team pppoe adsl tun"
+ _nmcli_list "ethernet wifi wimax gsm cdma infiniband bluetooth vpn olpc-mesh vlan bond bridge team pppoe adsl tun ip-tunnel"
fi
return 0
fi
diff --git a/clients/cli/settings.c b/clients/cli/settings.c
index bf2cadc707..3e8c10f4c2 100644
--- a/clients/cli/settings.c
+++ b/clients/cli/settings.c
@@ -718,6 +718,36 @@ NmcOutputField nmc_fields_setting_tun[] = {
NM_SETTING_TUN_MULTI_QUEUE
#define NMC_FIELDS_SETTING_TUN_COMMON NMC_FIELDS_SETTING_TUN_ALL
+/* Available fields for NM_SETTING_IP_TUNNEL_SETTING_NAME */
+NmcOutputField nmc_fields_setting_ip_tunnel[] = {
+ SETTING_FIELD ("name"), /* 0 */
+ SETTING_FIELD (NM_SETTING_IP_TUNNEL_MODE), /* 1 */
+ SETTING_FIELD (NM_SETTING_IP_TUNNEL_PARENT), /* 2 */
+ SETTING_FIELD (NM_SETTING_IP_TUNNEL_LOCAL), /* 3 */
+ SETTING_FIELD (NM_SETTING_IP_TUNNEL_REMOTE), /* 4 */
+ SETTING_FIELD (NM_SETTING_IP_TUNNEL_TTL), /* 5 */
+ SETTING_FIELD (NM_SETTING_IP_TUNNEL_TOS), /* 6 */
+ SETTING_FIELD (NM_SETTING_IP_TUNNEL_PATH_MTU_DISCOVERY), /* 7 */
+ SETTING_FIELD (NM_SETTING_IP_TUNNEL_INPUT_KEY), /* 8 */
+ SETTING_FIELD (NM_SETTING_IP_TUNNEL_OUTPUT_KEY), /* 9 */
+ SETTING_FIELD (NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT), /* 10 */
+ SETTING_FIELD (NM_SETTING_IP_TUNNEL_FLOW_LABEL), /* 11 */
+ {NULL, NULL, 0, NULL, FALSE, FALSE, 0}
+};
+#define NMC_FIELDS_SETTING_IP_TUNNEL_ALL "name"","\
+ NM_SETTING_IP_TUNNEL_MODE","\
+ NM_SETTING_IP_TUNNEL_PARENT","\
+ NM_SETTING_IP_TUNNEL_LOCAL","\
+ NM_SETTING_IP_TUNNEL_REMOTE","\
+ NM_SETTING_IP_TUNNEL_TTL","\
+ NM_SETTING_IP_TUNNEL_TOS","\
+ NM_SETTING_IP_TUNNEL_PATH_MTU_DISCOVERY","\
+ NM_SETTING_IP_TUNNEL_INPUT_KEY","\
+ NM_SETTING_IP_TUNNEL_OUTPUT_KEY","\
+ NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT","\
+ NM_SETTING_IP_TUNNEL_FLOW_LABEL
+#define NMC_FIELDS_SETTING_IP_TUNNEL_COMMON NMC_FIELDS_SETTING_IP_TUNNEL_ALL
+
/*----------------------------------------------------------------------------*/
static char *
wep_key_type_to_string (NMWepKeyType type)
@@ -1310,6 +1340,17 @@ DEFINE_GETTER (nmc_property_tun_get_pi, NM_SETTING_TUN_PI);
DEFINE_GETTER (nmc_property_tun_get_vnet_hdr, NM_SETTING_TUN_VNET_HDR);
DEFINE_GETTER (nmc_property_tun_get_multi_queue, NM_SETTING_TUN_MULTI_QUEUE);
+DEFINE_GETTER (nmc_property_ip_tunnel_get_parent, NM_SETTING_IP_TUNNEL_PARENT);
+DEFINE_GETTER (nmc_property_ip_tunnel_get_local, NM_SETTING_IP_TUNNEL_LOCAL);
+DEFINE_GETTER (nmc_property_ip_tunnel_get_remote, NM_SETTING_IP_TUNNEL_REMOTE);
+DEFINE_GETTER (nmc_property_ip_tunnel_get_ttl, NM_SETTING_IP_TUNNEL_TTL);
+DEFINE_GETTER (nmc_property_ip_tunnel_get_tos, NM_SETTING_IP_TUNNEL_TOS);
+DEFINE_GETTER (nmc_property_ip_tunnel_get_path_mtu_discovery, NM_SETTING_IP_TUNNEL_PATH_MTU_DISCOVERY);
+DEFINE_GETTER (nmc_property_ip_tunnel_get_input_key, NM_SETTING_IP_TUNNEL_INPUT_KEY);
+DEFINE_GETTER (nmc_property_ip_tunnel_get_output_key, NM_SETTING_IP_TUNNEL_OUTPUT_KEY);
+DEFINE_GETTER (nmc_property_ip_tunnel_get_encapsulation_limit, NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT);
+DEFINE_GETTER (nmc_property_ip_tunnel_get_flow_label, NM_SETTING_IP_TUNNEL_FLOW_LABEL);
+
static char *
nmc_property_ib_get_mtu (NMSetting *setting, NmcPropertyGetType get_type)
{
@@ -1665,6 +1706,44 @@ nmc_property_wired_set_wake_on_lan (NMSetting *setting, const char *prop,
return TRUE;
}
+static char *
+nmc_property_ip_tunnel_get_mode (NMSetting *setting, NmcPropertyGetType get_type)
+{
+ NMSettingIPTunnel *s_ip_tunnel = NM_SETTING_IP_TUNNEL (setting);
+ NMIPTunnelMode mode;
+
+ mode = nm_setting_ip_tunnel_get_mode (s_ip_tunnel);
+ return nm_utils_enum_to_str (nm_ip_tunnel_mode_get_type (), mode);
+}
+
+static gboolean
+nmc_property_ip_tunnel_set_mode (NMSetting *setting, const char *prop,
+ const char *val, GError **error)
+{
+ NMIPTunnelMode mode;
+ gboolean ret;
+
+ ret = nm_utils_enum_from_str (nm_ip_tunnel_mode_get_type(), val,
+ (int *) &mode, NULL);
+
+ if (!ret) {
+ gs_free const char **values = NULL;
+ gs_free char *values_str = NULL;
+
+ values = nm_utils_enum_get_values (nm_ip_tunnel_mode_get_type (),
+ NM_IP_TUNNEL_MODE_UKNOWN + 1,
+ G_MAXINT);
+ values_str = g_strjoinv (",", (char **) values);
+ g_set_error (error, 1, 0, _("invalid mode '%s', use one of %s"),
+ val, values_str);
+
+ return FALSE;
+ }
+
+ g_object_set (setting, prop, mode, NULL);
+ return TRUE;
+}
+
/* --- NM_SETTING_WIRELESS_SETTING_NAME property get functions --- */
DEFINE_GETTER (nmc_property_wireless_get_mode, NM_SETTING_WIRELESS_MODE)
DEFINE_GETTER (nmc_property_wireless_get_band, NM_SETTING_WIRELESS_BAND)
@@ -7073,6 +7152,85 @@ nmc_properties_init (void)
NULL,
NULL,
NULL);
+
+ /* Add editable properties for NM_SETTING_IP_TUNNEL_SETTING_NAME */
+ nmc_add_prop_funcs (GLUE (IP_TUNNEL, MODE),
+ nmc_property_ip_tunnel_get_mode,
+ nmc_property_ip_tunnel_set_mode,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ nmc_add_prop_funcs (GLUE (IP_TUNNEL, PARENT),
+ nmc_property_ip_tunnel_get_parent,
+ nmc_property_set_string,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ nmc_add_prop_funcs (GLUE (IP_TUNNEL, LOCAL),
+ nmc_property_ip_tunnel_get_local,
+ nmc_property_set_string,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ nmc_add_prop_funcs (GLUE (IP_TUNNEL, REMOTE),
+ nmc_property_ip_tunnel_get_remote,
+ nmc_property_set_string,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ nmc_add_prop_funcs (GLUE (IP_TUNNEL, TTL),
+ nmc_property_ip_tunnel_get_ttl,
+ nmc_property_set_uint,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ nmc_add_prop_funcs (GLUE (IP_TUNNEL, TOS),
+ nmc_property_ip_tunnel_get_tos,
+ nmc_property_set_uint,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ nmc_add_prop_funcs (GLUE (IP_TUNNEL, PATH_MTU_DISCOVERY),
+ nmc_property_ip_tunnel_get_path_mtu_discovery,
+ nmc_property_set_bool,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ nmc_add_prop_funcs (GLUE (IP_TUNNEL, INPUT_KEY),
+ nmc_property_ip_tunnel_get_input_key,
+ nmc_property_set_string,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ nmc_add_prop_funcs (GLUE (IP_TUNNEL, OUTPUT_KEY),
+ nmc_property_ip_tunnel_get_output_key,
+ nmc_property_set_string,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ nmc_add_prop_funcs (GLUE (IP_TUNNEL, ENCAPSULATION_LIMIT),
+ nmc_property_ip_tunnel_get_encapsulation_limit,
+ nmc_property_set_uint,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ nmc_add_prop_funcs (GLUE (IP_TUNNEL, FLOW_LABEL),
+ nmc_property_ip_tunnel_get_flow_label,
+ nmc_property_set_uint,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
}
void
@@ -8253,6 +8411,42 @@ setting_tun_details (NMSetting *setting, NmCli *nmc, const char *one_prop, gboo
return TRUE;
}
+static gboolean
+setting_ip_tunnel_details (NMSetting *setting, NmCli *nmc, const char *one_prop, gboolean secrets)
+{
+ NMSettingIPTunnel *s_ip_tunnel = NM_SETTING_IP_TUNNEL (setting);
+ NmcOutputField *tmpl, *arr;
+ size_t tmpl_len;
+
+ g_return_val_if_fail (NM_IS_SETTING_IP_TUNNEL (s_ip_tunnel), FALSE);
+
+ tmpl = nmc_fields_setting_ip_tunnel;
+ tmpl_len = sizeof (nmc_fields_setting_ip_tunnel);
+ nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_IP_TUNNEL_ALL,
+ tmpl, FALSE, NULL, NULL);
+ arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_FIELD_NAMES);
+ g_ptr_array_add (nmc->output_data, arr);
+
+ arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX);
+ set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting)));
+ set_val_str (arr, 1, nmc_property_ip_tunnel_get_mode (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 2, nmc_property_ip_tunnel_get_parent (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 3, nmc_property_ip_tunnel_get_local (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 4, nmc_property_ip_tunnel_get_remote (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 5, nmc_property_ip_tunnel_get_ttl (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 6, nmc_property_ip_tunnel_get_tos (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 7, nmc_property_ip_tunnel_get_path_mtu_discovery (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 8, nmc_property_ip_tunnel_get_input_key (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 9, nmc_property_ip_tunnel_get_output_key (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 10, nmc_property_ip_tunnel_get_encapsulation_limit (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 11, nmc_property_ip_tunnel_get_flow_label (setting, NMC_PROPERTY_GET_PRETTY));
+ g_ptr_array_add (nmc->output_data, arr);
+
+ print_data (nmc); /* Print all data */
+
+ return TRUE;
+}
+
typedef struct {
const char *sname;
gboolean (*func) (NMSetting *setting, NmCli *nmc, const char *one_prop, gboolean secrets);
@@ -8285,6 +8479,7 @@ static const SettingDetails detail_printers[] = {
{ NM_SETTING_TEAM_PORT_SETTING_NAME, setting_team_port_details },
{ NM_SETTING_DCB_SETTING_NAME, setting_dcb_details },
{ NM_SETTING_TUN_SETTING_NAME, setting_tun_details },
+ { NM_SETTING_IP_TUNNEL_SETTING_NAME, setting_ip_tunnel_details },
{ NULL },
};
diff --git a/introspection/Makefile.am b/introspection/Makefile.am
index c8a70cffc7..735921d373 100644
--- a/introspection/Makefile.am
+++ b/introspection/Makefile.am
@@ -31,10 +31,10 @@ nodist_libnmdbus_la_SOURCES = \
nmdbus-device.h \
nmdbus-device-generic.c \
nmdbus-device-generic.h \
- nmdbus-device-gre.c \
- nmdbus-device-gre.h \
nmdbus-device-infiniband.c \
nmdbus-device-infiniband.h \
+ nmdbus-device-ip-tunnel.c \
+ nmdbus-device-ip-tunnel.h \
nmdbus-device-macvlan.c \
nmdbus-device-macvlan.h \
nmdbus-device-modem.c \
@@ -108,8 +108,8 @@ EXTRA_DIST = \
nm-device-bt.xml \
nm-device-ethernet.xml \
nm-device-generic.xml \
- nm-device-gre.xml \
nm-device-infiniband.xml \
+ nm-device-ip-tunnel.xml \
nm-device-macvlan.xml \
nm-device-modem.xml \
nm-device-olpc-mesh.xml \
diff --git a/introspection/nm-device-gre.xml b/introspection/nm-device-ip-tunnel.xml
index ae418aab55..fcb42ce275 100644
--- a/introspection/nm-device-gre.xml
+++ b/introspection/nm-device-ip-tunnel.xml
@@ -1,7 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<node name="/" xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
- <interface name="org.freedesktop.NetworkManager.Device.Gre">
+ <interface name="org.freedesktop.NetworkManager.Device.IPTunnel">
+
+ <property name="Mode" type="u" access="read">
+ <tp:docstring>
+ The tunneling mode.
+ </tp:docstring>
+ </property>
<property name="Parent" type="o" access="read">
<tp:docstring>
@@ -9,63 +15,62 @@
</tp:docstring>
</property>
- <property name="InputFlags" type="q" access="read">
+ <property name="Local" type="s" access="read">
<tp:docstring>
- The expected set of GRE flags for incoming packets. (The
- values are specified by the GRE specification. On Linux, they
- are defined in &lt;linux/if_tunnel.h&gt;. Eg, GRE_KEY for the
- 'Key Present' bit.)
+ The local endpoint of the tunnel.
</tp:docstring>
</property>
- <property name="OutputFlags" type="q" access="read">
+ <property name="Remote" type="s" access="read">
<tp:docstring>
- The set of GRE flags to use for outgoing packets. (The
- values are specified by the GRE specification. On Linux, they
- are defined in &lt;linux/if_tunnel.h&gt;. Eg, GRE_KEY for the
- 'Key Present' bit.)
+ The remote endpoint of the tunnel.
</tp:docstring>
</property>
- <property name="InputKey" type="u" access="read">
+ <property name="Ttl" type="y" access="read">
<tp:docstring>
- Expected input key (if the "Key Present" bit is set in the input flags).
+ The TTL assigned to tunneled packets. 0 is a special value
+ meaning that packets inherit the TTL value
</tp:docstring>
</property>
- <property name="OutputKey" type="u" access="read">
+ <property name="Tos" type="y" access="read">
<tp:docstring>
- Output key (if the "Key Present" bit is set in the output flags).
+ The type of service (IPv4) or traffic class (IPv6) assigned to
+ tunneled packets.
</tp:docstring>
</property>
- <property name="Local" type="s" access="read">
+ <property name="PathMtuDiscovery" type="b" access="read">
<tp:docstring>
- The local end of the tunnel.
+ Whether path MTU discovery is enabled on this tunnel.
</tp:docstring>
</property>
- <property name="Remote" type="s" access="read">
+ <property name="InputKey" type="s" access="read">
<tp:docstring>
- The remote end of the tunnel.
+ The key used for incoming packets.
</tp:docstring>
</property>
- <property name="Ttl" type="y" access="read">
+ <property name="OutputKey" type="s" access="read">
<tp:docstring>
- The value to use in the IP TTL field for tunnel packets.
+ The key used for outgoing packets.
</tp:docstring>
</property>
- <property name="Tos" type="y" access="read">
+ <property name="EncapsulationLimit" type="y" access="read">
<tp:docstring>
- The value to use in the IP ToS field for tunnel packets.
+ How many additional levels of encapsulation are permitted to
+ be prepended to packets. This property applies only to IPv6
+ tunnels.
</tp:docstring>
</property>
- <property name="PathMtuDiscovery" type="b" access="read">
+ <property name="FlowLabel" type="u" access="read">
<tp:docstring>
- Whether path MTU discovery is performed.
+ The flow label to assign to tunnel packets. This property
+ applies only to IPv6 tunnels.
</tp:docstring>
</property>
diff --git a/libnm-core/Makefile.libnm-core b/libnm-core/Makefile.libnm-core
index 867dd9045d..02c1d1021b 100644
--- a/libnm-core/Makefile.libnm-core
+++ b/libnm-core/Makefile.libnm-core
@@ -25,6 +25,7 @@ libnm_core_headers = \
$(core)/nm-setting-gsm.h \
$(core)/nm-setting-infiniband.h \
$(core)/nm-setting-ip-config.h \
+ $(core)/nm-setting-ip-tunnel.h \
$(core)/nm-setting-ip4-config.h \
$(core)/nm-setting-ip6-config.h \
$(core)/nm-setting-olpc-mesh.h \
@@ -82,6 +83,7 @@ libnm_core_sources = \
$(core)/nm-setting-gsm.c \
$(core)/nm-setting-infiniband.c \
$(core)/nm-setting-ip-config.c \
+ $(core)/nm-setting-ip-tunnel.c \
$(core)/nm-setting-ip4-config.c \
$(core)/nm-setting-ip6-config.c \
$(core)/nm-setting-olpc-mesh.c \
diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c
index 94a897539a..e801f2fd47 100644
--- a/libnm-core/nm-connection.c
+++ b/libnm-core/nm-connection.c
@@ -1595,7 +1595,8 @@ nm_connection_is_virtual (NMConnection *connection)
|| !strcmp (type, NM_SETTING_TEAM_SETTING_NAME)
|| !strcmp (type, NM_SETTING_BRIDGE_SETTING_NAME)
|| !strcmp (type, NM_SETTING_VLAN_SETTING_NAME)
- || !strcmp (type, NM_SETTING_TUN_SETTING_NAME))
+ || !strcmp (type, NM_SETTING_TUN_SETTING_NAME)
+ || !strcmp (type, NM_SETTING_IP_TUNNEL_SETTING_NAME))
return TRUE;
if (!strcmp (type, NM_SETTING_INFINIBAND_SETTING_NAME)) {
@@ -1866,6 +1867,24 @@ nm_connection_get_setting_ip4_config (NMConnection *connection)
}
/**
+ * nm_connection_get_setting_ip_tunnel:
+ * @connection: the #NMConnection
+ *
+ * A shortcut to return any #NMSettingIPTunnel the connection might contain.
+ *
+ * Returns: (transfer none): an #NMSettingIPTunnel if the connection contains one, otherwise %NULL
+ *
+ * Since: 1.2
+ **/
+NMSettingIPTunnel *
+nm_connection_get_setting_ip_tunnel (NMConnection *connection)
+{
+ g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
+
+ return (NMSettingIPTunnel *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP_TUNNEL);
+}
+
+/**
* nm_connection_get_setting_ip6_config:
* @connection: the #NMConnection
*
diff --git a/libnm-core/nm-connection.h b/libnm-core/nm-connection.h
index fc2117f61e..8896e59bab 100644
--- a/libnm-core/nm-connection.h
+++ b/libnm-core/nm-connection.h
@@ -202,6 +202,8 @@ NMSettingDcb * nm_connection_get_setting_dcb (NMConnec
NMSettingGeneric * nm_connection_get_setting_generic (NMConnection *connection);
NMSettingGsm * nm_connection_get_setting_gsm (NMConnection *connection);
NMSettingInfiniband * nm_connection_get_setting_infiniband (NMConnection *connection);
+NM_AVAILABLE_IN_1_2
+NMSettingIPTunnel * nm_connection_get_setting_ip_tunnel (NMConnection *connection);
NMSettingIPConfig * nm_connection_get_setting_ip4_config (NMConnection *connection);
NMSettingIPConfig * nm_connection_get_setting_ip6_config (NMConnection *connection);
NMSettingOlpcMesh * nm_connection_get_setting_olpc_mesh (NMConnection *connection);
diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h
index d1b0992900..c1eea777f2 100644
--- a/libnm-core/nm-core-internal.h
+++ b/libnm-core/nm-core-internal.h
@@ -49,6 +49,7 @@
#include "nm-setting-generic.h"
#include "nm-setting-gsm.h"
#include "nm-setting-infiniband.h"
+#include "nm-setting-ip-tunnel.h"
#include "nm-setting-ip4-config.h"
#include "nm-setting-ip6-config.h"
#include "nm-setting-olpc-mesh.h"
diff --git a/libnm-core/nm-core-types.h b/libnm-core/nm-core-types.h
index 1355c92da6..29a34cc68d 100644
--- a/libnm-core/nm-core-types.h
+++ b/libnm-core/nm-core-types.h
@@ -42,6 +42,7 @@ typedef struct _NMSettingGeneric NMSettingGeneric;
typedef struct _NMSettingGsm NMSettingGsm;
typedef struct _NMSettingInfiniband NMSettingInfiniband;
typedef struct _NMSettingIPConfig NMSettingIPConfig;
+typedef struct _NMSettingIPTunnel NMSettingIPTunnel;
typedef struct _NMSettingIP4Config NMSettingIP4Config;
typedef struct _NMSettingIP6Config NMSettingIP6Config;
typedef struct _NMSettingOlpcMesh NMSettingOlpcMesh;
diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h
index ddd6834c23..f901028f9b 100644
--- a/libnm-core/nm-dbus-interface.h
+++ b/libnm-core/nm-dbus-interface.h
@@ -67,7 +67,7 @@
#define NM_DBUS_INTERFACE_DEVICE_MACVLAN NM_DBUS_INTERFACE_DEVICE ".Macvlan"
#define NM_DBUS_INTERFACE_DEVICE_VXLAN NM_DBUS_INTERFACE_DEVICE ".Vxlan"
#define NM_DBUS_INTERFACE_DEVICE_GRE NM_DBUS_INTERFACE_DEVICE ".Gre"
-
+#define NM_DBUS_INTERFACE_DEVICE_IP_TUNNEL NM_DBUS_INTERFACE_DEVICE ".IPTunnel"
#define NM_DBUS_INTERFACE_SETTINGS "org.freedesktop.NetworkManager.Settings"
#define NM_DBUS_PATH_SETTINGS "/org/freedesktop/NetworkManager/Settings"
@@ -173,6 +173,7 @@ typedef enum {
NM_DEVICE_TYPE_GENERIC = 14,
NM_DEVICE_TYPE_TEAM = 15,
NM_DEVICE_TYPE_TUN = 16,
+ NM_DEVICE_TYPE_IP_TUNNEL = 17,
} NMDeviceType;
/**
@@ -668,4 +669,34 @@ typedef enum /*< flags >*/ {
#define NM_LLDP_DEST_NEAREST_NON_TPMR_BRIDGE "nearest-non-tpmr-bridge"
#define NM_LLDP_DEST_NEAREST_CUSTOMER_BRIDGE "nearest-customer-bridge"
+/**
+ * NMIPTunnelMode:
+ * @NM_IP_TUNNEL_MODE_UNKNOWN: Unknown/unset tunnel mode
+ * @NM_IP_TUNNEL_MODE_IPIP: IP in IP tunnel
+ * @NM_IP_TUNNEL_MODE_GRE: GRE tunnel
+ * @NM_IP_TUNNEL_MODE_SIT: SIT tunnel
+ * @NM_IP_TUNNEL_MODE_ISATAP: ISATAP tunnel
+ * @NM_IP_TUNNEL_MODE_VTI: VTI tunnel
+ * @NM_IP_TUNNEL_MODE_IP6IP6: IPv6 in IPv6 tunnel
+ * @NM_IP_TUNNEL_MODE_IPIP6: IPv4 in IPv6 tunnel
+ * @NM_IP_TUNNEL_MODE_IP6GRE: IPv6 GRE tunnel
+ * @NM_IP_TUNNEL_MODE_VTI6: IPv6 VTI tunnel
+ *
+ * The tunneling mode.
+ *
+ * Since: 1.2
+ */
+typedef enum {
+ NM_IP_TUNNEL_MODE_UKNOWN = 0,
+ NM_IP_TUNNEL_MODE_IPIP = 1,
+ NM_IP_TUNNEL_MODE_GRE = 2,
+ NM_IP_TUNNEL_MODE_SIT = 3,
+ NM_IP_TUNNEL_MODE_ISATAP = 4,
+ NM_IP_TUNNEL_MODE_VTI = 5,
+ NM_IP_TUNNEL_MODE_IP6IP6 = 6,
+ NM_IP_TUNNEL_MODE_IPIP6 = 7,
+ NM_IP_TUNNEL_MODE_IP6GRE = 8,
+ NM_IP_TUNNEL_MODE_VTI6 = 9,
+} NMIPTunnelMode;
+
#endif /* __NM_DBUS_INTERFACE_H__ */
diff --git a/libnm-core/nm-setting-ip-tunnel.c b/libnm-core/nm-setting-ip-tunnel.c
new file mode 100644
index 0000000000..d561524950
--- /dev/null
+++ b/libnm-core/nm-setting-ip-tunnel.c
@@ -0,0 +1,724 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2015 Red Hat, Inc.
+ */
+
+#include "nm-setting-ip-tunnel.h"
+
+#include "config.h"
+
+#include "nm-setting-private.h"
+#include "nm-macros-internal.h"
+#include "nm-utils.h"
+
+/**
+ * SECTION:nm-setting-tunnel
+ * @short_description: Describes connection properties for IP tunnel devices
+ **/
+
+G_DEFINE_TYPE_WITH_CODE (NMSettingIPTunnel, nm_setting_ip_tunnel, NM_TYPE_SETTING,
+ _nm_register_setting (IP_TUNNEL, 1))
+NM_SETTING_REGISTER_TYPE (NM_TYPE_SETTING_IP_TUNNEL)
+
+#define NM_SETTING_IP_TUNNEL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_IP_TUNNEL, NMSettingIPTunnelPrivate))
+
+typedef struct {
+ char *parent;
+ NMIPTunnelMode mode;
+ char *local;
+ char *remote;
+ guint ttl;
+ guint tos;
+ gboolean path_mtu_discovery;
+ char *input_key;
+ char *output_key;
+ guint encapsulation_limit;
+ guint flow_label;
+} NMSettingIPTunnelPrivate;
+
+enum {
+ PROP_0,
+ PROP_PARENT,
+ PROP_MODE,
+ PROP_LOCAL,
+ PROP_REMOTE,
+ PROP_TTL,
+ PROP_TOS,
+ PROP_PATH_MTU_DISCOVERY,
+ PROP_INPUT_KEY,
+ PROP_OUTPUT_KEY,
+ PROP_ENCAPSULATION_LIMIT,
+ PROP_FLOW_LABEL,
+
+ LAST_PROP
+};
+
+/**
+ * nm_setting_ip_tunnel_get_parent:
+ * @setting: the #NMSettingIPTunnel
+ *
+ * Returns the #NMSettingIPTunnel:parent property of the setting
+ *
+ * Returns: the parent device
+ *
+ * Since: 1.2
+ **/
+const char *
+nm_setting_ip_tunnel_get_parent (NMSettingIPTunnel *setting)
+{
+ g_return_val_if_fail (NM_IS_SETTING_IP_TUNNEL (setting), NULL);
+ return NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting)->parent;
+}
+
+/**
+ * nm_setting_ip_tunnel_get_mode:
+ * @setting: the #NMSettingIPTunnel
+ *
+ * Returns the #NMSettingIPTunnel:mode property of the setting.
+ *
+ * Returns: the tunnel mode
+ *
+ * Since: 1.2
+ **/
+NMIPTunnelMode
+nm_setting_ip_tunnel_get_mode (NMSettingIPTunnel *setting)
+{
+ g_return_val_if_fail (NM_IS_SETTING_IP_TUNNEL (setting), 0);
+
+ return NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting)->mode;
+}
+
+/**
+ * nm_setting_ip_tunnel_get_local:
+ * @setting: the #NMSettingIPTunnel
+ *
+ * Returns the #NMSettingIPTunnel:local property of the setting.
+ *
+ * Returns: the local endpoint
+ *
+ * Since: 1.2
+ **/
+const char *
+nm_setting_ip_tunnel_get_local (NMSettingIPTunnel *setting)
+{
+ g_return_val_if_fail (NM_IS_SETTING_IP_TUNNEL (setting), NULL);
+
+ return NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting)->local;
+}
+
+/**
+ * nm_setting_ip_tunnel_get_remote:
+ * @setting: the #NMSettingIPTunnel
+ *
+ * Returns the #NMSettingIPTunnel:remote property of the setting.
+ *
+ * Returns: the remote endpoint
+ *
+ * Since: 1.2
+ **/
+const char *
+nm_setting_ip_tunnel_get_remote (NMSettingIPTunnel *setting)
+{
+ g_return_val_if_fail (NM_IS_SETTING_IP_TUNNEL (setting), NULL);
+
+ return NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting)->remote;
+}
+
+/**
+ * nm_setting_ip_tunnel_get_ttl:
+ * @setting: the #NMSettingIPTunnel
+ *
+ * Returns the #NMSettingIPTunnel:ttl property of the setting.
+ *
+ * Returns: the Time-to-live value
+ *
+ * Since: 1.2
+ **/
+
+guint
+nm_setting_ip_tunnel_get_ttl (NMSettingIPTunnel *setting)
+{
+ g_return_val_if_fail (NM_IS_SETTING_IP_TUNNEL (setting), 0);
+
+ return NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting)->ttl;
+}
+
+/**
+ * nm_setting_ip_tunnel_get_tos:
+ * @setting: the #NMSettingIPTunnel
+ *
+ * Returns the #NMSettingIPTunnel:tos property of the setting.
+ *
+ * Returns: the TOS value
+ *
+ * Since: 1.2
+ **/
+guint
+nm_setting_ip_tunnel_get_tos (NMSettingIPTunnel *setting)
+{
+ g_return_val_if_fail (NM_IS_SETTING_IP_TUNNEL (setting), 0);
+
+ return NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting)->tos;
+}
+
+/**
+ * nm_setting_ip_tunnel_get_path_mtu_discovery:
+ * @setting: the #NMSettingIPTunnel
+ *
+ * Returns the #NMSettingIPTunnel:path-mtu-discovery property of the setting.
+ *
+ * Returns: whether path MTU discovery is enabled
+ *
+ * Since: 1.2
+ **/
+gboolean
+nm_setting_ip_tunnel_get_path_mtu_discovery (NMSettingIPTunnel *setting)
+{
+ g_return_val_if_fail (NM_IS_SETTING_IP_TUNNEL (setting), TRUE);
+
+ return NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting)->path_mtu_discovery;
+}
+
+/**
+ * nm_setting_ip_tunnel_get_input_key:
+ * @setting: the #NMSettingIPTunnel
+ *
+ * Returns the #NMSettingIPTunnel:input-key property of the setting.
+ *
+ * Returns: the input key
+ *
+ * Since: 1.2
+ **/
+const char *
+nm_setting_ip_tunnel_get_input_key (NMSettingIPTunnel *setting)
+{
+ g_return_val_if_fail (NM_IS_SETTING_IP_TUNNEL (setting), NULL);
+
+ return NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting)->input_key;
+}
+
+/**
+ * nm_setting_ip_tunnel_get_output_key:
+ * @setting: the #NMSettingIPTunnel
+ *
+ * Returns the #NMSettingIPTunnel:output-key property of the setting.
+ *
+ * Returns: the output key
+ *
+ * Since: 1.2
+ **/
+const char *
+nm_setting_ip_tunnel_get_output_key (NMSettingIPTunnel *setting)
+{
+ g_return_val_if_fail (NM_IS_SETTING_IP_TUNNEL (setting), NULL);
+
+ return NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting)->output_key;
+}
+
+/**
+ * nm_setting_ip_tunnel_get_encapsulation_limit:
+ * @setting: the #NMSettingIPTunnel
+ *
+ * Returns the #NMSettingIPTunnel:encapsulation-limit property of the setting.
+ *
+ * Returns: the encapsulation limit value
+ *
+ * Since: 1.2
+ **/
+guint
+nm_setting_ip_tunnel_get_encapsulation_limit (NMSettingIPTunnel *setting)
+{
+ g_return_val_if_fail (NM_IS_SETTING_IP_TUNNEL (setting), 0);
+
+ return NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting)->encapsulation_limit;
+}
+
+/**
+ * nm_setting_ip_tunnel_get_flow_label:
+ * @setting: the #NMSettingIPTunnel
+ *
+ * Returns the #NMSettingIPTunnel:flow-label property of the setting.
+ *
+ * Returns: the flow label value
+ *
+ * Since: 1.2
+ **/
+guint
+nm_setting_ip_tunnel_get_flow_label (NMSettingIPTunnel *setting)
+{
+ g_return_val_if_fail (NM_IS_SETTING_IP_TUNNEL (setting), 0);
+
+ return NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting)->flow_label;
+}
+
+/*********************************************************************/
+
+static gboolean
+verify (NMSetting *setting, NMConnection *connection, GError **error)
+{
+ NMSettingIPTunnelPrivate *priv = NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting);
+ int family;
+
+ switch (priv->mode) {
+ case NM_IP_TUNNEL_MODE_IPIP:
+ case NM_IP_TUNNEL_MODE_SIT:
+ case NM_IP_TUNNEL_MODE_ISATAP:
+ case NM_IP_TUNNEL_MODE_GRE:
+ case NM_IP_TUNNEL_MODE_VTI:
+ family = AF_INET;
+ break;
+ case NM_IP_TUNNEL_MODE_IP6IP6:
+ case NM_IP_TUNNEL_MODE_IPIP6:
+ case NM_IP_TUNNEL_MODE_IP6GRE:
+ case NM_IP_TUNNEL_MODE_VTI6:
+ family = AF_INET6;
+ break;
+ default:
+ family = AF_UNSPEC;
+ }
+
+ if (family == AF_UNSPEC) {
+ g_set_error (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("'%d' is not a valid tunnel mode"),
+ (int) priv->mode);
+ g_prefix_error (error, "%s.%s: ", NM_SETTING_IP_TUNNEL_SETTING_NAME, NM_SETTING_IP_TUNNEL_MODE);
+ return FALSE;
+ }
+
+ if ( priv->parent
+ && !nm_utils_iface_valid_name (priv->parent)
+ && !nm_utils_is_uuid (priv->parent)) {
+ g_set_error (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("'%s' is neither an UUID nor an interface name"),
+ priv->parent);
+ g_prefix_error (error, "%s.%s: ", NM_SETTING_IP_TUNNEL_SETTING_NAME,
+ NM_SETTING_IP_TUNNEL_PARENT);
+ return FALSE;
+ }
+
+ if (priv->local && !nm_utils_ipaddr_valid (family, priv->local)) {
+ g_set_error (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("'%s' is not a valid IPv%c address"),
+ priv->local,
+ family == AF_INET ? '4' : '6');
+ g_prefix_error (error, "%s.%s: ", NM_SETTING_IP_TUNNEL_SETTING_NAME, NM_SETTING_IP_TUNNEL_LOCAL);
+ return FALSE;
+ }
+
+ if (priv->remote && !nm_utils_ipaddr_valid (family, priv->remote)) {
+ g_set_error (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("'%s' is not a valid IPv%c address"),
+ priv->remote,
+ family == AF_INET ? '4' : '6');
+ g_prefix_error (error, "%s.%s: ", NM_SETTING_IP_TUNNEL_SETTING_NAME, NM_SETTING_IP_TUNNEL_REMOTE);
+ return FALSE;
+ }
+
+ if ( (priv->input_key && priv->input_key[0])
+ || (priv->output_key && priv->output_key[0])) {
+ if ( priv->mode != NM_IP_TUNNEL_MODE_GRE
+ && priv->mode != NM_IP_TUNNEL_MODE_IP6GRE) {
+ g_set_error_literal (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("tunnel keys can only be specified for GRE tunnels"));
+ return FALSE;
+ }
+ }
+
+ if (priv->input_key && priv->input_key[0]) {
+ gint64 val;
+
+ val = _nm_utils_ascii_str_to_int64 (priv->input_key, 10, 0, G_MAXUINT32, -1);
+ if (val == -1) {
+ g_set_error (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("'%s' is not a valid tunnel key"),
+ priv->input_key);
+ g_prefix_error (error, "%s.%s: ", NM_SETTING_IP_TUNNEL_SETTING_NAME,
+ NM_SETTING_IP_TUNNEL_INPUT_KEY);
+ return FALSE;
+ }
+ }
+
+ if (priv->output_key && priv->output_key[0]) {
+ gint64 val;
+
+ val = _nm_utils_ascii_str_to_int64 (priv->output_key, 10, 0, G_MAXUINT32, -1);
+ if (val == -1) {
+ g_set_error (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("'%s' is not a valid tunnel key"),
+ priv->output_key);
+ g_prefix_error (error, "%s.%s: ", NM_SETTING_IP_TUNNEL_SETTING_NAME,
+ NM_SETTING_IP_TUNNEL_OUTPUT_KEY);
+ return FALSE;
+ }
+ }
+
+ if (!priv->path_mtu_discovery && priv->ttl != 0) {
+ g_set_error_literal (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("a fixed TTL is allowed only when path MTU discovery is enabled"));
+ g_prefix_error (error, "%s.%s: ", NM_SETTING_IP_TUNNEL_SETTING_NAME,
+ NM_SETTING_IP_TUNNEL_TTL);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * nm_setting_ip_tunnel_new:
+ *
+ * Creates a new #NMSettingIPTunnel object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingIPTunnel object
+ *
+ * Since: 1.2
+ **/
+NMSetting *
+nm_setting_ip_tunnel_new (void)
+{
+ return (NMSetting *) g_object_new (NM_TYPE_SETTING_IP_TUNNEL, NULL);
+}
+
+static void
+nm_setting_ip_tunnel_init (NMSettingIPTunnel *setting)
+{
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ NMSettingIPTunnel *setting = NM_SETTING_IP_TUNNEL (object);
+ NMSettingIPTunnelPrivate *priv = NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting);
+
+ switch (prop_id) {
+ case PROP_PARENT:
+ g_free (priv->parent);
+ priv->parent = g_value_dup_string (value);
+ break;
+ case PROP_MODE:
+ priv->mode = g_value_get_uint (value);
+ break;
+ case PROP_LOCAL:
+ g_free (priv->local);
+ priv->local = g_value_dup_string (value);
+ break;
+ case PROP_REMOTE:
+ g_free (priv->remote);
+ priv->remote = g_value_dup_string (value);
+ break;
+ case PROP_TTL:
+ priv->ttl = g_value_get_uint (value);
+ break;
+ case PROP_TOS:
+ priv->tos = g_value_get_uint (value);
+ break;
+ case PROP_PATH_MTU_DISCOVERY:
+ priv->path_mtu_discovery = g_value_get_boolean (value);
+ break;
+ case PROP_INPUT_KEY:
+ g_free (priv->input_key);
+ priv->input_key = g_value_dup_string (value);
+ break;
+ case PROP_OUTPUT_KEY:
+ g_free (priv->output_key);
+ priv->output_key = g_value_dup_string (value);
+ break;
+ case PROP_ENCAPSULATION_LIMIT:
+ priv->encapsulation_limit = g_value_get_uint (value);
+ break;
+ case PROP_FLOW_LABEL:
+ priv->flow_label = g_value_get_uint (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec)
+{
+ NMSettingIPTunnel *setting = NM_SETTING_IP_TUNNEL (object);
+ NMSettingIPTunnelPrivate *priv = NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting);
+
+ switch (prop_id) {
+ case PROP_PARENT:
+ g_value_set_string (value, priv->parent);
+ break;
+ case PROP_MODE:
+ g_value_set_uint (value, priv->mode);
+ break;
+ case PROP_LOCAL:
+ g_value_set_string (value, priv->local);
+ break;
+ case PROP_REMOTE:
+ g_value_set_string (value, priv->remote);
+ break;
+ case PROP_TTL:
+ g_value_set_uint (value, priv->ttl);
+ break;
+ case PROP_TOS:
+ g_value_set_uint (value, priv->tos);
+ break;
+ case PROP_PATH_MTU_DISCOVERY:
+ g_value_set_boolean (value, priv->path_mtu_discovery);
+ break;
+ case PROP_INPUT_KEY:
+ g_value_set_string (value, priv->input_key);
+ break;
+ case PROP_OUTPUT_KEY:
+ g_value_set_string (value, priv->output_key);
+ break;
+ case PROP_ENCAPSULATION_LIMIT:
+ g_value_set_uint (value, priv->encapsulation_limit);
+ break;
+ case PROP_FLOW_LABEL:
+ g_value_set_uint (value, priv->flow_label);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+finalize (GObject *object)
+{
+ NMSettingIPTunnel *setting = NM_SETTING_IP_TUNNEL (object);
+ NMSettingIPTunnelPrivate *priv = NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting);
+
+ g_free (priv->local);
+ g_free (priv->remote);
+ g_free (priv->input_key);
+ g_free (priv->output_key);
+
+ G_OBJECT_CLASS (nm_setting_ip_tunnel_parent_class)->finalize (object);
+}
+
+static void
+nm_setting_ip_tunnel_class_init (NMSettingIPTunnelClass *setting_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (setting_class);
+ NMSettingClass *parent_class = NM_SETTING_CLASS (setting_class);
+
+ g_type_class_add_private (setting_class, sizeof (NMSettingIPTunnelPrivate));
+
+ /* virtual methods */
+ object_class->set_property = set_property;
+ object_class->get_property = get_property;
+ object_class->finalize = finalize;
+ parent_class->verify = verify;
+
+ /**
+ * NMSettingIPTunnel:parent:
+ *
+ * If given, specifies the parent interface name or parent connection UUID
+ * the new device will be bound to so that tunneled packets will only be
+ * routed via that interface.
+ *
+ * Since: 1.2
+ **/
+ g_object_class_install_property
+ (object_class, PROP_PARENT,
+ g_param_spec_string (NM_SETTING_IP_TUNNEL_PARENT, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ NM_SETTING_PARAM_INFERRABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMSettingIPTunnel:mode:
+ *
+ * The tunneling mode, for example %NM_IP_TUNNEL_MODE_IPIP or
+ * %NM_IP_TUNNEL_MODE_GRE.
+ *
+ * Since: 1.2
+ **/
+ g_object_class_install_property
+ (object_class, PROP_MODE,
+ g_param_spec_uint (NM_SETTING_IP_TUNNEL_MODE, "", "",
+ 0, G_MAXUINT, 0,
+ G_PARAM_READWRITE |
+ NM_SETTING_PARAM_INFERRABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMSettingIPTunnel:local:
+ *
+ * The local endpoint of the tunnel; the value can be empty, otherwise it
+ * must contain an IPv4 or IPv6 address.
+ *
+ * Since: 1.2
+ **/
+ g_object_class_install_property
+ (object_class, PROP_LOCAL,
+ g_param_spec_string (NM_SETTING_IP_TUNNEL_LOCAL, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ NM_SETTING_PARAM_INFERRABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMSettingIPTunnel:remote:
+ *
+ * The remote endpoint of the tunnel; the value must contain an IPv4 or IPv6
+ * address.
+ *
+ * Since: 1.2
+ **/
+ g_object_class_install_property
+ (object_class, PROP_REMOTE,
+ g_param_spec_string (NM_SETTING_IP_TUNNEL_REMOTE, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ NM_SETTING_PARAM_INFERRABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMSettingIPTunnel:ttl
+ *
+ * The TTL to assign to tunneled packets. 0 is a special value meaning that
+ * packets inherit the TTL value.
+ *
+ * Since: 1.2
+ **/
+ g_object_class_install_property
+ (object_class, PROP_TTL,
+ g_param_spec_uint (NM_SETTING_IP_TUNNEL_TTL, "", "",
+ 0, 255, 0,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ NM_SETTING_PARAM_INFERRABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMSettingIPTunnel:tos
+ *
+ * The type of service (IPv4) or traffic class (IPv6) field to be set on
+ * tunneled packets.
+ *
+ * Since: 1.2
+ **/
+ g_object_class_install_property
+ (object_class, PROP_TOS,
+ g_param_spec_uint (NM_SETTING_IP_TUNNEL_TOS, "", "",
+ 0, 255, 0,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ NM_SETTING_PARAM_INFERRABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMSettingIPTunnel:path-mtu-discovery
+ *
+ * Whether to enable Path MTU Discovery on this tunnel.
+ *
+ * Since: 1.2
+ **/
+ g_object_class_install_property
+ (object_class, PROP_PATH_MTU_DISCOVERY,
+ g_param_spec_boolean (NM_SETTING_IP_TUNNEL_PATH_MTU_DISCOVERY, "", "",
+ TRUE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ NM_SETTING_PARAM_INFERRABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMSettingIPTunnel:input-key:
+ *
+ * The key used for tunnel input packets; the property is valid only for
+ * certain tunnel modes (GRE, IP6GRE). If empty, no key is used.
+ *
+ * Since: 1.2
+ **/
+ g_object_class_install_property
+ (object_class, PROP_INPUT_KEY,
+ g_param_spec_string (NM_SETTING_IP_TUNNEL_INPUT_KEY, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ NM_SETTING_PARAM_INFERRABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMSettingIPTunnel:output-key:
+ *
+ * The key used for tunnel output packets; the property is valid only for
+ * certain tunnel modes (GRE, IP6GRE). If empty, no key is used.
+ *
+ * Since: 1.2
+ **/
+ g_object_class_install_property
+ (object_class, PROP_OUTPUT_KEY,
+ g_param_spec_string (NM_SETTING_IP_TUNNEL_OUTPUT_KEY, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ NM_SETTING_PARAM_INFERRABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMSettingIPTunnel:encapsulation-limit:
+ *
+ * How many additional levels of encapsulation are permitted to be prepended
+ * to packets. This property applies only to IPv6 tunnels.
+ *
+ * Since: 1.2
+ **/
+ g_object_class_install_property
+ (object_class, PROP_ENCAPSULATION_LIMIT,
+ g_param_spec_uint (NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT, "", "",
+ 0, 255, 0,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ NM_SETTING_PARAM_INFERRABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMSettingIPTunnel:flow-label:
+ *
+ * The flow label to assign to tunnel packets. This property applies only to
+ * IPv6 tunnels.
+ *
+ * Since: 1.2
+ **/
+ g_object_class_install_property
+ (object_class, PROP_FLOW_LABEL,
+ g_param_spec_uint (NM_SETTING_IP_TUNNEL_FLOW_LABEL, "", "",
+ 0, (1 << 20) - 1, 0,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ NM_SETTING_PARAM_INFERRABLE |
+ G_PARAM_STATIC_STRINGS));
+}
diff --git a/libnm-core/nm-setting-ip-tunnel.h b/libnm-core/nm-setting-ip-tunnel.h
new file mode 100644
index 0000000000..a07bd50db0
--- /dev/null
+++ b/libnm-core/nm-setting-ip-tunnel.h
@@ -0,0 +1,95 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2015 Red Hat, Inc.
+ */
+
+#ifndef __NM_SETTING_IP_TUNNEL_H__
+#define __NM_SETTING_IP_TUNNEL_H__
+
+#if !defined (__NETWORKMANAGER_H_INSIDE__) && !defined (NETWORKMANAGER_COMPILATION)
+#error "Only <NetworkManager.h> can be included directly."
+#endif
+
+#include <nm-setting.h>
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_SETTING_IP_TUNNEL (nm_setting_ip_tunnel_get_type ())
+#define NM_SETTING_IP_TUNNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTING_IP_TUNNEL, NMSettingIPTunnel))
+#define NM_SETTING_IP_TUNNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SETTING_IP_TUNNEL, NMSettingIPTunnelClass))
+#define NM_IS_SETTING_IP_TUNNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTING_IP_TUNNEL))
+#define NM_IS_SETTING_IP_TUNNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SETTING_IP_TUNNEL))
+#define NM_SETTING_IP_TUNNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SETTING_IP_TUNNEL, NMSettingIPTunnelClass))
+
+#define NM_SETTING_IP_TUNNEL_SETTING_NAME "ip-tunnel"
+
+#define NM_SETTING_IP_TUNNEL_PARENT "parent"
+#define NM_SETTING_IP_TUNNEL_MODE "mode"
+#define NM_SETTING_IP_TUNNEL_LOCAL "local"
+#define NM_SETTING_IP_TUNNEL_REMOTE "remote"
+#define NM_SETTING_IP_TUNNEL_TTL "ttl"
+#define NM_SETTING_IP_TUNNEL_TOS "tos"
+#define NM_SETTING_IP_TUNNEL_PATH_MTU_DISCOVERY "path-mtu-discovery"
+#define NM_SETTING_IP_TUNNEL_INPUT_KEY "input-key"
+#define NM_SETTING_IP_TUNNEL_OUTPUT_KEY "output-key"
+#define NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT "encapsulation-limit"
+#define NM_SETTING_IP_TUNNEL_FLOW_LABEL "flow-label"
+
+struct _NMSettingIPTunnel {
+ NMSetting parent;
+};
+
+typedef struct {
+ NMSettingClass parent;
+
+ /*< private >*/
+ gpointer padding[4];
+} NMSettingIPTunnelClass;
+
+NM_AVAILABLE_IN_1_2
+GType nm_setting_ip_tunnel_get_type (void);
+
+NM_AVAILABLE_IN_1_2
+NMSetting * nm_setting_ip_tunnel_new (void);
+
+NM_AVAILABLE_IN_1_2
+const char *nm_setting_ip_tunnel_get_parent (NMSettingIPTunnel *setting);
+NM_AVAILABLE_IN_1_2
+NMIPTunnelMode nm_setting_ip_tunnel_get_mode (NMSettingIPTunnel *setting);
+NM_AVAILABLE_IN_1_2
+const char *nm_setting_ip_tunnel_get_local (NMSettingIPTunnel *setting);
+NM_AVAILABLE_IN_1_2
+const char *nm_setting_ip_tunnel_get_remote (NMSettingIPTunnel *setting);
+NM_AVAILABLE_IN_1_2
+guint nm_setting_ip_tunnel_get_ttl (NMSettingIPTunnel *setting);
+NM_AVAILABLE_IN_1_2
+guint nm_setting_ip_tunnel_get_tos (NMSettingIPTunnel *setting);
+NM_AVAILABLE_IN_1_2
+gboolean nm_setting_ip_tunnel_get_path_mtu_discovery (NMSettingIPTunnel *setting);
+NM_AVAILABLE_IN_1_2
+const char *nm_setting_ip_tunnel_get_input_key (NMSettingIPTunnel *setting);
+NM_AVAILABLE_IN_1_2
+const char *nm_setting_ip_tunnel_get_output_key (NMSettingIPTunnel *setting);
+NM_AVAILABLE_IN_1_2
+guint nm_setting_ip_tunnel_get_encapsulation_limit (NMSettingIPTunnel *setting);
+NM_AVAILABLE_IN_1_2
+guint nm_setting_ip_tunnel_get_flow_label (NMSettingIPTunnel *setting);
+
+G_END_DECLS
+
+#endif /* __NM_SETTING_IP_TUNNEL_H__ */
diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c
index e3c6b80bef..5e920de482 100644
--- a/libnm-core/nm-utils.c
+++ b/libnm-core/nm-utils.c
@@ -4120,3 +4120,55 @@ NM_BACKPORT_SYMBOL (libnm_1_0_6, gboolean, nm_utils_enum_from_str,
(GType type, const char *str, int *out_value, char **err_token),
(type, str, out_value, err_token));
+/**
+ * nm_utils_enum_get_values:
+ * @type: the %GType of the enum
+ * @from: the first element to be returned
+ * @to: the last element to be returned
+ *
+ * Returns the list of possible values for a given enum.
+ *
+ * Returns: a NULL-terminated dynamically-allocated array of static strings
+ * or %NULL on error
+ *
+ * Since: 1.2
+ */
+const char **nm_utils_enum_get_values (GType type, gint from, gint to)
+{
+ GTypeClass *class;
+ GPtrArray *array;
+ gint i;
+
+ class = g_type_class_ref (type);
+ array = g_ptr_array_new ();
+
+ if (G_IS_ENUM_CLASS (class)) {
+ GEnumClass *enum_class = G_ENUM_CLASS (class);
+ GEnumValue *enum_value;
+
+ for (i = 0; i < enum_class->n_values; i++) {
+ enum_value = &enum_class->values[i];
+ if (enum_value->value >= from && enum_value->value <= to)
+ g_ptr_array_add (array, (gpointer) enum_value->value_nick);
+ }
+ } else if (G_IS_FLAGS_CLASS (class)) {
+ GFlagsClass *flags_class = G_FLAGS_CLASS (class);
+ GFlagsValue *flags_value;
+
+ for (i = 0; i < flags_class->n_values; i++) {
+ flags_value = &flags_class->values[i];
+ if (flags_value->value >= from && flags_value->value <= to)
+ g_ptr_array_add (array, (gpointer) flags_value->value_nick);
+ }
+ } else {
+ g_type_class_unref (class);
+ g_ptr_array_free (array, TRUE);
+ g_return_val_if_reached (NULL);
+ }
+
+ g_type_class_unref (class);
+ g_ptr_array_add (array, NULL);
+
+ return (const char **) g_ptr_array_free (array, FALSE);
+}
+
diff --git a/libnm-core/nm-utils.h b/libnm-core/nm-utils.h
index 4be58e09a1..407c14e2c4 100644
--- a/libnm-core/nm-utils.h
+++ b/libnm-core/nm-utils.h
@@ -203,6 +203,9 @@ char *nm_utils_enum_to_str (GType type, int value);
NM_AVAILABLE_IN_1_2
gboolean nm_utils_enum_from_str (GType type, const char *str, int *out_value, char **err_token);
+NM_AVAILABLE_IN_1_2
+const char **nm_utils_enum_get_values (GType type, gint from, gint to);
+
G_END_DECLS
#endif /* __NM_UTILS_H__ */
diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c
index f4dec283ce..e8eb0bafb5 100644
--- a/libnm-core/tests/test-general.c
+++ b/libnm-core/tests/test-general.c
@@ -4740,6 +4740,21 @@ test_nm_utils_enum_to_str_do (GType type, int flags, const char *exp_str)
g_free (str);
}
+static void
+test_nm_utils_enum_get_values_do (GType type, int from, int to, const char *exp_str)
+{
+ const char **strv;
+ char *str;
+
+ strv = nm_utils_enum_get_values (type, from, to);
+ g_assert (strv);
+ str = g_strjoinv (",", (char **) strv);
+ g_assert_cmpstr (str, ==, exp_str);
+ g_free (str);
+ g_free (strv);
+}
+
+
static void test_nm_utils_enum (void)
{
GType bool_enum = nm_test_general_bool_enum_get_type();
@@ -4783,6 +4798,12 @@ static void test_nm_utils_enum (void)
test_nm_utils_enum_from_str_do (color_flags, "blue,red", TRUE, NM_TEST_GENERAL_COLOR_FLAGS_BLUE |
NM_TEST_GENERAL_COLOR_FLAGS_RED, NULL);
test_nm_utils_enum_from_str_do (color_flags, "blue,white", FALSE, 0, "white");
+
+ test_nm_utils_enum_get_values_do (bool_enum, 0, G_MAXINT, "no,yes,maybe,unknown");
+ test_nm_utils_enum_get_values_do (bool_enum, NM_TEST_GENERAL_BOOL_ENUM_YES,
+ NM_TEST_GENERAL_BOOL_ENUM_MAYBE, "yes,maybe");
+ test_nm_utils_enum_get_values_do (meta_flags, 0, G_MAXINT, "none,foo,bar,baz");
+ test_nm_utils_enum_get_values_do (color_flags, 0, G_MAXINT, "blue,red,green");
}
/******************************************************************************/
diff --git a/libnm-glib/nm-device.c b/libnm-glib/nm-device.c
index aac94fb1dc..ce76432107 100644
--- a/libnm-glib/nm-device.c
+++ b/libnm-glib/nm-device.c
@@ -321,6 +321,7 @@ _nm_device_gtype_from_dtype (NMDeviceType dtype)
return NM_TYPE_DEVICE_VLAN;
case NM_DEVICE_TYPE_GENERIC:
case NM_DEVICE_TYPE_TUN:
+ case NM_DEVICE_TYPE_IP_TUNNEL:
return NM_TYPE_DEVICE_GENERIC;
default:
g_warning ("Unknown device type %d", dtype);
diff --git a/libnm-util/NetworkManager.h b/libnm-util/NetworkManager.h
index 71862c42eb..8101082b77 100644
--- a/libnm-util/NetworkManager.h
+++ b/libnm-util/NetworkManager.h
@@ -152,6 +152,7 @@ typedef enum {
* @NM_DEVICE_TYPE_BRIDGE: a bridge master interface
* @NM_DEVICE_TYPE_TEAM: a team master interface
* @NM_DEVICE_TYPE_TUN: a TUN/TAP interface
+ * @NM_DEVICE_TYPE_IP_TUNNEL: an IP tunnel interface
*
* #NMDeviceType values indicate the type of hardware represented by
* an #NMDevice.
@@ -176,6 +177,7 @@ typedef enum {
NM_DEVICE_TYPE_GENERIC = 14,
NM_DEVICE_TYPE_TEAM = 15,
NM_DEVICE_TYPE_TUN = 16,
+ NM_DEVICE_TYPE_IP_TUNNEL = 17,
} NMDeviceType;
/**
diff --git a/libnm/Makefile.am b/libnm/Makefile.am
index bf921abd89..4ce9655554 100644
--- a/libnm/Makefile.am
+++ b/libnm/Makefile.am
@@ -38,6 +38,7 @@ libnminclude_hfiles = \
nm-device-ethernet.h \
nm-device-generic.h \
nm-device-infiniband.h \
+ nm-device-ip-tunnel.h \
nm-device-modem.h \
nm-device-olpc-mesh.h \
nm-device-team.h \
@@ -90,6 +91,7 @@ libnm_la_csources = \
nm-device-ethernet.c \
nm-device-generic.c \
nm-device-infiniband.c \
+ nm-device-ip-tunnel.c \
nm-device-modem.c \
nm-device-olpc-mesh.c \
nm-device-team.c \
diff --git a/libnm/NetworkManager.h b/libnm/NetworkManager.h
index 95c92965e3..17e7a3523b 100644
--- a/libnm/NetworkManager.h
+++ b/libnm/NetworkManager.h
@@ -61,6 +61,7 @@
#include <nm-setting-gsm.h>
#include <nm-setting-infiniband.h>
#include <nm-setting-ip-config.h>
+#include <nm-setting-ip-tunnel.h>
#include <nm-setting-ip4-config.h>
#include <nm-setting-ip6-config.h>
#include <nm-setting-olpc-mesh.h>
diff --git a/libnm/libnm.ver b/libnm/libnm.ver
index 865cc328df..dbd95922e9 100644
--- a/libnm/libnm.ver
+++ b/libnm/libnm.ver
@@ -858,10 +858,23 @@ libnm_1_0_6 {
libnm_1_2_0 {
global:
nm_access_point_get_last_seen;
+ nm_connection_get_setting_ip_tunnel;
nm_connection_verify_secrets;
nm_device_ethernet_get_s390_subchannels;
nm_device_get_lldp_neighbors;
nm_device_get_metered;
+ nm_device_ip_tunnel_get_encapsulation_limit;
+ nm_device_ip_tunnel_get_flow_label;
+ nm_device_ip_tunnel_get_input_key;
+ nm_device_ip_tunnel_get_local;
+ nm_device_ip_tunnel_get_mode;
+ nm_device_ip_tunnel_get_output_key;
+ nm_device_ip_tunnel_get_parent;
+ nm_device_ip_tunnel_get_path_mtu_discovery;
+ nm_device_ip_tunnel_get_remote;
+ nm_device_ip_tunnel_get_tos;
+ nm_device_ip_tunnel_get_ttl;
+ nm_device_ip_tunnel_get_type;
nm_device_get_nm_plugin_missing;
nm_device_set_managed;
nm_device_tun_get_group;
@@ -874,6 +887,7 @@ global:
nm_device_tun_get_vnet_hdr;
nm_device_wifi_request_scan_options;
nm_device_wifi_request_scan_options_async;
+ nm_ip_tunnel_mode_get_type;
nm_lldp_neighbor_get_attr_names;
nm_lldp_neighbor_get_attr_string_value;
nm_lldp_neighbor_get_attr_type;
@@ -904,6 +918,17 @@ global:
nm_setting_ip_config_has_dns_options;
nm_setting_ip_config_remove_dns_option;
nm_setting_ip_config_remove_dns_option_by_value;
+ nm_setting_ip_tunnel_get_input_key;
+ nm_setting_ip_tunnel_get_local;
+ nm_setting_ip_tunnel_get_mode;
+ nm_setting_ip_tunnel_get_output_key;
+ nm_setting_ip_tunnel_get_parent;
+ nm_setting_ip_tunnel_get_path_mtu_discovery;
+ nm_setting_ip_tunnel_get_remote;
+ nm_setting_ip_tunnel_get_tos;
+ nm_setting_ip_tunnel_get_type;
+ nm_setting_ip_tunnel_get_ttl;
+ nm_setting_ip_tunnel_new;
nm_setting_mac_randomization_get_type;
nm_setting_tun_get_group;
nm_setting_tun_get_mode;
@@ -925,6 +950,7 @@ global:
nm_utils_bond_mode_string_to_int;
nm_utils_enum_from_str;
nm_utils_enum_to_str;
+ nm_utils_enum_get_values;
nm_utils_wifi_2ghz_freqs;
nm_utils_wifi_5ghz_freqs;
nm_vpn_editor_plugin_load_from_file;
diff --git a/libnm/nm-device-ip-tunnel.c b/libnm/nm-device-ip-tunnel.c
new file mode 100644
index 0000000000..ad107155b8
--- /dev/null
+++ b/libnm/nm-device-ip-tunnel.c
@@ -0,0 +1,544 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2015 Red Hat, Inc.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <nm-setting-connection.h>
+#include <nm-setting-ip-tunnel.h>
+#include <nm-utils.h>
+
+#include "nm-default.h"
+#include "nm-device-ip-tunnel.h"
+#include "nm-device-private.h"
+#include "nm-object-private.h"
+#include "nm-core-internal.h"
+
+G_DEFINE_TYPE (NMDeviceIPTunnel, nm_device_ip_tunnel, NM_TYPE_DEVICE)
+
+#define NM_DEVICE_IP_TUNNEL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_IP_TUNNEL, NMDeviceIPTunnelPrivate))
+
+typedef struct {
+ NMIPTunnelMode mode;
+ NMDevice *parent;
+ char *local;
+ char *remote;
+ guint8 ttl;
+ guint8 tos;
+ gboolean path_mtu_discovery;
+ char *input_key;
+ char *output_key;
+ guint8 encap_limit;
+ guint32 flow_label;
+} NMDeviceIPTunnelPrivate;
+
+enum {
+ PROP_0,
+ PROP_MODE,
+ PROP_PARENT,
+ PROP_LOCAL,
+ PROP_REMOTE,
+ PROP_TTL,
+ PROP_TOS,
+ PROP_PATH_MTU_DISCOVERY,
+ PROP_INPUT_KEY,
+ PROP_OUTPUT_KEY,
+ PROP_ENCAPSULATION_LIMIT,
+ PROP_FLOW_LABEL,
+
+ LAST_PROP
+};
+
+/**
+ * nm_device_ip_tunnel_get_mode:
+ * @device: a #NMDeviceIPTunnel
+ *
+ * Returns: the tunneling mode
+ *
+ * Since: 1.2
+ **/
+NMIPTunnelMode
+nm_device_ip_tunnel_get_mode (NMDeviceIPTunnel *device)
+{
+ g_return_val_if_fail (NM_IS_DEVICE_IP_TUNNEL (device), 0);
+
+ return NM_DEVICE_IP_TUNNEL_GET_PRIVATE (device)->mode;
+}
+
+/**
+ * nm_device_ip_tunnel_get_parent:
+ * @device: a #NMDeviceIPTunnel
+ *
+ * Returns: (transfer none): the device's parent device
+ *
+ * Since: 1.2
+ **/
+NMDevice *
+nm_device_ip_tunnel_get_parent (NMDeviceIPTunnel *device)
+{
+ g_return_val_if_fail (NM_IS_DEVICE_IP_TUNNEL (device), NULL);
+
+ return NM_DEVICE_IP_TUNNEL_GET_PRIVATE (device)->parent;
+}
+
+/**
+ * nm_device_ip_tunnel_get_local:
+ * @device: a #NMDeviceIPTunnel
+ *
+ * Returns: the local endpoint of the tunnel
+ *
+ * Since: 1.2
+ **/
+const char *
+nm_device_ip_tunnel_get_local (NMDeviceIPTunnel *device)
+{
+ g_return_val_if_fail (NM_IS_DEVICE_IP_TUNNEL (device), NULL);
+
+ return NM_DEVICE_IP_TUNNEL_GET_PRIVATE (device)->local;
+}
+
+/**
+ * nm_device_ip_tunnel_get_remote:
+ * @device: a #NMDeviceIPTunnel
+ *
+ * Returns: the remote endpoint of the tunnel
+ *
+ * Since: 1.2
+ **/
+const char *
+nm_device_ip_tunnel_get_remote (NMDeviceIPTunnel *device)
+{
+ g_return_val_if_fail (NM_IS_DEVICE_IP_TUNNEL (device), NULL);
+
+ return NM_DEVICE_IP_TUNNEL_GET_PRIVATE (device)->remote;
+}
+
+/**
+ * nm_device_ip_tunnel_get_ttl:
+ * @device: a #NMDeviceIPTunnel
+ *
+ * Returns: the TTL assigned to tunneled packets
+ *
+ * Since: 1.2
+ **/
+guint8
+nm_device_ip_tunnel_get_ttl (NMDeviceIPTunnel *device)
+{
+ g_return_val_if_fail (NM_IS_DEVICE_IP_TUNNEL (device), 0);
+
+ return NM_DEVICE_IP_TUNNEL_GET_PRIVATE (device)->ttl;
+}
+
+/**
+ * nm_device_ip_tunnel_get_tos:
+ * @device: a #NMDeviceIPTunnel
+ *
+ * Returns: type of service (IPv4) or traffic class (IPv6) assigned
+ * to tunneled packets.
+ *
+ * Since: 1.2
+ **/
+guint8
+nm_device_ip_tunnel_get_tos (NMDeviceIPTunnel *device)
+{
+ g_return_val_if_fail (NM_IS_DEVICE_IP_TUNNEL (device), 0);
+
+ return NM_DEVICE_IP_TUNNEL_GET_PRIVATE (device)->tos;
+}
+
+/**
+ * nm_device_ip_tunnel_get_path_mtu_discovery:
+ * @device: a #NMDeviceIPTunnel
+ *
+ * Returns: whether path MTU discovery is enabled
+ *
+ * Since: 1.2
+ **/
+gboolean
+nm_device_ip_tunnel_get_path_mtu_discovery (NMDeviceIPTunnel *device)
+{
+ g_return_val_if_fail (NM_IS_DEVICE_IP_TUNNEL (device), TRUE);
+
+ return NM_DEVICE_IP_TUNNEL_GET_PRIVATE (device)->path_mtu_discovery;
+}
+
+/**
+ * nm_device_ip_tunnel_get_input_key:
+ * @device: a #NMDeviceIPTunnel
+ *
+ * Returns: the key used for incoming packets
+ *
+ * Since: 1.2
+ **/
+const char *
+nm_device_ip_tunnel_get_input_key (NMDeviceIPTunnel *device)
+{
+ g_return_val_if_fail (NM_IS_DEVICE_IP_TUNNEL (device), NULL);
+
+ return NM_DEVICE_IP_TUNNEL_GET_PRIVATE (device)->input_key;
+}
+
+/**
+ * nm_device_ip_tunnel_get_output_key:
+ * @device: a #NMDeviceIPTunnel
+ *
+ * Returns: the key used for outgoing packets
+ *
+ * Since: 1.2
+ **/
+const char *
+nm_device_ip_tunnel_get_output_key (NMDeviceIPTunnel *device)
+{
+ g_return_val_if_fail (NM_IS_DEVICE_IP_TUNNEL (device), NULL);
+
+ return NM_DEVICE_IP_TUNNEL_GET_PRIVATE (device)->output_key;
+}
+
+/**
+ * nm_device_ip_tunnel_get_encapsulation_limit:
+ * @device: a #NMDeviceIPTunnel
+ *
+ * Returns: the maximum permitted encapsulation level
+ *
+ * Since: 1.2
+ **/
+guint8
+nm_device_ip_tunnel_get_encapsulation_limit (NMDeviceIPTunnel *device)
+{
+ g_return_val_if_fail (NM_IS_DEVICE_IP_TUNNEL (device), 0);
+
+ return NM_DEVICE_IP_TUNNEL_GET_PRIVATE (device)->encap_limit;
+}
+
+/**
+ * nm_device_ip_tunnel_get_flow_label:
+ * @device: a #NMDeviceIPTunnel
+ *
+ * Returns: the flow label assigned to tunnel packets
+ *
+ * Since: 1.2
+ **/
+guint
+nm_device_ip_tunnel_get_flow_label (NMDeviceIPTunnel *device)
+{
+ g_return_val_if_fail (NM_IS_DEVICE_IP_TUNNEL (device), 0);
+
+ return NM_DEVICE_IP_TUNNEL_GET_PRIVATE (device)->flow_label;
+}
+
+static gboolean
+connection_compatible (NMDevice *device, NMConnection *connection, GError **error)
+{
+ if (!NM_DEVICE_CLASS (nm_device_ip_tunnel_parent_class)->connection_compatible (device, connection, error))
+ return FALSE;
+
+ if (!nm_connection_is_type (connection, NM_SETTING_IP_TUNNEL_SETTING_NAME)) {
+ g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
+ _("The connection was not an IP tunnel connection."));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static GType
+get_setting_type (NMDevice *device)
+{
+ return NM_TYPE_SETTING_IP_TUNNEL;
+}
+
+/***********************************************************/
+
+static void
+nm_device_ip_tunnel_init (NMDeviceIPTunnel *device)
+{
+ _nm_device_set_device_type (NM_DEVICE (device), NM_DEVICE_TYPE_IP_TUNNEL);
+}
+
+static void
+init_dbus (NMObject *object)
+{
+ NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (object);
+ const NMPropertiesInfo property_info[] = {
+ { NM_DEVICE_IP_TUNNEL_PARENT, &priv->parent, NULL, NM_TYPE_DEVICE },
+ { NM_DEVICE_IP_TUNNEL_MODE, &priv->mode },
+ { NM_DEVICE_IP_TUNNEL_LOCAL, &priv->local },
+ { NM_DEVICE_IP_TUNNEL_REMOTE, &priv->remote },
+ { NM_DEVICE_IP_TUNNEL_TTL, &priv->ttl },
+ { NM_DEVICE_IP_TUNNEL_TOS, &priv->tos },
+ { NM_DEVICE_IP_TUNNEL_PATH_MTU_DISCOVERY, &priv->path_mtu_discovery },
+ { NM_DEVICE_IP_TUNNEL_INPUT_KEY, &priv->input_key },
+ { NM_DEVICE_IP_TUNNEL_OUTPUT_KEY, &priv->output_key },
+ { NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT, &priv->encap_limit },
+ { NM_DEVICE_IP_TUNNEL_FLOW_LABEL, &priv->flow_label },
+ { NULL },
+ };
+
+ NM_OBJECT_CLASS (nm_device_ip_tunnel_parent_class)->init_dbus (object);
+
+ _nm_object_register_properties (object,
+ NM_DBUS_INTERFACE_DEVICE_IP_TUNNEL,
+ property_info);
+}
+
+static void
+finalize (GObject *object)
+{
+ NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (object);
+
+ g_free (priv->local);
+ g_free (priv->remote);
+ g_free (priv->input_key);
+ g_free (priv->output_key);
+ g_clear_object (&priv->parent);
+
+ G_OBJECT_CLASS (nm_device_ip_tunnel_parent_class)->finalize (object);
+}
+
+static void
+get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ NMDeviceIPTunnel *device = NM_DEVICE_IP_TUNNEL (object);
+
+ switch (prop_id) {
+ case PROP_PARENT:
+ g_value_set_object (value, nm_device_ip_tunnel_get_parent (device));
+ break;
+ case PROP_MODE:
+ g_value_set_uint (value, nm_device_ip_tunnel_get_mode (device));
+ break;
+ case PROP_LOCAL:
+ g_value_set_string (value, nm_device_ip_tunnel_get_local (device));
+ break;
+ case PROP_REMOTE:
+ g_value_set_string (value, nm_device_ip_tunnel_get_remote (device));
+ break;
+ case PROP_TTL:
+ g_value_set_uint (value, nm_device_ip_tunnel_get_ttl (device));
+ break;
+ case PROP_TOS:
+ g_value_set_uint (value, nm_device_ip_tunnel_get_tos (device));
+ break;
+ case PROP_PATH_MTU_DISCOVERY:
+ g_value_set_boolean (value, nm_device_ip_tunnel_get_path_mtu_discovery (device));
+ break;
+ case PROP_INPUT_KEY:
+ g_value_set_string (value, nm_device_ip_tunnel_get_input_key (device));
+ break;
+ case PROP_OUTPUT_KEY:
+ g_value_set_string (value, nm_device_ip_tunnel_get_output_key (device));
+ break;
+ case PROP_ENCAPSULATION_LIMIT:
+ g_value_set_uint (value, nm_device_ip_tunnel_get_encapsulation_limit (device));
+ break;
+ case PROP_FLOW_LABEL:
+ g_value_set_uint (value, nm_device_ip_tunnel_get_flow_label (device));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+nm_device_ip_tunnel_class_init (NMDeviceIPTunnelClass *bond_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (bond_class);
+ NMObjectClass *nm_object_class = NM_OBJECT_CLASS (bond_class);
+ NMDeviceClass *device_class = NM_DEVICE_CLASS (bond_class);
+
+ g_type_class_add_private (bond_class, sizeof (NMDeviceIPTunnelPrivate));
+
+ _nm_object_class_add_interface (nm_object_class, NM_DBUS_INTERFACE_DEVICE_IP_TUNNEL);
+
+ /* virtual methods */
+ object_class->finalize = finalize;
+ object_class->get_property = get_property;
+
+ nm_object_class->init_dbus = init_dbus;
+
+ device_class->connection_compatible = connection_compatible;
+ device_class->get_setting_type = get_setting_type;
+
+ /* properties */
+
+ /**
+ * NMDeviceIPTunnel:mode:
+ *
+ * The tunneling mode of the device.
+ *
+ * Since: 1.2
+ **/
+ g_object_class_install_property
+ (object_class, PROP_MODE,
+ g_param_spec_uint (NM_DEVICE_IP_TUNNEL_MODE, "", "",
+ 0, G_MAXUINT, 0,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMDeviceIPTunnel:parent:
+ *
+ * The devices's parent device.
+ *
+ * Since: 1.2
+ **/
+ g_object_class_install_property
+ (object_class, PROP_PARENT,
+ g_param_spec_object (NM_DEVICE_IP_TUNNEL_PARENT, "", "",
+ NM_TYPE_DEVICE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMDeviceIPTunnel:local:
+ *
+ * The local endpoint of the tunnel.
+ *
+ * Since: 1.2
+ **/
+ g_object_class_install_property
+ (object_class, PROP_LOCAL,
+ g_param_spec_string (NM_DEVICE_IP_TUNNEL_LOCAL, "", "",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMDeviceIPTunnel:remote:
+ *
+ * The remote endpoint of the tunnel.
+ *
+ * Since: 1.2
+ **/
+ g_object_class_install_property
+ (object_class, PROP_REMOTE,
+ g_param_spec_string (NM_DEVICE_IP_TUNNEL_REMOTE, "", "",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMDeviceIPTunnel:ttl:
+ *
+ * The TTL assigned to tunneled packets. 0 is a special value
+ * meaning that packets inherit the TTL value
+ *
+ * Since: 1.2
+ **/
+ g_object_class_install_property
+ (object_class, PROP_TTL,
+ g_param_spec_uchar (NM_DEVICE_IP_TUNNEL_TTL, "", "",
+ 0, 255, 0,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMDeviceIPTunnel:tos:
+ *
+ * The type of service (IPv4) or traffic class (IPv6) assigned to
+ * tunneled packets.
+ *
+ * Since: 1.2
+ **/
+ g_object_class_install_property
+ (object_class, PROP_TOS,
+ g_param_spec_uchar (NM_DEVICE_IP_TUNNEL_TOS, "", "",
+ 0, 255, 0,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMDeviceIPTunnel:path-mtu-discovery:
+ *
+ * Whether path MTU discovery is enabled on this tunnel.
+ *
+ * Since: 1.2
+ **/
+ g_object_class_install_property
+ (object_class, PROP_PATH_MTU_DISCOVERY,
+ g_param_spec_boolean (NM_DEVICE_IP_TUNNEL_PATH_MTU_DISCOVERY, "", "",
+ FALSE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMDeviceIPTunnel:parent:
+ *
+ * The key used for tunneled input packets, if applicable.
+ *
+ * Since: 1.2
+ **/
+ g_object_class_install_property
+ (object_class, PROP_INPUT_KEY,
+ g_param_spec_string (NM_DEVICE_IP_TUNNEL_INPUT_KEY, "", "",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMDeviceIPTunnel:output-key:
+ *
+ * The key used for tunneled output packets, if applicable.
+ *
+ * Since: 1.2
+ **/
+ g_object_class_install_property
+ (object_class, PROP_OUTPUT_KEY,
+ g_param_spec_string (NM_DEVICE_IP_TUNNEL_OUTPUT_KEY, "", "",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMDeviceIPTunnel:encapsulation-limit:
+ *
+ * How many additional levels of encapsulation are permitted to
+ * be prepended to packets. This property applies only to IPv6
+ * tunnels.
+ *
+ * Since: 1.2
+ **/
+ g_object_class_install_property
+ (object_class, PROP_ENCAPSULATION_LIMIT,
+ g_param_spec_uchar (NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT, "", "",
+ 0, 255, 0,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMDeviceIPTunnel:flow-label:
+ *
+ * The flow label to assign to tunnel packets. This property
+ * applies only to IPv6 tunnels.
+ *
+ * Since: 1.2
+ **/
+ g_object_class_install_property
+ (object_class, PROP_FLOW_LABEL,
+ g_param_spec_uint (NM_DEVICE_IP_TUNNEL_FLOW_LABEL, "", "",
+ 0, (1 << 20) - 1, 0,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+}
diff --git a/libnm/nm-device-ip-tunnel.h b/libnm/nm-device-ip-tunnel.h
new file mode 100644
index 0000000000..820eab16dc
--- /dev/null
+++ b/libnm/nm-device-ip-tunnel.h
@@ -0,0 +1,90 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2015 Red Hat, Inc.
+ */
+
+#ifndef __NM_DEVICE_IP_TUNNEL_H__
+#define __NM_DEVICE_IP_TUNNEL_H__
+
+#if !defined (__NETWORKMANAGER_H_INSIDE__) && !defined (NETWORKMANAGER_COMPILATION)
+#error "Only <NetworkManager.h> can be included directly."
+#endif
+
+#include <nm-device.h>
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_DEVICE_IP_TUNNEL (nm_device_ip_tunnel_get_type ())
+#define NM_DEVICE_IP_TUNNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_IP_TUNNEL, NMDeviceIPTunnel))
+#define NM_DEVICE_IP_TUNNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_IP_TUNNEL, NMDeviceIPTunnelClass))
+#define NM_IS_DEVICE_IP_TUNNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_IP_TUNNEL))
+#define NM_IS_DEVICE_IP_TUNNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_IP_TUNNEL))
+#define NM_DEVICE_IP_TUNNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_IP_TUNNEL, NMDeviceIPTunnelClass))
+
+#define NM_DEVICE_IP_TUNNEL_MODE "mode"
+#define NM_DEVICE_IP_TUNNEL_PARENT "parent"
+#define NM_DEVICE_IP_TUNNEL_LOCAL "local"
+#define NM_DEVICE_IP_TUNNEL_REMOTE "remote"
+#define NM_DEVICE_IP_TUNNEL_TTL "ttl"
+#define NM_DEVICE_IP_TUNNEL_TOS "tos"
+#define NM_DEVICE_IP_TUNNEL_PATH_MTU_DISCOVERY "path-mtu-discovery"
+#define NM_DEVICE_IP_TUNNEL_INPUT_KEY "input-key"
+#define NM_DEVICE_IP_TUNNEL_OUTPUT_KEY "output-key"
+#define NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT "encapsulation-limit"
+#define NM_DEVICE_IP_TUNNEL_FLOW_LABEL "flow-label"
+
+struct _NMDeviceIPTunnel {
+ NMDevice parent;
+};
+
+typedef struct {
+ NMDeviceClass parent;
+
+ /*< private >*/
+ gpointer padding[4];
+} NMDeviceIPTunnelClass;
+
+NM_AVAILABLE_IN_1_2
+GType nm_device_ip_tunnel_get_type (void);
+
+NM_AVAILABLE_IN_1_2
+NMDevice * nm_device_ip_tunnel_get_parent (NMDeviceIPTunnel *device);
+NM_AVAILABLE_IN_1_2
+NMIPTunnelMode nm_device_ip_tunnel_get_mode (NMDeviceIPTunnel *device);
+NM_AVAILABLE_IN_1_2
+const char * nm_device_ip_tunnel_get_local (NMDeviceIPTunnel *device);
+NM_AVAILABLE_IN_1_2
+const char * nm_device_ip_tunnel_get_remote (NMDeviceIPTunnel *device);
+NM_AVAILABLE_IN_1_2
+guint8 nm_device_ip_tunnel_get_ttl (NMDeviceIPTunnel *device);
+NM_AVAILABLE_IN_1_2
+guint8 nm_device_ip_tunnel_get_tos (NMDeviceIPTunnel *device);
+NM_AVAILABLE_IN_1_2
+gboolean nm_device_ip_tunnel_get_path_mtu_discovery (NMDeviceIPTunnel *device);
+NM_AVAILABLE_IN_1_2
+const char * nm_device_ip_tunnel_get_input_key (NMDeviceIPTunnel *device);
+NM_AVAILABLE_IN_1_2
+const char * nm_device_ip_tunnel_get_output_key (NMDeviceIPTunnel *device);
+NM_AVAILABLE_IN_1_2
+guint8 nm_device_ip_tunnel_get_encapsulation_limit (NMDeviceIPTunnel *device);
+NM_AVAILABLE_IN_1_2
+guint nm_device_ip_tunnel_get_flow_label (NMDeviceIPTunnel *device);
+
+G_END_DECLS
+
+#endif /* __NM_DEVICE_IP_TUNNEL_H__ */
diff --git a/libnm/nm-device.c b/libnm/nm-device.c
index e6e5126f51..3ca08c55ce 100644
--- a/libnm/nm-device.c
+++ b/libnm/nm-device.c
@@ -41,6 +41,7 @@
#include "nm-device-bridge.h"
#include "nm-device-vlan.h"
#include "nm-device-generic.h"
+#include "nm-device-ip-tunnel.h"
#include "nm-device.h"
#include "nm-device-private.h"
#include "nm-dhcp4-config.h"
@@ -365,6 +366,8 @@ _nm_device_gtype_from_dtype (NMDeviceType dtype)
return NM_TYPE_DEVICE_GENERIC;
case NM_DEVICE_TYPE_TUN:
return NM_TYPE_DEVICE_TUN;
+ case NM_DEVICE_TYPE_IP_TUNNEL:
+ return NM_TYPE_DEVICE_IP_TUNNEL;
default:
g_warning ("Unknown device type %d", dtype);
return G_TYPE_INVALID;
diff --git a/libnm/nm-types.h b/libnm/nm-types.h
index 334e4a17b7..f69deffaec 100644
--- a/libnm/nm-types.h
+++ b/libnm/nm-types.h
@@ -37,6 +37,7 @@ typedef struct _NMDeviceBt NMDeviceBt;
typedef struct _NMDeviceEthernet NMDeviceEthernet;
typedef struct _NMDeviceGeneric NMDeviceGeneric;
typedef struct _NMDeviceInfiniband NMDeviceInfiniband;
+typedef struct _NMDeviceIPTunnel NMDeviceIPTunnel;
typedef struct _NMDeviceModem NMDeviceModem;
typedef struct _NMDeviceOlpcMesh NMDeviceOlpcMesh;
typedef struct _NMDeviceTeam NMDeviceTeam;
diff --git a/po/POTFILES.in b/po/POTFILES.in
index ca4b76ab1f..a451d8dd00 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -65,6 +65,7 @@ libnm-core/nm-setting-infiniband.c
libnm-core/nm-setting-ip-config.c
libnm-core/nm-setting-ip4-config.c
libnm-core/nm-setting-ip6-config.c
+libnm-core/nm-setting-ip-tunnel.c
libnm-core/nm-setting-olpc-mesh.c
libnm-core/nm-setting-ppp.c
libnm-core/nm-setting-pppoe.c
@@ -119,6 +120,7 @@ libnm/nm-device-ethernet.c
libnm/nm-device-generic.c
libnm/nm-device-tun.c
libnm/nm-device-infiniband.c
+libnm/nm-device-ip-tunnel.c
libnm/nm-device-modem.c
libnm/nm-device-olpc-mesh.c
libnm/nm-device-team.c
@@ -148,6 +150,7 @@ src/devices/nm-device-bridge.c
src/devices/nm-device-ethernet.c
src/devices/nm-device-ethernet-utils.c
src/devices/nm-device-infiniband.c
+src/devices/nm-device-ip-tunnel.c
src/devices/nm-device-tun.c
src/devices/nm-device-vlan.c
src/devices/team/nm-device-team.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 89681f1970..e4b2cb090c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -204,8 +204,8 @@ nm_device_sources = \
devices/nm-device-bond.c \
devices/nm-device-bridge.c \
devices/nm-device-ethernet.c \
- devices/nm-device-gre.c \
devices/nm-device-infiniband.c \
+ devices/nm-device-ip-tunnel.c \
devices/nm-device-macvlan.c \
devices/nm-device-tun.c \
devices/nm-device-veth.c \
@@ -217,8 +217,8 @@ nm_device_headers = \
devices/nm-device-bond.h \
devices/nm-device-bridge.h \
devices/nm-device-ethernet.h \
- devices/nm-device-gre.h \
devices/nm-device-infiniband.h \
+ devices/nm-device-ip-tunnel.h \
devices/nm-device-macvlan.h \
devices/nm-device-tun.h \
devices/nm-device-veth.h \
diff --git a/src/devices/nm-device-gre.c b/src/devices/nm-device-gre.c
deleted file mode 100644
index 9b9ffc9be1..0000000000
--- a/src/devices/nm-device-gre.c
+++ /dev/null
@@ -1,287 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* NetworkManager -- Network link manager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright 2013 Red Hat, Inc.
- */
-
-#include "config.h"
-
-#include <string.h>
-#include <arpa/inet.h>
-
-#include "nm-device-gre.h"
-#include "nm-device-private.h"
-#include "nm-default.h"
-#include "nm-manager.h"
-#include "nm-platform.h"
-#include "nm-device-factory.h"
-#include "nm-core-internal.h"
-
-#include "nmdbus-device-gre.h"
-
-#include "nm-device-logging.h"
-_LOG_DECLARE_SELF(NMDeviceGre);
-
-G_DEFINE_TYPE (NMDeviceGre, nm_device_gre, NM_TYPE_DEVICE_GENERIC)
-
-#define NM_DEVICE_GRE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_GRE, NMDeviceGrePrivate))
-
-typedef struct {
- NMPlatformLnkGre props;
-} NMDeviceGrePrivate;
-
-enum {
- PROP_0,
- PROP_PARENT,
- PROP_INPUT_FLAGS,
- PROP_OUTPUT_FLAGS,
- PROP_INPUT_KEY,
- PROP_OUTPUT_KEY,
- PROP_LOCAL,
- PROP_REMOTE,
- PROP_TTL,
- PROP_TOS,
- PROP_PATH_MTU_DISCOVERY,
-
- LAST_PROP
-};
-
-/**************************************************************/
-
-static void
-update_properties (NMDevice *device)
-{
- NMDeviceGre *self = NM_DEVICE_GRE (device);
- NMDeviceGrePrivate *priv = NM_DEVICE_GRE_GET_PRIVATE (self);
- GObject *object = G_OBJECT (device);
- const NMPlatformLnkGre *props;
-
- props = nm_platform_link_get_lnk_gre (NM_PLATFORM_GET, nm_device_get_ifindex (device), NULL);
- if (!props) {
- _LOGW (LOGD_HW, "could not read gre properties");
- return;
- }
-
- g_object_freeze_notify (object);
-
- if (priv->props.parent_ifindex != props->parent_ifindex)
- g_object_notify (object, NM_DEVICE_GRE_PARENT);
- if (priv->props.input_flags != props->input_flags)
- g_object_notify (object, NM_DEVICE_GRE_INPUT_FLAGS);
- if (priv->props.output_flags != props->output_flags)
- g_object_notify (object, NM_DEVICE_GRE_OUTPUT_FLAGS);
- if (priv->props.input_key != props->input_key)
- g_object_notify (object, NM_DEVICE_GRE_INPUT_KEY);
- if (priv->props.output_key != props->output_key)
- g_object_notify (object, NM_DEVICE_GRE_OUTPUT_KEY);
- if (priv->props.local != props->local)
- g_object_notify (object, NM_DEVICE_GRE_LOCAL);
- if (priv->props.remote != props->remote)
- g_object_notify (object, NM_DEVICE_GRE_REMOTE);
- if (priv->props.ttl != props->ttl)
- g_object_notify (object, NM_DEVICE_GRE_TTL);
- if (priv->props.tos != props->tos)
- g_object_notify (object, NM_DEVICE_GRE_TOS);
- if (priv->props.path_mtu_discovery != props->path_mtu_discovery)
- g_object_notify (object, NM_DEVICE_GRE_PATH_MTU_DISCOVERY);
-
- priv->props = *props;
-
- g_object_thaw_notify (object);
-}
-
-static void
-link_changed (NMDevice *device, NMPlatformLink *info)
-{
- NM_DEVICE_CLASS (nm_device_gre_parent_class)->link_changed (device, info);
- update_properties (device);
-}
-
-/**************************************************************/
-
-static void
-nm_device_gre_init (NMDeviceGre *self)
-{
-}
-
-static void
-constructed (GObject *object)
-{
- update_properties (NM_DEVICE (object));
-
- G_OBJECT_CLASS (nm_device_gre_parent_class)->constructed (object);
-}
-
-static void
-get_property (GObject *object, guint prop_id,
- GValue *value, GParamSpec *pspec)
-{
- NMDeviceGrePrivate *priv = NM_DEVICE_GRE_GET_PRIVATE (object);
- char buf[INET_ADDRSTRLEN];
- NMDevice *parent;
-
- switch (prop_id) {
- case PROP_PARENT:
- parent = nm_manager_get_device_by_ifindex (nm_manager_get (), priv->props.parent_ifindex);
- nm_utils_g_value_set_object_path (value, parent);
- break;
- case PROP_INPUT_FLAGS:
- g_value_set_uint (value, priv->props.input_flags);
- break;
- case PROP_OUTPUT_FLAGS:
- g_value_set_uint (value, priv->props.output_flags);
- break;
- case PROP_INPUT_KEY:
- g_value_set_uint (value, priv->props.input_key);
- break;
- case PROP_OUTPUT_KEY:
- g_value_set_uint (value, priv->props.output_key);
- break;
- case PROP_LOCAL:
- g_value_set_string (value, inet_ntop (AF_INET, &priv->props.local, buf, sizeof (buf)));
- break;
- case PROP_REMOTE:
- g_value_set_string (value, inet_ntop (AF_INET, &priv->props.remote, buf, sizeof (buf)));
- break;
- case PROP_TTL:
- g_value_set_uchar (value, priv->props.ttl);
- break;
- case PROP_TOS:
- g_value_set_uchar (value, priv->props.tos);
- break;
- case PROP_PATH_MTU_DISCOVERY:
- g_value_set_boolean (value, priv->props.path_mtu_discovery);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-nm_device_gre_class_init (NMDeviceGreClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- NMDeviceClass *device_class = NM_DEVICE_CLASS (klass);
-
- g_type_class_add_private (klass, sizeof (NMDeviceGrePrivate));
-
- object_class->constructed = constructed;
- object_class->get_property = get_property;
-
- device_class->link_changed = link_changed;
-
- /* properties */
- g_object_class_install_property
- (object_class, PROP_PARENT,
- g_param_spec_string (NM_DEVICE_GRE_PARENT, "", "",
- NULL,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property
- (object_class, PROP_INPUT_FLAGS,
- g_param_spec_uint (NM_DEVICE_GRE_INPUT_FLAGS, "", "",
- 0, G_MAXUINT16, 0,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property
- (object_class, PROP_OUTPUT_FLAGS,
- g_param_spec_uint (NM_DEVICE_GRE_OUTPUT_FLAGS, "", "",
- 0, G_MAXUINT16, 0,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property
- (object_class, PROP_INPUT_KEY,
- g_param_spec_uint (NM_DEVICE_GRE_INPUT_KEY, "", "",
- 0, G_MAXUINT32, 0,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property
- (object_class, PROP_OUTPUT_KEY,
- g_param_spec_uint (NM_DEVICE_GRE_OUTPUT_KEY, "", "",
- 0, G_MAXUINT32, 0,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property
- (object_class, PROP_LOCAL,
- g_param_spec_string (NM_DEVICE_GRE_LOCAL, "", "",
- NULL,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property
- (object_class, PROP_REMOTE,
- g_param_spec_string (NM_DEVICE_GRE_REMOTE, "", "",
- NULL,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property
- (object_class, PROP_TTL,
- g_param_spec_uchar (NM_DEVICE_GRE_TTL, "", "",
- 0, 255, 0,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property
- (object_class, PROP_TOS,
- g_param_spec_uchar (NM_DEVICE_GRE_TOS, "", "",
- 0, 255, 0,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property
- (object_class, PROP_PATH_MTU_DISCOVERY,
- g_param_spec_boolean (NM_DEVICE_GRE_PATH_MTU_DISCOVERY, "", "",
- FALSE,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass),
- NMDBUS_TYPE_DEVICE_GRE_SKELETON,
- NULL);
-}
-
-/*************************************************************/
-
-#define NM_TYPE_GRE_FACTORY (nm_gre_factory_get_type ())
-#define NM_GRE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_GRE_FACTORY, NMGreFactory))
-
-static NMDevice *
-create_device (NMDeviceFactory *factory,
- const char *iface,
- NMPlatformLink *plink,
- NMConnection *connection,
- gboolean *out_ignore)
-{
- return (NMDevice *) g_object_new (NM_TYPE_DEVICE_GRE,
- NM_DEVICE_IFACE, iface,
- NM_DEVICE_TYPE_DESC, "Gre",
- NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC,
- NULL);
-}
-
-NM_DEVICE_FACTORY_DEFINE_INTERNAL (GRE, Gre, gre,
- NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_GRE, NM_LINK_TYPE_GRETAP),
- factory_iface->create_device = create_device;
- )
-
diff --git a/src/devices/nm-device-gre.h b/src/devices/nm-device-gre.h
deleted file mode 100644
index 7e2d105c4b..0000000000
--- a/src/devices/nm-device-gre.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* NetworkManager -- Network link manager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright 2013 Red Hat, Inc.
- */
-
-#ifndef __NETWORKMANAGER_DEVICE_GRE_H__
-#define __NETWORKMANAGER_DEVICE_GRE_H__
-
-#include "nm-device-generic.h"
-
-G_BEGIN_DECLS
-
-#define NM_TYPE_DEVICE_GRE (nm_device_gre_get_type ())
-#define NM_DEVICE_GRE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_GRE, NMDeviceGre))
-#define NM_DEVICE_GRE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_GRE, NMDeviceGreClass))
-#define NM_IS_DEVICE_GRE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_GRE))
-#define NM_IS_DEVICE_GRE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_GRE))
-#define NM_DEVICE_GRE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_GRE, NMDeviceGreClass))
-
-#define NM_DEVICE_GRE_PARENT "parent"
-#define NM_DEVICE_GRE_INPUT_FLAGS "input-flags"
-#define NM_DEVICE_GRE_OUTPUT_FLAGS "output-flags"
-#define NM_DEVICE_GRE_INPUT_KEY "input-key"
-#define NM_DEVICE_GRE_OUTPUT_KEY "output-key"
-#define NM_DEVICE_GRE_LOCAL "local"
-#define NM_DEVICE_GRE_REMOTE "remote"
-#define NM_DEVICE_GRE_TTL "ttl"
-#define NM_DEVICE_GRE_TOS "tos"
-#define NM_DEVICE_GRE_PATH_MTU_DISCOVERY "path-mtu-discovery"
-
-typedef NMDeviceGeneric NMDeviceGre;
-typedef NMDeviceGenericClass NMDeviceGreClass;
-
-GType nm_device_gre_get_type (void);
-
-G_END_DECLS
-
-#endif /* NM_DEVICE_GRE_H */
diff --git a/src/devices/nm-device-ip-tunnel.c b/src/devices/nm-device-ip-tunnel.c
new file mode 100644
index 0000000000..746fb170d0
--- /dev/null
+++ b/src/devices/nm-device-ip-tunnel.c
@@ -0,0 +1,971 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2015 Red Hat, Inc.
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <netinet/in.h>
+#include <linux/if.h>
+#include <linux/ip.h>
+#include <linux/if_tunnel.h>
+
+#include "nm-device-ip-tunnel.h"
+#include "nm-device-private.h"
+#include "nm-default.h"
+#include "nm-manager.h"
+#include "nm-platform.h"
+#include "nm-device-factory.h"
+#include "nm-core-internal.h"
+#include "nm-connection-provider.h"
+#include "nm-activation-request.h"
+
+#include "nmdbus-device-ip-tunnel.h"
+
+#include "nm-device-logging.h"
+_LOG_DECLARE_SELF(NMDeviceIPTunnel);
+
+G_DEFINE_TYPE (NMDeviceIPTunnel, nm_device_ip_tunnel, NM_TYPE_DEVICE)
+
+#define NM_DEVICE_IP_TUNNEL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_IP_TUNNEL, NMDeviceIPTunnelPrivate))
+
+typedef struct {
+ NMIPTunnelMode mode;
+ NMDevice *parent;
+ int parent_ifindex;
+ char *local;
+ char *remote;
+ guint8 ttl;
+ guint8 tos;
+ gboolean path_mtu_discovery;
+ int addr_family;
+ char *input_key;
+ char *output_key;
+ guint8 encap_limit;
+ guint32 flow_label;
+} NMDeviceIPTunnelPrivate;
+
+enum {
+ PROP_0,
+ PROP_MODE,
+ PROP_PARENT,
+ PROP_LOCAL,
+ PROP_REMOTE,
+ PROP_TTL,
+ PROP_TOS,
+ PROP_PATH_MTU_DISCOVERY,
+ PROP_INPUT_KEY,
+ PROP_OUTPUT_KEY,
+ PROP_ENCAPSULATION_LIMIT,
+ PROP_FLOW_LABEL,
+
+ LAST_PROP
+};
+
+/**************************************************************/
+
+static gboolean
+address_equal_pp (int family, const char *a, const char *b)
+{
+ char buffer1[sizeof (struct in6_addr)] = { };
+ char buffer2[sizeof (struct in6_addr)] = { };
+
+ g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE);
+
+ if (a)
+ inet_pton (family, a, buffer1);
+ if (b)
+ inet_pton (family, b, buffer2);
+
+ return !memcmp (buffer1, buffer2,
+ family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr));
+}
+
+static gboolean
+address_equal_pn (int family, const char *a, const void *b)
+{
+ char buffer1[sizeof (struct in6_addr)] = { };
+
+ g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE);
+
+ if (a)
+ inet_pton (family, a, buffer1);
+
+ return !memcmp (buffer1, b,
+ family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr));
+
+}
+
+static void
+update_properties (NMDevice *device)
+{
+ NMDeviceIPTunnel *self = NM_DEVICE_IP_TUNNEL (device);
+ NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (self);
+ GObject *object = G_OBJECT (device);
+ NMDevice *parent;
+ int parent_ifindex;
+ in_addr_t local4, remote4;
+ struct in6_addr local6, remote6;
+ guint8 ttl = 0, tos = 0, encap_limit = 0;
+ gboolean pmtud = FALSE;
+ guint32 flow_label = 0;
+ char *key;
+
+ if (priv->mode == NM_IP_TUNNEL_MODE_GRE) {
+ const NMPlatformLnkGre *lnk;
+
+ lnk = nm_platform_link_get_lnk_gre (NM_PLATFORM_GET, nm_device_get_ifindex (device), NULL);
+ if (!lnk) {
+ _LOGW (LOGD_HW, "could not read %s properties", "gre");
+ return;
+ }
+
+ parent_ifindex = lnk->parent_ifindex;
+ local4 = lnk->local;
+ remote4 = lnk->remote;
+ ttl = lnk->ttl;
+ tos = lnk->tos;
+ pmtud = lnk->path_mtu_discovery;
+
+ if (NM_FLAGS_HAS (lnk->input_flags, NM_GRE_KEY)) {
+ key = g_strdup_printf ("%u", lnk->input_key);
+ if (g_strcmp0 (priv->input_key, key)) {
+ g_free (priv->input_key);
+ priv->input_key = key;
+ g_object_notify (object, NM_DEVICE_IP_TUNNEL_INPUT_KEY);
+ } else
+ g_free (key);
+ } else {
+ if (priv->input_key) {
+ g_clear_pointer (&priv->input_key, g_free);
+ g_object_notify (object, NM_DEVICE_IP_TUNNEL_INPUT_KEY);
+ }
+ }
+
+ if (NM_FLAGS_HAS (lnk->output_flags, NM_GRE_KEY)) {
+ key = g_strdup_printf ("%u", lnk->output_key);
+ if (g_strcmp0 (priv->output_key, key)) {
+ g_free (priv->output_key);
+ priv->output_key = key;
+ g_object_notify (object, NM_DEVICE_IP_TUNNEL_OUTPUT_KEY);
+ } else
+ g_free (key);
+ } else {
+ if (priv->output_key) {
+ g_clear_pointer (&priv->output_key, g_free);
+ g_object_notify (object, NM_DEVICE_IP_TUNNEL_OUTPUT_KEY);
+ }
+ }
+ } else if (priv->mode == NM_IP_TUNNEL_MODE_SIT) {
+ const NMPlatformLnkSit *lnk;
+
+ lnk = nm_platform_link_get_lnk_sit (NM_PLATFORM_GET, nm_device_get_ifindex (device), NULL);
+ if (!lnk) {
+ _LOGW (LOGD_HW, "could not read %s properties", "sit");
+ return;
+ }
+
+ parent_ifindex = lnk->parent_ifindex;
+ local4 = lnk->local;
+ remote4 = lnk->remote;
+ ttl = lnk->ttl;
+ tos = lnk->tos;
+ pmtud = lnk->path_mtu_discovery;
+ } else if (priv->mode == NM_IP_TUNNEL_MODE_IPIP) {
+ const NMPlatformLnkIpIp *lnk;
+
+ lnk = nm_platform_link_get_lnk_ipip (NM_PLATFORM_GET, nm_device_get_ifindex (device), NULL);
+ if (!lnk) {
+ _LOGW (LOGD_HW, "could not read %s properties", "ipip");
+ return;
+ }
+
+ parent_ifindex = lnk->parent_ifindex;
+ local4 = lnk->local;
+ remote4 = lnk->remote;
+ ttl = lnk->ttl;
+ tos = lnk->tos;
+ pmtud = lnk->path_mtu_discovery;
+ } else if ( priv->mode == NM_IP_TUNNEL_MODE_IPIP6
+ || priv->mode == NM_IP_TUNNEL_MODE_IP6IP6) {
+ const NMPlatformLnkIp6Tnl *lnk;
+
+ lnk = nm_platform_link_get_lnk_ip6tnl (NM_PLATFORM_GET, nm_device_get_ifindex (device), NULL);
+ if (!lnk) {
+ _LOGW (LOGD_HW, "could not read %s properties", "ip6tnl");
+ return;
+ }
+
+ parent_ifindex = lnk->parent_ifindex;
+ local6 = lnk->local;
+ remote6 = lnk->remote;
+ ttl = lnk->ttl;
+ tos = lnk->tclass;
+ encap_limit = lnk->encap_limit;
+ flow_label = lnk->flow_label;
+ } else
+ g_return_if_reached ();
+
+ if (priv->parent_ifindex != parent_ifindex) {
+ g_clear_object (&priv->parent);
+ priv->parent_ifindex = parent_ifindex;
+ parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex);
+ if (parent)
+ priv->parent = g_object_ref (parent);
+ g_object_notify (object, NM_DEVICE_IP_TUNNEL_PARENT);
+ }
+
+ if (priv->addr_family == AF_INET) {
+ if (!address_equal_pn (AF_INET, priv->local, &local4)) {
+ g_clear_pointer (&priv->local, g_free);
+ if (local4)
+ priv->local = g_strdup (nm_utils_inet4_ntop (local4, NULL));
+ g_object_notify (object, NM_DEVICE_IP_TUNNEL_LOCAL);
+ }
+
+ if (!address_equal_pn (AF_INET, priv->remote, &remote4)) {
+ g_clear_pointer (&priv->remote, g_free);
+ if (remote4)
+ priv->remote = g_strdup (nm_utils_inet4_ntop (remote4, NULL));
+ g_object_notify (object, NM_DEVICE_IP_TUNNEL_REMOTE);
+ }
+ } else {
+ if (!address_equal_pn (AF_INET6, priv->local, &local6)) {
+ g_clear_pointer (&priv->local, g_free);
+ if (memcmp (&local6, &in6addr_any, sizeof (in6addr_any)))
+ priv->local = g_strdup (nm_utils_inet6_ntop (&local6, NULL));
+ g_object_notify (object, NM_DEVICE_IP_TUNNEL_LOCAL);
+ }
+
+ if (!address_equal_pn (AF_INET6, priv->remote, &remote6)) {
+ g_clear_pointer (&priv->remote, g_free);
+ if (memcmp (&remote6, &in6addr_any, sizeof (in6addr_any)))
+ priv->remote = g_strdup (nm_utils_inet6_ntop (&remote6, NULL));
+ g_object_notify (object, NM_DEVICE_IP_TUNNEL_REMOTE);
+ }
+ }
+
+ if (priv->ttl != ttl) {
+ priv->ttl = ttl;
+ g_object_notify (object, NM_DEVICE_IP_TUNNEL_TTL);
+ }
+
+ if (priv->tos != tos) {
+ priv->tos = tos;
+ g_object_notify (object, NM_DEVICE_IP_TUNNEL_TOS);
+ }
+
+ if (priv->path_mtu_discovery != pmtud) {
+ priv->path_mtu_discovery = pmtud;
+ g_object_notify (object, NM_DEVICE_IP_TUNNEL_PATH_MTU_DISCOVERY);
+ }
+
+ if (priv->encap_limit != encap_limit) {
+ priv->encap_limit = encap_limit;
+ g_object_notify (object, NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT);
+ }
+
+ if (priv->flow_label != flow_label) {
+ priv->flow_label = flow_label;
+ g_object_notify (object, NM_DEVICE_IP_TUNNEL_FLOW_LABEL);
+ }
+}
+
+static void
+link_changed (NMDevice *device, NMPlatformLink *info)
+{
+ NM_DEVICE_CLASS (nm_device_ip_tunnel_parent_class)->link_changed (device, info);
+ update_properties (device);
+}
+
+static gboolean
+complete_connection (NMDevice *device,
+ NMConnection *connection,
+ const char *specific_object,
+ const GSList *existing_connections,
+ GError **error)
+{
+ NMSettingIPTunnel *s_ip_tunnel;
+
+ nm_utils_complete_generic (connection,
+ NM_SETTING_IP_TUNNEL_SETTING_NAME,
+ existing_connections,
+ NULL,
+ _("IP tunnel connection"),
+ NULL,
+ TRUE);
+
+ s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection);
+ if (!s_ip_tunnel) {
+ g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION,
+ "A 'tunnel' setting is required.");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+update_connection (NMDevice *device, NMConnection *connection)
+{
+ NMDeviceIPTunnel *self = NM_DEVICE_IP_TUNNEL (device);
+ NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (self);
+ NMSettingIPTunnel *s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection);
+ NMDevice *parent = NULL;
+ const char *setting_parent, *new_parent;
+
+ if (!s_ip_tunnel) {
+ s_ip_tunnel = (NMSettingIPTunnel *) nm_setting_ip_tunnel_new ();
+ nm_connection_add_setting (connection, (NMSetting *) s_ip_tunnel);
+ }
+
+ update_properties (device);
+
+ if (nm_setting_ip_tunnel_get_mode (s_ip_tunnel) != priv->mode)
+ g_object_set (G_OBJECT (s_ip_tunnel), NM_SETTING_IP_TUNNEL_MODE, priv->mode, NULL);
+
+ if (priv->parent_ifindex > 0)
+ parent = nm_manager_get_device_by_ifindex (nm_manager_get (), priv->parent_ifindex);
+
+ /* Update parent in the connection; default to parent's interface name */
+ if (parent) {
+ new_parent = nm_device_get_iface (parent);
+ setting_parent = nm_setting_ip_tunnel_get_parent (s_ip_tunnel);
+ if (setting_parent && nm_utils_is_uuid (setting_parent)) {
+ NMConnection *parent_connection;
+
+ /* Don't change a parent specified by UUID if it's still valid */
+ parent_connection = nm_connection_provider_get_connection_by_uuid (nm_connection_provider_get (),
+ setting_parent);
+ if (parent_connection && nm_device_check_connection_compatible (parent, parent_connection))
+ new_parent = NULL;
+ }
+ if (new_parent)
+ g_object_set (s_ip_tunnel, NM_SETTING_IP_TUNNEL_PARENT, new_parent, NULL);
+ } else
+ g_object_set (s_ip_tunnel, NM_SETTING_IP_TUNNEL_PARENT, NULL, NULL);
+
+ if (!address_equal_pp (priv->addr_family,
+ nm_setting_ip_tunnel_get_local (s_ip_tunnel),
+ priv->local))
+ g_object_set (G_OBJECT (s_ip_tunnel), NM_SETTING_IP_TUNNEL_LOCAL, priv->local, NULL);
+
+ if (!address_equal_pp (priv->addr_family,
+ nm_setting_ip_tunnel_get_remote (s_ip_tunnel),
+ priv->remote))
+ g_object_set (G_OBJECT (s_ip_tunnel), NM_SETTING_IP_TUNNEL_REMOTE, priv->remote, NULL);
+
+ if (nm_setting_ip_tunnel_get_ttl (s_ip_tunnel) != priv->ttl)
+ g_object_set (G_OBJECT (s_ip_tunnel), NM_SETTING_IP_TUNNEL_TTL, priv->ttl, NULL);
+
+ if (nm_setting_ip_tunnel_get_tos (s_ip_tunnel) != priv->tos)
+ g_object_set (G_OBJECT (s_ip_tunnel), NM_SETTING_IP_TUNNEL_TOS, priv->tos, NULL);
+
+ if (nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel) != priv->path_mtu_discovery) {
+ g_object_set (G_OBJECT (s_ip_tunnel),
+ NM_SETTING_IP_TUNNEL_PATH_MTU_DISCOVERY,
+ priv->path_mtu_discovery,
+ NULL);
+ }
+
+ if (nm_setting_ip_tunnel_get_encapsulation_limit (s_ip_tunnel) != priv->encap_limit) {
+ g_object_set (G_OBJECT (s_ip_tunnel),
+ NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT,
+ priv->encap_limit,
+ NULL);
+ }
+
+ if (nm_setting_ip_tunnel_get_flow_label (s_ip_tunnel) != priv->flow_label) {
+ g_object_set (G_OBJECT (s_ip_tunnel),
+ NM_SETTING_IP_TUNNEL_FLOW_LABEL,
+ priv->flow_label,
+ NULL);
+ }
+
+ if (priv->mode == NM_IP_TUNNEL_MODE_GRE || priv->mode == NM_IP_TUNNEL_MODE_IP6GRE) {
+ if (g_strcmp0 (nm_setting_ip_tunnel_get_input_key (s_ip_tunnel), priv->input_key)) {
+ g_object_set (G_OBJECT (s_ip_tunnel),
+ NM_SETTING_IP_TUNNEL_INPUT_KEY,
+ priv->input_key,
+ NULL);
+ }
+ if (g_strcmp0 (nm_setting_ip_tunnel_get_output_key (s_ip_tunnel), priv->output_key)) {
+ g_object_set (G_OBJECT (s_ip_tunnel),
+ NM_SETTING_IP_TUNNEL_OUTPUT_KEY,
+ priv->output_key,
+ NULL);
+ }
+ }
+}
+
+static gboolean
+realize (NMDevice *self, NMPlatformLink *plink, GError **error)
+{
+ update_properties (self);
+ return TRUE;
+}
+
+static gboolean
+match_parent (NMDevice *dev_parent, const char *setting_parent)
+{
+ g_return_val_if_fail (setting_parent, FALSE);
+
+ if (!dev_parent)
+ return FALSE;
+
+ if (nm_utils_is_uuid (setting_parent)) {
+ NMActRequest *parent_req;
+ NMConnection *parent_connection;
+
+ /* If the parent is a UUID, the connection matches if our parent
+ * device has that connection activated.
+ */
+ parent_req = nm_device_get_act_request (dev_parent);
+ if (!parent_req)
+ return FALSE;
+
+ parent_connection = nm_active_connection_get_applied_connection (NM_ACTIVE_CONNECTION (parent_req));
+ if (!parent_connection)
+ return FALSE;
+
+ if (g_strcmp0 (setting_parent, nm_connection_get_uuid (parent_connection)) != 0)
+ return FALSE;
+ } else {
+ /* interface name */
+ if (g_strcmp0 (setting_parent, nm_device_get_ip_iface (dev_parent)) != 0)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+check_connection_compatible (NMDevice *device, NMConnection *connection)
+{
+ NMDeviceIPTunnel *self = NM_DEVICE_IP_TUNNEL (device);
+ NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (self);
+ NMSettingIPTunnel *s_ip_tunnel;
+ const char *parent;
+
+ if (!NM_DEVICE_CLASS (nm_device_ip_tunnel_parent_class)->check_connection_compatible (device, connection))
+ return FALSE;
+
+ s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection);
+ if (!s_ip_tunnel)
+ return FALSE;
+
+ update_properties (device);
+
+ /* Check parent interface; could be an interface name or a UUID */
+ parent = nm_setting_ip_tunnel_get_parent (s_ip_tunnel);
+ if (parent) {
+ if (!match_parent (priv->parent, parent))
+ return FALSE;
+ }
+
+ if (nm_setting_ip_tunnel_get_mode (s_ip_tunnel) != priv->mode)
+ return FALSE;
+
+ if (!address_equal_pp (priv->addr_family,
+ nm_setting_ip_tunnel_get_local (s_ip_tunnel),
+ priv->local))
+ return FALSE;
+
+ if (!address_equal_pp (priv->addr_family,
+ nm_setting_ip_tunnel_get_remote (s_ip_tunnel),
+ priv->remote))
+ return FALSE;
+
+ if (nm_setting_ip_tunnel_get_ttl (s_ip_tunnel) != priv->ttl)
+ return FALSE;
+
+ if (nm_setting_ip_tunnel_get_tos (s_ip_tunnel) != priv->tos)
+ return FALSE;
+
+ if (priv->addr_family == AF_INET) {
+ if (nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel) != priv->path_mtu_discovery)
+ return FALSE;
+ } else {
+ if (nm_setting_ip_tunnel_get_encapsulation_limit (s_ip_tunnel) != priv->encap_limit)
+ return FALSE;
+
+ if (nm_setting_ip_tunnel_get_flow_label (s_ip_tunnel) != priv->flow_label)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static NMIPTunnelMode
+platform_link_to_tunnel_mode (const NMPlatformLink *link)
+{
+ const NMPlatformLnkIp6Tnl *lnk;
+
+ switch (link->type) {
+ case NM_LINK_TYPE_GRE:
+ return NM_IP_TUNNEL_MODE_GRE;
+ case NM_LINK_TYPE_IP6TNL:
+ lnk = nm_platform_link_get_lnk_ip6tnl (NM_PLATFORM_GET, link->ifindex, NULL);
+ if (lnk->proto == IPPROTO_IPIP)
+ return NM_IP_TUNNEL_MODE_IPIP6;
+ else if (lnk->proto == IPPROTO_IPV6)
+ return NM_IP_TUNNEL_MODE_IP6IP6;
+ else
+ return NM_IP_TUNNEL_MODE_UKNOWN;
+ case NM_LINK_TYPE_IPIP:
+ return NM_IP_TUNNEL_MODE_IPIP;
+ case NM_LINK_TYPE_SIT:
+ return NM_IP_TUNNEL_MODE_SIT;
+ default:
+ g_return_val_if_reached (NM_IP_TUNNEL_MODE_UKNOWN);
+ }
+}
+
+/**************************************************************/
+
+static void
+nm_device_ip_tunnel_init (NMDeviceIPTunnel *self)
+{
+}
+
+static void
+constructed (GObject *object)
+{
+ NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (object);
+
+ if ( priv->mode == NM_IP_TUNNEL_MODE_IPIP6
+ || priv->mode == NM_IP_TUNNEL_MODE_IP6IP6)
+ priv->addr_family = AF_INET6;
+ else
+ priv->addr_family = AF_INET;
+
+ G_OBJECT_CLASS (nm_device_ip_tunnel_parent_class)->constructed (object);
+}
+
+static gboolean
+create_and_realize (NMDevice *device,
+ NMConnection *connection,
+ NMDevice *parent,
+ NMPlatformLink *out_plink,
+ GError **error)
+{
+ const char *iface = nm_device_get_iface (device);
+ NMSettingIPTunnel *s_ip_tunnel;
+ NMPlatformError plerr;
+ NMPlatformLnkGre lnk_gre = { };
+ NMPlatformLnkSit lnk_sit = { };
+ NMPlatformLnkIpIp lnk_ipip = { };
+ NMPlatformLnkIp6Tnl lnk_ip6tnl = { };
+ const char *str;
+ gint64 val;
+
+ s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection);
+ g_assert (s_ip_tunnel);
+ g_assert (out_plink);
+
+ switch (nm_setting_ip_tunnel_get_mode (s_ip_tunnel)) {
+ case NM_IP_TUNNEL_MODE_GRE:
+ if (parent)
+ lnk_gre.parent_ifindex = nm_device_get_ifindex (parent);
+
+ str = nm_setting_ip_tunnel_get_local (s_ip_tunnel);
+ if (str)
+ inet_pton (AF_INET, str, &lnk_gre.local);
+
+ str = nm_setting_ip_tunnel_get_remote (s_ip_tunnel);
+ g_assert (str);
+ inet_pton (AF_INET, str, &lnk_gre.remote);
+
+ lnk_gre.ttl = nm_setting_ip_tunnel_get_ttl (s_ip_tunnel);
+ lnk_gre.tos = nm_setting_ip_tunnel_get_tos (s_ip_tunnel);
+ lnk_gre.path_mtu_discovery = nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel);
+
+ val = _nm_utils_ascii_str_to_int64 (nm_setting_ip_tunnel_get_input_key (s_ip_tunnel),
+ 10,
+ 0,
+ G_MAXUINT32,
+ -1);
+ if (val != -1) {
+ lnk_gre.input_key = val;
+ lnk_gre.input_flags = NM_GRE_KEY;
+ }
+
+ val = _nm_utils_ascii_str_to_int64 (nm_setting_ip_tunnel_get_output_key (s_ip_tunnel),
+ 10,
+ 0,
+ G_MAXUINT32,
+ -1);
+ if (val != -1) {
+ lnk_gre.output_key = val;
+ lnk_gre.output_flags = NM_GRE_KEY;
+ }
+
+ plerr = nm_platform_link_gre_add (NM_PLATFORM_GET, iface, &lnk_gre, out_plink);
+ if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) {
+ g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
+ "Failed to create GRE interface '%s' for '%s': %s",
+ iface,
+ nm_connection_get_id (connection),
+ nm_platform_error_to_string (plerr));
+ return FALSE;
+ }
+ break;
+ case NM_IP_TUNNEL_MODE_SIT:
+ if (parent)
+ lnk_sit.parent_ifindex = nm_device_get_ifindex (parent);
+
+ str = nm_setting_ip_tunnel_get_local (s_ip_tunnel);
+ if (str)
+ inet_pton (AF_INET, str, &lnk_sit.local);
+
+ str = nm_setting_ip_tunnel_get_remote (s_ip_tunnel);
+ g_assert (str);
+ inet_pton (AF_INET, str, &lnk_sit.remote);
+
+ lnk_sit.ttl = nm_setting_ip_tunnel_get_ttl (s_ip_tunnel);
+ lnk_sit.tos = nm_setting_ip_tunnel_get_tos (s_ip_tunnel);
+ lnk_sit.path_mtu_discovery = nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel);
+
+ plerr = nm_platform_link_sit_add (NM_PLATFORM_GET, iface, &lnk_sit, out_plink);
+ if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) {
+ g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
+ "Failed to create SIT interface '%s' for '%s': %s",
+ iface,
+ nm_connection_get_id (connection),
+ nm_platform_error_to_string (plerr));
+ return FALSE;
+ }
+ break;
+ case NM_IP_TUNNEL_MODE_IPIP:
+ if (parent)
+ lnk_ipip.parent_ifindex = nm_device_get_ifindex (parent);
+
+ str = nm_setting_ip_tunnel_get_local (s_ip_tunnel);
+ if (str)
+ inet_pton (AF_INET, str, &lnk_ipip.local);
+
+ str = nm_setting_ip_tunnel_get_remote (s_ip_tunnel);
+ g_assert (str);
+ inet_pton (AF_INET, str, &lnk_ipip.remote);
+
+ lnk_ipip.ttl = nm_setting_ip_tunnel_get_ttl (s_ip_tunnel);
+ lnk_ipip.tos = nm_setting_ip_tunnel_get_tos (s_ip_tunnel);
+ lnk_ipip.path_mtu_discovery = nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel);
+
+ plerr = nm_platform_link_ipip_add (NM_PLATFORM_GET, iface, &lnk_ipip, out_plink);
+ if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) {
+ g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
+ "Failed to create IPIP interface '%s' for '%s': %s",
+ iface,
+ nm_connection_get_id (connection),
+ nm_platform_error_to_string (plerr));
+ return FALSE;
+ }
+ break;
+ case NM_IP_TUNNEL_MODE_IPIP6:
+ case NM_IP_TUNNEL_MODE_IP6IP6:
+ if (parent)
+ lnk_ip6tnl.parent_ifindex = nm_device_get_ifindex (parent);
+
+ str = nm_setting_ip_tunnel_get_local (s_ip_tunnel);
+ if (str)
+ inet_pton (AF_INET6, str, &lnk_ip6tnl.local);
+
+ str = nm_setting_ip_tunnel_get_remote (s_ip_tunnel);
+ g_assert (str);
+ inet_pton (AF_INET6, str, &lnk_ip6tnl.remote);
+
+ lnk_ip6tnl.ttl = nm_setting_ip_tunnel_get_ttl (s_ip_tunnel);
+ lnk_ip6tnl.tclass = nm_setting_ip_tunnel_get_tos (s_ip_tunnel);
+ lnk_ip6tnl.encap_limit = nm_setting_ip_tunnel_get_encapsulation_limit (s_ip_tunnel);
+ lnk_ip6tnl.flow_label = nm_setting_ip_tunnel_get_flow_label (s_ip_tunnel);
+ lnk_ip6tnl.proto = nm_setting_ip_tunnel_get_mode (s_ip_tunnel) == NM_IP_TUNNEL_MODE_IPIP6 ? IPPROTO_IPIP : IPPROTO_IPV6;
+
+ plerr = nm_platform_link_ip6tnl_add (NM_PLATFORM_GET, iface, &lnk_ip6tnl, out_plink);
+ if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) {
+ g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
+ "Failed to create IPIP interface '%s' for '%s': %s",
+ iface,
+ nm_connection_get_id (connection),
+ nm_platform_error_to_string (plerr));
+ return FALSE;
+ }
+ break;
+ default:
+ g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
+ "Failed to create IP tunnel interface '%s' for '%s': mode %d not supported",
+ iface,
+ nm_connection_get_id (connection),
+ (int) nm_setting_ip_tunnel_get_mode (s_ip_tunnel));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+setup (NMDevice *device, NMPlatformLink *plink)
+{
+ NM_DEVICE_CLASS (nm_device_ip_tunnel_parent_class)->setup (device, plink);
+
+ update_properties (device);
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec)
+{
+ NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (object);
+ NMDevice *parent;
+
+ switch (prop_id) {
+ case PROP_MODE:
+ g_value_set_uint (value, priv->mode);
+ break;
+ case PROP_PARENT:
+ parent = nm_manager_get_device_by_ifindex (nm_manager_get (), priv->parent_ifindex);
+ nm_utils_g_value_set_object_path (value, parent);
+ break;
+ case PROP_LOCAL:
+ g_value_set_string (value, priv->local);
+ break;
+ case PROP_REMOTE:
+ g_value_set_string (value, priv->remote);
+ break;
+ case PROP_TTL:
+ g_value_set_uchar (value, priv->ttl);
+ break;
+ case PROP_TOS:
+ g_value_set_uchar (value, priv->tos);
+ break;
+ case PROP_PATH_MTU_DISCOVERY:
+ g_value_set_boolean (value, priv->path_mtu_discovery);
+ break;
+ case PROP_INPUT_KEY:
+ g_value_set_string (value, priv->input_key);
+ break;
+ case PROP_OUTPUT_KEY:
+ g_value_set_string (value, priv->output_key);
+ break;
+ case PROP_ENCAPSULATION_LIMIT:
+ g_value_set_uchar (value, priv->encap_limit);
+ break;
+ case PROP_FLOW_LABEL:
+ g_value_set_uint (value, priv->flow_label);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (object);
+
+ switch (prop_id) {
+ case PROP_MODE:
+ priv->mode = g_value_get_uint (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+nm_device_ip_tunnel_class_init (NMDeviceIPTunnelClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ NMDeviceClass *device_class = NM_DEVICE_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (NMDeviceIPTunnelPrivate));
+
+ object_class->constructed = constructed;
+ object_class->get_property = get_property;
+ object_class->set_property = set_property;
+
+ device_class->link_changed = link_changed;
+ device_class->complete_connection = complete_connection;
+ device_class->update_connection = update_connection;
+ device_class->check_connection_compatible = check_connection_compatible;
+ device_class->create_and_realize = create_and_realize;
+ device_class->realize = realize;
+ device_class->setup = setup;
+
+ device_class->connection_type = NM_SETTING_IP_TUNNEL_SETTING_NAME;
+
+ /* properties */
+ g_object_class_install_property
+ (object_class, PROP_MODE,
+ g_param_spec_uint (NM_DEVICE_IP_TUNNEL_MODE, "", "",
+ 0, G_MAXUINT, 0,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ /* properties */
+ g_object_class_install_property
+ (object_class, PROP_PARENT,
+ g_param_spec_string (NM_DEVICE_IP_TUNNEL_PARENT, "", "",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property
+ (object_class, PROP_LOCAL,
+ g_param_spec_string (NM_DEVICE_IP_TUNNEL_LOCAL, "", "",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property
+ (object_class, PROP_REMOTE,
+ g_param_spec_string (NM_DEVICE_IP_TUNNEL_REMOTE, "", "",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property
+ (object_class, PROP_TTL,
+ g_param_spec_uchar (NM_DEVICE_IP_TUNNEL_TTL, "", "",
+ 0, 255, 0,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property
+ (object_class, PROP_TOS,
+ g_param_spec_uchar (NM_DEVICE_IP_TUNNEL_TOS, "", "",
+ 0, 255, 0,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property
+ (object_class, PROP_PATH_MTU_DISCOVERY,
+ g_param_spec_boolean (NM_DEVICE_IP_TUNNEL_PATH_MTU_DISCOVERY, "", "",
+ FALSE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property
+ (object_class, PROP_INPUT_KEY,
+ g_param_spec_string (NM_DEVICE_IP_TUNNEL_INPUT_KEY, "", "",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property
+ (object_class, PROP_OUTPUT_KEY,
+ g_param_spec_string (NM_DEVICE_IP_TUNNEL_OUTPUT_KEY, "", "",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property
+ (object_class, PROP_ENCAPSULATION_LIMIT,
+ g_param_spec_uchar (NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT, "", "",
+ 0, 255, 0,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property
+ (object_class, PROP_FLOW_LABEL,
+ g_param_spec_uint (NM_DEVICE_IP_TUNNEL_FLOW_LABEL, "", "",
+ 0, (1 << 20) - 1, 0,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass),
+ NMDBUS_TYPE_DEVICE_IPTUNNEL_SKELETON,
+ NULL);
+}
+/*************************************************************/
+
+#define NM_TYPE_IP_TUNNEL_FACTORY (nm_ip_tunnel_factory_get_type ())
+#define NM_IP_TUNNEL_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_IP_TUNNEL_FACTORY, NMIPTunnelFactory))
+
+static NMDevice *
+create_device (NMDeviceFactory *factory,
+ const char *iface,
+ NMPlatformLink *plink,
+ NMConnection *connection,
+ gboolean *out_ignore)
+{
+ NMSettingIPTunnel *s_ip_tunnel;
+ NMIPTunnelMode mode;
+
+ if (connection) {
+ s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection);
+ mode = nm_setting_ip_tunnel_get_mode (s_ip_tunnel);
+ } else
+ mode = platform_link_to_tunnel_mode (plink);
+
+ if (mode == NM_IP_TUNNEL_MODE_UKNOWN)
+ return NULL;
+
+ return (NMDevice *) g_object_new (NM_TYPE_DEVICE_IP_TUNNEL,
+ NM_DEVICE_IFACE, iface,
+ NM_DEVICE_TYPE_DESC, "IPTunnel",
+ NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_IP_TUNNEL,
+ NM_DEVICE_IP_TUNNEL_MODE, mode,
+ NULL);
+}
+
+static const char *
+get_connection_parent (NMDeviceFactory *factory, NMConnection *connection)
+{
+ NMSettingIPTunnel *s_ip_tunnel;
+
+ g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_IP_TUNNEL_SETTING_NAME), NULL);
+
+ s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection);
+ g_assert (s_ip_tunnel);
+
+ return nm_setting_ip_tunnel_get_parent (s_ip_tunnel);
+}
+
+static char *
+get_virtual_iface_name (NMDeviceFactory *factory,
+ NMConnection *connection,
+ const char *parent_iface)
+{
+ const char *ifname;
+ NMSettingIPTunnel *s_ip_tunnel;
+
+ g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_IP_TUNNEL_SETTING_NAME), NULL);
+
+ s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection);
+ g_assert (s_ip_tunnel);
+
+ if (nm_setting_ip_tunnel_get_parent (s_ip_tunnel) && !parent_iface)
+ return NULL;
+
+ ifname = nm_connection_get_interface_name (connection);
+
+ return g_strdup (ifname);
+}
+
+NM_DEVICE_FACTORY_DEFINE_INTERNAL (IP_TUNNEL, IPTunnel, ip_tunnel,
+ NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_GRE, NM_LINK_TYPE_SIT, NM_LINK_TYPE_IPIP)
+ NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_IP_TUNNEL_SETTING_NAME),
+ factory_iface->create_device = create_device;
+ factory_iface->get_connection_parent = get_connection_parent;
+ factory_iface->get_virtual_iface_name = get_virtual_iface_name;
+)
diff --git a/src/devices/nm-device-ip-tunnel.h b/src/devices/nm-device-ip-tunnel.h
new file mode 100644
index 0000000000..11cb5bce3b
--- /dev/null
+++ b/src/devices/nm-device-ip-tunnel.h
@@ -0,0 +1,60 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2015 Red Hat, Inc.
+ */
+
+#ifndef __NETWORKMANAGER_DEVICE_IP_TUNNEL_H__
+#define __NETWORKMANAGER_DEVICE_IP_TUNNEL_H__
+
+#include "nm-core-types.h"
+#include "nm-device.h"
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_DEVICE_IP_TUNNEL (nm_device_ip_tunnel_get_type ())
+#define NM_DEVICE_IP_TUNNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_IP_TUNNEL, NMDeviceIPTunnel))
+#define NM_DEVICE_IP_TUNNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_IP_TUNNEL, NMDeviceIPTunnelClass))
+#define NM_IS_DEVICE_IP_TUNNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_IP_TUNNEL))
+#define NM_IS_DEVICE_IP_TUNNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_IP_TUNNEL))
+#define NM_DEVICE_IP_TUNNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_IP_TUNNEL, NMDeviceIPTunnelClass))
+
+#define NM_DEVICE_IP_TUNNEL_MODE "mode"
+#define NM_DEVICE_IP_TUNNEL_PARENT "parent"
+#define NM_DEVICE_IP_TUNNEL_LOCAL "local"
+#define NM_DEVICE_IP_TUNNEL_REMOTE "remote"
+#define NM_DEVICE_IP_TUNNEL_TTL "ttl"
+#define NM_DEVICE_IP_TUNNEL_TOS "tos"
+#define NM_DEVICE_IP_TUNNEL_PATH_MTU_DISCOVERY "path-mtu-discovery"
+#define NM_DEVICE_IP_TUNNEL_INPUT_KEY "input-key"
+#define NM_DEVICE_IP_TUNNEL_OUTPUT_KEY "output-key"
+#define NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT "encapsulation-limit"
+#define NM_DEVICE_IP_TUNNEL_FLOW_LABEL "flow-label"
+
+typedef struct {
+ NMDevice parent;
+} NMDeviceIPTunnel;
+
+typedef struct {
+ NMDeviceClass parent;
+} NMDeviceIPTunnelClass;
+
+GType nm_device_ip_tunnel_get_type (void);
+
+G_END_DECLS
+
+#endif /* NM_DEVICE_IP_TUNNEL_H */
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 6a78ed4b1a..459d4ac664 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -760,6 +760,8 @@ nm_device_get_priority (NMDevice *self)
return 600;
case NM_DEVICE_TYPE_OLPC_MESH:
return 650;
+ case NM_DEVICE_TYPE_IP_TUNNEL:
+ return 675;
case NM_DEVICE_TYPE_MODEM:
return 700;
case NM_DEVICE_TYPE_BT:
diff --git a/src/nm-types.h b/src/nm-types.h
index 6dbd3b3b45..16ae6fa7b4 100644
--- a/src/nm-types.h
+++ b/src/nm-types.h
@@ -108,10 +108,13 @@ typedef enum {
NM_LINK_TYPE_GRE,
NM_LINK_TYPE_GRETAP,
NM_LINK_TYPE_IFB,
+ NM_LINK_TYPE_IP6TNL,
+ NM_LINK_TYPE_IPIP,
NM_LINK_TYPE_LOOPBACK,
NM_LINK_TYPE_MACVLAN,
NM_LINK_TYPE_MACVTAP,
NM_LINK_TYPE_OPENVSWITCH,
+ NM_LINK_TYPE_SIT,
NM_LINK_TYPE_TAP,
NM_LINK_TYPE_TUN,
NM_LINK_TYPE_VETH,
@@ -135,7 +138,10 @@ typedef enum {
NMP_OBJECT_TYPE_LNK_GRE,
NMP_OBJECT_TYPE_LNK_INFINIBAND,
+ NMP_OBJECT_TYPE_LNK_IP6TNL,
+ NMP_OBJECT_TYPE_LNK_IPIP,
NMP_OBJECT_TYPE_LNK_MACVLAN,
+ NMP_OBJECT_TYPE_LNK_SIT,
NMP_OBJECT_TYPE_LNK_VLAN,
NMP_OBJECT_TYPE_LNK_VXLAN,
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index b79aa76767..354641fee8 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -86,10 +86,29 @@
#define IFLA_MACVLAN_FLAGS 2
#define __IFLA_MACVLAN_MAX 3
+#define IFLA_IPTUN_LINK 1
+#define IFLA_IPTUN_LOCAL 2
+#define IFLA_IPTUN_REMOTE 3
+#define IFLA_IPTUN_TTL 4
+#define IFLA_IPTUN_TOS 5
+#define IFLA_IPTUN_ENCAP_LIMIT 6
+#define IFLA_IPTUN_FLOWINFO 7
+#define IFLA_IPTUN_FLAGS 8
+#define IFLA_IPTUN_PROTO 9
+#define IFLA_IPTUN_PMTUDISC 10
+#define __IFLA_IPTUN_MAX 19
+#ifndef IFLA_IPTUN_MAX
+#define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1)
+#endif
+
#ifndef MACVLAN_FLAG_NOPROMISC
#define MACVLAN_FLAG_NOPROMISC 1
#endif
+#define IP6_FLOWINFO_TCLASS_MASK 0x0FF00000
+#define IP6_FLOWINFO_TCLASS_SHIFT 20
+#define IP6_FLOWINFO_FLOWLABEL_MASK 0x000FFFFF
+
/*********************************************************************************************/
#define _NMLOG_PREFIX_NAME "platform-linux"
@@ -118,6 +137,8 @@
} \
} G_STMT_END
+#define LOG_FMT_IP_TUNNEL "adding %s '%s' parent %u local %s remote %s"
+
/******************************************************************
* Forward declarations and enums
******************************************************************/
@@ -314,10 +335,13 @@ static const LinkDesc linktypes[] = {
{ NM_LINK_TYPE_GRE, "gre", "gre", NULL },
{ NM_LINK_TYPE_GRETAP, "gretap", "gretap", NULL },
{ NM_LINK_TYPE_IFB, "ifb", "ifb", NULL },
+ { NM_LINK_TYPE_IP6TNL, "ip6tnl", "ip6tnl", NULL },
+ { NM_LINK_TYPE_IPIP, "ipip", "ipip", NULL },
{ NM_LINK_TYPE_LOOPBACK, "loopback", NULL, NULL },
{ NM_LINK_TYPE_MACVLAN, "macvlan", "macvlan", NULL },
{ NM_LINK_TYPE_MACVTAP, "macvtap", "macvtap", NULL },
{ NM_LINK_TYPE_OPENVSWITCH, "openvswitch", "openvswitch", NULL },
+ { NM_LINK_TYPE_SIT, "sit", "sit", NULL },
{ NM_LINK_TYPE_TAP, "tap", NULL, NULL },
{ NM_LINK_TYPE_TUN, "tun", NULL, NULL },
{ NM_LINK_TYPE_VETH, "veth", "veth", NULL },
@@ -611,6 +635,10 @@ _linktype_get_type (NMPlatform *platform,
return NM_LINK_TYPE_LOOPBACK;
else if (arptype == ARPHRD_INFINIBAND)
return NM_LINK_TYPE_INFINIBAND;
+ else if (arptype == ARPHRD_SIT)
+ return NM_LINK_TYPE_SIT;
+ else if (arptype == ARPHRD_TUNNEL6)
+ return NM_LINK_TYPE_IP6TNL;
if (ifname) {
gs_free char *driver = NULL;
@@ -821,10 +849,10 @@ _parse_lnk_gre (const char *kind, struct nlattr *info_data)
props = &obj->lnk_gre;
props->parent_ifindex = tb[IFLA_GRE_LINK] ? nla_get_u32 (tb[IFLA_GRE_LINK]) : 0;
- props->input_flags = tb[IFLA_GRE_IFLAGS] ? nla_get_u16 (tb[IFLA_GRE_IFLAGS]) : 0;
- props->output_flags = tb[IFLA_GRE_OFLAGS] ? nla_get_u16 (tb[IFLA_GRE_OFLAGS]) : 0;
- props->input_key = (props->input_flags & GRE_KEY) && tb[IFLA_GRE_IKEY] ? nla_get_u32 (tb[IFLA_GRE_IKEY]) : 0;
- props->output_key = (props->output_flags & GRE_KEY) && tb[IFLA_GRE_OKEY] ? nla_get_u32 (tb[IFLA_GRE_OKEY]) : 0;
+ props->input_flags = tb[IFLA_GRE_IFLAGS] ? ntohs (nla_get_u16 (tb[IFLA_GRE_IFLAGS])) : 0;
+ props->output_flags = tb[IFLA_GRE_OFLAGS] ? ntohs (nla_get_u16 (tb[IFLA_GRE_OFLAGS])) : 0;
+ props->input_key = tb[IFLA_GRE_IKEY] ? ntohl (nla_get_u32 (tb[IFLA_GRE_IKEY])) : 0;
+ props->output_key = tb[IFLA_GRE_OKEY] ? ntohl (nla_get_u32 (tb[IFLA_GRE_OKEY])) : 0;
props->local = tb[IFLA_GRE_LOCAL] ? nla_get_u32 (tb[IFLA_GRE_LOCAL]) : 0;
props->remote = tb[IFLA_GRE_REMOTE] ? nla_get_u32 (tb[IFLA_GRE_REMOTE]) : 0;
props->tos = tb[IFLA_GRE_TOS] ? nla_get_u8 (tb[IFLA_GRE_TOS]) : 0;
@@ -897,6 +925,97 @@ _parse_lnk_infiniband (const char *kind, struct nlattr *info_data)
/*****************************************************************************/
static NMPObject *
+_parse_lnk_ip6tnl (const char *kind, struct nlattr *info_data)
+{
+ static struct nla_policy policy[IFLA_IPTUN_MAX + 1] = {
+ [IFLA_IPTUN_LINK] = { .type = NLA_U32 },
+ [IFLA_IPTUN_LOCAL] = { .type = NLA_UNSPEC,
+ .minlen = sizeof (struct in6_addr)},
+ [IFLA_IPTUN_REMOTE] = { .type = NLA_UNSPEC,
+ .minlen = sizeof (struct in6_addr)},
+ [IFLA_IPTUN_TTL] = { .type = NLA_U8 },
+ [IFLA_IPTUN_ENCAP_LIMIT] = { .type = NLA_U8 },
+ [IFLA_IPTUN_FLOWINFO] = { .type = NLA_U32 },
+ [IFLA_IPTUN_PROTO] = { .type = NLA_U8 },
+ };
+ struct nlattr *tb[IFLA_IPTUN_MAX + 1];
+ int err;
+ NMPObject *obj;
+ NMPlatformLnkIp6Tnl *props;
+ guint32 flowinfo;
+
+ if (!info_data || g_strcmp0 (kind, "ip6tnl"))
+ return NULL;
+
+ err = nla_parse_nested (tb, IFLA_IPTUN_MAX, info_data, policy);
+ if (err < 0)
+ return NULL;
+
+ obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_IP6TNL, NULL);
+ props = &obj->lnk_ip6tnl;
+
+ if (tb[IFLA_IPTUN_LINK])
+ props->parent_ifindex = nla_get_u32 (tb[IFLA_IPTUN_LINK]);
+ if (tb[IFLA_IPTUN_LOCAL])
+ memcpy (&props->local, nla_data (tb[IFLA_IPTUN_LOCAL]), sizeof (props->local));
+ if (tb[IFLA_IPTUN_REMOTE])
+ memcpy (&props->remote, nla_data (tb[IFLA_IPTUN_REMOTE]), sizeof (props->remote));
+ if (tb[IFLA_IPTUN_TTL])
+ props->ttl = nla_get_u8 (tb[IFLA_IPTUN_TTL]);
+ if (tb[IFLA_IPTUN_ENCAP_LIMIT])
+ props->encap_limit = nla_get_u8 (tb[IFLA_IPTUN_ENCAP_LIMIT]);
+ if (tb[IFLA_IPTUN_FLOWINFO]) {
+ flowinfo = ntohl (nla_get_u32 (tb[IFLA_IPTUN_FLOWINFO]));
+ props->flow_label = flowinfo & IP6_FLOWINFO_FLOWLABEL_MASK;
+ props->tclass = (flowinfo & IP6_FLOWINFO_TCLASS_MASK) >> IP6_FLOWINFO_TCLASS_SHIFT;
+ }
+ if (tb[IFLA_IPTUN_PROTO])
+ props->proto = nla_get_u8 (tb[IFLA_IPTUN_PROTO]);
+
+ return obj;
+}
+
+/*****************************************************************************/
+
+static NMPObject *
+_parse_lnk_ipip (const char *kind, struct nlattr *info_data)
+{
+ static struct nla_policy policy[IFLA_IPTUN_MAX + 1] = {
+ [IFLA_IPTUN_LINK] = { .type = NLA_U32 },
+ [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 },
+ [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 },
+ [IFLA_IPTUN_TTL] = { .type = NLA_U8 },
+ [IFLA_IPTUN_TOS] = { .type = NLA_U8 },
+ [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 },
+ };
+ struct nlattr *tb[IFLA_IPTUN_MAX + 1];
+ int err;
+ NMPObject *obj;
+ NMPlatformLnkIpIp *props;
+
+ if (!info_data || g_strcmp0 (kind, "ipip"))
+ return NULL;
+
+ err = nla_parse_nested (tb, IFLA_IPTUN_MAX, info_data, policy);
+ if (err < 0)
+ return NULL;
+
+ obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_IPIP, NULL);
+ props = &obj->lnk_ipip;
+
+ props->parent_ifindex = tb[IFLA_IPTUN_LINK] ? nla_get_u32 (tb[IFLA_IPTUN_LINK]) : 0;
+ props->local = tb[IFLA_IPTUN_LOCAL] ? nla_get_u32 (tb[IFLA_IPTUN_LOCAL]) : 0;
+ props->remote = tb[IFLA_IPTUN_REMOTE] ? nla_get_u32 (tb[IFLA_IPTUN_REMOTE]) : 0;
+ props->tos = tb[IFLA_IPTUN_TOS] ? nla_get_u8 (tb[IFLA_IPTUN_TOS]) : 0;
+ props->ttl = tb[IFLA_IPTUN_TTL] ? nla_get_u8 (tb[IFLA_IPTUN_TTL]) : 0;
+ props->path_mtu_discovery = !tb[IFLA_IPTUN_PMTUDISC] || !!nla_get_u8 (tb[IFLA_IPTUN_PMTUDISC]);
+
+ return obj;
+}
+
+/*****************************************************************************/
+
+static NMPObject *
_parse_lnk_macvlan (const char *kind, struct nlattr *info_data)
{
static struct nla_policy policy[IFLA_MACVLAN_MAX + 1] = {
@@ -948,6 +1067,48 @@ _parse_lnk_macvlan (const char *kind, struct nlattr *info_data)
/*****************************************************************************/
+static NMPObject *
+_parse_lnk_sit (const char *kind, struct nlattr *info_data)
+{
+ static struct nla_policy policy[IFLA_IPTUN_MAX + 1] = {
+ [IFLA_IPTUN_LINK] = { .type = NLA_U32 },
+ [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 },
+ [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 },
+ [IFLA_IPTUN_TTL] = { .type = NLA_U8 },
+ [IFLA_IPTUN_TOS] = { .type = NLA_U8 },
+ [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 },
+ [IFLA_IPTUN_FLAGS] = { .type = NLA_U16 },
+ [IFLA_IPTUN_PROTO] = { .type = NLA_U8 },
+ };
+ struct nlattr *tb[IFLA_IPTUN_MAX + 1];
+ int err;
+ NMPObject *obj;
+ NMPlatformLnkSit *props;
+
+ if (!info_data || g_strcmp0 (kind, "sit"))
+ return NULL;
+
+ err = nla_parse_nested (tb, IFLA_IPTUN_MAX, info_data, policy);
+ if (err < 0)
+ return NULL;
+
+ obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_SIT, NULL);
+ props = &obj->lnk_sit;
+
+ props->parent_ifindex = tb[IFLA_IPTUN_LINK] ? nla_get_u32 (tb[IFLA_IPTUN_LINK]) : 0;
+ props->local = tb[IFLA_IPTUN_LOCAL] ? nla_get_u32 (tb[IFLA_IPTUN_LOCAL]) : 0;
+ props->remote = tb[IFLA_IPTUN_REMOTE] ? nla_get_u32 (tb[IFLA_IPTUN_REMOTE]) : 0;
+ props->tos = tb[IFLA_IPTUN_TOS] ? nla_get_u8 (tb[IFLA_IPTUN_TOS]) : 0;
+ props->ttl = tb[IFLA_IPTUN_TTL] ? nla_get_u8 (tb[IFLA_IPTUN_TTL]) : 0;
+ props->path_mtu_discovery = !tb[IFLA_IPTUN_PMTUDISC] || !!nla_get_u8 (tb[IFLA_IPTUN_PMTUDISC]);
+ props->flags = tb[IFLA_IPTUN_FLAGS] ? nla_get_u16 (tb[IFLA_IPTUN_FLAGS]) : 0;
+ props->proto = tb[IFLA_IPTUN_PROTO] ? nla_get_u8 (tb[IFLA_IPTUN_PROTO]) : 0;
+
+ return obj;
+}
+
+/*****************************************************************************/
+
static gboolean
_vlan_qos_mapping_from_nla (struct nlattr *nlattr,
const NMVlanQosMapping **out_map,
@@ -1325,9 +1486,18 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
case NM_LINK_TYPE_INFINIBAND:
lnk_data = _parse_lnk_infiniband (nl_info_kind, nl_info_data);
break;
+ case NM_LINK_TYPE_IP6TNL:
+ lnk_data = _parse_lnk_ip6tnl (nl_info_kind, nl_info_data);
+ break;
+ case NM_LINK_TYPE_IPIP:
+ lnk_data = _parse_lnk_ipip (nl_info_kind, nl_info_data);
+ break;
case NM_LINK_TYPE_MACVLAN:
lnk_data = _parse_lnk_macvlan (nl_info_kind, nl_info_data);
break;
+ case NM_LINK_TYPE_SIT:
+ lnk_data = _parse_lnk_sit (nl_info_kind, nl_info_data);
+ break;
case NM_LINK_TYPE_VLAN:
lnk_data = _parse_lnk_vlan (nl_info_kind, nl_info_data);
break;
@@ -2734,8 +2904,10 @@ cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMP
* For example https://bugzilla.redhat.com/show_bug.cgi?id=1284001 */
switch (new->link.type) {
case NM_LINK_TYPE_GRE:
+ case NM_LINK_TYPE_IP6TNL:
case NM_LINK_TYPE_INFINIBAND:
case NM_LINK_TYPE_MACVLAN:
+ case NM_LINK_TYPE_SIT:
case NM_LINK_TYPE_VLAN:
case NM_LINK_TYPE_VXLAN:
delayed_action_schedule (platform,
@@ -4034,6 +4206,224 @@ nla_put_failure:
g_return_val_if_reached (FALSE);
}
+static int
+link_gre_add (NMPlatform *platform,
+ const char *name,
+ NMPlatformLnkGre *props,
+ NMPlatformLink *out_link)
+{
+ nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
+ struct nlattr *info;
+ struct nlattr *data;
+ char buffer[INET_ADDRSTRLEN];
+
+ _LOGD (LOG_FMT_IP_TUNNEL,
+ "gre",
+ name,
+ props->parent_ifindex,
+ nm_utils_inet4_ntop (props->local, NULL),
+ nm_utils_inet4_ntop (props->remote, buffer));
+
+ nlmsg = _nl_msg_new_link (RTM_NEWLINK,
+ NLM_F_CREATE,
+ 0,
+ name,
+ 0,
+ 0);
+ if (!nlmsg)
+ return FALSE;
+
+ if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO)))
+ goto nla_put_failure;
+
+ NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "gre");
+
+ if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA)))
+ goto nla_put_failure;
+
+ if (props->parent_ifindex)
+ NLA_PUT_U32 (nlmsg, IFLA_GRE_LINK, props->parent_ifindex);
+ NLA_PUT_U32 (nlmsg, IFLA_GRE_LOCAL, props->local);
+ NLA_PUT_U32 (nlmsg, IFLA_GRE_REMOTE, props->remote);
+ NLA_PUT_U8 (nlmsg, IFLA_GRE_TTL, props->ttl);
+ NLA_PUT_U8 (nlmsg, IFLA_GRE_TOS, props->tos);
+ NLA_PUT_U8 (nlmsg, IFLA_GRE_PMTUDISC, !!props->path_mtu_discovery);
+ NLA_PUT_U32 (nlmsg, IFLA_GRE_IKEY, htonl (props->input_key));
+ NLA_PUT_U32 (nlmsg, IFLA_GRE_OKEY, htonl (props->output_key));
+ NLA_PUT_U32 (nlmsg, IFLA_GRE_IFLAGS, htons (props->input_flags));
+ NLA_PUT_U32 (nlmsg, IFLA_GRE_OFLAGS, htons (props->output_flags));
+
+ nla_nest_end (nlmsg, data);
+ nla_nest_end (nlmsg, info);
+
+ return do_add_link_with_lookup (platform, NM_LINK_TYPE_GRE, name, nlmsg, out_link);
+nla_put_failure:
+ g_return_val_if_reached (FALSE);
+}
+
+static int
+link_ip6tnl_add (NMPlatform *platform,
+ const char *name,
+ NMPlatformLnkIp6Tnl *props,
+ NMPlatformLink *out_link)
+{
+ nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
+ struct nlattr *info;
+ struct nlattr *data;
+ char buffer[INET_ADDRSTRLEN];
+ guint32 flowinfo;
+
+ _LOGD (LOG_FMT_IP_TUNNEL,
+ "ip6tnl",
+ name,
+ props->parent_ifindex,
+ nm_utils_inet6_ntop (&props->local, NULL),
+ nm_utils_inet6_ntop (&props->remote, buffer));
+
+ nlmsg = _nl_msg_new_link (RTM_NEWLINK,
+ NLM_F_CREATE,
+ 0,
+ name,
+ 0,
+ 0);
+ if (!nlmsg)
+ return FALSE;
+
+ if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO)))
+ goto nla_put_failure;
+
+ NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "ip6tnl");
+
+ if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA)))
+ goto nla_put_failure;
+
+ if (props->parent_ifindex)
+ NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LINK, props->parent_ifindex);
+
+ if (memcmp (&props->local, &in6addr_any, sizeof (in6addr_any)))
+ NLA_PUT (nlmsg, IFLA_IPTUN_LOCAL, sizeof (props->local), &props->local);
+ if (memcmp (&props->remote, &in6addr_any, sizeof (in6addr_any)))
+ NLA_PUT (nlmsg, IFLA_IPTUN_REMOTE, sizeof (props->remote), &props->remote);
+
+ NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TTL, props->ttl);
+ NLA_PUT_U8 (nlmsg, IFLA_IPTUN_ENCAP_LIMIT, props->encap_limit);
+
+ flowinfo = props->flow_label & IP6_FLOWINFO_FLOWLABEL_MASK;
+ flowinfo |= (props->tclass << IP6_FLOWINFO_TCLASS_SHIFT)
+ & IP6_FLOWINFO_TCLASS_MASK;
+ NLA_PUT_U32 (nlmsg, IFLA_IPTUN_FLOWINFO, htonl (flowinfo));
+ NLA_PUT_U8 (nlmsg, IFLA_IPTUN_PROTO, props->proto);
+
+ nla_nest_end (nlmsg, data);
+ nla_nest_end (nlmsg, info);
+
+ return do_add_link_with_lookup (platform, NM_LINK_TYPE_IP6TNL, name, nlmsg, out_link);
+nla_put_failure:
+ g_return_val_if_reached (FALSE);
+}
+
+static int
+link_ipip_add (NMPlatform *platform,
+ const char *name,
+ NMPlatformLnkIpIp *props,
+ NMPlatformLink *out_link)
+{
+ nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
+ struct nlattr *info;
+ struct nlattr *data;
+ char buffer[INET_ADDRSTRLEN];
+
+ _LOGD (LOG_FMT_IP_TUNNEL,
+ "ipip",
+ name,
+ props->parent_ifindex,
+ nm_utils_inet4_ntop (props->local, NULL),
+ nm_utils_inet4_ntop (props->remote, buffer));
+
+ nlmsg = _nl_msg_new_link (RTM_NEWLINK,
+ NLM_F_CREATE,
+ 0,
+ name,
+ 0,
+ 0);
+ if (!nlmsg)
+ return FALSE;
+
+ if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO)))
+ goto nla_put_failure;
+
+ NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "ipip");
+
+ if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA)))
+ goto nla_put_failure;
+
+ if (props->parent_ifindex)
+ NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LINK, props->parent_ifindex);
+ NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LOCAL, props->local);
+ NLA_PUT_U32 (nlmsg, IFLA_IPTUN_REMOTE, props->remote);
+ NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TTL, props->ttl);
+ NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TOS, props->tos);
+ NLA_PUT_U8 (nlmsg, IFLA_IPTUN_PMTUDISC, !!props->path_mtu_discovery);
+
+ nla_nest_end (nlmsg, data);
+ nla_nest_end (nlmsg, info);
+
+ return do_add_link_with_lookup (platform, NM_LINK_TYPE_IPIP, name, nlmsg, out_link);
+nla_put_failure:
+ g_return_val_if_reached (FALSE);
+}
+
+static int
+link_sit_add (NMPlatform *platform,
+ const char *name,
+ NMPlatformLnkSit *props,
+ NMPlatformLink *out_link)
+{
+ nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
+ struct nlattr *info;
+ struct nlattr *data;
+ char buffer[INET_ADDRSTRLEN];
+
+ _LOGD (LOG_FMT_IP_TUNNEL,
+ "sit",
+ name,
+ props->parent_ifindex,
+ nm_utils_inet4_ntop (props->local, NULL),
+ nm_utils_inet4_ntop (props->remote, buffer));
+
+ nlmsg = _nl_msg_new_link (RTM_NEWLINK,
+ NLM_F_CREATE,
+ 0,
+ name,
+ 0,
+ 0);
+ if (!nlmsg)
+ return FALSE;
+
+ if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO)))
+ goto nla_put_failure;
+
+ NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "sit");
+
+ if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA)))
+ goto nla_put_failure;
+
+ if (props->parent_ifindex)
+ NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LINK, props->parent_ifindex);
+ NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LOCAL, props->local);
+ NLA_PUT_U32 (nlmsg, IFLA_IPTUN_REMOTE, props->remote);
+ NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TTL, props->ttl);
+ NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TOS, props->tos);
+ NLA_PUT_U8 (nlmsg, IFLA_IPTUN_PMTUDISC, !!props->path_mtu_discovery);
+
+ nla_nest_end (nlmsg, data);
+ nla_nest_end (nlmsg, info);
+
+ return do_add_link_with_lookup (platform, NM_LINK_TYPE_SIT, name, nlmsg, out_link);
+nla_put_failure:
+ g_return_val_if_reached (FALSE);
+}
+
static void
_vlan_change_vlan_qos_mapping_create (gboolean is_ingress_map,
gboolean reset_all,
@@ -5487,6 +5877,11 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
platform_class->mesh_set_channel = mesh_set_channel;
platform_class->mesh_set_ssid = mesh_set_ssid;
+ platform_class->link_gre_add = link_gre_add;
+ platform_class->link_ip6tnl_add = link_ip6tnl_add;
+ platform_class->link_ipip_add = link_ipip_add;
+ platform_class->link_sit_add = link_sit_add;
+
platform_class->ip4_address_get = ip4_address_get;
platform_class->ip6_address_get = ip6_address_get;
platform_class->ip4_address_get_all = ip4_address_get_all;
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index bb82ab0959..959f6dfae3 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -71,6 +71,8 @@ G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPRoute, network_ptr) == G_STRUCT_OF
} \
} G_STMT_END
+#define LOG_FMT_IP_TUNNEL "adding %s '%s' parent %u local %s remote %s"
+
/*****************************************************************************/
#define NM_PLATFORM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_PLATFORM, NMPlatformPrivate))
@@ -1427,12 +1429,30 @@ nm_platform_link_get_lnk_infiniband (NMPlatform *self, int ifindex, const NMPlat
return _link_get_lnk (self, ifindex, NM_LINK_TYPE_INFINIBAND, out_link);
}
+const NMPlatformLnkIp6Tnl *
+nm_platform_link_get_lnk_ip6tnl (NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
+{
+ return _link_get_lnk (self, ifindex, NM_LINK_TYPE_IP6TNL, out_link);
+}
+
+const NMPlatformLnkIpIp *
+nm_platform_link_get_lnk_ipip (NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
+{
+ return _link_get_lnk (self, ifindex, NM_LINK_TYPE_IPIP, out_link);
+}
+
const NMPlatformLnkMacvlan *
nm_platform_link_get_lnk_macvlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
{
return _link_get_lnk (self, ifindex, NM_LINK_TYPE_MACVLAN, out_link);
}
+const NMPlatformLnkSit *
+nm_platform_link_get_lnk_sit (NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
+{
+ return _link_get_lnk (self, ifindex, NM_LINK_TYPE_SIT, out_link);
+}
+
const NMPlatformLnkVlan *
nm_platform_link_get_lnk_vlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
{
@@ -1709,6 +1729,45 @@ nm_platform_vlan_set_egress_map (NMPlatform *self, int ifindex, int from, int to
return nm_platform_link_vlan_change (self, ifindex, 0, 0, FALSE, NULL, 0, FALSE, &map, 1);
}
+/**
+ * nm_platform_link_gre_add:
+ * @self: platform instance
+ * @name: name of the new interface
+ * @props: interface properties
+ * @out_link: on success, the link object
+ *
+ * Create a software GRE device.
+ */
+NMPlatformError
+nm_platform_link_gre_add (NMPlatform *self,
+ const char *name,
+ NMPlatformLnkGre *props,
+ NMPlatformLink *out_link)
+{
+ NMPlatformError plerr;
+ char buffer[INET_ADDRSTRLEN];
+
+ _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG);
+
+ g_return_val_if_fail (props, NM_PLATFORM_ERROR_BUG);
+ g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG);
+
+ plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_GRE, out_link);
+ if (plerr != NM_PLATFORM_ERROR_SUCCESS)
+ return plerr;
+
+ _LOGD (LOG_FMT_IP_TUNNEL,
+ "gre",
+ name,
+ props->parent_ifindex,
+ nm_utils_inet4_ntop (props->local, NULL),
+ nm_utils_inet4_ntop (props->remote, buffer));
+
+ if (!klass->link_gre_add (self, name, props, out_link))
+ return NM_PLATFORM_ERROR_UNSPECIFIED;
+ return NM_PLATFORM_ERROR_SUCCESS;
+}
+
NMPlatformError
nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key, NMPlatformLink *out_link)
{
@@ -1806,6 +1865,123 @@ nm_platform_infiniband_get_properties (NMPlatform *self,
return TRUE;
}
+/**
+ * nm_platform_ip6tnl_add:
+ * @self: platform instance
+ * @name: name of the new interface
+ * @props: interface properties
+ * @out_link: on success, the link object
+ *
+ * Create an IPv6 tunnel.
+ */
+NMPlatformError
+nm_platform_link_ip6tnl_add (NMPlatform *self,
+ const char *name,
+ NMPlatformLnkIp6Tnl *props,
+ NMPlatformLink *out_link)
+{
+ NMPlatformError plerr;
+ char buffer[INET6_ADDRSTRLEN];
+
+ _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG);
+
+ g_return_val_if_fail (props, NM_PLATFORM_ERROR_BUG);
+ g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG);
+
+ plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_IP6TNL, out_link);
+ if (plerr != NM_PLATFORM_ERROR_SUCCESS)
+ return plerr;
+
+ _LOGD (LOG_FMT_IP_TUNNEL,
+ "ip6tnl",
+ name,
+ props->parent_ifindex,
+ nm_utils_inet6_ntop (&props->local, NULL),
+ nm_utils_inet6_ntop (&props->remote, buffer));
+
+ if (!klass->link_ip6tnl_add (self, name, props, out_link))
+ return NM_PLATFORM_ERROR_UNSPECIFIED;
+ return NM_PLATFORM_ERROR_SUCCESS;
+}
+
+/**
+ * nm_platform_ipip_add:
+ * @self: platform instance
+ * @name: name of the new interface
+ * @props: interface properties
+ * @out_link: on success, the link object
+ *
+ * Create an IPIP tunnel.
+ */
+NMPlatformError
+nm_platform_link_ipip_add (NMPlatform *self,
+ const char *name,
+ NMPlatformLnkIpIp *props,
+ NMPlatformLink *out_link)
+{
+ NMPlatformError plerr;
+ char buffer[INET_ADDRSTRLEN];
+
+ _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG);
+
+ g_return_val_if_fail (props, NM_PLATFORM_ERROR_BUG);
+ g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG);
+
+ plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_IPIP, out_link);
+ if (plerr != NM_PLATFORM_ERROR_SUCCESS)
+ return plerr;
+
+ _LOGD (LOG_FMT_IP_TUNNEL,
+ "ipip",
+ name,
+ props->parent_ifindex,
+ nm_utils_inet4_ntop (props->local, NULL),
+ nm_utils_inet4_ntop (props->remote, buffer));
+
+ if (!klass->link_ipip_add (self, name, props, out_link))
+ return NM_PLATFORM_ERROR_UNSPECIFIED;
+ return NM_PLATFORM_ERROR_SUCCESS;
+}
+
+/**
+ * nm_platform_sit_add:
+ * @self: platform instance
+ * @name: name of the new interface
+ * @props: interface properties
+ * @out_link: on success, the link object
+ *
+ * Create a software SIT device.
+ */
+NMPlatformError
+nm_platform_link_sit_add (NMPlatform *self,
+ const char *name,
+ NMPlatformLnkSit *props,
+ NMPlatformLink *out_link)
+{
+ NMPlatformError plerr;
+ char buffer[INET_ADDRSTRLEN];
+
+ _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG);
+
+ g_return_val_if_fail (props, NM_PLATFORM_ERROR_BUG);
+ g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG);
+
+ plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_SIT, out_link);
+ if (plerr != NM_PLATFORM_ERROR_SUCCESS)
+ return plerr;
+
+ _LOGD (LOG_FMT_IP_TUNNEL,
+ "sit",
+ name,
+ props->parent_ifindex,
+ nm_utils_inet4_ntop (props->local, NULL),
+ nm_utils_inet4_ntop (props->remote, buffer));
+
+ if (!klass->link_sit_add (self, name, props, out_link))
+ return NM_PLATFORM_ERROR_UNSPECIFIED;
+ return NM_PLATFORM_ERROR_SUCCESS;
+}
+
gboolean
nm_platform_veth_get_properties (NMPlatform *self, int ifindex, int *out_peer_ifindex)
{
@@ -2806,6 +2982,77 @@ nm_platform_lnk_infiniband_to_string (const NMPlatformLnkInfiniband *lnk, char *
}
const char *
+nm_platform_lnk_ip6tnl_to_string (const NMPlatformLnkIp6Tnl *lnk, char *buf, gsize len)
+{
+ char str_local[30];
+ char str_local1[NM_UTILS_INET_ADDRSTRLEN];
+ char str_remote[30];
+ char str_remote1[NM_UTILS_INET_ADDRSTRLEN];
+ char str_ttl[30];
+ char str_tclass[30];
+ char str_flow[30];
+ char str_encap[30];
+ char str_proto[30];
+ char str_parent_ifindex[30];
+
+ if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len))
+ return buf;
+
+ g_snprintf (buf, len,
+ "ip6tnl"
+ "%s" /* remote */
+ "%s" /* local */
+ "%s" /* parent_ifindex */
+ "%s" /* ttl */
+ "%s" /* tclass */
+ "%s" /* encap limit */
+ "%s" /* flow label */
+ "%s" /* proto */
+ "",
+ nm_sprintf_buf (str_remote, " remote %s", nm_utils_inet6_ntop (&lnk->remote, str_remote1)),
+ nm_sprintf_buf (str_local, " local %s", nm_utils_inet6_ntop (&lnk->local, str_local1)),
+ lnk->parent_ifindex ? nm_sprintf_buf (str_parent_ifindex, " dev %d", lnk->parent_ifindex) : "",
+ lnk->ttl ? nm_sprintf_buf (str_ttl, " ttl %u", lnk->ttl) : " ttl inherit",
+ lnk->tclass == 1 ? " tclass inherit" : nm_sprintf_buf (str_tclass, " tclass 0x%x", lnk->tclass),
+ nm_sprintf_buf (str_encap, " encap-limit %u", lnk->encap_limit),
+ nm_sprintf_buf (str_flow, " flow-label 0x05%x", lnk->flow_label),
+ nm_sprintf_buf (str_proto, " proto %u", lnk->proto));
+ return buf;
+}
+
+const char *
+nm_platform_lnk_ipip_to_string (const NMPlatformLnkIpIp *lnk, char *buf, gsize len)
+{
+ char str_local[30];
+ char str_local1[NM_UTILS_INET_ADDRSTRLEN];
+ char str_remote[30];
+ char str_remote1[NM_UTILS_INET_ADDRSTRLEN];
+ char str_ttl[30];
+ char str_tos[30];
+ char str_parent_ifindex[30];
+
+ if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len))
+ return buf;
+
+ g_snprintf (buf, len,
+ "ipip"
+ "%s" /* remote */
+ "%s" /* local */
+ "%s" /* parent_ifindex */
+ "%s" /* ttl */
+ "%s" /* tos */
+ "%s" /* path_mtu_discovery */
+ "",
+ lnk->remote ? nm_sprintf_buf (str_remote, " remote %s", nm_utils_inet4_ntop (lnk->remote, str_remote1)) : "",
+ lnk->local ? nm_sprintf_buf (str_local, " local %s", nm_utils_inet4_ntop (lnk->local, str_local1)) : "",
+ lnk->parent_ifindex ? nm_sprintf_buf (str_parent_ifindex, " dev %d", lnk->parent_ifindex) : "",
+ lnk->ttl ? nm_sprintf_buf (str_ttl, " ttl %u", lnk->ttl) : " ttl inherit",
+ lnk->tos ? (lnk->tos == 1 ? " tos inherit" : nm_sprintf_buf (str_tos, " tos 0x%x", lnk->tos)) : "",
+ lnk->path_mtu_discovery ? "" : " nopmtudisc");
+ return buf;
+}
+
+const char *
nm_platform_lnk_macvlan_to_string (const NMPlatformLnkMacvlan *lnk, char *buf, gsize len)
{
if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len))
@@ -2820,6 +3067,44 @@ nm_platform_lnk_macvlan_to_string (const NMPlatformLnkMacvlan *lnk, char *buf, g
}
const char *
+nm_platform_lnk_sit_to_string (const NMPlatformLnkSit *lnk, char *buf, gsize len)
+{
+ char str_local[30];
+ char str_local1[NM_UTILS_INET_ADDRSTRLEN];
+ char str_remote[30];
+ char str_remote1[NM_UTILS_INET_ADDRSTRLEN];
+ char str_ttl[30];
+ char str_tos[30];
+ char str_flags[30];
+ char str_proto[30];
+ char str_parent_ifindex[30];
+
+ if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len))
+ return buf;
+
+ g_snprintf (buf, len,
+ "sit"
+ "%s" /* remote */
+ "%s" /* local */
+ "%s" /* parent_ifindex */
+ "%s" /* ttl */
+ "%s" /* tos */
+ "%s" /* path_mtu_discovery */
+ "%s" /* flags */
+ "%s" /* proto */
+ "",
+ lnk->remote ? nm_sprintf_buf (str_remote, " remote %s", nm_utils_inet4_ntop (lnk->remote, str_remote1)) : "",
+ lnk->local ? nm_sprintf_buf (str_local, " local %s", nm_utils_inet4_ntop (lnk->local, str_local1)) : "",
+ lnk->parent_ifindex ? nm_sprintf_buf (str_parent_ifindex, " dev %d", lnk->parent_ifindex) : "",
+ lnk->ttl ? nm_sprintf_buf (str_ttl, " ttl %u", lnk->ttl) : " ttl inherit",
+ lnk->tos ? (lnk->tos == 1 ? " tos inherit" : nm_sprintf_buf (str_tos, " tos 0x%x", lnk->tos)) : "",
+ lnk->path_mtu_discovery ? "" : " nopmtudisc",
+ lnk->flags ? nm_sprintf_buf (str_flags, " flags 0x%x", lnk->flags) : "",
+ lnk->proto ? nm_sprintf_buf (str_proto, " proto 0x%x", lnk->proto) : "");
+ return buf;
+}
+
+const char *
nm_platform_lnk_vlan_to_string (const NMPlatformLnkVlan *lnk, char *buf, gsize len)
{
char *b;
@@ -3361,6 +3646,34 @@ nm_platform_lnk_infiniband_cmp (const NMPlatformLnkInfiniband *a, const NMPlatfo
}
int
+nm_platform_lnk_ip6tnl_cmp (const NMPlatformLnkIp6Tnl *a, const NMPlatformLnkIp6Tnl *b)
+{
+ _CMP_SELF (a, b);
+ _CMP_FIELD (a, b, parent_ifindex);
+ _CMP_FIELD_MEMCMP (a, b, local);
+ _CMP_FIELD_MEMCMP (a, b, remote);
+ _CMP_FIELD (a, b, ttl);
+ _CMP_FIELD (a, b, tclass);
+ _CMP_FIELD (a, b, encap_limit);
+ _CMP_FIELD (a, b, flow_label);
+ _CMP_FIELD (a, b, proto);
+ return 0;
+}
+
+int
+nm_platform_lnk_ipip_cmp (const NMPlatformLnkIpIp *a, const NMPlatformLnkIpIp *b)
+{
+ _CMP_SELF (a, b);
+ _CMP_FIELD (a, b, parent_ifindex);
+ _CMP_FIELD (a, b, local);
+ _CMP_FIELD (a, b, remote);
+ _CMP_FIELD (a, b, ttl);
+ _CMP_FIELD (a, b, tos);
+ _CMP_FIELD_BOOL (a, b, path_mtu_discovery);
+ return 0;
+}
+
+int
nm_platform_lnk_macvlan_cmp (const NMPlatformLnkMacvlan *a, const NMPlatformLnkMacvlan *b)
{
_CMP_SELF (a, b);
@@ -3370,6 +3683,21 @@ nm_platform_lnk_macvlan_cmp (const NMPlatformLnkMacvlan *a, const NMPlatformLnkM
}
int
+nm_platform_lnk_sit_cmp (const NMPlatformLnkSit *a, const NMPlatformLnkSit *b)
+{
+ _CMP_SELF (a, b);
+ _CMP_FIELD (a, b, parent_ifindex);
+ _CMP_FIELD (a, b, local);
+ _CMP_FIELD (a, b, remote);
+ _CMP_FIELD (a, b, ttl);
+ _CMP_FIELD (a, b, tos);
+ _CMP_FIELD_BOOL (a, b, path_mtu_discovery);
+ _CMP_FIELD (a, b, flags);
+ _CMP_FIELD (a, b, proto);
+ return 0;
+}
+
+int
nm_platform_lnk_vlan_cmp (const NMPlatformLnkVlan *a, const NMPlatformLnkVlan *b)
{
_CMP_SELF (a, b);
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index 00029b3aeb..5eb042cf78 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -63,6 +63,9 @@ typedef struct _NMPlatform NMPlatform;
#define NM_IFF_MULTI_QUEUE 0x0100 /* IFF_MULTI_QUEUE */
+/* Redefine this in host's endianness */
+#define NM_GRE_KEY 0x2000
+
typedef enum { /*< skip >*/
/* dummy value, to enforce that the enum type is signed and has a size
@@ -376,11 +379,42 @@ typedef struct {
} NMPlatformLnkInfiniband;
typedef struct {
+ int parent_ifindex;
+ struct in6_addr local;
+ struct in6_addr remote;
+ guint8 ttl;
+ guint8 tclass;
+ guint8 encap_limit;
+ guint flow_label;
+ guint8 proto;
+} NMPlatformLnkIp6Tnl;
+
+typedef struct {
+ int parent_ifindex;
+ in_addr_t local;
+ in_addr_t remote;
+ guint8 ttl;
+ guint8 tos;
+ gboolean path_mtu_discovery;
+} NMPlatformLnkIpIp;
+
+typedef struct {
const char *mode;
gboolean no_promisc;
} NMPlatformLnkMacvlan;
typedef struct {
+ int parent_ifindex;
+ in_addr_t local;
+ in_addr_t remote;
+ guint8 ttl;
+ guint8 tos;
+ gboolean path_mtu_discovery;
+ guint16 flags;
+ guint8 proto;
+} NMPlatformLnkSit;
+
+typedef struct {
/* rtnl_link_vlan_get_id(), IFLA_VLAN_ID */
guint16 id;
NMVlanFlags flags;
@@ -524,6 +558,15 @@ typedef struct {
const NMVlanQosMapping *egress_map,
gsize n_egress_map);
+ gboolean (*link_gre_add) (NMPlatform *, const char *name, NMPlatformLnkGre *props,
+ NMPlatformLink *out_link);
+ gboolean (*link_ip6tnl_add) (NMPlatform *, const char *name, NMPlatformLnkIp6Tnl *props,
+ NMPlatformLink *out_link);
+ gboolean (*link_ipip_add) (NMPlatform *, const char *name, NMPlatformLnkIpIp *props,
+ NMPlatformLink *out_link);
+ gboolean (*link_sit_add) (NMPlatform *, const char *name, NMPlatformLnkSit *props,
+ NMPlatformLink *out_link);
+
gboolean (*infiniband_partition_add) (NMPlatform *, int parent, int p_key, NMPlatformLink *out_link);
gboolean (*tun_add) (NMPlatform *platform, const char *name, gboolean tap, gint64 owner, gint64 group, gboolean pi,
@@ -712,8 +755,12 @@ char *nm_platform_slave_get_option (NMPlatform *self, int ifindex, const char *o
const NMPObject *nm_platform_link_get_lnk (NMPlatform *self, int ifindex, NMLinkType link_type, const NMPlatformLink **out_link);
const NMPlatformLnkGre *nm_platform_link_get_lnk_gre (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
+const NMPlatformLnkIp6Tnl *nm_platform_link_get_lnk_ip6tnl (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
+const NMPlatformLnkIpIp *nm_platform_link_get_lnk_ipip (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
const NMPlatformLnkInfiniband *nm_platform_link_get_lnk_infiniband (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
+const NMPlatformLnkIpIp *nm_platform_link_get_lnk_ipip (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
const NMPlatformLnkMacvlan *nm_platform_link_get_lnk_macvlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
+const NMPlatformLnkSit *nm_platform_link_get_lnk_sit (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
const NMPlatformLnkVlan *nm_platform_link_get_lnk_vlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
const NMPlatformLnkVxlan *nm_platform_link_get_lnk_vxlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
@@ -762,6 +809,16 @@ void nm_platform_ip4_address_set_addr (NMPlatformIP4Address *a
const struct in6_addr *nm_platform_ip6_address_get_peer (const NMPlatformIP6Address *addr);
const NMPlatformIP4Address *nm_platform_ip4_address_get (NMPlatform *self, int ifindex, in_addr_t address, int plen, in_addr_t peer_address);
+
+NMPlatformError nm_platform_link_gre_add (NMPlatform *self, const char *name, NMPlatformLnkGre *props,
+ NMPlatformLink *out_link);
+NMPlatformError nm_platform_link_ip6tnl_add (NMPlatform *self, const char *name, NMPlatformLnkIp6Tnl *props,
+ NMPlatformLink *out_link);
+NMPlatformError nm_platform_link_ipip_add (NMPlatform *self, const char *name, NMPlatformLnkIpIp *props,
+ NMPlatformLink *out_link);
+NMPlatformError nm_platform_link_sit_add (NMPlatform *self, const char *name, NMPlatformLnkSit *props,
+ NMPlatformLink *out_link);
+
const NMPlatformIP6Address *nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr address, int plen);
GArray *nm_platform_ip4_address_get_all (NMPlatform *self, int ifindex);
GArray *nm_platform_ip6_address_get_all (NMPlatform *self, int ifindex);
@@ -803,7 +860,10 @@ gboolean nm_platform_ip6_route_delete (NMPlatform *self, int ifindex, struct in6
const char *nm_platform_link_to_string (const NMPlatformLink *link, char *buf, gsize len);
const char *nm_platform_lnk_gre_to_string (const NMPlatformLnkGre *lnk, char *buf, gsize len);
const char *nm_platform_lnk_infiniband_to_string (const NMPlatformLnkInfiniband *lnk, char *buf, gsize len);
+const char *nm_platform_lnk_ip6tnl_to_string (const NMPlatformLnkIp6Tnl *lnk, char *buf, gsize len);
+const char *nm_platform_lnk_ipip_to_string (const NMPlatformLnkIpIp *lnk, char *buf, gsize len);
const char *nm_platform_lnk_macvlan_to_string (const NMPlatformLnkMacvlan *lnk, char *buf, gsize len);
+const char *nm_platform_lnk_sit_to_string (const NMPlatformLnkSit *lnk, char *buf, gsize len);
const char *nm_platform_lnk_vlan_to_string (const NMPlatformLnkVlan *lnk, char *buf, gsize len);
const char *nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize len);
const char *nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address, char *buf, gsize len);
@@ -820,7 +880,10 @@ const char *nm_platform_vlan_qos_mapping_to_string (const char *name,
int nm_platform_link_cmp (const NMPlatformLink *a, const NMPlatformLink *b);
int nm_platform_lnk_gre_cmp (const NMPlatformLnkGre *a, const NMPlatformLnkGre *b);
int nm_platform_lnk_infiniband_cmp (const NMPlatformLnkInfiniband *a, const NMPlatformLnkInfiniband *b);
+int nm_platform_lnk_ip6tnl_cmp (const NMPlatformLnkIp6Tnl *a, const NMPlatformLnkIp6Tnl *b);
+int nm_platform_lnk_ipip_cmp (const NMPlatformLnkIpIp *a, const NMPlatformLnkIpIp *b);
int nm_platform_lnk_macvlan_cmp (const NMPlatformLnkMacvlan *a, const NMPlatformLnkMacvlan *b);
+int nm_platform_lnk_sit_cmp (const NMPlatformLnkSit *a, const NMPlatformLnkSit *b);
int nm_platform_lnk_vlan_cmp (const NMPlatformLnkVlan *a, const NMPlatformLnkVlan *b);
int nm_platform_lnk_vxlan_cmp (const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan *b);
int nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b);
diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c
index ef467f4241..cb605c28f4 100644
--- a/src/platform/nmp-object.c
+++ b/src/platform/nmp-object.c
@@ -2045,6 +2045,24 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_infiniband_to_string,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_infiniband_cmp,
},
+ [NMP_OBJECT_TYPE_LNK_IP6TNL - 1] = {
+ .obj_type = NMP_OBJECT_TYPE_LNK_IP6TNL,
+ .sizeof_data = sizeof (NMPObjectLnkIp6Tnl),
+ .sizeof_public = sizeof (NMPlatformLnkIp6Tnl),
+ .obj_type_name = "ip6tnl",
+ .lnk_link_type = NM_LINK_TYPE_IP6TNL,
+ .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_ip6tnl_to_string,
+ .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_ip6tnl_cmp,
+ },
+ [NMP_OBJECT_TYPE_LNK_IPIP - 1] = {
+ .obj_type = NMP_OBJECT_TYPE_LNK_IPIP,
+ .sizeof_data = sizeof (NMPObjectLnkIpIp),
+ .sizeof_public = sizeof (NMPlatformLnkIpIp),
+ .obj_type_name = "ipip",
+ .lnk_link_type = NM_LINK_TYPE_IPIP,
+ .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_ipip_to_string,
+ .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_ipip_cmp,
+ },
[NMP_OBJECT_TYPE_LNK_MACVLAN - 1] = {
.obj_type = NMP_OBJECT_TYPE_LNK_MACVLAN,
.sizeof_data = sizeof (NMPObjectLnkMacvlan),
@@ -2054,6 +2072,15 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_macvlan_to_string,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_macvlan_cmp,
},
+ [NMP_OBJECT_TYPE_LNK_SIT - 1] = {
+ .obj_type = NMP_OBJECT_TYPE_LNK_SIT,
+ .sizeof_data = sizeof (NMPObjectLnkSit),
+ .sizeof_public = sizeof (NMPlatformLnkSit),
+ .obj_type_name = "sit",
+ .lnk_link_type = NM_LINK_TYPE_SIT,
+ .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_sit_to_string,
+ .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_sit_cmp,
+ },
[NMP_OBJECT_TYPE_LNK_VLAN - 1] = {
.obj_type = NMP_OBJECT_TYPE_LNK_VLAN,
.sizeof_data = sizeof (NMPObjectLnkVlan),
diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h
index 971bd37eca..38224acd30 100644
--- a/src/platform/nmp-object.h
+++ b/src/platform/nmp-object.h
@@ -170,10 +170,22 @@ typedef struct {
} NMPObjectLnkInfiniband;
typedef struct {
+ NMPlatformLnkIp6Tnl _public;
+} NMPObjectLnkIp6Tnl;
+
+typedef struct {
+ NMPlatformLnkIpIp _public;
+} NMPObjectLnkIpIp;
+
+typedef struct {
NMPlatformLnkMacvlan _public;
} NMPObjectLnkMacvlan;
typedef struct {
+ NMPlatformLnkSit _public;
+} NMPObjectLnkSit;
+
+typedef struct {
NMPlatformLnkVlan _public;
guint n_ingress_qos_map;
@@ -218,9 +230,18 @@ struct _NMPObject {
NMPlatformLnkInfiniband lnk_infiniband;
NMPObjectLnkInfiniband _lnk_infiniband;
+ NMPlatformLnkIpIp lnk_ipip;
+ NMPObjectLnkIpIp _lnk_ipip;
+
+ NMPlatformLnkIp6Tnl lnk_ip6tnl;
+ NMPObjectLnkIp6Tnl _lnk_ip6tnl;
+
NMPlatformLnkMacvlan lnk_macvlan;
NMPObjectLnkMacvlan _lnk_macvlan;
+ NMPlatformLnkSit lnk_sit;
+ NMPObjectLnkSit _lnk_sit;
+
NMPlatformLnkVlan lnk_vlan;
NMPObjectLnkVlan _lnk_vlan;
diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c
index 6f46546c46..595096d2fb 100644
--- a/src/platform/tests/test-common.c
+++ b/src/platform/tests/test-common.c
@@ -670,6 +670,140 @@ _ip_address_add (gboolean external_command,
} while (TRUE);
}
+gboolean
+nmtstp_link_gre_add (gboolean external_command, const char *name, NMPlatformLnkGre *lnk)
+{
+ gboolean success;
+ char buffer[INET_ADDRSTRLEN];
+
+ external_command = nmtstp_run_command_check_external (external_command);
+
+ if (external_command) {
+ gs_free char *dev = NULL;
+
+ if (lnk->parent_ifindex)
+ dev = g_strdup_printf ("dev %s", nm_platform_link_get_name (NM_PLATFORM_GET, lnk->parent_ifindex));
+
+ success = !nmtstp_run_command ("ip tunnel add %s mode gre %s local %s remote %s ttl %u tos %02x %s",
+ name,
+ dev ? dev : "",
+ nm_utils_inet4_ntop (lnk->local, NULL),
+ nm_utils_inet4_ntop (lnk->remote, buffer),
+ lnk->ttl,
+ lnk->tos,
+ lnk->path_mtu_discovery ? "pmtudisc" : "nopmtudisc");
+ if (success)
+ nmtstp_assert_wait_for_link (name, NM_LINK_TYPE_GRE, 100);
+ } else
+ success = nm_platform_link_gre_add (NM_PLATFORM_GET, name, lnk, NULL) == NM_PLATFORM_ERROR_SUCCESS;
+
+ return success;
+}
+
+gboolean
+nmtstp_link_ip6tnl_add (gboolean external_command, const char *name, NMPlatformLnkIp6Tnl *lnk)
+{
+ gboolean success;
+ char buffer[INET6_ADDRSTRLEN];
+
+ external_command = nmtstp_run_command_check_external (external_command);
+
+ if (external_command) {
+ gs_free char *dev = NULL;
+ const char *mode;
+
+ if (lnk->parent_ifindex)
+ dev = g_strdup_printf ("dev %s", nm_platform_link_get_name (NM_PLATFORM_GET, lnk->parent_ifindex));
+
+ switch (lnk->proto) {
+ case IPPROTO_IPIP:
+ mode = "ipip6";
+ break;
+ case IPPROTO_IPV6:
+ mode = "ip6ip6";
+ break;
+ default:
+ g_assert (FALSE);
+ }
+
+ success = !nmtstp_run_command ("ip -6 tunnel add %s mode %s %s local %s remote %s ttl %u tclass %02x encaplimit %u flowlabel %x",
+ name,
+ mode,
+ dev,
+ nm_utils_inet6_ntop (&lnk->local, NULL),
+ nm_utils_inet6_ntop (&lnk->remote, buffer),
+ lnk->ttl,
+ lnk->tclass,
+ lnk->encap_limit,
+ lnk->flow_label);
+ if (success)
+ nmtstp_assert_wait_for_link (name, NM_LINK_TYPE_IP6TNL, 100);
+ } else
+ success = nm_platform_link_ip6tnl_add (NM_PLATFORM_GET, name, lnk, NULL) == NM_PLATFORM_ERROR_SUCCESS;
+
+ return success;
+}
+
+gboolean
+nmtstp_link_ipip_add (gboolean external_command, const char *name, NMPlatformLnkIpIp *lnk)
+{
+ gboolean success;
+ char buffer[INET_ADDRSTRLEN];
+
+ external_command = nmtstp_run_command_check_external (external_command);
+
+ if (external_command) {
+ gs_free char *dev = NULL;
+
+ if (lnk->parent_ifindex)
+ dev = g_strdup_printf ("dev %s", nm_platform_link_get_name (NM_PLATFORM_GET, lnk->parent_ifindex));
+
+ success = !nmtstp_run_command ("ip tunnel add %s mode ipip %s local %s remote %s ttl %u tos %02x %s",
+ name,
+ dev,
+ nm_utils_inet4_ntop (lnk->local, NULL),
+ nm_utils_inet4_ntop (lnk->remote, buffer),
+ lnk->ttl,
+ lnk->tos,
+ lnk->path_mtu_discovery ? "pmtudisc" : "nopmtudisc");
+ if (success)
+ nmtstp_assert_wait_for_link (name, NM_LINK_TYPE_IPIP, 100);
+ } else
+ success = nm_platform_link_ipip_add (NM_PLATFORM_GET, name, lnk, NULL) == NM_PLATFORM_ERROR_SUCCESS;
+
+ return success;
+}
+
+gboolean
+nmtstp_link_sit_add (gboolean external_command, const char *name, NMPlatformLnkSit *lnk)
+{
+ gboolean success;
+ char buffer[INET_ADDRSTRLEN];
+
+ external_command = nmtstp_run_command_check_external (external_command);
+
+ if (external_command) {
+ gs_free char *dev = NULL;
+
+ if (lnk->parent_ifindex)
+ dev = g_strdup_printf ("dev %s", nm_platform_link_get_name (NM_PLATFORM_GET, lnk->parent_ifindex));
+
+ success = !nmtstp_run_command ("ip tunnel add %s mode sit %s local %s remote %s ttl %u tos %02x %s",
+ name,
+ dev,
+ nm_utils_inet4_ntop (lnk->local, NULL),
+ nm_utils_inet4_ntop (lnk->remote, buffer),
+ lnk->ttl,
+ lnk->tos,
+ lnk->path_mtu_discovery ? "pmtudisc" : "nopmtudisc");
+ if (success)
+ nmtstp_assert_wait_for_link (name, NM_LINK_TYPE_SIT, 100);
+ } else
+ success = nm_platform_link_sit_add (NM_PLATFORM_GET, name, lnk, NULL) == NM_PLATFORM_ERROR_SUCCESS;
+
+ return success;
+}
+
void
nmtstp_ip4_address_add (gboolean external_command,
int ifindex,
diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h
index ed7dd67fa1..6140f26406 100644
--- a/src/platform/tests/test-common.h
+++ b/src/platform/tests/test-common.h
@@ -135,6 +135,19 @@ void nmtstp_link_set_updown (gboolean external_command,
int ifindex,
gboolean up);
+gboolean nmtstp_link_gre_add (gboolean external_command,
+ const char *name,
+ NMPlatformLnkGre *lnk);
+gboolean nmtstp_link_ip6tnl_add (gboolean external_command,
+ const char *name,
+ NMPlatformLnkIp6Tnl *lnk);
+gboolean nmtstp_link_ipip_add (gboolean external_command,
+ const char *name,
+ NMPlatformLnkIpIp *lnk);
+gboolean nmtstp_link_sit_add (gboolean external_command,
+ const char *name,
+ NMPlatformLnkSit *lnk);
+
void init_tests (int *argc, char ***argv);
void setup_tests (void);
diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c
index 8a29df2d15..047dfe1cf7 100644
--- a/src/platform/tests/test-link.c
+++ b/src/platform/tests/test-link.c
@@ -659,32 +659,93 @@ test_software_detect (gconstpointer user_data)
const NMPlatformLink *plink;
const NMPObject *lnk;
guint i_step;
- int exit_code;
+ const gint EX = -1;
nmtstp_run_command_check ("ip link add %s type dummy", PARENT_NAME);
ifindex_parent = nmtstp_assert_wait_for_link (PARENT_NAME, NM_LINK_TYPE_DUMMY, 100)->ifindex;
switch (test_data->link_type) {
case NM_LINK_TYPE_GRE: {
+ NMPlatformLnkGre lnk_gre = { };
gboolean gracefully_skip = FALSE;
+ inet_pton (AF_INET, "192.168.233.204", &lnk_gre.local);
+ inet_pton (AF_INET, "172.168.10.25", &lnk_gre.remote);
+ lnk_gre.parent_ifindex = ifindex_parent;
+ lnk_gre.ttl = 174;
+ lnk_gre.tos = 37;
+ lnk_gre.path_mtu_discovery = TRUE;
+
if (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "gre0")) {
/* Seems that the ip_gre module is not loaded... try to load it. */
gracefully_skip = nm_utils_modprobe (NULL, TRUE, "ip_gre", NULL) != 0;
}
- exit_code = nmtstp_run_command ("ip tunnel add %s mode gre remote 172.168.10.25 local 192.168.233.204 ttl 174", DEVICE_NAME);
- if (exit_code != 0) {
+
+ if (!nmtstp_link_gre_add (EX, DEVICE_NAME, &lnk_gre)) {
if (gracefully_skip) {
g_test_skip ("Cannot create gre tunnel because of missing ip_gre module (modprobe ip_gre)");
goto out_delete_parent;
}
- g_error ("Failed adding GRE tunnel: exit code %d", exit_code);
+ g_error ("Failed adding GRE tunnel");
}
break;
}
+ case NM_LINK_TYPE_IPIP: {
+ NMPlatformLnkIpIp lnk_ipip = { };
+
+ inet_pton (AF_INET, "1.2.3.4", &lnk_ipip.local);
+ inet_pton (AF_INET, "5.6.7.8", &lnk_ipip.remote);
+ lnk_ipip.parent_ifindex = ifindex_parent;
+ lnk_ipip.tos = 32;
+ lnk_ipip.path_mtu_discovery = FALSE;
+
+ if (!nmtstp_link_ipip_add (EX, DEVICE_NAME, &lnk_ipip))
+ g_error ("Failed adding IPIP tunnel");
+ break;
+ }
+ case NM_LINK_TYPE_IP6TNL: {
+ NMPlatformLnkIp6Tnl lnk_ip6tnl = { };
+
+ inet_pton (AF_INET6, "fd01::15", &lnk_ip6tnl.local);
+ inet_pton (AF_INET6, "fd01::16", &lnk_ip6tnl.remote);
+ lnk_ip6tnl.parent_ifindex = ifindex_parent;
+ lnk_ip6tnl.tclass = 20;
+ lnk_ip6tnl.encap_limit = 6;
+ lnk_ip6tnl.flow_label = 1337;
+ lnk_ip6tnl.proto = IPPROTO_IPV6;
+
+ if (!nmtstp_link_ip6tnl_add (EX, DEVICE_NAME, &lnk_ip6tnl))
+ g_error ("Failed adding IPv6 tunnel");
+ break;
+ }
case NM_LINK_TYPE_MACVLAN:
nmtstp_run_command_check ("ip link add name %s link %s type macvlan", DEVICE_NAME, PARENT_NAME);
break;
+ case NM_LINK_TYPE_SIT: {
+ NMPlatformLnkSit lnk_sit = { };
+ gboolean gracefully_skip = FALSE;
+
+ inet_pton (AF_INET, "192.168.200.1", &lnk_sit.local);
+ inet_pton (AF_INET, "172.25.100.14", &lnk_sit.remote);
+ lnk_sit.parent_ifindex = ifindex_parent;
+ lnk_sit.ttl = 0;
+ lnk_sit.tos = 31;
+ lnk_sit.path_mtu_discovery = FALSE;
+
+ if (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "sit0")) {
+ /* Seems that the sit module is not loaded... try to load it. */
+ gracefully_skip = nm_utils_modprobe (NULL, TRUE, "sit", NULL) != 0;
+ }
+
+ if (!nmtstp_link_sit_add (EX, DEVICE_NAME, &lnk_sit)) {
+ if (gracefully_skip) {
+ g_test_skip ("Cannot create sit tunnel because of missing sit module (modprobe sit)");
+ goto out_delete_parent;
+ }
+ g_error ("Failed adding SIT tunnel");
+ }
+ break;
+ }
case NM_LINK_TYPE_VLAN:
nmtstp_run_command_check ("ip link add name %s link %s type vlan id 1242", DEVICE_NAME, PARENT_NAME);
break;
@@ -741,7 +802,7 @@ test_software_detect (gconstpointer user_data)
const NMPlatformLnkGre *plnk = &lnk->lnk_gre;
g_assert (plnk == nm_platform_link_get_lnk_gre (NM_PLATFORM_GET, ifindex, NULL));
- g_assert_cmpint (plnk->parent_ifindex, ==, 0);
+ g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent);
g_assert_cmpint (plnk->input_flags, ==, 0);
g_assert_cmpint (plnk->output_flags, ==, 0);
g_assert_cmpint (plnk->input_key, ==, 0);
@@ -749,10 +810,36 @@ test_software_detect (gconstpointer user_data)
nmtst_assert_ip4_address (plnk->local, "192.168.233.204");
nmtst_assert_ip4_address (plnk->remote, "172.168.10.25");
g_assert_cmpint (plnk->ttl, ==, 174);
- g_assert_cmpint (plnk->tos, ==, 0);
+ g_assert_cmpint (plnk->tos, ==, 37);
g_assert_cmpint (plnk->path_mtu_discovery, ==, TRUE);
break;
}
+ case NM_LINK_TYPE_IP6TNL: {
+ const NMPlatformLnkIp6Tnl *plnk = &lnk->lnk_ip6tnl;
+
+ g_assert (plnk == nm_platform_link_get_lnk_ip6tnl (NM_PLATFORM_GET, ifindex, NULL));
+ g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent);
+ nmtst_assert_ip6_address (&plnk->local, "fd01::15");
+ nmtst_assert_ip6_address (&plnk->remote, "fd01::16");
+ g_assert_cmpint (plnk->ttl, ==, 0);
+ g_assert_cmpint (plnk->tclass, ==, 20);
+ g_assert_cmpint (plnk->encap_limit, ==, 6);
+ g_assert_cmpint (plnk->flow_label, ==, 1337);
+ g_assert_cmpint (plnk->proto, ==, IPPROTO_IPV6);
+ break;
+ }
+ case NM_LINK_TYPE_IPIP: {
+ const NMPlatformLnkIpIp *plnk = &lnk->lnk_ipip;
+
+ g_assert (plnk == nm_platform_link_get_lnk_ipip (NM_PLATFORM_GET, ifindex, NULL));
+ g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent);
+ nmtst_assert_ip4_address (plnk->local, "1.2.3.4");
+ nmtst_assert_ip4_address (plnk->remote, "5.6.7.8");
+ g_assert_cmpint (plnk->ttl, ==, 0);
+ g_assert_cmpint (plnk->tos, ==, 32);
+ g_assert_cmpint (plnk->path_mtu_discovery, ==, FALSE);
+ break;
+ }
case NM_LINK_TYPE_MACVLAN: {
const NMPlatformLnkMacvlan *plnk = &lnk->lnk_macvlan;
@@ -761,6 +848,18 @@ test_software_detect (gconstpointer user_data)
g_assert_cmpstr (plnk->mode, ==, "vepa");
break;
}
+ case NM_LINK_TYPE_SIT: {
+ const NMPlatformLnkSit *plnk = &lnk->lnk_sit;
+
+ g_assert (plnk == nm_platform_link_get_lnk_sit (NM_PLATFORM_GET, ifindex, NULL));
+ g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent);
+ nmtst_assert_ip4_address (plnk->local, "192.168.200.1");
+ nmtst_assert_ip4_address (plnk->remote, "172.25.100.14");
+ g_assert_cmpint (plnk->ttl, ==, 0);
+ g_assert_cmpint (plnk->tos, ==, 31);
+ g_assert_cmpint (plnk->path_mtu_discovery, ==, FALSE);
+ break;
+ }
case NM_LINK_TYPE_VLAN: {
const NMPlatformLnkVlan *plnk = &lnk->lnk_vlan;
@@ -1579,7 +1678,10 @@ setup_tests (void)
g_test_add_func ("/link/external", test_external);
test_software_detect_add ("/link/software/detect/gre", NM_LINK_TYPE_GRE, 0);
+ test_software_detect_add ("/link/software/detect/ip6tnl", NM_LINK_TYPE_IP6TNL, 0);
+ test_software_detect_add ("/link/software/detect/ipip", NM_LINK_TYPE_IPIP, 0);
test_software_detect_add ("/link/software/detect/macvlan", NM_LINK_TYPE_MACVLAN, 0);
+ test_software_detect_add ("/link/software/detect/sit", NM_LINK_TYPE_SIT, 0);
test_software_detect_add ("/link/software/detect/vlan", NM_LINK_TYPE_VLAN, 0);
test_software_detect_add ("/link/software/detect/vxlan/0", NM_LINK_TYPE_VXLAN, 0);
test_software_detect_add ("/link/software/detect/vxlan/1", NM_LINK_TYPE_VXLAN, 1);
diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
index 219e0270ba..18fce10088 100644
--- a/src/tests/Makefile.am
+++ b/src/tests/Makefile.am
@@ -150,7 +150,7 @@ TESTS = \
if ENABLE_TESTS
check-local:
- @for t in bond bridge ethernet gre infiniband macvlan tun veth vlan vxlan; do \
+ @for t in bond bridge ethernet infiniband ip_tunnel macvlan tun veth vlan vxlan; do \
# Ensure the device subclass factory registration constructors exist \
# which could inadvertently break if src/Makefile.am gets changed \
if ! LC_ALL=C nm $(top_builddir)/src/NetworkManager | LC_ALL=C grep -q "register_device_factory_internal_$$t" ; then \