ifcfg-rh: add DCB setting reader and writer

See 'ifcfg-test-dcb' for details on all supported options.
This commit is contained in:
Dan Williams 2013-09-26 16:21:37 -05:00
parent 77e50740a8
commit a3bd6df05f
15 changed files with 1147 additions and 3 deletions

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