dcb: merge DCB/FCoE core functionality (bgo #710422) (rh #799241)

Add DCB setting and associated logic to propagate those settings to
dcbtool.  At the moment we don't use dcbnl to talk directly to the
kernel, because some devices do parts of DCB/LLDP in userland and
thus need lldpad running, which dcbtool talks to.
This commit is contained in:
Dan Williams 2013-10-31 13:39:03 -05:00
commit df406d06b6
37 changed files with 3799 additions and 8 deletions

2
.gitignore vendored
View file

@ -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

View file

@ -62,6 +62,7 @@
<xi:include href="xml/nm-setting-vlan.xml"/>
<xi:include href="xml/nm-setting-olpc-mesh.xml"/>
<xi:include href="xml/nm-setting-adsl.xml"/>
<xi:include href="xml/nm-setting-dcb.xml"/>
<xi:include href="xml/nm-setting-8021x.xml"/>
<xi:include href="xml/nm-setting-ip4-config.xml"/>
<xi:include href="xml/nm-setting-ip6-config.xml"/>

View file

@ -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;

View file

@ -579,6 +579,11 @@
A secondary connection of the base connection failed.
</tp:docstring>
</tp:enumvalue>
<tp:enumvalue suffix="DCB_FCOE_FAILED" value="55">
<tp:docstring>
DCB or FCoE setup failed.
</tp:docstring>
</tp:enumvalue>
</tp:enum>
<tp:struct name="NM_DEVICE_STATE_REASON_STRUCT">

View file

@ -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 \

View file

@ -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;

View file

@ -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

View file

@ -39,6 +39,7 @@
#include <nm-setting-bridge-port.h>
#include <nm-setting-cdma.h>
#include <nm-setting-connection.h>
#include <nm-setting-dcb.h>
#include <nm-setting-generic.h>
#include <nm-setting-gsm.h>
#include <nm-setting-infiniband.h>
@ -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);

1258
libnm-util/nm-setting-dcb.c Normal file

File diff suppressed because it is too large Load diff

187
libnm-util/nm-setting-dcb.h Normal file
View file

@ -0,0 +1,187 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
* Dan Williams <dcbw@redhat.com>
*
* 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 <nm-setting.h>
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 */

View file

@ -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"

View file

@ -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 <glib.h>
#include <string.h>
#include <nm-utils.h>
#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 ();
}

View file

@ -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.</para>
INFINIBAND, FIREWALL, ADSL, BOND, VLAN, BRIDGE, DBUS_PROPS,
TEAM, CONCHECK, DCB.</para>
<para>In addition, these special domains can be used: NONE,
ALL, DEFAULT, DHCP, IP.</para></listitem>
</varlistentry>

View file

@ -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

View file

@ -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 \

View file

@ -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);
}

View file

@ -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 }
};

View file

@ -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)

339
src/nm-dcb.c Normal file
View file

@ -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, 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);
}

93
src/nm-dcb.h Normal file
View file

@ -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 */

View file

@ -48,6 +48,7 @@
#include <nm-setting-team-port.h>
#include <nm-setting-bridge.h>
#include <nm-setting-bridge-port.h>
#include <nm-setting-dcb.h>
#include <nm-utils.h>
#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.
*/

View file

@ -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 \

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,6 @@
TYPE=Ethernet
DEVICE=eth0
DCB=yes
DCB_APP_FCOE_ENABLE=yes
DCB_APP_FCOE_MODE=fabric

View file

@ -0,0 +1,6 @@
TYPE=Ethernet
DEVICE=eth0
DCB=yes
DCB_APP_FCOE_ENABLE=yes
DCB_APP_FCOE_MODE=vn2vn

View file

@ -45,6 +45,7 @@
#include <nm-setting-cdma.h>
#include <nm-setting-serial.h>
#include <nm-setting-vlan.h>
#include <nm-setting-dcb.h>
#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 ();

View file

@ -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);

View file

@ -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

348
src/tests/test-dcb.c Normal file
View file

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