merge: branch 'bg/device-creation-ip-tunnel-bgo758047'

Add support for creating IP tunnel interfaces.

https://bugzilla.gnome.org/show_bug.cgi?id=758047
This commit is contained in:
Beniamino Galvani 2015-12-01 17:45:27 +01:00
commit 193bf92918
42 changed files with 4130 additions and 396 deletions

View file

@ -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 ();

View file

@ -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

View file

@ -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 },
};

View file

@ -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 \

View file

@ -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">
<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.)
</tp:docstring>
</property>
<property name="OutputFlags" type="q" 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.)
</tp:docstring>
</property>
<property name="InputKey" type="u" access="read">
<tp:docstring>
Expected input key (if the "Key Present" bit is set in the input flags).
</tp:docstring>
</property>
<property name="OutputKey" type="u" access="read">
<tp:docstring>
Output key (if the "Key Present" bit is set in the output flags).
</tp:docstring>
</property>
<property name="Local" type="s" access="read">
<tp:docstring>
The local end of the tunnel.
The local endpoint of the tunnel.
</tp:docstring>
</property>
<property name="Remote" type="s" access="read">
<tp:docstring>
The remote end of the tunnel.
The remote endpoint of the tunnel.
</tp:docstring>
</property>
<property name="Ttl" type="y" access="read">
<tp:docstring>
The value to use in the IP TTL field for tunnel packets.
The TTL assigned to tunneled packets. 0 is a special value
meaning that packets inherit the TTL value
</tp:docstring>
</property>
<property name="Tos" type="y" access="read">
<tp:docstring>
The value to use in the IP ToS field for tunnel packets.
The type of service (IPv4) or traffic class (IPv6) assigned to
tunneled packets.
</tp:docstring>
</property>
<property name="PathMtuDiscovery" type="b" access="read">
<tp:docstring>
Whether path MTU discovery is performed.
Whether path MTU discovery is enabled on this tunnel.
</tp:docstring>
</property>
<property name="InputKey" type="s" access="read">
<tp:docstring>
The key used for incoming packets.
</tp:docstring>
</property>
<property name="OutputKey" type="s" access="read">
<tp:docstring>
The key used for outgoing packets.
</tp:docstring>
</property>
<property name="EncapsulationLimit" type="y" access="read">
<tp:docstring>
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="FlowLabel" type="u" access="read">
<tp:docstring>
The flow label to assign to tunnel packets. This property
applies only to IPv6 tunnels.
</tp:docstring>
</property>

View file

@ -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 \

View file

@ -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)) {
@ -1865,6 +1866,24 @@ nm_connection_get_setting_ip4_config (NMConnection *connection)
return (NMSettingIPConfig *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
}
/**
* 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

View file

@ -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);

View file

@ -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"

View file

@ -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;

View file

@ -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__ */

View file

@ -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));
}

View file

@ -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__ */

View file

@ -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);
}

View file

@ -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__ */

View file

@ -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");
}
/******************************************************************************/

View file

@ -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);

View file

@ -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;
/**

View file

@ -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 \

View file

@ -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>

View file

@ -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;

544
libnm/nm-device-ip-tunnel.c Normal file
View file

@ -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));
}

View file

@ -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__ */

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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 \

View file

@ -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;
)

View file

@ -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 */

View file

@ -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;
)

View file

@ -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 */

View file

@ -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:

View file

@ -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,

View file

@ -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;
@ -896,6 +924,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)
{
@ -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;

View file

@ -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)
{
@ -2805,6 +2981,77 @@ nm_platform_lnk_infiniband_to_string (const NMPlatformLnkInfiniband *lnk, char *
return buf;
}
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)
{
@ -2819,6 +3066,44 @@ nm_platform_lnk_macvlan_to_string (const NMPlatformLnkMacvlan *lnk, char *buf, g
return buf;
}
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)
{
@ -3360,6 +3645,34 @@ nm_platform_lnk_infiniband_cmp (const NMPlatformLnkInfiniband *a, const NMPlatfo
return 0;
}
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)
{
@ -3369,6 +3682,21 @@ nm_platform_lnk_macvlan_cmp (const NMPlatformLnkMacvlan *a, const NMPlatformLnkM
return 0;
}
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)
{

View file

@ -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
@ -375,11 +378,42 @@ typedef struct {
const char *mode;
} 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;
@ -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);

View file

@ -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),

View file

@ -169,10 +169,22 @@ typedef struct {
NMPlatformLnkInfiniband _public;
} 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;
@ -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;

View file

@ -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,

View file

@ -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);

View file

@ -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);

View file

@ -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 \