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 ' - 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 ]\n" " [encapsulation vcmux|llc]\n\n" + " tun: mode tun|tap\n" + " [owner ]\n" + " [group ]\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/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 }, };