summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2013-10-03 23:42:26 -0500
committerDan Williams <dcbw@redhat.com>2013-10-26 11:46:29 -0500
commitbff2caea7fdb29a0ed6052bc9bbdbe02d3b596c6 (patch)
tree489fe4411c697a552d85902b6d4aedfd9dc3aaa8
parenta9387ac87ddc82599f526d8685d4781acfebd54d (diff)
downloadNetworkManager-bff2caea7fdb29a0ed6052bc9bbdbe02d3b596c6.tar.gz
core: add dcbtool manipulation logic
-rw-r--r--src/Makefile.am2
-rw-r--r--src/nm-dcb.c339
-rw-r--r--src/nm-dcb.h93
-rw-r--r--src/tests/Makefile.am12
-rw-r--r--src/tests/test-dcb.c348
5 files changed, 793 insertions, 1 deletions
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/nm-dcb.c b/src/nm-dcb.c
new file mode 100644
index 0000000000..50dd8b18d1
--- /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 <config.h>
+#include <sys/wait.h>
+#include <string.h>
+
+#include <glib.h>
+#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, 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 <glib.h>
+#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/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 <glib.h>
+#include <string.h>
+
+#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 ();
+}
+