diff options
author | Beniamino Galvani <bgalvani@redhat.com> | 2015-09-18 11:03:17 +0200 |
---|---|---|
committer | Beniamino Galvani <bgalvani@redhat.com> | 2015-12-09 14:30:08 +0100 |
commit | c3e6e25239ea691cc3eb7ee3d443a29f54d3bdfb (patch) | |
tree | d2c7ab330422d00049e2cd5c26c5b5147a145ba2 | |
parent | 4d0192e661e08727bb53295934ec8c3756bd93d7 (diff) | |
download | NetworkManager-c3e6e25239ea691cc3eb7ee3d443a29f54d3bdfb.tar.gz |
cli: add macvlan support
-rw-r--r-- | clients/cli/connections.c | 139 | ||||
-rw-r--r-- | clients/cli/nmcli-completion | 2 | ||||
-rw-r--r-- | clients/cli/settings.c | 131 | ||||
-rw-r--r-- | man/nmcli.1.in | 10 |
4 files changed, 280 insertions, 2 deletions
diff --git a/clients/cli/connections.c b/clients/cli/connections.c index 82f68c72a8..e5fa81b814 100644 --- a/clients/cli/connections.c +++ b/clients/cli/connections.c @@ -119,6 +119,7 @@ extern NmcOutputField nmc_fields_setting_team_port[]; extern NmcOutputField nmc_fields_setting_dcb[]; extern NmcOutputField nmc_fields_setting_tun[]; extern NmcOutputField nmc_fields_setting_ip_tunnel[]; +extern NmcOutputField nmc_fields_setting_macvlan[]; /* Available settings for 'connection show <con>' - profile part */ static NmcOutputField nmc_fields_settings_names[] = { @@ -149,6 +150,7 @@ static NmcOutputField nmc_fields_settings_names[] = { 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 */ SETTING_FIELD (NM_SETTING_IP_TUNNEL_SETTING_NAME, nmc_fields_setting_ip_tunnel + 1), /* 26 */ + SETTING_FIELD (NM_SETTING_MACVLAN_SETTING_NAME, nmc_fields_setting_macvlan + 1), /* 27 */ {NULL, NULL, 0, NULL, NULL, FALSE, FALSE, 0} }; #define NMC_FIELDS_SETTINGS_NAMES_ALL_X NM_SETTING_CONNECTION_SETTING_NAME","\ @@ -176,7 +178,8 @@ static NmcOutputField nmc_fields_settings_names[] = { NM_SETTING_TEAM_PORT_SETTING_NAME"," \ NM_SETTING_DCB_SETTING_NAME"," \ NM_SETTING_TUN_SETTING_NAME"," \ - NM_SETTING_IP_TUNNEL_SETTING_NAME + NM_SETTING_IP_TUNNEL_SETTING_NAME"," \ + NM_SETTING_MACVLAN_SETTING_NAME #define NMC_FIELDS_SETTINGS_NAMES_ALL NMC_FIELDS_SETTINGS_NAMES_ALL_X /* Active connection data */ @@ -423,6 +426,9 @@ usage_connection_add (void) " [pi yes|no]\n" " [vnet-hdr yes|no]\n" " [multi-queue yes|no]\n\n" + " macvlan: dev <parent device (connection UUID, ifname, or MAC)>\n" + " mode vepa|bridge|private|passthru|source\n" + " [tap yes|no]\n\n" " SLAVE_OPTIONS:\n" " bridge: [priority <0-63>]\n" " [path-cost <1-65535>]\n" @@ -2811,6 +2817,15 @@ static const NameItem nmc_ip_tunnel_settings [] = { { NULL, NULL, NULL, FALSE } }; +static const NameItem nmc_macvlan_settings [] = { + { NM_SETTING_CONNECTION_SETTING_NAME, NULL, NULL, TRUE }, + { NM_SETTING_WIRED_SETTING_NAME, "ethernet", NULL, FALSE }, + { NM_SETTING_MACVLAN_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[] = { { NM_SETTING_GENERIC_SETTING_NAME, NULL, nmc_generic_settings }, @@ -2834,6 +2849,7 @@ static const NameItem nmc_valid_connection_types[] = { { "bridge-slave", NULL, nmc_bridge_slave_settings }, { NM_SETTING_TUN_SETTING_NAME, NULL, nmc_tun_settings }, { NM_SETTING_IP_TUNNEL_SETTING_NAME, NULL, nmc_ip_tunnel_settings }, + { NM_SETTING_MACVLAN_SETTING_NAME, NULL, nmc_macvlan_settings }, { NULL, NULL, NULL } }; @@ -4206,6 +4222,33 @@ do_questionnaire_adsl (gboolean echo, char **password, char **encapsulation) } } + +static void +do_questionnaire_macvlan (char **tap) +{ + gboolean once_more; + GError *error = NULL; + + /* Ask for optional 'bridge-slave' arguments. */ + if (!want_provide_opt_args (_("macvlan"), 1)) + return; + + if (!*tap) { + gboolean tap_bool; + do { + *tap = nmc_readline (_("Tap %s"), prompt_yes_no (FALSE, ":")); + *tap = *tap ? *tap : g_strdup ("yes"); + normalize_yes_no (tap); + once_more = !nmc_string_to_bool (*tap, &tap_bool, &error); + if (once_more) { + g_print (_("Error: 'tap': %s.\n"), error->message); + g_clear_error (&error); + g_free (*tap); + } + } while (once_more); + } +} + static gboolean split_address (char* str, char **ip, char **rest) { @@ -4676,6 +4719,7 @@ complete_connection_by_type (NMConnection *connection, NMSettingAdsl *s_adsl; NMSettingTun *s_tun; NMSettingIPTunnel *s_ip_tunnel; + NMSettingMacvlan *s_macvlan; const char *slave_type; g_return_val_if_fail (error == NULL || *error == NULL, FALSE); @@ -5783,6 +5827,99 @@ cleanup_adsl: g_free (password); g_free (protocol_ask); g_free (encapsulation); + + if (!success) + return FALSE; + + } else if (!strcmp (con_type, NM_SETTING_MACVLAN_SETTING_NAME)) { + /* Build up the settings required for 'macvlan' */ + gboolean success = FALSE; + const char *parent = NULL; + char *parent_ask = NULL; + const char *mode = NULL; + char *mode_ask = NULL; + const char *tap_c = NULL; + char *tap = NULL; + NMSettingMacvlanMode mode_enum; + gboolean valid_mac = FALSE; + gboolean tap_bool = FALSE; + nmc_arg_t exp_args[] = { {"dev", TRUE, &parent, !ask}, + {"mode", TRUE, &mode, !ask}, + {"tap", TRUE, &tap_c, FALSE}, + {NULL} }; + + if (!nmc_parse_args (exp_args, FALSE, &argc, &argv, error)) + return FALSE; + + if (!parent && ask) + parent = parent_ask = nmc_readline (_("MACVLAN parent device or connection UUID: ")); + if (!parent) { + g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("Error: 'dev' is required.")); + return FALSE; + } + + if ( !(valid_mac = nm_utils_hwaddr_valid (parent, ETH_ALEN)) + && !nm_utils_is_uuid (parent) + && !nm_utils_iface_valid_name (parent)) { + g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("Error: 'dev': '%s' is neither UUID, interface name, nor MAC."), + parent); + goto cleanup_macvlan; + } + + if (!mode && ask) + mode = mode_ask = nmc_readline (_("MACVLAN mode: ")); + if (!mode) { + g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("Error: 'mode' is required.")); + return FALSE; + } + + if (!nm_utils_enum_from_str (nm_setting_macvlan_mode_get_type(), mode, (int *) &mode_enum, NULL)) { + g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("Error: 'mode' is not valid.")); + return FALSE; + } + + /* Also ask for all optional arguments if '--ask' is specified. */ + tap = g_strdup (tap_c); + if (ask) + do_questionnaire_macvlan (&tap); + + if (tap) { + GError *tmp_err = NULL; + if (!nmc_string_to_bool (tap, &tap_bool, &tmp_err)) { + g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("Error: 'tap': %s."), tmp_err->message); + g_clear_error (&tmp_err); + goto cleanup_macvlan; + } + } + + /* Add 'macvlan' setting */ + s_macvlan = (NMSettingMacvlan *) nm_setting_macvlan_new (); + nm_connection_add_setting (connection, NM_SETTING (s_macvlan)); + + /* Add 'wired' setting if necessary */ + if (valid_mac) { + s_wired = (NMSettingWired *) nm_setting_wired_new (); + nm_connection_add_setting (connection, NM_SETTING (s_wired)); + g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, parent, NULL); + } + + /* Set 'macvlan' properties */ + if (!valid_mac) + g_object_set (s_macvlan, NM_SETTING_MACVLAN_PARENT, parent, NULL); + g_object_set (s_macvlan, NM_SETTING_MACVLAN_MODE, mode_enum, NULL); + g_object_set (s_macvlan, NM_SETTING_MACVLAN_TAP, tap_bool, NULL); + + success = TRUE; +cleanup_macvlan: + g_free (parent_ask); + g_free (mode_ask); + g_free (tap); + if (!success) return FALSE; diff --git a/clients/cli/nmcli-completion b/clients/cli/nmcli-completion index aff78f7ace..aefd902a23 100644 --- a/clients/cli/nmcli-completion +++ b/clients/cli/nmcli-completion @@ -412,7 +412,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 tun ip-tunnel" + _nmcli_list "ethernet wifi wimax gsm cdma infiniband bluetooth vpn olpc-mesh vlan bond bridge team pppoe adsl tun ip-tunnel macvlan" fi return 0 fi diff --git a/clients/cli/settings.c b/clients/cli/settings.c index 3e8c10f4c2..05e5580165 100644 --- a/clients/cli/settings.c +++ b/clients/cli/settings.c @@ -748,6 +748,22 @@ NmcOutputField nmc_fields_setting_ip_tunnel[] = { NM_SETTING_IP_TUNNEL_FLOW_LABEL #define NMC_FIELDS_SETTING_IP_TUNNEL_COMMON NMC_FIELDS_SETTING_IP_TUNNEL_ALL +/* Available fields for NM_SETTING_MACVLAN_SETTING_NAME */ +NmcOutputField nmc_fields_setting_macvlan[] = { + SETTING_FIELD ("name"), /* 0 */ + SETTING_FIELD (NM_SETTING_MACVLAN_PARENT), /* 1 */ + SETTING_FIELD (NM_SETTING_MACVLAN_MODE), /* 2 */ + SETTING_FIELD (NM_SETTING_MACVLAN_PROMISCUOUS), /* 3 */ + SETTING_FIELD (NM_SETTING_MACVLAN_TAP), /* 4 */ + {NULL, NULL, 0, NULL, FALSE, FALSE, 0} +}; +#define NMC_FIELDS_SETTING_MACVLAN_ALL "name"","\ + NM_SETTING_MACVLAN_PARENT","\ + NM_SETTING_MACVLAN_MODE","\ + NM_SETTING_MACVLAN_PROMISCUOUS","\ + NM_SETTING_MACVLAN_TAP +#define NMC_FIELDS_SETTING_MACVLAN_COMMON NMC_FIELDS_SETTING_MACVLAN_ALL + /*----------------------------------------------------------------------------*/ static char * wep_key_type_to_string (NMWepKeyType type) @@ -1866,6 +1882,61 @@ nmc_property_wifi_sec_get_wep_key_type (NMSetting *setting, NmcPropertyGetType g return wep_key_type_to_string (nm_setting_wireless_security_get_wep_key_type (s_wireless_sec)); } +/* --- NM_SETTING_MACVLAN_SETTING_NAME property get functions --- */ +DEFINE_GETTER (nmc_property_macvlan_get_parent, NM_SETTING_MACVLAN_PARENT) +DEFINE_GETTER (nmc_property_macvlan_get_promiscuous, NM_SETTING_MACVLAN_PROMISCUOUS) +DEFINE_GETTER (nmc_property_macvlan_get_tap, NM_SETTING_MACVLAN_TAP) + +static char * +nmc_property_macvlan_get_mode (NMSetting *setting, NmcPropertyGetType get_type) +{ + NMSettingMacvlan *s_macvlan = NM_SETTING_MACVLAN (setting); + NMSettingMacvlanMode mode; + char *tmp, *str; + + mode = nm_setting_macvlan_get_mode (s_macvlan); + tmp = nm_utils_enum_to_str (nm_setting_macvlan_mode_get_type (), mode); + + if (get_type == NMC_PROPERTY_GET_PARSABLE) + str = g_strdup (tmp ? tmp : ""); + else + str = g_strdup_printf ("%d (%s)", mode, tmp ? tmp : ""); + g_free (tmp); + + return str; +} + +static gboolean +nmc_property_macvlan_set_mode (NMSetting *setting, const char *prop, + const char *val, GError **error) +{ + NMSettingMacvlanMode mode; + gs_free const char **options = NULL; + gs_free char *options_str = NULL; + long int t; + gboolean ret; + + if (nmc_string_to_int_base (val, 0, TRUE, 0, _NM_SETTING_MACVLAN_MODE_NUM - 1, &t)) + mode = (NMSettingMacvlanMode) t; + else { + ret = nm_utils_enum_from_str (nm_setting_macvlan_mode_get_type (), val, + (int *) &mode, NULL); + + if (!ret) { + options = nm_utils_enum_get_values (nm_setting_macvlan_mode_get_type(), + NM_SETTING_MACVLAN_MODE_UNKNOWN + 1, + G_MAXINT); + options_str = g_strjoinv (",", (char **) options); + g_set_error (error, 1, 0, _("invalid option '%s', use one of [%s]"), + val, options_str); + return FALSE; + } + } + + g_object_set (setting, prop, (guint) mode, NULL); + return TRUE; +} + /*----------------------------------------------------------------------------*/ static void @@ -7231,6 +7302,36 @@ nmc_properties_init (void) NULL, NULL, NULL); + + /* Add editable properties for NM_SETTING_MACVLAN_SETTING_NAME */ + nmc_add_prop_funcs (GLUE (MACVLAN, PARENT), + nmc_property_macvlan_get_parent, + nmc_property_set_string, + NULL, + NULL, + NULL, + NULL); + nmc_add_prop_funcs (GLUE (MACVLAN, MODE), + nmc_property_macvlan_get_mode, + nmc_property_macvlan_set_mode, + NULL, + NULL, + NULL, + NULL); + nmc_add_prop_funcs (GLUE (MACVLAN, PROMISCUOUS), + nmc_property_macvlan_get_promiscuous, + nmc_property_set_bool, + NULL, + NULL, + NULL, + NULL); + nmc_add_prop_funcs (GLUE (MACVLAN, TAP), + nmc_property_macvlan_get_tap, + nmc_property_set_bool, + NULL, + NULL, + NULL, + NULL); } void @@ -8447,6 +8548,35 @@ setting_ip_tunnel_details (NMSetting *setting, NmCli *nmc, const char *one_prop return TRUE; } +static gboolean +setting_macvlan_details (NMSetting *setting, NmCli *nmc, const char *one_prop, gboolean secrets) +{ + NMSettingMacvlan *s_macvlan = NM_SETTING_MACVLAN (setting); + NmcOutputField *tmpl, *arr; + size_t tmpl_len; + + g_return_val_if_fail (NM_IS_SETTING_MACVLAN (s_macvlan), FALSE); + + tmpl = nmc_fields_setting_macvlan; + tmpl_len = sizeof (nmc_fields_setting_macvlan); + nmc->print_fields.indices = parse_output_fields (one_prop ? one_prop : NMC_FIELDS_SETTING_MACVLAN_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_macvlan_get_parent (setting, NMC_PROPERTY_GET_PRETTY)); + set_val_str (arr, 2, nmc_property_macvlan_get_mode (setting, NMC_PROPERTY_GET_PRETTY)); + set_val_str (arr, 3, nmc_property_macvlan_get_promiscuous (setting, NMC_PROPERTY_GET_PRETTY)); + set_val_str (arr, 4, nmc_property_macvlan_get_tap (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); @@ -8480,6 +8610,7 @@ static const SettingDetails detail_printers[] = { { NM_SETTING_DCB_SETTING_NAME, setting_dcb_details }, { NM_SETTING_TUN_SETTING_NAME, setting_tun_details }, { NM_SETTING_IP_TUNNEL_SETTING_NAME, setting_ip_tunnel_details }, + { NM_SETTING_MACVLAN_SETTING_NAME, setting_macvlan_details }, { NULL }, }; diff --git a/man/nmcli.1.in b/man/nmcli.1.in index 58f96018f9..e78c72ea32 100644 --- a/man/nmcli.1.in +++ b/man/nmcli.1.in @@ -684,6 +684,16 @@ The value can be prefixed with \fBifname/\fP, \fBuuid/\fP or \fBid/\fP to disamb .RE .RS .TP +.B macvlan: +.IP "\fIdev <parent device (connection UUID, ifname, or MAC)>\fP" 42 +\(en parent device this MACVLAN is on +.IP "\fImode vepa|bridge|private|passthru|source\fP" 42 +\(en MACVLAN mode, which specifies the communication mechanism between multiple MACVLANs on the same lower device +.IP "\fI[tap yes|no]\fP" 42 +\(en controls the device type. If set to 'yes' a MACVTAP will be created (default: no) +.RE +.RS +.TP .B SLAVE_OPTIONS: .RE .RS |