merge: branch 'bg/sriov-vf-rh1555013'

Add support for changing SR-IOV VF settings.

https://bugzilla.redhat.com/show_bug.cgi?id=1555013
This commit is contained in:
Beniamino Galvani 2018-07-11 16:29:55 +02:00
commit 7df4fc3849
46 changed files with 3193 additions and 164 deletions

View file

@ -432,6 +432,7 @@ libnm_core_lib_h_pub_real = \
libnm-core/nm-setting-pppoe.h \
libnm-core/nm-setting-proxy.h \
libnm-core/nm-setting-serial.h \
libnm-core/nm-setting-sriov.h \
libnm-core/nm-setting-tc-config.h \
libnm-core/nm-setting-team-port.h \
libnm-core/nm-setting-team.h \
@ -502,6 +503,7 @@ libnm_core_lib_c_settings_real = \
libnm-core/nm-setting-pppoe.c \
libnm-core/nm-setting-proxy.c \
libnm-core/nm-setting-serial.c \
libnm-core/nm-setting-sriov.c \
libnm-core/nm-setting-tc-config.c \
libnm-core/nm-setting-team-port.c \
libnm-core/nm-setting-team.c \
@ -2301,6 +2303,8 @@ EXTRA_DIST += \
src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-permissions \
src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-read-proxy-basic \
src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-sit-ignore \
src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-sriov \
src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-sriov-write.cexpected \
src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-static-routes-legacy \
src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-static-routes-legacy.cexpected \
src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc \

View file

