/* Copyright (c) Citrix Systems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using XenAdmin.Network; using XenAPI; using XenAdmin.Core; using System.Collections; using System.Linq; namespace XenAdmin.Dialogs { public partial class VIFDialog : XenDialogBase { private VIF ExistingVif; private int Device; private readonly bool vSwitchController; private readonly bool allowSriov; public VIFDialog(IXenConnection Connection, VIF ExistingVif, int Device, bool allowSriov = false) : base(Connection) { InitializeComponent(); CueBannersManager.SetWatermark(promptTextBoxMac, "aa:bb:cc:dd:ee:ff"); this.ExistingVif = ExistingVif; this.Device = Device; if (ExistingVif != null) changeToPropertiesTitle(); this.allowSriov = allowSriov; // Check if vSwitch Controller is configured for the pool (CA-46299) Pool pool = Helpers.GetPoolOfOne(connection); vSwitchController = pool != null && pool.vSwitchController(); label1.Text = vSwitchController ? Messages.VIF_VSWITCH_CONTROLLER : Messages.VIF_LICENSE_RESTRICTION; LoadNetworks(); LoadDetails(); updateEnablement(); SetupEventHandlers(); } private void SetupEventHandlers() { promptTextBoxMac.GotFocus += new EventHandler(promptTextBoxMac_ReceivedFocus); promptTextBoxQoS.GotFocus += new EventHandler(promptTextBoxQoS_ReceivedFocus); promptTextBoxQoS.TextChanged += new EventHandler(promptTextBoxQoS_TextChanged); comboBoxNetwork.SelectedIndexChanged += new EventHandler(NetworkComboBox_SelectedIndexChanged); promptTextBoxMac.TextChanged += new EventHandler(promptTextBoxMac_TextChanged); } void promptTextBoxQoS_TextChanged(object sender, EventArgs e) { updateEnablement(); } void promptTextBoxQoS_ReceivedFocus(object sender, EventArgs e) { checkboxQoS.Checked = true; updateEnablement(); } void promptTextBoxMac_ReceivedFocus(object sender, EventArgs e) { radioButtonMac.Checked = true; updateEnablement(); } private void changeToPropertiesTitle() { this.Text = Messages.VIRTUAL_INTERFACE_PROPERTIES; this.buttonOk.Text = Messages.OK; } private void LoadDetails() { if (vSwitchController) { flowLayoutPanelQoS.Enabled = checkboxQoS.Enabled = checkboxQoS.Checked = false; panelLicenseRestriction.Visible = true; } else { if (ExistingVif == null) { promptTextBoxQoS.Text = ""; checkboxQoS.Checked = false; } else { promptTextBoxQoS.Text = ExistingVif.LimitString(); checkboxQoS.Checked = ExistingVif.qos_algorithm_type == VIF.RATE_LIMIT_QOS_VALUE; } flowLayoutPanelQoS.Enabled = checkboxQoS.Enabled = true; panelLicenseRestriction.Visible = false; } if (ExistingVif == null) { radioButtonAutogenerate.Checked = true; return; } foreach (NetworkComboBoxItem item in comboBoxNetwork.Items) { if (item.Network != null && item.Network.opaque_ref == ExistingVif.network.opaque_ref) comboBoxNetwork.SelectedItem = item; } promptTextBoxMac.Text = ExistingVif.MAC; if (!string.IsNullOrEmpty(ExistingVif.MAC)) radioButtonMac.Checked = true; else radioButtonAutogenerate.Checked = true; } void promptTextBoxMac_TextChanged(object sender, EventArgs e) { ValidateMACAddress(); } private void ValidateMACAddress() { if (MACAddressHasChanged() && !MACAddressIsAcceptable()) { MarkMACAsInvalid(); if (ExistingVif != null) promptTextBoxMac.Text = ExistingVif.MAC; return; } updateEnablement(); } private bool MACAddressHasChanged() { if (ExistingVif == null) return true; return promptTextBoxMac.Text != ExistingVif.MAC; } private void MarkMACAsInvalid() { buttonOk.Enabled = false; toolTipContainerOkButton.SetToolTip(Messages.MAC_INVALID); } private void updateEnablement() { if (!Helpers.IsValidMAC(promptTextBoxMac.Text) && !AutogenerateMac) { MarkMACAsInvalid(); } else if (comboBoxNetwork.SelectedItem == null || ((NetworkComboBoxItem)comboBoxNetwork.SelectedItem).Network == null) { buttonOk.Enabled = false; toolTipContainerOkButton.SetToolTip(Messages.SELECT_NETWORK_TOOLTIP); } else if (checkboxQoS.Checked && !isValidQoSLimit()) { buttonOk.Enabled = false; toolTipContainerOkButton.SetToolTip(Messages.ENTER_VALID_QOS); } else { buttonOk.Enabled = true; toolTipContainerOkButton.RemoveAll(); } } private void LoadNetworks() { List networks = new List(connection.Cache.Networks); networks.Sort(); foreach (XenAPI.Network network in networks) { if (!network.Show(Properties.Settings.Default.ShowHiddenVMs) || network.IsSlave() || (network.IsSriov() && !allowSriov)) continue; comboBoxNetwork.Items.Add(new NetworkComboBoxItem(network)); } if (comboBoxNetwork.Items.Count == 0) { comboBoxNetwork.Items.Add(new NetworkComboBoxItem(null)); } comboBoxNetwork.SelectedIndex = 0; } private void NetworkComboBox_SelectedIndexChanged(object sender, EventArgs e) { ValidateMACAddress(); updateEnablement(); } private XenAPI.Network SelectedNetwork { get { return ((NetworkComboBoxItem)comboBoxNetwork.SelectedItem).Network; } } private string SelectedMac { get { return AutogenerateMac ? "" : promptTextBoxMac.Text; } } private bool AutogenerateMac { get { return radioButtonAutogenerate.Checked; } } public VIF NewVif() { VIF vif = new VIF(); vif.Connection = connection; vif.network = new XenRef(SelectedNetwork.opaque_ref); vif.MAC = SelectedMac; vif.device = Device.ToString(); if (checkboxQoS.Checked) vif.qos_algorithm_type = VIF.RATE_LIMIT_QOS_VALUE; // preserve this param even if we have decided not to turn on qos if (!string.IsNullOrEmpty(promptTextBoxQoS.Text)) { Dictionary qos_algorithm_params = new Dictionary(); qos_algorithm_params.Add(VIF.KBPS_QOS_PARAMS_KEY, promptTextBoxQoS.Text); vif.qos_algorithm_params = qos_algorithm_params; } return vif; } /// /// Retrieves the new settings as a vif object. You will need to set the VM field to use these settings in a vif action /// /// public VIF GetNewSettings() { var newVif = new VIF(); if (ExistingVif != null) newVif.UpdateFrom(ExistingVif); newVif.network = new XenRef(SelectedNetwork.opaque_ref); newVif.MAC = SelectedMac; newVif.device = Device.ToString(); if (checkboxQoS.Checked) { newVif.qos_algorithm_type = VIF.RATE_LIMIT_QOS_VALUE; } else if (ExistingVif != null && ExistingVif.qos_algorithm_type == VIF.RATE_LIMIT_QOS_VALUE) { newVif.qos_algorithm_type = ""; } // else ... we leave it alone. Currently we only deal with "ratelimit" and "", don't overwrite the field if it's something else // preserve this param even if we turn off qos if (!string.IsNullOrEmpty(promptTextBoxQoS.Text)) newVif.qos_algorithm_params = new Dictionary { { VIF.KBPS_QOS_PARAMS_KEY, promptTextBoxQoS.Text } }; return newVif; } private bool ChangesHaveBeenMade { get { if (ExistingVif == null) return true; if (ExistingVif.network.opaque_ref != SelectedNetwork.opaque_ref) return true; if (ExistingVif.MAC != SelectedMac) return true; if (ExistingVif.device != Device.ToString()) return true; if (ExistingVif.qos_algorithm_type == VIF.RATE_LIMIT_QOS_VALUE) { if (!checkboxQoS.Checked) return true; if (ExistingVif.qos_algorithm_params[VIF.KBPS_QOS_PARAMS_KEY] != promptTextBoxQoS.Text) return true; } else if (string.IsNullOrEmpty(ExistingVif.qos_algorithm_type)) { if (checkboxQoS.Checked) return true; } return false; } } private void AutogenerateRadioButton_CheckedChanged(object sender, EventArgs e) { updateEnablement(); } private void MacRadioButton_CheckedChanged(object sender, EventArgs e) { updateEnablement(); } private ThreeButtonDialog MacAddressDuplicationWarningDialog(string macAddress, string vmName) { return new ThreeButtonDialog( new ThreeButtonDialog.Details(SystemIcons.Warning, String.Format(Messages.PROBLEM_MAC_ADDRESS_IS_DUPLICATE, macAddress, vmName).Replace("\\n", "\n"), Messages.PROBLEM_MAC_ADDRESS_IS_DUPLICATE_TITLE), new[] { new ThreeButtonDialog.TBDButton( Messages.YES_BUTTON_CAPTION, DialogResult.Yes), new ThreeButtonDialog.TBDButton( Messages.NO_BUTTON_CAPTION, DialogResult.No, ThreeButtonDialog.ButtonType.CANCEL, true) } ); } /// /// Determine if the MAC is accetable. It may not be if /// other VIFs have the same MAC address as entered /// /// If the MAC address entered is acceptable private bool MACAddressIsAcceptable() { foreach (var xenConnection in ConnectionsManager.XenConnectionsCopy.Where(c => c.IsConnected)) { foreach (VIF vif in xenConnection.Cache.VIFs) { var vm = xenConnection.Resolve(vif.VM); if (vif != ExistingVif && vif.MAC == SelectedMac && vm != null && vm.is_a_real_vm()) { DialogResult result; using (var dlg = MacAddressDuplicationWarningDialog(SelectedMac, vm.NameWithLocation())) { result = dlg.ShowDialog(Program.MainWindow); } return (result == DialogResult.Yes); } } } return true; } private void Okbutton_Click(object sender, EventArgs e) { DialogResult = !ChangesHaveBeenMade ? DialogResult.Cancel : DialogResult.OK; Close(); } private void Cancelbutton_Click(object sender, EventArgs e) { DialogResult = DialogResult.Cancel; Close(); } private bool isValidQoSLimit() { if (!checkboxQoS.Checked) { return true; } string value = promptTextBoxQoS.Text; if (value == null || value.Trim().Length == 0) return false; Int32 result; if (Int32.TryParse(value, out result)) { return result > 0; } else { return false; } } private void checkboxQoS_CheckedChanged(object sender, EventArgs e) { updateEnablement(); } internal override string HelpName { get { if (ExistingVif != null) return "EditVmNetworkSettingsDialog"; else return "VIFDialog"; } } } public class NetworkComboBoxItem : IEquatable { public XenAPI.Network Network; public NetworkComboBoxItem(XenAPI.Network network) { Network = network; } public override string ToString() { return Network == null ? Messages.NONE : Helpers.GetName(Network); } public bool Equals(NetworkComboBoxItem other) { if (Network == null) return other.Network == null; return Network.Equals(other.Network); } } }