From 00e0fffea221705393637d038dc61ccbc15c3585 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 21 Apr 2015 16:53:36 +0200 Subject: [PATCH 1/5] cli: process slave parameters after the rest of the settings are set up This separates setup of the master & slave type and addition of the wired settings for "bond-slave", "bridge-slave" and "team-slave" connection types from processing of slave type specific options. A follow-up commit will make it possible to specify master (and slave type) for any connection, not relying on "-slave" types. --- clients/cli/connections.c | 383 +++++++++++++++++++------------------- 1 file changed, 190 insertions(+), 193 deletions(-) diff --git a/clients/cli/connections.c b/clients/cli/connections.c index 796a8947ca..ed78d14c45 100644 --- a/clients/cli/connections.c +++ b/clients/cli/connections.c @@ -47,9 +47,7 @@ /* define some other prompts */ #define PROMPT_CON_TYPE _("Connection type: ") #define PROMPT_VPN_TYPE _("VPN type: ") -#define PROMPT_BOND_MASTER _("Bond master: ") -#define PROMPT_TEAM_MASTER _("Team master: ") -#define PROMPT_BRIDGE_MASTER _("Bridge master: ") +#define PROMPT_MASTER _("Master: ") #define PROMPT_CONNECTION _("Connection (name, UUID, or path): ") #define PROMPT_CONNECTIONS _("Connection(s) (name, UUID, or path): ") #define PROMPT_ACTIVE_CONNECTIONS _("Connection(s) (name, UUID, path or apath): ") @@ -4284,6 +4282,54 @@ finish: return success; } +static gboolean +complete_slave (NMSettingConnection *s_con, + const GPtrArray *all_connections, + const char *slave_type, + const char *master, + const char *type, + gboolean ask, + GError **error) +{ + char *master_ask = NULL; + const char *checked_master = NULL; + + if (type) + g_print (_("Warning: 'type' is currently ignored. " + "We only support ethernet slaves for now.\n")); + + if (nm_setting_connection_get_master (s_con)) { + /* Master already set. */ + if (master) { + g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("Error: redundant 'master' option.")); + return FALSE; + } + return TRUE; + } + + if (!master && ask) + master = master_ask = nmc_readline (PROMPT_MASTER); + if (!master) { + g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("Error: 'master' is required.")); + return FALSE; + } + /* Verify master argument */ + checked_master = verify_master_for_slave (all_connections, master, slave_type); + if (!checked_master) + g_print (_("Warning: master='%s' doesn't refer to any existing profile.\n"), master); + + /* Change properties in 'connection' setting */ + g_object_set (s_con, + NM_SETTING_CONNECTION_MASTER, checked_master ? checked_master : _strip_master_prefix (master, NULL), + NULL); + + g_free (master_ask); + + return TRUE; +} + static gboolean complete_connection_by_type (NMConnection *connection, const char *con_type, @@ -4311,6 +4357,7 @@ complete_connection_by_type (NMConnection *connection, NMSettingBridgePort *s_bridge_port; NMSettingVpn *s_vpn; NMSettingOlpcMesh *s_olpc_mesh; + const char *slave_type; g_return_val_if_fail (error == NULL || *error == NULL, FALSE); @@ -5015,41 +5062,10 @@ cleanup_bond: return FALSE; } else if (!strcmp (con_type, "bond-slave")) { - /* Build up the settings required for 'bond-slave' */ - const char *master = NULL; - char *master_ask = NULL; - const char *checked_master = NULL; - const char *type = NULL; - nmc_arg_t exp_args[] = { {"master", TRUE, &master, !ask}, - {"type", TRUE, &type, FALSE}, - {NULL} }; - - /* Set global variables for use in TAB completion */ - nmc_tab_completion.con_type = NM_SETTING_BOND_SETTING_NAME; - - if (!nmc_parse_args (exp_args, TRUE, &argc, &argv, error)) - return FALSE; - - if (!master && ask) - master = master_ask = nmc_readline (PROMPT_BOND_MASTER); - if (!master) { - g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, - _("Error: 'master' is required.")); - return FALSE; - } - /* Verify master argument */ - checked_master = verify_master_for_slave (all_connections, master, NM_SETTING_BOND_SETTING_NAME); - if (!checked_master) - g_print (_("Warning: master='%s' doesn't refer to any existing profile.\n"), master); - - if (type) - g_print (_("Warning: 'type' is currently ignored. " - "We only support ethernet slaves for now.\n")); /* Change properties in 'connection' setting */ g_object_set (s_con, NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, - NM_SETTING_CONNECTION_MASTER, checked_master ? checked_master : _strip_master_prefix (master, NULL), NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BOND_SETTING_NAME, NULL); @@ -5057,8 +5073,6 @@ cleanup_bond: s_wired = (NMSettingWired *) nm_setting_wired_new (); nm_connection_add_setting (connection, NM_SETTING (s_wired)); - g_free (master_ask); - } else if (!strcmp (con_type, NM_SETTING_TEAM_SETTING_NAME)) { /* Build up the settings required for 'team' */ gboolean success = FALSE; @@ -5108,63 +5122,10 @@ cleanup_team: return FALSE; } else if (!strcmp (con_type, "team-slave")) { - /* Build up the settings required for 'team-slave' */ - gboolean success = FALSE; - const char *master = NULL; - char *master_ask = NULL; - const char *checked_master = NULL; - const char *type = NULL; - const char *config_c = NULL; - char *config = NULL; - char *json = NULL; - nmc_arg_t exp_args[] = { {"master", TRUE, &master, !ask}, - {"type", TRUE, &type, FALSE}, - {"config", TRUE, &config_c, FALSE}, - {NULL} }; - - /* Set global variables for use in TAB completion */ - nmc_tab_completion.con_type = NM_SETTING_TEAM_SETTING_NAME; - - if (!nmc_parse_args (exp_args, TRUE, &argc, &argv, error)) - return FALSE; - - if (!master && ask) - master = master_ask = nmc_readline (PROMPT_TEAM_MASTER); - if (!master) { - g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, - _("Error: 'master' is required.")); - return FALSE; - } - /* Verify master argument */ - checked_master = verify_master_for_slave (all_connections, master, NM_SETTING_TEAM_SETTING_NAME); - if (!checked_master) - g_print (_("Warning: master='%s' doesn't refer to any existing profile.\n"), master); - - /* Also ask for all optional arguments if '--ask' is specified. */ - config = g_strdup (config_c); - if (ask) - do_questionnaire_team_slave (&config); - - if (type) - g_print (_("Warning: 'type' is currently ignored. " - "We only support ethernet slaves for now.\n")); - - /* Add 'team-port' setting */ - s_team_port = (NMSettingTeamPort *) nm_setting_team_port_new (); - nm_connection_add_setting (connection, NM_SETTING (s_team_port)); - - if (!nmc_team_check_config (config, &json, error)) { - g_prefix_error (error, _("Error: ")); - goto cleanup_team_slave; - } - - /* Set team-port options */ - g_object_set (s_team_port, NM_SETTING_TEAM_PORT_CONFIG, json, NULL); /* Change properties in 'connection' setting */ g_object_set (s_con, NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, - NM_SETTING_CONNECTION_MASTER, checked_master ? checked_master : _strip_master_prefix (master, NULL), NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_TEAM_SETTING_NAME, NULL); @@ -5172,14 +5133,6 @@ cleanup_team: s_wired = (NMSettingWired *) nm_setting_wired_new (); nm_connection_add_setting (connection, NM_SETTING (s_wired)); - success = TRUE; -cleanup_team_slave: - g_free (master_ask); - g_free (config); - g_free (json); - if (!success) - return FALSE; - } else if (!strcmp (con_type, NM_SETTING_BRIDGE_SETTING_NAME)) { /* Build up the settings required for 'bridge' */ gboolean success = FALSE; @@ -5319,83 +5272,10 @@ cleanup_bridge: return FALSE; } else if (!strcmp (con_type, "bridge-slave")) { - /* Build up the settings required for 'bridge-slave' */ - gboolean success = FALSE; - const char *master = NULL; - char *master_ask = NULL; - const char *checked_master = NULL; - const char *type = NULL; - const char *priority_c = NULL; - char *priority = NULL; - const char *path_cost_c = NULL; - char *path_cost = NULL; - const char *hairpin_c = NULL; - char *hairpin = NULL; - unsigned long prio_int, path_cost_int; - gboolean hairpin_bool; - nmc_arg_t exp_args[] = { {"master", TRUE, &master, !ask}, - {"type", TRUE, &type, FALSE}, - {"priority", TRUE, &priority_c, FALSE}, - {"path-cost", TRUE, &path_cost_c, FALSE}, - {"hairpin", TRUE, &hairpin_c, FALSE}, - {NULL} }; - - /* Set global variables for use in TAB completion */ - nmc_tab_completion.con_type = NM_SETTING_BRIDGE_SETTING_NAME; - - if (!nmc_parse_args (exp_args, TRUE, &argc, &argv, error)) - return FALSE; - - if (!master && ask) - master = master_ask = nmc_readline (PROMPT_BRIDGE_MASTER); - if (!master) { - g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, - _("Error: 'master' is required.")); - return FALSE; - } - /* Verify master argument */ - checked_master = verify_master_for_slave (all_connections, master, NM_SETTING_BRIDGE_SETTING_NAME); - if (!checked_master) - g_print (_("Warning: master='%s' doesn't refer to any existing profile.\n"), master); - - if (type) - g_print (_("Warning: 'type' is currently ignored. " - "We only support ethernet slaves for now.\n")); - - /* Add 'bridge-port' setting */ - /* Must be done *before* bridge_prop_string_to_uint() so that the type is known */ - s_bridge_port = (NMSettingBridgePort *) nm_setting_bridge_port_new (); - nm_connection_add_setting (connection, NM_SETTING (s_bridge_port)); - - /* Also ask for all optional arguments if '--ask' is specified. */ - priority = g_strdup (priority_c); - path_cost = g_strdup (path_cost_c); - hairpin = g_strdup (hairpin_c); - if (ask) - do_questionnaire_bridge_slave (&priority, &path_cost, &hairpin); - - if (priority) - if (!bridge_prop_string_to_uint (priority, "priority", NM_TYPE_SETTING_BRIDGE_PORT, - NM_SETTING_BRIDGE_PORT_PRIORITY, &prio_int, error)) - goto cleanup_bridge_slave; - if (path_cost) - if (!bridge_prop_string_to_uint (path_cost, "path-cost", NM_TYPE_SETTING_BRIDGE_PORT, - NM_SETTING_BRIDGE_PORT_PATH_COST, &path_cost_int, error)) - goto cleanup_bridge_slave; - if (hairpin) { - GError *tmp_err = NULL; - if (!nmc_string_to_bool (hairpin, &hairpin_bool, &tmp_err)) { - g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, - _("Error: 'hairpin': %s."), tmp_err->message); - g_clear_error (&tmp_err); - goto cleanup_bridge_slave; - } - } /* Change properties in 'connection' setting */ g_object_set (s_con, NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, - NM_SETTING_CONNECTION_MASTER, checked_master ? checked_master : _strip_master_prefix (master, NULL), NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BRIDGE_SETTING_NAME, NULL); @@ -5403,22 +5283,6 @@ cleanup_bridge: s_wired = (NMSettingWired *) nm_setting_wired_new (); nm_connection_add_setting (connection, NM_SETTING (s_wired)); - if (priority) - g_object_set (s_bridge_port, NM_SETTING_BRIDGE_PORT_PRIORITY, prio_int, NULL); - if (path_cost) - g_object_set (s_bridge_port, NM_SETTING_BRIDGE_PORT_PATH_COST, path_cost_int, NULL); - if (hairpin) - g_object_set (s_bridge_port, NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, hairpin_bool, NULL); - - success = TRUE; -cleanup_bridge_slave: - g_free (master_ask); - g_free (priority); - g_free (path_cost); - g_free (hairpin); - if (!success) - return FALSE; - } else if (!strcmp (con_type, NM_SETTING_VPN_SETTING_NAME)) { /* Build up the settings required for 'vpn' */ gboolean success = FALSE; @@ -5548,11 +5412,146 @@ cleanup_olpc: return FALSE; } - /* Read and add IP configuration */ - if ( strcmp (con_type, "bond-slave") != 0 - && strcmp (con_type, "team-slave") != 0 - && strcmp (con_type, "bridge-slave") != 0) { + slave_type = nm_setting_connection_get_slave_type (s_con); + if (slave_type) { + /* Set global variables for use in TAB completion */ + nmc_tab_completion.con_type = (char *)slave_type; + + if (!strcmp (slave_type, NM_SETTING_TEAM_SETTING_NAME)) { + /* Build up the settings required for 'team-slave' */ + gboolean success = FALSE; + const char *master = NULL; + char *master_ask = NULL; + const char *type = NULL; + const char *config_c = NULL; + char *config = NULL; + char *json = NULL; + nmc_arg_t exp_args[] = { {"master", TRUE, &master, FALSE}, + {"type", TRUE, &type, FALSE}, + {"config", TRUE, &config_c, FALSE}, + {NULL} }; + + if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error)) + return FALSE; + + if (!complete_slave (s_con, all_connections, slave_type, master, type, ask, error)) + return FALSE; + + /* Also ask for all optional arguments if '--ask' is specified. */ + config = g_strdup (config_c); + if (ask) + do_questionnaire_team_slave (&config); + + /* Add 'team-port' setting */ + s_team_port = (NMSettingTeamPort *) nm_setting_team_port_new (); + nm_connection_add_setting (connection, NM_SETTING (s_team_port)); + + if (!nmc_team_check_config (config, &json, error)) { + g_prefix_error (error, _("Error: ")); + goto cleanup_team_slave; + } + + /* Set team-port options */ + g_object_set (s_team_port, NM_SETTING_TEAM_PORT_CONFIG, json, NULL); + + success = TRUE; +cleanup_team_slave: + g_free (master_ask); + g_free (config); + g_free (json); + if (!success) + return FALSE; + + } else if (!strcmp (slave_type, NM_SETTING_BRIDGE_SETTING_NAME)) { + /* Build up the settings required for 'bridge-slave' */ + gboolean success = FALSE; + const char *master = NULL; + char *master_ask = NULL; + const char *type = NULL; + const char *priority_c = NULL; + char *priority = NULL; + const char *path_cost_c = NULL; + char *path_cost = NULL; + const char *hairpin_c = NULL; + char *hairpin = NULL; + unsigned long prio_int, path_cost_int; + gboolean hairpin_bool; + nmc_arg_t exp_args[] = { {"master", TRUE, &master, FALSE}, + {"type", TRUE, &type, FALSE}, + {"priority", TRUE, &priority_c, FALSE}, + {"path-cost", TRUE, &path_cost_c, FALSE}, + {"hairpin", TRUE, &hairpin_c, FALSE}, + {NULL} }; + + if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error)) + return FALSE; + + if (!complete_slave (s_con, all_connections, slave_type, master, type, ask, error)) + return FALSE; + + /* Add 'bridge-port' setting */ + /* Must be done *before* bridge_prop_string_to_uint() so that the type is known */ + s_bridge_port = (NMSettingBridgePort *) nm_setting_bridge_port_new (); + nm_connection_add_setting (connection, NM_SETTING (s_bridge_port)); + + /* Also ask for all optional arguments if '--ask' is specified. */ + priority = g_strdup (priority_c); + path_cost = g_strdup (path_cost_c); + hairpin = g_strdup (hairpin_c); + if (ask) + do_questionnaire_bridge_slave (&priority, &path_cost, &hairpin); + + if (priority) + if (!bridge_prop_string_to_uint (priority, "priority", NM_TYPE_SETTING_BRIDGE_PORT, + NM_SETTING_BRIDGE_PORT_PRIORITY, &prio_int, error)) + goto cleanup_bridge_slave; + if (path_cost) + if (!bridge_prop_string_to_uint (path_cost, "path-cost", NM_TYPE_SETTING_BRIDGE_PORT, + NM_SETTING_BRIDGE_PORT_PATH_COST, &path_cost_int, error)) + goto cleanup_bridge_slave; + if (hairpin) { + GError *tmp_err = NULL; + if (!nmc_string_to_bool (hairpin, &hairpin_bool, &tmp_err)) { + g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("Error: 'hairpin': %s."), tmp_err->message); + g_clear_error (&tmp_err); + goto cleanup_bridge_slave; + } + } + + if (priority) + g_object_set (s_bridge_port, NM_SETTING_BRIDGE_PORT_PRIORITY, prio_int, NULL); + if (path_cost) + g_object_set (s_bridge_port, NM_SETTING_BRIDGE_PORT_PATH_COST, path_cost_int, NULL); + if (hairpin) + g_object_set (s_bridge_port, NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, hairpin_bool, NULL); + + success = TRUE; +cleanup_bridge_slave: + g_free (master_ask); + g_free (priority); + g_free (path_cost); + g_free (hairpin); + if (!success) + return FALSE; + } else { + /* Slave types without any specific settings ('bond-slave') */ + const char *master = NULL; + const char *type = NULL; + nmc_arg_t exp_args[] = { {"master", TRUE, &master, FALSE}, + {"type", TRUE, &type, FALSE}, + {NULL} }; + + if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error)) + return FALSE; + + if (!complete_slave (s_con, all_connections, slave_type, master, type, ask, error)) + return FALSE; + } + + } else { + /* Read and add IP configuration */ NMIPAddress *ip4addr = NULL, *ip6addr = NULL; const char *ip4 = NULL, *gw4 = NULL, *ip6 = NULL, *gw6 = NULL; nmc_arg_t exp_args[] = { {"ip4", TRUE, &ip4, FALSE}, {"gw4", TRUE, &gw4, FALSE}, @@ -5854,9 +5853,7 @@ nmcli_con_add_tab_completion (const char *text, int start, int end) generator_func = gen_connection_types; else if (g_strcmp0 (rl_prompt, PROMPT_VPN_TYPE) == 0) generator_func = gen_func_vpn_types; - else if ( g_strcmp0 (rl_prompt, PROMPT_BOND_MASTER) == 0 - || g_strcmp0 (rl_prompt, PROMPT_TEAM_MASTER) == 0 - || g_strcmp0 (rl_prompt, PROMPT_BRIDGE_MASTER) == 0) + else if (g_strcmp0 (rl_prompt, PROMPT_MASTER) == 0) generator_func = gen_func_master_ifnames; else if ( g_str_has_suffix (rl_prompt, prompt_yes_no (TRUE, NULL)) || g_str_has_suffix (rl_prompt, prompt_yes_no (TRUE, ":")) From 07912b6e79cd9e12321f49ccb623590f230c331c Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 21 Apr 2015 17:29:34 +0200 Subject: [PATCH 2/5] cli: remove an extraneous _strip_master_prefix() call verify_master_for_slave() already ensures the returned string has no prefix. --- clients/cli/connections.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/cli/connections.c b/clients/cli/connections.c index ed78d14c45..da65afc0a5 100644 --- a/clients/cli/connections.c +++ b/clients/cli/connections.c @@ -4322,7 +4322,7 @@ complete_slave (NMSettingConnection *s_con, /* Change properties in 'connection' setting */ g_object_set (s_con, - NM_SETTING_CONNECTION_MASTER, checked_master ? checked_master : _strip_master_prefix (master, NULL), + NM_SETTING_CONNECTION_MASTER, checked_master, NULL); g_free (master_ask); From aa12bb353bca34be1bea0625c8e6e7715f24deb3 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 21 Apr 2015 17:26:35 +0200 Subject: [PATCH 3/5] cli: discover slave type for a connection with a master Rename verify_master_for_slave(), since it does a lot more than just verifying the master setting. Make the type check optional and return the type of the connection that matched. This makes it possible to omit setting the slave type on a command line and still get the slave type right. --- clients/cli/connections.c | 44 +++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/clients/cli/connections.c b/clients/cli/connections.c index da65afc0a5..2a7d2669f7 100644 --- a/clients/cli/connections.c +++ b/clients/cli/connections.c @@ -3152,27 +3152,31 @@ _strip_master_prefix (const char *master, const char *(**func)(NMConnection *)) return master; } -/* verify_master_for_slave: +/* normalized_master_for_slave: * @connections: list af all connections * @master: UUID, ifname or ID of the master connection - * @type: virtual connection type (bond, team, bridge, ...) + * @type: virtual connection type (bond, team, bridge, ...) or %NULL + * @out_type: type of the connection that matched * - * Check whether master is a valid interface name, UUID or ID of some @type connection. + * Check whether master is a valid interface name, UUID or ID of some connection, + * possibly of a specified @type. * First UUID and ifname are checked. If they don't match, ID is checked * and replaced by UUID on a match. * * Returns: identifier of master connection if found, %NULL otherwise */ static const char * -verify_master_for_slave (const GPtrArray *connections, - const char *master, - const char *type) +normalized_master_for_slave (const GPtrArray *connections, + const char *master, + const char *type, + const char **out_type) { NMConnection *connection; NMSettingConnection *s_con; - const char *con_type, *id, *uuid, *ifname; + const char *con_type = NULL, *id, *uuid, *ifname; int i; const char *found_by_id = NULL; + const char *out_type_by_id = NULL; const char *out_master = NULL; const char *(*func) (NMConnection *) = NULL; @@ -3185,11 +3189,12 @@ verify_master_for_slave (const GPtrArray *connections, s_con = nm_connection_get_setting_connection (connection); g_assert (s_con); con_type = nm_setting_connection_get_connection_type (s_con); - if (g_strcmp0 (con_type, type) != 0) + if (type && g_strcmp0 (con_type, type) != 0) continue; if (func) { /* There was a prefix; only compare to that type. */ if (g_strcmp0 (master, func (connection)) == 0) { + *out_type = con_type; if (func == nm_connection_get_id) out_master = nm_connection_get_uuid (connection); else @@ -3203,13 +3208,30 @@ verify_master_for_slave (const GPtrArray *connections, if ( g_strcmp0 (master, uuid) == 0 || g_strcmp0 (master, ifname) == 0) { out_master = master; + *out_type = con_type; break; } - if (!found_by_id && g_strcmp0 (master, id) == 0) + if (!found_by_id && g_strcmp0 (master, id) == 0) { + out_type_by_id = con_type; found_by_id = uuid; + } } } - return out_master ? out_master : found_by_id; + + if (!out_master) { + out_master = found_by_id; + if (out_type) + *out_type = out_type_by_id; + } + + if (!out_master) { + g_print (_("Warning: master='%s' doesn't refer to any existing profile.\n"), master); + out_master = master; + if (out_type) + *out_type = type; + } + + return out_master; } static gboolean @@ -4316,7 +4338,7 @@ complete_slave (NMSettingConnection *s_con, return FALSE; } /* Verify master argument */ - checked_master = verify_master_for_slave (all_connections, master, slave_type); + checked_master = normalized_master_for_slave (all_connections, master, slave_type, NULL); if (!checked_master) g_print (_("Warning: master='%s' doesn't refer to any existing profile.\n"), master); From 1375d9c13ad6062f2c84089242f0dcfac1bd8e07 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 8 Jun 2015 15:18:06 +0200 Subject: [PATCH 4/5] cli: add master option to "nmcli c add" --- clients/cli/connections.c | 31 +++++++++++++++++++++++------ man/nmcli-examples.xml | 12 +++++------ man/nmcli.1.in | 42 +++++++++++++++++++++++++++++---------- 3 files changed, 63 insertions(+), 22 deletions(-) diff --git a/clients/cli/connections.c b/clients/cli/connections.c index 2a7d2669f7..cfb6d81bc4 100644 --- a/clients/cli/connections.c +++ b/clients/cli/connections.c @@ -251,7 +251,7 @@ usage (void) " show [--active] [--show-secrets] [id | uuid | path | apath] ...\n\n" " up [[id | uuid | path] ] [ifname ] [ap ] [passwd-file ]\n\n" " down [id | uuid | path | apath] ...\n\n" - " add COMMON_OPTIONS TYPE_SPECIFIC_OPTIONS IP_OPTIONS [-- ([+|-]. )+]\n\n" + " add COMMON_OPTIONS TYPE_SPECIFIC_OPTIONS SLAVE_OPTIONS IP_OPTIONS [-- ([+|-]. )+]\n\n" " modify [--temporary] [id | uuid | path] ([+|-]. )+\n\n" " edit [id | uuid | path] \n" " edit [type ] [con-name ]\n\n" @@ -319,13 +319,16 @@ usage_connection_add (void) { g_printerr (_("Usage: nmcli connection add { ARGUMENTS | help }\n" "\n" - "ARGUMENTS := COMMON_OPTIONS TYPE_SPECIFIC_OPTIONS IP_OPTIONS [-- ([+|-]. )+]\n\n" + "ARGUMENTS := COMMON_OPTIONS TYPE_SPECIFIC_OPTIONS SLAVE_OPTIONS IP_OPTIONS [-- ([+|-]. )+]\n\n" " COMMON_OPTIONS:\n" " type \n" " ifname | \"*\"\n" " [con-name ]\n" " [autoconnect yes|no]\n\n" " [save yes|no]\n\n" + " [master ]\n" + " [slave-type ]\n\n" + " [save yes|no]\n\n" " TYPE_SPECIFIC_OPTIONS:\n" " ethernet: [mac ]\n" " [cloned-mac ]\n" @@ -390,6 +393,11 @@ usage_connection_add (void) " olpc-mesh: ssid \n" " [channel <1-13>]\n" " [dhcp-anycast ]\n\n" + " SLAVE_OPTIONS:\n" + " bridge: [priority <0-63>]\n" + " [path-cost <1-65535>]\n" + " [hairpin yes|no]\n\n" + " team: [config |]\n\n" " IP_OPTIONS:\n" " [ip4 ] [gw4 ]\n" " [ip6 ] [gw6 ]\n\n")); @@ -4317,8 +4325,9 @@ complete_slave (NMSettingConnection *s_con, const char *checked_master = NULL; if (type) - g_print (_("Warning: 'type' is currently ignored. " - "We only support ethernet slaves for now.\n")); + g_print (_("Warning: 'type' is ignored. " + "Use 'nmcli connection add \"%s\" ...' instead."), + type); if (nm_setting_connection_get_master (s_con)) { /* Master already set. */ @@ -4339,8 +4348,6 @@ complete_slave (NMSettingConnection *s_con, } /* Verify master argument */ checked_master = normalized_master_for_slave (all_connections, master, slave_type, NULL); - if (!checked_master) - g_print (_("Warning: master='%s' doesn't refer to any existing profile.\n"), master); /* Change properties in 'connection' setting */ g_object_set (s_con, @@ -5916,6 +5923,9 @@ do_connection_add (NmCli *nmc, int argc, char **argv) gboolean ifname_mandatory = TRUE; const char *save = NULL; gboolean save_bool = TRUE; + const char *master = NULL; + const char *checked_master = NULL; + const char *slave_type = NULL; AddConnectionInfo *info = NULL; const char *setting_name; GError *error = NULL; @@ -5924,6 +5934,8 @@ do_connection_add (NmCli *nmc, int argc, char **argv) {"autoconnect", TRUE, &autoconnect, FALSE}, {"ifname", TRUE, &ifname, FALSE}, {"save", TRUE, &save, FALSE}, + {"master", TRUE, &master, FALSE}, + {"slave-type", TRUE, &slave_type, FALSE}, {NULL} }; rl_attempted_completion_function = (rl_completion_func_t *) nmcli_con_add_tab_completion; @@ -6024,12 +6036,19 @@ do_connection_add (NmCli *nmc, int argc, char **argv) default_name = unique_connection_name (nmc->connections, try_name); g_free (try_name); } + + if (master) + /* Verify master argument */ + checked_master = normalized_master_for_slave (nmc->connections, master, slave_type, &slave_type); + g_object_set (s_con, NM_SETTING_CONNECTION_ID, default_name, NM_SETTING_CONNECTION_UUID, uuid, NM_SETTING_CONNECTION_TYPE, setting_name, NM_SETTING_CONNECTION_AUTOCONNECT, auto_bool, NM_SETTING_CONNECTION_INTERFACE_NAME, ifname, + NM_SETTING_CONNECTION_MASTER, checked_master, + NM_SETTING_CONNECTION_SLAVE_TYPE, slave_type, NULL); g_free (uuid); g_free (default_name); diff --git a/man/nmcli-examples.xml b/man/nmcli-examples.xml index 23ef231864..a0da09cc2d 100644 --- a/man/nmcli-examples.xml +++ b/man/nmcli-examples.xml @@ -178,8 +178,8 @@ $ nmcli g log level INFO domains DEFAULT Adding a bonding master and two slave connection profiles $ nmcli con add type bond ifname mybond0 mode active-backup -$ nmcli con add type bond-slave ifname eth1 master mybond0 -$ nmcli con add type bond-slave ifname eth2 master mybond0 +$ nmcli con add type ethernet ifname eth1 master mybond0 +$ nmcli con add type ethernet ifname eth2 master mybond0 @@ -194,8 +194,8 @@ $ nmcli con add type bond-slave ifname eth2 master mybond0 Adding a team master and two slave connection profiles $ nmcli con add type team con-name Team1 ifname Team1 config team1-master-json.conf -$ nmcli con add type team-slave con-name Team1-slave1 ifname em1 master Team1 -$ nmcli con add type team-slave con-name Team1-slave2 ifname em2 master Team1 +$ nmcli con add type ethernet con-name Team1-slave1 ifname em1 master Team1 +$ nmcli con add type ethernet con-name Team1-slave2 ifname em2 master Team1 @@ -222,8 +222,8 @@ $ nmcli con up Team1-slave2 Adding a bridge and two slave profiles $ nmcli con add type bridge con-name TowerBridge ifname TowerBridge -$ nmcli con add type bridge-slave con-name br-slave-1 ifname ens3 master TowerBridge -$ nmcli con add type bridge-slave con-name br-slave-2 ifname ens4 master TowerBridge +$ nmcli con add type ethernet con-name br-slave-1 ifname ens3 master TowerBridge +$ nmcli con add type ethernet con-name br-slave-2 ifname ens4 master TowerBridge $ nmcli con modify TowerBridge bridge.stp no diff --git a/man/nmcli.1.in b/man/nmcli.1.in index 0c9434c232..7ab3ef8cda 100644 --- a/man/nmcli.1.in +++ b/man/nmcli.1.in @@ -418,7 +418,7 @@ See \fBconnection show\fP above for the description of the -specifying keywo .br If '--wait' option is not specified, the default timeout will be 10 seconds. .TP -.B add COMMON_OPTIONS TYPE_SPECIFIC_OPTIONS IP_OPTIONS [-- [+|-]. ...] +.B add COMMON_OPTIONS TYPE_SPECIFIC_OPTIONS SLAVE_OPTIONS IP_OPTIONS [-- [+|-]. ...] .br Add a connection for NetworkManager. Arguments differ according to connection types, see below. .RS @@ -426,6 +426,9 @@ Add a connection for NetworkManager. Arguments differ according to connection ty .B COMMON_OPTIONS: .IP "\fItype \fP" 42 \(en connection type; see below \fBTYPE_SPECIFIC_OPTIONS\fP for allowed values; (mandatory) +Note that types \fIbond-slave\fP, \fIteam-slave\fP and \fIbridge-slave\fP create \fIethernet\fP +connection profiles. Their use is discouraged in favor of using a specific type with \fImaster\fP +option. .IP "\fIifname | \(dq\&*\(dq\&\fP" 42 \(en interface to bind the connection to. The connection will only be applicable to this interface name. A special value of "\fB*\fP" can be used for interface-independent connections. @@ -437,6 +440,13 @@ Note: use quotes around \fB*\fP to suppress shell expansion. \(en whether the connection profile can be automatically activated (default: yes) .IP "\fI[save yes|no]\fP" 42 \(en whether the connection should be persistent, i.e. NetworkManager should store it on disk (default: yes) +.IP "\fI[master ]\fP" 42 +\(en master interface name, or connection UUID or ID of master connection profile. +The value can be prefixed with \fBifname/\fP, \fBuuid/\fP or \fBid/\fP to disambiguate it. +See below \fBSLAVE_OPTIONS\fP for additional options for slave connection to masters of various types. +.IP "\fI[slave-type ]\fP" 42 +\(en type of master connection. Only required when it can not be inferred (i.e. the master connection does +not exist yet). .RE .RS .TP @@ -580,8 +590,6 @@ The value can be prefixed with \fBifname/\fP, \fBuuid/\fP or \fBid/\fP to disamb .IP "\fImaster \fP" 42 \(en master team interface name, or connection UUID or ID of team master connection profile. The value can be prefixed with \fBifname/\fP, \fBuuid/\fP or \fBid/\fP to disambiguate it. -.IP "\fI[config |]\fP" 42 -\(en JSON configuration for team .RE .RS .TP @@ -610,13 +618,6 @@ originally introduced in 3.15 upstream kernel) .IP "\fImaster \fP" 42 \(en master bridge interface name, or connection UUID or ID of bridge master connection profile. The value can be prefixed with \fBifname/\fP, \fBuuid/\fP or \fBid/\fP to disambiguate it. -.IP "\fI[priority <0-63>]\fP" 42 -\(en STP priority of this slave (default: 32) -.IP "\fI[path-cost <1-65535>]\fP" 42 -\(en STP port cost for destinations via this slave (default: 100) -.IP "\fI[hairpin yes|no]\fP" 42 -\(en 'hairpin mode' for the slave, which allows frames -to be sent back out through the slave the frame was received on (default: yes) .RE .RS .TP @@ -638,6 +639,27 @@ to be sent back out through the slave the frame was received on (default: yes) .RE .RS .TP +.B SLAVE_OPTIONS: +.RE +.RS +.TP +.B bridge: +.IP "\fI[priority <0-63>]\fP" 42 +\(en STP priority of this slave (default: 32) +.IP "\fI[path-cost <1-65535>]\fP" 42 +\(en STP port cost for destinations via this slave (default: 100) +.IP "\fI[hairpin yes|no]\fP" 42 +\(en 'hairpin mode' for the slave, which allows frames +to be sent back out through the slave the frame was received on (default: yes) +.RE +.RS +.TP +.B team: +.IP "\fI[config |]\fP" 42 +\(en JSON configuration for team +.RE +.RS +.TP .B IP_OPTIONS: .IP "\fI[ip4 ] [gw4 ]\fP" 42 \(en IPv4 addresses From 1ff98fca40168d01fcd9da33058ff6e1d012b426 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 21 Apr 2015 18:35:19 +0200 Subject: [PATCH 5/5] cli: add "nmcli c add master" to bash-completion Remove the discouraged forms. --- clients/cli/nmcli-completion | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/clients/cli/nmcli-completion b/clients/cli/nmcli-completion index 08c78ba062..825008cbb5 100644 --- a/clients/cli/nmcli-completion +++ b/clients/cli/nmcli-completion @@ -387,7 +387,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 bond-slave bridge bridge-slave team team-slave pppoe" + _nmcli_list "ethernet wifi wimax gsm cdma infiniband bluetooth vpn olpc-mesh vlan bond bridge team pppoe" fi return 0 fi @@ -934,7 +934,7 @@ _nmcli() ;; a|ad|add) if [[ ${#words[@]} -eq 3 ]]; then - _nmcli_compl_COMMAND "${words[2]}" type ifname con-name autoconnect + _nmcli_compl_COMMAND "${words[2]}" type ifname con-name autoconnect master elif [[ ${#words[@]} -gt 3 ]]; then _nmcli_array_delete_at words 0 1 @@ -947,14 +947,14 @@ _nmcli() ;; 1) if [[ "$HELP_ONLY_AS_FIRST" == 1 ]]; then - _nmcli_compl_COMMAND "${words[2]}" type ifname con-name autoconnect + _nmcli_compl_COMMAND "${words[2]}" type ifname con-name autoconnect master fi return 0 ;; esac OPTIONS_TYPE= - OPTIONS=(type ifname con-name autoconnect save) + OPTIONS=(type ifname con-name autoconnect save master) OPTIONS_MANDATORY=(type ifname) COMMAND_ARGS_WAIT_OPTIONS=1 OPTIONS_MANDATORY_IFNAME=1 @@ -1019,32 +1019,14 @@ _nmcli() OPTIONS_TYPE=bond OPTIONS_TYPED=(mode miimon downdelay updelay arp-interval arp-ip-target primary lacp-rate) ;; - bond-|bond-s|bond-sl|bond-sla|bond-slav|bond-slave) - OPTIONS_TYPE=bond-slave - OPTIONS_TYPED=(master) - OPTIONS_MANDATORY=(master) - OPTIONS_IP=() - ;; team) OPTIONS_TYPE=team OPTIONS_TYPED=(config) ;; - team-|team-s|team-sl|team-sla|team-slav|team-slave) - OPTIONS_TYPE=team-slave - OPTIONS_TYPED=(master config) - OPTIONS_MANDATORY=(master) - OPTIONS_IP=() - ;; bridge) OPTIONS_TYPE=bridge OPTIONS_TYPED=(stp priority forward-delay hello-time max-age ageing-time mac) ;; - bridge-|bridge-s|bridge-sl|bridge-sla|bridge-slav|bridge-slave) - OPTIONS_TYPE=bridge-slave - OPTIONS_TYPED=(master priority path-cost hairpin) - OPTIONS_MANDATORY=(master) - OPTIONS_IP=() - ;; vp|vpn) OPTIONS_TYPE=vpn OPTIONS_TYPED=(vpn-type user)