1
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2
/* NetworkManager Connection editor -- Connection editor for NetworkManager
4
* Dan Williams <dcbw@redhat.com>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License along
17
* with this program; if not, write to the Free Software Foundation, Inc.,
18
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
* Copyright 2013 - 2014 Red Hat, Inc.
23
#include "nm-default.h"
31
G_DEFINE_TYPE (CEPageDcb, ce_page_dcb, CE_TYPE_PAGE)
33
#define CE_PAGE_DCB_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CE_TYPE_PAGE_DCB, CEPageDcbPrivate))
36
/* Copy of initial setting, if any; changes in the Options dialogs
37
* update this setting, which is then copied to the final setting when
40
NMSettingDcb *options;
42
GtkToggleButton *enabled;
45
gboolean initial_have_dcb;
48
/***************************************************************************/
51
pfc_dialog_show (CEPageDcb *self)
53
CEPageDcbPrivate *priv = CE_PAGE_DCB_GET_PRIVATE (self);
54
CEPage *parent = CE_PAGE (self);
55
GtkWidget *dialog, *toplevel;
56
GtkToggleButton *check;
62
dialog = GTK_WIDGET (gtk_builder_get_object (parent->builder, "pfc_dialog"));
64
toplevel = gtk_widget_get_toplevel (parent->page);
65
if (gtk_widget_is_toplevel (toplevel))
66
gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (toplevel));
68
/* Set the initial value */
69
for (i = 0; i < 8; i++ ) {
70
tmp = g_strdup_printf ("pfc_prio%u_checkbutton", i);
71
check = GTK_TOGGLE_BUTTON (gtk_builder_get_object (parent->builder, tmp));
75
gtk_toggle_button_set_active (check, nm_setting_dcb_get_priority_flow_control (priv->options, i));
79
result = gtk_dialog_run (GTK_DIALOG (dialog));
80
if (result == GTK_RESPONSE_OK) {
81
for (i = 0; i < 8; i++ ) {
82
tmp = g_strdup_printf ("pfc_prio%u_checkbutton", i);
83
check = GTK_TOGGLE_BUTTON (gtk_builder_get_object (parent->builder, tmp));
87
active = gtk_toggle_button_get_active (check);
88
nm_setting_dcb_set_priority_flow_control (priv->options, i, active);
92
gtk_widget_hide (dialog);
93
ce_page_changed (CE_PAGE (self));
97
uint_entries_validate (GtkBuilder *builder, const char *fmt, gint max, gboolean sum)
104
gboolean valid = TRUE;
107
gdk_rgba_parse (&bgcolor, "red3");
109
for (i = 0; i < 8; i++) {
110
tmp = g_strdup_printf (fmt, i);
111
entry = GTK_ENTRY (gtk_builder_get_object (builder, tmp));
115
text = gtk_entry_get_text (entry);
118
num = strtol (text, NULL, 10);
119
if (errno || num < 0 || num > max) {
120
/* FIXME: only sets highlight color? */
121
utils_override_bg_color (GTK_WIDGET (entry), &bgcolor);
124
utils_override_bg_color (GTK_WIDGET (entry), NULL);
126
total += (guint) num;
127
if (sum && total > 100)
128
utils_override_bg_color (GTK_WIDGET (entry), &bgcolor);
131
if (sum && total != 100) {
132
utils_override_bg_color (GTK_WIDGET (entry), &bgcolor);
140
pg_dialog_valid_func (GtkBuilder *builder)
143
gboolean b1, b2, valid = FALSE;
145
b1 = uint_entries_validate (builder, "pg_pgpct%u_entry", 100, TRUE);
146
b2 = uint_entries_validate (builder, "pg_uppct%u_entry", 100, FALSE);
149
dialog = GTK_DIALOG (gtk_builder_get_object (builder, "pg_dialog"));
150
gtk_dialog_set_response_sensitive (dialog, GTK_RESPONSE_OK, valid);
155
combos_handle (GtkBuilder *builder,
161
guint (*get_func) (NMSettingDcb *s_dcb, guint n),
162
void (*set_func) (NMSettingDcb *s_dcb, guint n, guint val))
168
for (i = 0; i < 8; i++) {
169
tmp = g_strdup_printf (fmt, i);
170
combo = GTK_COMBO_BOX (gtk_builder_get_object (builder, tmp));
175
num = get_func (s_dcb, i);
176
if (other_num && (num == other_num))
177
gtk_combo_box_set_active (combo, last_idx);
179
gtk_combo_box_set_active (combo, num);
180
g_signal_connect_swapped (combo, "changed", (GCallback) pg_dialog_valid_func, builder);
181
} else if (set_func) {
182
gint idx = gtk_combo_box_get_active (combo);
184
if (idx >= 0 && idx <= max)
185
set_func (s_dcb, i, idx);
186
else if (idx == last_idx)
187
set_func (s_dcb, i, other_num);
189
g_assert_not_reached ();
194
uint_filter_cb (GtkEditable *editable,
200
utils_filter_editable_on_insert_text (editable,
201
text, length, position, user_data,
202
utils_char_is_ascii_digit,
207
uint_entries_handle (GtkBuilder *builder,
210
guint (*get_func) (NMSettingDcb *s_dcb, guint n),
211
void (*set_func) (NMSettingDcb *s_dcb, guint n, guint val))
218
for (i = 0; i < 8; i++) {
219
tmp = g_strdup_printf (fmt, i);
220
entry = GTK_ENTRY (gtk_builder_get_object (builder, tmp));
225
tmp = g_strdup_printf ("%u", get_func (s_dcb, i));
226
gtk_entry_set_text (entry, tmp);
229
g_signal_connect (entry, "insert-text", (GCallback) uint_filter_cb, NULL);
230
g_signal_connect_swapped (entry, "changed", (GCallback) pg_dialog_valid_func, builder);
231
} else if (set_func) {
234
text = gtk_entry_get_text (entry);
237
num = strtol (text, NULL, 10);
238
if (errno == 0 && num >= 0 && num <= 100)
239
set_func (s_dcb, i, (guint) num);
242
g_assert_not_reached ();
247
bool_entries_handle (GtkBuilder *builder,
250
gboolean (*get_func) (NMSettingDcb *s_dcb, guint n),
251
void (*set_func) (NMSettingDcb *s_dcb, guint n, gboolean val))
254
GtkToggleButton *toggle;
257
for (i = 0; i < 8; i++) {
258
tmp = g_strdup_printf (fmt, i);
259
toggle = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, tmp));
264
gtk_toggle_button_set_active (toggle, get_func (s_dcb, i));
266
set_func (s_dcb, i, gtk_toggle_button_get_active (toggle));
268
g_assert_not_reached ();
273
pg_dialog_show (CEPageDcb *self)
275
CEPageDcbPrivate *priv = CE_PAGE_DCB_GET_PRIVATE (self);
276
CEPage *parent = CE_PAGE (self);
277
GtkWidget *dialog, *toplevel;
280
dialog = GTK_WIDGET (gtk_builder_get_object (parent->builder, "pg_dialog"));
282
toplevel = gtk_widget_get_toplevel (parent->page);
283
if (gtk_widget_is_toplevel (toplevel))
284
gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (toplevel));
286
combos_handle (parent->builder,
292
nm_setting_dcb_get_priority_group_id,
295
uint_entries_handle (parent->builder,
298
nm_setting_dcb_get_priority_group_bandwidth,
301
uint_entries_handle (parent->builder,
304
nm_setting_dcb_get_priority_bandwidth,
307
bool_entries_handle (parent->builder,
309
"pg_strict%u_checkbutton",
310
nm_setting_dcb_get_priority_strict_bandwidth,
313
combos_handle (parent->builder,
319
nm_setting_dcb_get_priority_traffic_class,
322
pg_dialog_valid_func (parent->builder);
325
result = gtk_dialog_run (GTK_DIALOG (dialog));
326
if (result == GTK_RESPONSE_OK) {
327
combos_handle (parent->builder,
334
nm_setting_dcb_set_priority_group_id);
336
uint_entries_handle (parent->builder,
340
nm_setting_dcb_set_priority_group_bandwidth);
342
uint_entries_handle (parent->builder,
346
nm_setting_dcb_set_priority_bandwidth);
348
bool_entries_handle (parent->builder,
350
"pg_strict%u_checkbutton",
352
nm_setting_dcb_set_priority_strict_bandwidth);
354
combos_handle (parent->builder,
361
nm_setting_dcb_set_priority_traffic_class);
364
gtk_widget_hide (dialog);
365
ce_page_changed (CE_PAGE (self));
369
pg_enabled (CEPageDcb *self, gboolean enabled)
371
CEPageDcbPrivate *priv = CE_PAGE_DCB_GET_PRIVATE (self);
373
gboolean set_default = TRUE;
378
/* If the connection did not previously have DCB enabled, and the user
379
* just enabled DCB, set a valid priority group bandwidth so that the
380
* user doesn't have to go mess with the PG options dialog.
382
for (i = 0; i < 8; i++) {
383
if (nm_setting_dcb_get_priority_group_bandwidth (priv->options, i)) {
390
nm_setting_dcb_set_priority_group_bandwidth (priv->options, 0, 100);
392
ce_page_changed (CE_PAGE (self));
395
/***************************************************************************/
397
typedef void (*OptionsFunc) (CEPageDcb *self);
398
typedef void (*EnabledFunc) (CEPageDcb *self, gboolean enabled);
402
const char *flags_prop;
403
const char *priority_prop;
404
const OptionsFunc options_func;
405
const EnabledFunc enabled_func;
408
static const Feature features[] = {
409
{ "fcoe", NM_SETTING_DCB_APP_FCOE_FLAGS,
410
NM_SETTING_DCB_APP_FCOE_PRIORITY },
412
{ "iscsi", NM_SETTING_DCB_APP_ISCSI_FLAGS,
413
NM_SETTING_DCB_APP_ISCSI_PRIORITY },
415
{ "fip", NM_SETTING_DCB_APP_FIP_FLAGS,
416
NM_SETTING_DCB_APP_FIP_PRIORITY },
418
{ "pfc", NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS,
422
{ "pg", NM_SETTING_DCB_PRIORITY_GROUP_FLAGS,
434
get_widget (GtkBuilder *builder, const char *prefix, const char *suffix)
439
s = g_strdup_printf ("%s%s", prefix, suffix);
440
widget = GTK_WIDGET (gtk_builder_get_object (builder, s));
447
enable_toggled_cb (GtkToggleButton *button, EnableInfo *info)
449
gboolean enabled = gtk_toggle_button_get_active (button);
452
/* Set other feature widgets sensitive or not depending on enabled */
454
widget = get_widget (info->page->builder, info->f->prefix, "_advertise_checkbutton");
455
gtk_widget_set_sensitive (widget, enabled);
456
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
458
widget = get_widget (info->page->builder, info->f->prefix, "_willing_checkbutton");
459
gtk_widget_set_sensitive (widget, enabled);
460
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
462
if (info->f->priority_prop) {
463
widget = get_widget (info->page->builder, info->f->prefix, "_priority_combo");
464
gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
465
gtk_widget_set_sensitive (widget, enabled);
468
if (info->f->options_func) {
469
widget = get_widget (info->page->builder, info->f->prefix, "_options_button");
470
gtk_widget_set_sensitive (widget, enabled);
473
/* FCoE mode combo */
474
if (!strcmp (info->f->prefix, "fcoe")) {
475
widget = get_widget (info->page->builder, info->f->prefix, "_mode_combo");
476
gtk_widget_set_sensitive (widget, enabled);
479
if (info->f->enabled_func)
480
info->f->enabled_func (CE_PAGE_DCB (info->page), gtk_toggle_button_get_active (button));
482
ce_page_changed (info->page);
486
feature_setup (CEPageDcb *self, NMSettingDcb *s_dcb, const Feature *f)
488
CEPage *parent = CE_PAGE (self);
490
NMSettingDcbFlags flags = NM_SETTING_DCB_FLAG_NONE;
495
g_object_get (G_OBJECT (s_dcb), f->flags_prop, (guint32 *) &flags, NULL);
496
enabled = flags & NM_SETTING_DCB_FLAG_ENABLE;
499
widget = get_widget (parent->builder, f->prefix, "_enable_checkbutton");
500
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), enabled);
502
info = g_malloc0 (sizeof (EnableInfo));
505
g_signal_connect (widget, "toggled", G_CALLBACK (enable_toggled_cb), info);
506
g_object_weak_ref (G_OBJECT (widget), (GWeakNotify) g_free, info);
509
widget = get_widget (parent->builder, f->prefix, "_advertise_checkbutton");
510
gtk_widget_set_sensitive (widget, enabled);
512
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), flags & NM_SETTING_DCB_FLAG_ADVERTISE);
513
g_signal_connect_swapped (widget, "toggled", G_CALLBACK (ce_page_changed), self);
516
widget = get_widget (parent->builder, f->prefix, "_willing_checkbutton");
517
gtk_widget_set_sensitive (widget, enabled);
519
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), flags & NM_SETTING_DCB_FLAG_WILLING);
520
g_signal_connect_swapped (widget, "toggled", G_CALLBACK (ce_page_changed), self);
522
if (f->priority_prop) {
526
g_object_get (G_OBJECT (s_dcb), f->priority_prop, &priority, NULL);
527
priority = CLAMP (priority, -1, 7);
529
widget = get_widget (parent->builder, f->prefix, "_priority_combo");
530
gtk_widget_set_sensitive (widget, enabled);
531
gtk_combo_box_set_active (GTK_COMBO_BOX (widget), priority + 1);
532
g_signal_connect_swapped (widget, "changed", G_CALLBACK (ce_page_changed), self);
535
if (f->options_func) {
536
widget = get_widget (parent->builder, f->prefix, "_options_button");
537
gtk_widget_set_sensitive (widget, enabled);
538
g_signal_connect_swapped (widget, "clicked", G_CALLBACK (f->options_func), self);
541
/* Set up the FCoE mode combo */
542
if (!strcmp (f->prefix, "fcoe")) {
543
const char *mode = s_dcb ? nm_setting_dcb_get_app_fcoe_mode (s_dcb) : NULL;
546
widget = get_widget (info->page->builder, info->f->prefix, "_mode_combo");
547
if (g_strcmp0 (mode, NM_SETTING_DCB_FCOE_MODE_VN2VN) == 0)
549
gtk_combo_box_set_active (GTK_COMBO_BOX (widget), idx);
550
gtk_widget_set_sensitive (widget, enabled);
551
g_signal_connect_swapped (widget, "changed", G_CALLBACK (ce_page_changed), self);
556
enable_toggled (GtkToggleButton *button, gpointer user_data)
558
CEPageDcbPrivate *priv = CE_PAGE_DCB_GET_PRIVATE (user_data);
560
gtk_widget_set_sensitive (GTK_WIDGET (priv->box), gtk_toggle_button_get_active (button));
561
ce_page_changed (CE_PAGE (user_data));
565
finish_setup (CEPageDcb *self, gpointer unused, GError *error, gpointer user_data)
567
CEPage *parent = CE_PAGE (self);
568
CEPageDcbPrivate *priv = CE_PAGE_DCB_GET_PRIVATE (self);
569
NMSettingDcb *s_dcb = nm_connection_get_setting_dcb (parent->connection);
575
gtk_toggle_button_set_active (priv->enabled, priv->initial_have_dcb);
576
g_signal_connect (priv->enabled, "toggled", G_CALLBACK (enable_toggled), self);
577
gtk_widget_set_sensitive (GTK_WIDGET (priv->box), priv->initial_have_dcb);
579
for (i = 0; i < G_N_ELEMENTS (features); i++)
580
feature_setup (self, s_dcb, &features[i]);
584
ce_page_dcb_new (NMConnectionEditor *editor,
585
NMConnection *connection,
586
GtkWindow *parent_window,
588
const char **out_secrets_setting_name,
592
CEPageDcbPrivate *priv;
596
self = CE_PAGE_DCB (ce_page_new (CE_TYPE_PAGE_DCB,
601
UIDIR "/ce-page-dcb.ui",
605
g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("Could not load DCB user interface."));
609
priv = CE_PAGE_DCB_GET_PRIVATE (self);
610
parent = CE_PAGE (self);
612
priv->enabled = GTK_TOGGLE_BUTTON (gtk_builder_get_object (parent->builder, "dcb_enabled_checkbutton"));
613
priv->box = GTK_BOX (gtk_builder_get_object (parent->builder, "dcb_box"));
615
s_dcb = nm_connection_get_setting_dcb (connection);
617
priv->initial_have_dcb = TRUE;
618
priv->options = (NMSettingDcb *) nm_setting_duplicate (NM_SETTING (s_dcb));
620
priv->options = (NMSettingDcb *) nm_setting_dcb_new ();
622
g_signal_connect (self, "initialized", G_CALLBACK (finish_setup), NULL);
624
return CE_PAGE (self);
628
ui_to_setting (CEPageDcb *self, NMSettingDcb *s_dcb)
630
CEPage *parent = CE_PAGE (self);
631
CEPageDcbPrivate *priv = CE_PAGE_DCB_GET_PRIVATE (self);
632
NMSettingDcbFlags flags = NM_SETTING_DCB_FLAG_NONE;
638
enabled = gtk_toggle_button_get_active (priv->enabled);
639
for (i = 0; i < G_N_ELEMENTS (features); i++) {
640
const Feature *f = &features[i];
642
flags = NM_SETTING_DCB_FLAG_NONE;
645
widget = get_widget (parent->builder, f->prefix, "_enable_checkbutton");
646
if (enabled && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
647
flags |= NM_SETTING_DCB_FLAG_ENABLE;
650
widget = get_widget (parent->builder, f->prefix, "_advertise_checkbutton");
651
if (enabled && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
652
flags |= NM_SETTING_DCB_FLAG_ADVERTISE;
655
widget = get_widget (parent->builder, f->prefix, "_willing_checkbutton");
656
if (enabled && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
657
flags |= NM_SETTING_DCB_FLAG_WILLING;
659
g_object_set (G_OBJECT (s_dcb), f->flags_prop, flags, NULL);
661
if (f->priority_prop) {
664
widget = get_widget (parent->builder, f->prefix, "_priority_combo");
666
idx = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
667
g_object_set (G_OBJECT (s_dcb), f->priority_prop, (gint) (idx - 1), NULL);
672
flags = nm_setting_dcb_get_app_fcoe_flags (s_dcb);
673
tmp = NM_SETTING_DCB_FCOE_MODE_FABRIC;
674
if (flags & NM_SETTING_DCB_FLAG_ENABLE) {
675
widget = get_widget (parent->builder, "fcoe", "_mode_combo");
676
num = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
678
tmp = NM_SETTING_DCB_FCOE_MODE_FABRIC;
680
tmp = NM_SETTING_DCB_FCOE_MODE_VN2VN;
682
g_assert_not_reached ();
684
g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_APP_FCOE_MODE, tmp, NULL);
686
/* Priority Flow Control */
687
flags = nm_setting_dcb_get_priority_flow_control_flags (s_dcb);
688
for (i = 0; i < 8; i++) {
690
if (flags & NM_SETTING_DCB_FLAG_ENABLE)
691
b = nm_setting_dcb_get_priority_flow_control (priv->options, i);
692
nm_setting_dcb_set_priority_flow_control (s_dcb, i, b);
695
/* Priority Groups */
696
flags = nm_setting_dcb_get_priority_group_flags (s_dcb);
697
for (i = 0; i < 8; i++) {
700
if (flags & NM_SETTING_DCB_FLAG_ENABLE)
701
num = nm_setting_dcb_get_priority_group_id (priv->options, i);
702
nm_setting_dcb_set_priority_group_id (s_dcb, i, num);
705
if (flags & NM_SETTING_DCB_FLAG_ENABLE)
706
num = nm_setting_dcb_get_priority_group_bandwidth (priv->options, i);
707
nm_setting_dcb_set_priority_group_bandwidth (s_dcb, i, num);
710
if (flags & NM_SETTING_DCB_FLAG_ENABLE)
711
num = nm_setting_dcb_get_priority_bandwidth (priv->options, i);
712
nm_setting_dcb_set_priority_bandwidth (s_dcb, i, num);
715
if (flags & NM_SETTING_DCB_FLAG_ENABLE)
716
b = nm_setting_dcb_get_priority_strict_bandwidth (priv->options, i);
717
nm_setting_dcb_set_priority_strict_bandwidth (s_dcb, i, b);
720
if (flags & NM_SETTING_DCB_FLAG_ENABLE)
721
num = nm_setting_dcb_get_priority_traffic_class (priv->options, i);
722
nm_setting_dcb_set_priority_traffic_class (s_dcb, i, num);
728
ce_page_validate_v (CEPage *page, NMConnection *connection, GError **error)
730
CEPageDcb *self = CE_PAGE_DCB (page);
731
CEPageDcbPrivate *priv = CE_PAGE_DCB_GET_PRIVATE (self);
734
if (!gtk_toggle_button_get_active (priv->enabled)) {
735
nm_connection_remove_setting (connection, NM_TYPE_SETTING_DCB);
739
s_dcb = nm_connection_get_setting_dcb (connection);
741
s_dcb = (NMSettingDcb *) nm_setting_dcb_new ();
742
nm_connection_add_setting (connection, NM_SETTING (s_dcb));
744
ui_to_setting (self, s_dcb);
746
return nm_setting_verify (NM_SETTING (s_dcb), NULL, error);
750
ce_page_dcb_init (CEPageDcb *self)
755
dispose (GObject *object)
757
CEPageDcbPrivate *priv = CE_PAGE_DCB_GET_PRIVATE (object);
759
g_clear_object (&priv->options);
761
G_OBJECT_CLASS (ce_page_dcb_parent_class)->dispose (object);
765
ce_page_dcb_class_init (CEPageDcbClass *security_class)
767
GObjectClass *object_class = G_OBJECT_CLASS (security_class);
768
CEPageClass *parent_class = CE_PAGE_CLASS (security_class);
770
g_type_class_add_private (object_class, sizeof (CEPageDcbPrivate));
772
/* virtual methods */
773
object_class->dispose = dispose;
775
parent_class->ce_page_validate_v = ce_page_validate_v;