@ -769,7 +769,8 @@ const NmcMetaGenericInfo *const metagen_con_active_vpn[_NMC_GENERIC_INFO_TYPE_CO
NM_SETTING_WPAN_SETTING_NAME","\
NM_SETTING_6LOWPAN_SETTING_NAME","\
NM_SETTING_PROXY_SETTING_NAME"," \
NM_SETTING_TC_CONFIG_SETTING_NAME
NM_SETTING_TC_CONFIG_SETTING_NAME"," \
NM_SETTING_SRIOV_SETTING_NAME
// NM_SETTING_DUMMY_SETTING_NAME
// NM_SETTING_WIMAX_SETTING_NAME

View file

@ -351,6 +351,7 @@ NM_UTILS_LOOKUP_STR_DEFINE (nmc_device_reason_to_string, NMDeviceStateReason,
NM_UTILS_LOOKUP_ITEM (NM_DEVICE_STATE_REASON_OVSDB_FAILED, N_("OpenVSwitch database connection failed")),
NM_UTILS_LOOKUP_ITEM (NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE, N_("A duplicate IP address was detected")),
NM_UTILS_LOOKUP_ITEM (NM_DEVICE_STATE_REASON_IP_METHOD_UNSUPPORTED, N_("The selected IP method is not supported")),
NM_UTILS_LOOKUP_ITEM (NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED, N_("Failed to configure SR-IOV parameters")),
)
NM_UTILS_LOOKUP_STR_DEFINE (nm_active_connection_state_reason_to_string, NMActiveConnectionStateReason,

View file

@ -3774,6 +3774,37 @@ _validate_fcn_proxy_pac_script (const char *value, char **out_to_free, GError **
RETURN_STR_TO_FREE (script);
}
static gconstpointer
_get_fcn_sriov_vfs (ARGS_GET_FCN)
{
NMSettingSriov *s_sriov = NM_SETTING_SRIOV (setting);
GString *printable;
guint num_vfs, i;
NMSriovVF *vf;
char *str;
RETURN_UNSUPPORTED_GET_TYPE ();
printable = g_string_new (NULL);
num_vfs = nm_setting_sriov_get_num_vfs (s_sriov);
for (i = 0; i < num_vfs; i++) {
vf = nm_setting_sriov_get_vf (s_sriov, i);
if (printable->len > 0)
g_string_append (printable, ", ");
str = nm_utils_sriov_vf_to_str (vf, FALSE, NULL);
if (str) {
g_string_append (printable, str);
g_free (str);
}
}
NM_SET_OUT (out_is_default, num_vfs == 0);
RETURN_STR_TO_FREE (g_string_free (printable, FALSE));
}
static gconstpointer
_get_fcn_tc_config_qdiscs (ARGS_GET_FCN)
{
@ -3805,6 +3836,28 @@ _get_fcn_tc_config_qdiscs (ARGS_GET_FCN)
RETURN_STR_TO_FREE (g_string_free (printable, FALSE));
}
static gboolean
_set_fcn_sriov_vfs (ARGS_SET_FCN)
{
gs_free const char **strv = NULL;
const char *const*iter;
NMSriovVF *vf;
GError *local = NULL;
strv = nm_utils_strsplit_set (value, ",");
for (iter = strv; strv && *iter; iter++) {
vf = nm_utils_sriov_vf_from_str (*iter, &local);
if (!vf) {
g_set_error (error, 1, 0, "%s. %s", local->message,
_("The valid syntax is: vf [attribute=value]... [,vf [attribute=value]...]"));
return FALSE;
}
nm_setting_sriov_add_vf (NM_SETTING_SRIOV (setting), vf);
nm_sriov_vf_unref (vf);
}
return TRUE;
}
static gboolean
_set_fcn_tc_config_qdiscs (ARGS_SET_FCN)
{
@ -3827,6 +3880,34 @@ _set_fcn_tc_config_qdiscs (ARGS_SET_FCN)
return TRUE;
}
static gboolean
_validate_and_remove_sriov_vf (NMSettingSriov *setting,
const char *value,
GError **error)
{
NMSriovVF *vf;
gboolean ret;
vf = nm_utils_sriov_vf_from_str (value, error);
if (!vf)
return FALSE;
ret = nm_setting_sriov_remove_vf_by_index (setting, nm_sriov_vf_get_index (vf));
if (!ret) {
g_set_error (error, 1, 0,
_("the property doesn't contain vf with index %u"),
nm_sriov_vf_get_index (vf));
}
nm_sriov_vf_unref (vf);
return ret;
}
DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_sriov_vfs,
NM_SETTING_SRIOV,
nm_setting_sriov_get_num_vfs,
nm_setting_sriov_remove_vf,
_validate_and_remove_sriov_vf)
static gboolean
_validate_and_remove_tc_qdisc (NMSettingTCConfig *setting,
const char *value,
@ -6831,6 +6912,25 @@ static const NMMetaPropertyInfo *const property_infos_SERIAL[] = {
NULL
};
#undef _CURRENT_NM_META_SETTING_TYPE
#define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_SRIOV
static const NMMetaPropertyInfo *const property_infos_SRIOV[] = {
PROPERTY_INFO_WITH_DESC (NM_SETTING_SRIOV_TOTAL_VFS,
.property_type = &_pt_gobject_int,
),
PROPERTY_INFO_WITH_DESC (NM_SETTING_SRIOV_VFS,
.property_type = DEFINE_PROPERTY_TYPE (
.get_fcn = _get_fcn_sriov_vfs,
.set_fcn = _set_fcn_sriov_vfs,
.remove_fcn = _remove_fcn_sriov_vfs,
),
),
PROPERTY_INFO_WITH_DESC (NM_SETTING_SRIOV_AUTOPROBE_DRIVERS,
.property_type = &_pt_gobject_enum,
),
NULL
};
#undef _CURRENT_NM_META_SETTING_TYPE
#define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_TUN
static const NMMetaPropertyInfo *const property_infos_TUN[] = {
@ -7649,6 +7749,7 @@ _setting_init_fcn_wireless (ARGS_SETTING_INIT_FCN)
#define SETTING_PRETTY_NAME_PPPOE N_("PPPoE")
#define SETTING_PRETTY_NAME_PROXY N_("Proxy")
#define SETTING_PRETTY_NAME_SERIAL N_("Serial settings")
#define SETTING_PRETTY_NAME_SRIOV N_("SR-IOV settings")
#define SETTING_PRETTY_NAME_TC_CONFIG N_("Traffic controls")
#define SETTING_PRETTY_NAME_TEAM N_("Team device")
#define SETTING_PRETTY_NAME_TEAM_PORT N_("Team port")
@ -7765,6 +7866,7 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = {
.valid_parts = NM_META_SETTING_VALID_PARTS (
NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE),
NM_META_SETTING_VALID_PART_ITEM (INFINIBAND, TRUE),
NM_META_SETTING_VALID_PART_ITEM (SRIOV, FALSE),
),
.setting_init_fcn = _setting_init_fcn_infiniband,
),
@ -7844,6 +7946,7 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = {
.setting_init_fcn = _setting_init_fcn_proxy,
),
SETTING_INFO (SERIAL),
SETTING_INFO (SRIOV),
SETTING_INFO (TC_CONFIG),
SETTING_INFO (TEAM,
.valid_parts = NM_META_SETTING_VALID_PARTS (
@ -7896,6 +7999,7 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = {
NM_META_SETTING_VALID_PART_ITEM (WIRED, TRUE),
NM_META_SETTING_VALID_PART_ITEM (802_1X, FALSE),
NM_META_SETTING_VALID_PART_ITEM (DCB, FALSE),
NM_META_SETTING_VALID_PART_ITEM (SRIOV, FALSE),
),
),
SETTING_INFO (WIRELESS,

View file

@ -323,8 +323,12 @@
#define DESCRIBE_DOC_NM_SETTING_SERIAL_PARITY N_("Parity setting of the serial port.")
#define DESCRIBE_DOC_NM_SETTING_SERIAL_SEND_DELAY N_("Time to delay between each byte sent to the modem, in microseconds.")
#define DESCRIBE_DOC_NM_SETTING_SERIAL_STOPBITS N_("Number of stop bits for communication on the serial port. Either 1 or 2. The 1 in \"8n1\" for example.")
#define DESCRIBE_DOC_NM_SETTING_SRIOV_AUTOPROBE_DRIVERS N_("Whether to autoprobe virtual functions by a compatible driver. If set to NM_TERNARY_TRUE (1), the kernel will try to bind VFs to a compatible driver and if this succeeds a new network interface will be instantiated for each VF. If set to NM_TERNARY_FALSE (0), VFs will not be claimed and no network interfaces will be created for them. When set to NM_TERNARY_DEFAULT (-1), the global default is used; in case the global default is unspecified it is assumed to be NM_TERNARY_TRUE (1).")
#define DESCRIBE_DOC_NM_SETTING_SRIOV_NAME N_("The setting's name, which uniquely identifies the setting within the connection. Each setting type has a name unique to that type, for example \"ppp\" or \"wireless\" or \"wired\".")
#define DESCRIBE_DOC_NM_SETTING_SRIOV_TOTAL_VFS N_("The total number of virtual functions to create.")
#define DESCRIBE_DOC_NM_SETTING_SRIOV_VFS N_("Array of virtual function descriptors. Each VF descriptor is a dictionary mapping attribute names to GVariant values. The 'index' entry is mandatory for each VF. When represented as string a VF is in the form: \"INDEX [ATTR=VALUE[ ATTR=VALUE]...]\". for example: \"2 mac=00:11:22:33:44:55 spoof-check=true\". The \"vlans\" attribute is represented as a semicolor-separated list of VLAN descriptors, where each descriptor has the form \"ID[.PRIORITY[.PROTO]]\". PROTO can be either 'q' for 802.1Q (the default) or 'ad' for 802.1ad.")
#define DESCRIBE_DOC_NM_SETTING_TC_CONFIG_NAME N_("The setting's name, which uniquely identifies the setting within the connection. Each setting type has a name unique to that type, for example \"ppp\" or \"wireless\" or \"wired\".")
#define DESCRIBE_DOC_NM_SETTING_TC_CONFIG_QDISCS N_("Array of TC queuening disciplines.")
#define DESCRIBE_DOC_NM_SETTING_TC_CONFIG_QDISCS N_("Array of TC queueing disciplines.")
#define DESCRIBE_DOC_NM_SETTING_TC_CONFIG_TFILTERS N_("Array of TC traffic filters.")
#define DESCRIBE_DOC_NM_SETTING_TEAM_CONFIG N_("The JSON configuration for the team network interface. The property should contain raw JSON configuration data suitable for teamd, because the value is passed directly to teamd. If not specified, the default configuration is used. See man teamd.conf for the format details.")
#define DESCRIBE_DOC_NM_SETTING_TEAM_LINK_WATCHERS N_("Link watchers configuration for the connection: each link watcher is defined by a dictionary, whose keys depend upon the selected link watcher. Available link watchers are 'ethtool', 'nsna_ping' and 'arp_ping' and it is specified in the dictionary with the key 'name'. Available keys are: ethtool: 'delay-up', 'delay-down', 'init-wait'; nsna_ping: 'init-wait', 'interval', 'missed-max', 'target-host'; arp_ping: all the ones in nsna_ping and 'source-host', 'validate-active', 'validate-incative', 'send-always'. See teamd.conf man for more details.")

View file

@ -220,6 +220,7 @@ print ("NetworkManager version " + client.get_version())]]></programlisting></in
<xi:include href="xml/nm-setting-ppp.xml"/>
<xi:include href="xml/nm-setting-proxy.xml"/>
<xi:include href="xml/nm-setting-serial.xml"/>
<xi:include href="xml/nm-setting-sriov.xml"/>
<xi:include href="xml/nm-setting-tc-config.xml"/>
<xi:include href="xml/nm-setting-team-port.xml"/>
<xi:include href="xml/nm-setting-team.xml"/>

View file

@ -34,6 +34,7 @@ libnm_core_headers = files(
'nm-setting-pppoe.h',
'nm-setting-proxy.h',
'nm-setting-serial.h',
'nm-setting-sriov.h',
'nm-setting-tc-config.h',
'nm-setting-team-port.h',
'nm-setting-team.h',
@ -86,6 +87,7 @@ libnm_core_settings_sources = files(
'nm-setting-pppoe.c',
'nm-setting-proxy.c',
'nm-setting-serial.c',
'nm-setting-sriov.c',
'nm-setting-tc-config.c',
'nm-setting-team-port.c',
'nm-setting-team.c',

View file

@ -1177,6 +1177,18 @@ _normalize_ip_tunnel_wired_setting (NMConnection *self, GHashTable *parameters)
return FALSE;
}
static gboolean
_normalize_sriov_vf_order (NMConnection *self, GHashTable *parameters)
{
NMSettingSriov *s_sriov;
s_sriov = nm_connection_get_setting_sriov (self);
if (!s_sriov)
return FALSE;
return _nm_setting_sriov_sort_vfs (s_sriov);
}
static gboolean
_normalize_required_settings (NMConnection *self, GHashTable *parameters)
{
@ -1523,6 +1535,7 @@ nm_connection_normalize (NMConnection *connection,
was_modified |= _normalize_bluetooth_type (connection, parameters);
was_modified |= _normalize_ovs_interface_type (connection, parameters);
was_modified |= _normalize_ip_tunnel_wired_setting (connection, parameters);
was_modified |= _normalize_sriov_vf_order (connection, parameters);
/* Verify anew. */
success = _nm_connection_verify (connection, error);
@ -2626,6 +2639,22 @@ nm_connection_get_setting_serial (NMConnection *connection)
return _connection_get_setting_check (connection, NM_TYPE_SETTING_SERIAL);
}
/**
* nm_connection_get_setting_sriov:
* @connection: the #NMConnection
*
* A shortcut to return any #NMSettingSriov the connection might contain.
*
* Returns: (transfer none): an #NMSettingSriov if the connection contains one, otherwise %NULL
*
* Since: 1.14
**/
NMSettingSriov *
nm_connection_get_setting_sriov (NMConnection *connection)
{
return _connection_get_setting_check (connection, NM_TYPE_SETTING_SRIOV);
}
/**
* nm_connection_get_setting_tc_config:
* @connection: the #NMConnection

View file

@ -231,6 +231,8 @@ NMSettingPppoe * nm_connection_get_setting_pppoe (NMConnec
NM_AVAILABLE_IN_1_6
NMSettingProxy * nm_connection_get_setting_proxy (NMConnection *connection);
NMSettingSerial * nm_connection_get_setting_serial (NMConnection *connection);
NM_AVAILABLE_IN_1_14
NMSettingSriov * nm_connection_get_setting_sriov (NMConnection *connection);
NM_AVAILABLE_IN_1_12
NMSettingTCConfig * nm_connection_get_setting_tc_config (NMConnection *connection);
NMSettingTun * nm_connection_get_setting_tun (NMConnection *connection);

View file

@ -65,6 +65,7 @@
#include "nm-setting-ppp.h"
#include "nm-setting-pppoe.h"
#include "nm-setting-serial.h"
#include "nm-setting-sriov.h"
#include "nm-setting-tc-config.h"
#include "nm-setting-team-port.h"
#include "nm-setting-team.h"
@ -226,6 +227,9 @@ gboolean _nm_ip_route_attribute_validate_all (const NMIPRoute *route);
const char **_nm_ip_route_get_attribute_names (const NMIPRoute *route, gboolean sorted, guint *out_length);
GHashTable *_nm_ip_route_get_attributes_direct (NMIPRoute *route);
NMSriovVF *_nm_utils_sriov_vf_from_strparts (const char *index, const char *detail, GError **error);
gboolean _nm_sriov_vf_attribute_validate_all (const NMSriovVF *vf, GError **error);
static inline void
_nm_auto_ip_route_unref (NMIPRoute **v)
{
@ -513,4 +517,7 @@ _nm_connection_type_is_master (const char *type)
gboolean _nm_utils_dhcp_duid_valid (const char *duid, GBytes **out_duid_bin);
/*****************************************************************************/
gboolean _nm_setting_sriov_sort_vfs (NMSettingSriov *setting);
#endif

View file

@ -58,6 +58,7 @@ typedef struct _NMSettingOvsPort NMSettingOvsPort;
typedef struct _NMSettingPpp NMSettingPpp;
typedef struct _NMSettingPppoe NMSettingPppoe;
typedef struct _NMSettingSerial NMSettingSerial;
typedef struct _NMSettingSriov NMSettingSriov;
typedef struct _NMSettingTCConfig NMSettingTCConfig;
typedef struct _NMSettingTeam NMSettingTeam;
typedef struct _NMSettingTeamPort NMSettingTeamPort;

View file

@ -559,6 +559,7 @@ typedef enum {
* @NM_DEVICE_STATE_REASON_OVSDB_FAILED: problem communicating with Open vSwitch database
* @NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE: a duplicate IP address was detected
* @NM_DEVICE_STATE_REASON_IP_METHOD_UNSUPPORTED: The selected IP method is not supported
* @NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED: configuration of SR-IOV parameters failed
*
* Device state change reason codes
*/
@ -629,6 +630,7 @@ typedef enum {
NM_DEVICE_STATE_REASON_OVSDB_FAILED = 63,
NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE = 64,
NM_DEVICE_STATE_REASON_IP_METHOD_UNSUPPORTED = 65,
NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED = 66,
} NMDeviceStateReason;
/**
@ -991,4 +993,20 @@ typedef enum { /*< flags >*/
NM_SETTINGS_UPDATE2_FLAG_BLOCK_AUTOCONNECT = (1LL << 5),
} NMSettingsUpdate2Flags;
/**
* NMTernary:
* @NM_TERNARY_DEFAULT: use the globally-configured default value.
* @NM_TERNARY_FALSE: the option is disabled.
* @NM_TERNARY_TRUE: the option is enabled.
*
* An boolean value that can be overridden by a default.
*
* Since: 1.14
**/
typedef enum {
NM_TERNARY_DEFAULT = -1,
NM_TERNARY_FALSE = 0,
NM_TERNARY_TRUE = 1,
} NMTernary;
#endif /* __NM_DBUS_INTERFACE_H__ */

View file

@ -118,6 +118,49 @@ setting_alias_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *k
}
}
static void
sriov_vfs_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
{
const char *setting_name = nm_setting_get_name (setting);
gs_unref_ptrarray GPtrArray *vfs = NULL;
gs_strfreev char **keys = NULL;
gsize n_keys = 0;
int i;
keys = nm_keyfile_plugin_kf_get_keys (info->keyfile, setting_name, &n_keys, NULL);
if (!keys || n_keys == 0)
return;
vfs = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_sriov_vf_unref);
for (i = 0; i < n_keys; i++) {
gs_free char *value = NULL;
NMSriovVF *vf;
const char *rest;
if (!g_str_has_prefix (keys[i], "vf."))
continue;
rest = &keys[i][3];
if (!NM_STRCHAR_ALL (rest, ch, g_ascii_isdigit (ch)))
continue;
value = nm_keyfile_plugin_kf_get_string (info->keyfile,
setting_name,
keys[i],
NULL);
vf = _nm_utils_sriov_vf_from_strparts (rest, value, NULL);
if (vf)
g_ptr_array_add (vfs, vf);
}
g_object_set (G_OBJECT (setting),
key, vfs,
NULL);
}
static void
read_array_of_uint (GKeyFile *file,
NMSetting *setting,
@ -1509,6 +1552,37 @@ setting_alias_writer (KeyfileWriterInfo *info,
alias ?: str);
}
static void
sriov_vfs_writer (KeyfileWriterInfo *info,
NMSetting *setting,
const char *key,
const GValue *value)
{
GPtrArray *vfs;
guint i;
vfs = g_value_get_boxed (value);
if (!vfs)
return;
for (i = 0; i < vfs->len; i++) {
const NMSriovVF *vf = vfs->pdata[i];
gs_free char *kf_value = NULL;
char kf_key[32];
kf_value = nm_utils_sriov_vf_to_str (vf, TRUE, NULL);
if (!kf_value)
continue;
nm_sprintf_buf (kf_key, "vf.%u", nm_sriov_vf_get_index (vf));
nm_keyfile_plugin_kf_set_string (info->keyfile,
nm_setting_get_name (setting),
kf_key,
kf_value);
}
}
static void
write_array_of_uint (GKeyFile *file,
NMSetting *setting,
@ -2189,6 +2263,15 @@ static const ParseInfoSetting parse_infos[] = {
),
),
),
PARSE_INFO_SETTING (NM_SETTING_SRIOV_SETTING_NAME,
PARSE_INFO_PROPERTIES (
PARSE_INFO_PROPERTY (NM_SETTING_SRIOV_VFS,
.parser_no_check_key = TRUE,
.parser = sriov_vfs_parser,
.writer = sriov_vfs_writer,
),
),
),
PARSE_INFO_SETTING (NM_SETTING_TC_CONFIG_SETTING_NAME,
PARSE_INFO_PROPERTIES (
PARSE_INFO_PROPERTY (NM_SETTING_TC_CONFIG_QDISCS,

View file

@ -1589,8 +1589,11 @@ nm_setting_ip_config_clear_dns (NMSettingIPConfig *setting)
g_return_if_fail (NM_IS_SETTING_IP_CONFIG (setting));
priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
g_ptr_array_set_size (priv->dns, 0);
g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS);
if (priv->dns->len != 0) {
g_ptr_array_set_size (priv->dns, 0);
g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS);
}
}
/**
@ -1727,8 +1730,11 @@ nm_setting_ip_config_clear_dns_searches (NMSettingIPConfig *setting)
g_return_if_fail (NM_IS_SETTING_IP_CONFIG (setting));
priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
g_ptr_array_set_size (priv->dns_search, 0);
g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS_SEARCH);
if (priv->dns_search->len != 0) {
g_ptr_array_set_size (priv->dns_search, 0);
g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS_SEARCH);
}
}
/**
@ -2107,8 +2113,10 @@ nm_setting_ip_config_clear_addresses (NMSettingIPConfig *setting)
g_return_if_fail (NM_IS_SETTING_IP_CONFIG (setting));
g_ptr_array_set_size (priv->addresses, 0);
g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ADDRESSES);
if (priv->addresses->len != 0) {
g_ptr_array_set_size (priv->addresses, 0);
g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ADDRESSES);
}
}
/**
@ -2264,8 +2272,10 @@ nm_setting_ip_config_clear_routes (NMSettingIPConfig *setting)
g_return_if_fail (NM_IS_SETTING_IP_CONFIG (setting));
g_ptr_array_set_size (priv->routes, 0);
g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ROUTES);
if (priv->routes->len != 0) {
g_ptr_array_set_size (priv->routes, 0);
g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ROUTES);
}
}
/**

View file

@ -746,7 +746,7 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *ip4_class)
/* ---ifcfg-rh---
* property: dad-timeout
* variable: ACD_TIMEOUT, ARPING_WAIT
* variable: ACD_TIMEOUT(+), ARPING_WAIT
* default: missing variable means global default (config override or zero)
* description: Timeout (in milliseconds for ACD_TIMEOUT or in seconds
* for ARPING_WAIT) for address conflict detection before configuring

View file

@ -589,7 +589,7 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *ip6_class)
/* ---ifcfg-rh---
* property: dns-search
* variable: IPV6_DOMAIN
* variable: IPV6_DOMAIN(+)
* format: string (space-separated domains)
* description: List of DNS search domains.
* ---end---

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,123 @@
/* -*- 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.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/>.
*
* Copyright 2018 Red Hat, Inc.
*/
#ifndef NM_SETTING_SRIOV_H
#define NM_SETTING_SRIOV_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_SRIOV (nm_setting_sriov_get_type ())
#define NM_SETTING_SRIOV(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTING_SRIOV, NMSettingSriov))
#define NM_SETTING_SRIOV_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SETTING_SRIOV, NMSettingSriovClass))
#define NM_IS_SETTING_SRIOV(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTING_SRIOV))
#define NM_IS_SETTING_SRIOV_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SETTING_SRIOV))
#define NM_SETTING_SRIOV_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SETTING_SRIOV, NMSettingSriovClass))
#define NM_SETTING_SRIOV_SETTING_NAME "sriov"
#define NM_SETTING_SRIOV_TOTAL_VFS "total-vfs"
#define NM_SETTING_SRIOV_VFS "vfs"
#define NM_SETTING_SRIOV_AUTOPROBE_DRIVERS "autoprobe-drivers"
#define NM_SRIOV_VF_ATTRIBUTE_MAC "mac"
#define NM_SRIOV_VF_ATTRIBUTE_SPOOF_CHECK "spoof-check"
#define NM_SRIOV_VF_ATTRIBUTE_TRUST "trust"
#define NM_SRIOV_VF_ATTRIBUTE_MIN_TX_RATE "min-tx-rate"
#define NM_SRIOV_VF_ATTRIBUTE_MAX_TX_RATE "max-tx-rate"
typedef struct _NMSettingSriovClass NMSettingSriovClass;
typedef struct _NMSriovVF NMSriovVF;
/**
* NMSriovVFVlanProtocol:
* @NM_SRIOV_VF_VLAN_PROTOCOL_802_1Q: use 802.1Q
* @NM_SRIOV_VF_VLAN_PROTOCOL_802_1AD: use 802.1ad
*
* #NMSriovVFVlanProtocol indicates the VLAN protocol to use.
*
* Since: 1.14
*/
typedef enum {
NM_SRIOV_VF_VLAN_PROTOCOL_802_1Q = 0,
NM_SRIOV_VF_VLAN_PROTOCOL_802_1AD = 1,
} NMSriovVFVlanProtocol;
NM_AVAILABLE_IN_1_14
GType nm_setting_sriov_get_type (void);
NM_AVAILABLE_IN_1_14
NMSetting *nm_setting_sriov_new (void);
NM_AVAILABLE_IN_1_14
guint nm_setting_sriov_get_total_vfs (NMSettingSriov *setting);
NM_AVAILABLE_IN_1_14
guint nm_setting_sriov_get_num_vfs (NMSettingSriov *setting);
NM_AVAILABLE_IN_1_14
NMSriovVF *nm_setting_sriov_get_vf (NMSettingSriov *setting, guint idx);
NM_AVAILABLE_IN_1_14
void nm_setting_sriov_add_vf (NMSettingSriov *setting, NMSriovVF *vf);
NM_AVAILABLE_IN_1_14
void nm_setting_sriov_remove_vf (NMSettingSriov *setting, guint idx);
NM_AVAILABLE_IN_1_14
gboolean nm_setting_sriov_remove_vf_by_index (NMSettingSriov *setting, guint index);
NM_AVAILABLE_IN_1_14
void nm_setting_sriov_clear_vfs (NMSettingSriov *setting);
NM_AVAILABLE_IN_1_14
NMTernary nm_setting_sriov_get_autoprobe_drivers (NMSettingSriov *setting);
NM_AVAILABLE_IN_1_14
gboolean nm_sriov_vf_add_vlan (NMSriovVF *vf, guint vlan_id);
NM_AVAILABLE_IN_1_14
gboolean nm_sriov_vf_remove_vlan (NMSriovVF *vf, guint vlan_id);
NM_AVAILABLE_IN_1_14
const guint *nm_sriov_vf_get_vlan_ids (const NMSriovVF *vf, guint *length);
NM_AVAILABLE_IN_1_14
void nm_sriov_vf_set_vlan_qos (NMSriovVF *vf, guint vlan_id, guint32 qos);
NM_AVAILABLE_IN_1_14
void nm_sriov_vf_set_vlan_protocol (NMSriovVF *vf, guint vlan_id, NMSriovVFVlanProtocol protocol);
NM_AVAILABLE_IN_1_14
guint32 nm_sriov_vf_get_vlan_qos (const NMSriovVF *vf, guint vlan_id);
NM_AVAILABLE_IN_1_14
NMSriovVFVlanProtocol nm_sriov_vf_get_vlan_protocol (const NMSriovVF *vf, guint vlan_id);
NM_AVAILABLE_IN_1_14
GType nm_sriov_vf_get_type (void);
NM_AVAILABLE_IN_1_14
NMSriovVF *nm_sriov_vf_new (guint index);
NM_AVAILABLE_IN_1_14
void nm_sriov_vf_ref (NMSriovVF *vf);
NM_AVAILABLE_IN_1_14
void nm_sriov_vf_unref (NMSriovVF *vf);
NM_AVAILABLE_IN_1_14
gboolean nm_sriov_vf_equal (const NMSriovVF *vf, const NMSriovVF *other);
NM_AVAILABLE_IN_1_14
NMSriovVF *nm_sriov_vf_dup (const NMSriovVF *vf);
NM_AVAILABLE_IN_1_14
guint nm_sriov_vf_get_index (const NMSriovVF *vf);
NM_AVAILABLE_IN_1_14
void nm_sriov_vf_set_attribute (NMSriovVF *vf, const char *name, GVariant *value);
NM_AVAILABLE_IN_1_14
const char **nm_sriov_vf_get_attribute_names (const NMSriovVF *vf);
NM_AVAILABLE_IN_1_14
GVariant *nm_sriov_vf_get_attribute (const NMSriovVF *vf, const char *name);
NM_AVAILABLE_IN_1_14
gboolean nm_sriov_vf_attribute_validate (const char *name, GVariant *value, gboolean *known, GError **error);
G_END_DECLS
#endif /* NM_SETTING_SRIOV_H */

