diff --git a/src/fireedge/etc/sunstone/profiles/base.template b/src/fireedge/etc/sunstone/profiles/base.template index 34c10e31997..f0d6790dd53 100644 --- a/src/fireedge/etc/sunstone/profiles/base.template +++ b/src/fireedge/etc/sunstone/profiles/base.template @@ -133,6 +133,8 @@ SHORT_ADDRESS: "123ABC" SSH: "Yes" VIRTIO_QUEUES: 8 + VIRTIO_RX_QUEUE_SIZE: 256 + VIRTIO_TX_QUEUE_SIZE: 256 TYPE: "NIC" OsCpu: diff --git a/src/fireedge/src/modules/constants/translates.js b/src/fireedge/src/modules/constants/translates.js index d83be0f6310..3a6945bab0d 100644 --- a/src/fireedge/src/modules/constants/translates.js +++ b/src/fireedge/src/modules/constants/translates.js @@ -2379,6 +2379,10 @@ gpgkey=https://downloads.opennebula.io/repo/repo2.key...`, OnlySupportedForVirtioDriver: 'Only supported for virtio driver', AutoVirtioQueues: 'Set Transmission Queues automatically based on the number of vCPUs', + VirtioRxQueueSize: 'RX queue size', + VirtioTxQueueSize: 'TX queue size', + VirtioQueueSizeConcept: + 'Only supported for virtio driver. If set, must be a power of 2', GuestOptions: 'Guest options', GuestMTU: 'MTU of the Guest interfaces', GuestMTUConcept: 'Sets the MTU for the NICs in this network', @@ -2916,6 +2920,7 @@ gpgkey=https://downloads.opennebula.io/repo/repo2.key...`, 'validation.number.isDivisible': 'Should be divisible by %s', 'validation.number.isFinite': 'Must be a valid number', 'validation.number.isFloat': 'Must be a floating point number', + MustBePowerOfTwo: 'Must be a power of 2', /* Validation - date */ 'validation.date.min': 'Must be later than %s', 'validation.date.max': 'Must be at earlier than %s', diff --git a/src/fireedge/src/modules/resources/VirtualMachine/Forms/AttachNicForm/Steps/AdvancedOptions/schema.js b/src/fireedge/src/modules/resources/VirtualMachine/Forms/AttachNicForm/Steps/AdvancedOptions/schema.js index 9ab39bb82d4..29e9aa74869 100644 --- a/src/fireedge/src/modules/resources/VirtualMachine/Forms/AttachNicForm/Steps/AdvancedOptions/schema.js +++ b/src/fireedge/src/modules/resources/VirtualMachine/Forms/AttachNicForm/Steps/AdvancedOptions/schema.js @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { boolean, string, ObjectSchema } from 'yup' +import { boolean, number, string, ObjectSchema } from 'yup' import { AlertNotification } from '@ComponentsModule' import { uniqWith } from 'lodash' @@ -31,6 +31,19 @@ import { HostAPI } from '@FeaturesModule' const filterByHypAndDriver = (fields, { hypervisor, driver }) => filterFieldsByDriver(filterFieldsByHypervisor(fields, hypervisor), driver) +/** @type {(value: number) => boolean} Whether a number is a power of 2 */ +const isPowerOfTwo = (value) => + Number.isInteger(value) && value > 0 && (value & (value - 1)) === 0 + +/** + * @param {ObjectSchema} schema - Number schema to attach the test to + * @returns {ObjectSchema} Schema requiring a power-of-2 value, if set + */ +const validatePowerOfTwo = (schema) => + schema.test('power-of-two', T.MustBePowerOfTwo, (value) => + value === undefined ? true : isPowerOfTwo(value) + ) + const isNicPciDevice = (device) => device?.CLASS?.startsWith('02') const getPciRowId = (row) => { @@ -674,6 +687,46 @@ const SECTIONS = ({ .afterSubmit(() => undefined), grid: { md: 1.5 }, }, + { + name: 'VIRTIO_RX_QUEUE_SIZE', + label: T.VirtioRxQueueSize, + tooltip: T.VirtioQueueSizeConcept, + type: INPUT_TYPES.TEXT, + htmlType: ([pciType, , networkMode] = []) => + pciType !== 'emulated' && + networkMode !== 'dummy' && + INPUT_TYPES.HIDDEN, + dependOf: ['PCI_TYPE', 'AUTO_VIRTIO_QUEUES', 'NETWORK_MODE'], + fieldProps: { + disabled: hasAlias || isAlias, + }, + validation: validatePowerOfTwo( + number() + .notRequired() + .default(() => undefined) + ), + grid: { md: 6 }, + }, + { + name: 'VIRTIO_TX_QUEUE_SIZE', + label: T.VirtioTxQueueSize, + tooltip: T.VirtioQueueSizeConcept, + type: INPUT_TYPES.TEXT, + htmlType: ([pciType, , networkMode] = []) => + pciType !== 'emulated' && + networkMode !== 'dummy' && + INPUT_TYPES.HIDDEN, + dependOf: ['PCI_TYPE', 'AUTO_VIRTIO_QUEUES', 'NETWORK_MODE'], + fieldProps: { + disabled: hasAlias || isAlias, + }, + validation: validatePowerOfTwo( + number() + .notRequired() + .default(() => undefined) + ), + grid: { md: 6 }, + }, ] } diff --git a/src/mad/sh/scripts_common.sh b/src/mad/sh/scripts_common.sh index 45ec81659d0..d5b7ed5158b 100644 --- a/src/mad/sh/scripts_common.sh +++ b/src/mad/sh/scripts_common.sh @@ -1284,6 +1284,8 @@ function get_disk_information { # * IP # * FILTER # * VIRTIO_QUEUES +# * VIRTIO_RX_QUEUE_SIZE +# * VIRTIO_TX_QUEUE_SIZE # * VROUTER_IP # * INBOUND_AVG_BW # * INBOUND_PEAK_BW @@ -1318,6 +1320,8 @@ function get_nic_information { $NIC_XPATH/IP \ $NIC_XPATH/FILTER \ $NIC_XPATH/VIRTIO_QUEUES \ + $NIC_XPATH/VIRTIO_RX_QUEUE_SIZE \ + $NIC_XPATH/VIRTIO_TX_QUEUE_SIZE \ $NIC_XPATH/VROUTER_IP \ $NIC_XPATH/INBOUND_AVG_BW \ $NIC_XPATH/INBOUND_PEAK_BW \ @@ -1339,6 +1343,8 @@ function get_nic_information { IP="${XPATH_ELEMENTS[j++]}" FILTER="${XPATH_ELEMENTS[j++]}" VIRTIO_QUEUES="${XPATH_ELEMENTS[j++]}" + VIRTIO_RX_QUEUE_SIZE="${XPATH_ELEMENTS[j++]}" + VIRTIO_TX_QUEUE_SIZE="${XPATH_ELEMENTS[j++]}" VROUTER_IP="${XPATH_ELEMENTS[j++]}" INBOUND_AVG_BW="${XPATH_ELEMENTS[j++]}" INBOUND_PEAK_BW="${XPATH_ELEMENTS[j++]}" diff --git a/src/vmm/LibVirtDriverKVM.cc b/src/vmm/LibVirtDriverKVM.cc index 9d778793c90..05bbce6c588 100644 --- a/src/vmm/LibVirtDriverKVM.cc +++ b/src/vmm/LibVirtDriverKVM.cc @@ -691,6 +691,8 @@ int LibVirtDriver::deployment_description_kvm( string vrouter_ip; string filter; string virtio_queues; + string virtio_rx_queue_size; + string virtio_tx_queue_size; string bridge_type; string net_mode; string nic_id; @@ -705,6 +707,8 @@ int LibVirtDriver::deployment_description_kvm( string default_filter; string default_model; string default_virtio_queues; + string default_virtio_rx_queue_size; + string default_virtio_tx_queue_size; const VectorAttribute * graphics; @@ -1900,6 +1904,10 @@ int LibVirtDriver::deployment_description_kvm( get_attribute(nullptr, host, cluster, "NIC", "VIRTIO_QUEUES", default_virtio_queues); + get_attribute(nullptr, host, cluster, "NIC", "VIRTIO_RX_QUEUE_SIZE", default_virtio_rx_queue_size); + + get_attribute(nullptr, host, cluster, "NIC", "VIRTIO_TX_QUEUE_SIZE", default_virtio_tx_queue_size); + num = vm->get_template_attribute("NIC", nic); for (int i=0; ivector_value("IP"); filter = nic[i]->vector_value("FILTER"); virtio_queues = nic[i]->vector_value("VIRTIO_QUEUES"); + virtio_rx_queue_size = nic[i]->vector_value("VIRTIO_RX_QUEUE_SIZE"); + virtio_tx_queue_size = nic[i]->vector_value("VIRTIO_TX_QUEUE_SIZE"); + order = nic[i]->vector_value("ORDER"); bridge_type = nic[i]->vector_value("BRIDGE_TYPE"); net_mode = nic[i]->vector_value("NETWORK_MODE"); @@ -2008,11 +2019,34 @@ int LibVirtDriver::deployment_description_kvm( virtio_queues = default_virtio_queues; } - if (!virtio_queues.empty() && *the_model == "virtio") + if (virtio_rx_queue_size.empty() && !default_virtio_rx_queue_size.empty()) + { + virtio_rx_queue_size = default_virtio_rx_queue_size; + } + + if (virtio_tx_queue_size.empty() && !default_virtio_tx_queue_size.empty()) + { + virtio_tx_queue_size = default_virtio_tx_queue_size; + } + + if ((!virtio_queues.empty() || !virtio_rx_queue_size.empty() || !virtio_tx_queue_size.empty()) + && *the_model == "virtio") { - file << "\t\t\t\n"; + file << "\t\t\t\n"; } } diff --git a/src/vmm_mad/remotes/lib/kvm/opennebula_vm.rb b/src/vmm_mad/remotes/lib/kvm/opennebula_vm.rb index aad84236d44..8cca8bb9a82 100644 --- a/src/vmm_mad/remotes/lib/kvm/opennebula_vm.rb +++ b/src/vmm_mad/remotes/lib/kvm/opennebula_vm.rb @@ -521,6 +521,12 @@ def interface_xml virtio_queues = @xml['TEMPLATE/VCPU'] || '1' if virtio_queues == 'auto' virtio_queues.encode!(:xml => :attr) unless virtio_queues.empty? + virtio_rx_queue_size = @xml["#{@xpath_prefix}VIRTIO_RX_QUEUE_SIZE"] + virtio_rx_queue_size.encode!(:xml => :attr) unless virtio_rx_queue_size.empty? + + virtio_tx_queue_size = @xml["#{@xpath_prefix}VIRTIO_TX_QUEUE_SIZE"] + virtio_tx_queue_size.encode!(:xml => :attr) unless virtio_tx_queue_size.empty? + filter = @xml["#{@xpath_prefix}FILTER"] filter = env('DEFAULT_ATTACH_NIC_FILTER') if filter.empty? filter.encode!(:xml => :attr) unless filter.empty? @@ -557,8 +563,19 @@ def interface_xml dev << xputs('', 'ORDER') dev << "" unless model.empty? - if model == '"virtio"' && !virtio_queues.empty? - dev << "" + if model == '"virtio"' && + (!virtio_queues.empty? || !virtio_rx_queue_size.empty? || !virtio_tx_queue_size.empty?) + dev << "" end if exist?('IP') && !filter.empty?