mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-06 15:21:13 +02:00
Merge branch '3.1' into 3.1
This commit is contained in:
51 files changed
+3155
-183
No files matched your search
@@ -14,15 +14,18 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from enum import StrEnum
|
||||
import re
|
||||
from enum import Enum
|
||||
from typing import List, Optional, Union
|
||||
from uuid import UUID
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import BaseModel, Field, model_validator
|
||||
|
||||
from ..common import NodeStatus
|
||||
from ..update import PartialUpdateModel
|
||||
|
||||
LINUX_TAP_NAME_PATTERN = r"^[a-zA-Z0-9_.:-]{1,15}$"
|
||||
|
||||
|
||||
class HostInterfaceType(StrEnum):
|
||||
ethernet = "ethernet"
|
||||
@@ -57,6 +60,7 @@ class HostInterface(BaseModel):
|
||||
name: str = Field(..., description="Interface name")
|
||||
type: HostInterfaceType = Field(..., description="Interface type")
|
||||
special: bool = Field(..., description="Whether the interface is non standard")
|
||||
is_bridge: bool = Field(False, description="Whether this is a Linux bridge")
|
||||
ip_addresses: List[HostInterfaceIPAddress] = Field(
|
||||
default_factory=list, description="All IPv4 and IPv6 addresses on this interface"
|
||||
)
|
||||
@@ -94,6 +98,19 @@ class TAPPort(BaseModel):
|
||||
port_number: int
|
||||
type: TAPType
|
||||
interface: str
|
||||
bridge: Optional[str] = Field(
|
||||
None,
|
||||
min_length=1,
|
||||
max_length=15,
|
||||
pattern=LINUX_TAP_NAME_PATTERN,
|
||||
description="Existing Linux bridge to attach the TAP to",
|
||||
)
|
||||
|
||||
@model_validator(mode="after")
|
||||
def validate_bridged_interface(self):
|
||||
if self.bridge and not re.fullmatch(LINUX_TAP_NAME_PATTERN, self.interface):
|
||||
raise ValueError("A bridged TAP name must be 1-15 letters, digits, underscores, dots, colons or hyphens")
|
||||
return self
|
||||
|
||||
|
||||
class UDPType(StrEnum):
|
||||
|
||||
@@ -73,6 +73,26 @@ class BridgeNIOType(StrEnum):
|
||||
bridge = "nio_bridge"
|
||||
|
||||
|
||||
class BridgeVxlan(BaseModel):
|
||||
"""
|
||||
VXLAN tunnel spec carried by a cross-compute BridgeNIO. Each endpoint
|
||||
creates one VXLAN device (uBridge ``vxlan create``) and enslaves it into
|
||||
the link's per-link kernel bridge next to the node's anchor; the kernel
|
||||
encapsulates/decapsulates the frames. The controller derives the name
|
||||
and VNI (utils.vxlan) and resolves the peer address, so both endpoints
|
||||
agree on the VNI without ever talking to each other.
|
||||
|
||||
The device's MTU is derived by the kernel from the underlay interface
|
||||
the route to ``remote`` picks (MTU - 50 for the outer headers), which is
|
||||
what the link's bridge then reports as "what this fabric can carry".
|
||||
"""
|
||||
|
||||
name: str = Field(..., max_length=15, description="VXLAN device name on this endpoint's host (IFNAMSIZ-1)")
|
||||
vni: int = Field(..., ge=1, le=16777215, description="VXLAN network identifier, identical on both endpoints")
|
||||
remote: str = Field(..., description="Peer compute's address (unicast tunnel endpoint)")
|
||||
dstport: int = Field(..., ge=1, le=65535, description="UDP destination port, identical on both endpoints")
|
||||
|
||||
|
||||
class BridgeNIO(BaseModel):
|
||||
"""
|
||||
Kernel-datapath bridge Network Input/Output properties. The NIO tells the
|
||||
@@ -99,6 +119,11 @@ class BridgeNIO(BaseModel):
|
||||
description="Kernel bridge name e.g. gns3a1b2c3d4e5; None when an Ethernet switch "
|
||||
"owns the anchor's bridge membership (absorbed link)",
|
||||
)
|
||||
vxlan: Optional[BridgeVxlan] = Field(
|
||||
None,
|
||||
description="Cross-compute tunnel: the VXLAN device this end creates and enslaves into the bridge "
|
||||
"next to the anchor; absent for same-host kernel links",
|
||||
)
|
||||
suspend: Optional[bool] = Field(None, description="Suspend the NIO")
|
||||
filters: Optional[dict] = Field(
|
||||
None,
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from enum import StrEnum
|
||||
from typing import List, Optional
|
||||
from enum import Enum
|
||||
from typing import List, Literal, Optional
|
||||
from uuid import UUID
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
@@ -152,6 +152,9 @@ class QemuDiskInterfaceType(StrEnum):
|
||||
none = "none"
|
||||
|
||||
|
||||
QemuCdromInterface = Literal["ide", "sata"]
|
||||
|
||||
|
||||
class QemuBase(BaseModel):
|
||||
"""
|
||||
Common Qemu node properties.
|
||||
@@ -183,8 +186,12 @@ class QemuBase(BaseModel):
|
||||
hdd_disk_image_backing_file: Optional[str] = Field(None, description="QEMU hdd backing file disk image path")
|
||||
hdd_disk_image_md5sum: Optional[str] = Field(None, description="QEMU hdd disk image checksum")
|
||||
hdd_disk_interface: Optional[QemuDiskInterfaceType] = Field(None, description="QEMU hdd interface")
|
||||
cdrom_image: Optional[str] = Field(None, description="QEMU cdrom image path")
|
||||
cdrom_image_md5sum: Optional[str] = Field(None, description="QEMU cdrom image checksum")
|
||||
cdrom_image: Optional[str] = Field(None, description="QEMU first cdrom image path")
|
||||
cdrom_interface: QemuCdromInterface = Field("ide", description="First CD/DVD interface")
|
||||
cdrom2_interface: QemuCdromInterface = Field("ide", description="Second CD/DVD interface")
|
||||
cdrom2_image: Optional[str] = Field(None, description="QEMU second cdrom image path")
|
||||
cdrom_image_md5sum: Optional[str] = Field(None, description="QEMU first cdrom image checksum")
|
||||
cdrom2_image_md5sum: Optional[str] = Field(None, description="QEMU second cdrom image checksum")
|
||||
bios_image: Optional[str] = Field(None, description="QEMU bios image path")
|
||||
bios_image_md5sum: Optional[str] = Field(None, description="QEMU bios image checksum")
|
||||
initrd: Optional[str] = Field(None, description="QEMU initrd path")
|
||||
|
||||
@@ -192,6 +192,23 @@ class ServerSettings(BaseModel):
|
||||
"or QEMU when the compute's uBridge supports persistent TAPs) through kernel interfaces instead "
|
||||
"of the uBridge UDP relay",
|
||||
)
|
||||
enable_vxlan_cross_compute: bool = Field(
|
||||
False,
|
||||
description="Wire eligible cross-compute links through kernel VXLAN tunnels (one device per endpoint, "
|
||||
"uBridge's vxlan module) instead of the uBridge UDP relay. The kernel encapsulates/decapsulates, so "
|
||||
"no user-space forwarding is involved; the price is MTU: a tunnel can only carry the underlay MTU "
|
||||
"minus 50 bytes of outer headers, so enable this where the fabric between computes carries jumbo "
|
||||
"frames. The relay stays the default and the fallback when a tunnel cannot be wired",
|
||||
)
|
||||
vxlan_dstport: int = Field(
|
||||
4789,
|
||||
ge=1,
|
||||
le=65535,
|
||||
description="UDP destination port every cross-compute VXLAN tunnel listens on. The kernel shares one "
|
||||
"socket per port across all VXLAN devices, so all links of a deployment ride this one port — the "
|
||||
"IANA-assigned VXLAN port by default. Change it when other VXLAN software on the computes already "
|
||||
"listens on it: a shared socket merges their demux table with ours",
|
||||
)
|
||||
auto_discover_images: bool = Field(True, description="Automatically discover images in the images directory")
|
||||
image_sync_interval: int = Field(900, ge=10, description="Seconds between automatic image inventory scans")
|
||||
report_errors: bool = Field(True, description="Automatically send crash reports to the GNS3 team")
|
||||
|
||||
@@ -23,6 +23,7 @@ from uuid import UUID
|
||||
from pydantic import AnyUrl, BaseModel, BeforeValidator, Discriminator, EmailStr, Field, Tag
|
||||
|
||||
from ..common import ExtraConfig
|
||||
from ..compute.qemu_nodes import QemuCdromInterface
|
||||
|
||||
# ============================================================================
|
||||
# Shared Enums
|
||||
@@ -398,6 +399,8 @@ class Qemu(BaseModel):
|
||||
hdc_disk_interface: Optional[QemuDiskInterface] = Field(
|
||||
None, title="Disk interface for the installed hdc_disk_image"
|
||||
)
|
||||
cdrom_interface: Optional[QemuCdromInterface] = Field(None, title="First CD/DVD interface")
|
||||
cdrom2_interface: Optional[QemuCdromInterface] = Field(None, title="Second CD/DVD interface")
|
||||
hdd_disk_interface: Optional[QemuDiskInterface] = Field(
|
||||
None, title="Disk interface for the installed hdd_disk_image"
|
||||
)
|
||||
@@ -425,7 +428,8 @@ class ApplianceVersionImages(BaseModel):
|
||||
hdb_disk_image: Optional[str] = Field(None, title="Hdc disk image")
|
||||
hdc_disk_image: Optional[str] = Field(None, title="Hdd disk image")
|
||||
hdd_disk_image: Optional[str] = Field(None, title="Hdd diskimage")
|
||||
cdrom_image: Optional[str] = Field(None, title="cdrom image")
|
||||
cdrom_image: Optional[str] = Field(None, title="First cdrom image")
|
||||
cdrom2_image: Optional[str] = Field(None, title="Second cdrom image")
|
||||
|
||||
|
||||
class ApplianceVersion(BaseModel):
|
||||
@@ -578,6 +582,8 @@ class QemuPropertiesV8(BaseModel):
|
||||
hdc_disk_interface: Optional[QemuDiskInterface] = Field(
|
||||
None, title="Disk interface for the installed hdc_disk_image"
|
||||
)
|
||||
cdrom_interface: Optional[QemuCdromInterface] = Field(None, title="First CD/DVD interface")
|
||||
cdrom2_interface: Optional[QemuCdromInterface] = Field(None, title="Second CD/DVD interface")
|
||||
hdd_disk_interface: Optional[QemuDiskInterface] = Field(
|
||||
None, title="Disk interface for the installed hdd_disk_image"
|
||||
)
|
||||
|
||||
@@ -73,3 +73,8 @@ class Capabilities(BaseModel):
|
||||
"keeps the guest from auto-configuring the host side of the anchor TAP); absent when the "
|
||||
"probe failed",
|
||||
)
|
||||
ubridge_vxlan: Optional[bool] = Field(
|
||||
None,
|
||||
description="Whether uBridge can create VXLAN devices (the vxlan module, kernel support included) — "
|
||||
"the tunnel a cross-compute kernel link rides; absent when the probe failed",
|
||||
)
|
||||
@@ -37,6 +37,9 @@ class ImageBase(BaseModel):
|
||||
|
||||
filename: str = Field(..., description="Image filename")
|
||||
path: str = Field(..., description="Image path")
|
||||
reference: Optional[str] = Field(
|
||||
None, description="Image reference relative to its emulator directory, or an absolute additional-root path"
|
||||
)
|
||||
image_type: ImageType = Field(..., description="Image type")
|
||||
image_size: int = Field(..., description="Image size in bytes")
|
||||
checksum: str = Field(..., description="Checksum value")
|
||||
|
||||
@@ -29,6 +29,9 @@ class ReplaySource(BaseModel):
|
||||
marker: str
|
||||
data_link_type: str
|
||||
count: int = Field(..., description="Total frames in the capture, unaffected by filters")
|
||||
error: Optional[str] = Field(
|
||||
None, description="Set when the capture file could not be fetched from the compute hosting it"
|
||||
)
|
||||
|
||||
|
||||
class ReplayFrame(BaseModel):
|
||||
|
||||
@@ -23,6 +23,7 @@ from gns3server.schemas.compute.qemu_nodes import (
|
||||
CustomAdapter,
|
||||
QemuAdapterType,
|
||||
QemuBootPriority,
|
||||
QemuCdromInterface,
|
||||
QemuConsoleType,
|
||||
QemuDiskInterfaceType,
|
||||
QemuOnCloseAction,
|
||||
@@ -79,7 +80,10 @@ class QemuTemplate(TemplateBase):
|
||||
hdd_disk_interface: Optional[QemuDiskInterfaceType] = Field(
|
||||
QemuDiskInterfaceType.none, description="QEMU hdd interface"
|
||||
)
|
||||
cdrom_image: Optional[str] = Field("", description="QEMU cdrom image path")
|
||||
cdrom_image: Optional[str] = Field("", description="QEMU first cdrom image path")
|
||||
cdrom_interface: QemuCdromInterface = Field("ide", description="First CD/DVD interface")
|
||||
cdrom2_interface: QemuCdromInterface = Field("ide", description="Second CD/DVD interface")
|
||||
cdrom2_image: Optional[str] = Field("", description="QEMU second cdrom image path")
|
||||
initrd: Optional[str] = Field("", description="QEMU initrd path")
|
||||
kernel_image: Optional[str] = Field("", description="QEMU kernel image path")
|
||||
bios_image: Optional[str] = Field("", description="QEMU bios image path")
|
||||
|
||||
Reference in new issue
Block a user