1
0
mirror of https://github.com/GNS3/gns3-server synced 2024-11-24 17:28:08 +00:00

Allow up to 275 adapters for qemu

See #889 for more details
This commit is contained in:
Julien Duponchelle 2017-02-07 17:04:29 +01:00
parent 5e02a9d450
commit b0567772f7
No known key found for this signature in database
GPG Key ID: CE8B29639E07F5E8
3 changed files with 53 additions and 7 deletions

View File

@ -23,12 +23,13 @@ order to run a QEMU VM.
import sys import sys
import os import os
import re import re
import math
import shutil import shutil
import subprocess
import shlex import shlex
import asyncio import asyncio
import socket import socket
import gns3server import gns3server
import subprocess
from gns3server.utils import parse_version from gns3server.utils import parse_version
from .qemu_error import QemuError from .qemu_error import QemuError
@ -1446,6 +1447,14 @@ class QemuVM(BaseNode):
# this is a patched Qemu if version is below 1.1.0 # this is a patched Qemu if version is below 1.1.0
patched_qemu = True patched_qemu = True
# Each 32 PCI device we need to add a PCI bridge with max 9 bridges
pci_devices = 4 + len(self._ethernet_adapters) # 4 PCI devices are use by default by qemu
bridge_id = 0
for bridge_id in range(1, math.floor(pci_devices / 32) + 1):
network_options.extend(["-device", "i82801b11-bridge,id=dmi_pci_bridge{bridge_id}".format(bridge_id=bridge_id)])
network_options.extend(["-device", "pci-bridge,id=pci-bridge{bridge_id},bus=dmi_pci_bridge{bridge_id},chassis_nr=0x1,addr=0x{bridge_id},shpc=off".format(bridge_id=bridge_id)])
pci_device_id = 4 + bridge_id # Bridge consume PCI ports
for adapter_number, adapter in enumerate(self._ethernet_adapters): for adapter_number, adapter in enumerate(self._ethernet_adapters):
mac = int_to_macaddress(macaddress_to_int(self._mac_address) + adapter_number) mac = int_to_macaddress(macaddress_to_int(self._mac_address) + adapter_number)
@ -1483,8 +1492,14 @@ class QemuVM(BaseNode):
else: else:
# newer QEMU networking syntax # newer QEMU networking syntax
device_string = "{},mac={}".format(self._adapter_type, mac)
bridge_id = math.floor(pci_device_id / 32)
if bridge_id > 0:
addr = pci_device_id % 32
device_string = "{},bus=pci-bridge{bridge_id},addr=0x{addr:02x}".format(device_string, bridge_id=bridge_id, addr=addr)
pci_device_id += 1
if nio: if nio:
network_options.extend(["-device", "{},mac={},netdev=gns3-{}".format(self._adapter_type, mac, adapter_number)]) network_options.extend(["-device", "{},netdev=gns3-{}".format(device_string, adapter_number)])
if isinstance(nio, NIOUDP): if isinstance(nio, NIOUDP):
network_options.extend(["-netdev", "socket,id=gns3-{},udp={}:{},localaddr={}:{}".format(adapter_number, network_options.extend(["-netdev", "socket,id=gns3-{},udp={}:{},localaddr={}:{}".format(adapter_number,
nio.rhost, nio.rhost,
@ -1494,7 +1509,7 @@ class QemuVM(BaseNode):
elif isinstance(nio, NIOTAP): elif isinstance(nio, NIOTAP):
network_options.extend(["-netdev", "tap,id=gns3-{},ifname={},script=no,downscript=no".format(adapter_number, nio.tap_device)]) network_options.extend(["-netdev", "tap,id=gns3-{},ifname={},script=no,downscript=no".format(adapter_number, nio.tap_device)])
else: else:
network_options.extend(["-device", "{},mac={}".format(self._adapter_type, mac)]) network_options.extend(["-device", device_string])
return network_options return network_options

View File

@ -147,7 +147,7 @@ QEMU_CREATE_SCHEMA = {
"description": "Number of adapters", "description": "Number of adapters",
"type": ["integer", "null"], "type": ["integer", "null"],
"minimum": 0, "minimum": 0,
"maximum": 32, "maximum": 275,
}, },
"adapter_type": { "adapter_type": {
"description": "QEMU adapter type", "description": "QEMU adapter type",
@ -332,7 +332,7 @@ QEMU_UPDATE_SCHEMA = {
"description": "Number of adapters", "description": "Number of adapters",
"type": ["integer", "null"], "type": ["integer", "null"],
"minimum": 0, "minimum": 0,
"maximum": 32, "maximum": 275,
}, },
"adapter_type": { "adapter_type": {
"description": "QEMU adapter type", "description": "QEMU adapter type",
@ -520,7 +520,7 @@ QEMU_OBJECT_SCHEMA = {
"description": "Number of adapters", "description": "Number of adapters",
"type": "integer", "type": "integer",
"minimum": 0, "minimum": 0,
"maximum": 32, "maximum": 275,
}, },
"adapter_type": { "adapter_type": {
"description": "QEMU adapter type", "description": "QEMU adapter type",

View File

@ -588,7 +588,7 @@ def test_build_command_two_adapters_mac_address(vm, loop, fake_qemu_binary, port
vm.adapters = 2 vm.adapters = 2
vm.mac_address = "00:00:ab:0e:0f:09" vm.mac_address = "00:00:ab:0e:0f:09"
mac_0 = vm._mac_address mac_0 = vm._mac_address
mac_1 = int_to_macaddress(macaddress_to_int(vm._mac_address)) mac_1 = int_to_macaddress(macaddress_to_int(vm._mac_address) + 1)
assert mac_0[:8] == "00:00:ab" assert mac_0[:8] == "00:00:ab"
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process: with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process:
cmd = loop.run_until_complete(asyncio.async(vm._build_command())) cmd = loop.run_until_complete(asyncio.async(vm._build_command()))
@ -605,6 +605,37 @@ def test_build_command_two_adapters_mac_address(vm, loop, fake_qemu_binary, port
assert "e1000,mac={}".format(mac_1) in cmd assert "e1000,mac={}".format(mac_1) in cmd
def test_build_command_large_number_of_adapters(vm, loop, fake_qemu_binary, port_manager):
"""
When we have more than 28 interface we need to add a pci bridge for
additionnal interfaces
"""
vm.adapters = 100
vm.mac_address = "00:00:ab:0e:0f:09"
mac_0 = vm._mac_address
mac_1 = int_to_macaddress(macaddress_to_int(vm._mac_address) + 1)
assert mac_0[:8] == "00:00:ab"
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process:
cmd = loop.run_until_complete(asyncio.async(vm._build_command()))
assert "e1000,mac={}".format(mac_0) in cmd
assert "e1000,mac={}".format(mac_1) in cmd
assert "pci-bridge,id=pci-bridge0,bus=dmi_pci_bridge0,chassis_nr=0x1,addr=0x0,shpc=off" not in cmd
assert "pci-bridge,id=pci-bridge1,bus=dmi_pci_bridge1,chassis_nr=0x1,addr=0x1,shpc=off" in cmd
assert "pci-bridge,id=pci-bridge2,bus=dmi_pci_bridge2,chassis_nr=0x1,addr=0x2,shpc=off" in cmd
assert "i82801b11-bridge,id=dmi_pci_bridge1" in cmd
print(cmd)
mac_29 = int_to_macaddress(macaddress_to_int(vm._mac_address) + 29)
assert "e1000,mac={},bus=pci-bridge1,addr=0x04".format(mac_29) in cmd
mac_30 = int_to_macaddress(macaddress_to_int(vm._mac_address) + 30)
assert "e1000,mac={},bus=pci-bridge1,addr=0x05".format(mac_30) in cmd
mac_74 = int_to_macaddress(macaddress_to_int(vm._mac_address) + 74)
assert "e1000,mac={},bus=pci-bridge2,addr=0x11".format(mac_74) in cmd
# Windows accept this kind of mistake # Windows accept this kind of mistake
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows") @pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
def test_build_command_with_invalid_options(vm, loop, fake_qemu_binary): def test_build_command_with_invalid_options(vm, loop, fake_qemu_binary):