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 ();
+}
+