diff options
author | Dan Williams <dcbw@redhat.com> | 2013-10-03 23:42:26 -0500 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2013-10-26 11:46:29 -0500 |
commit | bff2caea7fdb29a0ed6052bc9bbdbe02d3b596c6 (patch) | |
tree | 489fe4411c697a552d85902b6d4aedfd9dc3aaa8 | |
parent | a9387ac87ddc82599f526d8685d4781acfebd54d (diff) | |
download | NetworkManager-bff2caea7fdb29a0ed6052bc9bbdbe02d3b596c6.tar.gz |
core: add dcbtool manipulation logic
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/nm-dcb.c | 339 | ||||
-rw-r--r-- | src/nm-dcb.h | 93 | ||||
-rw-r--r-- | src/tests/Makefile.am | 12 | ||||
-rw-r--r-- | src/tests/test-dcb.c | 348 |
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 (); +} + |