diff --git a/.gitignore b/.gitignore index dd5021475d..63b992550c 100644 --- a/.gitignore +++ b/.gitignore @@ -176,7 +176,9 @@ valgrind-*.log /libnm-util/tests/test-need-secrets /libnm-util/tests/test-secrets /libnm-util/tests/test-setting-8021x +/libnm-util/tests/test-setting-dcb /libnm-glib/tests/test-remote-settings-client +/src/tests/test-dcb /src/tests/test-dhcp-options /src/tests/test-ip4-config /src/tests/test-ip6-config diff --git a/docs/libnm-util/libnm-util-docs.sgml b/docs/libnm-util/libnm-util-docs.sgml index eaef262333..2c43164859 100644 --- a/docs/libnm-util/libnm-util-docs.sgml +++ b/docs/libnm-util/libnm-util-docs.sgml @@ -62,6 +62,7 @@ + diff --git a/include/NetworkManager.h b/include/NetworkManager.h index a635706656..192f9a5178 100644 --- a/include/NetworkManager.h +++ b/include/NetworkManager.h @@ -545,6 +545,9 @@ typedef enum { /* A secondary connection of the base connection failed */ NM_DEVICE_STATE_REASON_SECONDARY_CONNECTION_FAILED = 54, + /* DCB or FCoE setup failed */ + NM_DEVICE_STATE_REASON_DCB_FCOE_FAILED = 55, + /* Unused */ NM_DEVICE_STATE_REASON_LAST = 0xFFFF } NMDeviceStateReason; diff --git a/introspection/nm-device.xml b/introspection/nm-device.xml index fb84fe376e..7c63a3d738 100644 --- a/introspection/nm-device.xml +++ b/introspection/nm-device.xml @@ -579,6 +579,11 @@ A secondary connection of the base connection failed. + + + DCB or FCoE setup failed. + + diff --git a/libnm-util/Makefile.am b/libnm-util/Makefile.am index 6f267c13e5..f5b7773f6e 100644 --- a/libnm-util/Makefile.am +++ b/libnm-util/Makefile.am @@ -32,6 +32,7 @@ libnm_util_include_HEADERS = \ nm-setting-bridge.h \ nm-setting-bridge-port.h \ nm-setting-connection.h \ + nm-setting-dcb.h \ nm-setting-infiniband.h \ nm-setting-ip4-config.h \ nm-setting-vlan.h \ @@ -71,6 +72,7 @@ libnm_util_la_csources = \ nm-setting-bridge.c \ nm-setting-bridge-port.c \ nm-setting-connection.c \ + nm-setting-dcb.c \ nm-setting-infiniband.c \ nm-setting-ip4-config.c \ nm-setting-vlan.c \ diff --git a/libnm-util/libnm-util.ver b/libnm-util/libnm-util.ver index dd8fcfa3c9..f613c32213 100644 --- a/libnm-util/libnm-util.ver +++ b/libnm-util/libnm-util.ver @@ -23,6 +23,7 @@ global: nm_connection_get_setting_by_name; nm_connection_get_setting_cdma; nm_connection_get_setting_connection; + nm_connection_get_setting_dcb; nm_connection_get_setting_generic; nm_connection_get_setting_gsm; nm_connection_get_setting_infiniband; @@ -263,6 +264,32 @@ global: nm_setting_connection_permissions_user_allowed; nm_setting_connection_remove_permission; nm_setting_connection_remove_secondary; + nm_setting_dcb_error_get_type; + nm_setting_dcb_error_quark; + nm_setting_dcb_flags_get_type; + nm_setting_dcb_get_app_fcoe_flags; + nm_setting_dcb_get_app_fcoe_mode; + nm_setting_dcb_get_app_fcoe_priority; + nm_setting_dcb_get_app_fip_flags; + nm_setting_dcb_get_app_fip_priority; + nm_setting_dcb_get_app_iscsi_flags; + nm_setting_dcb_get_app_iscsi_priority; + nm_setting_dcb_get_priority_bandwidth; + nm_setting_dcb_get_priority_flow_control; + nm_setting_dcb_get_priority_flow_control_flags; + nm_setting_dcb_get_priority_group_bandwidth; + nm_setting_dcb_get_priority_group_flags; + nm_setting_dcb_get_priority_group_id; + nm_setting_dcb_get_priority_strict_bandwidth; + nm_setting_dcb_get_priority_traffic_class; + nm_setting_dcb_get_type; + nm_setting_dcb_new; + nm_setting_dcb_set_priority_bandwidth; + nm_setting_dcb_set_priority_flow_control; + nm_setting_dcb_set_priority_group_bandwidth; + nm_setting_dcb_set_priority_group_id; + nm_setting_dcb_set_priority_strict_bandwidth; + nm_setting_dcb_set_priority_traffic_class; nm_setting_diff; nm_setting_diff_result_get_type; nm_setting_duplicate; diff --git a/libnm-util/nm-connection.c b/libnm-util/nm-connection.c index 01223daf62..7c67e84461 100644 --- a/libnm-util/nm-connection.c +++ b/libnm-util/nm-connection.c @@ -1326,6 +1326,22 @@ nm_connection_get_setting_connection (NMConnection *connection) return (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); } +/** + * nm_connection_get_setting_dcb: + * @connection: the #NMConnection + * + * A shortcut to return any #NMSettingDcb the connection might contain. + * + * Returns: (transfer none): an #NMSettingDcb if the connection contains one, otherwise NULL + **/ +NMSettingDcb * +nm_connection_get_setting_dcb (NMConnection *connection) +{ + g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + + return (NMSettingDcb *) nm_connection_get_setting (connection, NM_TYPE_SETTING_DCB); +} + /** * nm_connection_get_setting_generic: * @connection: the #NMConnection diff --git a/libnm-util/nm-connection.h b/libnm-util/nm-connection.h index f310319969..cda8391e8b 100644 --- a/libnm-util/nm-connection.h +++ b/libnm-util/nm-connection.h @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -208,6 +209,7 @@ NMSettingBridge * nm_connection_get_setting_bridge (NMConnec NMSettingBridgePort * nm_connection_get_setting_bridge_port (NMConnection *connection); NMSettingCdma * nm_connection_get_setting_cdma (NMConnection *connection); NMSettingConnection * nm_connection_get_setting_connection (NMConnection *connection); +NMSettingDcb * nm_connection_get_setting_dcb (NMConnection *connection); NMSettingGeneric * nm_connection_get_setting_generic (NMConnection *connection); NMSettingGsm * nm_connection_get_setting_gsm (NMConnection *connection); NMSettingInfiniband * nm_connection_get_setting_infiniband (NMConnection *connection); diff --git a/libnm-util/nm-setting-dcb.c b/libnm-util/nm-setting-dcb.c new file mode 100644 index 0000000000..cf2d47d120 --- /dev/null +++ b/libnm-util/nm-setting-dcb.c @@ -0,0 +1,1258 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ + +/* + * Dan Williams + * + * 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. + * + * (C) Copyright 2013 Red Hat, Inc. + */ + +#include +#include +#include + +#include "nm-setting-dcb.h" +#include "nm-param-spec-specialized.h" +#include "nm-utils.h" +#include "nm-utils-private.h" +#include "nm-dbus-glib-types.h" +#include "nm-setting-private.h" + +/** + * SECTION:nm-setting-dcb + * @short_description: Connection properties for Data Center Bridging + * @include: nm-setting-dcb.h + * + * The #NMSettingDcb object is a #NMSetting subclass that describes properties + * for enabling and using Data Center Bridging (DCB) on Ethernet networks. + * DCB is a set of protocols (including 802.1Qbb, 802.1Qaz, 802.1Qau, and + * 802.1AB) to eliminate packet loss in Ethernet networks and support the use + * of storage technologies like Fibre Channel over Ethernet (FCoE) and iSCSI. + * + * Since: 0.9.10 + **/ + +/** + * nm_setting_dcb_error_quark: + * + * Registers an error quark for #NMSettingDcb if necessary. + * + * Returns: the error quark used for #NMSettingDcb errors. + * + * Since: 0.9.10 + **/ +GQuark +nm_setting_dcb_error_quark (void) +{ + static GQuark quark; + + if (G_UNLIKELY (!quark)) + quark = g_quark_from_static_string ("nm-setting-dcb-error-quark"); + return quark; +} + + +G_DEFINE_TYPE_WITH_CODE (NMSettingDcb, nm_setting_dcb, NM_TYPE_SETTING, + _nm_register_setting (NM_SETTING_DCB_SETTING_NAME, + g_define_type_id, + 2, + NM_SETTING_DCB_ERROR)) +NM_SETTING_REGISTER_TYPE (NM_TYPE_SETTING_DCB) + +#define NM_SETTING_DCB_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_DCB, NMSettingDcbPrivate)) + +typedef struct { + NMSettingDcbFlags app_fcoe_flags; + gint app_fcoe_priority; + const char * app_fcoe_mode; + + NMSettingDcbFlags app_iscsi_flags; + gint app_iscsi_priority; + + NMSettingDcbFlags app_fip_flags; + gint app_fip_priority; + + /* Priority Flow Control */ + NMSettingDcbFlags pfc_flags; + guint pfc[8]; + + /* Priority Groups */ + NMSettingDcbFlags priority_group_flags; + guint priority_group_id[8]; + guint priority_group_bandwidth[8]; + guint priority_bandwidth[8]; + guint priority_strict[8]; + guint priority_traffic_class[8]; +} NMSettingDcbPrivate; + +enum { + PROP_0, + PROP_APP_FCOE_FLAGS, + PROP_APP_FCOE_PRIORITY, + PROP_APP_FCOE_MODE, + + PROP_APP_ISCSI_FLAGS, + PROP_APP_ISCSI_PRIORITY, + + PROP_APP_FIP_FLAGS, + PROP_APP_FIP_PRIORITY, + + PROP_PFC_FLAGS, + PROP_PFC, + + PROP_PRIORITY_GROUP_FLAGS, + PROP_PRIORITY_GROUP_ID, + PROP_PRIORITY_GROUP_BANDWIDTH, + PROP_PRIORITY_BANDWIDTH, + PROP_PRIORITY_STRICT, + PROP_PRIORITY_TRAFFIC_CLASS, + + LAST_PROP +}; + +/** + * nm_setting_dcb_new: + * + * Creates a new #NMSettingDcb object with default values. + * + * Returns: (transfer full): the new empty #NMSettingDcb object + * + * Since: 0.9.10 + **/ +NMSetting * +nm_setting_dcb_new (void) +{ + return (NMSetting *) g_object_new (NM_TYPE_SETTING_DCB, NULL); +} + +/** + * nm_setting_dcb_get_app_fcoe_flags: + * @setting: the #NMSettingDcb + * + * Returns: the #NMSettingDcb:app-fcoe-flags property of the setting + * + * Since: 0.9.10 + **/ +NMSettingDcbFlags +nm_setting_dcb_get_app_fcoe_flags (NMSettingDcb *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_DCB (setting), 0); + + return NM_SETTING_DCB_GET_PRIVATE (setting)->app_fcoe_flags; +} + +/** + * nm_setting_dcb_get_app_fcoe_priority: + * @setting: the #NMSettingDcb + * + * Returns: the #NMSettingDcb:app-fcoe-priority property of the setting + * + * Since: 0.9.10 + **/ +gint +nm_setting_dcb_get_app_fcoe_priority (NMSettingDcb *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_DCB (setting), 0); + + return NM_SETTING_DCB_GET_PRIVATE (setting)->app_fcoe_priority; +} + +/** + * nm_setting_dcb_get_app_fcoe_mode: + * @setting: the #NMSettingDcb + * + * Returns: the #NMSettingDcb:app-fcoe-mode property of the setting + * + * Since: 0.9.10 + **/ +const char * +nm_setting_dcb_get_app_fcoe_mode (NMSettingDcb *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_DCB (setting), NULL); + + return NM_SETTING_DCB_GET_PRIVATE (setting)->app_fcoe_mode; +} + +/** + * nm_setting_dcb_get_app_iscsi_flags: + * @setting: the #NMSettingDcb + * + * Returns: the #NMSettingDcb:app-iscsi-flags property of the setting + * + * Since: 0.9.10 + **/ +NMSettingDcbFlags +nm_setting_dcb_get_app_iscsi_flags (NMSettingDcb *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_DCB (setting), 0); + + return NM_SETTING_DCB_GET_PRIVATE (setting)->app_iscsi_flags; +} + +/** + * nm_setting_dcb_get_app_iscsi_priority: + * @setting: the #NMSettingDcb + * + * Returns: the #NMSettingDcb:app-iscsi-priority property of the setting + * + * Since: 0.9.10 + **/ +gint +nm_setting_dcb_get_app_iscsi_priority (NMSettingDcb *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_DCB (setting), 0); + + return NM_SETTING_DCB_GET_PRIVATE (setting)->app_iscsi_priority; +} + +/** + * nm_setting_dcb_get_app_fip_flags: + * @setting: the #NMSettingDcb + * + * Returns: the #NMSettingDcb:app-fip-flags property of the setting + * + * Since: 0.9.10 + **/ +NMSettingDcbFlags +nm_setting_dcb_get_app_fip_flags (NMSettingDcb *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_DCB (setting), 0); + + return NM_SETTING_DCB_GET_PRIVATE (setting)->app_fip_flags; +} + +/** + * nm_setting_dcb_get_app_fip_priority: + * @setting: the #NMSettingDcb + * + * Returns: the #NMSettingDcb:app-fip-priority property of the setting + * + * Since: 0.9.10 + **/ +gint +nm_setting_dcb_get_app_fip_priority (NMSettingDcb *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_DCB (setting), 0); + + return NM_SETTING_DCB_GET_PRIVATE (setting)->app_fip_priority; +} + +/** + * nm_setting_dcb_get_priority_flow_control_flags: + * @setting: the #NMSettingDcb + * + * Returns: the #NMSettingDcb:priority-flow-control-flags property of the setting + * + * Since: 0.9.10 + **/ +NMSettingDcbFlags +nm_setting_dcb_get_priority_flow_control_flags (NMSettingDcb *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_DCB (setting), 0); + + return NM_SETTING_DCB_GET_PRIVATE (setting)->pfc_flags; +} + +/** + * nm_setting_dcb_get_priority_flow_control: + * @setting: the #NMSettingDcb + * @user_priority: the User Priority (0 - 7) to retrieve flow control for + * + * Returns: %TRUE if flow control is enabled for the given @user_priority, + * %FALSE if not enabled + * + * Since: 0.9.10 + **/ +gboolean +nm_setting_dcb_get_priority_flow_control (NMSettingDcb *setting, guint user_priority) +{ + g_return_val_if_fail (NM_IS_SETTING_DCB (setting), FALSE); + g_return_val_if_fail (user_priority <= 7, FALSE); + + return !!NM_SETTING_DCB_GET_PRIVATE (setting)->pfc[user_priority]; +} + +/** + * nm_setting_dcb_set_priority_flow_control: + * @setting: the #NMSettingDcb + * @user_priority: the User Priority (0 - 7) to set flow control for + * @enabled: %TRUE to enable flow control for this priority, %FALSE to disable it + * + * These values are only valid when #NMSettingDcb:priority-flow-control includes + * the %NM_SETTING_DCB_FLAG_ENABLE flag. + * + * Since: 0.9.10 + **/ +void +nm_setting_dcb_set_priority_flow_control (NMSettingDcb *setting, + guint user_priority, + gboolean enabled) +{ + NMSettingDcbPrivate *priv; + guint uint_enabled = enabled ? 1 : 0; + + g_return_if_fail (NM_IS_SETTING_DCB (setting)); + g_return_if_fail (user_priority <= 7); + + priv = NM_SETTING_DCB_GET_PRIVATE (setting); + if (priv->pfc[user_priority] != uint_enabled) { + priv->pfc[user_priority] = uint_enabled; + g_object_notify (G_OBJECT (setting), NM_SETTING_DCB_PRIORITY_FLOW_CONTROL); + } +} + +/** + * nm_setting_dcb_get_priority_group_flags: + * @setting: the #NMSettingDcb + * + * Returns: the #NMSettingDcb:priority-group-flags property of the setting + * + * Since: 0.9.10 + **/ +NMSettingDcbFlags +nm_setting_dcb_get_priority_group_flags (NMSettingDcb *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_DCB (setting), 0); + + return NM_SETTING_DCB_GET_PRIVATE (setting)->priority_group_flags; +} + +/** + * nm_setting_dcb_get_priority_group_id: + * @setting: the #NMSettingDcb + * @user_priority: the User Priority (0 - 7) to retrieve the group ID for + * + * Returns: the group number @user_priority is assigned to. These values are + * only valid when #NMSettingDcb:priority-group-flags includes the + * %NM_SETTING_DCB_FLAG_ENABLE flag. + * + * Since: 0.9.10 + **/ +guint +nm_setting_dcb_get_priority_group_id (NMSettingDcb *setting, guint user_priority) +{ + g_return_val_if_fail (NM_IS_SETTING_DCB (setting), 0); + g_return_val_if_fail (user_priority <= 7, 0); + + return NM_SETTING_DCB_GET_PRIVATE (setting)->priority_group_id[user_priority]; +} + +/** + * nm_setting_dcb_set_priority_group_id: + * @setting: the #NMSettingDcb + * @user_priority: the User Priority (0 - 7) to set flow control for + * @group_id: the group (0 - 7) to assign @user_priority to, or 15 for the + * unrestricted group. + * + * These values are only valid when #NMSettingDcb:priority-group-flags includes + * the %NM_SETTING_DCB_FLAG_ENABLE flag. + * + * Since: 0.9.10 + **/ +void +nm_setting_dcb_set_priority_group_id (NMSettingDcb *setting, + guint user_priority, + guint group_id) +{ + NMSettingDcbPrivate *priv; + + g_return_if_fail (NM_IS_SETTING_DCB (setting)); + g_return_if_fail (user_priority <= 7); + g_return_if_fail (group_id <= 7 || group_id == 15); + + priv = NM_SETTING_DCB_GET_PRIVATE (setting); + if (priv->priority_group_id[user_priority] != group_id) { + priv->priority_group_id[user_priority] = group_id; + g_object_notify (G_OBJECT (setting), NM_SETTING_DCB_PRIORITY_GROUP_ID); + } +} + +/** + * nm_setting_dcb_get_priority_group_bandwidth: + * @setting: the #NMSettingDcb + * @group_id: the priority group (0 - 7) to retrieve the bandwidth percentage for + * + * Returns: the bandwidth percentage assigned to @group_id. These values are + * only valid when #NMSettingDcb:priority-group-flags includes the + * %NM_SETTING_DCB_FLAG_ENABLE flag. + * + * Since: 0.9.10 + **/ +guint +nm_setting_dcb_get_priority_group_bandwidth (NMSettingDcb *setting, guint group_id) +{ + g_return_val_if_fail (NM_IS_SETTING_DCB (setting), 0); + g_return_val_if_fail (group_id <= 7, FALSE); + + return NM_SETTING_DCB_GET_PRIVATE (setting)->priority_group_bandwidth[group_id]; +} + +/** + * nm_setting_dcb_set_priority_group_bandwidth: + * @setting: the #NMSettingDcb + * @group_id: the priority group (0 - 7) to set the bandwidth percentage for + * @bandwidth_percent: the bandwidth percentage (0 - 100) to assign to @group_id to + * + * These values are only valid when #NMSettingDcb:priority-group-flags includes + * the %NM_SETTING_DCB_FLAG_ENABLE flag. + * + * Since: 0.9.10 + **/ +void +nm_setting_dcb_set_priority_group_bandwidth (NMSettingDcb *setting, + guint group_id, + guint bandwidth_percent) +{ + NMSettingDcbPrivate *priv; + + g_return_if_fail (NM_IS_SETTING_DCB (setting)); + g_return_if_fail (group_id <= 7); + g_return_if_fail (bandwidth_percent <= 100); + + priv = NM_SETTING_DCB_GET_PRIVATE (setting); + if (priv->priority_group_bandwidth[group_id] != bandwidth_percent) { + priv->priority_group_bandwidth[group_id] = bandwidth_percent; + g_object_notify (G_OBJECT (setting), NM_SETTING_DCB_PRIORITY_GROUP_BANDWIDTH); + } +} + +/** + * nm_setting_dcb_get_priority_bandwidth: + * @setting: the #NMSettingDcb + * @user_priority: the User Priority (0 - 7) to retrieve the group bandwidth percentage for + * + * Returns: the allowed bandwidth percentage of @user_priority in its priority group. + * These values are only valid when #NMSettingDcb:priority-group-flags includes the + * %NM_SETTING_DCB_FLAG_ENABLE flag. + * + * Since: 0.9.10 + **/ +guint +nm_setting_dcb_get_priority_bandwidth (NMSettingDcb *setting, guint user_priority) +{ + g_return_val_if_fail (NM_IS_SETTING_DCB (setting), 0); + g_return_val_if_fail (user_priority <= 7, FALSE); + + return NM_SETTING_DCB_GET_PRIVATE (setting)->priority_bandwidth[user_priority]; +} + +/** + * nm_setting_dcb_set_priority_bandwidth: + * @setting: the #NMSettingDcb + * @user_priority: the User Priority (0 - 7) to set the bandwidth percentage for + * @bandwidth_percent: the bandwidth percentage (0 - 100) that @user_priority is + * allowed to use within its priority group + * + * These values are only valid when #NMSettingDcb:priority-group-flags includes + * the %NM_SETTING_DCB_FLAG_ENABLE flag. + * + * Since: 0.9.10 + **/ +void +nm_setting_dcb_set_priority_bandwidth (NMSettingDcb *setting, + guint user_priority, + guint bandwidth_percent) +{ + NMSettingDcbPrivate *priv; + + g_return_if_fail (NM_IS_SETTING_DCB (setting)); + g_return_if_fail (user_priority <= 7); + g_return_if_fail (bandwidth_percent <= 100); + + priv = NM_SETTING_DCB_GET_PRIVATE (setting); + if (priv->priority_bandwidth[user_priority] != bandwidth_percent) { + priv->priority_bandwidth[user_priority] = bandwidth_percent; + g_object_notify (G_OBJECT (setting), NM_SETTING_DCB_PRIORITY_BANDWIDTH); + } +} + +/** + * nm_setting_dcb_get_priority_strict_bandwidth: + * @setting: the #NMSettingDcb + * @user_priority: the User Priority (0 - 7) to retrieve strict bandwidth for + * + * Returns: %TRUE if @user_priority may use all of the bandwidth allocated to its + * assigned group, or %FALSE if not. These values are only valid when + * #NMSettingDcb:priority-group-flags includes the %NM_SETTING_DCB_FLAG_ENABLE flag. + * + * Since: 0.9.10 + **/ +gboolean +nm_setting_dcb_get_priority_strict_bandwidth (NMSettingDcb *setting, guint user_priority) +{ + g_return_val_if_fail (NM_IS_SETTING_DCB (setting), 0); + g_return_val_if_fail (user_priority <= 7, FALSE); + + return !!NM_SETTING_DCB_GET_PRIVATE (setting)->priority_strict[user_priority]; +} + +/** + * nm_setting_dcb_set_priority_strict_bandwidth: + * @setting: the #NMSettingDcb + * @user_priority: the User Priority (0 - 7) to set strict bandwidth for + * @strict: %TRUE to allow @user_priority to use all the bandwidth allocated to + * its priority group, or %FALSE if not + * + * These values are only valid when #NMSettingDcb:priority-group-flags includes + * the %NM_SETTING_DCB_FLAG_ENABLE flag. + * + * Since: 0.9.10 + **/ +void +nm_setting_dcb_set_priority_strict_bandwidth (NMSettingDcb *setting, + guint user_priority, + gboolean strict) +{ + NMSettingDcbPrivate *priv; + guint uint_strict = strict ? 1 : 0; + + g_return_if_fail (NM_IS_SETTING_DCB (setting)); + g_return_if_fail (user_priority <= 7); + + priv = NM_SETTING_DCB_GET_PRIVATE (setting); + if (priv->priority_strict[user_priority] != uint_strict) { + priv->priority_strict[user_priority] = uint_strict; + g_object_notify (G_OBJECT (setting), NM_SETTING_DCB_PRIORITY_STRICT_BANDWIDTH); + } +} + +/** + * nm_setting_dcb_get_priority_traffic_class: + * @setting: the #NMSettingDcb + * @user_priority: the User Priority (0 - 7) to retrieve the traffic class for + * + * Returns: the traffic class assigned to @user_priority. These values are only + * valid when #NMSettingDcb:priority-group-flags includes the + * %NM_SETTING_DCB_FLAG_ENABLE flag. + * + * Since: 0.9.10 + **/ +guint +nm_setting_dcb_get_priority_traffic_class (NMSettingDcb *setting, guint user_priority) +{ + g_return_val_if_fail (NM_IS_SETTING_DCB (setting), 0); + g_return_val_if_fail (user_priority <= 7, FALSE); + + return NM_SETTING_DCB_GET_PRIVATE (setting)->priority_traffic_class[user_priority]; +} + +/** + * nm_setting_dcb_set_priority_traffic_clas: + * @setting: the #NMSettingDcb + * @user_priority: the User Priority (0 - 7) to set the bandwidth percentage for + * @traffic_class: the traffic_class (0 - 7) that @user_priority should map to + * + * These values are only valid when #NMSettingDcb:priority-group-flags includes + * the %NM_SETTING_DCB_FLAG_ENABLE flag. + * + * Since: 0.9.10 + **/ +void +nm_setting_dcb_set_priority_traffic_class (NMSettingDcb *setting, + guint user_priority, + guint traffic_class) +{ + NMSettingDcbPrivate *priv; + + g_return_if_fail (NM_IS_SETTING_DCB (setting)); + g_return_if_fail (user_priority <= 7); + g_return_if_fail (traffic_class <= 7); + + priv = NM_SETTING_DCB_GET_PRIVATE (setting); + if (priv->priority_traffic_class[user_priority] != traffic_class) { + priv->priority_traffic_class[user_priority] = traffic_class; + g_object_notify (G_OBJECT (setting), NM_SETTING_DCB_PRIORITY_TRAFFIC_CLASS); + } +} + +/******************************************************************/ + +#define DCB_FLAGS_ALL (NM_SETTING_DCB_FLAG_ENABLE | \ + NM_SETTING_DCB_FLAG_ADVERTISE | \ + NM_SETTING_DCB_FLAG_WILLING) + +static gboolean +check_dcb_flags (NMSettingDcbFlags flags, const char *prop_name, GError **error) +{ + if (flags & ~DCB_FLAGS_ALL) { + g_set_error_literal (error, + NM_SETTING_DCB_ERROR, + NM_SETTING_DCB_ERROR_INVALID_PROPERTY, + _("flags invalid")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_DCB_SETTING_NAME, prop_name); + return FALSE; + } + + if (!(flags & NM_SETTING_DCB_FLAG_ENABLE) && (flags & ~NM_SETTING_DCB_FLAG_ENABLE)) { + g_set_error_literal (error, + NM_SETTING_DCB_ERROR, + NM_SETTING_DCB_ERROR_INVALID_PROPERTY, + _("flags invalid - disabled")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_DCB_SETTING_NAME, prop_name); + return FALSE; + } + + return TRUE; +} + +static gboolean +check_uint_array (const guint *array, + guint len, + NMSettingDcbFlags flags, + guint max, + guint extra, + gboolean sum_pct, + const char *prop_name, + GError **error) +{ + guint i, sum = 0; + + /* Ensure each element is <= to max or equals extra */ + for (i = 0; i < len; i++) { + if (!(flags & NM_SETTING_DCB_FLAG_ENABLE) && array[i]) { + g_set_error_literal (error, + NM_SETTING_DCB_ERROR, + NM_SETTING_DCB_ERROR_INVALID_PROPERTY, + _("property invalid (not enabled)")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_DCB_SETTING_NAME, prop_name); + return FALSE; + } + + if ((array[i] > max) && (array[i] != extra)) { + g_set_error_literal (error, + NM_SETTING_DCB_ERROR, + NM_SETTING_DCB_ERROR_INVALID_PROPERTY, + _("element invalid")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_DCB_SETTING_NAME, prop_name); + return FALSE; + } + sum += array[i]; + } + + /* Verify sum of percentages */ + if (sum_pct) { + if (flags & NM_SETTING_DCB_FLAG_ENABLE) { + /* If the feature is enabled, sum must equal 100% */ + if (sum != 100) { + g_set_error_literal (error, + NM_SETTING_DCB_ERROR, + NM_SETTING_DCB_ERROR_INVALID_PROPERTY, + _("sum not 100%")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_DCB_SETTING_NAME, prop_name); + return FALSE; + } + } else { + /* If the feature is disabled, sum must equal 0%, which was checked + * by the for() loop above. + */ + g_assert_cmpint (sum, ==, 0); + } + } + + return TRUE; +} + +static gboolean +check_priority (gint val, + NMSettingDcbFlags flags, + const char *prop_name, + GError **error) +{ + if (!(flags & NM_SETTING_DCB_FLAG_ENABLE) && (val >= 0)) { + g_set_error_literal (error, + NM_SETTING_DCB_ERROR, + NM_SETTING_DCB_ERROR_INVALID_PROPERTY, + _("property invalid (not enabled)")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_DCB_SETTING_NAME, prop_name); + return FALSE; + } + + if (val < -1 || val > 7) { + g_set_error_literal (error, + NM_SETTING_DCB_ERROR, + NM_SETTING_DCB_ERROR_INVALID_PROPERTY, + _("property invalid")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_DCB_SETTING_NAME, prop_name); + return FALSE; + } + return TRUE; +} + +static gboolean +verify (NMSetting *setting, GSList *all_settings, GError **error) +{ + NMSettingDcbPrivate *priv = NM_SETTING_DCB_GET_PRIVATE (setting); + + if (!check_dcb_flags (priv->app_fcoe_flags, NM_SETTING_DCB_APP_FCOE_FLAGS, error)) + return FALSE; + + if (!check_priority (priv->app_fcoe_priority, priv->app_fcoe_flags, NM_SETTING_DCB_APP_FCOE_PRIORITY, error)) + return FALSE; + + if (!priv->app_fcoe_mode) { + g_set_error_literal (error, + NM_SETTING_DCB_ERROR, + NM_SETTING_DCB_ERROR_MISSING_PROPERTY, + _("property missing")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_DCB_SETTING_NAME, NM_SETTING_DCB_APP_FCOE_MODE); + return FALSE; + } + + if (strcmp (priv->app_fcoe_mode, NM_SETTING_DCB_FCOE_MODE_FABRIC) && + strcmp (priv->app_fcoe_mode, NM_SETTING_DCB_FCOE_MODE_VN2VN)) { + g_set_error_literal (error, + NM_SETTING_DCB_ERROR, + NM_SETTING_DCB_ERROR_INVALID_PROPERTY, + _("property invalid")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_DCB_SETTING_NAME, NM_SETTING_DCB_APP_FCOE_MODE); + return FALSE; + } + + if (!check_dcb_flags (priv->app_iscsi_flags, NM_SETTING_DCB_APP_ISCSI_FLAGS, error)) + return FALSE; + + if (!check_priority (priv->app_iscsi_priority, priv->app_iscsi_flags, NM_SETTING_DCB_APP_ISCSI_PRIORITY, error)) + return FALSE; + + if (!check_dcb_flags (priv->app_fip_flags, NM_SETTING_DCB_APP_FIP_FLAGS, error)) + return FALSE; + + if (!check_priority (priv->app_fip_priority, priv->app_fip_flags, NM_SETTING_DCB_APP_FIP_PRIORITY, error)) + return FALSE; + + if (!check_dcb_flags (priv->pfc_flags, NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS, error)) + return FALSE; + + if (!check_uint_array (priv->pfc, G_N_ELEMENTS (priv->pfc), priv->pfc_flags, 1, 0, FALSE, NM_SETTING_DCB_PRIORITY_FLOW_CONTROL, error)) + return FALSE; + + if (!check_dcb_flags (priv->priority_group_flags, NM_SETTING_DCB_PRIORITY_GROUP_FLAGS, error)) + return FALSE; + + if (!check_uint_array (priv->priority_group_id, + G_N_ELEMENTS (priv->priority_group_id), + priv->priority_group_flags, + 7, + 15, + FALSE, + NM_SETTING_DCB_PRIORITY_GROUP_ID, + error)) + return FALSE; + + if (!check_uint_array (priv->priority_group_bandwidth, + G_N_ELEMENTS (priv->priority_group_bandwidth), + priv->priority_group_flags, + 100, + 0, + TRUE, + NM_SETTING_DCB_PRIORITY_GROUP_BANDWIDTH, + error)) + return FALSE; + + /* FIXME: sum bandwidths in each group */ + if (!check_uint_array (priv->priority_bandwidth, + G_N_ELEMENTS (priv->priority_bandwidth), + priv->priority_group_flags, + 100, + 0, + FALSE, + NM_SETTING_DCB_PRIORITY_BANDWIDTH, + error)) + return FALSE; + + if (!check_uint_array (priv->priority_strict, + G_N_ELEMENTS (priv->priority_strict), + priv->priority_group_flags, + 1, + 0, + FALSE, + NM_SETTING_DCB_PRIORITY_STRICT_BANDWIDTH, + error)) + return FALSE; + + if (!check_uint_array (priv->priority_traffic_class, + G_N_ELEMENTS (priv->priority_traffic_class), + priv->priority_group_flags, + 7, + 0, + FALSE, + NM_SETTING_DCB_PRIORITY_TRAFFIC_CLASS, + error)) + return FALSE; + + return TRUE; +} + +/******************************************************************/ + +static void +nm_setting_dcb_init (NMSettingDcb *setting) +{ + g_object_set (setting, NM_SETTING_NAME, NM_SETTING_DCB_SETTING_NAME, NULL); +} + +static inline void +set_uint_array (const GValue *v, uint *a, size_t len) +{ + GArray *src = g_value_get_boxed (v); + const guint total_len = len * sizeof (a[0]); + + memset (a, 0, total_len); + if (src) { + g_return_if_fail (g_array_get_element_size (src) == sizeof (a[0])); + g_return_if_fail (src->len == len); + memcpy (a, src->data, total_len); + } +} +#define SET_UINT_ARRAY(v, a) set_uint_array (v, a, G_N_ELEMENTS (a)) + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMSettingDcbPrivate *priv = NM_SETTING_DCB_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_APP_FCOE_FLAGS: + priv->app_fcoe_flags = g_value_get_uint (value); + break; + case PROP_APP_FCOE_PRIORITY: + priv->app_fcoe_priority = g_value_get_int (value); + break; + case PROP_APP_FCOE_MODE: + priv->app_fcoe_mode = g_value_dup_string (value); + break; + case PROP_APP_ISCSI_FLAGS: + priv->app_iscsi_flags = g_value_get_uint (value); + break; + case PROP_APP_ISCSI_PRIORITY: + priv->app_iscsi_priority = g_value_get_int (value); + break; + case PROP_APP_FIP_FLAGS: + priv->app_fip_flags = g_value_get_uint (value); + break; + case PROP_APP_FIP_PRIORITY: + priv->app_fip_priority = g_value_get_int (value); + break; + case PROP_PFC_FLAGS: + priv->pfc_flags = g_value_get_uint (value); + break; + case PROP_PFC: + SET_UINT_ARRAY (value, priv->pfc); + break; + case PROP_PRIORITY_GROUP_FLAGS: + priv->priority_group_flags = g_value_get_uint (value); + break; + case PROP_PRIORITY_GROUP_ID: + SET_UINT_ARRAY (value, priv->priority_group_id); + break; + case PROP_PRIORITY_GROUP_BANDWIDTH: + SET_UINT_ARRAY (value, priv->priority_group_bandwidth); + break; + case PROP_PRIORITY_BANDWIDTH: + SET_UINT_ARRAY (value, priv->priority_bandwidth); + break; + case PROP_PRIORITY_STRICT: + SET_UINT_ARRAY (value, priv->priority_strict); + break; + case PROP_PRIORITY_TRAFFIC_CLASS: + SET_UINT_ARRAY (value, priv->priority_traffic_class); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +#define TAKE_UINT_ARRAY(v, a) \ +{ \ + guint len = G_N_ELEMENTS (a); \ + GArray *dst = g_array_sized_new (FALSE, TRUE, sizeof (guint), len); \ + g_array_append_vals (dst, (a), len); \ + g_value_take_boxed (v, dst); \ +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMSettingDcb *setting = NM_SETTING_DCB (object); + NMSettingDcbPrivate *priv = NM_SETTING_DCB_GET_PRIVATE (setting); + + switch (prop_id) { + case PROP_APP_FCOE_FLAGS: + g_value_set_uint (value, priv->app_fcoe_flags); + break; + case PROP_APP_FCOE_PRIORITY: + g_value_set_int (value, priv->app_fcoe_priority); + break; + case PROP_APP_FCOE_MODE: + g_value_set_string (value, priv->app_fcoe_mode); + break; + case PROP_APP_ISCSI_FLAGS: + g_value_set_uint (value, priv->app_iscsi_flags); + break; + case PROP_APP_ISCSI_PRIORITY: + g_value_set_int (value, priv->app_iscsi_priority); + break; + case PROP_APP_FIP_FLAGS: + g_value_set_uint (value, priv->app_fip_flags); + break; + case PROP_APP_FIP_PRIORITY: + g_value_set_int (value, priv->app_fip_priority); + break; + case PROP_PFC_FLAGS: + g_value_set_uint (value, priv->pfc_flags); + break; + case PROP_PFC: + TAKE_UINT_ARRAY (value, priv->pfc); + break; + case PROP_PRIORITY_GROUP_FLAGS: + g_value_set_uint (value, priv->priority_group_flags); + break; + case PROP_PRIORITY_GROUP_ID: + TAKE_UINT_ARRAY (value, priv->priority_group_id); + break; + case PROP_PRIORITY_GROUP_BANDWIDTH: + TAKE_UINT_ARRAY (value, priv->priority_group_bandwidth); + break; + case PROP_PRIORITY_BANDWIDTH: + TAKE_UINT_ARRAY (value, priv->priority_bandwidth); + break; + case PROP_PRIORITY_STRICT: + TAKE_UINT_ARRAY (value, priv->priority_strict); + break; + case PROP_PRIORITY_TRAFFIC_CLASS: + TAKE_UINT_ARRAY (value, priv->priority_traffic_class); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nm_setting_dcb_class_init (NMSettingDcbClass *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 (NMSettingDcbPrivate)); + + /* virtual methods */ + object_class->set_property = set_property; + object_class->get_property = get_property; + parent_class->verify = verify; + + /* Properties */ + /** + * NMSettingDcb:app-fcoe-flags: + * + * Specifies the %NMSettingDcbFlags for the DCB FCoE application. + * + * Since: 0.9.10 + **/ + g_object_class_install_property + (object_class, PROP_APP_FCOE_FLAGS, + g_param_spec_uint (NM_SETTING_DCB_APP_FCOE_FLAGS, + "App FCoE Flags", + "Specifies the flags for the DCB FCoE application. " + "Flags may be any combination of 0x1 (enable), 0x2 " + "(advertise), and 0x4 (willing).", + 0, DCB_FLAGS_ALL, 0, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + + /** + * NMSettingDcb:app-fcoe-priority: + * + * The highest User Priority (0 - 7) which FCoE frames should use, or -1 for + * default priority. Only used when #NMSettingDcb:app-fcoe-flags includes + * %NM_SETTING_DCB_FLAG_ENABLE. + * + * Since: 0.9.10 + **/ + g_object_class_install_property + (object_class, PROP_APP_FCOE_PRIORITY, + g_param_spec_int (NM_SETTING_DCB_APP_FCOE_PRIORITY, + "App FCoE Priority", + "The highest User Priority (0 - 7) which FCoE " + "frames should use, or -1 for default priority. Only " + "used when the 'app-fcoe-flags' property includes " + "the 'enabled' flag.", + -1, 7, -1, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE)); + + /** + * NMSettingDcb:app-fcoe-mode: + * + * The FCoE controller mode; either %NM_SETTING_DCB_FCOE_MODE_FABRIC (default) + * or %NM_SETTING_DCB_FCOE_MODE_VN2VN. + * + * Since: 0.9.10 + **/ + g_object_class_install_property + (object_class, PROP_APP_FCOE_MODE, + g_param_spec_string (NM_SETTING_DCB_APP_FCOE_MODE, + "App FCoE Mode", + "The FCoe controller mode; either 'fabric' (default) " + "or 'vn2vn'.", + NM_SETTING_DCB_FCOE_MODE_FABRIC, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE)); + + /** + * NMSettingDcb:app-iscsi-flags: + * + * Specifies the %NMSettingDcbFlags for the DCB iSCSI application. + * + * Since: 0.9.10 + **/ + g_object_class_install_property + (object_class, PROP_APP_ISCSI_FLAGS, + g_param_spec_uint (NM_SETTING_DCB_APP_ISCSI_FLAGS, + "App iSCSI Flags", + "Specifies the flags for the DCB iSCSI application. " + "Flags may be any combination of 0x1 (enable), 0x2 " + "(advertise), and 0x4 (willing).", + 0, DCB_FLAGS_ALL, 0, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + + /** + * NMSettingDcb:app-iscsi-priority: + * + * The highest User Priority (0 - 7) which iSCSI frames should use. Only + * used when #NMSettingDcb:app-iscsi-flags includes %NM_SETTING_DCB_FLAG_ENABLE. + * + * Since: 0.9.10 + **/ + g_object_class_install_property + (object_class, PROP_APP_ISCSI_PRIORITY, + g_param_spec_int (NM_SETTING_DCB_APP_ISCSI_PRIORITY, + "App iSCSI Priority", + "The highest User Priority (0 - 7) which iSCSI " + "frames should use, or -1 for default priority. Only " + "used when the 'app-iscsi-flags' property includes " + "the 'enabled' flag.", + -1, 7, -1, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE)); + + /** + * NMSettingDcb:app-fip-flags: + * + * Specifies the %NMSettingDcbFlags for the DCB FIP application. + * + * Since: 0.9.10 + **/ + g_object_class_install_property + (object_class, PROP_APP_FIP_FLAGS, + g_param_spec_uint (NM_SETTING_DCB_APP_FIP_FLAGS, + "App FIP Flags", + "Specifies the flags for the DCB FIP application. " + "Flags may be any combination of 0x1 (enable), 0x2 " + "(advertise), and 0x4 (willing).", + 0, DCB_FLAGS_ALL, 0, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + + /** + * NMSettingDcb:app-fip-priority: + * + * The highest User Priority (0 - 7) which FIP frames should use. Only + * used when #NMSettingDcb:app-fip-flags includes %NM_SETTING_DCB_FLAG_ENABLE. + * + * Since: 0.9.10 + **/ + g_object_class_install_property + (object_class, PROP_APP_FIP_PRIORITY, + g_param_spec_int (NM_SETTING_DCB_APP_FIP_PRIORITY, + "App FIP Priority", + "The highest User Priority (0 - 7) which FIP " + "frames should use, or -1 for default priority. Only " + "used when the 'app-fip-flags' property includes " + "the 'enabled' flag.", + -1, 7, -1, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE)); + + /** + * NMSettingDcb:priority-flow-control-flags: + * + * Specifies the %NMSettingDcbFlags for DCB Priority Flow Control (PFC). + * + * Since: 0.9.10 + **/ + g_object_class_install_property + (object_class, PROP_PFC_FLAGS, + g_param_spec_uint (NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS, + "Priority Flow Control Flags", + "Specifies the flags for DCB Priority Flow Control. " + "Flags may be any combination of 0x1 (enable), 0x2 " + "(advertise), and 0x4 (willing).", + 0, DCB_FLAGS_ALL, 0, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + + /** + * NMSettingDcb:priority-flow-control: + * + * An array of 8 uint values, where the array index corresponds to the + * User Priority (0 - 7) and the value indicates whether or not the + * corresponding priority should transmit priority pause. Allowed values + * are 0 (do not transmit pause) and 1 (transmit pause). + * + * Since: 0.9.10 + **/ + g_object_class_install_property + (object_class, PROP_PFC, + _nm_param_spec_specialized (NM_SETTING_DCB_PRIORITY_FLOW_CONTROL, + "Priority Flow Control", + "An array of 8 uint values, where the array index " + "corresponds to the User Priority (0 - 7) and the " + "value indicates whether or not the corresponding " + "priority should transmit priority pause. Allowed " + "values are 0 (do not transmit pause) and 1 " + "(transmit pause).", + DBUS_TYPE_G_UINT_ARRAY, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + + /** + * NMSettingDcb:priority-group-flags: + * + * Specifies the %NMSettingDcbFlags for DCB Priority Groups. + * + * Since: 0.9.10 + **/ + g_object_class_install_property + (object_class, PROP_PRIORITY_GROUP_FLAGS, + g_param_spec_uint (NM_SETTING_DCB_PRIORITY_GROUP_FLAGS, + "Priority Group Flags", + "Specifies the flags for DCB Priority Groups. " + "Flags may be any combination of 0x1 (enable), 0x2 " + "(advertise), and 0x4 (willing).", + 0, DCB_FLAGS_ALL, 0, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + + /** + * NMSettingDcb:priority-group-id: + * + * An array of 8 uint values, where the array index corresponds to the + * User Priority (0 - 7) and the value indicates the Priority Group ID. + * Allowed Priority Group ID values are 0 - 7 or 15 for the unrestricted + * group. + * + * Since: 0.9.10 + **/ + g_object_class_install_property + (object_class, PROP_PRIORITY_GROUP_ID, + _nm_param_spec_specialized (NM_SETTING_DCB_PRIORITY_GROUP_ID, + "Priority Group ID", + "An array of 8 uint values, where the array " + "index corresponds to the User Priority (0 - 7) " + "and the value indicates the Priority Group ID. " + "Allowed Priority Group ID values are 0 - 7 or " + "15 for the unrestricted group.", + DBUS_TYPE_G_UINT_ARRAY, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + + /** + * NMSettingDcb:priority-group-bandwidth: + * + * An array of 8 uint values, where the array index corresponds to the + * Priority Group ID (0 - 7) and the value indicates the percentage of + * link bandwidth allocated to that group. Allowed values are 0 - 100, + * and the sum of all values must total 100 percent. + * + * Since: 0.9.10 + **/ + g_object_class_install_property + (object_class, PROP_PRIORITY_GROUP_BANDWIDTH, + _nm_param_spec_specialized (NM_SETTING_DCB_PRIORITY_GROUP_BANDWIDTH, + "Priority Group Bandwidth", + "An array of 8 uint values, where the array index " + "corresponds to the Priority Group ID (0 - 7) and " + "the value indicates the percentage of link bandwidth " + "allocated to that group. Allowed values are 0 - 100, " + "and the sum of all values must total 100 percent.", + DBUS_TYPE_G_UINT_ARRAY, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + + /** + * NMSettingDcb:priority-bandwidth: + * + * An array of 8 uint values, where the array index corresponds to the + * User Priority (0 - 7) and the value indicates the percentage of bandwidth + * of the priority's assigned group that the priority may use. The sum of + * all percentages for priorities which belong to the same group must total + * 100 percent. + * + * Since: 0.9.10 + **/ + g_object_class_install_property + (object_class, PROP_PRIORITY_BANDWIDTH, + _nm_param_spec_specialized (NM_SETTING_DCB_PRIORITY_BANDWIDTH, + "Priority Bandwidth", + "An array of 8 uint values, where the array index " + "corresponds to the User Priority (0 - 7) and the " + "value indicates the percentage of bandwidth of " + "the priority's assigned group that the priority may " + "use. The sum of all percentages for priorities which " + "belong to the same group must total 100 percent.", + DBUS_TYPE_G_UINT_ARRAY, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + + /** + * NMSettingDcb:priority-strict: + * + * An array of 8 uint values, where the array index corresponds to the + * User Priority (0 - 7) and the value indicates whether or not the + * priority may use all of the bandwidth allocated to its assigned group. + * Allowed values are 0 (the priority may not utilize all bandwidth) or + * 1 (the priority may utilize all bandwidth). + * + * Since: 0.9.10 + **/ + g_object_class_install_property + (object_class, PROP_PRIORITY_STRICT, + _nm_param_spec_specialized (NM_SETTING_DCB_PRIORITY_STRICT_BANDWIDTH, + "Priority Strict", + "An array of 8 uint values, where the array index " + "corresponds to the User Priority (0 - 7) and the " + "value indicates whether or not the priority may " + "use all of the bandwidth allocated to its assigned " + "group. Allowed values are 0 (the priority may not " + "utilize all bandwidth) or 1 (the priority may " + "utilize all bandwidth).", + DBUS_TYPE_G_UINT_ARRAY, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + + /** + * NMSettingDcb:priority-traffic-class: + * + * An array of 8 uint values, where the array index corresponds to the + * User Priority (0 - 7) and the value indicates the traffic class (0 - 7) + * to which the priority is mapped. + * + * Since: 0.9.10 + **/ + g_object_class_install_property + (object_class, PROP_PRIORITY_TRAFFIC_CLASS, + _nm_param_spec_specialized (NM_SETTING_DCB_PRIORITY_TRAFFIC_CLASS, + "Priority Traffic Class", + "An array of 8 uint values, where the array index " + "corresponds to the User Priority (0 - 7) and the " + "value indicates the traffic class (0 - 7) to which " + "the priority is mapped.", + DBUS_TYPE_G_UINT_ARRAY, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); +} + diff --git a/libnm-util/nm-setting-dcb.h b/libnm-util/nm-setting-dcb.h new file mode 100644 index 0000000000..a8523d20af --- /dev/null +++ b/libnm-util/nm-setting-dcb.h @@ -0,0 +1,187 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ + +/* + * Dan Williams + * + * 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. + * + * (C) Copyright 2013 Red Hat, Inc. + */ + +#ifndef NM_SETTING_DCB_H +#define NM_SETTING_DCB_H + +#include + +G_BEGIN_DECLS + +#define NM_TYPE_SETTING_DCB (nm_setting_dcb_get_type ()) +#define NM_SETTING_DCB(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTING_DCB, NMSettingDcb)) +#define NM_SETTING_DCB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SETTING_DCB, NMSettingDcbClass)) +#define NM_IS_SETTING_DCB(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTING_DCB)) +#define NM_IS_SETTING_DCB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SETTING_DCB)) +#define NM_SETTING_DCB_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SETTING_DCB, NMSettingDcbClass)) + +#define NM_SETTING_DCB_SETTING_NAME "dcb" + +/** + * NMSettingDcbError: + * @NM_SETTING_DCB_ERROR_UNKNOWN: unknown or unclassified error + * @NM_SETTING_DCB_ERROR_INVALID_PROPERTY: the property was invalid + * @NM_SETTING_DCB_ERROR_MISSING_PROPERTY: the property was missing and is + * required + */ +typedef enum { + NM_SETTING_DCB_ERROR_UNKNOWN = 0, /*< nick=UnknownError >*/ + NM_SETTING_DCB_ERROR_INVALID_PROPERTY, /*< nick=InvalidProperty >*/ + NM_SETTING_DCB_ERROR_MISSING_PROPERTY /*< nick=MissingProperty >*/ +} NMSettingDcbError; + +#define NM_SETTING_DCB_ERROR nm_setting_dcb_error_quark () +GQuark nm_setting_dcb_error_quark (void); + +/** + * NMSettingDcbFlags: + * @NM_SETTING_DCB_FLAG_NONE: no flag + * @NM_SETTING_DCB_FLAG_ENABLE: the feature is enabled + * @NM_SETTING_DCB_FLAG_ADVERTISE: the feature is advertised + * @NM_SETTING_DCB_FLAG_WILLING: the feature is willing to change based on + * peer configuration advertisements + * + * DCB feature flags. + * + * Since: 0.9.10 + **/ +typedef enum { + NM_SETTING_DCB_FLAG_NONE = 0x00000000, + NM_SETTING_DCB_FLAG_ENABLE = 0x00000001, + NM_SETTING_DCB_FLAG_ADVERTISE = 0x00000002, + NM_SETTING_DCB_FLAG_WILLING = 0x00000004 +} NMSettingDcbFlags; + +/** + * NM_SETTING_DCB_FCOE_MODE_FABRIC: + * + * Indicates that the FCoE controller should use "fabric" mode (default) + * + * Since: 0.9.10 + */ +#define NM_SETTING_DCB_FCOE_MODE_FABRIC "fabric" + +/** + * NM_SETTING_DCB_FCOE_MODE_VN2VN: + * + * Indicates that the FCoE controller should use "VN2VN" mode. + * + * Since: 0.9.10 + */ +#define NM_SETTING_DCB_FCOE_MODE_VN2VN "vn2vn" + + +/* Properties */ +#define NM_SETTING_DCB_APP_FCOE_FLAGS "app-fcoe-flags" +#define NM_SETTING_DCB_APP_FCOE_PRIORITY "app-fcoe-priority" +#define NM_SETTING_DCB_APP_FCOE_MODE "app-fcoe-mode" + +#define NM_SETTING_DCB_APP_ISCSI_FLAGS "app-iscsi-flags" +#define NM_SETTING_DCB_APP_ISCSI_PRIORITY "app-iscsi-priority" + +#define NM_SETTING_DCB_APP_FIP_FLAGS "app-fip-flags" +#define NM_SETTING_DCB_APP_FIP_PRIORITY "app-fip-priority" + +#define NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS "priority-flow-control-flags" +#define NM_SETTING_DCB_PRIORITY_FLOW_CONTROL "priority-flow-control" + +#define NM_SETTING_DCB_PRIORITY_GROUP_FLAGS "priority-group-flags" +#define NM_SETTING_DCB_PRIORITY_GROUP_ID "priority-group-id" +#define NM_SETTING_DCB_PRIORITY_GROUP_BANDWIDTH "priority-group-bandwidth" +#define NM_SETTING_DCB_PRIORITY_BANDWIDTH "priority-bandwidth" +#define NM_SETTING_DCB_PRIORITY_STRICT_BANDWIDTH "priority-strict-bandwidth" +#define NM_SETTING_DCB_PRIORITY_TRAFFIC_CLASS "priority-traffic-class" + + +typedef struct { + NMSetting parent; +} NMSettingDcb; + +typedef struct { + NMSettingClass parent; + + /* Padding for future expansion */ + void (*_reserved1) (void); + void (*_reserved2) (void); + void (*_reserved3) (void); + void (*_reserved4) (void); +} NMSettingDcbClass; + +GType nm_setting_dcb_get_type (void); + +NMSetting * nm_setting_dcb_new (void); + +NMSettingDcbFlags nm_setting_dcb_get_app_fcoe_flags (NMSettingDcb *setting); +gint nm_setting_dcb_get_app_fcoe_priority (NMSettingDcb *setting); +const char * nm_setting_dcb_get_app_fcoe_mode (NMSettingDcb *setting); + +NMSettingDcbFlags nm_setting_dcb_get_app_iscsi_flags (NMSettingDcb *setting); +gint nm_setting_dcb_get_app_iscsi_priority (NMSettingDcb *setting); + +NMSettingDcbFlags nm_setting_dcb_get_app_fip_flags (NMSettingDcb *setting); +gint nm_setting_dcb_get_app_fip_priority (NMSettingDcb *setting); + +/* Priority Flow Control */ +NMSettingDcbFlags nm_setting_dcb_get_priority_flow_control_flags (NMSettingDcb *setting); +gboolean nm_setting_dcb_get_priority_flow_control (NMSettingDcb *setting, + guint user_priority); +void nm_setting_dcb_set_priority_flow_control (NMSettingDcb *setting, + guint user_priority, + gboolean enabled); + +/* Priority Groups */ +NMSettingDcbFlags nm_setting_dcb_get_priority_group_flags (NMSettingDcb *setting); + +guint nm_setting_dcb_get_priority_group_id (NMSettingDcb *setting, + guint user_priority); +void nm_setting_dcb_set_priority_group_id (NMSettingDcb *setting, + guint user_priority, + guint group_id); + +guint nm_setting_dcb_get_priority_group_bandwidth (NMSettingDcb *setting, + guint group_id); +void nm_setting_dcb_set_priority_group_bandwidth (NMSettingDcb *setting, + guint group_id, + guint bandwidth_percent); + +guint nm_setting_dcb_get_priority_bandwidth (NMSettingDcb *setting, + guint user_priority); +void nm_setting_dcb_set_priority_bandwidth (NMSettingDcb *setting, + guint user_priority, + guint bandwidth_percent); + +gboolean nm_setting_dcb_get_priority_strict_bandwidth (NMSettingDcb *setting, + guint user_priority); +void nm_setting_dcb_set_priority_strict_bandwidth (NMSettingDcb *setting, + guint user_priority, + gboolean strict); + +guint nm_setting_dcb_get_priority_traffic_class (NMSettingDcb *setting, + guint user_priority); +void nm_setting_dcb_set_priority_traffic_class (NMSettingDcb *setting, + guint user_priority, + guint traffic_class); + +G_END_DECLS + +#endif /* NM_SETTING_DCB_H */ diff --git a/libnm-util/tests/Makefile.am b/libnm-util/tests/Makefile.am index 45690c4f8b..b5bbacce6c 100644 --- a/libnm-util/tests/Makefile.am +++ b/libnm-util/tests/Makefile.am @@ -16,7 +16,8 @@ noinst_PROGRAMS = \ test-crypto \ test-secrets \ test-general \ - test-setting-8021x + test-setting-8021x \ + test-setting-dcb test_settings_defaults_SOURCES = \ test-settings-defaults.c @@ -58,10 +59,19 @@ test_setting_8021x_LDADD = \ $(GLIB_LIBS) \ $(DBUS_LIBS) -check-local: test-settings-defaults test-crypto test-secrets +test_setting_dcb_SOURCES = \ + test-setting-dcb.c + +test_setting_dcb_LDADD = \ + $(top_builddir)/libnm-util/libnm-util.la \ + $(GLIB_LIBS) \ + $(DBUS_LIBS) + +check-local: test-settings-defaults test-crypto test-secrets test-setting-8021x test-setting-dcb $(abs_builddir)/test-settings-defaults $(abs_builddir)/test-secrets $(abs_builddir)/test-general + $(abs_builddir)/test-setting-dcb # Private key and CA certificate in the same file (PEM) $(abs_builddir)/test-setting-8021x $(srcdir)/certs/test_key_and_cert.pem "test" diff --git a/libnm-util/tests/test-setting-dcb.c b/libnm-util/tests/test-setting-dcb.c new file mode 100644 index 0000000000..cefdeed8f9 --- /dev/null +++ b/libnm-util/tests/test-setting-dcb.c @@ -0,0 +1,308 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2013 Red Hat, Inc. + * + */ + +#include +#include +#include +#include "nm-setting-dcb.h" + +#define DCB_FLAGS_ALL (NM_SETTING_DCB_FLAG_ENABLE | \ + NM_SETTING_DCB_FLAG_ADVERTISE | \ + NM_SETTING_DCB_FLAG_WILLING) + +static void +test_dcb_flags_valid (void) +{ + NMSettingDcb *s_dcb; + GError *error = NULL; + gboolean success; + guint i; + + s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); + g_assert (s_dcb); + + g_assert_cmpint (nm_setting_dcb_get_app_fcoe_flags (s_dcb), ==, 0); + g_assert_cmpint (nm_setting_dcb_get_app_iscsi_flags (s_dcb), ==, 0); + g_assert_cmpint (nm_setting_dcb_get_app_fip_flags (s_dcb), ==, 0); + g_assert_cmpint (nm_setting_dcb_get_priority_flow_control_flags (s_dcb), ==, 0); + g_assert_cmpint (nm_setting_dcb_get_priority_group_flags (s_dcb), ==, 0); + + g_object_set (G_OBJECT (s_dcb), + NM_SETTING_DCB_APP_FCOE_FLAGS, DCB_FLAGS_ALL, + NM_SETTING_DCB_APP_ISCSI_FLAGS, DCB_FLAGS_ALL, + NM_SETTING_DCB_APP_FIP_FLAGS, DCB_FLAGS_ALL, + NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS, DCB_FLAGS_ALL, + NM_SETTING_DCB_PRIORITY_GROUP_FLAGS, DCB_FLAGS_ALL, + NULL); + /* Priority Group Bandwidth must total 100% */ + for (i = 0; i < 7; i++) + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, i, 12); + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 7, 16); + + success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error); + g_assert_no_error (error); + g_assert (success); + + g_assert_cmpint (nm_setting_dcb_get_app_fcoe_flags (s_dcb), ==, DCB_FLAGS_ALL); + g_assert_cmpint (nm_setting_dcb_get_app_iscsi_flags (s_dcb), ==, DCB_FLAGS_ALL); + g_assert_cmpint (nm_setting_dcb_get_app_fip_flags (s_dcb), ==, DCB_FLAGS_ALL); + g_assert_cmpint (nm_setting_dcb_get_priority_flow_control_flags (s_dcb), ==, DCB_FLAGS_ALL); + g_assert_cmpint (nm_setting_dcb_get_priority_group_flags (s_dcb), ==, DCB_FLAGS_ALL); +} + +#define TEST_FLAG(p, f, v) \ +{ \ + /* GObject property min/max should ensure the property does not get set to \ + * the invalid value, so we ensure the value we just tried to set is 0 and \ + * that verify is successful since the property never got set. \ + */ \ + g_object_set (G_OBJECT (s_dcb), p, v, NULL); \ + g_assert_cmpint (f (s_dcb), ==, 0); \ + success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error); \ + g_assert_no_error (error); \ + g_assert (success); \ +} + +static void +test_dcb_flags_invalid (void) +{ + NMSettingDcb *s_dcb; + GError *error = NULL; + gboolean success; + + s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); + g_assert (s_dcb); + + TEST_FLAG (NM_SETTING_DCB_APP_FCOE_FLAGS, nm_setting_dcb_get_app_fcoe_flags, 0x332523); + TEST_FLAG (NM_SETTING_DCB_APP_ISCSI_FLAGS, nm_setting_dcb_get_app_iscsi_flags, 0xFF); + TEST_FLAG (NM_SETTING_DCB_APP_FIP_FLAGS, nm_setting_dcb_get_app_fip_flags, 0x1111); + TEST_FLAG (NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS, nm_setting_dcb_get_priority_flow_control_flags, G_MAXUINT32); + TEST_FLAG (NM_SETTING_DCB_PRIORITY_GROUP_FLAGS, nm_setting_dcb_get_priority_group_flags, + (NM_SETTING_DCB_FLAG_ENABLE | NM_SETTING_DCB_FLAG_ADVERTISE | NM_SETTING_DCB_FLAG_WILLING) + 1); +} + +#define TEST_APP_PRIORITY(lcprop, ucprop, v) \ +{ \ + g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_APP_##ucprop##_FLAGS, NM_SETTING_DCB_FLAG_NONE, NULL); \ + \ + g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_APP_##ucprop##_PRIORITY, v, NULL); \ + g_assert_cmpint (nm_setting_dcb_get_app_##lcprop##_priority (s_dcb), ==, v); \ + \ + /* Assert that the setting is invalid while the app is disabled unless v is default */ \ + success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error); \ + if (v >= 0) { \ + g_assert_error (error, NM_SETTING_DCB_ERROR, NM_SETTING_DCB_ERROR_INVALID_PROPERTY); \ + g_assert (success == FALSE); \ + } else { \ + g_assert_no_error (error); \ + g_assert (success); \ + } \ + g_clear_error (&error); \ + \ + /* Set the enable flag and re-verify, this time it should be valid */ \ + g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_APP_##ucprop##_FLAGS, NM_SETTING_DCB_FLAG_ENABLE, NULL); \ + success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error); \ + g_assert_no_error (error); \ + g_assert (success); \ + \ + g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_APP_##ucprop##_PRIORITY, 0, NULL); \ +} + +static void +test_dcb_app_priorities (void) +{ + NMSettingDcb *s_dcb; + GError *error = NULL; + gboolean success; + + s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); + g_assert (s_dcb); + + /* Defaults */ + g_assert_cmpint (nm_setting_dcb_get_app_fcoe_priority (s_dcb), ==, -1); + g_assert_cmpint (nm_setting_dcb_get_app_iscsi_priority (s_dcb), ==, -1); + g_assert_cmpint (nm_setting_dcb_get_app_fip_priority (s_dcb), ==, -1); + + TEST_APP_PRIORITY (fcoe, FCOE, 6); + TEST_APP_PRIORITY (iscsi, ISCSI, 5); + TEST_APP_PRIORITY (fip, FIP, 4); + + TEST_APP_PRIORITY (fcoe, FCOE, -1); + TEST_APP_PRIORITY (iscsi, ISCSI, -1); + TEST_APP_PRIORITY (fip, FIP, -1); +} + +#define TEST_PRIORITY_VALID(fn, id, val, flagsprop, verify) \ +{ \ + /* Assert that setting the value gets the same value back out */ \ + nm_setting_dcb_set_priority_##fn (s_dcb, id, val); \ + g_assert_cmpint (nm_setting_dcb_get_priority_##fn (s_dcb, id), ==, val); \ + \ + if (verify) { \ + if (val != 0) { \ + /* Assert that verify fails because the flags do not include 'enabled' \ + * and a value has been set. \ + */ \ + success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error); \ + g_assert_error (error, NM_SETTING_DCB_ERROR, NM_SETTING_DCB_ERROR_INVALID_PROPERTY); \ + g_assert (success == FALSE); \ + g_clear_error (&error); \ + } \ + \ + /* Assert that adding the 'enabled' flag verifies the setting */ \ + g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_PRIORITY_##flagsprop##_FLAGS, NM_SETTING_DCB_FLAG_ENABLE, NULL); \ + success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error); \ + g_assert_no_error (error); \ + g_assert (success); \ + } \ + \ + /* Reset everything */ \ + g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_PRIORITY_##flagsprop##_FLAGS, NM_SETTING_DCB_FLAG_NONE, NULL); \ + nm_setting_dcb_set_priority_##fn (s_dcb, id, 0); \ +} + +/* If Priority Groups are enabled, PG bandwidth must equal 100% */ +#define SET_VALID_PRIORITY_GROUP_BANDWIDTH \ +{ \ + guint x; \ + for (x = 0; x < 7; x++) \ + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, x, 12); \ + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 7, 16); \ +} + +static void +test_dcb_priorities_valid (void) +{ + NMSettingDcb *s_dcb; + GError *error = NULL; + gboolean success; + guint i; + + s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); + g_assert (s_dcb); + + for (i = 0; i < 8; i++) + TEST_PRIORITY_VALID (flow_control, i, TRUE, FLOW_CONTROL, TRUE); + + SET_VALID_PRIORITY_GROUP_BANDWIDTH + for (i = 0; i < 8; i++) { + TEST_PRIORITY_VALID (group_id, i, i, GROUP, TRUE); + TEST_PRIORITY_VALID (group_id, i, 7 - i, GROUP, TRUE); + } + + /* Clear PG bandwidth from earlier tests */ + for (i = 0; i < 8; i++) + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, i, 0); + + /* Priority Group Bandwidth must add up to 100% if enabled, which requires + * some dancing for verifying individual values here. + */ + for (i = 0; i < 8; i++) { + guint other = 7 - (i % 8); + + /* Set another priority group to the remaining bandwidth */ + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, other, 100 - i); + TEST_PRIORITY_VALID (group_bandwidth, i, i, GROUP, TRUE); + + /* Set another priority group to the remaining bandwidth */ + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, other, 100 - (7 - i)); + TEST_PRIORITY_VALID (group_bandwidth, i, 7 - i, GROUP, TRUE); + + /* Clear remaining bandwidth */ + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, other, 0); + } + + SET_VALID_PRIORITY_GROUP_BANDWIDTH + for (i = 0; i < 8; i++) { + TEST_PRIORITY_VALID (bandwidth, i, i, GROUP, TRUE); + TEST_PRIORITY_VALID (bandwidth, i, 7 - i, GROUP, TRUE); + } + + SET_VALID_PRIORITY_GROUP_BANDWIDTH + for (i = 0; i < 8; i++) + TEST_PRIORITY_VALID (strict_bandwidth, i, TRUE, GROUP, TRUE); + + SET_VALID_PRIORITY_GROUP_BANDWIDTH + for (i = 0; i < 8; i++) { + TEST_PRIORITY_VALID (traffic_class, i, i, GROUP, TRUE); + TEST_PRIORITY_VALID (traffic_class, i, 7 - i, GROUP, TRUE); + } +} + +static void +test_dcb_bandwidth_sums (void) +{ + NMSettingDcb *s_dcb; + GError *error = NULL; + gboolean success; + + s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); + g_assert (s_dcb); + + /* Assert that setting the value gets the same value back out */ + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 0, 9); + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 1, 10); + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 2, 11); + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 3, 12); + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 4, 13); + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 5, 14); + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 6, 15); + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 7, 16); + + /* Assert verify success when sums total 100% */ + g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_PRIORITY_GROUP_FLAGS, NM_SETTING_DCB_FLAG_ENABLE, NULL); + success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error); + g_assert_no_error (error); + g_assert (success); + + /* Assert verify fails when sums do not total 100% */ + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 4, 20); + success = nm_setting_verify (NM_SETTING (s_dcb), NULL, &error); + g_assert_error (error, NM_SETTING_DCB_ERROR, NM_SETTING_DCB_ERROR_INVALID_PROPERTY); + g_assert (success == FALSE); + g_clear_error (&error); +} + +#define TPATH "/libnm-util/settings/dcb/" + +int main (int argc, char **argv) +{ + GError *error = NULL; + gboolean success; + + g_test_init (&argc, &argv, NULL); + g_type_init (); + + success = nm_utils_init (&error); + g_assert_no_error (error); + g_assert (success); + + g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL); + + g_test_add_func (TPATH "flags-valid", test_dcb_flags_valid); + g_test_add_func (TPATH "flags-invalid", test_dcb_flags_invalid); + g_test_add_func (TPATH "app-priorities", test_dcb_app_priorities); + g_test_add_func (TPATH "priorities", test_dcb_priorities_valid); + g_test_add_func (TPATH "bandwidth-sums", test_dcb_bandwidth_sums); + + return g_test_run (); +} + diff --git a/man/NetworkManager.conf.xml b/man/NetworkManager.conf.xml index 79f350d872..a07ba6e028 100644 --- a/man/NetworkManager.conf.xml +++ b/man/NetworkManager.conf.xml @@ -286,7 +286,8 @@ unmanaged-devices=mac:00:22:68:1c:59:b1;mac:00:1E:65:30:D1:C4;interface-name:eth HW, RFKILL, ETHER, WIFI, BT, MB, DHCP4, DHCP6, PPP, WIFI_SCAN, IP4, IP6, AUTOIP4, DNS, VPN, SHARING, SUPPLICANT, AGENTS, SETTINGS, SUSPEND, CORE, DEVICE, OLPC, WIMAX, - INFINIBAND, FIREWALL, ADSL, BOND, VLAN, BRIDGE. + INFINIBAND, FIREWALL, ADSL, BOND, VLAN, BRIDGE, DBUS_PROPS, + TEAM, CONCHECK, DCB. In addition, these special domains can be used: NONE, ALL, DEFAULT, DHCP, IP. diff --git a/po/POTFILES.in b/po/POTFILES.in index e953666cc3..3be5735052 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -19,6 +19,7 @@ libnm-util/nm-setting-bridge-port.c libnm-util/nm-setting-bridge.c libnm-util/nm-setting-cdma.c libnm-util/nm-setting-connection.c +libnm-util/nm-setting-dcb.c libnm-util/nm-setting-gsm.c libnm-util/nm-setting-infiniband.c libnm-util/nm-setting-ip4-config.c diff --git a/src/Makefile.am b/src/Makefile.am index d301000bf3..3a64a8f7d9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -230,6 +230,8 @@ nm_sources = \ nm-connectivity.h \ nm-dbus-manager.c \ nm-dbus-manager.h \ + nm-dcb.c \ + nm-dcb.h \ nm-dhcp4-config.c \ nm-dhcp4-config.h \ nm-dhcp6-config.c \ diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index 91a39ed18d..83f27b86b3 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -55,6 +55,7 @@ #include "nm-enum-types.h" #include "nm-dbus-manager.h" #include "nm-platform.h" +#include "nm-dcb.h" #include "nm-device-ethernet-glue.h" @@ -1045,9 +1046,24 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) NMSettingConnection *s_con; const char *connection_type; NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; + NMSettingDcb *s_dcb; + GError *error = NULL; g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); + /* DCB and FCoE setup */ + s_dcb = (NMSettingDcb *) device_get_setting (device, NM_TYPE_SETTING_DCB); + if (s_dcb) { + if (!nm_dcb_setup (nm_device_get_iface (device), s_dcb, &error)) { + nm_log_warn (LOGD_DEVICE | LOGD_HW, + "Activation (%s/wired) failed to enable DCB/FCoE: %s", + nm_device_get_iface (device), error->message); + g_clear_error (&error); + *reason = NM_DEVICE_STATE_REASON_DCB_FCOE_FAILED; + return NM_ACT_STAGE_RETURN_FAILURE; + } + } + s_con = NM_SETTING_CONNECTION (device_get_setting (device, NM_TYPE_SETTING_CONNECTION)); g_assert (s_con); @@ -1113,6 +1129,8 @@ deactivate (NMDevice *device) { NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device); NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); + NMSettingDcb *s_dcb; + GError *error = NULL; /* Clear wired secrets tries when deactivating */ clear_secrets_tries (device); @@ -1129,6 +1147,17 @@ deactivate (NMDevice *device) supplicant_interface_release (self); + /* Tear down DCB/FCoE if it was enabled */ + s_dcb = (NMSettingDcb *) device_get_setting (device, NM_TYPE_SETTING_DCB); + if (s_dcb) { + if (!nm_dcb_cleanup (nm_device_get_iface (device), &error)) { + nm_log_warn (LOGD_DEVICE | LOGD_HW, + "(%s) failed to disable DCB/FCoE: %s", + nm_device_get_iface (device), error->message); + g_clear_error (&error); + } + } + /* Reset MAC address back to initial address */ nm_device_set_hw_addr (device, priv->initial_hw_addr, "reset", LOGD_ETHER); } diff --git a/src/logging/nm-logging.c b/src/logging/nm-logging.c index cbb04a78e7..446b15fa50 100644 --- a/src/logging/nm-logging.c +++ b/src/logging/nm-logging.c @@ -49,7 +49,8 @@ nm_log_handler (const gchar *log_domain, LOGD_SUPPLICANT | LOGD_AGENTS | LOGD_SETTINGS | LOGD_SUSPEND | \ LOGD_CORE | LOGD_DEVICE | LOGD_OLPC_MESH | LOGD_WIMAX | \ LOGD_INFINIBAND | LOGD_FIREWALL | LOGD_ADSL | LOGD_BOND | \ - LOGD_VLAN | LOGD_BRIDGE | LOGD_DBUS_PROPS | LOGD_TEAM | LOGD_CONCHECK) + LOGD_VLAN | LOGD_BRIDGE | LOGD_DBUS_PROPS | LOGD_TEAM | LOGD_CONCHECK | \ + LOGD_DCB) #define LOGD_DEFAULT (LOGD_ALL & ~(LOGD_WIFI_SCAN | LOGD_DBUS_PROPS)) @@ -105,6 +106,7 @@ static const LogDesc domain_descs[] = { { LOGD_DBUS_PROPS,"DBUS_PROPS" }, { LOGD_TEAM, "TEAM" }, { LOGD_CONCHECK, "CONCHECK" }, + { LOGD_DCB, "DCB" }, { 0, NULL } }; diff --git a/src/logging/nm-logging.h b/src/logging/nm-logging.h index 1e3a16762c..07cfbce991 100644 --- a/src/logging/nm-logging.h +++ b/src/logging/nm-logging.h @@ -61,6 +61,7 @@ enum { LOGD_DBUS_PROPS = (1LL << 31), LOGD_TEAM = (1LL << 32), LOGD_CONCHECK = (1LL << 33), + LOGD_DCB = (1LL << 34), /* Data Center Bridging */ }; #define LOGD_DHCP (LOGD_DHCP4 | LOGD_DHCP6) diff --git a/src/nm-dcb.c b/src/nm-dcb.c new file mode 100644 index 0000000000..d42cf23ea1 --- /dev/null +++ b/src/nm-dcb.c @@ -0,0 +1,339 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2013 Red Hat, Inc. + */ + +#include +#include +#include + +#include +#include "nm-dcb.h" +#include "nm-platform.h" +#include "NetworkManagerUtils.h" +#include "nm-posix-signals.h" +#include "nm-logging.h" + +GQuark +nm_dcb_error_quark (void) +{ + static GQuark ret = 0; + + if (ret == 0) + ret = g_quark_from_static_string ("nm-dcb-error"); + return ret; +} + +static const char *helper_names[] = { "dcbtool", "fcoeadm" }; + +gboolean +do_helper (const char *iface, + guint which, + DcbFunc run_func, + gpointer user_data, + GError **error, + const char *fmt, + ...) +{ + char **argv = NULL, **split = NULL, *cmdline, *errmsg = NULL; + gboolean success = FALSE; + guint i, u; + va_list args; + + g_return_val_if_fail (fmt != NULL, FALSE); + + va_start (args, fmt); + cmdline = g_strdup_vprintf (fmt, args); + va_end (args); + + split = g_strsplit_set (cmdline, " ", 0); + if (!split) { + g_set_error (error, NM_DCB_ERROR, NM_DCB_ERROR_INTERNAL, + "failure parsing %s command line", helper_names[which]); + goto out; + } + + /* Allocate space for path, custom arg, interface name, arguments, and NULL */ + i = u = 0; + argv = g_new0 (char *, g_strv_length (split) + 4); + argv[i++] = NULL; /* Placeholder for dcbtool path */ + if (which == DCBTOOL) { + argv[i++] = "sc"; + argv[i++] = (char *) iface; + } + while (u < g_strv_length (split)) + argv[i++] = split[u++]; + argv[i++] = NULL; + success = run_func (argv, which, user_data, error); + if (!success && error) + g_assert (*error); + +out: + if (split) + g_strfreev (split); + g_free (argv); + g_free (cmdline); + g_free (errmsg); + return success; +} + +#define SET_FLAGS(f, tag) \ +G_STMT_START { \ + if (!do_helper (iface, DCBTOOL, run_func, user_data, error, tag " e:%c a:%c w:%c", \ + f & NM_SETTING_DCB_FLAG_ENABLE ? '1' : '0', \ + f & NM_SETTING_DCB_FLAG_ADVERTISE ? '1' : '0', \ + f & NM_SETTING_DCB_FLAG_WILLING ? '1' : '0')) \ + return FALSE; \ +} G_STMT_END + +#define SET_APP(f, s, tag) \ +G_STMT_START { \ + gint prio = nm_setting_dcb_get_app_##tag##_priority (s); \ + \ + SET_FLAGS (f, "app:" #tag); \ + if ((f & NM_SETTING_DCB_FLAG_ENABLE) && (prio >= 0)) { \ + if (!do_helper (iface, DCBTOOL, run_func, user_data, error, "app:" #tag " appcfg:%02x", (1 << prio))) \ + return FALSE; \ + } \ +} G_STMT_END + +gboolean +_dcb_setup (const char *iface, + NMSettingDcb *s_dcb, + DcbFunc run_func, + gpointer user_data, + GError **error) +{ + NMSettingDcbFlags flags; + guint i; + + g_assert (s_dcb); + + if (!do_helper (iface, DCBTOOL, run_func, user_data, error, "dcb on")) + return FALSE; + + /* FCoE */ + flags = nm_setting_dcb_get_app_fcoe_flags (s_dcb); + SET_APP (flags, s_dcb, fcoe); + + /* iSCSI */ + flags = nm_setting_dcb_get_app_iscsi_flags (s_dcb); + SET_APP (flags, s_dcb, iscsi); + + /* FIP */ + flags = nm_setting_dcb_get_app_fip_flags (s_dcb); + SET_APP (flags, s_dcb, fip); + + /* Priority Flow Control */ + flags = nm_setting_dcb_get_priority_flow_control_flags (s_dcb); + SET_FLAGS (flags, "pfc"); + if (flags & NM_SETTING_DCB_FLAG_ENABLE) { + char buf[10]; + + for (i = 0; i < 8; i++) + buf[i] = nm_setting_dcb_get_priority_flow_control (s_dcb, i) ? '1' : '0'; + buf[i] = 0; + if (!do_helper (iface, DCBTOOL, run_func, user_data, error, "pfc pfcup:%s", buf)) + return FALSE; + } + + /* Priority Groups */ + flags = nm_setting_dcb_get_priority_group_flags (s_dcb); + SET_FLAGS (flags, "pg"); + if (flags & NM_SETTING_DCB_FLAG_ENABLE) { + char buf[10]; + guint id; + + /* Priority Groups */ + for (i = 0; i < 8; i++) { + id = nm_setting_dcb_get_priority_group_id (s_dcb, i); + g_assert (id < 8 || id == 15); + buf[i] = (id < 8) ? ('0' + id) : 'f'; + } + buf[i] = 0; + if (!do_helper (iface, DCBTOOL, run_func, user_data, error, "pg pgid:%s", buf)) + return FALSE; + + /* Priority Group Bandwidth */ + if (!do_helper (iface, DCBTOOL, run_func, user_data, error, "pg pgpct:%u,%u,%u,%u,%u,%u,%u,%u", + nm_setting_dcb_get_priority_group_bandwidth (s_dcb, 0), + nm_setting_dcb_get_priority_group_bandwidth (s_dcb, 1), + nm_setting_dcb_get_priority_group_bandwidth (s_dcb, 2), + nm_setting_dcb_get_priority_group_bandwidth (s_dcb, 3), + nm_setting_dcb_get_priority_group_bandwidth (s_dcb, 4), + nm_setting_dcb_get_priority_group_bandwidth (s_dcb, 5), + nm_setting_dcb_get_priority_group_bandwidth (s_dcb, 6), + nm_setting_dcb_get_priority_group_bandwidth (s_dcb, 7))) + return FALSE; + + /* Priority Bandwidth */ + if (!do_helper (iface, DCBTOOL, run_func, user_data, error, "pg uppct:%u,%u,%u,%u,%u,%u,%u,%u", + nm_setting_dcb_get_priority_bandwidth (s_dcb, 0), + nm_setting_dcb_get_priority_bandwidth (s_dcb, 1), + nm_setting_dcb_get_priority_bandwidth (s_dcb, 2), + nm_setting_dcb_get_priority_bandwidth (s_dcb, 3), + nm_setting_dcb_get_priority_bandwidth (s_dcb, 4), + nm_setting_dcb_get_priority_bandwidth (s_dcb, 5), + nm_setting_dcb_get_priority_bandwidth (s_dcb, 6), + nm_setting_dcb_get_priority_bandwidth (s_dcb, 7))) + return FALSE; + + /* Strict Bandwidth */ + for (i = 0; i < 8; i++) + buf[i] = nm_setting_dcb_get_priority_strict_bandwidth (s_dcb, i) ? '1' : '0'; + buf[i] = 0; + if (!do_helper (iface, DCBTOOL, run_func, user_data, error, "pg strict:%s", buf)) + return FALSE; + + /* Priority Traffic Class */ + for (i = 0; i < 8; i++) { + id = nm_setting_dcb_get_priority_traffic_class (s_dcb, i); + g_assert (id < 8); + buf[i] = '0' + id; + } + buf[i] = 0; + if (!do_helper (iface, DCBTOOL, run_func, user_data, error, "pg up2tc:%s", buf)) + return FALSE; + } + + return TRUE; +} + +gboolean +_dcb_cleanup (const char *iface, + DcbFunc run_func, + gpointer user_data, + GError **error) +{ + /* FIXME: do we need to turn off features individually here? */ + return do_helper (iface, DCBTOOL, run_func, user_data, error, "dcb off"); +} + +gboolean +_fcoe_setup (const char *iface, + NMSettingDcb *s_dcb, + DcbFunc run_func, + gpointer user_data, + GError **error) +{ + NMSettingDcbFlags flags; + + g_assert (s_dcb); + + flags = nm_setting_dcb_get_app_fcoe_flags (s_dcb); + if (flags & NM_SETTING_DCB_FLAG_ENABLE) { + const char *mode = nm_setting_dcb_get_app_fcoe_mode (s_dcb); + + if (!do_helper (NULL, FCOEADM, run_func, user_data, error, "-m %s -c %s", mode, iface)) + return FALSE; + } else { + if (!do_helper (NULL, FCOEADM, run_func, user_data, error, "-d %s", iface)) + return FALSE; + } + + return TRUE; +} + +gboolean +_fcoe_cleanup (const char *iface, + DcbFunc run_func, + gpointer user_data, + GError **error) +{ + return do_helper (NULL, FCOEADM, run_func, user_data, error, "-d %s", iface); +} + + +static const char *dcbpaths[] = { + "/sbin/dcbtool", + "/usr/sbin/dcbtool", + "/usr/local/sbin/dcbtool", + NULL +}; +static const char *fcoepaths[] = { + "/sbin/fcoeadm", + "/usr/sbin/fcoeadm", + "/usr/local/sbin/fcoeadm", + NULL +}; + + +static gboolean +run_helper (char **argv, guint which, gpointer user_data, GError **error) +{ + static const char *helper_path[2] = { NULL, NULL }; + int exit_status = 0; + gboolean success; + char *errmsg = NULL, *outmsg = NULL; + const char **iter; + char *cmdline; + + if (G_UNLIKELY (helper_path[which] == NULL)) { + iter = (which == DCBTOOL) ? dcbpaths : fcoepaths; + while (*iter) { + if (g_file_test (*iter, G_FILE_TEST_EXISTS)) + helper_path[which] = *iter; + iter++; + } + if (!helper_path[which]) { + g_set_error (error, NM_DCB_ERROR, NM_DCB_ERROR_HELPER_NOT_FOUND, + "%s not found", + which == DCBTOOL ? "dcbtool" : "fcoadm"); + return FALSE; + } + } + + argv[0] = (char *) helper_path[which]; + cmdline = g_strjoinv (" ", argv); + nm_log_dbg (LOGD_DCB, "%s", cmdline); + + success = g_spawn_sync ("/", argv, NULL, 0 /*G_SPAWN_DEFAULT*/, + nm_unblock_posix_signals, NULL, + &outmsg, &errmsg, &exit_status, error); + /* Log any stderr output */ + if (success && WIFEXITED (exit_status) && WEXITSTATUS (exit_status) && (errmsg || outmsg)) { + nm_log_dbg (LOGD_DCB, "'%s' failed: '%s'", + cmdline, (errmsg && strlen (errmsg)) ? errmsg : outmsg); + g_set_error (error, NM_DCB_ERROR, NM_DCB_ERROR_HELPER_FAILED, + "Failed to run '%s'", cmdline); + success = FALSE; + } + g_free (errmsg); + + g_free (cmdline); + return success; +} + +gboolean +nm_dcb_setup (const char *iface, NMSettingDcb *s_dcb, GError **error) +{ + gboolean success; + + success = _dcb_setup (iface, s_dcb, run_helper, GUINT_TO_POINTER (DCBTOOL), error); + if (success) + success = _fcoe_setup (iface, s_dcb, run_helper, GUINT_TO_POINTER (FCOEADM), error); + + return success; +} + +gboolean +nm_dcb_cleanup (const char *iface, GError **error) +{ + return _dcb_cleanup (iface, run_helper, GUINT_TO_POINTER (DCBTOOL), error); +} + diff --git a/src/nm-dcb.h b/src/nm-dcb.h new file mode 100644 index 0000000000..3dbd5e6f4f --- /dev/null +++ b/src/nm-dcb.h @@ -0,0 +1,93 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2013 Red Hat, Inc. + */ + +#ifndef NM_DCB_H +#define NM_DCB_H + +#include +#include "nm-setting-dcb.h" + +/** + * NMDcbError: + * @NM_DCB_ERROR_UNKNOWN: unknown or unclassified error + * @NM_DCB_ERROR_INTERNAL: a internal programmer error + * @NM_DCB_ERROR_BAD_CONFIG: configuration was invalid + * @NM_DCB_ERROR_HELPER_NOT_FOUND: the required helper program was not found + * @NM_DCB_ERROR_HELPER_FAILED: the helper program failed + * + * NOTE: these errors are internal-use only and should never be used with D-Bus. + **/ +typedef enum { + NM_DCB_ERROR_UNKNOWN = 0, + NM_DCB_ERROR_INTERNAL, + NM_DCB_ERROR_BAD_CONFIG, + NM_DCB_ERROR_HELPER_NOT_FOUND, + NM_DCB_ERROR_HELPER_FAILED, +} NMDcbError; + +#define NM_DCB_ERROR (nm_dcb_error_quark ()) +GQuark nm_dcb_error_quark (void); +#define NM_TYPE_DCB_ERROR (nm_dcb_error_get_type ()) +GType nm_dcb_error_get_type (void); + + +gboolean nm_dcb_setup (const char *iface, NMSettingDcb *s_dcb, GError **error); +gboolean nm_dcb_cleanup (const char *iface, GError **error); + +/* For testcases only! */ +typedef gboolean (*DcbFunc) (char **argv, + guint which, + gpointer user_data, + GError **error); + +#define DCBTOOL 0 +#define FCOEADM 1 + +gboolean do_helper (const char *iface, + guint which, + DcbFunc run_func, + gpointer user_data, + GError **error, + const char *fmt, + ...) G_GNUC_PRINTF(6, 7); + +gboolean _dcb_setup (const char *iface, + NMSettingDcb *s_dcb, + DcbFunc run_func, + gpointer user_data, + GError **error); + +gboolean _dcb_cleanup (const char *iface, + DcbFunc run_func, + gpointer user_data, + GError **error); + +gboolean _fcoe_setup (const char *iface, + NMSettingDcb *s_dcb, + DcbFunc run_func, + gpointer user_data, + GError **error); + +gboolean _fcoe_cleanup (const char *iface, + DcbFunc run_func, + gpointer user_data, + GError **error); + +#endif /* NM_DCB_H */ diff --git a/src/settings/plugins/ifcfg-rh/reader.c b/src/settings/plugins/ifcfg-rh/reader.c index de53e401c9..ddcb1e0b2e 100644 --- a/src/settings/plugins/ifcfg-rh/reader.c +++ b/src/settings/plugins/ifcfg-rh/reader.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include "wifi-utils.h" @@ -74,7 +75,7 @@ get_int (const char *str, int *value) errno = 0; tmp = strtol (str, &e, 0); - if (errno || *e != '\0') + if (errno || *e != '\0' || tmp > G_MAXINT || tmp < G_MININT) return FALSE; *value = (int) tmp; return TRUE; @@ -1772,6 +1773,397 @@ check_if_team_slave (shvarFile *ifcfg, g_free (value); } +typedef struct { + const char *enable_key; + const char *advertise_key; + const char *willing_key; + const char *flags_prop; +} DcbFlagsProperty; + +enum { + DCB_APP_FCOE_FLAGS = 0, + DCB_APP_ISCSI_FLAGS = 1, + DCB_APP_FIP_FLAGS = 2, + DCB_PFC_FLAGS = 3, + DCB_PG_FLAGS = 4, +}; + +static DcbFlagsProperty dcb_flags_props[] = { + { "DCB_APP_FCOE_ENABLE", "DCB_APP_FCOE_ADVERTISE", "DCB_APP_FCOE_WILLING", NM_SETTING_DCB_APP_FCOE_FLAGS }, + { "DCB_APP_ISCSI_ENABLE", "DCB_APP_ISCSI_ADVERTISE", "DCB_APP_ISCSI_WILLING", NM_SETTING_DCB_APP_ISCSI_FLAGS }, + { "DCB_APP_FIP_ENABLE", "DCB_APP_FIP_ADVERTISE", "DCB_APP_FIP_WILLING", NM_SETTING_DCB_APP_FIP_FLAGS }, + { "DCB_PFC_ENABLE", "DCB_PFC_ADVERTISE", "DCB_PFC_WILLING", NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS }, + { "DCB_PG_ENABLE", "DCB_PG_ADVERTISE", "DCB_PG_WILLING", NM_SETTING_DCB_PRIORITY_GROUP_FLAGS }, + { NULL }, +}; + +static NMSettingDcbFlags +read_dcb_flags (shvarFile *ifcfg, DcbFlagsProperty *property) +{ + NMSettingDcbFlags flags = NM_SETTING_DCB_FLAG_NONE; + + if (svTrueValue (ifcfg, property->enable_key, FALSE)) + flags |= NM_SETTING_DCB_FLAG_ENABLE; + if (svTrueValue (ifcfg, property->advertise_key, FALSE)) + flags |= NM_SETTING_DCB_FLAG_ADVERTISE; + if (svTrueValue (ifcfg, property->willing_key, FALSE)) + flags |= NM_SETTING_DCB_FLAG_WILLING; + + return flags; +} + +static gboolean +read_dcb_app (shvarFile *ifcfg, + NMSettingDcb *s_dcb, + const char *app, + DcbFlagsProperty *flags_prop, + const char *priority_prop, + GError **error) +{ + NMSettingDcbFlags flags = NM_SETTING_DCB_FLAG_NONE; + char *tmp, *val; + gboolean success = TRUE; + int priority = -1; + + flags = read_dcb_flags (ifcfg, flags_prop); + + /* Priority */ + tmp = g_strdup_printf ("DCB_APP_%s_PRIORITY", app); + val = svGetValue (ifcfg, tmp, FALSE); + if (val) { + success = get_int (val, &priority); + if (success) + success = (priority >= 0 && priority <= 7); + if (!success) { + g_set_error (error, IFCFG_PLUGIN_ERROR, 0, + "Invalid %s value '%s' (expected 0 - 7)", + tmp, val); + } + g_free (val); + + if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: ignoring DCB %s priority; app not enabled", app); + } + g_free (tmp); + + if (success) { + g_object_set (G_OBJECT (s_dcb), + flags_prop->flags_prop, flags, + priority_prop, (guint) priority, + NULL); + } + + return success; +} + +typedef void (*DcbSetBoolFunc) (NMSettingDcb *, guint, gboolean); + +static gboolean +read_dcb_bool_array (shvarFile *ifcfg, + NMSettingDcb *s_dcb, + NMSettingDcbFlags flags, + const char *prop, + const char *desc, + DcbSetBoolFunc set_func, + GError **error) +{ + char *val; + gboolean success = FALSE; + guint i; + + val = svGetValue (ifcfg, prop, FALSE); + if (!val) + return TRUE; + + if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: ignoring %s; %s is not enabled", prop, desc); + success = TRUE; + goto out; + } + + val = g_strstrip (val); + if (strlen (val) != 8) { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " error: %s value '%s' must be 8 characters long", prop, val); + g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0, "boolean array must be 8 characters"); + goto out; + } + + /* All characters must be either 0 or 1 */ + for (i = 0; i < 8; i++) { + if (val[i] != '0' && val[i] != '1') { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " error: invalid %s value '%s': not all 0s and 1s", prop, val); + g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0, "invalid boolean digit"); + goto out; + } + set_func (s_dcb, i, (val[i] == '1')); + } + success = TRUE; + +out: + g_free (val); + return success; +} + +typedef void (*DcbSetUintFunc) (NMSettingDcb *, guint, guint); + +static gboolean +read_dcb_uint_array (shvarFile *ifcfg, + NMSettingDcb *s_dcb, + NMSettingDcbFlags flags, + const char *prop, + const char *desc, + gboolean f_allowed, + DcbSetUintFunc set_func, + GError **error) +{ + char *val; + gboolean success = FALSE; + guint i; + + val = svGetValue (ifcfg, prop, FALSE); + if (!val) + return TRUE; + + if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: ignoring %s; %s is not enabled", prop, desc); + success = TRUE; + goto out; + } + + val = g_strstrip (val); + if (strlen (val) != 8) { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " error: %s value '%s' must be 8 characters long", prop, val); + g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0, "uint array must be 8 characters"); + goto out; + } + + /* All characters must be either 0 - 7 or (optionally) f */ + for (i = 0; i < 8; i++) { + if (val[i] >= '0' && val[i] <= '7') + set_func (s_dcb, i, val[i] - '0'); + else if (f_allowed && (val[i] == 'f' || val[i] == 'F')) + set_func (s_dcb, i, 15); + else { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " error: invalid %s value '%s': not 0 - 7%s", + prop, val, f_allowed ? " or 'f'" : ""); + g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0, "invalid uint digit"); + goto out; + } + } + success = TRUE; + +out: + g_free (val); + return success; +} + +static gboolean +read_dcb_percent_array (shvarFile *ifcfg, + NMSettingDcb *s_dcb, + NMSettingDcbFlags flags, + const char *prop, + const char *desc, + gboolean sum_pct, + DcbSetUintFunc set_func, + GError **error) +{ + char *val; + gboolean success = FALSE; + char **split = NULL, **iter; + int tmp; + guint i, sum = 0; + + val = svGetValue (ifcfg, prop, FALSE); + if (!val) + return TRUE; + + if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: ignoring %s; %s is not enabled", prop, desc); + success = TRUE; + goto out; + } + + val = g_strstrip (val); + split = g_strsplit_set (val, ",", 0); + if (!split || (g_strv_length (split) != 8)) { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " error: invalid %s percentage list value '%s'", prop, val); + g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0, "percent array must be 8 elements"); + goto out; + } + + for (iter = split, i = 0; iter && *iter; iter++, i++) { + if (!get_int (*iter, &tmp) || tmp < 0 || tmp > 100) { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " error: invalid %s percentage value '%s'", prop, *iter); + g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0, "invalid percent element"); + goto out; + } + set_func (s_dcb, i, (guint) tmp); + sum += (guint) tmp; + } + + if (sum_pct && (sum != 100)) { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " error: %s percentages do not equal 100%%", prop); + g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0, "invalid percentage sum"); + goto out; + } + + success = TRUE; + +out: + if (split) + g_strfreev (split); + g_free (val); + return success; +} + +static gboolean +make_dcb_setting (shvarFile *ifcfg, + const char *network_file, + NMSetting **out_setting, + GError **error) +{ + NMSettingDcb *s_dcb = NULL; + gboolean dcb_on; + NMSettingDcbFlags flags = NM_SETTING_DCB_FLAG_NONE; + char *val; + + g_return_val_if_fail (out_setting != NULL, FALSE); + + dcb_on = !!svTrueValue (ifcfg, "DCB", FALSE); + if (!dcb_on) + return TRUE; + + s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); + g_assert (s_dcb); + + /* FCOE */ + if (!read_dcb_app (ifcfg, s_dcb, "FCOE", + &dcb_flags_props[DCB_APP_FCOE_FLAGS], + NM_SETTING_DCB_APP_FCOE_PRIORITY, + error)) { + g_object_unref (s_dcb); + return FALSE; + } + if (nm_setting_dcb_get_app_fcoe_flags (s_dcb) & NM_SETTING_DCB_FLAG_ENABLE) { + val = svGetValue (ifcfg, "DCB_APP_FCOE_MODE", FALSE); + if (val) { + if (strcmp (val, NM_SETTING_DCB_FCOE_MODE_FABRIC) == 0 || + strcmp (val, NM_SETTING_DCB_FCOE_MODE_VN2VN) == 0) + g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_APP_FCOE_MODE, val, NULL); + else { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " error: invalid FCoE mode '%s'", val); + g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0, "invalid FCoE mode"); + g_free (val); + g_object_unref (s_dcb); + return FALSE; + } + g_free (val); + } + } + + /* iSCSI */ + if (!read_dcb_app (ifcfg, s_dcb, "ISCSI", + &dcb_flags_props[DCB_APP_ISCSI_FLAGS], + NM_SETTING_DCB_APP_ISCSI_PRIORITY, + error)) { + g_object_unref (s_dcb); + return FALSE; + } + + /* FIP */ + if (!read_dcb_app (ifcfg, s_dcb, "FIP", + &dcb_flags_props[DCB_APP_FIP_FLAGS], + NM_SETTING_DCB_APP_FIP_PRIORITY, + error)) { + g_object_unref (s_dcb); + return FALSE; + } + + /* Priority Flow Control */ + flags = read_dcb_flags (ifcfg, &dcb_flags_props[DCB_PFC_FLAGS]); + g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS, flags, NULL); + + if (!read_dcb_bool_array (ifcfg, + s_dcb, + flags, + "DCB_PFC_UP", + "PFC", + nm_setting_dcb_set_priority_flow_control, + error)) { + g_object_unref (s_dcb); + return FALSE; + } + + /* Priority Groups */ + flags = read_dcb_flags (ifcfg, &dcb_flags_props[DCB_PG_FLAGS]); + g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_PRIORITY_GROUP_FLAGS, flags, NULL); + + if (!read_dcb_uint_array (ifcfg, + s_dcb, + flags, + "DCB_PG_ID", + "PGID", + TRUE, + nm_setting_dcb_set_priority_group_id, + error)) { + g_object_unref (s_dcb); + return FALSE; + } + + /* Group bandwidth */ + if (!read_dcb_percent_array (ifcfg, + s_dcb, + flags, + "DCB_PG_PCT", + "PGPCT", + TRUE, + nm_setting_dcb_set_priority_group_bandwidth, + error)) { + g_object_unref (s_dcb); + return FALSE; + } + + /* Priority bandwidth */ + if (!read_dcb_percent_array (ifcfg, + s_dcb, + flags, + "DCB_PG_UPPCT", + "UPPCT", + FALSE, + nm_setting_dcb_set_priority_bandwidth, + error)) { + g_object_unref (s_dcb); + return FALSE; + } + + /* Strict Bandwidth */ + if (!read_dcb_bool_array (ifcfg, + s_dcb, + flags, + "DCB_PG_STRICT", + "STRICT", + nm_setting_dcb_set_priority_strict_bandwidth, + error)) { + g_object_unref (s_dcb); + return FALSE; + } + + if (!read_dcb_uint_array (ifcfg, + s_dcb, + flags, + "DCB_PG_UP2TC", + "UP2TC", + FALSE, + nm_setting_dcb_set_priority_traffic_class, + error)) { + g_object_unref (s_dcb); + return FALSE; + } + + *out_setting = NM_SETTING (s_dcb); + return TRUE; +} + static gboolean add_one_wep_key (shvarFile *ifcfg, const char *shvar_key, @@ -4505,7 +4897,7 @@ connection_from_file (const char *filename, NMConnection *connection = NULL; shvarFile *parsed; char *type, *devtype, *nmc = NULL, *bootproto; - NMSetting *s_ip4, *s_ip6, *s_port; + NMSetting *s_ip4, *s_ip6, *s_port, *s_dcb = NULL; const char *ifcfg_name = NULL; gboolean nm_controlled = TRUE; char *unmanaged = NULL; @@ -4678,6 +5070,14 @@ connection_from_file (const char *filename, if (s_port) nm_connection_add_setting (connection, s_port); + if (!make_dcb_setting (parsed, network_file, &s_dcb, error)) { + g_object_unref (connection); + connection = NULL; + goto done; + } + if (s_dcb) + nm_connection_add_setting (connection, s_dcb); + /* iSCSI / ibft connections are read-only since their settings are * stored in NVRAM and can only be changed in BIOS. */ diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am b/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am index ee9b5db9f8..f5b731a0bb 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am @@ -96,7 +96,18 @@ EXTRA_DIST = \ ifcfg-test-infiniband \ ifcfg-test-bond-main \ ifcfg-test-bond-slave \ - ifcfg-test-bond-slave-ib + ifcfg-test-bond-slave-ib \ + ifcfg-test-dcb \ + ifcfg-test-dcb-default-app-priorities \ + ifcfg-test-dcb-bad-booleans \ + ifcfg-test-dcb-short-booleans \ + ifcfg-test-dcb-bad-uints \ + ifcfg-test-dcb-short-uints \ + ifcfg-test-dcb-bad-percent \ + ifcfg-test-dcb-short-percent \ + ifcfg-test-dcb-pgpct-not-100 \ + ifcfg-test-fcoe-fabric \ + ifcfg-test-fcoe-vn2vn check-local: @for f in $(EXTRA_DIST); do \ diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb new file mode 100644 index 0000000000..6e6589d39e --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb @@ -0,0 +1,43 @@ +TYPE=Ethernet +DEVICE=eth0 +HWADDR=00:11:22:33:44:ee +BOOTPROTO=none +IPADDR=1.2.3.4 +PREFIX=24 +GATEWAY=1.1.1.1 + +# dcb global switch +# use DCB=no to turn it off +DCB=yes + +# application settings +DCB_APP_FCOE_PRIORITY=7 +DCB_APP_FCOE_ENABLE=yes +DCB_APP_FCOE_ADVERTISE=yes +DCB_APP_FCOE_WILLING=yes + +DCB_APP_ISCSI_PRIORITY=6 +DCB_APP_ISCSI_ENABLE=yes +DCB_APP_ISCSI_ADVERTISE=yes +DCB_APP_ISCSI_WILLING=yes + +DCB_APP_FIP_PRIORITY=2 +DCB_APP_FIP_ENABLE=yes +DCB_APP_FIP_ADVERTISE=yes +DCB_APP_FIP_WILLING=yes + +# priority group settings +DCB_PG_UP2TC=76543210 +DCB_PG_PCT=25,0,0,75,0,0,0,0 +DCB_PG_ID=0000111f +DCB_PG_UPPCT=5,10,30,25,10,50,5,0 +DCB_PG_STRICT=00110101 +DCB_PG_ENABLE=yes +DCB_PG_ADVERTISE=yes +DCB_PG_WILLING=yes + +# priority flow control settings +DCB_PFC_UP=10011010 +DCB_PFC_ENABLE=yes +DCB_PFC_ADVERTISE=yes +DCB_PFC_WILLING=no diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-bad-booleans b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-bad-booleans new file mode 100644 index 0000000000..2f46a0823c --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-bad-booleans @@ -0,0 +1,12 @@ +TYPE=Ethernet +DEVICE=eth0 +HWADDR=00:11:22:33:44:ee +BOOTPROTO=none +IPADDR=1.2.3.4 +PREFIX=24 +GATEWAY=1.1.1.1 + +DCB=yes +DCB_PG_STRICT=02030101 +DCB_PG_ENABLE=yes + diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-bad-percent b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-bad-percent new file mode 100644 index 0000000000..0c5d7b8872 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-bad-percent @@ -0,0 +1,12 @@ +TYPE=Ethernet +DEVICE=eth0 +HWADDR=00:11:22:33:44:ee +BOOTPROTO=none +IPADDR=1.2.3.4 +PREFIX=24 +GATEWAY=1.1.1.1 + +DCB=yes +DCB_PG_PCT=25,0,0,75,0,0,110,0 +DCB_PG_ENABLE=yes + diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-bad-uints b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-bad-uints new file mode 100644 index 0000000000..8334999b12 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-bad-uints @@ -0,0 +1,12 @@ +TYPE=Ethernet +DEVICE=eth0 +HWADDR=00:11:22:33:44:ee +BOOTPROTO=none +IPADDR=1.2.3.4 +PREFIX=24 +GATEWAY=1.1.1.1 + +DCB=yes +DCB_PG_UP2TC=96543210 +DCB_PG_ENABLE=yes + diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-default-app-priorities b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-default-app-priorities new file mode 100644 index 0000000000..5bdcb63ce6 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-default-app-priorities @@ -0,0 +1,7 @@ +TYPE=Ethernet +DEVICE=eth0 +DCB=yes +DCB_APP_FCOE_ENABLE=yes +DCB_APP_ISCSI_ENABLE=yes +DCB_APP_FIP_ENABLE=yes + diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-pgpct-not-100 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-pgpct-not-100 new file mode 100644 index 0000000000..95eb7c5b55 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-pgpct-not-100 @@ -0,0 +1,12 @@ +TYPE=Ethernet +DEVICE=eth0 +HWADDR=00:11:22:33:44:ee +BOOTPROTO=none +IPADDR=1.2.3.4 +PREFIX=24 +GATEWAY=1.1.1.1 + +DCB=yes +DCB_PG_PCT=25,0,0,3,75,0,25,0 +DCB_PG_ENABLE=yes + diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-short-booleans b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-short-booleans new file mode 100644 index 0000000000..fbe1cbbc53 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-short-booleans @@ -0,0 +1,12 @@ +TYPE=Ethernet +DEVICE=eth0 +HWADDR=00:11:22:33:44:ee +BOOTPROTO=none +IPADDR=1.2.3.4 +PREFIX=24 +GATEWAY=1.1.1.1 + +DCB=yes +DCB_PG_STRICT=0111010 +DCB_PG_ENABLE=yes + diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-short-percent b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-short-percent new file mode 100644 index 0000000000..07ba6b6412 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-short-percent @@ -0,0 +1,12 @@ +TYPE=Ethernet +DEVICE=eth0 +HWADDR=00:11:22:33:44:ee +BOOTPROTO=none +IPADDR=1.2.3.4 +PREFIX=24 +GATEWAY=1.1.1.1 + +DCB=yes +DCB_PG_PCT=25,0,0,75,0,0,0 +DCB_PG_ENABLE=yes + diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-short-uints b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-short-uints new file mode 100644 index 0000000000..05ae39cb6e --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-short-uints @@ -0,0 +1,12 @@ +TYPE=Ethernet +DEVICE=eth0 +HWADDR=00:11:22:33:44:ee +BOOTPROTO=none +IPADDR=1.2.3.4 +PREFIX=24 +GATEWAY=1.1.1.1 + +DCB=yes +DCB_PG_UP2TC=7654321 +DCB_PG_ENABLE=yes + diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-fcoe-fabric b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-fcoe-fabric new file mode 100644 index 0000000000..cde1c28d67 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-fcoe-fabric @@ -0,0 +1,6 @@ +TYPE=Ethernet +DEVICE=eth0 +DCB=yes +DCB_APP_FCOE_ENABLE=yes +DCB_APP_FCOE_MODE=fabric + diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-fcoe-vn2vn b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-fcoe-vn2vn new file mode 100644 index 0000000000..20c08451e2 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-fcoe-vn2vn @@ -0,0 +1,6 @@ +TYPE=Ethernet +DEVICE=eth0 +DCB=yes +DCB_APP_FCOE_ENABLE=yes +DCB_APP_FCOE_MODE=vn2vn + diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index 51aef533a4..1d93ed1b40 100644 --- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -45,6 +45,7 @@ #include #include #include +#include #include "nm-test-helpers.h" #include "NetworkManagerUtils.h" @@ -12712,6 +12713,416 @@ test_write_bond_slave_ib (void) g_object_unref (reread); } +#define DCB_ALL_FLAGS (NM_SETTING_DCB_FLAG_ENABLE | \ + NM_SETTING_DCB_FLAG_ADVERTISE | \ + NM_SETTING_DCB_FLAG_WILLING) + +static void +test_read_dcb_basic (void) +{ + NMConnection *connection; + GError *error = NULL; + NMSettingDcb *s_dcb; + gboolean success; + guint i; + guint expected_group_ids[8] = { 0, 0, 0, 0, 1, 1, 1, 0xF }; + guint expected_group_bandwidths[8] = { 25, 0, 0, 75, 0, 0, 0, 0 }; + guint expected_bandwidths[8] = { 5, 10, 30, 25, 10, 50, 5, 0 }; + gboolean expected_strict[8] = { FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE }; + guint expected_traffic_classes[8] = { 7, 6, 5, 4, 3, 2, 1, 0 }; + gboolean expected_pfcs[8] = { TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, FALSE }; + + connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb", + NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, NULL, &error, NULL); + g_assert_no_error (error); + g_assert (connection); + success = nm_connection_verify (connection, &error); + g_assert_no_error (error); + g_assert (success); + + s_dcb = nm_connection_get_setting_dcb (connection); + g_assert (s_dcb); + + g_assert_cmpint (nm_setting_dcb_get_app_fcoe_flags (s_dcb), ==, DCB_ALL_FLAGS); + g_assert_cmpint (nm_setting_dcb_get_app_fcoe_priority (s_dcb), ==, 7); + + g_assert_cmpint (nm_setting_dcb_get_app_iscsi_flags (s_dcb), ==, DCB_ALL_FLAGS); + g_assert_cmpint (nm_setting_dcb_get_app_iscsi_priority (s_dcb), ==, 6); + + g_assert_cmpint (nm_setting_dcb_get_app_fip_flags (s_dcb), ==, DCB_ALL_FLAGS); + g_assert_cmpint (nm_setting_dcb_get_app_fip_priority (s_dcb), ==, 2); + + g_assert_cmpint (nm_setting_dcb_get_priority_flow_control_flags (s_dcb), ==, (NM_SETTING_DCB_FLAG_ENABLE | NM_SETTING_DCB_FLAG_ADVERTISE)); + for (i = 0; i < 8; i++) + g_assert_cmpint (nm_setting_dcb_get_priority_flow_control (s_dcb, i), ==, expected_pfcs[i]); + + g_assert_cmpint (nm_setting_dcb_get_priority_group_flags (s_dcb), ==, DCB_ALL_FLAGS); + + /* Group IDs */ + for (i = 0; i < 8; i++) + g_assert_cmpint (nm_setting_dcb_get_priority_group_id (s_dcb, i), ==, expected_group_ids[i]); + + /* Group bandwidth */ + for (i = 0; i < 8; i++) + g_assert_cmpint (nm_setting_dcb_get_priority_group_bandwidth (s_dcb, i), ==, expected_group_bandwidths[i]); + + /* User priority bandwidth */ + for (i = 0; i < 8; i++) + g_assert_cmpint (nm_setting_dcb_get_priority_bandwidth (s_dcb, i), ==, expected_bandwidths[i]); + + /* Strict bandwidth */ + for (i = 0; i < 8; i++) + g_assert_cmpint (nm_setting_dcb_get_priority_strict_bandwidth (s_dcb, i), ==, expected_strict[i]); + + /* Traffic class */ + for (i = 0; i < 8; i++) + g_assert_cmpint (nm_setting_dcb_get_priority_traffic_class (s_dcb, i), ==, expected_traffic_classes[i]); + + g_object_unref (connection); +} + +static void +test_write_dcb_basic (void) +{ + NMConnection *connection, *reread; + GError *error = NULL; + NMSettingConnection *s_con; + NMSettingWired *s_wired; + NMSettingDcb *s_dcb; + NMSettingIP4Config *s_ip4; + NMSettingIP6Config *s_ip6; + gboolean success, ignore_error; + guint i; + char *uuid, *testfile; + const guint group_ids[8] = { 4, 0xF, 6, 0xF, 1, 7, 3, 0xF }; + const guint group_bandwidths[8] = { 10, 20, 15, 10, 2, 3, 35, 5 }; + const guint bandwidths[8] = { 10, 20, 30, 40, 50, 10, 0, 25 }; + const gboolean strict[8] = { TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE }; + const guint traffic_classes[8] = { 3, 4, 7, 2, 1, 0, 5, 6 }; + const gboolean pfcs[8] = { TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE }; + + connection = nm_connection_new (); + + s_con = (NMSettingConnection *) nm_setting_connection_new (); + nm_connection_add_setting (connection, NM_SETTING (s_con)); + uuid = nm_utils_uuid_generate (); + g_object_set (G_OBJECT (s_con), + NM_SETTING_CONNECTION_ID, "dcb-test", + NM_SETTING_CONNECTION_UUID, uuid, + NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_CONNECTION_INTERFACE_NAME, "eth0", + NULL); + g_free (uuid); + + /* Wired setting */ + s_wired = (NMSettingWired *) nm_setting_wired_new (); + nm_connection_add_setting (connection, NM_SETTING (s_wired)); + + /* IP stuff */ + s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new (); + g_object_set (G_OBJECT (s_ip4), NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL); + nm_connection_add_setting (connection, NM_SETTING (s_ip4)); + + s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new (); + g_object_set (G_OBJECT (s_ip6), NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NULL); + nm_connection_add_setting (connection, NM_SETTING (s_ip6)); + + /* DCB */ + s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); + nm_connection_add_setting (connection, NM_SETTING (s_dcb)); + + g_object_set (G_OBJECT (s_dcb), + NM_SETTING_DCB_APP_FCOE_FLAGS, DCB_ALL_FLAGS, + NM_SETTING_DCB_APP_FCOE_PRIORITY, 5, + NM_SETTING_DCB_APP_ISCSI_FLAGS, DCB_ALL_FLAGS, + NM_SETTING_DCB_APP_ISCSI_PRIORITY, 1, + NM_SETTING_DCB_APP_FIP_FLAGS, DCB_ALL_FLAGS, + NM_SETTING_DCB_APP_FIP_PRIORITY, 3, + NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS, DCB_ALL_FLAGS, + NM_SETTING_DCB_PRIORITY_GROUP_FLAGS, DCB_ALL_FLAGS, + NULL); + + for (i = 0; i < 8; i++) { + nm_setting_dcb_set_priority_flow_control (s_dcb, i, pfcs[i]); + nm_setting_dcb_set_priority_group_id (s_dcb, i, group_ids[i]); + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, i, group_bandwidths[i]); + nm_setting_dcb_set_priority_bandwidth (s_dcb, i, bandwidths[i]); + nm_setting_dcb_set_priority_strict_bandwidth (s_dcb, i, strict[i]); + nm_setting_dcb_set_priority_traffic_class (s_dcb, i, traffic_classes[i]); + } + + g_assert (nm_connection_verify (connection, &error)); + + /* Save the ifcfg */ + success = writer_new_connection (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile, + &error); + g_assert_no_error (error); + g_assert (success); + g_assert (testfile); + + /* re-read the connection for comparison */ + reread = connection_from_file (testfile, + NULL, + TYPE_ETHERNET, + NULL, NULL, NULL, + NULL, NULL, + &error, + &ignore_error); + unlink (testfile); + + g_assert_no_error (error); + g_assert (reread); + g_assert (nm_connection_verify (reread, &error)); + g_assert (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT)); + + g_object_unref (connection); + g_object_unref (reread); + g_free (testfile); +} + +static void +test_read_dcb_default_app_priorities (void) +{ + NMConnection *connection; + GError *error = NULL; + NMSettingDcb *s_dcb; + gboolean success; + + connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-default-app-priorities", + NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, NULL, &error, NULL); + g_assert_no_error (error); + g_assert (connection); + success = nm_connection_verify (connection, &error); + g_assert_no_error (error); + g_assert (success); + + s_dcb = nm_connection_get_setting_dcb (connection); + g_assert (s_dcb); + + g_assert_cmpint (nm_setting_dcb_get_app_fcoe_flags (s_dcb), ==, NM_SETTING_DCB_FLAG_ENABLE); + g_assert_cmpint (nm_setting_dcb_get_app_fcoe_priority (s_dcb), ==, -1); + + g_assert_cmpint (nm_setting_dcb_get_app_iscsi_flags (s_dcb), ==, NM_SETTING_DCB_FLAG_ENABLE); + g_assert_cmpint (nm_setting_dcb_get_app_iscsi_priority (s_dcb), ==, -1); + + g_assert_cmpint (nm_setting_dcb_get_app_fip_flags (s_dcb), ==, NM_SETTING_DCB_FLAG_ENABLE); + g_assert_cmpint (nm_setting_dcb_get_app_fip_priority (s_dcb), ==, -1); + + g_object_unref (connection); +} + +static void +test_read_dcb_bad_booleans (void) +{ + NMConnection *connection; + GError *error = NULL; + + connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-bad-booleans", + NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, NULL, &error, NULL); + g_assert_error (error, IFCFG_PLUGIN_ERROR, 0); + g_assert (strstr (error->message, "invalid boolean digit")); + g_assert (connection == NULL); +} + +static void +test_read_dcb_short_booleans (void) +{ + NMConnection *connection; + GError *error = NULL; + + connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-short-booleans", + NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, NULL, &error, NULL); + g_assert_error (error, IFCFG_PLUGIN_ERROR, 0); + g_assert (strstr (error->message, "boolean array must be 8 characters")); + g_assert (connection == NULL); +} + +static void +test_read_dcb_bad_uints (void) +{ + NMConnection *connection; + GError *error = NULL; + + connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-bad-uints", + NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, NULL, &error, NULL); + g_assert_error (error, IFCFG_PLUGIN_ERROR, 0); + g_assert (strstr (error->message, "invalid uint digit")); + g_assert (connection == NULL); +} + +static void +test_read_dcb_short_uints (void) +{ + NMConnection *connection; + GError *error = NULL; + + connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-short-uints", + NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, NULL, &error, NULL); + g_assert_error (error, IFCFG_PLUGIN_ERROR, 0); + g_assert (strstr (error->message, "uint array must be 8 characters")); + g_assert (connection == NULL); +} + +static void +test_read_dcb_bad_percent (void) +{ + NMConnection *connection; + GError *error = NULL; + + connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-bad-percent", + NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, NULL, &error, NULL); + g_assert_error (error, IFCFG_PLUGIN_ERROR, 0); + g_assert (strstr (error->message, "invalid percent element")); + g_assert (connection == NULL); +} + +static void +test_read_dcb_short_percent (void) +{ + NMConnection *connection; + GError *error = NULL; + + connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-short-percent", + NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, NULL, &error, NULL); + g_assert_error (error, IFCFG_PLUGIN_ERROR, 0); + g_assert (strstr (error->message, "percent array must be 8 elements")); + g_assert (connection == NULL); +} + +static void +test_read_dcb_pgpct_not_100 (void) +{ + NMConnection *connection; + GError *error = NULL; + + connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-pgpct-not-100", + NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, NULL, &error, NULL); + g_assert_error (error, IFCFG_PLUGIN_ERROR, 0); + g_assert (strstr (error->message, "invalid percentage sum")); + g_assert (connection == NULL); +} + +static void +test_read_fcoe_mode (gconstpointer user_data) +{ + const char *expected_mode = user_data; + NMConnection *connection; + GError *error = NULL; + NMSettingDcb *s_dcb; + gboolean success; + char *file; + + file = g_strdup_printf (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-fcoe-%s", expected_mode); + connection = connection_from_file (file, NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, NULL, &error, NULL); + g_free (file); + g_assert_no_error (error); + g_assert (connection); + success = nm_connection_verify (connection, &error); + g_assert_no_error (error); + g_assert (success); + + s_dcb = nm_connection_get_setting_dcb (connection); + g_assert (s_dcb); + + g_assert_cmpint (nm_setting_dcb_get_app_fcoe_flags (s_dcb), ==, NM_SETTING_DCB_FLAG_ENABLE); + g_assert_cmpstr (nm_setting_dcb_get_app_fcoe_mode (s_dcb), ==, expected_mode); + + g_object_unref (connection); +} + +static void +test_write_fcoe_mode (gconstpointer user_data) +{ + const char *expected_mode = user_data; + NMConnection *connection, *reread; + GError *error = NULL; + NMSettingConnection *s_con; + NMSettingWired *s_wired; + NMSettingDcb *s_dcb; + NMSettingIP4Config *s_ip4; + NMSettingIP6Config *s_ip6; + gboolean success, ignore_error; + char *uuid, *testfile; + + connection = nm_connection_new (); + + s_con = (NMSettingConnection *) nm_setting_connection_new (); + nm_connection_add_setting (connection, NM_SETTING (s_con)); + uuid = nm_utils_uuid_generate (); + g_object_set (G_OBJECT (s_con), + NM_SETTING_CONNECTION_ID, "fcoe-test", + NM_SETTING_CONNECTION_UUID, uuid, + NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_CONNECTION_INTERFACE_NAME, "eth0", + NULL); + g_free (uuid); + + /* Wired setting */ + s_wired = (NMSettingWired *) nm_setting_wired_new (); + nm_connection_add_setting (connection, NM_SETTING (s_wired)); + + /* IP stuff */ + s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new (); + g_object_set (G_OBJECT (s_ip4), NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL); + nm_connection_add_setting (connection, NM_SETTING (s_ip4)); + + s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new (); + g_object_set (G_OBJECT (s_ip6), NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NULL); + nm_connection_add_setting (connection, NM_SETTING (s_ip6)); + + /* DCB */ + s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); + nm_connection_add_setting (connection, NM_SETTING (s_dcb)); + + g_object_set (G_OBJECT (s_dcb), + NM_SETTING_DCB_APP_FCOE_FLAGS, NM_SETTING_DCB_FLAG_ENABLE, + NM_SETTING_DCB_APP_FCOE_MODE, expected_mode, + NULL); + + g_assert (nm_connection_verify (connection, &error)); + + /* Save the ifcfg */ + success = writer_new_connection (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile, + &error); + g_assert_no_error (error); + g_assert (success); + g_assert (testfile); + + { + shvarFile *ifcfg = svNewFile (testfile); + char *written_mode; + + g_assert (ifcfg); + written_mode = svGetValue (ifcfg, "DCB_APP_FCOE_MODE", FALSE); + svCloseFile (ifcfg); + g_assert_cmpstr (written_mode, ==, expected_mode); + g_free (written_mode); + } + + /* re-read the connection for comparison */ + reread = connection_from_file (testfile, + NULL, + TYPE_ETHERNET, + NULL, NULL, NULL, + NULL, NULL, + &error, + &ignore_error); + unlink (testfile); + + g_assert_no_error (error); + g_assert (reread); + g_assert (nm_connection_verify (reread, &error)); + g_assert (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT)); + + g_object_unref (connection); + g_object_unref (reread); + g_free (testfile); +} + #define TEST_IFCFG_WIFI_OPEN_SSID_BAD_HEX TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wifi-open-ssid-bad-hex" #define TEST_IFCFG_WIFI_OPEN_SSID_LONG_QUOTED TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wifi-open-ssid-long-quoted" #define TEST_IFCFG_WIFI_OPEN_SSID_LONG_HEX TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wifi-open-ssid-long-hex" @@ -12897,6 +13308,20 @@ int main (int argc, char **argv) test_read_ibft_malformed ("ibft-bad-gateway-read", TEST_IFCFG_DIR "/iscsiadm-test-bad-gateway"); test_read_ibft_malformed ("ibft-bad-dns1-read", TEST_IFCFG_DIR "/iscsiadm-test-bad-dns1"); test_read_ibft_malformed ("ibft-bad-dns2-read", TEST_IFCFG_DIR "/iscsiadm-test-bad-dns2"); + g_test_add_func (TPATH "dcb/read-basic", test_read_dcb_basic); + g_test_add_func (TPATH "dcb/write-basic", test_write_dcb_basic); + g_test_add_func (TPATH "dcb/default-app-priorities", test_read_dcb_default_app_priorities); + g_test_add_func (TPATH "dcb/bad-booleans", test_read_dcb_bad_booleans); + g_test_add_func (TPATH "dcb/short-booleans", test_read_dcb_short_booleans); + g_test_add_func (TPATH "dcb/bad-uints", test_read_dcb_bad_uints); + g_test_add_func (TPATH "dcb/short-uints", test_read_dcb_short_uints); + g_test_add_func (TPATH "dcb/bad-percent", test_read_dcb_bad_percent); + g_test_add_func (TPATH "dcb/short-percent", test_read_dcb_short_percent); + g_test_add_func (TPATH "dcb/pgpct-not-100", test_read_dcb_pgpct_not_100); + g_test_add_data_func (TPATH "fcoe/fabric", (gpointer) NM_SETTING_DCB_FCOE_MODE_FABRIC, test_read_fcoe_mode); + g_test_add_data_func (TPATH "fcoe/vn2vn", (gpointer) NM_SETTING_DCB_FCOE_MODE_VN2VN, test_read_fcoe_mode); + g_test_add_data_func (TPATH "fcoe/write-fabric", (gpointer) NM_SETTING_DCB_FCOE_MODE_FABRIC, test_write_fcoe_mode); + g_test_add_data_func (TPATH "fcoe/write-vn2vn", (gpointer) NM_SETTING_DCB_FCOE_MODE_VN2VN, test_write_fcoe_mode); /* bonding */ test_read_bond_main (); diff --git a/src/settings/plugins/ifcfg-rh/writer.c b/src/settings/plugins/ifcfg-rh/writer.c index 077f1be9d4..01304c0826 100644 --- a/src/settings/plugins/ifcfg-rh/writer.c +++ b/src/settings/plugins/ifcfg-rh/writer.c @@ -1470,6 +1470,165 @@ write_team_port_setting (NMConnection *connection, shvarFile *ifcfg, GError **er return TRUE; } +static void +write_dcb_flags (shvarFile *ifcfg, const char *tag, NMSettingDcbFlags flags) +{ + char *prop; + + prop = g_strdup_printf ("DCB_%s_ENABLE", tag); + svSetValue (ifcfg, prop, (flags & NM_SETTING_DCB_FLAG_ENABLE) ? "yes" : NULL, FALSE); + g_free (prop); + + prop = g_strdup_printf ("DCB_%s_ADVERTISE", tag); + svSetValue (ifcfg, prop, (flags & NM_SETTING_DCB_FLAG_ADVERTISE) ? "yes" : NULL, FALSE); + g_free (prop); + + prop = g_strdup_printf ("DCB_%s_WILLING", tag); + svSetValue (ifcfg, prop, (flags & NM_SETTING_DCB_FLAG_WILLING) ? "yes" : NULL, FALSE); + g_free (prop); +} + +static void +write_dcb_app (shvarFile *ifcfg, + const char *tag, + NMSettingDcbFlags flags, + gint priority) +{ + char *prop, *tmp = NULL; + + write_dcb_flags (ifcfg, tag, flags); + + if ((flags & NM_SETTING_DCB_FLAG_ENABLE) && (priority >= 0)) + tmp = g_strdup_printf ("%d", priority); + prop = g_strdup_printf ("DCB_%s_PRIORITY", tag); + svSetValue (ifcfg, prop, tmp, FALSE); + g_free (prop); + g_free (tmp); +} + +typedef gboolean (*DcbGetBoolFunc) (NMSettingDcb *, guint); + +static void +write_dcb_bool_array (shvarFile *ifcfg, + const char *key, + NMSettingDcb *s_dcb, + NMSettingDcbFlags flags, + DcbGetBoolFunc get_func) +{ + char str[9]; + guint i; + + if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) { + svSetValue (ifcfg, key, NULL, FALSE); + return; + } + + str[8] = 0; + for (i = 0; i < 8; i++) + str[i] = get_func (s_dcb, i) ? '1' : '0'; + svSetValue (ifcfg, key, str, FALSE); +} + +typedef guint (*DcbGetUintFunc) (NMSettingDcb *, guint); + +static void +write_dcb_uint_array (shvarFile *ifcfg, + const char *key, + NMSettingDcb *s_dcb, + NMSettingDcbFlags flags, + DcbGetUintFunc get_func) +{ + char str[9]; + guint i, num; + + if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) { + svSetValue (ifcfg, key, NULL, FALSE); + return; + } + + str[8] = 0; + for (i = 0; i < 8; i++) { + num = get_func (s_dcb, i); + if (num < 10) + str[i] = '0' + num; + else if (num == 15) + str[i] = 'f'; + else + g_assert_not_reached (); + } + svSetValue (ifcfg, key, str, FALSE); +} + +static void +write_dcb_percent_array (shvarFile *ifcfg, + const char *key, + NMSettingDcb *s_dcb, + NMSettingDcbFlags flags, + DcbGetUintFunc get_func) +{ + GString *str; + guint i; + + if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) { + svSetValue (ifcfg, key, NULL, FALSE); + return; + } + + str = g_string_sized_new (30); + for (i = 0; i < 8; i++) { + if (str->len) + g_string_append_c (str, ','); + g_string_append_printf (str, "%d", get_func (s_dcb, i)); + } + svSetValue (ifcfg, key, str->str, FALSE); + g_string_free (str, TRUE); +} + +static gboolean +write_dcb_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) +{ + NMSettingDcb *s_dcb; + NMSettingDcbFlags flags; + + s_dcb = nm_connection_get_setting_dcb (connection); + if (!s_dcb) { + svSetValue (ifcfg, "DCB", NULL, FALSE); + return TRUE; + } + + svSetValue (ifcfg, "DCB", "yes", FALSE); + + write_dcb_app (ifcfg, "APP_FCOE", + nm_setting_dcb_get_app_fcoe_flags (s_dcb), + nm_setting_dcb_get_app_fcoe_priority (s_dcb)); + if (nm_setting_dcb_get_app_fcoe_flags (s_dcb) & NM_SETTING_DCB_FLAG_ENABLE) + svSetValue (ifcfg, "DCB_APP_FCOE_MODE", nm_setting_dcb_get_app_fcoe_mode (s_dcb), FALSE); + else + svSetValue (ifcfg, "DCB_APP_FCOE_MODE", NULL, FALSE); + + write_dcb_app (ifcfg, "APP_ISCSI", + nm_setting_dcb_get_app_iscsi_flags (s_dcb), + nm_setting_dcb_get_app_iscsi_priority (s_dcb)); + write_dcb_app (ifcfg, "APP_FIP", + nm_setting_dcb_get_app_fip_flags (s_dcb), + nm_setting_dcb_get_app_fip_priority (s_dcb)); + + write_dcb_flags (ifcfg, "PFC", nm_setting_dcb_get_priority_flow_control_flags (s_dcb)); + write_dcb_bool_array (ifcfg, "DCB_PFC_UP", s_dcb, + nm_setting_dcb_get_priority_flow_control_flags (s_dcb), + nm_setting_dcb_get_priority_flow_control); + + flags = nm_setting_dcb_get_priority_group_flags (s_dcb); + write_dcb_flags (ifcfg, "PG", flags); + write_dcb_uint_array (ifcfg, "DCB_PG_ID", s_dcb, flags, nm_setting_dcb_get_priority_group_id); + write_dcb_percent_array (ifcfg, "DCB_PG_PCT", s_dcb, flags, nm_setting_dcb_get_priority_group_bandwidth); + write_dcb_percent_array (ifcfg, "DCB_PG_UPPCT", s_dcb, flags, nm_setting_dcb_get_priority_bandwidth); + write_dcb_bool_array (ifcfg, "DCB_PG_STRICT", s_dcb, flags, nm_setting_dcb_get_priority_strict_bandwidth); + write_dcb_uint_array (ifcfg, "DCB_PG_UP2TC", s_dcb, flags, nm_setting_dcb_get_priority_traffic_class); + + return TRUE; +} + static void write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) { @@ -2275,6 +2434,9 @@ write_connection (NMConnection *connection, if (!write_team_port_setting (connection, ifcfg, error)) goto out; + if (!write_dcb_setting (connection, ifcfg, error)) + goto out; + if (!utils_ignore_ip_config (connection)) { svSetValue (ifcfg, "DHCP_HOSTNAME", NULL, FALSE); diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index 3e485fdc3d..9d17e9ad1a 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -15,7 +15,8 @@ noinst_PROGRAMS = \ test-policy-hosts \ test-wifi-ap-utils \ test-ip4-config \ - test-ip6-config + test-ip6-config \ + test-dcb ####### DHCP options test ####### @@ -62,6 +63,14 @@ test_ip6_config_SOURCES = \ test_ip6_config_LDADD = \ $(top_builddir)/src/libNetworkManager.la +####### DCB test ####### + +test_dcb_SOURCES = \ + test-dcb.c + +test_dcb_LDADD = \ + $(top_builddir)/src/libNetworkManager.la + ####### secret agent interface test ####### EXTRA_DIST = test-secret-agent.py @@ -74,4 +83,5 @@ check-local: test-dhcp-options test-policy-hosts test-wifi-ap-utils test-ip4-con $(abs_builddir)/test-wifi-ap-utils $(abs_builddir)/test-ip4-config $(abs_builddir)/test-ip6-config + $(abs_builddir)/test-dcb diff --git a/src/tests/test-dcb.c b/src/tests/test-dcb.c new file mode 100644 index 0000000000..0a0924423e --- /dev/null +++ b/src/tests/test-dcb.c @@ -0,0 +1,348 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2013 Red Hat, Inc. + * + */ + +#include +#include + +#include "nm-dcb.h" + +typedef struct { + guint num; + const char *cmds[]; +} DcbExpected; + +static gboolean +test_dcb_func (char **argv, guint which, gpointer user_data, GError **error) +{ + DcbExpected *e = user_data; + char *f; + + g_assert (argv[0] == NULL); + argv[0] = (which == DCBTOOL) ? "dcbtool" : "fcoeadm"; + + f = g_strjoinv (" ", argv); + if (e->cmds[e->num] == NULL) + g_assert_cmpstr (f, ==, NULL); + g_assert_cmpstr (e->cmds[e->num], !=, NULL); + g_assert_cmpstr (f, ==, e->cmds[e->num++]); + g_free (f); + return TRUE; +} + +#define DCB_FLAGS_ALL (NM_SETTING_DCB_FLAG_ENABLE | \ + NM_SETTING_DCB_FLAG_ADVERTISE | \ + NM_SETTING_DCB_FLAG_WILLING) + +static void +test_dcb_fcoe (void) +{ + static DcbExpected expected = { 0, + { "dcbtool sc eth0 dcb on", + "dcbtool sc eth0 app:fcoe e:1 a:1 w:1", + "dcbtool sc eth0 app:fcoe appcfg:40", + "dcbtool sc eth0 app:iscsi e:0 a:0 w:0", + "dcbtool sc eth0 app:fip e:0 a:0 w:0", + "dcbtool sc eth0 pfc e:0 a:0 w:0", + "dcbtool sc eth0 pg e:0 a:0 w:0", + NULL }, + }; + NMSettingDcb *s_dcb; + GError *error = NULL; + gboolean success; + + s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); + g_object_set (G_OBJECT (s_dcb), + NM_SETTING_DCB_APP_FCOE_FLAGS, DCB_FLAGS_ALL, + NM_SETTING_DCB_APP_FCOE_PRIORITY, 6, + NULL); + + success = _dcb_setup ("eth0", s_dcb, test_dcb_func, &expected, &error); + g_assert_no_error (error); + g_assert (success); + + g_assert_cmpstr (expected.cmds[expected.num], ==, NULL); + g_object_unref (s_dcb); +} + +static void +test_dcb_iscsi (void) +{ + static DcbExpected expected = { 0, + { "dcbtool sc eth0 dcb on", + "dcbtool sc eth0 app:fcoe e:0 a:0 w:0", + "dcbtool sc eth0 app:iscsi e:1 a:0 w:1", + "dcbtool sc eth0 app:iscsi appcfg:08", + "dcbtool sc eth0 app:fip e:0 a:0 w:0", + "dcbtool sc eth0 pfc e:0 a:0 w:0", + "dcbtool sc eth0 pg e:0 a:0 w:0", + NULL }, + }; + NMSettingDcb *s_dcb; + GError *error = NULL; + gboolean success; + + s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); + g_object_set (G_OBJECT (s_dcb), + NM_SETTING_DCB_APP_ISCSI_FLAGS, (NM_SETTING_DCB_FLAG_ENABLE | NM_SETTING_DCB_FLAG_WILLING), + NM_SETTING_DCB_APP_ISCSI_PRIORITY, 3, + NULL); + + success = _dcb_setup ("eth0", s_dcb, test_dcb_func, &expected, &error); + g_assert_no_error (error); + g_assert (success); + + g_assert_cmpstr (expected.cmds[expected.num], ==, NULL); + g_object_unref (s_dcb); +} + +static void +test_dcb_fip (void) +{ + static DcbExpected expected = { 0, + { "dcbtool sc eth0 dcb on", + "dcbtool sc eth0 app:fcoe e:0 a:0 w:0", + "dcbtool sc eth0 app:iscsi e:0 a:0 w:0", + "dcbtool sc eth0 app:fip e:1 a:1 w:0", + "dcbtool sc eth0 app:fip appcfg:01", + "dcbtool sc eth0 pfc e:0 a:0 w:0", + "dcbtool sc eth0 pg e:0 a:0 w:0", + NULL }, + }; + NMSettingDcb *s_dcb; + GError *error = NULL; + gboolean success; + + s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); + g_object_set (G_OBJECT (s_dcb), + NM_SETTING_DCB_APP_FIP_FLAGS, (NM_SETTING_DCB_FLAG_ENABLE | NM_SETTING_DCB_FLAG_ADVERTISE), + NM_SETTING_DCB_APP_FIP_PRIORITY, 0, + NULL); + + success = _dcb_setup ("eth0", s_dcb, test_dcb_func, &expected, &error); + g_assert_no_error (error); + g_assert (success); + + g_assert_cmpstr (expected.cmds[expected.num], ==, NULL); + g_object_unref (s_dcb); +} + +static void +test_dcb_fip_default_prio (void) +{ + static DcbExpected expected = { 0, + { "dcbtool sc eth0 dcb on", + "dcbtool sc eth0 app:fcoe e:0 a:0 w:0", + "dcbtool sc eth0 app:iscsi e:0 a:0 w:0", + "dcbtool sc eth0 app:fip e:1 a:1 w:0", + "dcbtool sc eth0 pfc e:0 a:0 w:0", + "dcbtool sc eth0 pg e:0 a:0 w:0", + NULL }, + }; + NMSettingDcb *s_dcb; + GError *error = NULL; + gboolean success; + + s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); + g_object_set (G_OBJECT (s_dcb), + NM_SETTING_DCB_APP_FIP_FLAGS, (NM_SETTING_DCB_FLAG_ENABLE | NM_SETTING_DCB_FLAG_ADVERTISE), + NM_SETTING_DCB_APP_FIP_PRIORITY, -1, + NULL); + + success = _dcb_setup ("eth0", s_dcb, test_dcb_func, &expected, &error); + g_assert_no_error (error); + g_assert (success); + + g_assert_cmpstr (expected.cmds[expected.num], ==, NULL); + g_object_unref (s_dcb); +} + +static void +test_dcb_pfc (void) +{ + static DcbExpected expected = { 0, + { "dcbtool sc eth0 dcb on", + "dcbtool sc eth0 app:fcoe e:0 a:0 w:0", + "dcbtool sc eth0 app:iscsi e:0 a:0 w:0", + "dcbtool sc eth0 app:fip e:0 a:0 w:0", + "dcbtool sc eth0 pfc e:1 a:1 w:1", + "dcbtool sc eth0 pfc pfcup:01101100", + "dcbtool sc eth0 pg e:0 a:0 w:0", + NULL }, + }; + NMSettingDcb *s_dcb; + GError *error = NULL; + gboolean success; + + s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); + g_object_set (G_OBJECT (s_dcb), + NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS, DCB_FLAGS_ALL, + NULL); + + nm_setting_dcb_set_priority_flow_control (s_dcb, 0, FALSE); + nm_setting_dcb_set_priority_flow_control (s_dcb, 1, TRUE); + nm_setting_dcb_set_priority_flow_control (s_dcb, 2, TRUE); + nm_setting_dcb_set_priority_flow_control (s_dcb, 3, FALSE); + nm_setting_dcb_set_priority_flow_control (s_dcb, 4, TRUE); + nm_setting_dcb_set_priority_flow_control (s_dcb, 5, TRUE); + nm_setting_dcb_set_priority_flow_control (s_dcb, 6, FALSE); + nm_setting_dcb_set_priority_flow_control (s_dcb, 7, FALSE); + + success = _dcb_setup ("eth0", s_dcb, test_dcb_func, &expected, &error); + g_assert_no_error (error); + g_assert (success); + + g_assert_cmpstr (expected.cmds[expected.num], ==, NULL); + g_object_unref (s_dcb); +} + +static void +test_dcb_priority_groups (void) +{ + static DcbExpected expected = { 0, + { "dcbtool sc eth0 dcb on", + "dcbtool sc eth0 app:fcoe e:0 a:0 w:0", + "dcbtool sc eth0 app:iscsi e:0 a:0 w:0", + "dcbtool sc eth0 app:fip e:0 a:0 w:0", + "dcbtool sc eth0 pfc e:0 a:0 w:0", + "dcbtool sc eth0 pg e:1 a:1 w:1", + "dcbtool sc eth0 pg pgid:765f3210", + "dcbtool sc eth0 pg pgpct:10,40,5,10,5,20,7,3", + "dcbtool sc eth0 pg uppct:100,50,33,25,20,16,14,12", + "dcbtool sc eth0 pg strict:01010101", + "dcbtool sc eth0 pg up2tc:01201201", + NULL }, + }; + NMSettingDcb *s_dcb; + GError *error = NULL; + gboolean success; + guint i; + + s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); + g_object_set (G_OBJECT (s_dcb), + NM_SETTING_DCB_PRIORITY_GROUP_FLAGS, DCB_FLAGS_ALL, + NULL); + + for (i = 0; i < 8; i++) { + /* Make sure at least one 15/f is present in the group IDs */ + nm_setting_dcb_set_priority_group_id (s_dcb, i, (i == 3) ? 15 : 7 - i); + nm_setting_dcb_set_priority_bandwidth (s_dcb, i, 100 / (i + 1)); + nm_setting_dcb_set_priority_strict_bandwidth (s_dcb, i, i % 2); + nm_setting_dcb_set_priority_traffic_class (s_dcb, i, i % 3); + } + + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 0, 10); + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 1, 40); + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 2, 5); + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 3, 10); + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 4, 5); + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 5, 20); + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 6, 7); + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, 7, 3); + + success = _dcb_setup ("eth0", s_dcb, test_dcb_func, &expected, &error); + g_assert_no_error (error); + g_assert (success); + + g_assert_cmpstr (expected.cmds[expected.num], ==, NULL); + g_object_unref (s_dcb); +} + +static void +test_dcb_cleanup (void) +{ + static DcbExpected expected = { 0, + { "dcbtool sc eth0 dcb off", NULL }, + }; + GError *error = NULL; + gboolean success; + + success = _dcb_cleanup ("eth0", test_dcb_func, &expected, &error); + g_assert_no_error (error); + g_assert (success); +} + +static void +test_fcoe_create (void) +{ + static DcbExpected expected1 = { 0, + { "fcoeadm -m fabric -c eth0", NULL }, + }; + static DcbExpected expected2 = { 0, + { "fcoeadm -m vn2vn -c eth0", NULL }, + }; + GError *error = NULL; + gboolean success; + NMSettingDcb *s_dcb; + + s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); + g_object_set (G_OBJECT (s_dcb), + NM_SETTING_DCB_APP_FCOE_FLAGS, DCB_FLAGS_ALL, + NULL); + + /* Default mode is fabric */ + success = _fcoe_setup ("eth0", s_dcb, test_dcb_func, &expected1, &error); + g_assert_no_error (error); + g_assert (success); + + /* Test VN2VN */ + g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_APP_FCOE_MODE, NM_SETTING_DCB_FCOE_MODE_VN2VN, NULL); + success = _fcoe_setup ("eth0", s_dcb, test_dcb_func, &expected2, &error); + g_assert_no_error (error); + g_assert (success); + + g_object_unref (s_dcb); +} + +static void +test_fcoe_cleanup (void) +{ + static DcbExpected expected = { 0, + { "fcoeadm -d eth0", NULL }, + }; + GError *error = NULL; + gboolean success; + + success = _fcoe_cleanup ("eth0", test_dcb_func, &expected, &error); + g_assert_no_error (error); + g_assert (success); +} + +/*******************************************/ + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + g_type_init (); + + g_test_add_func ("/dcb/fcoe", test_dcb_fcoe); + g_test_add_func ("/dcb/iscsi", test_dcb_iscsi); + g_test_add_func ("/dcb/fip", test_dcb_fip); + g_test_add_func ("/dcb/fip-default-priority", test_dcb_fip_default_prio); + g_test_add_func ("/dcb/pfc", test_dcb_pfc); + g_test_add_func ("/dcb/priority-groups", test_dcb_priority_groups); + g_test_add_func ("/dcb/cleanup", test_dcb_cleanup); + g_test_add_func ("/fcoe/create", test_fcoe_create); + g_test_add_func ("/fcoe/cleanup", test_fcoe_cleanup); + + return g_test_run (); +} +