View file

@ -820,18 +820,18 @@ enum {
/**
* NMSettingTCConfig:
*
* Linux Traffic Contril Settings.
* Linux Traffic Control Settings.
*
* Since: 1.12
*/
struct _NMSettingTCConfig {
NMSetting parent;
NMSetting parent;
GPtrArray *qdiscs;
GPtrArray *tfilters;
};
struct _NMSettingTCConfigClass {
NMSettingClass parent;
NMSettingClass parent;
};
G_DEFINE_TYPE_WITH_CODE (NMSettingTCConfig, nm_setting_tc_config, NM_TYPE_SETTING,
@ -982,8 +982,10 @@ nm_setting_tc_config_clear_qdiscs (NMSettingTCConfig *self)
{
g_return_if_fail (NM_IS_SETTING_TC_CONFIG (self));
g_ptr_array_set_size (self->qdiscs, 0);
g_object_notify (G_OBJECT (self), NM_SETTING_TC_CONFIG_QDISCS);
if (self->qdiscs->len != 0) {
g_ptr_array_set_size (self->qdiscs, 0);
g_object_notify (G_OBJECT (self), NM_SETTING_TC_CONFIG_QDISCS);
}
}
/*****************************************************************************/
@ -1116,8 +1118,10 @@ nm_setting_tc_config_clear_tfilters (NMSettingTCConfig *self)
{
g_return_if_fail (NM_IS_SETTING_TC_CONFIG (self));
g_ptr_array_set_size (self->tfilters, 0);
g_object_notify (G_OBJECT (self), NM_SETTING_TC_CONFIG_TFILTERS);
if (self->tfilters->len != 0) {
g_ptr_array_set_size (self->tfilters, 0);
g_object_notify (G_OBJECT (self), NM_SETTING_TC_CONFIG_TFILTERS);
}
}
/*****************************************************************************/
@ -1602,11 +1606,11 @@ nm_setting_tc_config_class_init (NMSettingTCConfigClass *setting_class)
/**
* NMSettingTCConfig:qdiscs: (type GPtrArray(NMTCQdisc))
*
* Array of TC queuening disciplines.
* Array of TC queueing disciplines.
**/
/* ---ifcfg-rh---
* property: qdiscs
* variable: QDISC1, QDISC2, ...
* variable: QDISC1(+), QDISC2(+), ...
* description: Queueing disciplines
* example: QDISC1=ingress, QDISC2="root handle 1234: fq_codel"
* ---end---
@ -1633,7 +1637,7 @@ nm_setting_tc_config_class_init (NMSettingTCConfigClass *setting_class)
**/
/* ---ifcfg-rh---
* property: qdiscs
* variable: FILTER1, FILTER2, ...
* variable: FILTER1(+), FILTER2(+), ...
* description: Traffic filters
* example: FILTER1="parent ffff: matchall action simple sdata Input", ...
* ---end---

View file

@ -322,8 +322,10 @@ nm_setting_team_port_clear_link_watchers (NMSettingTeamPort *setting)
g_return_if_fail (NM_IS_SETTING_TEAM_PORT (setting));
g_ptr_array_set_size (priv->link_watchers, 0);
g_object_notify (G_OBJECT (setting), NM_SETTING_TEAM_PORT_LINK_WATCHERS);
if (priv->link_watchers->len != 0) {
g_ptr_array_set_size (priv->link_watchers, 0);
g_object_notify (G_OBJECT (setting), NM_SETTING_TEAM_PORT_LINK_WATCHERS);
}
}
static GVariant *

View file

@ -1120,8 +1120,10 @@ nm_setting_team_clear_link_watchers (NMSettingTeam *setting) {
g_return_if_fail (NM_IS_SETTING_TEAM (setting));
g_ptr_array_set_size (priv->link_watchers, 0);
g_object_notify (G_OBJECT (setting), NM_SETTING_TEAM_LINK_WATCHERS);
if (priv->link_watchers->len != 0) {
g_ptr_array_set_size (priv->link_watchers, 0);
g_object_notify (G_OBJECT (setting), NM_SETTING_TEAM_LINK_WATCHERS);
}
}
static GVariant *

View file

@ -132,6 +132,7 @@ _register_settings_ensure_types (void)
ENSURE_TYPE (nm_setting_pppoe_get_type);
ENSURE_TYPE (nm_setting_proxy_get_type);
ENSURE_TYPE (nm_setting_serial_get_type);
ENSURE_TYPE (nm_setting_sriov_get_type);
ENSURE_TYPE (nm_setting_tc_config_get_type);
ENSURE_TYPE (nm_setting_team_get_type);
ENSURE_TYPE (nm_setting_team_port_get_type);

View file

@ -83,6 +83,13 @@ char * _nm_utils_hwaddr_canonical_or_invalid (const char *mac, gssize lengt
GPtrArray * _nm_utils_team_link_watchers_from_variant (GVariant *value);
GVariant * _nm_utils_team_link_watchers_to_variant (GPtrArray *link_watchers);
void _nm_utils_format_variant_attributes_full (GString *str,
const NMUtilsNamedValue *values,
guint num_values,
char attr_separator,
char key_value_separator);
gboolean _nm_sriov_vf_parse_vlans (NMSriovVF *vf, const char *str, GError **error);
/* JSON to GValue conversion macros */
typedef struct {

View file

@ -2657,6 +2657,249 @@ nm_utils_tc_tfilter_from_str (const char *str, GError **error)
/*****************************************************************************/
extern const NMVariantAttributeSpec *const _nm_sriov_vf_attribute_spec[];
/**
* nm_utils_sriov_vf_to_str:
* @vf: the %NMSriovVF
* @omit_index: if %TRUE, the VF index will be omitted from output string
* @error: (out) (allow-none): location to store the error on failure
*
* Converts a SR-IOV virtual function object to its string representation.
*
* Returns: a newly allocated string or %NULL on error
*
* Since: 1.14
*/
char *
nm_utils_sriov_vf_to_str (const NMSriovVF *vf, gboolean omit_index, GError **error)
{
gs_free NMUtilsNamedValue *values = NULL;
gs_free const char **names = NULL;
const guint *vlan_ids;
guint num_vlans, num_attrs;
guint i;
GString *str;
str = g_string_new ("");
if (!omit_index)
g_string_append_printf (str, "%u", nm_sriov_vf_get_index (vf));
names = nm_sriov_vf_get_attribute_names (vf);
num_attrs = names ? g_strv_length ((char **) names) : 0;
values = g_new0 (NMUtilsNamedValue, num_attrs);
for (i = 0; i < num_attrs; i++) {
values[i].name = names[i];
values[i].value_ptr = nm_sriov_vf_get_attribute (vf, names[i]);
}
if (num_attrs > 0) {
if (!omit_index)
g_string_append_c (str, ' ');
_nm_utils_format_variant_attributes_full (str, values, num_attrs, ' ', '=');
}
vlan_ids = nm_sriov_vf_get_vlan_ids (vf, &num_vlans);
if (num_vlans != 0) {
g_string_append (str, " vlans");
for (i = 0; i < num_vlans; i++) {
guint32 qos;
NMSriovVFVlanProtocol protocol;
qos = nm_sriov_vf_get_vlan_qos (vf, vlan_ids[i]);
protocol = nm_sriov_vf_get_vlan_protocol (vf, vlan_ids[i]);
g_string_append_c (str, i == 0 ? '=' : ';');
g_string_append_printf (str, "%u", vlan_ids[i]);
if ( qos != 0
|| protocol != NM_SRIOV_VF_VLAN_PROTOCOL_802_1Q) {
g_string_append_printf (str,
".%u%s",
(unsigned) qos,
protocol == NM_SRIOV_VF_VLAN_PROTOCOL_802_1Q ? "" : ".ad");
}
}
}
return g_string_free (str, FALSE);
}
gboolean
_nm_sriov_vf_parse_vlans (NMSriovVF *vf, const char *str, GError **error)
{
gs_free const char **vlans = NULL;
guint i;
vlans = nm_utils_strsplit_set (str, ";");
if (!vlans) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_FAILED,
"empty VF VLAN");
return FALSE;
}
for (i = 0; vlans[i]; i++) {
gs_strfreev char **params = NULL;
guint id = G_MAXUINT;
gint64 qos = -1;
/* we accept leading/trailing whitespace around vlans[1]. Hence
* the nm_str_skip_leading_spaces() and g_strchomp() below.
*
* However, we don't accept any whitespace inside the specifier.
* Hence the NM_STRCHAR_ALL() checks. */
params = g_strsplit (nm_str_skip_leading_spaces (vlans[i]), ".", 3);
if (!params || !params[0] || *params[0] == '\0') {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_FAILED,
"empty VF VLAN");
return FALSE;
}
if (!params[1])
g_strchomp (params[0]);
if (NM_STRCHAR_ALL (params[0], ch, ch == 'x' || g_ascii_isdigit (ch)))
id = _nm_utils_ascii_str_to_int64 (params[0], 0, 0, 4095, G_MAXUINT);
if (id == G_MAXUINT) {
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_FAILED,
"invalid VF VLAN id '%s'",
params[0]);
return FALSE;
}
if (!nm_sriov_vf_add_vlan (vf, id)) {
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_FAILED,
"duplicate VLAN id %u",
id);
return FALSE;
}
if (!params[1])
continue;
if (!params[2])
g_strchomp (params[1]);
if (NM_STRCHAR_ALL (params[1], ch, ch == 'x' || g_ascii_isdigit (ch)))
qos = _nm_utils_ascii_str_to_int64 (params[1], 0, 0, G_MAXUINT32, -1);
if (qos == -1) {
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_FAILED,
"invalid VF VLAN QoS '%s'",
params[1]);
return FALSE;
}
nm_sriov_vf_set_vlan_qos (vf, id, qos);
if (!params[2])
continue;
g_strchomp (params[2]);
if (nm_streq (params[2], "ad"))
nm_sriov_vf_set_vlan_protocol (vf, id, NM_SRIOV_VF_VLAN_PROTOCOL_802_1AD);
else if (nm_streq (params[2], "q"))
nm_sriov_vf_set_vlan_protocol (vf, id, NM_SRIOV_VF_VLAN_PROTOCOL_802_1Q);
else {
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_FAILED,
"invalid VF VLAN protocol '%s'",
params[2]);
return FALSE;
}
}
return TRUE;
}
/**
* nm_utils_sriov_vf_from_str:
* @str: the input string
* @error: (out) (allow-none): location to store the error on failure
*
* Converts a string to a SR-IOV virtual function object.
*
* Returns: (transfer full): the virtual function object
*
* Since: 1.14
*/
NMSriovVF *
nm_utils_sriov_vf_from_str (const char *str, GError **error)
{
gs_free char *index_free = NULL;
const char *detail;
g_return_val_if_fail (str, NULL);
g_return_val_if_fail (!error || !*error, NULL);
while (*str == ' ')
str++;
detail = strchr (str, ' ');
if (detail) {
index_free = g_strndup (str, detail - str);
str = index_free;
detail++;
}
return _nm_utils_sriov_vf_from_strparts (str, detail, error);
}
NMSriovVF *
_nm_utils_sriov_vf_from_strparts (const char *index, const char *detail, GError **error)
{
NMSriovVF *vf;
guint32 n_index;
GHashTableIter iter;
char *key;
GVariant *variant;
gs_unref_hashtable GHashTable *ht = NULL;
n_index = _nm_utils_ascii_str_to_int64 (index, 10, 0, G_MAXUINT32, 0);
if (errno) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_FAILED,
"invalid index");
return NULL;
}
vf = nm_sriov_vf_new (n_index);
if (detail) {
ht = nm_utils_parse_variant_attributes (detail, ' ', '=', TRUE, _nm_sriov_vf_attribute_spec, error);
if (!ht) {
nm_sriov_vf_unref (vf);
return NULL;
}
if ((variant = g_hash_table_lookup (ht, "vlans"))) {
if (!_nm_sriov_vf_parse_vlans (vf, g_variant_get_string (variant, NULL), error)) {
nm_sriov_vf_unref (vf);
return NULL;
}
g_hash_table_remove (ht, "vlans");
}
g_hash_table_iter_init (&iter, ht);
while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &variant))
nm_sriov_vf_set_attribute (vf, key, g_variant_ref_sink (variant));
}
return vf;
}
/*****************************************************************************/
/**
* nm_utils_uuid_generate_buf_:
* @buf: input buffer, must contain at least 37 bytes
@ -6156,44 +6399,21 @@ next:
return g_steal_pointer (&ht);
}
/*
* nm_utils_format_variant_attributes:
* @attributes: (element-type utf8 GVariant): a #GHashTable mapping attribute names to #GVariant values
* @attr_separator: the attribute separator character
* @key_value_separator: character separating key and values
*
* Format attributes to a string.
*
* Returns: (transfer full): the string representing attributes, or %NULL
* in case there are no attributes
*
* Since: 1.8
*/
char *
nm_utils_format_variant_attributes (GHashTable *attributes,
char attr_separator,
char key_value_separator)
void
_nm_utils_format_variant_attributes_full (GString *str,
const NMUtilsNamedValue *values,
guint num_values,
char attr_separator,
char key_value_separator)
{
GString *str = NULL;
GVariant *variant;
char sep = 0;
const char *name, *value;
GVariant *variant;
char *escaped;
char buf[64];
gs_free NMUtilsNamedValue *values = NULL;
guint i, len;
char sep = 0;
guint i;
g_return_val_if_fail (attr_separator, NULL);
g_return_val_if_fail (key_value_separator, NULL);
if (!attributes || !g_hash_table_size (attributes))
return NULL;
values = nm_utils_named_values_from_str_dict (attributes, &len);
str = g_string_new ("");
for (i = 0; i < len; i++) {
for (i = 0; i < num_values; i++) {
name = values[i].name;
variant = (GVariant *) values[i].value_ptr;
value = NULL;
@ -6226,7 +6446,44 @@ nm_utils_format_variant_attributes (GHashTable *attributes,
sep = attr_separator;
}
}
/*
* nm_utils_format_variant_attributes:
* @attributes: (element-type utf8 GVariant): a #GHashTable mapping attribute names to #GVariant values
* @attr_separator: the attribute separator character
* @key_value_separator: character separating key and values
*
* Format attributes to a string.
*
* Returns: (transfer full): the string representing attributes, or %NULL
* in case there are no attributes
*
* Since: 1.8
*/
char *
nm_utils_format_variant_attributes (GHashTable *attributes,
char attr_separator,
char key_value_separator)
{
GString *str = NULL;
gs_free NMUtilsNamedValue *values = NULL;
guint len;
g_return_val_if_fail (attr_separator, NULL);
g_return_val_if_fail (key_value_separator, NULL);
if (!attributes || !g_hash_table_size (attributes))
return NULL;
values = nm_utils_named_values_from_str_dict (attributes, &len);
str = g_string_new ("");
_nm_utils_format_variant_attributes_full (str,
values,
len,
attr_separator,
key_value_separator);
return g_string_free (str, FALSE);
}

View file

@ -34,8 +34,9 @@
#include <linux/if_infiniband.h>
#include "nm-core-enum-types.h"
#include "nm-setting-wireless-security.h"
#include "nm-setting-sriov.h"
#include "nm-setting-tc-config.h"
#include "nm-setting-wireless-security.h"
G_BEGIN_DECLS
@ -250,9 +251,17 @@ char *nm_utils_tc_tfilter_to_str (NMTCTfilter *tfilter, GError **error
/*****************************************************************************/
NM_AVAILABLE_IN_1_14
char *nm_utils_sriov_vf_to_str (const NMSriovVF *vf, gboolean omit_index, GError **error);
NM_AVAILABLE_IN_1_14
NMSriovVF *nm_utils_sriov_vf_from_str (const char *str, GError **error);
/*****************************************************************************/
NM_AVAILABLE_IN_1_12
gint64 nm_utils_get_timestamp_msec (void);
G_END_DECLS
#endif /* __NM_UTILS_H__ */

View file

@ -23,6 +23,8 @@
#include <string.h>
#include "nm-utils.h"
#include "nm-utils-private.h"
#include "nm-core-internal.h"
#include "nm-setting-8021x.h"
#include "nm-setting-bond.h"
#include "nm-setting-dcb.h"
@ -1262,6 +1264,234 @@ test_team_port_full_config (void)
/*****************************************************************************/
static void
test_sriov_vf (void)
{
NMSriovVF *vf1, *vf2;
GError *error = NULL;
char *str;
vf1 = nm_sriov_vf_new (1);
nm_sriov_vf_set_attribute (vf1, NM_SRIOV_VF_ATTRIBUTE_MAC, g_variant_new_string ("00:11:22:33:44:55"));
nm_sriov_vf_set_attribute (vf1, NM_SRIOV_VF_ATTRIBUTE_SPOOF_CHECK, g_variant_new_boolean (TRUE));
nm_sriov_vf_set_attribute (vf1, NM_SRIOV_VF_ATTRIBUTE_TRUST, g_variant_new_boolean (FALSE));
nm_sriov_vf_set_attribute (vf1, NM_SRIOV_VF_ATTRIBUTE_MIN_TX_RATE, g_variant_new_uint32 (100));
nm_sriov_vf_set_attribute (vf1, NM_SRIOV_VF_ATTRIBUTE_MAX_TX_RATE, g_variant_new_uint32 (500));
str = nm_utils_sriov_vf_to_str (vf1, FALSE, &error);
g_assert_no_error (error);
g_assert_cmpstr (str, ==, "1 mac=00:11:22:33:44:55 max-tx-rate=500 min-tx-rate=100 spoof-check=true trust=false");
g_free (str);
vf2 = nm_utils_sriov_vf_from_str (" 1 mac=00:11:22:33:44:55 max-tx-rate=500 min-tx-rate=100", &error);
nmtst_assert_success (vf2, error);
nm_sriov_vf_set_attribute (vf2, NM_SRIOV_VF_ATTRIBUTE_SPOOF_CHECK, g_variant_new_boolean (FALSE));
nm_sriov_vf_set_attribute (vf2, NM_SRIOV_VF_ATTRIBUTE_SPOOF_CHECK, g_variant_new_boolean (TRUE));
nm_sriov_vf_set_attribute (vf2, NM_SRIOV_VF_ATTRIBUTE_TRUST, g_variant_new_boolean (TRUE));
nm_sriov_vf_set_attribute (vf2, NM_SRIOV_VF_ATTRIBUTE_TRUST, NULL);
nm_sriov_vf_set_attribute (vf2, NM_SRIOV_VF_ATTRIBUTE_TRUST, g_variant_new_boolean (FALSE));
g_assert (nm_sriov_vf_equal (vf1, vf2));
nm_sriov_vf_unref (vf1);
nm_sriov_vf_unref (vf2);
}
static void
test_sriov_vf_dup (void)
{
NMSriovVF *vf1, *vf2;
vf1 = nm_sriov_vf_new (1);
nm_sriov_vf_set_attribute (vf1, NM_SRIOV_VF_ATTRIBUTE_MAC, g_variant_new_string ("foobar"));
nm_sriov_vf_set_attribute (vf1, NM_SRIOV_VF_ATTRIBUTE_TRUST, g_variant_new_boolean (FALSE));
nm_sriov_vf_set_attribute (vf1, NM_SRIOV_VF_ATTRIBUTE_MIN_TX_RATE, g_variant_new_uint32 (10));
nm_sriov_vf_set_attribute (vf1, NM_SRIOV_VF_ATTRIBUTE_MAX_TX_RATE, g_variant_new_uint32 (1000));
nm_sriov_vf_add_vlan (vf1, 80);
nm_sriov_vf_set_vlan_qos (vf1, 80, NM_SRIOV_VF_VLAN_PROTOCOL_802_1AD);
vf2 = nm_sriov_vf_dup (vf1);
g_assert (nm_sriov_vf_equal (vf1, vf2));
nm_sriov_vf_unref (vf1);
nm_sriov_vf_unref (vf2);
}
static void
test_sriov_vf_vlan (void)
{
NMSriovVF *vf;
const guint *vlan_ids;
guint num;
GError *error = NULL;
gs_free char *str = NULL;
vf = nm_sriov_vf_new (19);
nm_sriov_vf_set_attribute (vf, NM_SRIOV_VF_ATTRIBUTE_MAC, g_variant_new_string ("00:11:22"));
g_assert (nm_sriov_vf_add_vlan (vf, 80));
g_assert (!nm_sriov_vf_add_vlan (vf, 80));
g_assert (nm_sriov_vf_add_vlan (vf, 82));
g_assert (nm_sriov_vf_add_vlan (vf, 83));
g_assert (nm_sriov_vf_add_vlan (vf, 81));
g_assert (!nm_sriov_vf_remove_vlan (vf, 100));
g_assert (nm_sriov_vf_remove_vlan (vf, 82));
nm_sriov_vf_set_vlan_qos (vf, 81, 0xabba);
nm_sriov_vf_set_vlan_protocol (vf, 81, NM_SRIOV_VF_VLAN_PROTOCOL_802_1AD);
vlan_ids = nm_sriov_vf_get_vlan_ids (vf, &num);
g_assert (vlan_ids);
g_assert_cmpint (num, ==, 3);
g_assert_cmpint (vlan_ids[0], ==, 80);
g_assert_cmpint (vlan_ids[1], ==, 81);
g_assert_cmpint (vlan_ids[2], ==, 83);
g_assert_cmpint (nm_sriov_vf_get_vlan_qos (vf, 80), ==, 0x0);
g_assert_cmpint (nm_sriov_vf_get_vlan_protocol (vf, 80), ==, NM_SRIOV_VF_VLAN_PROTOCOL_802_1Q);
g_assert_cmpint (nm_sriov_vf_get_vlan_qos (vf, 81), ==, 0xabba);
g_assert_cmpint (nm_sriov_vf_get_vlan_protocol (vf, 81), ==, NM_SRIOV_VF_VLAN_PROTOCOL_802_1AD);
nm_sriov_vf_unref (vf);
vf = nm_utils_sriov_vf_from_str ("20 spoof-check=false vlans=85.0.q;4000.0x20.ad;81.10;83", &error);
nmtst_assert_success (vf, error);
vlan_ids = nm_sriov_vf_get_vlan_ids (vf, &num);
g_assert (vlan_ids);
g_assert_cmpint (num, ==, 4);
g_assert_cmpint (vlan_ids[0], ==, 81);
g_assert_cmpint (nm_sriov_vf_get_vlan_qos (vf, 81), ==, 10);
g_assert_cmpint (nm_sriov_vf_get_vlan_protocol (vf, 81), ==, NM_SRIOV_VF_VLAN_PROTOCOL_802_1Q);
g_assert_cmpint (vlan_ids[1], ==, 83);
g_assert_cmpint (nm_sriov_vf_get_vlan_qos (vf, 83), ==, 0);
g_assert_cmpint (nm_sriov_vf_get_vlan_protocol (vf, 83), ==, NM_SRIOV_VF_VLAN_PROTOCOL_802_1Q);
g_assert_cmpint (vlan_ids[2], ==, 85);
g_assert_cmpint (nm_sriov_vf_get_vlan_qos (vf, 85), ==, 0);
g_assert_cmpint (nm_sriov_vf_get_vlan_protocol (vf, 85), ==, NM_SRIOV_VF_VLAN_PROTOCOL_802_1Q);
g_assert_cmpint (vlan_ids[3], ==, 4000);
g_assert_cmpint (nm_sriov_vf_get_vlan_qos (vf, 4000), ==, 0x20);
g_assert_cmpint (nm_sriov_vf_get_vlan_protocol (vf, 4000), ==, NM_SRIOV_VF_VLAN_PROTOCOL_802_1AD);
str = nm_utils_sriov_vf_to_str (vf, FALSE, &error);
nmtst_assert_success (str, error);
g_assert_cmpstr (str, ==, "20 spoof-check=false vlans=81.10;83;85;4000.32.ad");
nm_sriov_vf_unref (vf);
}
static void
test_sriov_setting (void)
{
gs_unref_object NMConnection *con = NULL;
NMSettingConnection *s_con;
NMSettingSriov *s_sriov = NULL;
NMSriovVF *vf1, *vf2, *vf3;
GError *error = NULL;
gboolean success;
con = nm_simple_connection_new ();
s_con = (NMSettingConnection *) nm_setting_connection_new ();
nm_connection_add_setting (con, NM_SETTING (s_con));
g_object_set (s_con,
NM_SETTING_CONNECTION_ID, "Test SR-IOV connection",
NM_SETTING_CONNECTION_UUID, nm_utils_uuid_generate_a (),
NM_SETTING_CONNECTION_AUTOCONNECT, TRUE,
NM_SETTING_CONNECTION_INTERFACE_NAME, "eth0",
NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME,
NULL);
nm_connection_add_setting (con, nm_setting_wired_new ());
s_sriov = (NMSettingSriov *) nm_setting_sriov_new ();
nm_connection_add_setting (con, NM_SETTING (s_sriov));
g_object_set (s_sriov, NM_SETTING_SRIOV_TOTAL_VFS, 16, NULL);
nm_setting_sriov_add_vf (s_sriov, (vf1 = nm_sriov_vf_new (0)));
nm_setting_sriov_add_vf (s_sriov, (vf2 = nm_sriov_vf_new (4)));
nm_setting_sriov_add_vf (s_sriov, (vf3 = nm_sriov_vf_new (10)));
g_assert (nm_setting_sriov_remove_vf_by_index (s_sriov, 4));
nm_sriov_vf_unref (vf2);
nm_setting_sriov_add_vf (s_sriov, (vf2 = nm_sriov_vf_new (2)));
nmtst_assert_connection_verifies_and_normalizable (con);
nmtst_connection_normalize (con);
success = nm_setting_verify ((NMSetting *) s_sriov, con, &error);
nmtst_assert_success (success, error);
g_assert_cmpint (nm_setting_sriov_get_num_vfs (s_sriov), ==, 3);
g_assert_cmpint (nm_sriov_vf_get_index (nm_setting_sriov_get_vf (s_sriov, 0)), ==, 0);
g_assert_cmpint (nm_sriov_vf_get_index (nm_setting_sriov_get_vf (s_sriov, 1)), ==, 2);
g_assert_cmpint (nm_sriov_vf_get_index (nm_setting_sriov_get_vf (s_sriov, 2)), ==, 10);
nm_sriov_vf_unref (vf1);
nm_sriov_vf_unref (vf2);
nm_sriov_vf_unref (vf3);
}
typedef struct {
guint id;
guint qos;
bool proto_ad;
} VlanData;
static void
_test_sriov_parse_vlan_one (const char *string, gboolean exp_res, VlanData *data, guint data_length)
{
NMSriovVF *vf;
gboolean res;
guint i, num_vlans;
const guint *vlan_ids;
vf = nm_sriov_vf_new (1);
g_assert (vf);
res = _nm_sriov_vf_parse_vlans (vf, string, NULL);
g_assert_cmpint (res, ==, exp_res);
if (exp_res) {
vlan_ids = nm_sriov_vf_get_vlan_ids (vf, &num_vlans);
g_assert_cmpint (num_vlans, ==, data_length);
for (i = 0; i < num_vlans; i++) {
g_assert_cmpint (vlan_ids[i], ==, data[i].id);
g_assert_cmpint (nm_sriov_vf_get_vlan_qos (vf, vlan_ids[i]), ==, data[i].qos);
g_assert_cmpint (nm_sriov_vf_get_vlan_protocol (vf, vlan_ids[i]),
==,
data[i].proto_ad ? NM_SRIOV_VF_VLAN_PROTOCOL_802_1AD: NM_SRIOV_VF_VLAN_PROTOCOL_802_1Q);
}
}
nm_sriov_vf_unref (vf);
}
#define test_sriov_parse_vlan_one(string, result, ...) \
{ \
VlanData _data[] = { __VA_ARGS__ }; \
guint _length = G_N_ELEMENTS (_data); \
\
_test_sriov_parse_vlan_one (string, result, _data, _length); \
}
static void
test_sriov_parse_vlans (void)
{
test_sriov_parse_vlan_one ("", FALSE, {});
test_sriov_parse_vlan_one ("1", TRUE, {1, 0, 0});
test_sriov_parse_vlan_one ("1;2", TRUE, {1, 0, 0}, {2, 0, 0});
test_sriov_parse_vlan_one ("4095;;2", TRUE, {2, 0, 0}, {4095, 0, 0});
test_sriov_parse_vlan_one ("1 2", FALSE, {});
test_sriov_parse_vlan_one ("4096", FALSE, {});
test_sriov_parse_vlan_one ("1.10", TRUE, {1, 10, 0});
test_sriov_parse_vlan_one ("1.20.ad", TRUE, {1, 20, 1});
test_sriov_parse_vlan_one ("1.21.q", TRUE, {1, 21, 0});
test_sriov_parse_vlan_one ("9.20.foo", FALSE, {});
test_sriov_parse_vlan_one ("1.20.ad.12", FALSE, {});
test_sriov_parse_vlan_one ("1;1.10", FALSE, {});
test_sriov_parse_vlan_one ("1..1;2", FALSE, {});
test_sriov_parse_vlan_one ("1..ad;2", FALSE, {});
test_sriov_parse_vlan_one ("1.2.ad;2.0.q;5;3", TRUE, {1, 2, 1}, {2, 0, 0}, {3, 0, 0}, {5, 0, 0});
}
/*****************************************************************************/
static void
test_tc_config_qdisc (void)
{
@ -1669,6 +1899,12 @@ main (int argc, char **argv)
g_test_add_func ("/libnm/settings/dcb/priorities", test_dcb_priorities_valid);
g_test_add_func ("/libnm/settings/dcb/bandwidth-sums", test_dcb_bandwidth_sums);
g_test_add_func ("/libnm/settings/sriov/vf", test_sriov_vf);
g_test_add_func ("/libnm/settings/sriov/vf-dup", test_sriov_vf_dup);
g_test_add_func ("/libnm/settings/sriov/vf-vlan", test_sriov_vf_vlan);
g_test_add_func ("/libnm/settings/sriov/setting", test_sriov_setting);
g_test_add_func ("/libnm/settings/sriov/vlans", test_sriov_parse_vlans);
g_test_add_func ("/libnm/settings/tc_config/qdisc", test_tc_config_qdisc);
g_test_add_func ("/libnm/settings/tc_config/action", test_tc_config_action);
g_test_add_func ("/libnm/settings/tc_config/tfilter", test_tc_config_tfilter);

View file

@ -89,6 +89,7 @@
#include "nm-setting-pppoe.h"
#include "nm-setting-proxy.h"
#include "nm-setting-serial.h"
#include "nm-setting-sriov.h"
#include "nm-setting-tc-config.h"
#include "nm-setting-team.h"
#include "nm-setting-team-port.h"

View file

@ -1381,9 +1381,41 @@ libnm_1_12_2 {
libnm_1_14_0 {
global:
nm_connection_get_setting_6lowpan;
nm_connection_get_setting_sriov;
nm_connection_get_setting_wpan;
nm_device_6lowpan_get_type;
nm_device_wpan_get_type;
nm_setting_6lowpan_get_type;
nm_setting_sriov_add_vf;
nm_setting_sriov_clear_vfs;
nm_setting_sriov_get_autoprobe_drivers;
nm_setting_sriov_get_num_vfs;
nm_setting_sriov_get_total_vfs;
nm_setting_sriov_get_type;
nm_setting_sriov_get_vf;
nm_setting_sriov_new;
nm_setting_sriov_remove_vf;
nm_setting_sriov_remove_vf_by_index;
nm_setting_wpan_get_type;
nm_sriov_vf_add_vlan;
nm_sriov_vf_dup;
nm_sriov_vf_equal;
nm_sriov_vf_get_attribute;
nm_sriov_vf_get_attribute_names;
nm_sriov_vf_get_index;
nm_sriov_vf_get_type;
nm_sriov_vf_get_vlan_ids;
nm_sriov_vf_get_vlan_protocol;
nm_sriov_vf_get_vlan_qos;
nm_sriov_vf_new;
nm_sriov_vf_ref;
nm_sriov_vf_remove_vlan;
nm_sriov_vf_set_attribute;
nm_sriov_vf_set_vlan_protocol;
nm_sriov_vf_set_vlan_qos;
nm_sriov_vf_unref;
nm_sriov_vf_vlan_protocol_get_type;
nm_ternary_get_type;
nm_utils_sriov_vf_from_str;
nm_utils_sriov_vf_to_str;
} libnm_1_12_0;

View file

@ -727,6 +727,10 @@ ipv6.ip6-privacy=0
removes extraneous routes from the tables.
</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>sriov.autoprobe-drivers</varname></term>
<listitem><para>If left unspecified, drivers are autoprobed when the SR-IOV VF gets created.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>vpn.timeout</varname></term>
<listitem><para>If left unspecified, default value of 60 seconds is used.</para></listitem>

View file

@ -83,6 +83,7 @@ libnm-core/nm-setting-ovs-bridge.c
libnm-core/nm-setting-ppp.c
libnm-core/nm-setting-pppoe.c
libnm-core/nm-setting-proxy.c
libnm-core/nm-setting-sriov.c
libnm-core/nm-setting-tc-config.c
libnm-core/nm-setting-team.c
libnm-core/nm-setting-team-port.c

View file

@ -287,6 +287,11 @@ const NMMetaSettingInfo nm_meta_setting_infos[] = {
.setting_name = NM_SETTING_SERIAL_SETTING_NAME,
.get_setting_gtype = nm_setting_serial_get_type,
},
[NM_META_SETTING_TYPE_SRIOV] = {
.meta_type = NM_META_SETTING_TYPE_SRIOV,
.setting_name = NM_SETTING_SRIOV_SETTING_NAME,
.get_setting_gtype = nm_setting_sriov_get_type,
},
[NM_META_SETTING_TYPE_TC_CONFIG] = {
.meta_type = NM_META_SETTING_TYPE_TC_CONFIG,
.setting_name = NM_SETTING_TC_CONFIG_SETTING_NAME,

View file

@ -84,6 +84,7 @@ typedef enum {
NM_META_SETTING_TYPE_PPPOE,
NM_META_SETTING_TYPE_PROXY,
NM_META_SETTING_TYPE_SERIAL,
NM_META_SETTING_TYPE_SRIOV,
NM_META_SETTING_TYPE_TC_CONFIG,
NM_META_SETTING_TYPE_TEAM,
NM_META_SETTING_TYPE_TEAM_PORT,

View file

@ -209,6 +209,15 @@ guint nm_direct_hash (gconstpointer str);
guint nm_hash_str (const char *str);
guint nm_str_hash (gconstpointer str);
#define nm_hash_val(static_seed, val) \
({ \
NMHashState _h; \
\
nm_hash_init (&_h, static_seed); \
nm_hash_update_val (&_h, val); \
nm_hash_complete (&_h); \
})
/*****************************************************************************/
/* nm_pstr_*() are for hashing keys that are pointers to strings,

View file

@ -161,6 +161,23 @@ _nm_auto_unref_gsource (GSource **ptr)
}
#define nm_auto_unref_gsource nm_auto(_nm_auto_unref_gsource)
static inline void
_nm_auto_freev (gpointer ptr)
{
gpointer **p = ptr;
gpointer *_ptr;
if (*p) {
for (_ptr = *p; *_ptr; _ptr++)
g_free (*_ptr);
g_free (*p);
}
}
/* g_free a NULL terminated array of pointers, with also freeing each
* pointer with g_free(). It essentially does the same as
* gs_strfreev / g_strfreev(), but not restricted to strv arrays. */
#define nm_auto_freev nm_auto(_nm_auto_freev)
/*****************************************************************************/
/* http://stackoverflow.com/a/11172679 */

View file

@ -724,6 +724,7 @@ NM_UTILS_LOOKUP_STR_DEFINE (nm_device_state_reason_to_str, NMDeviceStateReason,
NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_OVSDB_FAILED, "ovsdb-failed"),
NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE, "ip-address-duplicate"),
NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_IP_METHOD_UNSUPPORTED, "ip-method-unsupported"),
NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED, "sriov-configuration-failed"),
);
#define reason_to_string(reason) \
@ -3937,7 +3938,7 @@ nm_device_update_from_platform_link (NMDevice *self, const NMPlatformLink *plink
}
static void
device_init_sriov_num_vfs (NMDevice *self)
device_init_static_sriov_num_vfs (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
gs_free char *value = NULL;
@ -3951,8 +3952,8 @@ device_init_sriov_num_vfs (NMDevice *self)
NULL);
num_vfs = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXINT32, -1);
if (num_vfs >= 0) {
nm_platform_link_set_sriov_num_vfs (nm_device_get_platform (self),
priv->ifindex, num_vfs);
nm_platform_link_set_sriov_params (nm_device_get_platform (self),
priv->ifindex, num_vfs, -1);
}
}
}
@ -3971,7 +3972,7 @@ config_changed (NMConfig *config,
priv->ignore_carrier = nm_config_data_get_ignore_carrier (config_data, self);
if (NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_VALUES))
device_init_sriov_num_vfs (self);
device_init_static_sriov_num_vfs (self);
}
static void
@ -4115,7 +4116,7 @@ realize_start_setup (NMDevice *self,
nm_device_set_carrier_from_platform (self);
device_init_sriov_num_vfs (self);
device_init_static_sriov_num_vfs (self);
nm_assert (!priv->stats.timeout_id);
real_rate = _stats_refresh_rate_real (priv->stats.refresh_rate_ms);
@ -5859,9 +5860,140 @@ lldp_rx_enabled (NMDevice *self)
return lldp == NM_SETTING_CONNECTION_LLDP_ENABLE_RX;
}
static NMPlatformVF *
sriov_vf_config_to_platform (NMDevice *self,
NMSriovVF *vf,
GError **error)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
gs_free NMPlatformVF *plat_vf = NULL;
const guint *vlan_ids;
GVariant *variant;
guint i, num_vlans;
gsize length;
g_return_val_if_fail (!error || !*error, FALSE);
vlan_ids = nm_sriov_vf_get_vlan_ids (vf, &num_vlans);
plat_vf = g_malloc0 ( sizeof (NMPlatformVF)
+ sizeof (NMPlatformVFVlan) * num_vlans);
plat_vf->index = nm_sriov_vf_get_index (vf);
variant = nm_sriov_vf_get_attribute (vf, NM_SRIOV_VF_ATTRIBUTE_SPOOF_CHECK);
if (variant)
plat_vf->spoofchk = g_variant_get_boolean (variant);
else
plat_vf->spoofchk = -1;
variant = nm_sriov_vf_get_attribute (vf, NM_SRIOV_VF_ATTRIBUTE_TRUST);
if (variant)
plat_vf->trust = g_variant_get_boolean (variant);
else
plat_vf->trust = -1;
variant = nm_sriov_vf_get_attribute (vf, NM_SRIOV_VF_ATTRIBUTE_MAC);
if (variant) {
if (!_nm_utils_hwaddr_aton (g_variant_get_string (variant, NULL),
plat_vf->mac.data,
sizeof (plat_vf->mac.data),
&length)) {
g_set_error (error,
NM_DEVICE_ERROR,
NM_DEVICE_ERROR_FAILED,
"invalid MAC %s",
g_variant_get_string (variant, NULL));
return NULL;
}
if (length != priv->hw_addr_len) {
g_set_error (error,
NM_DEVICE_ERROR,
NM_DEVICE_ERROR_FAILED,
"wrong MAC length %" G_GSIZE_FORMAT ", should be %u",
length, priv->hw_addr_len);
return NULL;
}
plat_vf->mac.len = length;
}
variant = nm_sriov_vf_get_attribute (vf, NM_SRIOV_VF_ATTRIBUTE_MIN_TX_RATE);
if (variant)
plat_vf->min_tx_rate = g_variant_get_uint32 (variant);
variant = nm_sriov_vf_get_attribute (vf, NM_SRIOV_VF_ATTRIBUTE_MAX_TX_RATE);
if (variant)
plat_vf->max_tx_rate = g_variant_get_uint32 (variant);
plat_vf->num_vlans = num_vlans;
plat_vf->vlans = (NMPlatformVFVlan *) (&plat_vf[1]);
for (i = 0; i < num_vlans; i++) {
plat_vf->vlans[i].id = vlan_ids[i];
plat_vf->vlans[i].qos = nm_sriov_vf_get_vlan_qos (vf, vlan_ids[i]);
plat_vf->vlans[i].proto_ad = nm_sriov_vf_get_vlan_protocol (vf, vlan_ids[i]) == NM_SRIOV_VF_VLAN_PROTOCOL_802_1AD;
}
return g_steal_pointer (&plat_vf);
}
static NMActStageReturn
act_stage1_prepare (NMDevice *self, NMDeviceStateReason *out_failure_reason)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMSettingSriov *s_sriov;
guint i, num;
if ( priv->ifindex > 0
&& nm_device_has_capability (self, NM_DEVICE_CAP_SRIOV)
&& (s_sriov = (NMSettingSriov *) nm_device_get_applied_setting (self, NM_TYPE_SETTING_SRIOV))) {
nm_auto_freev NMPlatformVF **plat_vfs = NULL;
gs_free_error GError *error = NULL;
gs_free const char *str = NULL;
NMSriovVF *vf;
int autoprobe;
autoprobe = nm_setting_sriov_get_autoprobe_drivers (s_sriov);
if (autoprobe == NM_TERNARY_DEFAULT) {
str = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA,
"sriov.autoprobe-drivers", self);
autoprobe = _nm_utils_ascii_str_to_int64 (str, 10,
NM_TERNARY_FALSE,
NM_TERNARY_TRUE,
NM_TERNARY_TRUE);
}
num = nm_setting_sriov_get_num_vfs (s_sriov);
plat_vfs = g_new0 (NMPlatformVF *, num + 1);
for (i = 0; i < num; i++) {
vf = nm_setting_sriov_get_vf (s_sriov, i);
plat_vfs[i] = sriov_vf_config_to_platform (self, vf, &error);
if (!plat_vfs[i]) {
_LOGE (LOGD_DEVICE,
"failed to apply SR-IOV VF '%s': %s",
nm_utils_sriov_vf_to_str (vf, FALSE, NULL),
error->message);
NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED);
return NM_ACT_STAGE_RETURN_FAILURE;
}
}
if (!nm_platform_link_set_sriov_params (nm_device_get_platform (self),
priv->ifindex,
nm_setting_sriov_get_total_vfs (s_sriov),
autoprobe)) {
_LOGE (LOGD_DEVICE, "failed to apply SR-IOV parameters");
NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED);
return NM_ACT_STAGE_RETURN_FAILURE;
}
if (!nm_platform_link_set_sriov_vfs (nm_device_get_platform (self),
priv->ifindex,
(const NMPlatformVF *const *) plat_vfs)) {
_LOGE (LOGD_DEVICE, "failed to apply SR-IOV VFs");
NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED);
return NM_ACT_STAGE_RETURN_FAILURE;
}
}
return NM_ACT_STAGE_RETURN_SUCCESS;
}

