diff --git a/src/settings/plugins/ifcfg-rh/reader.c b/src/settings/plugins/ifcfg-rh/reader.c index de53e401c9..ddcb1e0b2e 100644 --- a/src/settings/plugins/ifcfg-rh/reader.c +++ b/src/settings/plugins/ifcfg-rh/reader.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include "wifi-utils.h" @@ -74,7 +75,7 @@ get_int (const char *str, int *value) errno = 0; tmp = strtol (str, &e, 0); - if (errno || *e != '\0') + if (errno || *e != '\0' || tmp > G_MAXINT || tmp < G_MININT) return FALSE; *value = (int) tmp; return TRUE; @@ -1772,6 +1773,397 @@ check_if_team_slave (shvarFile *ifcfg, g_free (value); } +typedef struct { + const char *enable_key; + const char *advertise_key; + const char *willing_key; + const char *flags_prop; +} DcbFlagsProperty; + +enum { + DCB_APP_FCOE_FLAGS = 0, + DCB_APP_ISCSI_FLAGS = 1, + DCB_APP_FIP_FLAGS = 2, + DCB_PFC_FLAGS = 3, + DCB_PG_FLAGS = 4, +}; + +static DcbFlagsProperty dcb_flags_props[] = { + { "DCB_APP_FCOE_ENABLE", "DCB_APP_FCOE_ADVERTISE", "DCB_APP_FCOE_WILLING", NM_SETTING_DCB_APP_FCOE_FLAGS }, + { "DCB_APP_ISCSI_ENABLE", "DCB_APP_ISCSI_ADVERTISE", "DCB_APP_ISCSI_WILLING", NM_SETTING_DCB_APP_ISCSI_FLAGS }, + { "DCB_APP_FIP_ENABLE", "DCB_APP_FIP_ADVERTISE", "DCB_APP_FIP_WILLING", NM_SETTING_DCB_APP_FIP_FLAGS }, + { "DCB_PFC_ENABLE", "DCB_PFC_ADVERTISE", "DCB_PFC_WILLING", NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS }, + { "DCB_PG_ENABLE", "DCB_PG_ADVERTISE", "DCB_PG_WILLING", NM_SETTING_DCB_PRIORITY_GROUP_FLAGS }, + { NULL }, +}; + +static NMSettingDcbFlags +read_dcb_flags (shvarFile *ifcfg, DcbFlagsProperty *property) +{ + NMSettingDcbFlags flags = NM_SETTING_DCB_FLAG_NONE; + + if (svTrueValue (ifcfg, property->enable_key, FALSE)) + flags |= NM_SETTING_DCB_FLAG_ENABLE; + if (svTrueValue (ifcfg, property->advertise_key, FALSE)) + flags |= NM_SETTING_DCB_FLAG_ADVERTISE; + if (svTrueValue (ifcfg, property->willing_key, FALSE)) + flags |= NM_SETTING_DCB_FLAG_WILLING; + + return flags; +} + +static gboolean +read_dcb_app (shvarFile *ifcfg, + NMSettingDcb *s_dcb, + const char *app, + DcbFlagsProperty *flags_prop, + const char *priority_prop, + GError **error) +{ + NMSettingDcbFlags flags = NM_SETTING_DCB_FLAG_NONE; + char *tmp, *val; + gboolean success = TRUE; + int priority = -1; + + flags = read_dcb_flags (ifcfg, flags_prop); + + /* Priority */ + tmp = g_strdup_printf ("DCB_APP_%s_PRIORITY", app); + val = svGetValue (ifcfg, tmp, FALSE); + if (val) { + success = get_int (val, &priority); + if (success) + success = (priority >= 0 && priority <= 7); + if (!success) { + g_set_error (error, IFCFG_PLUGIN_ERROR, 0, + "Invalid %s value '%s' (expected 0 - 7)", + tmp, val); + } + g_free (val); + + if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: ignoring DCB %s priority; app not enabled", app); + } + g_free (tmp); + + if (success) { + g_object_set (G_OBJECT (s_dcb), + flags_prop->flags_prop, flags, + priority_prop, (guint) priority, + NULL); + } + + return success; +} + +typedef void (*DcbSetBoolFunc) (NMSettingDcb *, guint, gboolean); + +static gboolean +read_dcb_bool_array (shvarFile *ifcfg, + NMSettingDcb *s_dcb, + NMSettingDcbFlags flags, + const char *prop, + const char *desc, + DcbSetBoolFunc set_func, + GError **error) +{ + char *val; + gboolean success = FALSE; + guint i; + + val = svGetValue (ifcfg, prop, FALSE); + if (!val) + return TRUE; + + if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: ignoring %s; %s is not enabled", prop, desc); + success = TRUE; + goto out; + } + + val = g_strstrip (val); + if (strlen (val) != 8) { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " error: %s value '%s' must be 8 characters long", prop, val); + g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0, "boolean array must be 8 characters"); + goto out; + } + + /* All characters must be either 0 or 1 */ + for (i = 0; i < 8; i++) { + if (val[i] != '0' && val[i] != '1') { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " error: invalid %s value '%s': not all 0s and 1s", prop, val); + g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0, "invalid boolean digit"); + goto out; + } + set_func (s_dcb, i, (val[i] == '1')); + } + success = TRUE; + +out: + g_free (val); + return success; +} + +typedef void (*DcbSetUintFunc) (NMSettingDcb *, guint, guint); + +static gboolean +read_dcb_uint_array (shvarFile *ifcfg, + NMSettingDcb *s_dcb, + NMSettingDcbFlags flags, + const char *prop, + const char *desc, + gboolean f_allowed, + DcbSetUintFunc set_func, + GError **error) +{ + char *val; + gboolean success = FALSE; + guint i; + + val = svGetValue (ifcfg, prop, FALSE); + if (!val) + return TRUE; + + if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: ignoring %s; %s is not enabled", prop, desc); + success = TRUE; + goto out; + } + + val = g_strstrip (val); + if (strlen (val) != 8) { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " error: %s value '%s' must be 8 characters long", prop, val); + g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0, "uint array must be 8 characters"); + goto out; + } + + /* All characters must be either 0 - 7 or (optionally) f */ + for (i = 0; i < 8; i++) { + if (val[i] >= '0' && val[i] <= '7') + set_func (s_dcb, i, val[i] - '0'); + else if (f_allowed && (val[i] == 'f' || val[i] == 'F')) + set_func (s_dcb, i, 15); + else { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " error: invalid %s value '%s': not 0 - 7%s", + prop, val, f_allowed ? " or 'f'" : ""); + g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0, "invalid uint digit"); + goto out; + } + } + success = TRUE; + +out: + g_free (val); + return success; +} + +static gboolean +read_dcb_percent_array (shvarFile *ifcfg, + NMSettingDcb *s_dcb, + NMSettingDcbFlags flags, + const char *prop, + const char *desc, + gboolean sum_pct, + DcbSetUintFunc set_func, + GError **error) +{ + char *val; + gboolean success = FALSE; + char **split = NULL, **iter; + int tmp; + guint i, sum = 0; + + val = svGetValue (ifcfg, prop, FALSE); + if (!val) + return TRUE; + + if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: ignoring %s; %s is not enabled", prop, desc); + success = TRUE; + goto out; + } + + val = g_strstrip (val); + split = g_strsplit_set (val, ",", 0); + if (!split || (g_strv_length (split) != 8)) { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " error: invalid %s percentage list value '%s'", prop, val); + g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0, "percent array must be 8 elements"); + goto out; + } + + for (iter = split, i = 0; iter && *iter; iter++, i++) { + if (!get_int (*iter, &tmp) || tmp < 0 || tmp > 100) { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " error: invalid %s percentage value '%s'", prop, *iter); + g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0, "invalid percent element"); + goto out; + } + set_func (s_dcb, i, (guint) tmp); + sum += (guint) tmp; + } + + if (sum_pct && (sum != 100)) { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " error: %s percentages do not equal 100%%", prop); + g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0, "invalid percentage sum"); + goto out; + } + + success = TRUE; + +out: + if (split) + g_strfreev (split); + g_free (val); + return success; +} + +static gboolean +make_dcb_setting (shvarFile *ifcfg, + const char *network_file, + NMSetting **out_setting, + GError **error) +{ + NMSettingDcb *s_dcb = NULL; + gboolean dcb_on; + NMSettingDcbFlags flags = NM_SETTING_DCB_FLAG_NONE; + char *val; + + g_return_val_if_fail (out_setting != NULL, FALSE); + + dcb_on = !!svTrueValue (ifcfg, "DCB", FALSE); + if (!dcb_on) + return TRUE; + + s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); + g_assert (s_dcb); + + /* FCOE */ + if (!read_dcb_app (ifcfg, s_dcb, "FCOE", + &dcb_flags_props[DCB_APP_FCOE_FLAGS], + NM_SETTING_DCB_APP_FCOE_PRIORITY, + error)) { + g_object_unref (s_dcb); + return FALSE; + } + if (nm_setting_dcb_get_app_fcoe_flags (s_dcb) & NM_SETTING_DCB_FLAG_ENABLE) { + val = svGetValue (ifcfg, "DCB_APP_FCOE_MODE", FALSE); + if (val) { + if (strcmp (val, NM_SETTING_DCB_FCOE_MODE_FABRIC) == 0 || + strcmp (val, NM_SETTING_DCB_FCOE_MODE_VN2VN) == 0) + g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_APP_FCOE_MODE, val, NULL); + else { + PLUGIN_WARN (IFCFG_PLUGIN_NAME, " error: invalid FCoE mode '%s'", val); + g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0, "invalid FCoE mode"); + g_free (val); + g_object_unref (s_dcb); + return FALSE; + } + g_free (val); + } + } + + /* iSCSI */ + if (!read_dcb_app (ifcfg, s_dcb, "ISCSI", + &dcb_flags_props[DCB_APP_ISCSI_FLAGS], + NM_SETTING_DCB_APP_ISCSI_PRIORITY, + error)) { + g_object_unref (s_dcb); + return FALSE; + } + + /* FIP */ + if (!read_dcb_app (ifcfg, s_dcb, "FIP", + &dcb_flags_props[DCB_APP_FIP_FLAGS], + NM_SETTING_DCB_APP_FIP_PRIORITY, + error)) { + g_object_unref (s_dcb); + return FALSE; + } + + /* Priority Flow Control */ + flags = read_dcb_flags (ifcfg, &dcb_flags_props[DCB_PFC_FLAGS]); + g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS, flags, NULL); + + if (!read_dcb_bool_array (ifcfg, + s_dcb, + flags, + "DCB_PFC_UP", + "PFC", + nm_setting_dcb_set_priority_flow_control, + error)) { + g_object_unref (s_dcb); + return FALSE; + } + + /* Priority Groups */ + flags = read_dcb_flags (ifcfg, &dcb_flags_props[DCB_PG_FLAGS]); + g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_PRIORITY_GROUP_FLAGS, flags, NULL); + + if (!read_dcb_uint_array (ifcfg, + s_dcb, + flags, + "DCB_PG_ID", + "PGID", + TRUE, + nm_setting_dcb_set_priority_group_id, + error)) { + g_object_unref (s_dcb); + return FALSE; + } + + /* Group bandwidth */ + if (!read_dcb_percent_array (ifcfg, + s_dcb, + flags, + "DCB_PG_PCT", + "PGPCT", + TRUE, + nm_setting_dcb_set_priority_group_bandwidth, + error)) { + g_object_unref (s_dcb); + return FALSE; + } + + /* Priority bandwidth */ + if (!read_dcb_percent_array (ifcfg, + s_dcb, + flags, + "DCB_PG_UPPCT", + "UPPCT", + FALSE, + nm_setting_dcb_set_priority_bandwidth, + error)) { + g_object_unref (s_dcb); + return FALSE; + } + + /* Strict Bandwidth */ + if (!read_dcb_bool_array (ifcfg, + s_dcb, + flags, + "DCB_PG_STRICT", + "STRICT", + nm_setting_dcb_set_priority_strict_bandwidth, + error)) { + g_object_unref (s_dcb); + return FALSE; + } + + if (!read_dcb_uint_array (ifcfg, + s_dcb, + flags, + "DCB_PG_UP2TC", + "UP2TC", + FALSE, + nm_setting_dcb_set_priority_traffic_class, + error)) { + g_object_unref (s_dcb); + return FALSE; + } + + *out_setting = NM_SETTING (s_dcb); + return TRUE; +} + static gboolean add_one_wep_key (shvarFile *ifcfg, const char *shvar_key, @@ -4505,7 +4897,7 @@ connection_from_file (const char *filename, NMConnection *connection = NULL; shvarFile *parsed; char *type, *devtype, *nmc = NULL, *bootproto; - NMSetting *s_ip4, *s_ip6, *s_port; + NMSetting *s_ip4, *s_ip6, *s_port, *s_dcb = NULL; const char *ifcfg_name = NULL; gboolean nm_controlled = TRUE; char *unmanaged = NULL; @@ -4678,6 +5070,14 @@ connection_from_file (const char *filename, if (s_port) nm_connection_add_setting (connection, s_port); + if (!make_dcb_setting (parsed, network_file, &s_dcb, error)) { + g_object_unref (connection); + connection = NULL; + goto done; + } + if (s_dcb) + nm_connection_add_setting (connection, s_dcb); + /* iSCSI / ibft connections are read-only since their settings are * stored in NVRAM and can only be changed in BIOS. */ diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am b/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am index ee9b5db9f8..f5b731a0bb 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am @@ -96,7 +96,18 @@ EXTRA_DIST = \ ifcfg-test-infiniband \ ifcfg-test-bond-main \ ifcfg-test-bond-slave \ - ifcfg-test-bond-slave-ib + ifcfg-test-bond-slave-ib \ + ifcfg-test-dcb \ + ifcfg-test-dcb-default-app-priorities \ + ifcfg-test-dcb-bad-booleans \ + ifcfg-test-dcb-short-booleans \ + ifcfg-test-dcb-bad-uints \ + ifcfg-test-dcb-short-uints \ + ifcfg-test-dcb-bad-percent \ + ifcfg-test-dcb-short-percent \ + ifcfg-test-dcb-pgpct-not-100 \ + ifcfg-test-fcoe-fabric \ + ifcfg-test-fcoe-vn2vn check-local: @for f in $(EXTRA_DIST); do \ diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb new file mode 100644 index 0000000000..6e6589d39e --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb @@ -0,0 +1,43 @@ +TYPE=Ethernet +DEVICE=eth0 +HWADDR=00:11:22:33:44:ee +BOOTPROTO=none +IPADDR=1.2.3.4 +PREFIX=24 +GATEWAY=1.1.1.1 + +# dcb global switch +# use DCB=no to turn it off +DCB=yes + +# application settings +DCB_APP_FCOE_PRIORITY=7 +DCB_APP_FCOE_ENABLE=yes +DCB_APP_FCOE_ADVERTISE=yes +DCB_APP_FCOE_WILLING=yes + +DCB_APP_ISCSI_PRIORITY=6 +DCB_APP_ISCSI_ENABLE=yes +DCB_APP_ISCSI_ADVERTISE=yes +DCB_APP_ISCSI_WILLING=yes + +DCB_APP_FIP_PRIORITY=2 +DCB_APP_FIP_ENABLE=yes +DCB_APP_FIP_ADVERTISE=yes +DCB_APP_FIP_WILLING=yes + +# priority group settings +DCB_PG_UP2TC=76543210 +DCB_PG_PCT=25,0,0,75,0,0,0,0 +DCB_PG_ID=0000111f +DCB_PG_UPPCT=5,10,30,25,10,50,5,0 +DCB_PG_STRICT=00110101 +DCB_PG_ENABLE=yes +DCB_PG_ADVERTISE=yes +DCB_PG_WILLING=yes + +# priority flow control settings +DCB_PFC_UP=10011010 +DCB_PFC_ENABLE=yes +DCB_PFC_ADVERTISE=yes +DCB_PFC_WILLING=no diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-bad-booleans b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-bad-booleans new file mode 100644 index 0000000000..2f46a0823c --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-bad-booleans @@ -0,0 +1,12 @@ +TYPE=Ethernet +DEVICE=eth0 +HWADDR=00:11:22:33:44:ee +BOOTPROTO=none +IPADDR=1.2.3.4 +PREFIX=24 +GATEWAY=1.1.1.1 + +DCB=yes +DCB_PG_STRICT=02030101 +DCB_PG_ENABLE=yes + diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-bad-percent b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-bad-percent new file mode 100644 index 0000000000..0c5d7b8872 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-bad-percent @@ -0,0 +1,12 @@ +TYPE=Ethernet +DEVICE=eth0 +HWADDR=00:11:22:33:44:ee +BOOTPROTO=none +IPADDR=1.2.3.4 +PREFIX=24 +GATEWAY=1.1.1.1 + +DCB=yes +DCB_PG_PCT=25,0,0,75,0,0,110,0 +DCB_PG_ENABLE=yes + diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-bad-uints b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-bad-uints new file mode 100644 index 0000000000..8334999b12 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-bad-uints @@ -0,0 +1,12 @@ +TYPE=Ethernet +DEVICE=eth0 +HWADDR=00:11:22:33:44:ee +BOOTPROTO=none +IPADDR=1.2.3.4 +PREFIX=24 +GATEWAY=1.1.1.1 + +DCB=yes +DCB_PG_UP2TC=96543210 +DCB_PG_ENABLE=yes + diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-default-app-priorities b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-default-app-priorities new file mode 100644 index 0000000000..5bdcb63ce6 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-default-app-priorities @@ -0,0 +1,7 @@ +TYPE=Ethernet +DEVICE=eth0 +DCB=yes +DCB_APP_FCOE_ENABLE=yes +DCB_APP_ISCSI_ENABLE=yes +DCB_APP_FIP_ENABLE=yes + diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-pgpct-not-100 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-pgpct-not-100 new file mode 100644 index 0000000000..95eb7c5b55 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-pgpct-not-100 @@ -0,0 +1,12 @@ +TYPE=Ethernet +DEVICE=eth0 +HWADDR=00:11:22:33:44:ee +BOOTPROTO=none +IPADDR=1.2.3.4 +PREFIX=24 +GATEWAY=1.1.1.1 + +DCB=yes +DCB_PG_PCT=25,0,0,3,75,0,25,0 +DCB_PG_ENABLE=yes + diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-short-booleans b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-short-booleans new file mode 100644 index 0000000000..fbe1cbbc53 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-short-booleans @@ -0,0 +1,12 @@ +TYPE=Ethernet +DEVICE=eth0 +HWADDR=00:11:22:33:44:ee +BOOTPROTO=none +IPADDR=1.2.3.4 +PREFIX=24 +GATEWAY=1.1.1.1 + +DCB=yes +DCB_PG_STRICT=0111010 +DCB_PG_ENABLE=yes + diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-short-percent b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-short-percent new file mode 100644 index 0000000000..07ba6b6412 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-short-percent @@ -0,0 +1,12 @@ +TYPE=Ethernet +DEVICE=eth0 +HWADDR=00:11:22:33:44:ee +BOOTPROTO=none +IPADDR=1.2.3.4 +PREFIX=24 +GATEWAY=1.1.1.1 + +DCB=yes +DCB_PG_PCT=25,0,0,75,0,0,0 +DCB_PG_ENABLE=yes + diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-short-uints b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-short-uints new file mode 100644 index 0000000000..05ae39cb6e --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dcb-short-uints @@ -0,0 +1,12 @@ +TYPE=Ethernet +DEVICE=eth0 +HWADDR=00:11:22:33:44:ee +BOOTPROTO=none +IPADDR=1.2.3.4 +PREFIX=24 +GATEWAY=1.1.1.1 + +DCB=yes +DCB_PG_UP2TC=7654321 +DCB_PG_ENABLE=yes + diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-fcoe-fabric b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-fcoe-fabric new file mode 100644 index 0000000000..cde1c28d67 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-fcoe-fabric @@ -0,0 +1,6 @@ +TYPE=Ethernet +DEVICE=eth0 +DCB=yes +DCB_APP_FCOE_ENABLE=yes +DCB_APP_FCOE_MODE=fabric + diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-fcoe-vn2vn b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-fcoe-vn2vn new file mode 100644 index 0000000000..20c08451e2 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-fcoe-vn2vn @@ -0,0 +1,6 @@ +TYPE=Ethernet +DEVICE=eth0 +DCB=yes +DCB_APP_FCOE_ENABLE=yes +DCB_APP_FCOE_MODE=vn2vn + diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index 51aef533a4..1d93ed1b40 100644 --- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -45,6 +45,7 @@ #include #include #include +#include #include "nm-test-helpers.h" #include "NetworkManagerUtils.h" @@ -12712,6 +12713,416 @@ test_write_bond_slave_ib (void) g_object_unref (reread); } +#define DCB_ALL_FLAGS (NM_SETTING_DCB_FLAG_ENABLE | \ + NM_SETTING_DCB_FLAG_ADVERTISE | \ + NM_SETTING_DCB_FLAG_WILLING) + +static void +test_read_dcb_basic (void) +{ + NMConnection *connection; + GError *error = NULL; + NMSettingDcb *s_dcb; + gboolean success; + guint i; + guint expected_group_ids[8] = { 0, 0, 0, 0, 1, 1, 1, 0xF }; + guint expected_group_bandwidths[8] = { 25, 0, 0, 75, 0, 0, 0, 0 }; + guint expected_bandwidths[8] = { 5, 10, 30, 25, 10, 50, 5, 0 }; + gboolean expected_strict[8] = { FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE }; + guint expected_traffic_classes[8] = { 7, 6, 5, 4, 3, 2, 1, 0 }; + gboolean expected_pfcs[8] = { TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, FALSE }; + + connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb", + NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, NULL, &error, NULL); + g_assert_no_error (error); + g_assert (connection); + success = nm_connection_verify (connection, &error); + g_assert_no_error (error); + g_assert (success); + + s_dcb = nm_connection_get_setting_dcb (connection); + g_assert (s_dcb); + + g_assert_cmpint (nm_setting_dcb_get_app_fcoe_flags (s_dcb), ==, DCB_ALL_FLAGS); + g_assert_cmpint (nm_setting_dcb_get_app_fcoe_priority (s_dcb), ==, 7); + + g_assert_cmpint (nm_setting_dcb_get_app_iscsi_flags (s_dcb), ==, DCB_ALL_FLAGS); + g_assert_cmpint (nm_setting_dcb_get_app_iscsi_priority (s_dcb), ==, 6); + + g_assert_cmpint (nm_setting_dcb_get_app_fip_flags (s_dcb), ==, DCB_ALL_FLAGS); + g_assert_cmpint (nm_setting_dcb_get_app_fip_priority (s_dcb), ==, 2); + + g_assert_cmpint (nm_setting_dcb_get_priority_flow_control_flags (s_dcb), ==, (NM_SETTING_DCB_FLAG_ENABLE | NM_SETTING_DCB_FLAG_ADVERTISE)); + for (i = 0; i < 8; i++) + g_assert_cmpint (nm_setting_dcb_get_priority_flow_control (s_dcb, i), ==, expected_pfcs[i]); + + g_assert_cmpint (nm_setting_dcb_get_priority_group_flags (s_dcb), ==, DCB_ALL_FLAGS); + + /* Group IDs */ + for (i = 0; i < 8; i++) + g_assert_cmpint (nm_setting_dcb_get_priority_group_id (s_dcb, i), ==, expected_group_ids[i]); + + /* Group bandwidth */ + for (i = 0; i < 8; i++) + g_assert_cmpint (nm_setting_dcb_get_priority_group_bandwidth (s_dcb, i), ==, expected_group_bandwidths[i]); + + /* User priority bandwidth */ + for (i = 0; i < 8; i++) + g_assert_cmpint (nm_setting_dcb_get_priority_bandwidth (s_dcb, i), ==, expected_bandwidths[i]); + + /* Strict bandwidth */ + for (i = 0; i < 8; i++) + g_assert_cmpint (nm_setting_dcb_get_priority_strict_bandwidth (s_dcb, i), ==, expected_strict[i]); + + /* Traffic class */ + for (i = 0; i < 8; i++) + g_assert_cmpint (nm_setting_dcb_get_priority_traffic_class (s_dcb, i), ==, expected_traffic_classes[i]); + + g_object_unref (connection); +} + +static void +test_write_dcb_basic (void) +{ + NMConnection *connection, *reread; + GError *error = NULL; + NMSettingConnection *s_con; + NMSettingWired *s_wired; + NMSettingDcb *s_dcb; + NMSettingIP4Config *s_ip4; + NMSettingIP6Config *s_ip6; + gboolean success, ignore_error; + guint i; + char *uuid, *testfile; + const guint group_ids[8] = { 4, 0xF, 6, 0xF, 1, 7, 3, 0xF }; + const guint group_bandwidths[8] = { 10, 20, 15, 10, 2, 3, 35, 5 }; + const guint bandwidths[8] = { 10, 20, 30, 40, 50, 10, 0, 25 }; + const gboolean strict[8] = { TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE }; + const guint traffic_classes[8] = { 3, 4, 7, 2, 1, 0, 5, 6 }; + const gboolean pfcs[8] = { TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE }; + + connection = nm_connection_new (); + + s_con = (NMSettingConnection *) nm_setting_connection_new (); + nm_connection_add_setting (connection, NM_SETTING (s_con)); + uuid = nm_utils_uuid_generate (); + g_object_set (G_OBJECT (s_con), + NM_SETTING_CONNECTION_ID, "dcb-test", + NM_SETTING_CONNECTION_UUID, uuid, + NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_CONNECTION_INTERFACE_NAME, "eth0", + NULL); + g_free (uuid); + + /* Wired setting */ + s_wired = (NMSettingWired *) nm_setting_wired_new (); + nm_connection_add_setting (connection, NM_SETTING (s_wired)); + + /* IP stuff */ + s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new (); + g_object_set (G_OBJECT (s_ip4), NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL); + nm_connection_add_setting (connection, NM_SETTING (s_ip4)); + + s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new (); + g_object_set (G_OBJECT (s_ip6), NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NULL); + nm_connection_add_setting (connection, NM_SETTING (s_ip6)); + + /* DCB */ + s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); + nm_connection_add_setting (connection, NM_SETTING (s_dcb)); + + g_object_set (G_OBJECT (s_dcb), + NM_SETTING_DCB_APP_FCOE_FLAGS, DCB_ALL_FLAGS, + NM_SETTING_DCB_APP_FCOE_PRIORITY, 5, + NM_SETTING_DCB_APP_ISCSI_FLAGS, DCB_ALL_FLAGS, + NM_SETTING_DCB_APP_ISCSI_PRIORITY, 1, + NM_SETTING_DCB_APP_FIP_FLAGS, DCB_ALL_FLAGS, + NM_SETTING_DCB_APP_FIP_PRIORITY, 3, + NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS, DCB_ALL_FLAGS, + NM_SETTING_DCB_PRIORITY_GROUP_FLAGS, DCB_ALL_FLAGS, + NULL); + + for (i = 0; i < 8; i++) { + nm_setting_dcb_set_priority_flow_control (s_dcb, i, pfcs[i]); + nm_setting_dcb_set_priority_group_id (s_dcb, i, group_ids[i]); + nm_setting_dcb_set_priority_group_bandwidth (s_dcb, i, group_bandwidths[i]); + nm_setting_dcb_set_priority_bandwidth (s_dcb, i, bandwidths[i]); + nm_setting_dcb_set_priority_strict_bandwidth (s_dcb, i, strict[i]); + nm_setting_dcb_set_priority_traffic_class (s_dcb, i, traffic_classes[i]); + } + + g_assert (nm_connection_verify (connection, &error)); + + /* Save the ifcfg */ + success = writer_new_connection (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile, + &error); + g_assert_no_error (error); + g_assert (success); + g_assert (testfile); + + /* re-read the connection for comparison */ + reread = connection_from_file (testfile, + NULL, + TYPE_ETHERNET, + NULL, NULL, NULL, + NULL, NULL, + &error, + &ignore_error); + unlink (testfile); + + g_assert_no_error (error); + g_assert (reread); + g_assert (nm_connection_verify (reread, &error)); + g_assert (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT)); + + g_object_unref (connection); + g_object_unref (reread); + g_free (testfile); +} + +static void +test_read_dcb_default_app_priorities (void) +{ + NMConnection *connection; + GError *error = NULL; + NMSettingDcb *s_dcb; + gboolean success; + + connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-default-app-priorities", + NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, NULL, &error, NULL); + g_assert_no_error (error); + g_assert (connection); + success = nm_connection_verify (connection, &error); + g_assert_no_error (error); + g_assert (success); + + s_dcb = nm_connection_get_setting_dcb (connection); + g_assert (s_dcb); + + g_assert_cmpint (nm_setting_dcb_get_app_fcoe_flags (s_dcb), ==, NM_SETTING_DCB_FLAG_ENABLE); + g_assert_cmpint (nm_setting_dcb_get_app_fcoe_priority (s_dcb), ==, -1); + + g_assert_cmpint (nm_setting_dcb_get_app_iscsi_flags (s_dcb), ==, NM_SETTING_DCB_FLAG_ENABLE); + g_assert_cmpint (nm_setting_dcb_get_app_iscsi_priority (s_dcb), ==, -1); + + g_assert_cmpint (nm_setting_dcb_get_app_fip_flags (s_dcb), ==, NM_SETTING_DCB_FLAG_ENABLE); + g_assert_cmpint (nm_setting_dcb_get_app_fip_priority (s_dcb), ==, -1); + + g_object_unref (connection); +} + +static void +test_read_dcb_bad_booleans (void) +{ + NMConnection *connection; + GError *error = NULL; + + connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-bad-booleans", + NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, NULL, &error, NULL); + g_assert_error (error, IFCFG_PLUGIN_ERROR, 0); + g_assert (strstr (error->message, "invalid boolean digit")); + g_assert (connection == NULL); +} + +static void +test_read_dcb_short_booleans (void) +{ + NMConnection *connection; + GError *error = NULL; + + connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-short-booleans", + NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, NULL, &error, NULL); + g_assert_error (error, IFCFG_PLUGIN_ERROR, 0); + g_assert (strstr (error->message, "boolean array must be 8 characters")); + g_assert (connection == NULL); +} + +static void +test_read_dcb_bad_uints (void) +{ + NMConnection *connection; + GError *error = NULL; + + connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-bad-uints", + NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, NULL, &error, NULL); + g_assert_error (error, IFCFG_PLUGIN_ERROR, 0); + g_assert (strstr (error->message, "invalid uint digit")); + g_assert (connection == NULL); +} + +static void +test_read_dcb_short_uints (void) +{ + NMConnection *connection; + GError *error = NULL; + + connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-short-uints", + NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, NULL, &error, NULL); + g_assert_error (error, IFCFG_PLUGIN_ERROR, 0); + g_assert (strstr (error->message, "uint array must be 8 characters")); + g_assert (connection == NULL); +} + +static void +test_read_dcb_bad_percent (void) +{ + NMConnection *connection; + GError *error = NULL; + + connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-bad-percent", + NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, NULL, &error, NULL); + g_assert_error (error, IFCFG_PLUGIN_ERROR, 0); + g_assert (strstr (error->message, "invalid percent element")); + g_assert (connection == NULL); +} + +static void +test_read_dcb_short_percent (void) +{ + NMConnection *connection; + GError *error = NULL; + + connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-short-percent", + NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, NULL, &error, NULL); + g_assert_error (error, IFCFG_PLUGIN_ERROR, 0); + g_assert (strstr (error->message, "percent array must be 8 elements")); + g_assert (connection == NULL); +} + +static void +test_read_dcb_pgpct_not_100 (void) +{ + NMConnection *connection; + GError *error = NULL; + + connection = connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-pgpct-not-100", + NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, NULL, &error, NULL); + g_assert_error (error, IFCFG_PLUGIN_ERROR, 0); + g_assert (strstr (error->message, "invalid percentage sum")); + g_assert (connection == NULL); +} + +static void +test_read_fcoe_mode (gconstpointer user_data) +{ + const char *expected_mode = user_data; + NMConnection *connection; + GError *error = NULL; + NMSettingDcb *s_dcb; + gboolean success; + char *file; + + file = g_strdup_printf (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-fcoe-%s", expected_mode); + connection = connection_from_file (file, NULL, TYPE_ETHERNET, NULL, NULL, NULL, NULL, NULL, &error, NULL); + g_free (file); + g_assert_no_error (error); + g_assert (connection); + success = nm_connection_verify (connection, &error); + g_assert_no_error (error); + g_assert (success); + + s_dcb = nm_connection_get_setting_dcb (connection); + g_assert (s_dcb); + + g_assert_cmpint (nm_setting_dcb_get_app_fcoe_flags (s_dcb), ==, NM_SETTING_DCB_FLAG_ENABLE); + g_assert_cmpstr (nm_setting_dcb_get_app_fcoe_mode (s_dcb), ==, expected_mode); + + g_object_unref (connection); +} + +static void +test_write_fcoe_mode (gconstpointer user_data) +{ + const char *expected_mode = user_data; + NMConnection *connection, *reread; + GError *error = NULL; + NMSettingConnection *s_con; + NMSettingWired *s_wired; + NMSettingDcb *s_dcb; + NMSettingIP4Config *s_ip4; + NMSettingIP6Config *s_ip6; + gboolean success, ignore_error; + char *uuid, *testfile; + + connection = nm_connection_new (); + + s_con = (NMSettingConnection *) nm_setting_connection_new (); + nm_connection_add_setting (connection, NM_SETTING (s_con)); + uuid = nm_utils_uuid_generate (); + g_object_set (G_OBJECT (s_con), + NM_SETTING_CONNECTION_ID, "fcoe-test", + NM_SETTING_CONNECTION_UUID, uuid, + NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_CONNECTION_INTERFACE_NAME, "eth0", + NULL); + g_free (uuid); + + /* Wired setting */ + s_wired = (NMSettingWired *) nm_setting_wired_new (); + nm_connection_add_setting (connection, NM_SETTING (s_wired)); + + /* IP stuff */ + s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new (); + g_object_set (G_OBJECT (s_ip4), NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL); + nm_connection_add_setting (connection, NM_SETTING (s_ip4)); + + s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new (); + g_object_set (G_OBJECT (s_ip6), NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NULL); + nm_connection_add_setting (connection, NM_SETTING (s_ip6)); + + /* DCB */ + s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); + nm_connection_add_setting (connection, NM_SETTING (s_dcb)); + + g_object_set (G_OBJECT (s_dcb), + NM_SETTING_DCB_APP_FCOE_FLAGS, NM_SETTING_DCB_FLAG_ENABLE, + NM_SETTING_DCB_APP_FCOE_MODE, expected_mode, + NULL); + + g_assert (nm_connection_verify (connection, &error)); + + /* Save the ifcfg */ + success = writer_new_connection (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile, + &error); + g_assert_no_error (error); + g_assert (success); + g_assert (testfile); + + { + shvarFile *ifcfg = svNewFile (testfile); + char *written_mode; + + g_assert (ifcfg); + written_mode = svGetValue (ifcfg, "DCB_APP_FCOE_MODE", FALSE); + svCloseFile (ifcfg); + g_assert_cmpstr (written_mode, ==, expected_mode); + g_free (written_mode); + } + + /* re-read the connection for comparison */ + reread = connection_from_file (testfile, + NULL, + TYPE_ETHERNET, + NULL, NULL, NULL, + NULL, NULL, + &error, + &ignore_error); + unlink (testfile); + + g_assert_no_error (error); + g_assert (reread); + g_assert (nm_connection_verify (reread, &error)); + g_assert (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT)); + + g_object_unref (connection); + g_object_unref (reread); + g_free (testfile); +} + #define TEST_IFCFG_WIFI_OPEN_SSID_BAD_HEX TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wifi-open-ssid-bad-hex" #define TEST_IFCFG_WIFI_OPEN_SSID_LONG_QUOTED TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wifi-open-ssid-long-quoted" #define TEST_IFCFG_WIFI_OPEN_SSID_LONG_HEX TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wifi-open-ssid-long-hex" @@ -12897,6 +13308,20 @@ int main (int argc, char **argv) test_read_ibft_malformed ("ibft-bad-gateway-read", TEST_IFCFG_DIR "/iscsiadm-test-bad-gateway"); test_read_ibft_malformed ("ibft-bad-dns1-read", TEST_IFCFG_DIR "/iscsiadm-test-bad-dns1"); test_read_ibft_malformed ("ibft-bad-dns2-read", TEST_IFCFG_DIR "/iscsiadm-test-bad-dns2"); + g_test_add_func (TPATH "dcb/read-basic", test_read_dcb_basic); + g_test_add_func (TPATH "dcb/write-basic", test_write_dcb_basic); + g_test_add_func (TPATH "dcb/default-app-priorities", test_read_dcb_default_app_priorities); + g_test_add_func (TPATH "dcb/bad-booleans", test_read_dcb_bad_booleans); + g_test_add_func (TPATH "dcb/short-booleans", test_read_dcb_short_booleans); + g_test_add_func (TPATH "dcb/bad-uints", test_read_dcb_bad_uints); + g_test_add_func (TPATH "dcb/short-uints", test_read_dcb_short_uints); + g_test_add_func (TPATH "dcb/bad-percent", test_read_dcb_bad_percent); + g_test_add_func (TPATH "dcb/short-percent", test_read_dcb_short_percent); + g_test_add_func (TPATH "dcb/pgpct-not-100", test_read_dcb_pgpct_not_100); + g_test_add_data_func (TPATH "fcoe/fabric", (gpointer) NM_SETTING_DCB_FCOE_MODE_FABRIC, test_read_fcoe_mode); + g_test_add_data_func (TPATH "fcoe/vn2vn", (gpointer) NM_SETTING_DCB_FCOE_MODE_VN2VN, test_read_fcoe_mode); + g_test_add_data_func (TPATH "fcoe/write-fabric", (gpointer) NM_SETTING_DCB_FCOE_MODE_FABRIC, test_write_fcoe_mode); + g_test_add_data_func (TPATH "fcoe/write-vn2vn", (gpointer) NM_SETTING_DCB_FCOE_MODE_VN2VN, test_write_fcoe_mode); /* bonding */ test_read_bond_main (); diff --git a/src/settings/plugins/ifcfg-rh/writer.c b/src/settings/plugins/ifcfg-rh/writer.c index 077f1be9d4..01304c0826 100644 --- a/src/settings/plugins/ifcfg-rh/writer.c +++ b/src/settings/plugins/ifcfg-rh/writer.c @@ -1470,6 +1470,165 @@ write_team_port_setting (NMConnection *connection, shvarFile *ifcfg, GError **er return TRUE; } +static void +write_dcb_flags (shvarFile *ifcfg, const char *tag, NMSettingDcbFlags flags) +{ + char *prop; + + prop = g_strdup_printf ("DCB_%s_ENABLE", tag); + svSetValue (ifcfg, prop, (flags & NM_SETTING_DCB_FLAG_ENABLE) ? "yes" : NULL, FALSE); + g_free (prop); + + prop = g_strdup_printf ("DCB_%s_ADVERTISE", tag); + svSetValue (ifcfg, prop, (flags & NM_SETTING_DCB_FLAG_ADVERTISE) ? "yes" : NULL, FALSE); + g_free (prop); + + prop = g_strdup_printf ("DCB_%s_WILLING", tag); + svSetValue (ifcfg, prop, (flags & NM_SETTING_DCB_FLAG_WILLING) ? "yes" : NULL, FALSE); + g_free (prop); +} + +static void +write_dcb_app (shvarFile *ifcfg, + const char *tag, + NMSettingDcbFlags flags, + gint priority) +{ + char *prop, *tmp = NULL; + + write_dcb_flags (ifcfg, tag, flags); + + if ((flags & NM_SETTING_DCB_FLAG_ENABLE) && (priority >= 0)) + tmp = g_strdup_printf ("%d", priority); + prop = g_strdup_printf ("DCB_%s_PRIORITY", tag); + svSetValue (ifcfg, prop, tmp, FALSE); + g_free (prop); + g_free (tmp); +} + +typedef gboolean (*DcbGetBoolFunc) (NMSettingDcb *, guint); + +static void +write_dcb_bool_array (shvarFile *ifcfg, + const char *key, + NMSettingDcb *s_dcb, + NMSettingDcbFlags flags, + DcbGetBoolFunc get_func) +{ + char str[9]; + guint i; + + if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) { + svSetValue (ifcfg, key, NULL, FALSE); + return; + } + + str[8] = 0; + for (i = 0; i < 8; i++) + str[i] = get_func (s_dcb, i) ? '1' : '0'; + svSetValue (ifcfg, key, str, FALSE); +} + +typedef guint (*DcbGetUintFunc) (NMSettingDcb *, guint); + +static void +write_dcb_uint_array (shvarFile *ifcfg, + const char *key, + NMSettingDcb *s_dcb, + NMSettingDcbFlags flags, + DcbGetUintFunc get_func) +{ + char str[9]; + guint i, num; + + if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) { + svSetValue (ifcfg, key, NULL, FALSE); + return; + } + + str[8] = 0; + for (i = 0; i < 8; i++) { + num = get_func (s_dcb, i); + if (num < 10) + str[i] = '0' + num; + else if (num == 15) + str[i] = 'f'; + else + g_assert_not_reached (); + } + svSetValue (ifcfg, key, str, FALSE); +} + +static void +write_dcb_percent_array (shvarFile *ifcfg, + const char *key, + NMSettingDcb *s_dcb, + NMSettingDcbFlags flags, + DcbGetUintFunc get_func) +{ + GString *str; + guint i; + + if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) { + svSetValue (ifcfg, key, NULL, FALSE); + return; + } + + str = g_string_sized_new (30); + for (i = 0; i < 8; i++) { + if (str->len) + g_string_append_c (str, ','); + g_string_append_printf (str, "%d", get_func (s_dcb, i)); + } + svSetValue (ifcfg, key, str->str, FALSE); + g_string_free (str, TRUE); +} + +static gboolean +write_dcb_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) +{ + NMSettingDcb *s_dcb; + NMSettingDcbFlags flags; + + s_dcb = nm_connection_get_setting_dcb (connection); + if (!s_dcb) { + svSetValue (ifcfg, "DCB", NULL, FALSE); + return TRUE; + } + + svSetValue (ifcfg, "DCB", "yes", FALSE); + + write_dcb_app (ifcfg, "APP_FCOE", + nm_setting_dcb_get_app_fcoe_flags (s_dcb), + nm_setting_dcb_get_app_fcoe_priority (s_dcb)); + if (nm_setting_dcb_get_app_fcoe_flags (s_dcb) & NM_SETTING_DCB_FLAG_ENABLE) + svSetValue (ifcfg, "DCB_APP_FCOE_MODE", nm_setting_dcb_get_app_fcoe_mode (s_dcb), FALSE); + else + svSetValue (ifcfg, "DCB_APP_FCOE_MODE", NULL, FALSE); + + write_dcb_app (ifcfg, "APP_ISCSI", + nm_setting_dcb_get_app_iscsi_flags (s_dcb), + nm_setting_dcb_get_app_iscsi_priority (s_dcb)); + write_dcb_app (ifcfg, "APP_FIP", + nm_setting_dcb_get_app_fip_flags (s_dcb), + nm_setting_dcb_get_app_fip_priority (s_dcb)); + + write_dcb_flags (ifcfg, "PFC", nm_setting_dcb_get_priority_flow_control_flags (s_dcb)); + write_dcb_bool_array (ifcfg, "DCB_PFC_UP", s_dcb, + nm_setting_dcb_get_priority_flow_control_flags (s_dcb), + nm_setting_dcb_get_priority_flow_control); + + flags = nm_setting_dcb_get_priority_group_flags (s_dcb); + write_dcb_flags (ifcfg, "PG", flags); + write_dcb_uint_array (ifcfg, "DCB_PG_ID", s_dcb, flags, nm_setting_dcb_get_priority_group_id); + write_dcb_percent_array (ifcfg, "DCB_PG_PCT", s_dcb, flags, nm_setting_dcb_get_priority_group_bandwidth); + write_dcb_percent_array (ifcfg, "DCB_PG_UPPCT", s_dcb, flags, nm_setting_dcb_get_priority_bandwidth); + write_dcb_bool_array (ifcfg, "DCB_PG_STRICT", s_dcb, flags, nm_setting_dcb_get_priority_strict_bandwidth); + write_dcb_uint_array (ifcfg, "DCB_PG_UP2TC", s_dcb, flags, nm_setting_dcb_get_priority_traffic_class); + + return TRUE; +} + static void write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) { @@ -2275,6 +2434,9 @@ write_connection (NMConnection *connection, if (!write_team_port_setting (connection, ifcfg, error)) goto out; + if (!write_dcb_setting (connection, ifcfg, error)) + goto out; + if (!utils_ignore_ip_config (connection)) { svSetValue (ifcfg, "DHCP_HOSTNAME", NULL, FALSE);