summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBeniamino Galvani <bgalvani@redhat.com>2015-11-25 11:53:37 +0100
committerBeniamino Galvani <bgalvani@redhat.com>2015-11-25 11:53:37 +0100
commit123d0ba9b8c92ce00d2a0b2f98c5f329353e70d1 (patch)
tree4fc5e55aaf4f0038fd78cf547f47f7045212733b
parentfa96bade799b274eaa1b94e4dd04bdac26f54136 (diff)
parentc223e811f119d88222482432c0a700fa28630adb (diff)
merge: branch 'bg/create-sw-devices-bgo749369-tun'
Add support for creating TUN/TAP devices. https://bugzilla.gnome.org/show_bug.cgi?id=749369
-rw-r--r--clients/cli/connections.c221
-rw-r--r--clients/cli/nmcli-completion2
-rw-r--r--clients/cli/settings.c147
-rw-r--r--introspection/nm-device-tun.xml6
-rw-r--r--libnm-core/Makefile.libnm-core2
-rw-r--r--libnm-core/nm-connection.c21
-rw-r--r--libnm-core/nm-connection.h1
-rw-r--r--libnm-core/nm-core-internal.h1
-rw-r--r--libnm-core/nm-core-types.h1
-rw-r--r--libnm-core/nm-dbus-interface.h2
-rw-r--r--libnm-core/nm-setting-tun.c409
-rw-r--r--libnm-core/nm-setting-tun.h94
-rw-r--r--libnm-glib/libnm-glib-test.c9
-rw-r--r--libnm-glib/nm-device-generic.c30
-rw-r--r--libnm-glib/nm-device-private.h1
-rw-r--r--libnm-glib/nm-device.c37
-rw-r--r--libnm-util/NetworkManager.h2
-rw-r--r--libnm/Makefile.am2
-rw-r--r--libnm/NetworkManager.h1
-rw-r--r--libnm/libnm.ver17
-rw-r--r--libnm/nm-device-tun.c439
-rw-r--r--libnm/nm-device-tun.h78
-rw-r--r--libnm/nm-device.c3
-rw-r--r--libnm/nm-types.h1
-rw-r--r--po/POTFILES.in3
-rw-r--r--src/devices/nm-device-tun.c192
-rw-r--r--src/devices/nm-device-tun.h4
-rw-r--r--src/devices/nm-device.c2
-rw-r--r--src/platform/nm-linux-platform.c63
-rw-r--r--src/platform/nm-platform.c43
-rw-r--r--src/platform/nm-platform.h8
31 files changed, 1796 insertions, 46 deletions
diff --git a/clients/cli/connections.c b/clients/cli/connections.c
index c00ab173c3..68640239eb 100644
--- a/clients/cli/connections.c
+++ b/clients/cli/connections.c
@@ -54,6 +54,9 @@ static const char *nmc_known_vpns[] =
{ "openvpn", "vpnc", "pptp", "openconnect", "openswan", "libreswan",
"ssh", "l2tp", "iodine", NULL };
+static const char *nmc_tun_modes[] =
+ { "tun", "tap", NULL };
+
/* Available fields for 'connection show' */
static NmcOutputField nmc_fields_con_show[] = {
{"NAME", N_("NAME")}, /* 0 */
@@ -104,6 +107,7 @@ extern NmcOutputField nmc_fields_setting_bridge_port[];
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[];
/* Available settings for 'connection show <con>' - profile part */
static NmcOutputField nmc_fields_settings_names[] = {
@@ -132,6 +136,7 @@ static NmcOutputField nmc_fields_settings_names[] = {
SETTING_FIELD (NM_SETTING_TEAM_SETTING_NAME, nmc_fields_setting_team + 1), /* 22 */
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 */
{NULL, NULL, 0, NULL, NULL, FALSE, FALSE, 0}
};
#define NMC_FIELDS_SETTINGS_NAMES_ALL_X NM_SETTING_CONNECTION_SETTING_NAME","\
@@ -157,7 +162,8 @@ static NmcOutputField nmc_fields_settings_names[] = {
NM_SETTING_BRIDGE_PORT_SETTING_NAME","\
NM_SETTING_TEAM_SETTING_NAME","\
NM_SETTING_TEAM_PORT_SETTING_NAME"," \
- NM_SETTING_DCB_SETTING_NAME
+ NM_SETTING_DCB_SETTING_NAME"," \
+ NM_SETTING_TUN_SETTING_NAME
#define NMC_FIELDS_SETTINGS_NAMES_ALL NMC_FIELDS_SETTINGS_NAMES_ALL_X
/* Active connection data */
@@ -395,6 +401,12 @@ usage_connection_add (void)
" protocol pppoa|pppoe|ipoatm\n"
" [password <password>]\n"
" [encapsulation vcmux|llc]\n\n"
+ " tun: mode tun|tap\n"
+ " [owner <UID>]\n"
+ " [group <GID>]\n"
+ " [pi yes|no]\n"
+ " [vnet-hdr yes|no]\n"
+ " [multi-queue yes|no]\n\n"
" SLAVE_OPTIONS:\n"
" bridge: [priority <0-63>]\n"
" [path-cost <1-65535>]\n"
@@ -2729,6 +2741,13 @@ static const NameItem nmc_bridge_slave_settings [] = {
{ NULL, NULL, NULL, FALSE }
};
+static const NameItem nmc_tun_settings [] = {
+ { NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL, TRUE },
+ { NM_SETTING_TUN_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[] = {
@@ -2751,6 +2770,7 @@ static const NameItem nmc_valid_connection_types[] = {
{ "bond-slave", NULL, nmc_bond_slave_settings },
{ "team-slave", NULL, nmc_team_slave_settings },
{ "bridge-slave", NULL, nmc_bridge_slave_settings },
+ { NM_SETTING_TUN_SETTING_NAME, NULL, nmc_tun_settings },
{ NULL, NULL, NULL }
};
@@ -2983,6 +3003,20 @@ check_infiniband_p_key (const char *p_key, guint32 *p_key_int, GError **error)
return TRUE;
}
+static gboolean
+check_user_group_id (const char *id, GError **error)
+{
+ unsigned long int value;
+
+ if (!nmc_string_to_uint (id, FALSE, 0, 0, &value)) {
+ g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: '%s' is not a valid UID/GID."), id);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
/**
* check_valid_enumeration:
* @str: string to check against string array @strings
@@ -4249,6 +4283,82 @@ is_property_valid (NMSetting *setting, const char *property, GError **error)
return ret;
}
+static void
+do_questionnaire_tun (char **user, char **group,
+ char **pi, char **vnet_hdr, char **multi_queue)
+{
+ gboolean once_more;
+ GError *error = NULL;
+ gboolean b;
+
+ if (!*user) {
+ do {
+ *user = nmc_readline (_("User ID [none]: "));
+ if (!*user)
+ break;
+ once_more = !check_user_group_id (*user, &error);
+ if (once_more) {
+ g_print ("%s\n", error->message);
+ g_clear_error (&error);
+ g_free (*user);
+ }
+ } while (once_more);
+ }
+ if (!*group) {
+ do {
+ *group = nmc_readline (_("Group ID [none]: "));
+ if (!*group)
+ break;
+ once_more = !check_user_group_id (*group, &error);
+ if (once_more) {
+ g_print ("%s\n", error->message);
+ g_clear_error (&error);
+ g_free (*group);
+ }
+ } while (once_more);
+ }
+
+ if (!*pi) {
+ do {
+ *pi = nmc_readline (_("Enable PI %s"), prompt_yes_no (FALSE, ":"));
+ *pi = *pi ? *pi : g_strdup ("no");
+ normalize_yes_no (pi);
+ once_more = !nmc_string_to_bool (*pi, &b, &error);
+ if (once_more) {
+ g_print (_("Error: 'pi': %s.\n"), error->message);
+ g_clear_error (&error);
+ g_free (*pi);
+ }
+ } while (once_more);
+ }
+ if (!*vnet_hdr) {
+ do {
+ *vnet_hdr = nmc_readline (_("Enable VNET header %s"), prompt_yes_no (FALSE, ":"));
+ *vnet_hdr = *vnet_hdr ? *vnet_hdr : g_strdup ("no");
+ normalize_yes_no (vnet_hdr);
+ once_more = !nmc_string_to_bool (*vnet_hdr, &b, &error);
+ if (once_more) {
+ g_print (_("Error: 'vnet-hdr': %s.\n"), error->message);
+ g_clear_error (&error);
+ g_free (*vnet_hdr);
+ }
+ } while (once_more);
+ }
+ if (!*multi_queue) {
+ do {
+ *multi_queue = nmc_readline (_("Enable multi queue %s"), prompt_yes_no (FALSE, ":"));
+ *multi_queue = *multi_queue ? *multi_queue : g_strdup ("no");
+ normalize_yes_no (multi_queue);
+ once_more = !nmc_string_to_bool (*multi_queue, &b, &error);
+ if (once_more) {
+ g_print (_("Error: 'multi-queue': %s.\n"), error->message);
+ g_clear_error (&error);
+ g_free (*multi_queue);
+ }
+ } while (once_more);
+ }
+}
+
static gboolean
read_connection_properties (NMConnection *connection,
int argc,
@@ -4459,6 +4569,7 @@ complete_connection_by_type (NMConnection *connection,
NMSettingVpn *s_vpn;
NMSettingOlpcMesh *s_olpc_mesh;
NMSettingAdsl *s_adsl;
+ NMSettingTun *s_tun;
const char *slave_type;
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
@@ -5569,6 +5680,114 @@ cleanup_adsl:
if (!success)
return FALSE;
+ } else if (!strcmp (con_type, NM_SETTING_TUN_SETTING_NAME)) {
+ /* Build up the settings required for 'tun' */
+ gboolean success = FALSE;
+ const char *mode = NULL;
+ NMSettingTunMode mode_enum;
+ char *mode_ask = NULL;
+ const char *owner_c = NULL, *group_c = NULL;
+ char *owner = NULL, *group = NULL;
+ const char *pi_c = NULL, *vnet_hdr_c = NULL, *multi_queue_c = NULL;
+ char *pi = NULL, *vnet_hdr = NULL, *multi_queue = NULL;
+ gboolean pi_bool, vnet_hdr_bool, multi_queue_bool;
+ nmc_arg_t exp_args[] = { {"mode", TRUE, &mode, !ask},
+ {"owner", TRUE, &owner_c, FALSE},
+ {"group", TRUE, &group_c, FALSE},
+ {"pi", TRUE, &pi_c, FALSE},
+ {"vnet-hdr", TRUE, &vnet_hdr_c, FALSE},
+ {"multi-queue", TRUE, &multi_queue_c, FALSE},
+ {NULL} };
+
+ if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error))
+ return FALSE;
+
+ if (!mode && ask)
+ mode = mode_ask = nmc_readline (_("Mode: "));
+ if (!mode) {
+ g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: 'mode' is required."));
+ goto cleanup_tun;
+ }
+
+ if (!(mode = nmc_string_is_valid (mode, nmc_tun_modes, NULL))) {
+ g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: 'mode' must be 'tun' or 'tap'."));
+ goto cleanup_tun;
+ }
+
+ if (owner && !check_user_group_id (owner, error))
+ goto cleanup_tun;
+ if (group && !check_user_group_id (group, error))
+ goto cleanup_tun;
+
+ owner = g_strdup (owner_c);
+ group = g_strdup (group_c);
+ pi = g_strdup (pi_c);
+ vnet_hdr = g_strdup (vnet_hdr_c);
+ multi_queue = g_strdup (multi_queue_c);
+ if (ask)
+ do_questionnaire_tun (&owner, &group, &pi, &vnet_hdr, &multi_queue);
+
+ if (pi) {
+ GError *tmp_err = NULL;
+
+ if (!nmc_string_to_bool (pi, &pi_bool, &tmp_err)) {
+ g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: 'pi': %s."), tmp_err->message);
+ g_clear_error (&tmp_err);
+ goto cleanup_tun;
+ }
+ }
+
+ if (vnet_hdr) {
+ GError *tmp_err = NULL;
+
+ if (!nmc_string_to_bool (vnet_hdr, &vnet_hdr_bool, &tmp_err)) {
+ g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: 'vnet-hdr': %s."), tmp_err->message);
+ g_clear_error (&tmp_err);
+ goto cleanup_tun;
+ }
+ }
+
+ if (multi_queue) {
+ GError *tmp_err = NULL;
+
+ if (!nmc_string_to_bool (multi_queue, &multi_queue_bool, &tmp_err)) {
+ g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: 'multi-queue': %s."), tmp_err->message);
+ g_clear_error (&tmp_err);
+ goto cleanup_tun;
+ }
+ }
+ /* Add 'tun' setting */
+ s_tun = (NMSettingTun *) nm_setting_tun_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_tun));
+ mode_enum = !strcmp (mode, "tun") ? NM_SETTING_TUN_MODE_TUN : NM_SETTING_TUN_MODE_TAP;
+
+ g_object_set (s_tun,
+ NM_SETTING_TUN_MODE, mode_enum,
+ NM_SETTING_TUN_OWNER, owner,
+ NM_SETTING_TUN_GROUP, group,
+ NULL);
+ if (pi)
+ g_object_set (s_tun, NM_SETTING_TUN_PI, pi_bool, NULL);
+ if (vnet_hdr)
+ g_object_set (s_tun, NM_SETTING_TUN_VNET_HDR, vnet_hdr_bool, NULL);
+ if (multi_queue)
+ g_object_set (s_tun, NM_SETTING_TUN_MULTI_QUEUE, multi_queue_bool, NULL);
+
+ success = TRUE;
+cleanup_tun:
+ g_free (mode_ask);
+ g_free (owner);
+ g_free (group);
+ g_free (pi);
+ g_free (vnet_hdr);
+ g_free (multi_queue);
+ if (!success)
+ return FALSE;
} else if (!strcmp (con_type, NM_SETTING_GENERIC_SETTING_NAME)) {
/* Add 'generic' setting */
s_generic = (NMSettingGeneric *) nm_setting_generic_new ();
diff --git a/clients/cli/nmcli-completion b/clients/cli/nmcli-completion
index 90365a0086..1827551b0c 100644
--- a/clients/cli/nmcli-completion
+++ b/clients/cli/nmcli-completion
@@ -401,7 +401,7 @@ _nmcli_compl_ARGS()
# user friendly. Only complete them, if the current word already starts with an "8".
_nmcli_list "802-3-ethernet 802-11-wireless 802-11-olpc-mesh"
else
- _nmcli_list "ethernet wifi wimax gsm cdma infiniband bluetooth vpn olpc-mesh vlan bond bridge team pppoe adsl"
+ _nmcli_list "ethernet wifi wimax gsm cdma infiniband bluetooth vpn olpc-mesh vlan bond bridge team pppoe adsl tun"
fi
return 0
fi
diff --git a/clients/cli/settings.c b/clients/cli/settings.c
index e9539f2795..7769fc9d2c 100644
--- a/clients/cli/settings.c
+++ b/clients/cli/settings.c
@@ -698,8 +698,27 @@ NmcOutputField nmc_fields_setting_dcb[] = {
NM_SETTING_DCB_PRIORITY_TRAFFIC_CLASS
#define NMC_FIELDS_SETTING_DCB_COMMON NMC_FIELDS_SETTING_DCB_ALL
-/*----------------------------------------------------------------------------*/
+/* Available fields for NM_SETTING_TUN_SETTING_NAME */
+NmcOutputField nmc_fields_setting_tun[] = {
+ SETTING_FIELD ("name"), /* 0 */
+ SETTING_FIELD (NM_SETTING_TUN_MODE), /* 1 */
+ SETTING_FIELD (NM_SETTING_TUN_OWNER), /* 2 */
+ SETTING_FIELD (NM_SETTING_TUN_GROUP), /* 3 */
+ SETTING_FIELD (NM_SETTING_TUN_PI), /* 4 */
+ SETTING_FIELD (NM_SETTING_TUN_VNET_HDR), /* 5 */
+ SETTING_FIELD (NM_SETTING_TUN_MULTI_QUEUE), /* 6 */
+ {NULL, NULL, 0, NULL, FALSE, FALSE, 0}
+};
+#define NMC_FIELDS_SETTING_TUN_ALL "name"","\
+ NM_SETTING_TUN_MODE","\
+ NM_SETTING_TUN_OWNER","\
+ NM_SETTING_TUN_GROUP","\
+ NM_SETTING_TUN_PI","\
+ NM_SETTING_TUN_VNET_HDR","\
+ NM_SETTING_TUN_MULTI_QUEUE
+#define NMC_FIELDS_SETTING_TUN_COMMON NMC_FIELDS_SETTING_TUN_ALL
+/*----------------------------------------------------------------------------*/
static char *
wep_key_type_to_string (NMWepKeyType type)
{
@@ -1284,6 +1303,13 @@ DEFINE_GETTER (nmc_property_gsm_get_sim_operator_id, NM_SETTING_GSM_SIM_OPERATOR
DEFINE_GETTER (nmc_property_ib_get_mac_address, NM_SETTING_INFINIBAND_MAC_ADDRESS)
DEFINE_GETTER (nmc_property_ib_get_transport_mode, NM_SETTING_INFINIBAND_TRANSPORT_MODE)
+/* --- NM_SETTING_TUN_SETTING_NAME property get functions --- */
+DEFINE_GETTER (nmc_property_tun_get_owner, NM_SETTING_TUN_OWNER);
+DEFINE_GETTER (nmc_property_tun_get_group, NM_SETTING_TUN_GROUP);
+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);
+
static char *
nmc_property_ib_get_mtu (NMSetting *setting, NmcPropertyGetType get_type)
{
@@ -5226,7 +5252,6 @@ nmc_property_gsm_set_sim_operator_id (NMSetting *setting, const char *prop, cons
return FALSE;
}
}
-
g_object_set (G_OBJECT (setting),
NM_SETTING_GSM_SIM_OPERATOR_ID,
val,
@@ -5234,6 +5259,48 @@ nmc_property_gsm_set_sim_operator_id (NMSetting *setting, const char *prop, cons
return TRUE;
}
+static char *
+nmc_property_tun_get_mode (NMSetting *setting, NmcPropertyGetType get_type)
+{
+ NMSettingTun *s_tun = NM_SETTING_TUN (setting);
+ NMSettingTunMode mode;
+ char *tmp, *str;
+
+ mode = nm_setting_tun_get_mode (s_tun);
+ tmp = nm_utils_enum_to_str (nm_setting_tun_mode_get_type (), mode);
+ if (get_type == NMC_PROPERTY_GET_PARSABLE)
+ str = g_strdup_printf ("%s", tmp ? tmp : "");
+ else
+ str = g_strdup_printf ("%d (%s)", mode, tmp ? tmp : "");
+ g_free (tmp);
+ return str;
+}
+
+static gboolean
+nmc_property_tun_set_mode (NMSetting *setting, const char *prop,
+ const char *val, GError **error)
+{
+ NMSettingTunMode mode;
+ gboolean ret;
+ long int t;
+
+ if (nmc_string_to_int_base (val, 0, TRUE, 0, NM_SETTING_TUN_MODE_TAP, &t))
+ mode = (NMSettingTunMode) t;
+ else {
+ ret = nm_utils_enum_from_str (nm_setting_tun_mode_get_type (), val,
+ (int *) &mode, NULL);
+
+ if (!ret) {
+ g_set_error (error, 1, 0, _("invalid option '%s', use '%s' or '%s"),
+ val, "tun", "tap");
+ return FALSE;
+ }
+ }
+
+ g_object_set (setting, prop, (guint) mode, NULL);
+ return TRUE;
+}
+
/*----------------------------------------------------------------------------*/
static inline void
@@ -6934,6 +7001,50 @@ nmc_properties_init (void)
NULL,
NULL,
NULL);
+
+ /* Add editable properties for NM_SETTING_TUN_SETTING_NAME */
+ nmc_add_prop_funcs (GLUE (TUN, MODE),
+ nmc_property_tun_get_mode,
+ nmc_property_tun_set_mode,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ nmc_add_prop_funcs (GLUE (TUN, OWNER),
+ nmc_property_tun_get_owner,
+ nmc_property_set_string,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ nmc_add_prop_funcs (GLUE (TUN, GROUP),
+ nmc_property_tun_get_group,
+ nmc_property_set_string,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ nmc_add_prop_funcs (GLUE (TUN, PI),
+ nmc_property_tun_get_pi,
+ nmc_property_set_bool,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ nmc_add_prop_funcs (GLUE (TUN, VNET_HDR),
+ nmc_property_tun_get_vnet_hdr,
+ nmc_property_set_bool,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ nmc_add_prop_funcs (GLUE (TUN, MULTI_QUEUE),
+ nmc_property_tun_get_multi_queue,
+ nmc_property_set_bool,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
}
void
@@ -8083,6 +8194,37 @@ setting_dcb_details (NMSetting *setting, NmCli *nmc, const char *one_prop, gboo
return TRUE;
}
+static gboolean
+setting_tun_details (NMSetting *setting, NmCli *nmc, const char *one_prop, gboolean secrets)
+{
+ NMSettingTun *s_tun = NM_SETTING_TUN (setting);
+ NmcOutputField *tmpl, *arr;
+ size_t tmpl_len;
+
+ g_return_val_if_fail (NM_IS_SETTING_TUN (s_tun), FALSE);
+
+ tmpl = nmc_fields_setting_tun;
+ tmpl_len = sizeof (nmc_fields_setting_tun);
+ nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_TUN_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_tun_get_mode (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 2, nmc_property_tun_get_owner (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 3, nmc_property_tun_get_group (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 4, nmc_property_tun_get_pi (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 5, nmc_property_tun_get_vnet_hdr (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 6, nmc_property_tun_get_multi_queue (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);
@@ -8114,6 +8256,7 @@ static const SettingDetails detail_printers[] = {
{ NM_SETTING_TEAM_SETTING_NAME, setting_team_details },
{ 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 },
{ NULL },
};
diff --git a/introspection/nm-device-tun.xml b/introspection/nm-device-tun.xml
index 8b0f81fbc6..2b3ae2f521 100644
--- a/introspection/nm-device-tun.xml
+++ b/introspection/nm-device-tun.xml
@@ -43,6 +43,12 @@
</tp:docstring>
</property>
+ <property name="HwAddress" type="s" access="read">
+ <tp:docstring>
+ Hardware address of the device.
+ </tp:docstring>
+ </property>
+
<signal name="PropertiesChanged">
<arg name="properties" type="a{sv}" tp:type="String_Variant_Map">
<tp:docstring>
diff --git a/libnm-core/Makefile.libnm-core b/libnm-core/Makefile.libnm-core
index fb201bdbad..867dd9045d 100644
--- a/libnm-core/Makefile.libnm-core
+++ b/libnm-core/Makefile.libnm-core
@@ -33,6 +33,7 @@ libnm_core_headers = \
$(core)/nm-setting-serial.h \
$(core)/nm-setting-team-port.h \
$(core)/nm-setting-team.h \
+ $(core)/nm-setting-tun.h \
$(core)/nm-setting-vlan.h \
$(core)/nm-setting-vpn.h \
$(core)/nm-setting-wimax.h \
@@ -89,6 +90,7 @@ libnm_core_sources = \
$(core)/nm-setting-serial.c \
$(core)/nm-setting-team-port.c \
$(core)/nm-setting-team.c \
+ $(core)/nm-setting-tun.c \
$(core)/nm-setting-vlan.c \
$(core)/nm-setting-vpn.c \
$(core)/nm-setting-wimax.c \
diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c
index 412ca3c4a7..94a897539a 100644
--- a/libnm-core/nm-connection.c
+++ b/libnm-core/nm-connection.c
@@ -1594,7 +1594,8 @@ nm_connection_is_virtual (NMConnection *connection)
if ( !strcmp (type, NM_SETTING_BOND_SETTING_NAME)
|| !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_VLAN_SETTING_NAME)
+ || !strcmp (type, NM_SETTING_TUN_SETTING_NAME))
return TRUE;
if (!strcmp (type, NM_SETTING_INFINIBAND_SETTING_NAME)) {
@@ -1950,6 +1951,24 @@ nm_connection_get_setting_serial (NMConnection *connection)
}
/**
+ * nm_connection_get_setting_tun:
+ * @connection: the #NMConnection
+ *
+ * A shortcut to return any #NMSettingTun the connection might contain.
+ *
+ * Returns: (transfer none): an #NMSettingTun if the connection contains one, otherwise %NULL
+ *
+ * Since: 1.2
+ **/
+NMSettingTun *
+nm_connection_get_setting_tun (NMConnection *connection)
+{
+ g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
+
+ return (NMSettingTun *) nm_connection_get_setting (connection, NM_TYPE_SETTING_TUN);
+}
+
+/**
* nm_connection_get_setting_vpn:
* @connection: the #NMConnection
*
diff --git a/libnm-core/nm-connection.h b/libnm-core/nm-connection.h
index f27ecc5bc0..fc2117f61e 100644
--- a/libnm-core/nm-connection.h
+++ b/libnm-core/nm-connection.h
@@ -208,6 +208,7 @@ NMSettingOlpcMesh * nm_connection_get_setting_olpc_mesh (NMConnec
NMSettingPpp * nm_connection_get_setting_ppp (NMConnection *connection);
NMSettingPppoe * nm_connection_get_setting_pppoe (NMConnection *connection);
NMSettingSerial * nm_connection_get_setting_serial (NMConnection *connection);
+NMSettingTun * nm_connection_get_setting_tun (NMConnection *connection);
NMSettingVpn * nm_connection_get_setting_vpn (NMConnection *connection);
NMSettingWimax * nm_connection_get_setting_wimax (NMConnection *connection);
NMSettingAdsl * nm_connection_get_setting_adsl (NMConnection *connection);
diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h
index 4c95d0d0a7..d1b0992900 100644
--- a/libnm-core/nm-core-internal.h
+++ b/libnm-core/nm-core-internal.h
@@ -57,6 +57,7 @@
#include "nm-setting-serial.h"
#include "nm-setting-team-port.h"
#include "nm-setting-team.h"
+#include "nm-setting-tun.h"
#include "nm-setting-vlan.h"
#include "nm-setting-vpn.h"
#include "nm-setting-wimax.h"
diff --git a/libnm-core/nm-core-types.h b/libnm-core/nm-core-types.h
index 19388c5bb3..1355c92da6 100644
--- a/libnm-core/nm-core-types.h
+++ b/libnm-core/nm-core-types.h
@@ -50,6 +50,7 @@ typedef struct _NMSettingPppoe NMSettingPppoe;
typedef struct _NMSettingSerial NMSettingSerial;
typedef struct _NMSettingTeam NMSettingTeam;
typedef struct _NMSettingTeamPort NMSettingTeamPort;
+typedef struct _NMSettingTun NMSettingTun;
typedef struct _NMSettingVlan NMSettingVlan;
typedef struct _NMSettingVpn NMSettingVpn;
typedef struct _NMSettingWimax NMSettingWimax;
diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h
index 68b0592e72..ddd6834c23 100644
--- a/libnm-core/nm-dbus-interface.h
+++ b/libnm-core/nm-dbus-interface.h
@@ -148,6 +148,7 @@ typedef enum {
* @NM_DEVICE_TYPE_ADSL: ADSL modem
* @NM_DEVICE_TYPE_BRIDGE: a bridge master interface
* @NM_DEVICE_TYPE_TEAM: a team master interface
+ * @NM_DEVICE_TYPE_TUN: a TUN or TAP interface
*
* #NMDeviceType values indicate the type of hardware represented by
* an #NMDevice.
@@ -171,6 +172,7 @@ typedef enum {
NM_DEVICE_TYPE_BRIDGE = 13,
NM_DEVICE_TYPE_GENERIC = 14,
NM_DEVICE_TYPE_TEAM = 15,
+ NM_DEVICE_TYPE_TUN = 16,
} NMDeviceType;
/**
diff --git a/libnm-core/nm-setting-tun.c b/libnm-core/nm-setting-tun.c
new file mode 100644
index 0000000000..b3c118601b
--- /dev/null
+++ b/libnm-core/nm-setting-tun.c
@@ -0,0 +1,409 @@
+/* -*- 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 <stdlib.h>
+#include <string.h>
+
+#include "nm-setting-tun.h"
+#include "nm-utils.h"
+#include "nm-setting-connection.h"
+#include "nm-setting-private.h"
+#include "nm-connection-private.h"
+
+/**
+ * SECTION:nm-setting-tun
+ * @short_description: Describes connection properties for TUN/TAP interfaces
+ *
+ * The #NMSettingTun object is a #NMSetting subclass that describes properties
+ * necessary for connection to TUN/TAP interfaces.
+ **/
+
+G_DEFINE_TYPE_WITH_CODE (NMSettingTun, nm_setting_tun, NM_TYPE_SETTING,
+ _nm_register_setting (TUN, 1))
+NM_SETTING_REGISTER_TYPE (NM_TYPE_SETTING_TUN)
+
+#define NM_SETTING_TUN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_TUN, NMSettingTunPrivate))
+
+typedef struct {
+ NMSettingTunMode mode;
+ char *owner;
+ char *group;
+ gboolean pi;
+ gboolean vnet_hdr;
+ gboolean multi_queue;
+} NMSettingTunPrivate;
+
+enum {
+ PROP_0,
+ PROP_MODE,
+ PROP_OWNER,
+ PROP_GROUP,
+ PROP_PI,
+ PROP_VNET_HDR,
+ PROP_MULTI_QUEUE,
+ LAST_PROP
+};
+
+/**
+ * nm_setting_tun_new:
+ *
+ * Creates a new #NMSettingTun object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingTun object
+ *
+ * Since: 1.2
+ **/
+NMSetting *
+nm_setting_tun_new (void)
+{
+ return (NMSetting *) g_object_new (NM_TYPE_SETTING_TUN, NULL);
+}
+
+/**
+ * nm_setting_tun_get_mode:
+ * @setting: the #NMSettingTun
+ *
+ * Returns: the #NMSettingTun:mode property of the setting
+ *
+ * Since: 1.2
+ **/
+NMSettingTunMode
+nm_setting_tun_get_mode (NMSettingTun *setting)
+{
+ g_return_val_if_fail (NM_IS_SETTING_TUN (setting), NM_SETTING_TUN_MODE_TUN);
+ return NM_SETTING_TUN_GET_PRIVATE (setting)->mode;
+}
+
+/**
+ * nm_setting_tun_get_owner:
+ * @setting: the #NMSettingTun
+ *
+ * Returns: the #NMSettingTun:owner property of the setting
+ *
+ * Since: 1.2
+ **/
+const char *
+nm_setting_tun_get_owner (NMSettingTun *setting)
+{
+ g_return_val_if_fail (NM_IS_SETTING_TUN (setting), NULL);
+ return NM_SETTING_TUN_GET_PRIVATE (setting)->owner;
+}
+
+/**
+ * nm_setting_tun_get_group:
+ * @setting: the #NMSettingTun
+ *
+ * Returns: the #NMSettingTun:group property of the setting
+ *
+ * Since: 1.2
+ **/
+const char *
+nm_setting_tun_get_group (NMSettingTun *setting)
+{
+ g_return_val_if_fail (NM_IS_SETTING_TUN (setting), NULL);
+ return NM_SETTING_TUN_GET_PRIVATE (setting)->group;
+}
+
+/**
+ * nm_setting_tun_get_pi:
+ * @setting: the #NMSettingTun
+ *
+ * Returns: the #NMSettingTun:pi property of the setting
+ *
+ * Since: 1.2
+ **/
+gboolean
+nm_setting_tun_get_pi (NMSettingTun *setting)
+{
+ g_return_val_if_fail (NM_IS_SETTING_TUN (setting), FALSE);
+ return NM_SETTING_TUN_GET_PRIVATE (setting)->pi;
+}
+
+/**
+ * nm_setting_tun_get_vnet_hdr:
+ * @setting: the #NMSettingTun
+ *
+ * Returns: the #NMSettingTun:vnet_hdr property of the setting
+ *
+ * Since: 1.2
+ **/
+gboolean
+nm_setting_tun_get_vnet_hdr (NMSettingTun *setting)
+{
+ g_return_val_if_fail (NM_IS_SETTING_TUN (setting), FALSE);
+ return NM_SETTING_TUN_GET_PRIVATE (setting)->vnet_hdr;
+}
+
+/**
+ * nm_setting_tun_get_multi_queue:
+ * @setting: the #NMSettingTun
+ *
+ * Returns: the #NMSettingTun:multi-queue property of the setting
+ *
+ * Since: 1.2
+ **/
+gboolean
+nm_setting_tun_get_multi_queue (NMSettingTun *setting)
+{
+ g_return_val_if_fail (NM_IS_SETTING_TUN (setting), FALSE);
+ return NM_SETTING_TUN_GET_PRIVATE (setting)->multi_queue;
+}
+
+static void
+nm_setting_tun_init (NMSettingTun *setting)
+{
+}
+
+static gboolean
+verify (NMSetting *setting, NMConnection *connection, GError **error)
+{
+ NMSettingTunPrivate *priv = NM_SETTING_TUN_GET_PRIVATE (setting);
+
+ if ( priv->mode != NM_SETTING_TUN_MODE_TUN
+ && priv->mode != NM_SETTING_TUN_MODE_TAP) {
+ g_set_error (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("'%u': invalid mode"), (unsigned int) priv->mode);
+ g_prefix_error (error, "%s.%s: ", NM_SETTING_TUN_SETTING_NAME, NM_SETTING_TUN_MODE);
+ return FALSE;
+ }
+
+ if (priv->owner) {
+ if (_nm_utils_ascii_str_to_int64 (priv->owner, 10, 0, G_MAXINT32, -1) == -1) {
+ g_set_error (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("'%s': invalid user ID"), priv->owner);
+ g_prefix_error (error, "%s.%s: ", NM_SETTING_TUN_SETTING_NAME, NM_SETTING_TUN_OWNER);
+ return FALSE;
+ }
+ }
+
+ if (priv->group) {
+ if (_nm_utils_ascii_str_to_int64 (priv->group, 10, 0, G_MAXINT32, -1) == -1) {
+ g_set_error (error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_INVALID_PROPERTY,
+ _("'%s': invalid group ID"), priv->group);
+ g_prefix_error (error, "%s.%s: ", NM_SETTING_TUN_SETTING_NAME, NM_SETTING_TUN_GROUP);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ NMSettingTun *setting = NM_SETTING_TUN (object);
+ NMSettingTunPrivate *priv = NM_SETTING_TUN_GET_PRIVATE (setting);
+
+ switch (prop_id) {
+ case PROP_MODE:
+ priv->mode = g_value_get_uint (value);
+ break;
+ case PROP_OWNER:
+ g_free (priv->owner);
+ priv->owner = g_value_dup_string (value);
+ break;
+ case PROP_GROUP:
+ g_free (priv->group);
+ priv->group = g_value_dup_string (value);
+ break;
+ case PROP_PI:
+ priv->pi = g_value_get_boolean (value);
+ break;
+ case PROP_VNET_HDR:
+ priv->vnet_hdr = g_value_get_boolean (value);
+ break;
+ case PROP_MULTI_QUEUE:
+ priv->multi_queue = g_value_get_boolean (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)
+{
+ NMSettingTun *setting = NM_SETTING_TUN (object);
+ NMSettingTunPrivate *priv = NM_SETTING_TUN_GET_PRIVATE (setting);
+
+ switch (prop_id) {
+ case PROP_MODE:
+ g_value_set_uint (value, priv->mode);
+ break;
+ case PROP_OWNER:
+ g_value_set_string (value, priv->owner);
+ break;
+ case PROP_GROUP:
+ g_value_set_string (value, priv->group);
+ break;
+ case PROP_PI:
+ g_value_set_boolean (value, priv->pi);
+ break;
+ case PROP_VNET_HDR:
+ g_value_set_boolean (value, priv->vnet_hdr);
+ break;
+ case PROP_MULTI_QUEUE:
+ g_value_set_boolean (value, priv->multi_queue);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+finalize (GObject *object)
+{
+ NMSettingTun *setting = NM_SETTING_TUN (object);
+ NMSettingTunPrivate *priv = NM_SETTING_TUN_GET_PRIVATE (setting);
+
+ g_free (priv->owner);
+ g_free (priv->group);
+
+ G_OBJECT_CLASS (nm_setting_tun_parent_class)->finalize (object);
+}
+
+static void
+nm_setting_tun_class_init (NMSettingTunClass *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 (NMSettingTunPrivate));
+
+ /* virtual methods */
+ object_class->set_property = set_property;
+ object_class->get_property = get_property;
+ object_class->finalize = finalize;
+ parent_class->verify = verify;
+
+ /* Properties */
+ /**
+ * NMSettingTun:mode:
+ *
+ * The operating mode of the virtual device. Allowed values are
+ * %NM_SETTING_TUN_MODE_TUN to create a layer 3 device and
+ * %NM_SETTING_TUN_MODE_TAP to create an Ethernet-like layer 2
+ * one.
+ *
+ * Since: 1.2
+ */
+ g_object_class_install_property
+ (object_class, PROP_MODE,
+ g_param_spec_uint (NM_SETTING_TUN_MODE, "", "",
+ 0, G_MAXUINT, NM_SETTING_TUN_MODE_TUN,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ NM_SETTING_PARAM_INFERRABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMSettingTun:owner:
+ *
+ * The user ID which will own the device. If set to %NULL everyone
+ * will be able to use the device.
+ *
+ * Since: 1.2
+ */
+ g_object_class_install_property
+ (object_class, PROP_OWNER,
+ g_param_spec_string (NM_SETTING_TUN_OWNER, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ NM_SETTING_PARAM_INFERRABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMSettingTun:group:
+ *
+ * The group ID which will own the device. If set to %NULL everyone
+ * will be able to use the device.
+ *
+ * Since: 1.2
+ */
+ g_object_class_install_property
+ (object_class, PROP_GROUP,
+ g_param_spec_string (NM_SETTING_TUN_GROUP, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ NM_SETTING_PARAM_INFERRABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMSettingTun:pi:
+ *
+ * If %TRUE the interface will prepend a 4 byte header describing the
+ * physical interface to the packets.
+ *
+ * Since: 1.2
+ */
+ g_object_class_install_property
+ (object_class, PROP_PI,
+ g_param_spec_boolean (NM_SETTING_TUN_PI, "", "",
+ FALSE,
+ G_PARAM_READWRITE |
+ NM_SETTING_PARAM_INFERRABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMSettingTun:vnet-hdr:
+ *
+ * If %TRUE the IFF_VNET_HDR the tunnel packets will include a virtio
+ * network header.
+ *
+ * Since: 1.2
+ */
+ g_object_class_install_property
+ (object_class, PROP_VNET_HDR,
+ g_param_spec_boolean (NM_SETTING_TUN_VNET_HDR, "", "",
+ FALSE,
+ G_PARAM_READWRITE |
+ NM_SETTING_PARAM_INFERRABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMSettingTun:multi-queue:
+ *
+ * If the property is set to %TRUE, the interface will support
+ * multiple file descriptors (queues) to parallelize packet
+ * sending or receiving. Otherwise, the interface will only
+ * support a single queue.
+ *
+ * Since: 1.2
+ */
+ g_object_class_install_property
+ (object_class, PROP_MULTI_QUEUE,
+ g_param_spec_boolean (NM_SETTING_TUN_MULTI_QUEUE, "", "",
+ FALSE,
+ G_PARAM_READWRITE |
+ NM_SETTING_PARAM_INFERRABLE |
+ G_PARAM_STATIC_STRINGS));
+}
diff --git a/libnm-core/nm-setting-tun.h b/libnm-core/nm-setting-tun.h
new file mode 100644
index 0000000000..2b368a694a
--- /dev/null
+++ b/libnm-core/nm-setting-tun.h
@@ -0,0 +1,94 @@
+/* -*- 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_TUN_H__
+#define __NM_SETTING_TUN_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_TUN (nm_setting_tun_get_type ())
+#define NM_SETTING_TUN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTING_TUN, NMSettingTun))
+#define NM_SETTING_TUN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SETTING_TUNCONFIG, NMSettingTunClass))
+#define NM_IS_SETTING_TUN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTING_TUN))
+#define NM_IS_SETTING_TUN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SETTING_TUN))
+#define NM_SETTING_TUN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SETTING_TUN, NMSettingTunClass))
+
+#define NM_SETTING_TUN_SETTING_NAME "tun"
+
+#define NM_SETTING_TUN_MODE "mode"
+#define NM_SETTING_TUN_OWNER "owner"
+#define NM_SETTING_TUN_GROUP "group"
+#define NM_SETTING_TUN_PI "pi"
+#define NM_SETTING_TUN_VNET_HDR "vnet-hdr"
+#define NM_SETTING_TUN_MULTI_QUEUE "multi-queue"
+
+/**
+ * NMSettingTunMode:
+ * @NM_SETTING_TUN_MODE_UNKNOWN: an unknown device type
+ * @NM_SETTING_TUN_MODE_TUN: a TUN device
+ * @NM_SETTING_TUN_MODE_TAP: a TAP device
+ *
+ * #NMSettingTunMode values indicate the device type (TUN/TAP)
+ */
+typedef enum {
+ NM_SETTING_TUN_MODE_UNKNOWN = 0,
+ NM_SETTING_TUN_MODE_TUN = 1,
+ NM_SETTING_TUN_MODE_TAP = 2,
+} NMSettingTunMode;
+
+struct _NMSettingTun {
+ NMSetting parent;
+};
+
+typedef struct {
+ NMSettingClass parent;
+
+ /*< private >*/
+ gpointer padding[4];
+} NMSettingTunClass;
+
+NM_AVAILABLE_IN_1_2
+GType nm_setting_tun_get_type (void);
+NM_AVAILABLE_IN_1_2
+NMSetting *nm_setting_tun_new (void);
+
+NM_AVAILABLE_IN_1_2
+NMSettingTunMode nm_setting_tun_get_mode (NMSettingTun *setting);
+NM_AVAILABLE_IN_1_2
+const char *nm_setting_tun_get_owner (NMSettingTun *setting);
+NM_AVAILABLE_IN_1_2
+const char *nm_setting_tun_get_group (NMSettingTun *setting);
+NM_AVAILABLE_IN_1_2
+gboolean nm_setting_tun_get_pi (NMSettingTun *setting);
+NM_AVAILABLE_IN_1_2
+gboolean nm_setting_tun_get_vnet_hdr (NMSettingTun *setting);
+NM_AVAILABLE_IN_1_2
+gboolean nm_setting_tun_get_multi_queue (NMSettingTun *setting);
+
+G_END_DECLS
+
+#endif /* __NM_SETTING_TUN_H__ */
diff --git a/libnm-glib/libnm-glib-test.c b/libnm-glib/libnm-glib-test.c
index 3b8f6cab14..9c8085d371 100644
--- a/libnm-glib/libnm-glib-test.c
+++ b/libnm-glib/libnm-glib-test.c
@@ -36,6 +36,7 @@
#include "nm-device.h"
#include "nm-device-ethernet.h"
#include "nm-device-wifi.h"
+#include "nm-device-generic.h"
#include "nm-utils.h"
#include "nm-active-connection.h"
#include "nm-vpn-connection.h"
@@ -212,6 +213,12 @@ dump_wireless (NMDeviceWifi *device)
}
static void
+dump_generic (NMDeviceGeneric *device)
+{
+ g_print ("HW address: %s\n", nm_device_generic_get_hw_address (device));
+}
+
+static void
dump_wired (NMDeviceEthernet *device)
{
const char *str;
@@ -253,6 +260,8 @@ dump_device (NMDevice *device)
dump_wired (NM_DEVICE_ETHERNET (device));
else if (NM_IS_DEVICE_WIFI (device))
dump_wireless (NM_DEVICE_WIFI (device));
+ else if (NM_IS_DEVICE_GENERIC (device))
+ dump_generic (NM_DEVICE_GENERIC (device));
dump_dhcp4_config (nm_device_get_dhcp4_config (device));
}
diff --git a/libnm-glib/nm-device-generic.c b/libnm-glib/nm-device-generic.c
index a17a67355a..a7b2fa04dd 100644
--- a/libnm-glib/nm-device-generic.c
+++ b/libnm-glib/nm-device-generic.c
@@ -184,15 +184,41 @@ register_properties (NMDeviceGeneric *device)
property_info);
}
+static const char *
+_device_type_to_interface (NMDeviceType type)
+{
+ switch (type) {
+ case NM_DEVICE_TYPE_GENERIC:
+ return NM_DBUS_INTERFACE_DEVICE_GENERIC;
+ case NM_DEVICE_TYPE_TUN:
+ return NM_DBUS_INTERFACE_DEVICE_TUN;
+ default:
+ return NULL;
+ }
+}
+
static void
constructed (GObject *object)
{
NMDeviceGenericPrivate *priv = NM_DEVICE_GENERIC_GET_PRIVATE (object);
+ NMDeviceType type;
+ DBusGConnection *connection;
+ const char *path, *interface;
G_OBJECT_CLASS (nm_device_generic_parent_class)->constructed (object);
- priv->proxy = _nm_object_new_proxy (NM_OBJECT (object), NULL, NM_DBUS_INTERFACE_DEVICE_GENERIC);
- register_properties (NM_DEVICE_GENERIC (object));
+ g_object_get (object,
+ NM_OBJECT_DBUS_CONNECTION, &connection,
+ NM_OBJECT_DBUS_PATH, &path,
+ NULL);
+
+ type = _nm_device_type_for_path (connection, path);
+ interface = _device_type_to_interface (type);
+
+ if (interface) {
+ priv->proxy = _nm_object_new_proxy (NM_OBJECT (object), NULL, interface);
+ register_properties (NM_DEVICE_GENERIC (object));
+ }
}
static void
diff --git a/libnm-glib/nm-device-private.h b/libnm-glib/nm-device-private.h
index 82d676f92e..1a29c97d7b 100644
--- a/libnm-glib/nm-device-private.h
+++ b/libnm-glib/nm-device-private.h
@@ -22,5 +22,6 @@
#define NM_DEVICE_PRIVATE_H
void _nm_device_set_device_type (NMDevice *device, NMDeviceType dtype);
+NMDeviceType _nm_device_type_for_path (DBusGConnection *connection, const char *path);
#endif /* NM_DEVICE_PRIVATE_H */
diff --git a/libnm-glib/nm-device.c b/libnm-glib/nm-device.c
index 460f079409..aac94fb1dc 100644
--- a/libnm-glib/nm-device.c
+++ b/libnm-glib/nm-device.c
@@ -50,17 +50,17 @@
#include "nm-utils.h"
#include "nm-dbus-helpers-private.h"
-static GType _nm_device_type_for_path (DBusGConnection *connection,
- const char *path);
-static void _nm_device_type_for_path_async (DBusGConnection *connection,
- const char *path,
- NMObjectTypeCallbackFunc callback,
- gpointer user_data);
+static GType _nm_device_gtype_for_path (DBusGConnection *connection,
+ const char *path);
+static void _nm_device_gtype_for_path_async (DBusGConnection *connection,
+ const char *path,
+ NMObjectTypeCallbackFunc callback,
+ gpointer user_data);
gboolean connection_compatible (NMDevice *device, NMConnection *connection, GError **error);
G_DEFINE_TYPE_WITH_CODE (NMDevice, nm_device, NM_TYPE_OBJECT,
- _nm_object_register_type_func (g_define_type_id, _nm_device_type_for_path,
- _nm_device_type_for_path_async);
+ _nm_object_register_type_func (g_define_type_id, _nm_device_gtype_for_path,
+ _nm_device_gtype_for_path_async);
)
#define DBUS_G_TYPE_UINT_STRUCT (dbus_g_type_get_struct ("GValueArray", G_TYPE_UINT, G_TYPE_UINT, G_TYPE_INVALID))
@@ -320,6 +320,7 @@ _nm_device_gtype_from_dtype (NMDeviceType dtype)
case NM_DEVICE_TYPE_VLAN:
return NM_TYPE_DEVICE_VLAN;
case NM_DEVICE_TYPE_GENERIC:
+ case NM_DEVICE_TYPE_TUN:
return NM_TYPE_DEVICE_GENERIC;
default:
g_warning ("Unknown device type %d", dtype);
@@ -882,14 +883,12 @@ _nm_device_set_device_type (NMDevice *device, NMDeviceType dtype)
g_warn_if_fail (dtype == priv->device_type);
}
-static GType
-_nm_device_type_for_path (DBusGConnection *connection,
- const char *path)
+NMDeviceType
+_nm_device_type_for_path (DBusGConnection *connection, const char *path)
{
DBusGProxy *proxy;
GError *err = NULL;
GValue value = G_VALUE_INIT;
- NMDeviceType nm_dtype;
proxy = _nm_dbus_new_proxy_for_connection (connection, path, DBUS_INTERFACE_PROPERTIES);
if (!proxy) {
@@ -910,8 +909,14 @@ _nm_device_type_for_path (DBusGConnection *connection,
}
g_object_unref (proxy);
- nm_dtype = g_value_get_uint (&value);
- return _nm_device_gtype_from_dtype (nm_dtype);
+ return g_value_get_uint (&value);
+}
+
+static GType
+_nm_device_gtype_for_path (DBusGConnection *connection,
+ const char *path)
+{
+ return _nm_device_gtype_from_dtype (_nm_device_type_for_path (connection, path));
}
/**
@@ -932,7 +937,7 @@ nm_device_new (DBusGConnection *connection, const char *path)
g_return_val_if_fail (connection != NULL, NULL);
g_return_val_if_fail (path != NULL, NULL);
- dtype = _nm_device_type_for_path (connection, path);
+ dtype = _nm_device_gtype_for_path (connection, path);
if (dtype == G_TYPE_INVALID)
return NULL;
@@ -978,7 +983,7 @@ async_got_type (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
}
static void
-_nm_device_type_for_path_async (DBusGConnection *connection,
+_nm_device_gtype_for_path_async (DBusGConnection *connection,
const char *path,
NMObjectTypeCallbackFunc callback,
gpointer user_data)
diff --git a/libnm-util/NetworkManager.h b/libnm-util/NetworkManager.h
index d83e4ab5a5..71862c42eb 100644
--- a/libnm-util/NetworkManager.h
+++ b/libnm-util/NetworkManager.h
@@ -151,6 +151,7 @@ typedef enum {
* @NM_DEVICE_TYPE_ADSL: ADSL modem
* @NM_DEVICE_TYPE_BRIDGE: a bridge master interface
* @NM_DEVICE_TYPE_TEAM: a team master interface
+ * @NM_DEVICE_TYPE_TUN: a TUN/TAP interface
*
* #NMDeviceType values indicate the type of hardware represented by
* an #NMDevice.
@@ -174,6 +175,7 @@ typedef enum {
NM_DEVICE_TYPE_BRIDGE = 13,
NM_DEVICE_TYPE_GENERIC = 14,
NM_DEVICE_TYPE_TEAM = 15,
+ NM_DEVICE_TYPE_TUN = 16,
} NMDeviceType;
/**
diff --git a/libnm/Makefile.am b/libnm/Makefile.am
index a08bd80088..bf921abd89 100644
--- a/libnm/Makefile.am
+++ b/libnm/Makefile.am
@@ -41,6 +41,7 @@ libnminclude_hfiles = \
nm-device-modem.h \
nm-device-olpc-mesh.h \
nm-device-team.h \
+ nm-device-tun.h \
nm-device-vlan.h \
nm-device-wifi.h \
nm-device-wimax.h \
@@ -92,6 +93,7 @@ libnm_la_csources = \
nm-device-modem.c \
nm-device-olpc-mesh.c \
nm-device-team.c \
+ nm-device-tun.c \
nm-device-vlan.c \
nm-device-wifi.c \
nm-device-wimax.c \
diff --git a/libnm/NetworkManager.h b/libnm/NetworkManager.h
index 085437e6f5..95c92965e3 100644
--- a/libnm/NetworkManager.h
+++ b/libnm/NetworkManager.h
@@ -69,6 +69,7 @@
#include <nm-setting-serial.h>
#include <nm-setting-team-port.h>
#include <nm-setting-team.h>
+#include <nm-setting-tun.h>
#include <nm-setting-vlan.h>
#include <nm-setting-vpn.h>
#include <nm-setting-wimax.h>
diff --git a/libnm/libnm.ver b/libnm/libnm.ver
index 7feed07577..865cc328df 100644
--- a/libnm/libnm.ver
+++ b/libnm/libnm.ver
@@ -864,6 +864,14 @@ global:
nm_device_get_metered;
nm_device_get_nm_plugin_missing;
nm_device_set_managed;
+ nm_device_tun_get_group;
+ nm_device_tun_get_hw_address;
+ nm_device_tun_get_mode;
+ nm_device_tun_get_multi_queue;
+ nm_device_tun_get_owner;
+ nm_device_tun_get_no_pi;
+ nm_device_tun_get_type;
+ nm_device_tun_get_vnet_hdr;
nm_device_wifi_request_scan_options;
nm_device_wifi_request_scan_options_async;
nm_lldp_neighbor_get_attr_names;
@@ -897,6 +905,15 @@ global:
nm_setting_ip_config_remove_dns_option;
nm_setting_ip_config_remove_dns_option_by_value;
nm_setting_mac_randomization_get_type;
+ nm_setting_tun_get_group;
+ nm_setting_tun_get_mode;
+ nm_setting_tun_get_multi_queue;
+ nm_setting_tun_get_owner;
+ nm_setting_tun_get_pi;
+ nm_setting_tun_get_type;
+ nm_setting_tun_get_vnet_hdr;
+ nm_setting_tun_mode_get_type;
+ nm_setting_tun_new;
nm_setting_verify_secrets;
nm_setting_vpn_get_timeout;
nm_setting_wired_get_wake_on_lan;
diff --git a/libnm/nm-device-tun.c b/libnm/nm-device-tun.c
new file mode 100644
index 0000000000..ce2558f0a9
--- /dev/null
+++ b/libnm/nm-device-tun.c
@@ -0,0 +1,439 @@
+/* -*- 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 <arpa/inet.h>
+
+#include <nm-setting-connection.h>
+#include <nm-setting-tun.h>
+#include <nm-utils.h>
+
+#include "nm-default.h"
+#include "nm-device-tun.h"
+#include "nm-device-private.h"
+#include "nm-object-private.h"
+
+G_DEFINE_TYPE (NMDeviceTun, nm_device_tun, NM_TYPE_DEVICE)
+
+#define NM_DEVICE_TUN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_TUN, NMDeviceTunPrivate))
+
+typedef struct {
+ char *hw_address;
+ char *mode;
+ gint64 owner;
+ gint64 group;
+ gboolean no_pi;
+ gboolean vnet_hdr;
+ gboolean multi_queue;
+} NMDeviceTunPrivate;
+
+enum {
+ PROP_0,
+ PROP_HW_ADDRESS,
+ PROP_MODE,
+ PROP_OWNER,
+ PROP_GROUP,
+ PROP_NO_PI,
+ PROP_VNET_HDR,
+ PROP_MULTI_QUEUE,
+
+ LAST_PROP
+};
+
+/**
+ * nm_device_tun_get_hw_address:
+ * @device: a #NMDeviceTun
+ *
+ * Gets the hardware (MAC) address of the #NMDeviceTun
+ *
+ * Returns: the hardware address. This is the internal string used by the
+ * device, and must not be modified.
+ *
+ * Since: 1.2
+ **/
+const char *
+nm_device_tun_get_hw_address (NMDeviceTun *device)
+{
+ g_return_val_if_fail (NM_IS_DEVICE_TUN (device), NULL);
+
+ return NM_DEVICE_TUN_GET_PRIVATE (device)->hw_address;
+}
+
+/**
+ * nm_device_tun_get_mode:
+ * @device: a #NMDeviceTun
+ *
+ * Returns the TUN/TAP mode for the device.
+ *
+ * Returns: 'tun' or 'tap'
+ *
+ * Since: 1.2
+ **/
+const char *
+nm_device_tun_get_mode (NMDeviceTun *device)
+{
+ g_return_val_if_fail (NM_IS_DEVICE_TUN (device), NULL);
+
+ return NM_DEVICE_TUN_GET_PRIVATE (device)->mode;
+}
+
+/**
+ * nm_device_tun_get_owner:
+ * @device: a #NMDeviceTun
+ *
+ * Gets the tunnel owner.
+ *
+ * Returns: the uid of the tunnel owner, or -1 if it has no owner.
+ *
+ * Since: 1.2
+ **/
+gint64
+nm_device_tun_get_owner (NMDeviceTun *device)
+{
+ g_return_val_if_fail (NM_IS_DEVICE_TUN (device), -1);
+
+ return NM_DEVICE_TUN_GET_PRIVATE (device)->owner;
+}
+
+/**
+ * nm_device_tun_get_group:
+ * @device: a #NMDeviceTun
+ *
+ * Gets the tunnel group.
+ *
+ * Returns: the gid of the tunnel group, or -1 if it has no owner.
+ *
+ * Since: 1.2
+ **/
+gint64
+nm_device_tun_get_group (NMDeviceTun *device)
+{
+ g_return_val_if_fail (NM_IS_DEVICE_TUN (device), -1);
+
+ return NM_DEVICE_TUN_GET_PRIVATE (device)->group;
+}
+
+/**
+ * nm_device_tun_get_pi:
+ * @device: a #NMDeviceTun
+ *
+ * Returns whether the #NMDeviceTun has the IFF_NO_PI flag.
+ *
+ * Returns: %TRUE if the device has the flag, %FALSE otherwise
+ *
+ * Since: 1.2
+ **/
+gboolean
+nm_device_tun_get_no_pi (NMDeviceTun *device)
+{
+ g_return_val_if_fail (NM_IS_DEVICE_TUN (device), FALSE);
+
+ return NM_DEVICE_TUN_GET_PRIVATE (device)->no_pi;
+}
+
+/**
+ * nm_device_tun_get_vnet_hdr:
+ * @device: a #NMDeviceTun
+ *
+ * Returns whether the #NMDeviceTun has the IFF_VNET_HDR flag.
+ *
+ * Returns: %TRUE if the device has the flag, %FALSE otherwise
+ *
+ * Since: 1.2
+ **/
+gboolean
+nm_device_tun_get_vnet_hdr (NMDeviceTun *device)
+{
+ g_return_val_if_fail (NM_IS_DEVICE_TUN (device), FALSE);
+
+ return NM_DEVICE_TUN_GET_PRIVATE (device)->vnet_hdr;
+}
+
+/**
+ * nm_device_tun_get_multi_queue:
+ * @device: a #NMDeviceTun
+ *
+ * Returns whether the #NMDeviceTun has the IFF_MULTI_QUEUE flag.
+ *
+ * Returns: %TRUE if the device doesn't have the flag, %FALSE otherwise
+ *
+ * Since: 1.2
+ **/
+gboolean
+nm_device_tun_get_multi_queue (NMDeviceTun *device)
+{
+ g_return_val_if_fail (NM_IS_DEVICE_TUN (device), FALSE);
+
+ return NM_DEVICE_TUN_GET_PRIVATE (device)->multi_queue;
+}
+
+static int
+tun_mode_from_string (const char *string)
+{
+ if (!g_strcmp0 (string, "tap"))
+ return NM_SETTING_TUN_MODE_TAP;
+ else
+ return NM_SETTING_TUN_MODE_TUN;
+}
+
+static gboolean
+connection_compatible (NMDevice *device, NMConnection *connection, GError **error)
+{
+ NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (device);
+ NMSettingTunMode mode;
+ NMSettingTun *s_tun;
+
+ if (!NM_DEVICE_CLASS (nm_device_tun_parent_class)->connection_compatible (device, connection, error))
+ return FALSE;
+
+ if (!nm_connection_is_type (connection, NM_SETTING_TUN_SETTING_NAME)) {
+ g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
+ _("The connection was not a tun connection."));
+ return FALSE;
+ }
+
+ s_tun = nm_connection_get_setting_tun (connection);
+
+ mode = tun_mode_from_string (priv->mode);
+ if (s_tun && mode != nm_setting_tun_get_mode (s_tun)) {
+ g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
+ _("The mode of the device and the connection didn't match"));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static GType
+get_setting_type (NMDevice *device)
+{
+ return NM_TYPE_SETTING_TUN;
+}
+
+static const char *
+get_hw_address (NMDevice *device)
+{
+ return nm_device_tun_get_hw_address (NM_DEVICE_TUN (device));
+}
+
+/***********************************************************/
+
+static void
+nm_device_tun_init (NMDeviceTun *device)
+{
+ _nm_device_set_device_type (NM_DEVICE (device), NM_DEVICE_TYPE_TUN);
+}
+
+static void
+init_dbus (NMObject *object)
+{
+ NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (object);
+ const NMPropertiesInfo property_info[] = {
+ { NM_DEVICE_TUN_HW_ADDRESS, &priv->hw_address },
+ { NM_DEVICE_TUN_MODE, &priv->mode },
+ { NM_DEVICE_TUN_OWNER, &priv->owner },
+ { NM_DEVICE_TUN_GROUP, &priv->group },
+ { NM_DEVICE_TUN_NO_PI, &priv->no_pi },
+ { NM_DEVICE_TUN_VNET_HDR, &priv->vnet_hdr },
+ { NM_DEVICE_TUN_MULTI_QUEUE, &priv->multi_queue },
+ { NULL },
+ };
+
+ NM_OBJECT_CLASS (nm_device_tun_parent_class)->init_dbus (object);
+
+ _nm_object_register_properties (object,
+ NM_DBUS_INTERFACE_DEVICE_TUN,
+ property_info);
+}
+
+static void
+finalize (GObject *object)
+{
+ NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (object);
+
+ g_free (priv->mode);
+
+ G_OBJECT_CLASS (nm_device_tun_parent_class)->finalize (object);
+}
+
+static void
+get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ NMDeviceTun *device = NM_DEVICE_TUN (object);
+
+ switch (prop_id) {
+ case PROP_HW_ADDRESS:
+ g_value_set_string (value, nm_device_tun_get_hw_address (device));
+ break;
+ case PROP_MODE:
+ g_value_set_string (value, nm_device_tun_get_mode (device));
+ break;
+ case PROP_OWNER:
+ g_value_set_int64 (value, nm_device_tun_get_owner (device));
+ break;
+ case PROP_GROUP:
+ g_value_set_int64 (value, nm_device_tun_get_group (device));
+ break;
+ case PROP_NO_PI:
+ g_value_set_boolean (value, nm_device_tun_get_no_pi (device));
+ break;
+ case PROP_VNET_HDR:
+ g_value_set_boolean (value, nm_device_tun_get_vnet_hdr (device));
+ break;
+ case PROP_MULTI_QUEUE:
+ g_value_set_boolean (value, nm_device_tun_get_multi_queue (device));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+nm_device_tun_class_init (NMDeviceTunClass *gre_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (gre_class);
+ NMObjectClass *nm_object_class = NM_OBJECT_CLASS (gre_class);
+ NMDeviceClass *device_class = NM_DEVICE_CLASS (gre_class);
+
+ g_type_class_add_private (gre_class, sizeof (NMDeviceTunPrivate));
+
+ _nm_object_class_add_interface (nm_object_class, NM_DBUS_INTERFACE_DEVICE_TUN);
+
+ /* 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;
+ device_class->get_hw_address = get_hw_address;
+
+ /* properties */
+
+ /**
+ * NMDeviceTun:hw-address:
+ *
+ * The hardware (MAC) address of the device.
+ *
+ * Since: 1.2
+ **/
+ g_object_class_install_property
+ (object_class, PROP_HW_ADDRESS,
+ g_param_spec_string (NM_DEVICE_TUN_HW_ADDRESS, "", "",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMDeviceTun:mode:
+ *
+ * The tunnel mode, either "tun" or "tap".
+ *
+ * Since: 1.2
+ **/
+ g_object_class_install_property
+ (object_class, PROP_MODE,
+ g_param_spec_string (NM_DEVICE_TUN_MODE, "", "",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMDeviceTun:owner:
+ *
+ * The uid of the tunnel owner, or -1 if it has no owner.
+ *
+ * Since: 1.2
+ **/
+ g_object_class_install_property
+ (object_class, PROP_OWNER,
+ g_param_spec_int64 (NM_DEVICE_TUN_OWNER, "", "",
+ -1, G_MAXUINT32, -1,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMDeviceTun:group:
+ *
+ * The gid of the tunnel group, or -1 if it has no owner.
+ *
+ * Since: 1.2
+ **/
+ g_object_class_install_property
+ (object_class, PROP_GROUP,
+ g_param_spec_int64 (NM_DEVICE_TUN_GROUP, "", "",
+ -1, G_MAXUINT32, -1,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMDeviceTun:no-pi:
+ *
+ * The tunnel's "TUN_NO_PI" flag; true if no protocol info is
+ * prepended to the tunnel packets.
+ *
+ * Since: 1.2
+ **/
+ g_object_class_install_property
+ (object_class, PROP_NO_PI,
+ g_param_spec_boolean (NM_DEVICE_TUN_NO_PI, "", "",
+ FALSE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMDeviceTun:vnet-hdr:
+ *
+ * The tunnel's "TUN_VNET_HDR" flag; true if the tunnel packets
+ * include a virtio network header.
+ *
+ * Since: 1.2
+ **/
+ g_object_class_install_property
+ (object_class, PROP_VNET_HDR,
+ g_param_spec_boolean (NM_DEVICE_TUN_VNET_HDR, "", "",
+ FALSE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * NMDeviceTun:multi-queue:
+ *
+ * The tunnel's "TUN_TAP_MQ" flag; true if callers can connect to
+ * the tap device multiple times, for multiple send/receive
+ * queues.
+ *
+ * Since: 1.2
+ **/
+ g_object_class_install_property
+ (object_class, PROP_MULTI_QUEUE,
+ g_param_spec_boolean (NM_DEVICE_TUN_MULTI_QUEUE, "", "",
+ FALSE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+}
diff --git a/libnm/nm-device-tun.h b/libnm/nm-device-tun.h
new file mode 100644
index 0000000000..b83e2b3fb9
--- /dev/null
+++ b/libnm/nm-device-tun.h
@@ -0,0 +1,78 @@
+/* -*- 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_TUN_H__
+#define __NM_DEVICE_TUN_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_TUN (nm_device_tun_get_type ())
+#define NM_DEVICE_TUN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_TUN, NMDeviceTun))
+#define NM_DEVICE_TUN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_TUN, NMDeviceTunClass))
+#define NM_IS_DEVICE_TUN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_TUN))
+#define NM_IS_DEVICE_TUN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_TUN))
+#define NM_DEVICE_TUN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_TUN, NMDeviceTunClass))
+
+#define NM_DEVICE_TUN_HW_ADDRESS "hw-address"
+#define NM_DEVICE_TUN_OWNER "owner"
+#define NM_DEVICE_TUN_GROUP "group"
+#define NM_DEVICE_TUN_MODE "mode"
+#define NM_DEVICE_TUN_NO_PI "no-pi"
+#define NM_DEVICE_TUN_VNET_HDR "vnet-hdr"
+#define NM_DEVICE_TUN_MULTI_QUEUE "multi-queue"
+
+struct _NMDeviceTun {
+ NMDevice parent;
+};
+
+typedef struct {
+ NMDeviceClass parent;
+
+ /*< private >*/
+ gpointer padding[4];
+} NMDeviceTunClass;
+
+NM_AVAILABLE_IN_1_2
+GType nm_device_tun_get_type (void);
+
+NM_AVAILABLE_IN_1_2
+const char * nm_device_tun_get_hw_address (NMDeviceTun *device);
+NM_AVAILABLE_IN_1_2
+const char * nm_device_tun_get_mode (NMDeviceTun *device);
+NM_AVAILABLE_IN_1_2
+gint64 nm_device_tun_get_owner (NMDeviceTun *device);
+NM_AVAILABLE_IN_1_2
+gint64 nm_device_tun_get_group (NMDeviceTun *device);
+NM_AVAILABLE_IN_1_2
+gboolean nm_device_tun_get_no_pi (NMDeviceTun *device);
+NM_AVAILABLE_IN_1_2
+gboolean nm_device_tun_get_vnet_hdr (NMDeviceTun *device);
+NM_AVAILABLE_IN_1_2
+gboolean nm_device_tun_get_multi_queue (NMDeviceTun *device);
+
+G_END_DECLS
+
+#endif /* __NM_DEVICE_TUN_H__ */
diff --git a/libnm/nm-device.c b/libnm/nm-device.c
index 2c354f2728..e6e5126f51 100644
--- a/libnm/nm-device.c
+++ b/libnm/nm-device.c
@@ -53,6 +53,7 @@
#include "nm-core-internal.h"
#include "nm-utils.h"
#include "nm-dbus-helpers.h"
+#include "nm-device-tun.h"
#include "nm-setting-connection.h"
#include "nm-macros-internal.h"
@@ -362,6 +363,8 @@ _nm_device_gtype_from_dtype (NMDeviceType dtype)
return NM_TYPE_DEVICE_VLAN;
case NM_DEVICE_TYPE_GENERIC:
return NM_TYPE_DEVICE_GENERIC;
+ case NM_DEVICE_TYPE_TUN:
+ return NM_TYPE_DEVICE_TUN;
default:
g_warning ("Unknown device type %d", dtype);
return G_TYPE_INVALID;
diff --git a/libnm/nm-types.h b/libnm/nm-types.h
index ee1ed643eb..334e4a17b7 100644
--- a/libnm/nm-types.h
+++ b/libnm/nm-types.h
@@ -40,6 +40,7 @@ typedef struct _NMDeviceInfiniband NMDeviceInfiniband;
typedef struct _NMDeviceModem NMDeviceModem;
typedef struct _NMDeviceOlpcMesh NMDeviceOlpcMesh;
typedef struct _NMDeviceTeam NMDeviceTeam;
+typedef struct _NMDeviceTun NMDeviceTun;
typedef struct _NMDeviceVlan NMDeviceVlan;
typedef struct _NMDeviceWifi NMDeviceWifi;
typedef struct _NMDeviceWimax NMDeviceWimax;
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 8bffd707a9..ca4b76ab1f 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -69,6 +69,7 @@ libnm-core/nm-setting-olpc-mesh.c
libnm-core/nm-setting-ppp.c
libnm-core/nm-setting-pppoe.c
libnm-core/nm-setting-team-port.c
+libnm-core/nm-setting-tun.c
libnm-core/nm-setting-vlan.c
libnm-core/nm-setting-vpn.c
libnm-core/nm-setting-wimax.c
@@ -116,6 +117,7 @@ libnm/nm-device-bridge.c
libnm/nm-device-bt.c
libnm/nm-device-ethernet.c
libnm/nm-device-generic.c
+libnm/nm-device-tun.c
libnm/nm-device-infiniband.c
libnm/nm-device-modem.c
libnm/nm-device-olpc-mesh.c
@@ -146,6 +148,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-tun.c
src/devices/nm-device-vlan.c
src/devices/team/nm-device-team.c
src/devices/wifi/nm-device-olpc-mesh.c
diff --git a/src/devices/nm-device-tun.c b/src/devices/nm-device-tun.c
index e103363361..978c1bace3 100644
--- a/src/devices/nm-device-tun.c
+++ b/src/devices/nm-device-tun.c
@@ -15,26 +15,29 @@
* 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.
+ * Copyright 2013 - 2015 Red Hat, Inc.
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
+#include <sys/types.h>
#include "nm-device-tun.h"
#include "nm-device-private.h"
#include "nm-default.h"
#include "nm-platform.h"
#include "nm-device-factory.h"
+#include "nm-setting-tun.h"
+#include "nm-core-internal.h"
#include "nmdbus-device-tun.h"
#include "nm-device-logging.h"
_LOG_DECLARE_SELF(NMDeviceTun);
-G_DEFINE_TYPE (NMDeviceTun, nm_device_tun, NM_TYPE_DEVICE_GENERIC)
+G_DEFINE_TYPE (NMDeviceTun, nm_device_tun, NM_TYPE_DEVICE)
#define NM_DEVICE_TUN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_TUN, NMDeviceTunPrivate))
@@ -47,7 +50,6 @@ enum {
PROP_0,
PROP_OWNER,
PROP_GROUP,
- PROP_FLAGS,
PROP_MODE,
PROP_NO_PI,
PROP_VNET_HDR,
@@ -81,6 +83,7 @@ reload_tun_properties (NMDeviceTun *self)
if (priv->props.multi_queue != props.multi_queue)
g_object_notify (object, NM_DEVICE_TUN_MULTI_QUEUE);
+ priv->mode = props.mode;
memcpy (&priv->props, &props, sizeof (NMPlatformTunProperties));
g_object_thaw_notify (object);
@@ -94,24 +97,172 @@ link_changed (NMDevice *device, NMPlatformLink *info)
reload_tun_properties (NM_DEVICE_TUN (device));
}
+static gboolean
+complete_connection (NMDevice *device,
+ NMConnection *connection,
+ const char *specific_object,
+ const GSList *existing_connections,
+ GError **error)
+{
+ NMSettingTun *s_tun;
+
+ nm_utils_complete_generic (connection,
+ NM_SETTING_TUN_SETTING_NAME,
+ existing_connections,
+ NULL,
+ _("TUN connection"),
+ NULL,
+ TRUE);
+
+ s_tun = nm_connection_get_setting_tun (connection);
+ if (!s_tun) {
+ g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION,
+ "A 'tun' setting is required.");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int
+tun_mode_from_string (const char *string)
+{
+ if (!g_strcmp0 (string, "tap"))
+ return NM_SETTING_TUN_MODE_TAP;
+ else
+ return NM_SETTING_TUN_MODE_TUN;
+}
+
static void
-setup (NMDevice *device, NMPlatformLink *plink)
+update_connection (NMDevice *device, NMConnection *connection)
{
NMDeviceTun *self = NM_DEVICE_TUN (device);
- NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self);
+ NMSettingTun *s_tun = nm_connection_get_setting_tun (connection);
+ NMPlatformTunProperties props;
+ NMSettingTunMode mode;
+ gint64 user, group;
+ char *str;
- NM_DEVICE_CLASS (nm_device_tun_parent_class)->setup (device, plink);
+ if (!s_tun) {
+ s_tun = (NMSettingTun *) nm_setting_tun_new ();
+ nm_connection_add_setting (connection, (NMSetting *) s_tun);
+ }
- priv->mode = NULL;
- if (plink->type == NM_LINK_TYPE_TUN)
- priv->mode = "tun";
- else if (plink->type == NM_LINK_TYPE_TAP)
- priv->mode = "tap";
- else
- g_assert_not_reached ();
- g_object_notify (G_OBJECT (device), NM_DEVICE_TUN_MODE);
+ if (!nm_platform_tun_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (device), &props)) {
+ _LOGW (LOGD_HW, "failed to get TUN interface info while updating connection.");
+ return;
+ }
+
+ mode = tun_mode_from_string (props.mode);
+
+ if (mode != nm_setting_tun_get_mode (s_tun))
+ g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_MODE, mode, NULL);
+
+ user = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_owner (s_tun), 10, 0, G_MAXINT32, -1);
+ group = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_group (s_tun), 10, 0, G_MAXINT32, -1);
+ if (props.owner != user) {
+ str = props.owner >= 0 ? g_strdup_printf ("%" G_GINT32_FORMAT, (gint32) props.owner) : NULL;
+ g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_OWNER, str, NULL);
+ g_free (str);
+ }
+
+ if (props.group != group) {
+ str = props.group >= 0 ? g_strdup_printf ("%" G_GINT32_FORMAT, (gint32) props.group) : NULL;
+ g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_GROUP, str, NULL);
+ g_free (str);
+ }
+
+ if ((!props.no_pi) != nm_setting_tun_get_pi (s_tun))
+ g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_PI, !props.no_pi, NULL);
+ if (props.vnet_hdr != nm_setting_tun_get_vnet_hdr (s_tun))
+ g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_VNET_HDR, props.vnet_hdr, NULL);
+ if (props.multi_queue != nm_setting_tun_get_multi_queue (s_tun))
+ g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_MULTI_QUEUE, props.multi_queue, NULL);
+}
+
+static gboolean
+create_and_realize (NMDevice *device,
+ NMConnection *connection,
+ NMDevice *parent,
+ NMPlatformLink *out_plink,
+ GError **error)
+{
+ const char *iface = nm_device_get_iface (device);
+ NMPlatformError plerr;
+ NMSettingTun *s_tun;
+ gint64 user, group;
+
+ s_tun = nm_connection_get_setting_tun (connection);
+ g_assert (s_tun);
+ g_assert (out_plink);
+
+ user = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_owner (s_tun), 10, 0, G_MAXINT32, -1);
+ group = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_group (s_tun), 10, 0, G_MAXINT32, -1);
+
+ plerr = nm_platform_tun_add (NM_PLATFORM_GET, iface,
+ nm_setting_tun_get_mode (s_tun) == NM_SETTING_TUN_MODE_TAP,
+ user, group,
+ nm_setting_tun_get_pi (s_tun),
+ nm_setting_tun_get_vnet_hdr (s_tun),
+ nm_setting_tun_get_multi_queue (s_tun),
+ 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 TUN/TAP interface '%s' for '%s': %s",
+ iface,
+ nm_connection_get_id (connection),
+ nm_platform_error_to_string (plerr));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+realize (NMDevice *device, NMPlatformLink *plink, GError **error)
+{
reload_tun_properties (NM_DEVICE_TUN (device));
+ return TRUE;
+}
+
+static gboolean
+check_connection_compatible (NMDevice *device, NMConnection *connection)
+{
+ NMDeviceTun *self = NM_DEVICE_TUN (device);
+ NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self);
+ NMSettingTunMode mode;
+ NMSettingTun *s_tun;
+ gint64 user, group;
+
+ reload_tun_properties (self);
+
+ if (!NM_DEVICE_CLASS (nm_device_tun_parent_class)->check_connection_compatible (device, connection))
+ return FALSE;
+
+ s_tun = nm_connection_get_setting_tun (connection);
+ if (!s_tun)
+ return FALSE;
+
+ mode = tun_mode_from_string (priv->mode);
+ if (mode != nm_setting_tun_get_mode (s_tun))
+ return FALSE;
+
+ user = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_owner (s_tun), 10, 0, G_MAXINT32, -1);
+ group = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_group (s_tun), 10, 0, G_MAXINT32, -1);
+
+ if (user != priv->props.owner)
+ return FALSE;
+ if (group != priv->props.group)
+ return FALSE;
+ if (nm_setting_tun_get_pi (s_tun) == priv->props.no_pi)
+ return FALSE;
+ if (nm_setting_tun_get_vnet_hdr (s_tun) != priv->props.vnet_hdr)
+ return FALSE;
+ if (nm_setting_tun_get_multi_queue (s_tun) != priv->props.multi_queue)
+ return FALSE;
+
+ return TRUE;
}
/**************************************************************/
@@ -191,8 +342,14 @@ nm_device_tun_class_init (NMDeviceTunClass *klass)
object_class->get_property = get_property;
object_class->set_property = set_property;
+ device_class->connection_type = NM_SETTING_TUN_SETTING_NAME;
+
device_class->link_changed = link_changed;
- device_class->setup = setup;
+ device_class->complete_connection = complete_connection;
+ device_class->check_connection_compatible = check_connection_compatible;
+ device_class->create_and_realize = create_and_realize;
+ device_class->realize = realize;
+ device_class->update_connection = update_connection;
/* properties */
g_object_class_install_property
@@ -252,12 +409,13 @@ create_device (NMDeviceFactory *factory,
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_TUN,
NM_DEVICE_IFACE, iface,
NM_DEVICE_TYPE_DESC, "Tun",
- NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC,
+ NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_TUN,
NULL);
}
NM_DEVICE_FACTORY_DEFINE_INTERNAL (TUN, Tun, tun,
- NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_TUN, NM_LINK_TYPE_TAP),
+ NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_TUN, NM_LINK_TYPE_TAP)
+ NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_TUN_SETTING_NAME),
factory_iface->create_device = create_device;
)
diff --git a/src/devices/nm-device-tun.h b/src/devices/nm-device-tun.h
index b253d68e45..32dcfd47b5 100644
--- a/src/devices/nm-device-tun.h
+++ b/src/devices/nm-device-tun.h
@@ -39,8 +39,8 @@ G_BEGIN_DECLS
#define NM_DEVICE_TUN_VNET_HDR "vnet-hdr"
#define NM_DEVICE_TUN_MULTI_QUEUE "multi-queue"
-typedef NMDeviceGeneric NMDeviceTun;
-typedef NMDeviceGenericClass NMDeviceTunClass;
+typedef NMDevice NMDeviceTun;
+typedef NMDeviceClass NMDeviceTunClass;
GType nm_device_tun_get_type (void);
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index f9e0475c2f..07b7b072bf 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -754,6 +754,8 @@ nm_device_get_priority (NMDevice *self)
return 400;
case NM_DEVICE_TYPE_BRIDGE:
return 425;
+ case NM_DEVICE_TYPE_TUN:
+ return 450;
case NM_DEVICE_TYPE_WIFI:
return 600;
case NM_DEVICE_TYPE_OLPC_MESH:
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index 2e0c871df3..b7506e7d1c 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -22,6 +22,7 @@
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
+#include <sys/ioctl.h>
#include <fcntl.h>
#include <dlfcn.h>
#include <netinet/icmp6.h>
@@ -4235,6 +4236,66 @@ link_vlan_change (NMPlatform *platform,
return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS;
}
+static int
+tun_add (NMPlatform *platform, const char *name, gboolean tap,
+ gint64 owner, gint64 group, gboolean pi, gboolean vnet_hdr,
+ gboolean multi_queue, NMPlatformLink *out_link)
+{
+ const NMPObject *obj;
+ struct ifreq ifr = { };
+ int fd;
+
+ _LOGD ("link: add %s '%s' owner %" G_GINT64_FORMAT " group %" G_GINT64_FORMAT,
+ tap ? "tap" : "tun", name, owner, group);
+
+ fd = open ("/dev/net/tun", O_RDWR);
+ if (fd < 0)
+ return FALSE;
+
+ strncpy (ifr.ifr_name, name, IFNAMSIZ);
+ ifr.ifr_flags = tap ? IFF_TAP : IFF_TUN;
+
+ if (!pi)
+ ifr.ifr_flags |= IFF_NO_PI;
+ if (vnet_hdr)
+ ifr.ifr_flags |= IFF_VNET_HDR;
+ if (multi_queue)
+ ifr.ifr_flags |= NM_IFF_MULTI_QUEUE;
+
+ if (ioctl (fd, TUNSETIFF, &ifr)) {
+ close (fd);
+ return FALSE;
+ }
+
+ if (owner >= 0 && owner < G_MAXINT32) {
+ if (ioctl (fd, TUNSETOWNER, (uid_t) owner)) {
+ close (fd);
+ return FALSE;
+ }
+ }
+
+ if (group >= 0 && group < G_MAXINT32) {
+ if (ioctl (fd, TUNSETGROUP, (gid_t) group)) {
+ close (fd);
+ return FALSE;
+ }
+ }
+
+ if (ioctl (fd, TUNSETPERSIST, 1)) {
+ close (fd);
+ return FALSE;
+ }
+ do_request_link (platform, 0, name, TRUE);
+ obj = nmp_cache_lookup_link_full (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache,
+ 0, name, FALSE,
+ tap ? NM_LINK_TYPE_TAP : NM_LINK_TYPE_TUN,
+ NULL, NULL);
+ if (out_link && obj)
+ *out_link = obj->link;
+
+ return !!obj;
+}
+
static gboolean
link_enslave (NMPlatform *platform, int master, int slave)
{
@@ -5444,6 +5505,8 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
platform_class->vlan_add = vlan_add;
platform_class->link_vlan_change = link_vlan_change;
+ platform_class->tun_add = tun_add;
+
platform_class->infiniband_partition_add = infiniband_partition_add;
platform_class->wifi_get_capabilities = wifi_get_capabilities;
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index 5124db6147..6988d1a5f4 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -1531,6 +1531,44 @@ nm_platform_vlan_add (NMPlatform *self,
return NM_PLATFORM_ERROR_SUCCESS;
}
+/**
+ * nm_platform_tun_add:
+ * @self: platform instance
+ * @name: new interface name
+ * @tap: whether the interface is a TAP
+ * @owner: interface owner or -1
+ * @group: interface group or -1
+ * @pi: whether to clear the IFF_NO_PI flag
+ * @vnet_hdr: whether to set the IFF_VNET_HDR flag
+ * @multi_queue: whether to set the IFF_MULTI_QUEUE flag
+ * @out_link: on success, the link object
+ *
+ * Create a TUN or TAP interface.
+ */
+NMPlatformError
+nm_platform_tun_add (NMPlatform *self, const char *name, gboolean tap,
+ gint64 owner, gint64 group, gboolean pi, gboolean vnet_hdr,
+ gboolean multi_queue, NMPlatformLink *out_link)
+{
+ NMPlatformError plerr;
+
+ _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG);
+
+ g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG);
+ g_return_val_if_fail (klass->tun_add, NM_PLATFORM_ERROR_BUG);
+
+ plerr = _link_add_check_existing (self, name, tap ? NM_LINK_TYPE_TAP : NM_LINK_TYPE_TUN, out_link);
+ if (plerr != NM_PLATFORM_ERROR_SUCCESS)
+ return plerr;
+
+ _LOGD ("link: adding %s '%s' owner %" G_GINT64_FORMAT " group %" G_GINT64_FORMAT,
+ tap ? "tap" : "tun", name, owner, group);
+ if (!klass->tun_add (self, name, tap, owner, group, pi, vnet_hdr, multi_queue, out_link))
+ return NM_PLATFORM_ERROR_UNSPECIFIED;
+ return NM_PLATFORM_ERROR_SUCCESS;
+}
+
+
gboolean
nm_platform_master_set_option (NMPlatform *self, int ifindex, const char *option, const char *value)
{
@@ -1844,13 +1882,10 @@ nm_platform_tun_get_properties_ifname (NMPlatform *self, const char *ifname, NMP
flags = _nm_utils_ascii_str_to_int64 (val, 16, 0, G_MAXINT64, 0);
if (!errno) {
-#ifndef IFF_MULTI_QUEUE
- const int IFF_MULTI_QUEUE = 0x0100;
-#endif
props->mode = ((flags & (IFF_TUN | IFF_TAP)) == IFF_TUN) ? "tun" : "tap";
props->no_pi = !!(flags & IFF_NO_PI);
props->vnet_hdr = !!(flags & IFF_VNET_HDR);
- props->multi_queue = !!(flags & IFF_MULTI_QUEUE);
+ props->multi_queue = !!(flags & NM_IFF_MULTI_QUEUE);
} else
success = FALSE;
g_free (val);
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index 42c3b79390..e64a9bf9e0 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -61,6 +61,8 @@ typedef struct _NMPlatform NMPlatform;
#define NM_IN6_ADDR_GEN_MODE_NONE 1 /* IN6_ADDR_GEN_MODE_NONE */
#define NM_IN6_ADDR_GEN_MODE_STABLE_PRIVACY 2 /* IN6_ADDR_GEN_MODE_STABLE_PRIVACY */
+#define NM_IFF_MULTI_QUEUE 0x0100 /* IFF_MULTI_QUEUE */
+
typedef enum { /*< skip >*/
/* dummy value, to enforce that the enum type is signed and has a size
@@ -525,6 +527,9 @@ typedef struct {
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,
+ gboolean vnet_hdr, gboolean multi_queue, NMPlatformLink *out_link);
+
gboolean (*wifi_get_capabilities) (NMPlatform *, int ifindex, NMDeviceWifiCapabilities *caps);
gboolean (*wifi_get_bssid) (NMPlatform *, int ifindex, guint8 *bssid);
GByteArray *(*wifi_get_ssid) (NMPlatform *, int ifindex);
@@ -728,6 +733,9 @@ gboolean nm_platform_link_vlan_change (NMPlatform *self,
gsize n_egress_map);
+NMPlatformError nm_platform_tun_add (NMPlatform *self, const char *name, gboolean tap, gint64 owner, gint64 group, gboolean pi,
+ gboolean vnet_hdr, gboolean multi_queue, NMPlatformLink *out_link);
+
NMPlatformError nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key, NMPlatformLink *out_link);
gboolean nm_platform_infiniband_get_properties (NMPlatform *self, int ifindex, int *parent, int *p_key, const char **mode);