View file

@ -602,12 +602,6 @@ link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu)
return NM_PLATFORM_ERROR_SUCCESS;
}
static gboolean
link_set_sriov_num_vfs (NMPlatform *platform, int ifindex, guint num_vfs)
{
return TRUE;
}
static const char *
link_get_udi (NMPlatform *platform, int ifindex)
{
@ -1422,7 +1416,6 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass)
platform_class->link_set_address = link_set_address;
platform_class->link_set_mtu = link_set_mtu;
platform_class->link_set_sriov_num_vfs = link_set_sriov_num_vfs;
platform_class->link_get_driver_info = link_get_driver_info;

View file

@ -215,6 +215,46 @@ G_STATIC_ASSERT (RTA_MAX == (__RTA_MAX - 1));
/*****************************************************************************/
/* Redefine VF enums and structures that are not available on older kernels. */
#define IFLA_VF_UNSPEC 0
#define IFLA_VF_MAC 1
#define IFLA_VF_VLAN 2
#define IFLA_VF_TX_RATE 3
#define IFLA_VF_SPOOFCHK 4
#define IFLA_VF_LINK_STATE 5
#define IFLA_VF_RATE 6
#define IFLA_VF_RSS_QUERY_EN 7
#define IFLA_VF_STATS 8
#define IFLA_VF_TRUST 9
#define IFLA_VF_IB_NODE_GUID 10
#define IFLA_VF_IB_PORT_GUID 11
#define IFLA_VF_VLAN_LIST 12
#define IFLA_VF_VLAN_INFO_UNSPEC 0
#define IFLA_VF_VLAN_INFO 1
/* valid for TRUST, SPOOFCHK, LINK_STATE, RSS_QUERY_EN */
struct _ifla_vf_setting {
guint32 vf;
guint32 setting;
};
struct _ifla_vf_rate {
guint32 vf;
guint32 min_tx_rate;
guint32 max_tx_rate;
};
struct _ifla_vf_vlan_info {
guint32 vf;
guint32 vlan; /* 0 - 4095, 0 disables VLAN filter */
guint32 qos;
guint16 vlan_proto; /* VLAN protocol, either 802.1Q or 802.1ad */
};
/*****************************************************************************/
#define _NMLOG_PREFIX_NAME "platform-linux"
#define _NMLOG_DOMAIN LOGD_PLATFORM
#define _NMLOG2_DOMAIN LOGD_PLATFORM
@ -5528,16 +5568,18 @@ nla_put_failure:
}
static gboolean
link_set_sriov_num_vfs (NMPlatform *platform, int ifindex, guint num_vfs)
link_set_sriov_params (NMPlatform *platform,
int ifindex,
guint num_vfs,
int autoprobe)
{
nm_auto_pop_netns NMPNetns *netns = NULL;
nm_auto_close int dirfd = -1;
int total, current;
gboolean current_autoprobe;
guint total, current_num;
char ifname[IFNAMSIZ];
char buf[64];
_LOGD ("link: change %d: num VFs: %u", ifindex, num_vfs);
if (!nm_platform_netns_push (platform, &netns))
return FALSE;
@ -5545,46 +5587,69 @@ link_set_sriov_num_vfs (NMPlatform *platform, int ifindex, guint num_vfs)
if (!dirfd)
return FALSE;
total = nm_platform_sysctl_get_int32 (platform,
NMP_SYSCTL_PATHID_NETDIR (dirfd,
ifname,
"device/sriov_totalvfs"),
-1);
if (total < 1)
total = nm_platform_sysctl_get_int_checked (platform,
NMP_SYSCTL_PATHID_NETDIR (dirfd,
ifname,
"device/sriov_totalvfs"),
10, 0, G_MAXUINT, 0);
if (errno)
return FALSE;
if (num_vfs > total) {
_LOGW ("link: %d only supports %u VFs (requested %u)", ifindex, total, num_vfs);
num_vfs = total;
}
current = nm_platform_sysctl_get_int32 (platform,
NMP_SYSCTL_PATHID_NETDIR (dirfd,
ifname,
"device/sriov_numvfs"),
-1);
if (current == num_vfs)
/*
* Take special care when setting new values:
* - don't touch anything if the right values are already set
* - to change the number of VFs or autoprobe we need to destroy existing VFs
* - the autoprobe setting is irrelevant when numvfs is zero
*/
current_num = nm_platform_sysctl_get_int_checked (platform,
NMP_SYSCTL_PATHID_NETDIR (dirfd,
ifname,
"device/sriov_numvfs"),
10, 0, G_MAXUINT, 0);
current_autoprobe = nm_platform_sysctl_get_int_checked (platform,
NMP_SYSCTL_PATHID_NETDIR (dirfd,
ifname,
"device/sriov_drivers_autoprobe"),
10, 0, G_MAXUINT, 0);
if ( current_num == num_vfs
&& (autoprobe == -1 || current_autoprobe == autoprobe))
return TRUE;
if (current != 0) {
/* We need to destroy all other VFs before changing the value */
if (current_num != 0) {
/* We need to destroy all other VFs before changing any value */
if (!nm_platform_sysctl_set (NM_PLATFORM_GET,
NMP_SYSCTL_PATHID_NETDIR (dirfd,
ifname,
"device/sriov_numvfs"),
"0")) {
_LOGW ("link: couldn't set SR-IOV num_vfs to %d: %s", 0, strerror (errno));
_LOGW ("link: couldn't reset SR-IOV num_vfs: %s", strerror (errno));
return FALSE;
}
if (num_vfs == 0)
return TRUE;
}
/* Finally, set the desired value */
if (num_vfs == 0)
return TRUE;
if ( autoprobe >= 0
&& current_autoprobe != autoprobe
&& !nm_platform_sysctl_set (NM_PLATFORM_GET,
NMP_SYSCTL_PATHID_NETDIR (dirfd,
ifname,
"device/sriov_drivers_autoprobe"),
nm_sprintf_buf (buf, "%d", autoprobe))) {
_LOGW ("link: couldn't set SR-IOV drivers-autoprobe to %d: %s", autoprobe, strerror (errno));
return FALSE;
}
if (!nm_platform_sysctl_set (NM_PLATFORM_GET,
NMP_SYSCTL_PATHID_NETDIR (dirfd,
ifname,
"device/sriov_numvfs"),
nm_sprintf_buf (buf, "%d", num_vfs))) {
nm_sprintf_buf (buf, "%u", num_vfs))) {
_LOGW ("link: couldn't set SR-IOV num_vfs to %d: %s", num_vfs, strerror (errno));
return FALSE;
}
@ -5592,6 +5657,101 @@ link_set_sriov_num_vfs (NMPlatform *platform, int ifindex, guint num_vfs)
return TRUE;
}
static gboolean
link_set_sriov_vfs (NMPlatform *platform, int ifindex, const NMPlatformVF *const *vfs)
{
nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
struct nlattr *list, *info, *vlan_list;
guint i;
nlmsg = _nl_msg_new_link (RTM_NEWLINK,
0,
ifindex,
NULL,
0,
0);
if (!nlmsg)
g_return_val_if_reached (NM_PLATFORM_ERROR_UNSPECIFIED);
if (!(list = nla_nest_start (nlmsg, IFLA_VFINFO_LIST)))
goto nla_put_failure;
for (i = 0; vfs[i]; i++) {
const NMPlatformVF *vf = vfs[i];
if (!(info = nla_nest_start (nlmsg, IFLA_VF_INFO)))
goto nla_put_failure;
if (vf->spoofchk >= 0) {
struct _ifla_vf_setting ivs = { 0 };
ivs.vf = vf->index;
ivs.setting = vf->spoofchk;
NLA_PUT (nlmsg, IFLA_VF_SPOOFCHK, sizeof (ivs), &ivs);
}
if (vf->trust >= 0) {
struct _ifla_vf_setting ivs = { 0 };
ivs.vf = vf->index;
ivs.setting = vf->trust;
NLA_PUT (nlmsg, IFLA_VF_TRUST, sizeof (ivs), &ivs);
}
if (vf->mac.len) {
struct ifla_vf_mac ivm = { 0 };
ivm.vf = vf->index;
memcpy (ivm.mac, vf->mac.data, vf->mac.len);
NLA_PUT (nlmsg, IFLA_VF_MAC, sizeof (ivm), &ivm);
}
if (vf->min_tx_rate || vf->max_tx_rate) {
struct _ifla_vf_rate ivr = { 0 };
ivr.vf = vf->index;
ivr.min_tx_rate = vf->min_tx_rate;
ivr.max_tx_rate = vf->max_tx_rate;
NLA_PUT (nlmsg, IFLA_VF_RATE, sizeof (ivr), &ivr);
}
/* Kernel only supports one VLAN per VF now. If this
* changes in the future, we need to figure out how to
* clear existing VLANs and set new ones in one message
* with the new API.*/
if (vf->num_vlans > 1) {
_LOGW ("multiple VLANs per VF are not supported at the moment");
return FALSE;
} else {
struct _ifla_vf_vlan_info ivvi = { 0 };
if (!(vlan_list = nla_nest_start (nlmsg, IFLA_VF_VLAN_LIST)))
goto nla_put_failure;
ivvi.vf = vf->index;
if (vf->num_vlans == 1) {
ivvi.vlan = vf->vlans[0].id;
ivvi.qos = vf->vlans[0].qos;
ivvi.vlan_proto = htons (vf->vlans[0].proto_ad ? ETH_P_8021AD : ETH_P_8021Q);
} else {
/* Clear existing VLAN */
ivvi.vlan = 0;
ivvi.qos = 0;
ivvi.vlan_proto = htons (ETH_P_8021Q);
}
NLA_PUT (nlmsg, IFLA_VF_VLAN_INFO, sizeof (ivvi), &ivvi);
nla_nest_end (nlmsg, vlan_list);
}
nla_nest_end (nlmsg, info);
}
nla_nest_end (nlmsg, list);
return do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) == NM_PLATFORM_ERROR_SUCCESS;
nla_put_failure:
g_return_val_if_reached (FALSE);
}
static char *
link_get_physical_port_id (NMPlatform *platform, int ifindex)
{
@ -7735,7 +7895,8 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
platform_class->link_get_permanent_address = link_get_permanent_address;
platform_class->link_set_mtu = link_set_mtu;
platform_class->link_set_name = link_set_name;
platform_class->link_set_sriov_num_vfs = link_set_sriov_num_vfs;
platform_class->link_set_sriov_params = link_set_sriov_params;
platform_class->link_set_sriov_vfs = link_set_sriov_vfs;
platform_class->link_get_physical_port_id = link_get_physical_port_id;
platform_class->link_get_dev_id = link_get_dev_id;

View file

@ -1463,18 +1463,52 @@ nm_platform_link_supports_sriov (NMPlatform *self, int ifindex)
return klass->link_supports_sriov (self, ifindex);
}
/**
* nm_platform_link_set_sriov_params:
* @self: platform instance
* @ifindex: the index of the interface to change
* @num_vfs: the number of VFs to create
* @autoprobe: -1 to keep the current autoprobe-drivers value,
* or {0,1} to set a new value
*/
gboolean
nm_platform_link_set_sriov_num_vfs (NMPlatform *self, int ifindex, guint num_vfs)
nm_platform_link_set_sriov_params (NMPlatform *self,
int ifindex,
guint num_vfs,
int autoprobe)
{
_CHECK_SELF (self, klass, FALSE);
g_return_val_if_fail (ifindex > 0, FALSE);
g_return_val_if_fail (NM_IN_SET (autoprobe, -1, 0, 1), FALSE);
_LOGD ("link: setting %u VFs for %s (%d)",
_LOGD ("link: setting %u total VFs and autoprobe %d for %s (%d)",
num_vfs,
autoprobe,
nm_strquote_a (25, nm_platform_link_get_name (self, ifindex)),
ifindex);
return klass->link_set_sriov_num_vfs (self, ifindex, num_vfs);
return klass->link_set_sriov_params (self, ifindex, num_vfs, autoprobe);
}
gboolean
nm_platform_link_set_sriov_vfs (NMPlatform *self, int ifindex, const NMPlatformVF *const *vfs)
{
guint i;
_CHECK_SELF (self, klass, FALSE);
g_return_val_if_fail (ifindex > 0, FALSE);
_LOGD ("link: setting VFs for \"%s\" (%d):",
nm_platform_link_get_name (self, ifindex),
ifindex);
for (i = 0; vfs[i]; i++) {
const NMPlatformVF *vf = vfs[i];
_LOGD ("link: VF %s", nm_platform_vf_to_string (vf, NULL, 0));
}
return klass->link_set_sriov_vfs (self, ifindex, vfs);
}
/**
@ -6042,6 +6076,56 @@ nm_platform_tfilter_cmp (const NMPlatformTfilter *a, const NMPlatformTfilter *b)
return 0;
}
const char *
nm_platform_vf_to_string (const NMPlatformVF *vf, char *buf, gsize len)
{
char str_mac[128], mac[128];
char str_spoof_check[64];
char str_trust[64];
char str_min_tx_rate[64];
char str_max_tx_rate[64];
nm_auto_free_gstring GString *gstr_vlans = NULL;
guint i;
if (!nm_utils_to_string_buffer_init_null (vf, &buf, &len))
return buf;
if (vf->mac.len) {
nm_utils_hwaddr_ntoa_buf (vf->mac.data, vf->mac.len, TRUE, mac, sizeof (mac));
nm_sprintf_buf (str_mac, " mac %s", mac);
} else
str_mac[0] = '\0';
if (vf->num_vlans) {
gstr_vlans = g_string_new ("");
for (i = 0; i < vf->num_vlans; i++) {
g_string_append_printf (gstr_vlans, " vlan %u", (unsigned) vf->vlans[i].id);
if (vf->vlans[i].qos)
g_string_append_printf (gstr_vlans, " qos %u", (unsigned) vf->vlans[i].qos);
if (vf->vlans[i].proto_ad)
g_string_append (gstr_vlans, " proto 802.1ad");
}
}
g_snprintf (buf, len,
"%u" /* index */
"%s" /* MAC */
"%s" /* spoof check */
"%s" /* trust */
"%s" /* min tx rate */
"%s" /* max tx rate */
"%s", /* VLANs */
vf->index,
str_mac,
vf->spoofchk >= 0 ? nm_sprintf_buf (str_spoof_check, " spoofchk %d", vf->spoofchk) : "",
vf->trust >= 0 ? nm_sprintf_buf (str_trust, " trust %d", vf->trust) : "",
vf->min_tx_rate ? nm_sprintf_buf (str_min_tx_rate, " min_tx_rate %u", (unsigned) vf->min_tx_rate) : "",
vf->max_tx_rate ? nm_sprintf_buf (str_max_tx_rate, " max_tx_rate %u", (unsigned) vf->max_tx_rate) : "",
gstr_vlans ? gstr_vlans->str : "");
return buf;
}
void
nm_platform_link_hash_update (const NMPlatformLink *obj, NMHashState *h)
{

View file

@ -607,6 +607,26 @@ typedef struct {
extern const NMPlatformVTableRoute nm_platform_vtable_route_v4;
extern const NMPlatformVTableRoute nm_platform_vtable_route_v6;
typedef struct {
guint16 id;
guint32 qos;
bool proto_ad:1;
} NMPlatformVFVlan;
typedef struct {
guint32 index;
guint32 min_tx_rate;
guint32 max_tx_rate;
guint num_vlans;
NMPlatformVFVlan *vlans;
struct {
guint8 data[20]; /* NM_UTILS_HWADDR_LEN_MAX */
guint8 len;
} mac;
gint8 spoofchk;
gint8 trust;
} NMPlatformVF;
typedef struct {
in_addr_t local;
in_addr_t remote;
@ -802,7 +822,8 @@ typedef struct {
NMPlatformError (*link_set_address) (NMPlatform *, int ifindex, gconstpointer address, size_t length);
NMPlatformError (*link_set_mtu) (NMPlatform *, int ifindex, guint32 mtu);
gboolean (*link_set_name) (NMPlatform *, int ifindex, const char *name);
gboolean (*link_set_sriov_num_vfs) (NMPlatform *, int ifindex, guint num_vfs);
gboolean (*link_set_sriov_params) (NMPlatform *, int ifindex, guint num_vfs, int autoprobe);
gboolean (*link_set_sriov_vfs) (NMPlatform *self, int ifindex, const NMPlatformVF *const *vfs);
char * (*link_get_physical_port_id) (NMPlatform *, int ifindex);
guint (*link_get_dev_id) (NMPlatform *, int ifindex);
@ -1193,7 +1214,8 @@ gboolean nm_platform_link_get_permanent_address (NMPlatform *self, int ifindex,
NMPlatformError nm_platform_link_set_address (NMPlatform *self, int ifindex, const void *address, size_t length);
NMPlatformError nm_platform_link_set_mtu (NMPlatform *self, int ifindex, guint32 mtu);
gboolean nm_platform_link_set_name (NMPlatform *self, int ifindex, const char *name);
gboolean nm_platform_link_set_sriov_num_vfs (NMPlatform *self, int ifindex, guint num_vfs);
gboolean nm_platform_link_set_sriov_params (NMPlatform *self, int ifindex, guint num_vfs, int autoprobe);
gboolean nm_platform_link_set_sriov_vfs (NMPlatform *self, int ifindex, const NMPlatformVF *const *vfs);
char *nm_platform_link_get_physical_port_id (NMPlatform *self, int ifindex);
guint nm_platform_link_get_dev_id (NMPlatform *self, int ifindex);
@ -1434,6 +1456,7 @@ const char *nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, ch
const char *nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsize len);
const char *nm_platform_qdisc_to_string (const NMPlatformQdisc *qdisc, char *buf, gsize len);
const char *nm_platform_tfilter_to_string (const NMPlatformTfilter *tfilter, char *buf, gsize len);
const char *nm_platform_vf_to_string (const NMPlatformVF *vf, char *buf, gsize len);
const char *nm_platform_vlan_qos_mapping_to_string (const char *name,
const NMVlanQosMapping *map,

View file

@ -1178,7 +1178,7 @@ make_user_setting (shvarFile *ifcfg)
const char *key;
nm_auto_free_gstring GString *str = NULL;
keys = svGetKeys (ifcfg);
keys = svGetKeys (ifcfg, SV_KEY_TYPE_USER);
if (!keys)
return NULL;
@ -1187,9 +1187,6 @@ make_user_setting (shvarFile *ifcfg)
const char *value;
gs_free char *value_to_free = NULL;
if (!g_str_has_prefix (key, "NM_USER_"))
continue;
value = svGetValue (ifcfg, key, &value_to_free);
if (!value)
@ -1981,6 +1978,68 @@ error:
return NULL;
}
static NMSetting *
make_sriov_setting (shvarFile *ifcfg)
{
gs_unref_hashtable GHashTable *keys = NULL;
gs_unref_ptrarray GPtrArray *vfs = NULL;
NMTernary autoprobe_drivers;
NMSettingSriov *s_sriov;
int total_vfs;
total_vfs = svGetValueInt64 (ifcfg, "SRIOV_TOTAL_VFS", 10, 0, G_MAXINT32, 0);
if (!total_vfs)
return NULL;
autoprobe_drivers = svGetValueInt64 (ifcfg,
"SRIOV_AUTOPROBE_DRIVERS",
10,
NM_TERNARY_FALSE,
NM_TERNARY_TRUE,
NM_TERNARY_DEFAULT);
keys = svGetKeys (ifcfg, SV_KEY_TYPE_SRIOV_VF);
if (keys) {
GHashTableIter iter;
const char *key;
g_hash_table_iter_init (&iter, keys);
while (g_hash_table_iter_next (&iter, (gpointer *) &key, NULL)) {
gs_free_error GError *error = NULL;
gs_free char *value_to_free = NULL;
const char *value;
NMSriovVF *vf;
nm_assert (g_str_has_prefix (key, "SRIOV_VF"));
value = svGetValue (ifcfg, key, &value_to_free);
if (!value)
continue;
key += NM_STRLEN ("SRIOV_VF");
vf = _nm_utils_sriov_vf_from_strparts (key, value, &error);
if (!vf) {
PARSE_WARNING ("ignoring invalid SR-IOV VF '%s %s': %s",
key, value, error->message);
continue;
}
if (!vfs)
vfs = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_sriov_vf_unref);
g_ptr_array_add (vfs, vf);
}
}
s_sriov = (NMSettingSriov *) nm_setting_sriov_new ();
g_object_set (s_sriov,
NM_SETTING_SRIOV_TOTAL_VFS, total_vfs,
NM_SETTING_SRIOV_VFS, vfs,
NM_SETTING_SRIOV_AUTOPROBE_DRIVERS, (int) autoprobe_drivers,
NULL);
return (NMSetting *) s_sriov;
}
static NMSetting *
make_tc_setting (shvarFile *ifcfg)
{
@ -5327,6 +5386,7 @@ connection_from_file_full (const char *filename,
gs_free char *type = NULL;
char *devtype, *bootproto;
NMSetting *s_ip4, *s_ip6, *s_tc, *s_proxy, *s_port, *s_dcb = NULL, *s_user;
NMSetting *s_sriov;
const char *ifcfg_name = NULL;
gboolean has_ip4_defroute = FALSE;
gboolean has_complex_routes_v4;
@ -5582,6 +5642,10 @@ connection_from_file_full (const char *filename,
nm_connection_add_setting (connection, s_ip4);
}
s_sriov = make_sriov_setting (parsed);
if (s_sriov)
nm_connection_add_setting (connection, s_sriov);
s_tc = make_tc_setting (parsed);
if (s_tc)
nm_connection_add_setting (connection, s_tc);

View file

@ -2135,6 +2135,45 @@ write_user_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
return TRUE;
}
static void
write_sriov_setting (NMConnection *connection, shvarFile *ifcfg)
{
NMSettingSriov *s_sriov;
guint i, num = 0;
NMTernary b;
NMSriovVF *vf;
char key[32];
char *str;
svUnsetAll (ifcfg, SV_KEY_TYPE_SRIOV_VF);
s_sriov = nm_connection_get_setting_sriov (connection);
if (s_sriov)
num = nm_setting_sriov_get_total_vfs (s_sriov);
if (num == 0) {
svUnsetValue (ifcfg, "SRIOV_TOTAL_VFS");
svUnsetValue (ifcfg, "SRIOV_AUTOPROBE_DRIVERS");
return;
}
svSetValueInt64 (ifcfg, "SRIOV_TOTAL_VFS", num);
b = nm_setting_sriov_get_autoprobe_drivers (s_sriov);
if (b != NM_TERNARY_DEFAULT)
svSetValueInt64 (ifcfg, "SRIOV_AUTOPROBE_DRIVERS", b);
else
svUnsetValue (ifcfg, "SRIOV_AUTOPROBE_DRIVERS");
num = nm_setting_sriov_get_num_vfs (s_sriov);
for (i = 0; i < num; i++) {
vf = nm_setting_sriov_get_vf (s_sriov, i);
nm_sprintf_buf (key, "SRIOV_VF%u", nm_sriov_vf_get_index (vf));
str = nm_utils_sriov_vf_to_str (vf, TRUE, NULL);
svSetValueStr (ifcfg, key, str);
g_free (str);
}
}
static gboolean
write_tc_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
{
@ -2921,6 +2960,8 @@ do_write_construct (NMConnection *connection,
if (!write_user_setting (connection, ifcfg, error))
return FALSE;
write_sriov_setting (connection, ifcfg);
if (!write_tc_setting (connection, ifcfg, error))
return FALSE;

View file

@ -870,8 +870,61 @@ svCreateFile (const char *name)
/*****************************************************************************/
static gboolean
_is_all_digits (const char *str)
{
return str[0]
&& NM_STRCHAR_ALL (str, ch, g_ascii_isdigit (ch));
}
#define IS_NUMBERED_TAG(key, tab_name) \
({ \
const char *_key = (key); \
\
( (strncmp (_key, tab_name, NM_STRLEN (tab_name)) == 0) \
&& _is_all_digits (&_key[NM_STRLEN (tab_name)])); \
})
static gboolean
_svKeyMatchesType (const char *key, SvKeyType match_key_type)
{
if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_ANY))
return TRUE;
if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_ROUTE_SVFORMAT)) {
if ( IS_NUMBERED_TAG (key, "ADDRESS")
|| IS_NUMBERED_TAG (key, "NETMASK")
|| IS_NUMBERED_TAG (key, "GATEWAY")
|| IS_NUMBERED_TAG (key, "METRIC")
|| IS_NUMBERED_TAG (key, "OPTIONS"))
return TRUE;
}
if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_IP4_ADDRESS)) {
if ( IS_NUMBERED_TAG (key, "IPADDR")
|| IS_NUMBERED_TAG (key, "PREFIX")
|| IS_NUMBERED_TAG (key, "NETMASK")
|| IS_NUMBERED_TAG (key, "GATEWAY"))
return TRUE;
}
if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_USER)) {
if (g_str_has_prefix (key, "NM_USER_"))
return TRUE;
}
if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_TC)) {
if ( IS_NUMBERED_TAG (key, "QDISC")
|| IS_NUMBERED_TAG (key, "FILTER"))
return TRUE;
}
if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_SRIOV_VF)) {
if (IS_NUMBERED_TAG (key, "SRIOV_VF"))
return TRUE;
}
return FALSE;
}
GHashTable *
svGetKeys (shvarFile *s)
svGetKeys (shvarFile *s, SvKeyType match_key_type)
{
GHashTable *keys = NULL;
CList *current;
@ -881,7 +934,9 @@ svGetKeys (shvarFile *s)
c_list_for_each (current, &s->lst_head) {
line = c_list_entry (current, shvarLine, lst);
if (line->key && line->line) {
if ( line->key
&& line->line
&& _svKeyMatchesType (line->key, match_key_type)) {
/* we don't clone the keys. The keys are only valid
* until @s gets modified. */
if (!keys)
@ -1120,21 +1175,6 @@ svGetValueEnum (shvarFile *s, const char *key,
/*****************************************************************************/
static gboolean
_is_all_digits (const char *str)
{
return str[0]
&& NM_STRCHAR_ALL (str, ch, g_ascii_isdigit (ch));
}
#define IS_NUMBERED_TAG(key, tab_name) \
({ \
const char *_key = (key); \
\
( (strncmp (_key, tab_name, NM_STRLEN (tab_name)) == 0) \
&& _is_all_digits (&_key[NM_STRLEN (tab_name)])); \
})
gboolean
svUnsetAll (shvarFile *s, SvKeyType match_key_type)
{
@ -1150,38 +1190,11 @@ svUnsetAll (shvarFile *s, SvKeyType match_key_type)
if (!line->key)
continue;
if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_ANY))
goto do_clear;
if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_ROUTE_SVFORMAT)) {
if ( IS_NUMBERED_TAG (line->key, "ADDRESS")
|| IS_NUMBERED_TAG (line->key, "NETMASK")
|| IS_NUMBERED_TAG (line->key, "GATEWAY")
|| IS_NUMBERED_TAG (line->key, "METRIC")
|| IS_NUMBERED_TAG (line->key, "OPTIONS"))
goto do_clear;
}
if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_IP4_ADDRESS)) {
if ( IS_NUMBERED_TAG (line->key, "IPADDR")
|| IS_NUMBERED_TAG (line->key, "PREFIX")
|| IS_NUMBERED_TAG (line->key, "NETMASK")
|| IS_NUMBERED_TAG (line->key, "GATEWAY"))
goto do_clear;
}
if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_USER)) {
if (g_str_has_prefix (line->key, "NM_USER_"))
goto do_clear;
}
if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_TC)) {
if ( IS_NUMBERED_TAG (line->key, "QDISC")
|| IS_NUMBERED_TAG (line->key, "FILTER"))
goto do_clear;
}
continue;
do_clear:
if (nm_clear_g_free (&line->line)) {
ASSERT_shvarLine (line);
changed = TRUE;
if (_svKeyMatchesType (line->key, match_key_type)) {
if (nm_clear_g_free (&line->line)) {
ASSERT_shvarLine (line);
changed = TRUE;
}
}
}

