This is an automated email from the ASF dual-hosted git repository.
wido pushed a commit to branch direct-routed-network
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/direct-routed-network by this
push:
new 8275a0c3c61 Direct Routed networks: DefaultL3NetworkOffering and
ROUTED in the remaining UI form
8275a0c3c61 is described below
commit 8275a0c3c6172c40e73ef92e61aeea11d7f30369
Author: Wido den Hollander <[email protected]>
AuthorDate: Sat Sep 5 10:35:04 2026 +0000
Direct Routed networks: DefaultL3NetworkOffering and ROUTED in the
remaining UI form
Add a default network offering for Direct Routed (L3) guest networks,
DefaultL3NetworkOffering: UserData and DNS via ConfigDrive, Security
Groups enabled - the only service set validateL3NetworkOffering()
permits. It is created in NetworkOrchestrator.configure() like the
other default offerings, so it appears on fresh installs and on
upgrades alike; until now the operator had to create it by hand.
The routed id is allocated from the ROUTED physical network's range
(no specifyVlan).
UI: the ROUTED isolation method was selectable in the zone wizard and
in the infrastructure listing's add-physical-network form, but missing
from the form on a zone's Physical Networks tab - add it there. Give
the VLAN, VXLAN and ROUTED options hover descriptions explaining what
each isolation method does, so operators understand what they are
opting into; ROUTED's spells out the Direct Routed model (no VLANs on
the wire, no Virtual Router, no DHCP, addressing via ConfigDrive, L3
offerings only, KVM only).
---
.../java/com/cloud/offering/NetworkOffering.java | 1 +
.../engine/orchestration/NetworkOrchestrator.java | 22 ++++++++++++++++++++++
ui/public/locales/en.json | 3 +++
ui/src/views/infra/zone/PhysicalNetworksTab.vue | 12 ++++++++++--
.../zone/ZoneWizardPhysicalNetworkSetupStep.vue | 6 +++---
5 files changed, 39 insertions(+), 5 deletions(-)
diff --git a/api/src/main/java/com/cloud/offering/NetworkOffering.java
b/api/src/main/java/com/cloud/offering/NetworkOffering.java
index 5000a4f8c62..b3ab6961fd7 100644
--- a/api/src/main/java/com/cloud/offering/NetworkOffering.java
+++ b/api/src/main/java/com/cloud/offering/NetworkOffering.java
@@ -81,6 +81,7 @@ public interface NetworkOffering extends
InfrastructureEntity, InternalIdentity,
public final static String DefaultL2NetworkOfferingVlan =
"DefaultL2NetworkOfferingVlan";
public final static String DefaultL2NetworkOfferingConfigDrive =
"DefaultL2NetworkOfferingConfigDrive";
public final static String DefaultL2NetworkOfferingConfigDriveVlan =
"DefaultL2NetworkOfferingConfigDriveVlan";
+ public final static String DefaultL3NetworkOffering =
"DefaultL3NetworkOffering";
/**
* @return name for the network offering.
diff --git
a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
index d13d9d0f60d..24f9b83ac2a 100644
---
a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
+++
b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
@@ -557,6 +557,17 @@ public class NetworkOrchestrator extends ManagerBase
implements NetworkOrchestra
sgProviders.add(Provider.SecurityGroupProvider);
defaultSharedSGEnabledNetworkOfferingProviders.put(Service.SecurityGroup,
sgProviders);
+ // Direct Routed (L3) networks have no Virtual Router and no DHCP:
Instances learn their
+ // addressing from ConfigDrive, which also carries UserData and the
DNS configuration.
+ final Map<Network.Service, Set<Network.Provider>>
defaultL3NetworkOfferingProviders = new HashMap<>();
+ final Set<Provider> configDriveProvider = new HashSet<>();
+ configDriveProvider.add(Provider.ConfigDrive);
+ defaultL3NetworkOfferingProviders.put(Service.UserData,
configDriveProvider);
+ defaultL3NetworkOfferingProviders.put(Service.Dns,
configDriveProvider);
+ final Set<Provider> l3SecurityGroupProvider = new HashSet<>();
+ l3SecurityGroupProvider.add(Provider.SecurityGroupProvider);
+ defaultL3NetworkOfferingProviders.put(Service.SecurityGroup,
l3SecurityGroupProvider);
+
tungstenProvider.add(Provider.Tungsten);
final Map<Network.Service, Set<Network.Provider>>
defaultTungstenSharedSGEnabledNetworkOfferingProviders = new HashMap<>();
defaultTungstenSharedSGEnabledNetworkOfferingProviders.put(Service.Connectivity,
tungstenProvider);
@@ -620,6 +631,17 @@ public class NetworkOrchestrator extends ManagerBase
implements NetworkOrchestra
null, true, false, false, false, false, null,
null, null, true, null, null, false);
}
+ //#3b - Direct Routed (L3) network offering: ConfigDrive for
UserData and DNS,
+ // Security Groups for Instance isolation. Created on upgrade
and fresh install
+ // alike, since this block runs on every management server
start. The routed id
+ // is allocated from the ROUTED physical network's range (no
specifyVlan).
+ if
(_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultL3NetworkOffering)
== null) {
+ offering =
_configMgr.createNetworkOffering(NetworkOffering.DefaultL3NetworkOffering,
+ "Offering for Direct Routed (L3) networks - public
IPs routed directly to Instances, configuration via ConfigDrive (UserData and
DNS), Security Groups enabled, no Virtual Router and no DHCP",
+ TrafficType.Guest, null, false,
Availability.Optional, null, defaultL3NetworkOfferingProviders, true,
Network.GuestType.L3, false, null, true,
+ null, true, false, null, false, null, true, false,
false, false, false, null, null, null, true, null, null, false);
+ }
+
if
(_networkOfferingDao.findByUniqueName(NetworkOffering.DEFAULT_TUNGSTEN_SHARED_NETWORK_OFFERING_WITH_SGSERVICE)
== null) {
offering =
_configMgr.createNetworkOffering(NetworkOffering.DEFAULT_TUNGSTEN_SHARED_NETWORK_OFFERING_WITH_SGSERVICE,
"Offering for Tungsten Shared Security group enabled networks",
TrafficType.Guest, null, true,
Availability.Optional, null,
defaultTungstenSharedSGEnabledNetworkOfferingProviders, true,
Network.GuestType.Shared, false, null, true,
diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json
index f8713471ce6..78cf90618d8 100644
--- a/ui/public/locales/en.json
+++ b/ui/public/locales/en.json
@@ -3822,6 +3822,9 @@
"message.ip.v6.prefix.delete": "IPv6 prefix deleted",
"message.iso.arch": "Please select an ISO architecture",
"message.iso.desc": "Disc image containing data or bootable media for OS.",
+"message.isolationmethod.routed.description": "Direct Routed (L3): public
IPv4/IPv6 subnets are routed directly to Instances over a per-network bridge on
every host. No VLAN or tunnel on the wire, no Virtual Router and no DHCP -
Instances receive their address, routes and DNS through ConfigDrive. Only guest
networks created from an L3 network offering (such as DefaultL3NetworkOffering)
can be created on this physical network. KVM only.",
+"message.isolationmethod.vlan.description": "Guest networks are isolated from
each other by 802.1Q VLAN tags on the physical network.",
+"message.isolationmethod.vxlan.description": "Guest networks are isolated from
each other by VXLAN tunnels (one VNI per network) carried over the physical
network.",
"message.kubernetes.cluster.add.nodes": "Please confirm that you want to add
the following nodes to the cluster",
"message.kubernetes.cluster.delete": "Please confirm that you want to destroy
the Cluster.",
"message.kubeconfig.cluster.not.available": "Kubernetes Cluster kubeconfig not
available currently.",
diff --git a/ui/src/views/infra/zone/PhysicalNetworksTab.vue
b/ui/src/views/infra/zone/PhysicalNetworksTab.vue
index cccb8719805..a7c9fee7c3a 100644
--- a/ui/src/views/infra/zone/PhysicalNetworksTab.vue
+++ b/ui/src/views/infra/zone/PhysicalNetworksTab.vue
@@ -109,7 +109,7 @@
}"
v-focus="true"
:placeholder="apiParams.isolationmethods.description">
- <a-select-option v-for="i in isolationMethods" :key="i" :value="i"
:label="i">{{ i }}</a-select-option>
+ <a-select-option v-for="i in isolationMethods" :key="i" :value="i"
:label="i" :title="isolationMethodDescription(i)">{{ i }}</a-select-option>
</a-select>
</a-form-item>
<a-form-item name="vlan" ref="vlan">
@@ -200,10 +200,18 @@ export default {
},
computed: {
isolationMethods () {
- return ['VLAN', 'VXLAN', 'GRE', 'STT', 'BCF_SEGMENT', 'SSP', 'ODL',
'L3VPN', 'VCS', 'NSX', 'NETRIS']
+ return ['VLAN', 'VXLAN', 'ROUTED', 'GRE', 'STT', 'BCF_SEGMENT', 'SSP',
'ODL', 'L3VPN', 'VCS', 'NSX', 'NETRIS']
}
},
methods: {
+ isolationMethodDescription (method) {
+ const keys = {
+ VLAN: 'message.isolationmethod.vlan.description',
+ VXLAN: 'message.isolationmethod.vxlan.description',
+ ROUTED: 'message.isolationmethod.routed.description'
+ }
+ return method in keys ? this.$t(keys[method]) : method
+ },
fetchData () {
this.fetchLoading = true
getAPI('listPhysicalNetworks', { zoneid: this.resource.id }).then(json
=> {
diff --git a/ui/src/views/infra/zone/ZoneWizardPhysicalNetworkSetupStep.vue
b/ui/src/views/infra/zone/ZoneWizardPhysicalNetworkSetupStep.vue
index 759fe1421e4..b8050ffd832 100644
--- a/ui/src/views/infra/zone/ZoneWizardPhysicalNetworkSetupStep.vue
+++ b/ui/src/views/infra/zone/ZoneWizardPhysicalNetworkSetupStep.vue
@@ -56,9 +56,9 @@
:filterOption="(input, option) => {
return option.value.toLowerCase().indexOf(input.toLowerCase())
>= 0
}" >
- <a-select-option value="VLAN"> VLAN </a-select-option>
- <a-select-option value="VXLAN"> VXLAN </a-select-option>
- <a-select-option v-if="hypervisor === 'KVM'" value="ROUTED">
ROUTED </a-select-option>
+ <a-select-option value="VLAN"
:title="$t('message.isolationmethod.vlan.description')"> VLAN </a-select-option>
+ <a-select-option value="VXLAN"
:title="$t('message.isolationmethod.vxlan.description')"> VXLAN
</a-select-option>
+ <a-select-option v-if="hypervisor === 'KVM'" value="ROUTED"
:title="$t('message.isolationmethod.routed.description')"> ROUTED
</a-select-option>
<a-select-option value="GRE"> GRE </a-select-option>
<a-select-option value="STT"> STT </a-select-option>
<a-select-option value="BCF_SEGMENT"> BCF_SEGMENT
</a-select-option>