diff options
author | Beniamino Galvani <bgalvani@redhat.com> | 2015-11-25 11:53:37 +0100 |
---|---|---|
committer | Beniamino Galvani <bgalvani@redhat.com> | 2015-11-25 11:53:37 +0100 |
commit | 123d0ba9b8c92ce00d2a0b2f98c5f329353e70d1 (patch) | |
tree | 4fc5e55aaf4f0038fd78cf547f47f7045212733b | |
parent | fa96bade799b274eaa1b94e4dd04bdac26f54136 (diff) | |
parent | c223e811f119d88222482432c0a700fa28630adb (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
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); |