View file

@ -33,6 +33,15 @@
typedef struct _shvarFile shvarFile;
typedef enum {
SV_KEY_TYPE_ANY = (1LL << 0),
SV_KEY_TYPE_ROUTE_SVFORMAT = (1LL << 1),
SV_KEY_TYPE_IP4_ADDRESS = (1LL << 2),
SV_KEY_TYPE_TC = (1LL << 3),
SV_KEY_TYPE_USER = (1LL << 4),
SV_KEY_TYPE_SRIOV_VF = (1LL << 5),
} SvKeyType;
const char *svFileGetName (const shvarFile *s);
void _nmtst_svFileSetName (shvarFile *s, const char *fileName);
@ -58,7 +67,7 @@ char *svGetValueStr_cp (shvarFile *s, const char *key);
int svParseBoolean (const char *value, int def);
GHashTable *svGetKeys (shvarFile *s);
GHashTable *svGetKeys (shvarFile *s, SvKeyType match_key_type);
/* return TRUE if <key> resolves to any truth value (e.g. "yes", "y", "true")
* return FALSE if <key> resolves to any non-truth value (e.g. "no", "n", "false")
@ -85,15 +94,6 @@ gboolean svSetValueInt64_cond (shvarFile *s, const char *key, gboolean do_set, g
gboolean svSetValueEnum (shvarFile *s, const char *key, GType gtype, int value);
gboolean svUnsetValue (shvarFile *s, const char *key);
typedef enum {
SV_KEY_TYPE_ANY = (1LL << 0),
SV_KEY_TYPE_ROUTE_SVFORMAT = (1LL << 1),
SV_KEY_TYPE_IP4_ADDRESS = (1LL << 2),
SV_KEY_TYPE_TC = (1LL << 3),
SV_KEY_TYPE_USER = (1LL << 4),
} SvKeyType;
gboolean svUnsetAll (shvarFile *s, SvKeyType match_key_type);
/* Write the current contents iff modified. Returns FALSE on error

View file

@ -0,0 +1,19 @@
TYPE=Ethernet
DEVICE=eth0
HWADDR=00:11:22:33:44:55
BOOTPROTO=none
ONBOOT=yes
DNS1=4.2.2.1
DNS2=4.2.2.2
IPADDR=192.168.1.5
PREFIX=24
NETMASK=255.255.255.0
GATEWAY=192.168.1.1
IPV6INIT=no
NAME=ethernet-sriov
UUID=acc703b8-e751-44ce-b456-1550bdf2057e
SRIOV_TOTAL_VFS=16
SRIOV_AUTOPROBE_DRIVERS=0
SRIOV_VF15="max-tx-rate=200 mac=01:23:45:67:89:ab vlans=2"
SRIOV_VF12="trust=false min-tx-rate=100 vlans=1.200.ad"
SRIOV_VF3="mac=55:44:33:22:11:00 spoof-check=true"

View file

@ -0,0 +1,18 @@
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
SRIOV_TOTAL_VFS=64
SRIOV_AUTOPROBE_DRIVERS=1
SRIOV_VF2="mac=55:55:55:55:55:55 vlans=3.10.ad;10"
SRIOV_VF19=spoof-check=true
BOOTPROTO=none
IPADDR=1.1.1.3
PREFIX=24
GATEWAY=1.1.1.1
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=no
NAME="Test Write SR-IOV config"
UUID=${UUID}
DEVICE=eth0
ONBOOT=yes

View file

@ -9632,6 +9632,153 @@ test_utils_ignore (void)
do_test_utils_ignored ("ignored-augtmp", "ifcfg-FooBar" AUGTMP_TAG, TRUE);
}
/*****************************************************************************/
static void
test_sriov_read (void)
{
gs_unref_object NMConnection *connection = NULL;
NMSettingSriov *s_sriov;
NMSriovVF *vf;
GVariant *variant;
GError *error = NULL;
char *str;
connection = _connection_from_file (TEST_IFCFG_DIR "/ifcfg-test-sriov",
NULL, TYPE_ETHERNET,NULL);
g_assert_cmpstr (nm_connection_get_interface_name (connection), ==, "eth0");
s_sriov = nm_connection_get_setting_sriov (connection);
g_assert (s_sriov);
g_assert_cmpint (nm_setting_sriov_get_total_vfs (s_sriov), ==, 16);
g_assert_cmpint (nm_setting_sriov_get_num_vfs (s_sriov), ==, 3);
g_assert_cmpint (nm_setting_sriov_get_autoprobe_drivers (s_sriov), ==, NM_TERNARY_FALSE);
/* VF 3 */
vf = nm_setting_sriov_get_vf (s_sriov, 0);
g_assert (vf);
g_assert_cmpint (nm_sriov_vf_get_index (vf), ==, 3);
variant = nm_sriov_vf_get_attribute (vf, NM_SRIOV_VF_ATTRIBUTE_MAC);
g_assert (variant);
g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING));
g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "55:44:33:22:11:00");
variant = nm_sriov_vf_get_attribute (vf, NM_SRIOV_VF_ATTRIBUTE_SPOOF_CHECK);
g_assert (variant);
g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_BOOLEAN));
g_assert_cmpint (g_variant_get_boolean (variant), ==, TRUE);
/* VF 12 */
vf = nm_setting_sriov_get_vf (s_sriov, 1);
str = nm_utils_sriov_vf_to_str (vf, FALSE, &error);
g_assert_no_error (error);
g_assert_cmpstr (str, ==, "12 min-tx-rate=100 trust=false vlans=1.200.ad");
g_free (str);
/* VF 15 */
vf = nm_setting_sriov_get_vf (s_sriov, 2);
str = nm_utils_sriov_vf_to_str (vf, FALSE, &error);
g_assert_no_error (error);
g_assert_cmpstr (str, ==, "15 mac=01:23:45:67:89:ab max-tx-rate=200 vlans=2");
g_free (str);
}
static void
test_sriov_write (void)
{
nmtst_auto_unlinkfile char *testfile = NULL;
gs_unref_object NMConnection *connection = NULL;
gs_unref_object NMConnection *reread = NULL;
NMSettingConnection *s_con;
NMSettingIPConfig *s_ip4;
NMSettingIPConfig *s_ip6;
NMSettingWired *s_wired;
NMSettingSriov *s_sriov;
NMSriovVF *vf;
gs_unref_ptrarray GPtrArray *vfs = NULL;
NMIPAddress *addr;
GError *error = NULL;
connection = nm_simple_connection_new ();
/* Connection setting */
s_con = (NMSettingConnection *) nm_setting_connection_new ();
nm_connection_add_setting (connection, NM_SETTING (s_con));
g_object_set (s_con,
NM_SETTING_CONNECTION_ID, "Test Write SR-IOV config",
NM_SETTING_CONNECTION_UUID, nm_utils_uuid_generate_a (),
NM_SETTING_CONNECTION_AUTOCONNECT, TRUE,
NM_SETTING_CONNECTION_INTERFACE_NAME, "eth0",
NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME,
NULL);
/* Wired setting */
s_wired = (NMSettingWired *) nm_setting_wired_new ();
nm_connection_add_setting (connection, NM_SETTING (s_wired));
/* IP4 setting */
s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new ();
nm_connection_add_setting (connection, NM_SETTING (s_ip4));
g_object_set (s_ip4,
NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
NM_SETTING_IP_CONFIG_GATEWAY, "1.1.1.1",
NM_SETTING_IP_CONFIG_MAY_FAIL, TRUE,
NULL);
addr = nm_ip_address_new (AF_INET, "1.1.1.3", 24, &error);
g_assert_no_error (error);
nm_setting_ip_config_add_address (s_ip4, addr);
nm_ip_address_unref (addr);
/* IP6 setting */
s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new ();
nm_connection_add_setting (connection, NM_SETTING (s_ip6));
g_object_set (s_ip6,
NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
NULL);
/* SRIOV setting */
s_sriov = (NMSettingSriov *) nm_setting_sriov_new ();
nm_connection_add_setting (connection, NM_SETTING (s_sriov));
vfs = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_sriov_vf_unref);
vf = nm_utils_sriov_vf_from_str ("2 mac=55:55:55:55:55:55 vlans=3.10.ad;10", &error);
nmtst_assert_success (vf, error);
g_ptr_array_add (vfs, vf);
vf = nm_utils_sriov_vf_from_str ("19 spoof-check=true", &error);
nmtst_assert_success (vf, error);
g_ptr_array_add (vfs, vf);
g_object_set (s_sriov,
NM_SETTING_SRIOV_TOTAL_VFS, 64,
NM_SETTING_SRIOV_VFS, vfs,
NM_SETTING_SRIOV_AUTOPROBE_DRIVERS, NM_TERNARY_TRUE,
NULL);
nm_connection_add_setting (connection, nm_setting_proxy_new ());
nmtst_assert_connection_verifies_without_normalization (connection);
_writer_new_connec_exp (connection,
TEST_SCRATCH_DIR,
TEST_IFCFG_DIR "/ifcfg-test-sriov-write.cexpected",
&testfile);
reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL);
nmtst_assert_connection_equals (connection, TRUE, reread, FALSE);
}
/*****************************************************************************/
static void
test_tc_read (void)
{
@ -10033,6 +10180,9 @@ int main (int argc, char **argv)
g_test_add_func (TPATH "utils/path", test_utils_path);
g_test_add_func (TPATH "utils/ignore", test_utils_ignore);
g_test_add_func (TPATH "sriov/read", test_sriov_read);
g_test_add_func (TPATH "sriov/write", test_sriov_write);
g_test_add_func (TPATH "tc/read", test_tc_read);
g_test_add_func (TPATH "tc/write", test_tc_write);