mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-03 02:20:14 +01:00
merge: branch 'lr/cli-add-master'
Make it possible to specify master connection/device for any connection profile https://bugzilla.gnome.org/show_bug.cgi?id=748302
This commit is contained in:
commit
9d5f114bfd
4 changed files with 285 additions and 243 deletions
|
|
@ -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): ")
|
||||
|
|
@ -253,7 +251,7 @@ usage (void)
|
|||
" show [--active] [--show-secrets] [id | uuid | path | apath] <ID> ...\n\n"
|
||||
" up [[id | uuid | path] <ID>] [ifname <ifname>] [ap <BSSID>] [passwd-file <file with passwords>]\n\n"
|
||||
" down [id | uuid | path | apath] <ID> ...\n\n"
|
||||
" add COMMON_OPTIONS TYPE_SPECIFIC_OPTIONS IP_OPTIONS [-- ([+|-]<setting>.<property> <value>)+]\n\n"
|
||||
" add COMMON_OPTIONS TYPE_SPECIFIC_OPTIONS SLAVE_OPTIONS IP_OPTIONS [-- ([+|-]<setting>.<property> <value>)+]\n\n"
|
||||
" modify [--temporary] [id | uuid | path] <ID> ([+|-]<setting>.<property> <value>)+\n\n"
|
||||
" edit [id | uuid | path] <ID>\n"
|
||||
" edit [type <new_con_type>] [con-name <new_con_name>]\n\n"
|
||||
|
|
@ -321,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 [-- ([+|-]<setting>.<property> <value>)+]\n\n"
|
||||
"ARGUMENTS := COMMON_OPTIONS TYPE_SPECIFIC_OPTIONS SLAVE_OPTIONS IP_OPTIONS [-- ([+|-]<setting>.<property> <value>)+]\n\n"
|
||||
" COMMON_OPTIONS:\n"
|
||||
" type <type>\n"
|
||||
" ifname <interface name> | \"*\"\n"
|
||||
" [con-name <connection name>]\n"
|
||||
" [autoconnect yes|no]\n\n"
|
||||
" [save yes|no]\n\n"
|
||||
" [master <master (ifname, or connection UUID or name)>]\n"
|
||||
" [slave-type <master connection type>]\n\n"
|
||||
" [save yes|no]\n\n"
|
||||
" TYPE_SPECIFIC_OPTIONS:\n"
|
||||
" ethernet: [mac <MAC address>]\n"
|
||||
" [cloned-mac <cloned MAC address>]\n"
|
||||
|
|
@ -392,6 +393,11 @@ usage_connection_add (void)
|
|||
" olpc-mesh: ssid <SSID>\n"
|
||||
" [channel <1-13>]\n"
|
||||
" [dhcp-anycast <MAC address>]\n\n"
|
||||
" SLAVE_OPTIONS:\n"
|
||||
" bridge: [priority <0-63>]\n"
|
||||
" [path-cost <1-65535>]\n"
|
||||
" [hairpin yes|no]\n\n"
|
||||
" team: [config <file>|<raw JSON data>]\n\n"
|
||||
" IP_OPTIONS:\n"
|
||||
" [ip4 <IPv4 address>] [gw4 <IPv4 gateway>]\n"
|
||||
" [ip6 <IPv6 address>] [gw6 <IPv6 gateway>]\n\n"));
|
||||
|
|
@ -3154,27 +3160,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;
|
||||
|
||||
|
|
@ -3187,11 +3197,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
|
||||
|
|
@ -3205,13 +3216,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
|
||||
|
|
@ -4284,6 +4312,53 @@ 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 ignored. "
|
||||
"Use 'nmcli connection add \"%s\" ...' instead."),
|
||||
type);
|
||||
|
||||
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 = normalized_master_for_slave (all_connections, master, slave_type, NULL);
|
||||
|
||||
/* Change properties in 'connection' setting */
|
||||
g_object_set (s_con,
|
||||
NM_SETTING_CONNECTION_MASTER, checked_master,
|
||||
NULL);
|
||||
|
||||
g_free (master_ask);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
complete_connection_by_type (NMConnection *connection,
|
||||
const char *con_type,
|
||||
|
|
@ -4311,6 +4386,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 +5091,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 +5102,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 +5151,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 +5162,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 +5301,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 +5312,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 +5441,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 +5882,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, ":"))
|
||||
|
|
@ -5897,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;
|
||||
|
|
@ -5905,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;
|
||||
|
|
@ -6005,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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -178,8 +178,8 @@ $ nmcli g log level INFO domains DEFAULT
|
|||
<example><title>Adding a bonding master and two slave connection profiles</title>
|
||||
<programlisting><emphasis role="bold">
|
||||
$ 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
|
||||
</emphasis></programlisting>
|
||||
</example>
|
||||
<para>
|
||||
|
|
@ -194,8 +194,8 @@ $ nmcli con add type bond-slave ifname eth2 master mybond0
|
|||
<example><title>Adding a team master and two slave connection profiles</title>
|
||||
<programlisting><emphasis role="bold">
|
||||
$ 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
|
||||
</emphasis></programlisting>
|
||||
</example>
|
||||
<para>
|
||||
|
|
@ -222,8 +222,8 @@ $ nmcli con up Team1-slave2
|
|||
<example><title>Adding a bridge and two slave profiles</title>
|
||||
<programlisting><emphasis role="bold">
|
||||
$ 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
|
||||
</emphasis></programlisting>
|
||||
</example>
|
||||
|
|
|
|||
|
|
@ -418,7 +418,7 @@ See \fBconnection show\fP above for the description of the <ID>-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 [-- [+|-]<setting>.<property> <value> ...]
|
||||
.B add COMMON_OPTIONS TYPE_SPECIFIC_OPTIONS SLAVE_OPTIONS IP_OPTIONS [-- [+|-]<setting>.<property> <value> ...]
|
||||
.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 <type>\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 <ifname> | \(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 <master (ifname, or connection UUID or name)>]\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 <master connection 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 <master (ifname, or connection UUID or name)>\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 <file>|<raw JSON data>]\fP" 42
|
||||
\(en JSON configuration for team
|
||||
.RE
|
||||
.RS
|
||||
.TP
|
||||
|
|
@ -610,13 +618,6 @@ originally introduced in 3.15 upstream kernel)
|
|||
.IP "\fImaster <master (ifname, or connection UUID or name)>\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 <file>|<raw JSON data>]\fP" 42
|
||||
\(en JSON configuration for team
|
||||
.RE
|
||||
.RS
|
||||
.TP
|
||||
.B IP_OPTIONS:
|
||||
.IP "\fI[ip4 <IPv4 address>] [gw4 <IPv4 gateway>]\fP" 42
|
||||
\(en IPv4 addresses
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue