merge: macvlan and macvtap devices creation support

https://bugzilla.gnome.org/show_bug.cgi?id=755986
This commit is contained in:
Beniamino Galvani 2015-12-09 14:30:27 +01:00
commit e25d144d77
33 changed files with 2012 additions and 59 deletions

View file

@ -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;

View file

@ -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

View file

@ -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 },
};

View file

@ -21,6 +21,12 @@
</tp:docstring>
</property>
<property name="Tap" type="b" access="read">
<tp:docstring>
Whether the device is a macvtap.
</tp:docstring>
</property>
<signal name="PropertiesChanged">
<arg name="properties" type="a{sv}" tp:type="String_Variant_Map">
<tp:docstring>

View file

@ -28,6 +28,7 @@ libnm_core_headers = \
$(core)/nm-setting-ip-tunnel.h \
$(core)/nm-setting-ip4-config.h \
$(core)/nm-setting-ip6-config.h \
$(core)/nm-setting-macvlan.h \
$(core)/nm-setting-olpc-mesh.h \
$(core)/nm-setting-ppp.h \
$(core)/nm-setting-pppoe.h \
@ -86,6 +87,7 @@ libnm_core_sources = \
$(core)/nm-setting-ip-tunnel.c \
$(core)/nm-setting-ip4-config.c \
$(core)/nm-setting-ip6-config.c \
$(core)/nm-setting-macvlan.c \
$(core)/nm-setting-olpc-mesh.c \
$(core)/nm-setting-ppp.c \
$(core)/nm-setting-pppoe.c \

View file

@ -1596,7 +1596,8 @@ nm_connection_is_virtual (NMConnection *connection)
|| !strcmp (type, NM_SETTING_BRIDGE_SETTING_NAME)
|| !strcmp (type, NM_SETTING_VLAN_SETTING_NAME)
|| !strcmp (type, NM_SETTING_TUN_SETTING_NAME)
|| !strcmp (type, NM_SETTING_IP_TUNNEL_SETTING_NAME))
|| !strcmp (type, NM_SETTING_IP_TUNNEL_SETTING_NAME)
|| !strcmp (type, NM_SETTING_MACVLAN_SETTING_NAME))
return TRUE;
if (!strcmp (type, NM_SETTING_INFINIBAND_SETTING_NAME)) {
@ -1905,6 +1906,24 @@ nm_connection_get_setting_ip6_config (NMConnection *connection)
return (NMSettingIPConfig *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG);
}
/**
* nm_connection_get_setting_macvlan:
* @connection: the #NMConnection
*
* A shortcut to return any #NMSettingMacvlan the connection might contain.
*
* Returns: (transfer none): an #NMSettingMacvlan if the connection contains one, otherwise %NULL
*
* Since: 1.2
**/
NMSettingMacvlan *
nm_connection_get_setting_macvlan (NMConnection *connection)
{
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
return (NMSettingMacvlan *) nm_connection_get_setting (connection, NM_TYPE_SETTING_MACVLAN);
}
/**
* nm_connection_get_setting_olpc_mesh:
* @connection: the #NMConnection

View file

@ -206,6 +206,8 @@ NM_AVAILABLE_IN_1_2
NMSettingIPTunnel * nm_connection_get_setting_ip_tunnel (NMConnection *connection);
NMSettingIPConfig * nm_connection_get_setting_ip4_config (NMConnection *connection);
NMSettingIPConfig * nm_connection_get_setting_ip6_config (NMConnection *connection);
NM_AVAILABLE_IN_1_2
NMSettingMacvlan * nm_connection_get_setting_macvlan (NMConnection *connection);
NMSettingOlpcMesh * nm_connection_get_setting_olpc_mesh (NMConnection *connection);
NMSettingPpp * nm_connection_get_setting_ppp (NMConnection *connection);
NMSettingPppoe * nm_connection_get_setting_pppoe (NMConnection *connection);

View file

@ -52,6 +52,7 @@
#include "nm-setting-ip-tunnel.h"
#include "nm-setting-ip4-config.h"
#include "nm-setting-ip6-config.h"
#include "nm-setting-macvlan.h"
#include "nm-setting-olpc-mesh.h"
#include "nm-setting-ppp.h"
#include "nm-setting-pppoe.h"

View file

@ -45,6 +45,7 @@ typedef struct _NMSettingIPConfig NMSettingIPConfig;
typedef struct _NMSettingIPTunnel NMSettingIPTunnel;
typedef struct _NMSettingIP4Config NMSettingIP4Config;
typedef struct _NMSettingIP6Config NMSettingIP6Config;
typedef struct _NMSettingMacvlan NMSettingMacvlan;
typedef struct _NMSettingOlpcMesh NMSettingOlpcMesh;
typedef struct _NMSettingPpp NMSettingPpp;
typedef struct _NMSettingPppoe NMSettingPppoe;

View file

@ -149,6 +149,8 @@ typedef enum {
* @NM_DEVICE_TYPE_BRIDGE: a bridge master interface
* @NM_DEVICE_TYPE_TEAM: a team master interface
* @NM_DEVICE_TYPE_TUN: a TUN or TAP interface
* @NM_DEVICE_TYPE_IP_TUNNEL: a IP tunnel interface
* @NM_DEVICE_TYPE_MACVLAN: a MACVLAN interface
*
* #NMDeviceType values indicate the type of hardware represented by
* an #NMDevice.
@ -174,6 +176,7 @@ typedef enum {
NM_DEVICE_TYPE_TEAM = 15,
NM_DEVICE_TYPE_TUN = 16,
NM_DEVICE_TYPE_IP_TUNNEL = 17,
NM_DEVICE_TYPE_MACVLAN = 18,
} NMDeviceType;
/**

View file

@ -0,0 +1,350 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* Copyright 2015 Red Hat, Inc.
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include "nm-setting-macvlan.h"
#include "nm-utils.h"
#include "nm-setting-connection.h"
#include "nm-setting-private.h"
#include "nm-setting-wired.h"
#include "nm-connection-private.h"
/**
* SECTION:nm-setting-macvlan
* @short_description: Describes connection properties for macvlan interfaces
*
* The #NMSettingMacvlan object is a #NMSetting subclass that describes properties
* necessary for connection to macvlan interfaces.
**/
G_DEFINE_TYPE_WITH_CODE (NMSettingMacvlan, nm_setting_macvlan, NM_TYPE_SETTING,
_nm_register_setting (MACVLAN, 1))
NM_SETTING_REGISTER_TYPE (NM_TYPE_SETTING_MACVLAN)
#define NM_SETTING_MACVLAN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_MACVLAN, NMSettingMacvlanPrivate))
typedef struct {
char *parent;
NMSettingMacvlanMode mode;
gboolean promiscuous;
gboolean tap;
} NMSettingMacvlanPrivate;
enum {
PROP_0,
PROP_PARENT,
PROP_MODE,
PROP_PROMISCUOUS,
PROP_TAP,
LAST_PROP
};
/**
* nm_setting_macvlan_new:
*
* Creates a new #NMSettingMacvlan object with default values.
*
* Returns: (transfer full): the new empty #NMSettingMacvlan object
*
* Since: 1.2
**/
NMSetting *
nm_setting_macvlan_new (void)
{
return (NMSetting *) g_object_new (NM_TYPE_SETTING_MACVLAN, NULL);
}
/**
* nm_setting_macvlan_get_parent:
* @setting: the #NMSettingMacvlan
*
* Returns: the #NMSettingMacvlan:parent property of the setting
*
* Since: 1.2
**/
const char *
nm_setting_macvlan_get_parent (NMSettingMacvlan *setting)
{
g_return_val_if_fail (NM_IS_SETTING_MACVLAN (setting), NULL);
return NM_SETTING_MACVLAN_GET_PRIVATE (setting)->parent;
}
/**
* nm_setting_macvlan_get_mode:
* @setting: the #NMSettingMacvlan
*
* Returns: the #NMSettingMacvlan:mode property of the setting
*
* Since: 1.2
**/
NMSettingMacvlanMode
nm_setting_macvlan_get_mode (NMSettingMacvlan *setting)
{
g_return_val_if_fail (NM_IS_SETTING_MACVLAN (setting), NM_SETTING_MACVLAN_MODE_UNKNOWN);
return NM_SETTING_MACVLAN_GET_PRIVATE (setting)->mode;
}
/**
* nm_setting_macvlan_get_promiscuous:
* @setting: the #NMSettingMacvlan
*
* Returns: the #NMSettingMacvlan:promiscuous property of the setting
*
* Since: 1.2
**/
gboolean
nm_setting_macvlan_get_promiscuous (NMSettingMacvlan *setting)
{
g_return_val_if_fail (NM_IS_SETTING_MACVLAN (setting), FALSE);
return NM_SETTING_MACVLAN_GET_PRIVATE (setting)->promiscuous;
}
/**
* nm_setting_macvlan_get_tap:
* @setting: the #NMSettingMacvlan
*
* Returns: the #NMSettingMacvlan:tap property of the setting
*
* Since: 1.2
**/
gboolean
nm_setting_macvlan_get_tap (NMSettingMacvlan *setting)
{
g_return_val_if_fail (NM_IS_SETTING_MACVLAN (setting), FALSE);
return NM_SETTING_MACVLAN_GET_PRIVATE (setting)->tap;
}
/*********************************************************************/
static void
nm_setting_macvlan_init (NMSettingMacvlan *setting)
{
}
static gboolean
verify (NMSetting *setting, NMConnection *connection, GError **error)
{
NMSettingMacvlanPrivate *priv = NM_SETTING_MACVLAN_GET_PRIVATE (setting);
NMSettingConnection *s_con;
NMSettingWired *s_wired;
if (connection) {
s_con = nm_connection_get_setting_connection (connection);
s_wired = nm_connection_get_setting_wired (connection);
} else {
s_con = NULL;
s_wired = NULL;
}
if (priv->parent) {
if ( !nm_utils_is_uuid (priv->parent)
&& !nm_utils_iface_valid_name (priv->parent)) {
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("'%s' is neither an UUID nor an interface name"),
priv->parent);
g_prefix_error (error, "%s.%s: ", NM_SETTING_MACVLAN_SETTING_NAME, NM_SETTING_MACVLAN_PARENT);
return FALSE;
}
} else {
/* If parent is NULL, the parent must be specified via
* NMSettingWired:mac-address.
*/
if ( connection
&& (!s_wired || !nm_setting_wired_get_mac_address (s_wired))) {
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_MISSING_PROPERTY,
_("property is not specified and neither is '%s:%s'"),
NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_MAC_ADDRESS);
g_prefix_error (error, "%s.%s: ", NM_SETTING_MACVLAN_SETTING_NAME, NM_SETTING_MACVLAN_PARENT);
return FALSE;
}
}
if (!priv->promiscuous && priv->mode != NM_SETTING_MACVLAN_MODE_PASSTHRU) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("non promiscuous operation is allowed only in passthru mode'"));
g_prefix_error (error, "%s.%s: ",
NM_SETTING_MACVLAN_SETTING_NAME,
NM_SETTING_MACVLAN_PROMISCUOUS);
return FALSE;
}
return TRUE;
}
static void
set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
NMSettingMacvlan *setting = NM_SETTING_MACVLAN (object);
NMSettingMacvlanPrivate *priv = NM_SETTING_MACVLAN_GET_PRIVATE (setting);
switch (prop_id) {
case PROP_PARENT:
g_free (priv->parent);
priv->parent = g_value_dup_string (value);
break;
case PROP_MODE:
priv->mode = g_value_get_uint (value);
break;
case PROP_PROMISCUOUS:
priv->promiscuous = g_value_get_boolean (value);
break;
case PROP_TAP:
priv->tap = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
NMSettingMacvlan *setting = NM_SETTING_MACVLAN (object);
NMSettingMacvlanPrivate *priv = NM_SETTING_MACVLAN_GET_PRIVATE (setting);
switch (prop_id) {
case PROP_PARENT:
g_value_set_string (value, priv->parent);
break;
case PROP_MODE:
g_value_set_uint (value, priv->mode);
break;
case PROP_PROMISCUOUS:
g_value_set_boolean (value, priv->promiscuous);
break;
case PROP_TAP:
g_value_set_boolean (value, priv->tap);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
finalize (GObject *object)
{
NMSettingMacvlan *setting = NM_SETTING_MACVLAN (object);
NMSettingMacvlanPrivate *priv = NM_SETTING_MACVLAN_GET_PRIVATE (setting);
g_free (priv->parent);
G_OBJECT_CLASS (nm_setting_macvlan_parent_class)->finalize (object);
}
static void
nm_setting_macvlan_class_init (NMSettingMacvlanClass *setting_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (setting_class);
NMSettingClass *parent_class = NM_SETTING_CLASS (setting_class);
g_type_class_add_private (setting_class, sizeof (NMSettingMacvlanPrivate));
/* virtual methods */
object_class->set_property = set_property;
object_class->get_property = get_property;
object_class->finalize = finalize;
parent_class->verify = verify;
/* Properties */
/**
* NMSettingMacvlan:parent:
*
* If given, specifies the parent interface name or parent connection UUID
* from which this MAC-VLAN interface should be created. If this property is
* not specified, the connection must contain an #NMSettingWired setting
* with a #NMSettingWired:mac-address property.
*
* Since: 1.2
**/
g_object_class_install_property
(object_class, PROP_PARENT,
g_param_spec_string (NM_SETTING_MACVLAN_PARENT, "", "",
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
NM_SETTING_PARAM_INFERRABLE |
G_PARAM_STATIC_STRINGS));
/**
* NMSettingMacvlan:mode:
*
* The macvlan mode, which specifies the communication mechanism between multiple
* macvlans on the same lower device.
*
* Since: 1.2
**/
g_object_class_install_property
(object_class, PROP_MODE,
g_param_spec_uint (NM_SETTING_MACVLAN_MODE, "", "",
0, G_MAXUINT, 0,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
NM_SETTING_PARAM_INFERRABLE |
G_PARAM_STATIC_STRINGS));
/**
* NMSettingMacvlan:promiscuous:
*
* Whether the interface should be put in promiscuous mode.
*
* Since: 1.2
**/
g_object_class_install_property
(object_class, PROP_PROMISCUOUS,
g_param_spec_boolean (NM_SETTING_MACVLAN_PROMISCUOUS, "", "",
TRUE,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
NM_SETTING_PARAM_INFERRABLE |
G_PARAM_STATIC_STRINGS));
/**
* NMSettingMacvlan:tap:
*
* Whether the interface should be a MACVTAP.
*
* Since: 1.2
**/
g_object_class_install_property
(object_class, PROP_TAP,
g_param_spec_boolean (NM_SETTING_MACVLAN_TAP, "", "",
FALSE,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
NM_SETTING_PARAM_INFERRABLE |
G_PARAM_STATIC_STRINGS));
}

View file

@ -0,0 +1,94 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* Copyright 2015 Red Hat, Inc.
*/
#ifndef __NM_SETTING_MACVLAN_H__
#define __NM_SETTING_MACVLAN_H__
#if !defined (__NETWORKMANAGER_H_INSIDE__) && !defined (NETWORKMANAGER_COMPILATION)
#error "Only <NetworkManager.h> can be included directly."
#endif
#include "nm-setting.h"
G_BEGIN_DECLS
#define NM_TYPE_SETTING_MACVLAN (nm_setting_macvlan_get_type ())
#define NM_SETTING_MACVLAN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTING_MACVLAN, NMSettingMacvlan))
#define NM_SETTING_MACVLAN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SETTING_MACVLANCONFIG, NMSettingMacvlanClass))
#define NM_IS_SETTING_MACVLAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTING_MACVLAN))
#define NM_IS_SETTING_MACVLAN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SETTING_MACVLAN))
#define NM_SETTING_MACVLAN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SETTING_MACVLAN, NMSettingMacvlanClass))
#define NM_SETTING_MACVLAN_SETTING_NAME "macvlan"
#define NM_SETTING_MACVLAN_PARENT "parent"
#define NM_SETTING_MACVLAN_MODE "mode"
#define NM_SETTING_MACVLAN_PROMISCUOUS "promiscuous"
#define NM_SETTING_MACVLAN_TAP "tap"
struct _NMSettingMacvlan {
NMSetting parent;
};
typedef struct {
NMSettingClass parent;
/*< private >*/
gpointer padding[4];
} NMSettingMacvlanClass;
/**
* NMSettingMacvlanMode:
* @NM_SETTING_MACVLAN_MODE_UNKNOWN: unknown/unset mode
* @NM_SETTING_MACVLAN_MODE_VEPA: Virtual Ethernet Port Aggregator mode
* @NM_SETTING_MACVLAN_MODE_BRIDGE: bridge mode
* @NM_SETTING_MACVLAN_MODE_PRIVATE: private mode
* @NM_SETTING_MACVLAN_MODE_PASSTHRU: passthru mode
* @NM_SETTING_MACVLAN_MODE_SOURCE: source mode
**/
typedef enum {
NM_SETTING_MACVLAN_MODE_UNKNOWN = 0,
NM_SETTING_MACVLAN_MODE_VEPA = 1,
NM_SETTING_MACVLAN_MODE_BRIDGE = 2,
NM_SETTING_MACVLAN_MODE_PRIVATE = 3,
NM_SETTING_MACVLAN_MODE_PASSTHRU = 4,
NM_SETTING_MACVLAN_MODE_SOURCE = 5,
_NM_SETTING_MACVLAN_MODE_NUM, /*< skip >*/
NM_SETTING_MACVLAN_MODE_LAST = _NM_SETTING_MACVLAN_MODE_NUM - 1, /*< skip >*/
} NMSettingMacvlanMode;
NM_AVAILABLE_IN_1_2
GType nm_setting_macvlan_get_type (void);
NM_AVAILABLE_IN_1_2
NMSetting *nm_setting_macvlan_new (void);
NM_AVAILABLE_IN_1_2
const char *nm_setting_macvlan_get_parent (NMSettingMacvlan *setting);
NM_AVAILABLE_IN_1_2
NMSettingMacvlanMode nm_setting_macvlan_get_mode (NMSettingMacvlan *setting);
NM_AVAILABLE_IN_1_2
gboolean nm_setting_macvlan_get_promiscuous (NMSettingMacvlan *setting);
NM_AVAILABLE_IN_1_2
gboolean nm_setting_macvlan_get_tap (NMSettingMacvlan *setting);
G_END_DECLS
#endif /* __NM_SETTING_MACVLAN_H__ */

View file

@ -39,6 +39,7 @@ libnminclude_hfiles = \
nm-device-generic.h \
nm-device-infiniband.h \
nm-device-ip-tunnel.h \
nm-device-macvlan.h \
nm-device-modem.h \
nm-device-olpc-mesh.h \
nm-device-team.h \
@ -92,6 +93,7 @@ libnm_la_csources = \
nm-device-generic.c \
nm-device-infiniband.c \
nm-device-ip-tunnel.c \
nm-device-macvlan.c \
nm-device-modem.c \
nm-device-olpc-mesh.c \
nm-device-team.c \

View file

@ -64,6 +64,7 @@
#include <nm-setting-ip-tunnel.h>
#include <nm-setting-ip4-config.h>
#include <nm-setting-ip6-config.h>
#include <nm-setting-macvlan.h>
#include <nm-setting-olpc-mesh.h>
#include <nm-setting-ppp.h>
#include <nm-setting-pppoe.h>

View file

@ -859,6 +859,7 @@ libnm_1_2_0 {
global:
nm_access_point_get_last_seen;
nm_connection_get_setting_ip_tunnel;
nm_connection_get_setting_macvlan;
nm_connection_verify_secrets;
nm_device_ethernet_get_s390_subchannels;
nm_client_get_all_devices;
@ -876,6 +877,12 @@ global:
nm_device_ip_tunnel_get_tos;
nm_device_ip_tunnel_get_ttl;
nm_device_ip_tunnel_get_type;
nm_device_macvlan_get_hw_address;
nm_device_macvlan_get_mode;
nm_device_macvlan_get_no_promisc;
nm_device_macvlan_get_parent;
nm_device_macvlan_get_tap;
nm_device_macvlan_get_type;
nm_device_get_nm_plugin_missing;
nm_device_is_real;
nm_device_set_managed;
@ -944,6 +951,13 @@ global:
nm_setting_tun_new;
nm_setting_verify_secrets;
nm_setting_vpn_get_timeout;
nm_setting_macvlan_get_mode;
nm_setting_macvlan_get_parent;
nm_setting_macvlan_get_promiscuous;
nm_setting_macvlan_get_tap;
nm_setting_macvlan_get_type;
nm_setting_macvlan_mode_get_type;
nm_setting_macvlan_new;
nm_setting_wired_get_wake_on_lan;
nm_setting_wired_get_wake_on_lan_password;
nm_setting_wired_wake_on_lan_get_type;

347
libnm/nm-device-macvlan.c Normal file
View file

@ -0,0 +1,347 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* Copyright 2015 Red Hat, Inc.
*/
#include "config.h"
#include <string.h>
#include <nm-setting-connection.h>
#include <nm-setting-macvlan.h>
#include <nm-setting-wired.h>
#include <nm-utils.h>
#include "nm-default.h"
#include "nm-device-macvlan.h"
#include "nm-device-private.h"
#include "nm-object-private.h"
G_DEFINE_TYPE (NMDeviceMacvlan, nm_device_macvlan, NM_TYPE_DEVICE)
#define NM_DEVICE_MACVLAN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_MACVLAN, NMDeviceMacvlanPrivate))
typedef struct {
NMDevice *parent;
char *mode;
gboolean no_promisc;
gboolean tap;
char *hw_address;
} NMDeviceMacvlanPrivate;
enum {
PROP_0,
PROP_PARENT,
PROP_MODE,
PROP_NO_PROMISC,
PROP_TAP,
PROP_HW_ADDRESS,
LAST_PROP
};
/**
* nm_device_macvlan_get_parent:
* @device: a #NMDeviceMacvlan
*
* Returns: (transfer none): the device's parent device
*
* Since: 1.2
**/
NMDevice *
nm_device_macvlan_get_parent (NMDeviceMacvlan *device)
{
g_return_val_if_fail (NM_IS_DEVICE_MACVLAN (device), FALSE);
return NM_DEVICE_MACVLAN_GET_PRIVATE (device)->parent;
}
/**
* nm_device_macvlan_get_mode:
* @device: a #NMDeviceMacvlan
*
* Gets the MACVLAN mode of the device.
*
* Returns: the MACVLAN mode. This is the internal string used by the
* device, and must not be modified.
*
* Since: 1.2
**/
const char *
nm_device_macvlan_get_mode (NMDeviceMacvlan *device)
{
g_return_val_if_fail (NM_IS_DEVICE_MACVLAN (device), NULL);
return NM_DEVICE_MACVLAN_GET_PRIVATE (device)->mode;
}
/**
* nm_device_macvlan_get_no_promisc
* @device: a #NMDeviceMacvlan
*
* Gets the no-promiscuous flag of the device.
*
* Returns: the no-promiscuous flag of the device.
*
* Since: 1.2
**/
gboolean
nm_device_macvlan_get_no_promisc (NMDeviceMacvlan *device)
{
g_return_val_if_fail (NM_IS_DEVICE_MACVLAN (device), FALSE);
return NM_DEVICE_MACVLAN_GET_PRIVATE (device)->no_promisc;
}
/**
* nm_device_macvlan_get_tap:
* @device: a #NMDeviceMacvlan
*
* Gets the device type (MACVLAN or MACVTAP).
*
* Returns: %TRUE if the device is a MACVTAP, %FALSE if it is a MACVLAN.
*
* Since: 1.2
**/
gboolean
nm_device_macvlan_get_tap (NMDeviceMacvlan *device)
{
g_return_val_if_fail (NM_IS_DEVICE_MACVLAN (device), FALSE);
return NM_DEVICE_MACVLAN_GET_PRIVATE (device)->tap;
}
/**
* nm_device_macvlan_get_hw_address:
* @device: a #NMDeviceMacvlan
*
* Gets the hardware (MAC) address of the #NMDeviceMacvlan
*
* Returns: the hardware address. This is the internal string used by the
* device, and must not be modified.
*
* Since: 1.2
**/
const char *
nm_device_macvlan_get_hw_address (NMDeviceMacvlan *device)
{
g_return_val_if_fail (NM_IS_DEVICE_MACVLAN (device), NULL);
return NM_DEVICE_MACVLAN_GET_PRIVATE (device)->hw_address;
}
static gboolean
connection_compatible (NMDevice *device, NMConnection *connection, GError **error)
{
NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (device);
NMSettingMacvlan *s_macvlan;
if (!NM_DEVICE_CLASS (nm_device_macvlan_parent_class)->connection_compatible (device, connection, error))
return FALSE;
if (!nm_connection_is_type (connection, NM_SETTING_MACVLAN_SETTING_NAME)) {
g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
_("The connection was not a MAC-VLAN connection."));
return FALSE;
}
s_macvlan = nm_connection_get_setting_macvlan (connection);
if (s_macvlan) {
if (nm_setting_macvlan_get_tap (s_macvlan) != priv->tap)
return FALSE;
}
return TRUE;
}
static const char *
get_hw_address (NMDevice *device)
{
return nm_device_macvlan_get_hw_address (NM_DEVICE_MACVLAN (device));
}
static GType
get_setting_type (NMDevice *device)
{
return NM_TYPE_SETTING_MACVLAN;
}
/***********************************************************/
static void
nm_device_macvlan_init (NMDeviceMacvlan *device)
{
_nm_device_set_device_type (NM_DEVICE (device), NM_DEVICE_TYPE_MACVLAN);
}
static void
init_dbus (NMObject *object)
{
NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (object);
const NMPropertiesInfo property_info[] = {
{ NM_DEVICE_MACVLAN_PARENT, &priv->parent, NULL, NM_TYPE_DEVICE },
{ NM_DEVICE_MACVLAN_MODE, &priv->mode },
{ NM_DEVICE_MACVLAN_NO_PROMISC, &priv->no_promisc },
{ NM_DEVICE_MACVLAN_TAP, &priv->tap },
{ NM_DEVICE_MACVLAN_HW_ADDRESS, &priv->hw_address },
{ NULL },
};
NM_OBJECT_CLASS (nm_device_macvlan_parent_class)->init_dbus (object);
_nm_object_register_properties (object,
NM_DBUS_INTERFACE_DEVICE_MACVLAN,
property_info);
}
static void
finalize (GObject *object)
{
NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (object);
g_free (priv->mode);
g_free (priv->hw_address);
g_clear_object (&priv->parent);
G_OBJECT_CLASS (nm_device_macvlan_parent_class)->finalize (object);
}
static void
get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
NMDeviceMacvlan *device = NM_DEVICE_MACVLAN (object);
switch (prop_id) {
case PROP_PARENT:
g_value_set_object (value, nm_device_macvlan_get_parent (device));
break;
case PROP_MODE:
g_value_set_string (value, nm_device_macvlan_get_mode (device));
break;
case PROP_NO_PROMISC:
g_value_set_boolean (value, nm_device_macvlan_get_no_promisc (device));
break;
case PROP_TAP:
g_value_set_boolean (value, nm_device_macvlan_get_tap (device));
break;
case PROP_HW_ADDRESS:
g_value_set_string (value, nm_device_macvlan_get_hw_address (device));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
nm_device_macvlan_class_init (NMDeviceMacvlanClass *gre_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (gre_class);
NMObjectClass *nm_object_class = NM_OBJECT_CLASS (gre_class);
NMDeviceClass *device_class = NM_DEVICE_CLASS (gre_class);
g_type_class_add_private (gre_class, sizeof (NMDeviceMacvlanPrivate));
_nm_object_class_add_interface (nm_object_class, NM_DBUS_INTERFACE_DEVICE_MACVLAN);
/* virtual methods */
object_class->finalize = finalize;
object_class->get_property = get_property;
nm_object_class->init_dbus = init_dbus;
device_class->connection_compatible = connection_compatible;
device_class->get_setting_type = get_setting_type;
device_class->get_hw_address = get_hw_address;
/* properties */
/**
* NMDeviceMacvlan:parent:
*
* The devices's parent device.
*
* Since: 1.2
**/
g_object_class_install_property
(object_class, PROP_PARENT,
g_param_spec_object (NM_DEVICE_MACVLAN_PARENT, "", "",
NM_TYPE_DEVICE,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
/**
* NMDeviceMacvlan:mode:
*
* The MACVLAN mode.
*
* Since: 1.2
**/
g_object_class_install_property
(object_class, PROP_MODE,
g_param_spec_string (NM_DEVICE_MACVLAN_MODE, "", "",
NULL,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
/**
* NMDeviceMacvlan:no-promisc:
*
* Whether the device has the no-promiscuos flag.
*
* Since: 1.2
**/
g_object_class_install_property
(object_class, PROP_NO_PROMISC,
g_param_spec_boolean (NM_DEVICE_MACVLAN_NO_PROMISC, "", "",
FALSE,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
/**
* NMDeviceMacvlan:tap:
*
* Whether the device is a MACVTAP.
*
* Since: 1.2
**/
g_object_class_install_property
(object_class, PROP_TAP,
g_param_spec_boolean (NM_DEVICE_MACVLAN_TAP, "", "",
FALSE,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
/**
* NMDeviceMacvlan:hw-address:
*
* The hardware (MAC) address of the device.
*
* Since: 1.2
**/
g_object_class_install_property
(object_class, PROP_HW_ADDRESS,
g_param_spec_string (NM_DEVICE_MACVLAN_HW_ADDRESS, "", "",
NULL,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
}

72
libnm/nm-device-macvlan.h Normal file
View file

@ -0,0 +1,72 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* Copyright 2015 Red Hat, Inc.
*/
#ifndef __NM_DEVICE_MACVLAN_H__
#define __NM_DEVICE_MACVLAN_H__
#if !defined (__NETWORKMANAGER_H_INSIDE__) && !defined(NETWORKMANAGER_COMPILATION)
#error "Only <NetworkManager.h> can be included directly."
#endif
#include <nm-device.h>
G_BEGIN_DECLS
#define NM_TYPE_DEVICE_MACVLAN (nm_device_macvlan_get_type ())
#define NM_DEVICE_MACVLAN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_MACVLAN, NMDeviceMacvlan))
#define NM_DEVICE_MACVLAN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_MACVLAN, NMDeviceMacvlanClass))
#define NM_IS_DEVICE_MACVLAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_MACVLAN))
#define NM_IS_DEVICE_MACVLAN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_MACVLAN))
#define NM_DEVICE_MACVLAN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_MACVLAN, NMDeviceMacvlanClass))
#define NM_DEVICE_MACVLAN_PARENT "parent"
#define NM_DEVICE_MACVLAN_MODE "mode"
#define NM_DEVICE_MACVLAN_NO_PROMISC "no-promisc"
#define NM_DEVICE_MACVLAN_TAP "tap"
#define NM_DEVICE_MACVLAN_HW_ADDRESS "hw-address"
struct _NMDeviceMacvlan {
NMDevice parent;
};
typedef struct {
NMDeviceClass parent;
/*< private >*/
gpointer padding[4];
} NMDeviceMacvlanClass;
NM_AVAILABLE_IN_1_2
GType nm_device_macvlan_get_type (void);
NM_AVAILABLE_IN_1_2
NMDevice * nm_device_macvlan_get_parent (NMDeviceMacvlan *device);
NM_AVAILABLE_IN_1_2
const char * nm_device_macvlan_get_mode (NMDeviceMacvlan *device);
NM_AVAILABLE_IN_1_2
gboolean nm_device_macvlan_get_no_promisc (NMDeviceMacvlan *device);
NM_AVAILABLE_IN_1_2
gboolean nm_device_macvlan_get_tap (NMDeviceMacvlan *device);
NM_AVAILABLE_IN_1_2
const char * nm_device_macvlan_get_hw_address (NMDeviceMacvlan *device);
G_END_DECLS
#endif /* __NM_DEVICE_MACVLAN_H__ */

View file

@ -42,6 +42,7 @@
#include "nm-device-vlan.h"
#include "nm-device-generic.h"
#include "nm-device-ip-tunnel.h"
#include "nm-device-macvlan.h"
#include "nm-device.h"
#include "nm-device-private.h"
#include "nm-dhcp4-config.h"
@ -371,6 +372,8 @@ _nm_device_gtype_from_dtype (NMDeviceType dtype)
return NM_TYPE_DEVICE_TUN;
case NM_DEVICE_TYPE_IP_TUNNEL:
return NM_TYPE_DEVICE_IP_TUNNEL;
case NM_DEVICE_TYPE_MACVLAN:
return NM_TYPE_DEVICE_MACVLAN;
default:
g_warning ("Unknown device type %d", dtype);
return G_TYPE_INVALID;

View file

@ -38,6 +38,7 @@ typedef struct _NMDeviceEthernet NMDeviceEthernet;
typedef struct _NMDeviceGeneric NMDeviceGeneric;
typedef struct _NMDeviceInfiniband NMDeviceInfiniband;
typedef struct _NMDeviceIPTunnel NMDeviceIPTunnel;
typedef struct _NMDeviceMacvlan NMDeviceMacvlan;
typedef struct _NMDeviceModem NMDeviceModem;
typedef struct _NMDeviceOlpcMesh NMDeviceOlpcMesh;
typedef struct _NMDeviceTeam NMDeviceTeam;

View file

@ -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

View file

@ -67,6 +67,7 @@ libnm-core/nm-setting-ip-config.c
libnm-core/nm-setting-ip4-config.c
libnm-core/nm-setting-ip6-config.c
libnm-core/nm-setting-ip-tunnel.c
libnm-core/nm-setting-macvlan.c
libnm-core/nm-setting-olpc-mesh.c
libnm-core/nm-setting-ppp.c
libnm-core/nm-setting-pppoe.c
@ -122,6 +123,7 @@ libnm/nm-device-generic.c
libnm/nm-device-tun.c
libnm/nm-device-infiniband.c
libnm/nm-device-ip-tunnel.c
libnm/nm-device-macvlan.c
libnm/nm-device-modem.c
libnm/nm-device-olpc-mesh.c
libnm/nm-device-team.c
@ -152,6 +154,7 @@ src/devices/nm-device-ethernet.c
src/devices/nm-device-ethernet-utils.c
src/devices/nm-device-infiniband.c
src/devices/nm-device-ip-tunnel.c
src/devices/nm-device-macvlan.c
src/devices/nm-device-tun.c
src/devices/nm-device-vlan.c
src/devices/team/nm-device-team.c

View file

@ -15,31 +15,40 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright 2013 Red Hat, Inc.
* Copyright 2013 - 2015 Red Hat, Inc.
*/
#include "config.h"
#include <string.h>
#include "nm-default.h"
#include "nm-device-macvlan.h"
#include "nm-device-private.h"
#include "nm-default.h"
#include "nm-connection-provider.h"
#include "nm-activation-request.h"
#include "nm-manager.h"
#include "nm-platform.h"
#include "nm-device-factory.h"
#include "nm-setting-macvlan.h"
#include "nm-setting-wired.h"
#include "nm-active-connection.h"
#include "nm-ip4-config.h"
#include "nm-utils.h"
#include "nmdbus-device-macvlan.h"
#include "nm-device-logging.h"
_LOG_DECLARE_SELF(NMDeviceMacvlan);
G_DEFINE_TYPE (NMDeviceMacvlan, nm_device_macvlan, NM_TYPE_DEVICE_GENERIC)
G_DEFINE_TYPE (NMDeviceMacvlan, nm_device_macvlan, NM_TYPE_DEVICE)
#define NM_DEVICE_MACVLAN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_MACVLAN, NMDeviceMacvlanPrivate))
typedef struct {
int parent_ifindex;
guint parent_state_id;
NMDevice *parent;
NMPlatformLnkMacvlan props;
} NMDeviceMacvlanPrivate;
@ -48,14 +57,114 @@ enum {
PROP_PARENT,
PROP_MODE,
PROP_NO_PROMISC,
PROP_TAP,
LAST_PROP
};
/**************************************************************/
static int modes[][2] = {
{ NM_SETTING_MACVLAN_MODE_VEPA, MACVLAN_MODE_VEPA },
{ NM_SETTING_MACVLAN_MODE_BRIDGE, MACVLAN_MODE_BRIDGE },
{ NM_SETTING_MACVLAN_MODE_PRIVATE, MACVLAN_MODE_PRIVATE },
{ NM_SETTING_MACVLAN_MODE_PASSTHRU, MACVLAN_MODE_PASSTHRU },
};
static int
setting_mode_to_platform (int mode)
{
guint i;
for (i = 0; i < G_N_ELEMENTS (modes); i++) {
if (modes[i][0] == mode)
return modes[i][1];
}
return 0;
}
static int
platform_mode_to_setting (int mode)
{
guint i;
for (i = 0; i < G_N_ELEMENTS (modes); i++) {
if (modes[i][1] == mode)
return modes[i][0];
}
return 0;
}
static const char *
platform_mode_to_string (guint mode)
{
switch (mode) {
case MACVLAN_MODE_PRIVATE:
return "private";
case MACVLAN_MODE_VEPA:
return "vepa";
case MACVLAN_MODE_BRIDGE:
return "bridge";
case MACVLAN_MODE_PASSTHRU:
return "passthru";
default:
return "unknown";
}
}
/**************************************************************/
static void
parent_state_changed (NMDevice *parent,
NMDeviceState new_state,
NMDeviceState old_state,
NMDeviceStateReason reason,
gpointer user_data)
{
NMDeviceMacvlan *self = NM_DEVICE_MACVLAN (user_data);
/* We'll react to our own carrier state notifications. Ignore the parent's. */
if (reason == NM_DEVICE_STATE_REASON_CARRIER)
return;
nm_device_set_unmanaged_flags (NM_DEVICE (self), NM_UNMANAGED_PARENT, !nm_device_get_managed (parent), reason);
}
static void
nm_device_macvlan_set_parent (NMDeviceMacvlan *self, NMDevice *parent)
{
NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (self);
NMDevice *device = NM_DEVICE (self);
if (parent == priv->parent)
return;
if (priv->parent_state_id)
nm_clear_g_signal_handler (priv->parent, &priv->parent_state_id);
g_clear_object (&priv->parent);
if (parent) {
priv->parent = g_object_ref (parent);
priv->parent_state_id = g_signal_connect (priv->parent,
"state-changed",
G_CALLBACK (parent_state_changed),
device);
/* Set parent-dependent unmanaged flag */
nm_device_set_unmanaged_flags (device,
NM_UNMANAGED_PARENT,
!nm_device_get_managed (parent),
NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED);
}
/* Recheck availability now that the parent has changed */
nm_device_queue_recheck_available (self,
NM_DEVICE_STATE_REASON_PARENT_CHANGED,
NM_DEVICE_STATE_REASON_PARENT_CHANGED);
g_object_notify (G_OBJECT (device), NM_DEVICE_MACVLAN_PARENT);
}
static void
update_properties (NMDevice *device)
{
@ -64,18 +173,25 @@ update_properties (NMDevice *device)
GObject *object = G_OBJECT (device);
const NMPlatformLnkMacvlan *props;
const NMPlatformLink *plink;
NMDevice *parent = NULL;
if (priv->props.tap)
props = nm_platform_link_get_lnk_macvtap (NM_PLATFORM_GET, nm_device_get_ifindex (device), &plink);
else
props = nm_platform_link_get_lnk_macvlan (NM_PLATFORM_GET, nm_device_get_ifindex (device), &plink);
props = nm_platform_link_get_lnk_macvlan (NM_PLATFORM_GET, nm_device_get_ifindex (device), &plink);
if (!props) {
_LOGW (LOGD_HW, "could not get macvlan properties");
_LOGW (LOGD_HW, "could not get %s properties", priv->props.tap ? "macvtap" : "macvlan");
return;
}
g_object_freeze_notify (object);
if (priv->parent_ifindex != plink->parent)
g_object_notify (object, NM_DEVICE_MACVLAN_PARENT);
if (g_strcmp0 (priv->props.mode, props->mode) != 0)
if (priv->parent_ifindex != plink->parent) {
parent = nm_manager_get_device_by_ifindex (nm_manager_get (), plink->parent);
nm_device_macvlan_set_parent (self, parent);
}
if (priv->props.mode != props->mode)
g_object_notify (object, NM_DEVICE_MACVLAN_MODE);
if (priv->props.no_promisc != props->no_promisc)
g_object_notify (object, NM_DEVICE_MACVLAN_NO_PROMISC);
@ -93,21 +209,380 @@ link_changed (NMDevice *device, NMPlatformLink *info)
update_properties (device);
}
static gboolean
realize (NMDevice *device, NMPlatformLink *plink, GError **error)
{
update_properties (device);
return TRUE;
}
static gboolean
create_and_realize (NMDevice *device,
NMConnection *connection,
NMDevice *parent,
NMPlatformLink *out_plink,
GError **error)
{
const char *iface = nm_device_get_iface (device);
NMPlatformError plerr;
NMSettingMacvlan *s_macvlan;
NMPlatformLnkMacvlan lnk = { };
int parent_ifindex;
s_macvlan = nm_connection_get_setting_macvlan (connection);
g_assert (s_macvlan);
g_assert (out_plink);
parent_ifindex = nm_device_get_ifindex (parent);
g_warn_if_fail (parent_ifindex > 0);
lnk.mode = setting_mode_to_platform (nm_setting_macvlan_get_mode (s_macvlan));
if (!lnk.mode) {
nm_log_info (LOGD_DEVICE, "unsupported MACVLAN mode %u in connection %s",
nm_setting_macvlan_get_mode (s_macvlan),
nm_connection_get_uuid (connection));
return FALSE;
}
lnk.no_promisc = !nm_setting_macvlan_get_promiscuous (s_macvlan);
lnk.tap = nm_setting_macvlan_get_tap (s_macvlan);
plerr = nm_platform_link_macvlan_add (NM_PLATFORM_GET, iface, parent_ifindex, &lnk, out_plink);
if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) {
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
"Failed to create %s interface '%s' for '%s': %s",
lnk.tap ? "macvtap" : "macvlan",
iface,
nm_connection_get_id (connection),
nm_platform_error_to_string (plerr));
return FALSE;
}
return TRUE;
}
/******************************************************************/
static NMDeviceCapabilities
get_generic_capabilities (NMDevice *dev)
{
/* We assume MACVLAN interfaces always support carrier detect */
return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_IS_SOFTWARE;
}
static gboolean
bring_up (NMDevice *dev, gboolean *no_firmware)
{
gboolean success = FALSE;
guint i = 20;
while (i-- > 0 && !success) {
success = NM_DEVICE_CLASS (nm_device_macvlan_parent_class)->bring_up (dev, no_firmware);
g_usleep (50);
}
return success;
}
/******************************************************************/
static gboolean
is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags)
{
if (!NM_DEVICE_MACVLAN_GET_PRIVATE (device)->parent)
return FALSE;
return NM_DEVICE_CLASS (nm_device_macvlan_parent_class)->is_available (device, flags);
}
static void
notify_new_device_added (NMDevice *device, NMDevice *new_device)
{
NMDeviceMacvlan *self = NM_DEVICE_MACVLAN (device);
NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (self);
if (priv->parent)
return;
if (!nm_device_is_real (device))
return;
update_properties (device);
if ( priv->parent_ifindex <= 0
|| nm_device_get_ifindex (new_device) != priv->parent_ifindex)
return;
priv->parent_ifindex = nm_device_get_ifindex (new_device);
nm_device_macvlan_set_parent (self, new_device);
}
/**************************************************************/
static gboolean
match_parent (NMDeviceMacvlan *self, const char *parent)
{
NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (self);
g_return_val_if_fail (parent != NULL, FALSE);
if (!priv->parent)
return FALSE;
if (nm_utils_is_uuid (parent)) {
NMActRequest *parent_req;
NMConnection *parent_connection;
/* If the parent is a UUID, the connection matches if our parent
* device has that connection activated.
*/
parent_req = nm_device_get_act_request (priv->parent);
if (!parent_req)
return FALSE;
parent_connection = nm_active_connection_get_applied_connection (NM_ACTIVE_CONNECTION (parent_req));
if (!parent_connection)
return FALSE;
if (g_strcmp0 (parent, nm_connection_get_uuid (parent_connection)) != 0)
return FALSE;
} else {
/* interface name */
if (g_strcmp0 (parent, nm_device_get_ip_iface (priv->parent)) != 0)
return FALSE;
}
return TRUE;
}
static gboolean
match_hwaddr (NMDevice *device, NMConnection *connection, gboolean fail_if_no_hwaddr)
{
NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (device);
NMSettingWired *s_wired;
const char *setting_mac;
const char *parent_mac;
s_wired = nm_connection_get_setting_wired (connection);
if (!s_wired)
return !fail_if_no_hwaddr;
setting_mac = nm_setting_wired_get_mac_address (s_wired);
if (!setting_mac)
return !fail_if_no_hwaddr;
if (!priv->parent)
return !fail_if_no_hwaddr;
parent_mac = nm_device_get_hw_address (priv->parent);
return nm_utils_hwaddr_matches (setting_mac, -1, parent_mac, -1);
}
static gboolean
check_connection_compatible (NMDevice *device, NMConnection *connection)
{
NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (device);
NMSettingMacvlan *s_macvlan;
const char *parent, *iface = NULL;
if (!NM_DEVICE_CLASS (nm_device_macvlan_parent_class)->check_connection_compatible (device, connection))
return FALSE;
s_macvlan = nm_connection_get_setting_macvlan (connection);
if (!s_macvlan)
return FALSE;
if (nm_setting_macvlan_get_tap (s_macvlan) != priv->props.tap)
return FALSE;
/* Before the device is realized some properties will not be set */
if (nm_device_is_real (device)) {
if (setting_mode_to_platform (nm_setting_macvlan_get_mode (s_macvlan)) != priv->props.mode)
return FALSE;
if (nm_setting_macvlan_get_promiscuous (s_macvlan) == priv->props.no_promisc)
return FALSE;
/* Check parent interface; could be an interface name or a UUID */
parent = nm_setting_macvlan_get_parent (s_macvlan);
if (parent) {
if (!match_parent (NM_DEVICE_MACVLAN (device), parent))
return FALSE;
} else {
/* Parent could be a MAC address in an NMSettingWired */
if (!match_hwaddr (device, connection, TRUE))
return FALSE;
}
}
/* Ensure the interface name matches */
iface = nm_connection_get_interface_name (connection);
if (iface) {
if (g_strcmp0 (nm_device_get_ip_iface (device), iface) != 0)
return FALSE;
}
return TRUE;
}
static gboolean
complete_connection (NMDevice *device,
NMConnection *connection,
const char *specific_object,
const GSList *existing_connections,
GError **error)
{
NMSettingMacvlan *s_macvlan;
nm_utils_complete_generic (connection,
NM_SETTING_MACVLAN_SETTING_NAME,
existing_connections,
NULL,
_("MACVLAN connection"),
NULL,
TRUE);
s_macvlan = nm_connection_get_setting_macvlan (connection);
if (!s_macvlan) {
g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION,
"A 'macvlan' setting is required.");
return FALSE;
}
/* If there's no MACVLAN interface, no parent, and no hardware address in the
* settings, then there's not enough information to complete the setting.
*/
if ( !nm_setting_macvlan_get_parent (s_macvlan)
&& !match_hwaddr (device, connection, TRUE)) {
g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION,
"The 'macvlan' setting had no interface name, parent, or hardware address.");
return FALSE;
}
return TRUE;
}
static void
update_connection (NMDevice *device, NMConnection *connection)
{
NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (device);
NMSettingMacvlan *s_macvlan = nm_connection_get_setting_macvlan (connection);
const char *setting_parent, *new_parent;
int new_mode;
if (!s_macvlan) {
s_macvlan = (NMSettingMacvlan *) nm_setting_macvlan_new ();
nm_connection_add_setting (connection, (NMSetting *) s_macvlan);
}
new_mode = platform_mode_to_setting (priv->props.mode);
if (new_mode != nm_setting_macvlan_get_mode (s_macvlan))
g_object_set (s_macvlan, NM_SETTING_MACVLAN_MODE, new_mode, NULL);
if (priv->props.no_promisc == nm_setting_macvlan_get_promiscuous (s_macvlan))
g_object_set (s_macvlan, NM_SETTING_MACVLAN_PROMISCUOUS, !priv->props.no_promisc, NULL);
if (priv->props.tap != nm_setting_macvlan_get_tap (s_macvlan))
g_object_set (s_macvlan, NM_SETTING_MACVLAN_TAP, !!priv->props.tap, NULL);
/* Update parent in the connection; default to parent's interface name */
if (priv->parent) {
new_parent = nm_device_get_iface (priv->parent);
setting_parent = nm_setting_macvlan_get_parent (s_macvlan);
if (setting_parent && nm_utils_is_uuid (setting_parent)) {
NMConnection *parent_connection;
/* Don't change a parent specified by UUID if it's still valid */
parent_connection = nm_connection_provider_get_connection_by_uuid (nm_connection_provider_get (), setting_parent);
if (parent_connection && nm_device_check_connection_compatible (priv->parent, parent_connection))
new_parent = NULL;
}
if (new_parent)
g_object_set (s_macvlan, NM_SETTING_MACVLAN_PARENT, new_parent, NULL);
} else
g_object_set (s_macvlan, NM_SETTING_MACVLAN_PARENT, NULL, NULL);
}
static NMActStageReturn
act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
{
NMActRequest *req;
NMConnection *connection;
NMSettingWired *s_wired;
const char *cloned_mac;
NMActStageReturn ret;
g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
ret = NM_DEVICE_CLASS (nm_device_macvlan_parent_class)->act_stage1_prepare (dev, reason);
if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
return ret;
req = nm_device_get_act_request (dev);
g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE);
connection = nm_act_request_get_applied_connection (req);
g_return_val_if_fail (connection != NULL, NM_ACT_STAGE_RETURN_FAILURE);
s_wired = nm_connection_get_setting_wired (connection);
if (s_wired) {
/* Set device MAC address if the connection wants to change it */
cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired);
if (cloned_mac)
nm_device_set_hw_addr (dev, cloned_mac, "set", LOGD_HW);
}
return TRUE;
}
static void
ip4_config_pre_commit (NMDevice *device, NMIP4Config *config)
{
NMConnection *connection;
NMSettingWired *s_wired;
guint32 mtu;
connection = nm_device_get_applied_connection (device);
g_assert (connection);
s_wired = nm_connection_get_setting_wired (connection);
if (s_wired) {
mtu = nm_setting_wired_get_mtu (s_wired);
if (mtu)
nm_ip4_config_set_mtu (config, mtu, NM_IP_CONFIG_SOURCE_USER);
}
}
static void
setup_start (NMDevice *device, NMPlatformLink *plink)
{
NM_DEVICE_CLASS (nm_device_macvlan_parent_class)->setup_start (device, plink);
update_properties (device);
}
static void
deactivate (NMDevice *device)
{
/* Reset MAC address back to initial address */
if (nm_device_get_initial_hw_address (device)) {
nm_device_set_hw_addr (device, nm_device_get_initial_hw_address (device),
"reset", LOGD_DEVICE);
}
}
/******************************************************************/
static void
nm_device_macvlan_init (NMDeviceMacvlan *self)
{
}
static void
constructed (GObject *object)
{
update_properties (NM_DEVICE (object));
G_OBJECT_CLASS (nm_device_macvlan_parent_class)->constructed (object);
}
static void
get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
@ -124,17 +599,35 @@ get_property (GObject *object, guint prop_id,
nm_utils_g_value_set_object_path (value, parent);
break;
case PROP_MODE:
g_value_set_string (value, priv->props.mode);
g_value_set_string (value, platform_mode_to_string (priv->props.mode));
break;
case PROP_NO_PROMISC:
g_value_set_boolean (value, priv->props.no_promisc);
break;
case PROP_TAP:
g_value_set_boolean (value, priv->props.tap);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (object);
switch (prop_id) {
case PROP_TAP:
priv->props.tap = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
nm_device_macvlan_class_init (NMDeviceMacvlanClass *klass)
{
@ -145,10 +638,24 @@ nm_device_macvlan_class_init (NMDeviceMacvlanClass *klass)
NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_MACVLAN, NM_LINK_TYPE_MACVTAP)
object_class->constructed = constructed;
object_class->get_property = get_property;
object_class->set_property = set_property;
device_class->act_stage1_prepare = act_stage1_prepare;
device_class->bring_up = bring_up;
device_class->check_connection_compatible = check_connection_compatible;
device_class->complete_connection = complete_connection;
device_class->connection_type = NM_SETTING_MACVLAN_SETTING_NAME;
device_class->create_and_realize = create_and_realize;
device_class->deactivate = deactivate;
device_class->get_generic_capabilities = get_generic_capabilities;
device_class->ip4_config_pre_commit = ip4_config_pre_commit;
device_class->is_available = is_available;
device_class->link_changed = link_changed;
device_class->notify_new_device_added = notify_new_device_added;
device_class->realize = realize;
device_class->setup_start = setup_start;
device_class->update_connection = update_connection;
/* properties */
g_object_class_install_property
@ -172,6 +679,14 @@ nm_device_macvlan_class_init (NMDeviceMacvlanClass *klass)
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_TAP,
g_param_spec_boolean (NM_DEVICE_MACVLAN_TAP, "", "",
FALSE,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass),
NMDBUS_TYPE_DEVICE_MACVLAN_SKELETON,
NULL);
@ -189,18 +704,79 @@ create_device (NMDeviceFactory *factory,
NMConnection *connection,
gboolean *out_ignore)
{
g_return_val_if_fail (plink, NULL);
NMSettingMacvlan *s_macvlan;
NMLinkType link_type;
gboolean tap;
if (connection) {
s_macvlan = nm_connection_get_setting_macvlan (connection);
g_assert (s_macvlan);
tap = nm_setting_macvlan_get_tap (s_macvlan);
} else {
g_assert (plink);
tap = plink->type == NM_LINK_TYPE_MACVTAP;
}
link_type = tap ? NM_LINK_TYPE_MACVTAP : NM_LINK_TYPE_MACVLAN;
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_MACVLAN,
NM_DEVICE_IFACE, iface,
NM_DEVICE_TYPE_DESC, "Macvlan",
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC,
NM_DEVICE_LINK_TYPE, plink->type,
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_MACVLAN,
NM_DEVICE_LINK_TYPE, link_type,
NM_DEVICE_MACVLAN_TAP, tap,
NULL);
}
static const char *
get_connection_parent (NMDeviceFactory *factory, NMConnection *connection)
{
NMSettingMacvlan *s_macvlan;
NMSettingWired *s_wired;
const char *parent = NULL;
g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_MACVLAN_SETTING_NAME), NULL);
s_macvlan = nm_connection_get_setting_macvlan (connection);
g_assert (s_macvlan);
parent = nm_setting_macvlan_get_parent (s_macvlan);
if (parent)
return parent;
/* Try the hardware address from the MACVLAN connection's hardware setting */
s_wired = nm_connection_get_setting_wired (connection);
if (s_wired)
return nm_setting_wired_get_mac_address (s_wired);
return NULL;
}
static char *
get_virtual_iface_name (NMDeviceFactory *factory,
NMConnection *connection,
const char *parent_iface)
{
NMSettingMacvlan *s_macvlan;
const char *ifname;
g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_MACVLAN_SETTING_NAME), NULL);
s_macvlan = nm_connection_get_setting_macvlan (connection);
g_assert (s_macvlan);
if (!parent_iface)
return NULL;
ifname = nm_connection_get_interface_name (connection);
return g_strdup (ifname);
}
NM_DEVICE_FACTORY_DEFINE_INTERNAL (MACVLAN, Macvlan, macvlan,
NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_MACVLAN, NM_LINK_TYPE_MACVTAP),
NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_MACVLAN, NM_LINK_TYPE_MACVTAP)
NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_MACVLAN_SETTING_NAME),
factory_iface->create_device = create_device;
factory_iface->get_connection_parent = get_connection_parent;
factory_iface->get_virtual_iface_name = get_virtual_iface_name;
)

View file

@ -21,7 +21,7 @@
#ifndef __NETWORKMANAGER_DEVICE_MACVLAN_H__
#define __NETWORKMANAGER_DEVICE_MACVLAN_H__
#include "nm-device-generic.h"
#include "nm-device.h"
G_BEGIN_DECLS
@ -35,9 +35,10 @@ G_BEGIN_DECLS
#define NM_DEVICE_MACVLAN_PARENT "parent"
#define NM_DEVICE_MACVLAN_MODE "mode"
#define NM_DEVICE_MACVLAN_NO_PROMISC "no-promisc"
#define NM_DEVICE_MACVLAN_TAP "tap"
typedef NMDeviceGeneric NMDeviceMacvlan;
typedef NMDeviceGenericClass NMDeviceMacvlanClass;
typedef NMDevice NMDeviceMacvlan;
typedef NMDeviceClass NMDeviceMacvlanClass;
GType nm_device_macvlan_get_type (void);

View file

@ -781,6 +781,8 @@ nm_device_get_priority (NMDevice *self)
return 350;
case NM_DEVICE_TYPE_VLAN:
return 400;
case NM_DEVICE_TYPE_MACVLAN:
return 410;
case NM_DEVICE_TYPE_BRIDGE:
return 425;
case NM_DEVICE_TYPE_TUN:

View file

@ -143,6 +143,7 @@ typedef enum {
NMP_OBJECT_TYPE_LNK_IP6TNL,
NMP_OBJECT_TYPE_LNK_IPIP,
NMP_OBJECT_TYPE_LNK_MACVLAN,
NMP_OBJECT_TYPE_LNK_MACVTAP,
NMP_OBJECT_TYPE_LNK_SIT,
NMP_OBJECT_TYPE_LNK_VLAN,
NMP_OBJECT_TYPE_LNK_VXLAN,

View file

@ -1026,9 +1026,16 @@ _parse_lnk_macvlan (const char *kind, struct nlattr *info_data)
struct nlattr *tb[IFLA_MACVLAN_MAX + 1];
int err;
NMPObject *obj;
const char *mode;
gboolean tap;
if (!info_data || g_strcmp0 (kind, "macvlan"))
if (!info_data)
return NULL;
if (!g_strcmp0 (kind, "macvlan"))
tap = FALSE;
else if (!g_strcmp0 (kind, "macvtap"))
tap = TRUE;
else
return NULL;
err = nla_parse_nested (tb, IFLA_MACVLAN_MAX, info_data, policy);
@ -1038,26 +1045,10 @@ _parse_lnk_macvlan (const char *kind, struct nlattr *info_data)
if (!tb[IFLA_MACVLAN_MODE])
return NULL;
switch (nla_get_u32 (tb[IFLA_MACVLAN_MODE])) {
case MACVLAN_MODE_PRIVATE:
mode = "private";
break;
case MACVLAN_MODE_VEPA:
mode = "vepa";
break;
case MACVLAN_MODE_BRIDGE:
mode = "bridge";
break;
case MACVLAN_MODE_PASSTHRU:
mode = "passthru";
break;
default:
return NULL;
}
obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_MACVLAN, NULL);
obj = nmp_object_new (tap ? NMP_OBJECT_TYPE_LNK_MACVTAP : NMP_OBJECT_TYPE_LNK_MACVLAN, NULL);
props = &obj->lnk_macvlan;
props->mode = mode;
props->mode = nla_get_u32 (tb[IFLA_MACVLAN_MODE]);
props->tap = tap;
if (tb[IFLA_MACVLAN_FLAGS])
props->no_promisc = NM_FLAGS_HAS (nla_get_u16 (tb[IFLA_MACVLAN_FLAGS]), MACVLAN_FLAG_NOPROMISC);
@ -1493,6 +1484,7 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
lnk_data = _parse_lnk_ipip (nl_info_kind, nl_info_data);
break;
case NM_LINK_TYPE_MACVLAN:
case NM_LINK_TYPE_MACVTAP:
lnk_data = _parse_lnk_macvlan (nl_info_kind, nl_info_data);
break;
case NM_LINK_TYPE_SIT:
@ -2907,6 +2899,7 @@ cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMP
case NM_LINK_TYPE_IP6TNL:
case NM_LINK_TYPE_INFINIBAND:
case NM_LINK_TYPE_MACVLAN:
case NM_LINK_TYPE_MACVTAP:
case NM_LINK_TYPE_SIT:
case NM_LINK_TYPE_VLAN:
case NM_LINK_TYPE_VXLAN:
@ -4373,6 +4366,55 @@ nla_put_failure:
g_return_val_if_reached (FALSE);
}
static int
link_macvlan_add (NMPlatform *platform,
const char *name,
int parent,
NMPlatformLnkMacvlan *props,
NMPlatformLink *out_link)
{
nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
struct nlattr *info;
struct nlattr *data;
_LOGD ("adding %s '%s' parent %u mode %u",
props->tap ? "macvtap" : "macvlan",
name,
parent,
props->mode);
nlmsg = _nl_msg_new_link (RTM_NEWLINK,
NLM_F_CREATE,
0,
name,
0,
0);
if (!nlmsg)
return FALSE;
NLA_PUT_U32 (nlmsg, IFLA_LINK, parent);
if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO)))
goto nla_put_failure;
NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, props->tap ? "macvtap" : "macvlan");
if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA)))
goto nla_put_failure;
NLA_PUT_U32 (nlmsg, IFLA_MACVLAN_MODE, props->mode);
NLA_PUT_U16 (nlmsg, IFLA_MACVLAN_FLAGS, props->no_promisc ? MACVLAN_FLAG_NOPROMISC : 0);
nla_nest_end (nlmsg, data);
nla_nest_end (nlmsg, info);
return do_add_link_with_lookup (platform,
props->tap ? NM_LINK_TYPE_MACVTAP : NM_LINK_TYPE_MACVLAN,
name, nlmsg, out_link);
nla_put_failure:
g_return_val_if_reached (FALSE);
}
static int
link_sit_add (NMPlatform *platform,
const char *name,
@ -5879,6 +5921,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
platform_class->link_gre_add = link_gre_add;
platform_class->link_ip6tnl_add = link_ip6tnl_add;
platform_class->link_macvlan_add = link_macvlan_add;
platform_class->link_ipip_add = link_ipip_add;
platform_class->link_sit_add = link_sit_add;

View file

@ -1447,6 +1447,12 @@ nm_platform_link_get_lnk_macvlan (NMPlatform *self, int ifindex, const NMPlatfor
return _link_get_lnk (self, ifindex, NM_LINK_TYPE_MACVLAN, out_link);
}
const NMPlatformLnkMacvtap *
nm_platform_link_get_lnk_macvtap (NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
{
return _link_get_lnk (self, ifindex, NM_LINK_TYPE_MACVTAP, out_link);
}
const NMPlatformLnkSit *
nm_platform_link_get_lnk_sit (NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
{
@ -1943,6 +1949,47 @@ nm_platform_link_ipip_add (NMPlatform *self,
return NM_PLATFORM_ERROR_SUCCESS;
}
/**
* nm_platform_macvlan_add:
* @self: platform instance
* @name: name of the new interface
* @props: interface properties
* @out_link: on success, the link object
*
* Create a MACVLAN or MACVTAP device.
*/
NMPlatformError
nm_platform_link_macvlan_add (NMPlatform *self,
const char *name,
int parent,
NMPlatformLnkMacvlan *props,
NMPlatformLink *out_link)
{
NMPlatformError plerr;
NMLinkType type;
_CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG);
g_return_val_if_fail (props, NM_PLATFORM_ERROR_BUG);
g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG);
type = props->tap ? NM_LINK_TYPE_MACVTAP : NM_LINK_TYPE_MACVLAN;
plerr = _link_add_check_existing (self, name, type, out_link);
if (plerr != NM_PLATFORM_ERROR_SUCCESS)
return plerr;
_LOGD ("adding %s '%s' parent %u mode %u",
props->tap ? "macvtap" : "macvlan",
name,
parent,
props->mode);
if (!klass->link_macvlan_add (self, name, parent, props, out_link))
return NM_PLATFORM_ERROR_UNSPECIFIED;
return NM_PLATFORM_ERROR_SUCCESS;
}
/**
* nm_platform_sit_add:
* @self: platform instance
@ -3059,10 +3106,9 @@ nm_platform_lnk_macvlan_to_string (const NMPlatformLnkMacvlan *lnk, char *buf, g
return buf;
g_snprintf (buf, len,
"macvlan%s%s%s",
lnk->mode ? " mode " : "",
lnk->mode ?: "",
lnk->no_promisc ? " not-promisc" : " promisc");
"macvlan mode %u %s",
lnk->mode,
lnk->no_promisc ? "not-promisc" : "promisc");
return buf;
}
@ -3667,7 +3713,7 @@ int
nm_platform_lnk_macvlan_cmp (const NMPlatformLnkMacvlan *a, const NMPlatformLnkMacvlan *b)
{
_CMP_SELF (a, b);
_CMP_FIELD_STR_INTERNED (a, b, mode);
_CMP_FIELD (a, b, mode);
_CMP_FIELD_BOOL (a, b, no_promisc);
return 0;
}

View file

@ -24,6 +24,7 @@
#include <netinet/in.h>
#include <linux/if.h>
#include <linux/if_addr.h>
#include <linux/if_link.h>
#include "nm-dbus-interface.h"
#include "nm-default.h"
@ -399,10 +400,13 @@ typedef struct {
} NMPlatformLnkIpIp;
typedef struct {
const char *mode;
guint mode;
gboolean no_promisc;
gboolean tap;
} NMPlatformLnkMacvlan;
typedef NMPlatformLnkMacvlan NMPlatformLnkMacvtap;
typedef struct {
int parent_ifindex;
in_addr_t local;
@ -564,6 +568,8 @@ typedef struct {
NMPlatformLink *out_link);
gboolean (*link_ipip_add) (NMPlatform *, const char *name, NMPlatformLnkIpIp *props,
NMPlatformLink *out_link);
gboolean (*link_macvlan_add) (NMPlatform *, const char *name, int parent, NMPlatformLnkMacvlan *props,
NMPlatformLink *out_link);
gboolean (*link_sit_add) (NMPlatform *, const char *name, NMPlatformLnkSit *props,
NMPlatformLink *out_link);
@ -760,6 +766,7 @@ const NMPlatformLnkIpIp *nm_platform_link_get_lnk_ipip (NMPlatform *self, int if
const NMPlatformLnkInfiniband *nm_platform_link_get_lnk_infiniband (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
const NMPlatformLnkIpIp *nm_platform_link_get_lnk_ipip (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
const NMPlatformLnkMacvlan *nm_platform_link_get_lnk_macvlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
const NMPlatformLnkMacvtap *nm_platform_link_get_lnk_macvtap (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
const NMPlatformLnkSit *nm_platform_link_get_lnk_sit (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
const NMPlatformLnkVlan *nm_platform_link_get_lnk_vlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
const NMPlatformLnkVxlan *nm_platform_link_get_lnk_vxlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
@ -816,6 +823,8 @@ NMPlatformError nm_platform_link_ip6tnl_add (NMPlatform *self, const char *name,
NMPlatformLink *out_link);
NMPlatformError nm_platform_link_ipip_add (NMPlatform *self, const char *name, NMPlatformLnkIpIp *props,
NMPlatformLink *out_link);
NMPlatformError nm_platform_link_macvlan_add (NMPlatform *self, const char *name, int parent, NMPlatformLnkMacvlan *props,
NMPlatformLink *out_link);
NMPlatformError nm_platform_link_sit_add (NMPlatform *self, const char *name, NMPlatformLnkSit *props,
NMPlatformLink *out_link);

View file

@ -2072,6 +2072,15 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_macvlan_to_string,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_macvlan_cmp,
},
[NMP_OBJECT_TYPE_LNK_MACVTAP - 1] = {
.obj_type = NMP_OBJECT_TYPE_LNK_MACVTAP,
.sizeof_data = sizeof (NMPObjectLnkMacvtap),
.sizeof_public = sizeof (NMPlatformLnkMacvtap),
.obj_type_name = "macvtap",
.lnk_link_type = NM_LINK_TYPE_MACVTAP,
.cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_macvlan_to_string,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_macvlan_cmp,
},
[NMP_OBJECT_TYPE_LNK_SIT - 1] = {
.obj_type = NMP_OBJECT_TYPE_LNK_SIT,
.sizeof_data = sizeof (NMPObjectLnkSit),

View file

@ -181,6 +181,8 @@ typedef struct {
NMPlatformLnkMacvlan _public;
} NMPObjectLnkMacvlan;
typedef NMPObjectLnkMacvlan NMPObjectLnkMacvtap;
typedef struct {
NMPlatformLnkSit _public;
} NMPObjectLnkSit;

View file

@ -774,6 +774,40 @@ nmtstp_link_ipip_add (gboolean external_command, const char *name, NMPlatformLnk
return success;
}
gboolean
nmtstp_link_macvlan_add (gboolean external_command, const char *name, int parent, NMPlatformLnkMacvlan *lnk)
{
gboolean success;
external_command = nmtstp_run_command_check_external (external_command);
if (external_command) {
const char *dev;
char *modes[] = {
[MACVLAN_MODE_BRIDGE] = "bridge",
[MACVLAN_MODE_VEPA] = "vepa",
[MACVLAN_MODE_PRIVATE] = "private",
[MACVLAN_MODE_PASSTHRU] = "passthru",
};
dev = nm_platform_link_get_name (NM_PLATFORM_GET, parent);
g_assert (dev);
g_assert_cmpint (lnk->mode, <, G_N_ELEMENTS (modes));
success = !nmtstp_run_command ("ip link add name %s link %s type %s mode %s %s",
name,
dev,
lnk->tap ? "macvtap" : "macvlan",
modes[lnk->mode],
lnk->no_promisc ? "nopromisc" : "");
if (success)
nmtstp_assert_wait_for_link (name, lnk->tap ? NM_LINK_TYPE_MACVTAP : NM_LINK_TYPE_MACVLAN, 100);
} else
success = nm_platform_link_macvlan_add (NM_PLATFORM_GET, name, parent, lnk, NULL) == NM_PLATFORM_ERROR_SUCCESS;
return success;
}
gboolean
nmtstp_link_sit_add (gboolean external_command, const char *name, NMPlatformLnkSit *lnk)
{

View file

@ -144,6 +144,9 @@ gboolean nmtstp_link_ip6tnl_add (gboolean external_command,
gboolean nmtstp_link_ipip_add (gboolean external_command,
const char *name,
NMPlatformLnkIpIp *lnk);
gboolean nmtstp_link_macvlan_add (gboolean external_command,
const char *name,
int parent, NMPlatformLnkMacvlan *lnk);
gboolean nmtstp_link_sit_add (gboolean external_command,
const char *name,
NMPlatformLnkSit *lnk);

View file

@ -740,9 +740,28 @@ test_software_detect (gconstpointer user_data)
}
break;
}
case NM_LINK_TYPE_MACVLAN:
nmtstp_run_command_check ("ip link add name %s link %s type macvlan", DEVICE_NAME, PARENT_NAME);
case NM_LINK_TYPE_MACVLAN: {
NMPlatformLnkMacvlan lnk_macvlan = { };
lnk_macvlan.mode = MACVLAN_MODE_BRIDGE;
lnk_macvlan.no_promisc = FALSE;
lnk_macvlan.tap = FALSE;
if (!nmtstp_link_macvlan_add (EX, DEVICE_NAME, ifindex_parent, &lnk_macvlan))
g_error ("Failed adding MACVLAN interface");
break;
}
case NM_LINK_TYPE_MACVTAP: {
NMPlatformLnkMacvtap lnk_macvtap = { };
lnk_macvtap.mode = MACVLAN_MODE_PRIVATE;
lnk_macvtap.no_promisc = FALSE;
lnk_macvtap.tap = TRUE;
if (!nmtstp_link_macvlan_add (EX, DEVICE_NAME, ifindex_parent, &lnk_macvtap))
g_error ("Failed adding MACVTAP interface");
break;
}
case NM_LINK_TYPE_SIT: {
NMPlatformLnkSit lnk_sit = { };
gboolean gracefully_skip = FALSE;
@ -867,7 +886,15 @@ test_software_detect (gconstpointer user_data)
g_assert (plnk == nm_platform_link_get_lnk_macvlan (NM_PLATFORM_GET, ifindex, NULL));
g_assert_cmpint (plnk->no_promisc, ==, FALSE);
g_assert_cmpstr (plnk->mode, ==, "vepa");
g_assert_cmpint (plnk->mode, ==, MACVLAN_MODE_BRIDGE);
break;
}
case NM_LINK_TYPE_MACVTAP: {
const NMPlatformLnkMacvtap *plnk = &lnk->lnk_macvlan;
g_assert (plnk == nm_platform_link_get_lnk_macvtap (NM_PLATFORM_GET, ifindex, NULL));
g_assert_cmpint (plnk->no_promisc, ==, FALSE);
g_assert_cmpint (plnk->mode, ==, MACVLAN_MODE_PRIVATE);
break;
}
case NM_LINK_TYPE_SIT: {
@ -1703,6 +1730,7 @@ setup_tests (void)
test_software_detect_add ("/link/software/detect/ip6tnl", NM_LINK_TYPE_IP6TNL, 0);
test_software_detect_add ("/link/software/detect/ipip", NM_LINK_TYPE_IPIP, 0);
test_software_detect_add ("/link/software/detect/macvlan", NM_LINK_TYPE_MACVLAN, 0);
test_software_detect_add ("/link/software/detect/macvtap", NM_LINK_TYPE_MACVTAP, 0);
test_software_detect_add ("/link/software/detect/sit", NM_LINK_TYPE_SIT, 0);
test_software_detect_add ("/link/software/detect/vlan", NM_LINK_TYPE_VLAN, 0);
test_software_detect_add ("/link/software/detect/vxlan/0", NM_LINK_TYPE_VXLAN, 0);