-
Notifications
You must be signed in to change notification settings - Fork 935
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Network: Add support for OVN uplink networks attached to a VLAN #14196
Conversation
1d70282
to
498b0b0
Compare
lxd/network/openvswitch/ovn.go
Outdated
@@ -119,8 +119,9 @@ type OVNSwitchPortOpts struct { | |||
DHCPv4OptsID OVNDHCPOptionsUUID // Optional, if empty, no DHCPv4 enabled on port. | |||
DHCPv6OptsID OVNDHCPOptionsUUID // Optional, if empty, no DHCPv6 enabled on port. | |||
Parent OVNSwitchPort // Optional, if set a nested port is created. | |||
VLAN uint16 // Optional, use with Parent to request a specific VLAN for nested port. | |||
NestedVLAN uint16 // Optional, use with Parent to request a specific VLAN for nested port. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shall we call this ParentVLAN to show it is related to Parent field?
lxd/network/openvswitch/ovn.go
Outdated
@@ -1269,6 +1270,10 @@ func (o *OVN) LogicalSwitchPortAdd(switchName OVNSwitch, portName OVNSwitchPort, | |||
if opts.Location != "" { | |||
args = append(args, "--", "set", "logical_switch_port", string(portName), fmt.Sprintf("external_ids:%s=%s", ovnExtIDLXDLocation, opts.Location)) | |||
} | |||
|
|||
if opts.VLAN != 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If opts.VLAN == 0 we should clear the tag_request field (and confirm that doing that clears the tag field set by OVN) so that one can disable the VLAN setting later.
lxd/network/driver_ovn.go
Outdated
@@ -3104,6 +3161,13 @@ func (n *ovn) Start() error { | |||
return err | |||
} | |||
|
|||
// If VLAN config is provided to the OVN network, configure the necessary ports | |||
// to handle traffic on the specified VLAN. | |||
err = n.configurePortsForVLAN(n.config["vlan"], false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we make this called, or be part of, startUplinkPort() as that can then avoid loading the uplink network from the DB again, and also it keeps the uplink port configuration together, rather than splitting it out.
lxd/network/driver_ovn.go
Outdated
@@ -3218,6 +3282,12 @@ func (n *ovn) Update(newNetwork api.NetworkPut, targetNode string, clientType re | |||
delete(newNetwork.Config, ovnVolatileUplinkIPv6) | |||
} | |||
|
|||
// Update port configurations for VLAN if necessary. | |||
err = n.configurePortsForVLAN(newNetwork.Config["vlan"], true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where do changes to uplink ports get applied during updates currently? Can we move this call there?
lxd/network/driver_ovn.go
Outdated
@@ -2302,8 +2348,19 @@ func (n *ovn) setup(update bool) error { | |||
return fmt.Errorf("Failed linking external router port to external switch port: %w", err) | |||
} | |||
|
|||
// If VLAN is provided, ensure localnet port is properly tagged. | |||
localnetOpts := &openvswitch.OVNSwitchPortOpts{} | |||
if n.config["vlan"] != "" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if vlan is unset, how is the vlan setting removed?
lxd/network/driver_ovn.go
Outdated
|
||
ovs := openvswitch.NewOVS() | ||
vars := n.uplinkPortBridgeVars(uplinkNet) | ||
uplinkHostName := GetHostDevice(uplinkNet.Config()["parent"], uplinkNet.Config()["vlan"]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hrm, so referring to my question #12234 (comment) that we didn't discuss yet:
Should we add a vlan setting to the uplink network or each OVN network?
You've gone with adding the vlan
setting to each OVN network in this PR.
Because each uplink network can be used by multiple OVN networks, this means there is the possibility of using multiple VLANs on a single uplink (which in principle would work as we are trunking VLANs through the uplink OVS bridge into the uplink interface).
But I don't think using the uplink's vlan setting in the call to GetHostDevice
makes sense in that case.
I also see some other places in the existing code where we've called uplinkHostName := GetHostDevice
and used the uplink's VLAN setting which needs to be reviewed as part of this PR.
Right now, say I had an eth0.101 interface (a physical port eth0, with an untagged VLAN 101 interface layered ontop) which I want to use for my uplink, you could create a physical network that has parent=eth0
and vlan=101
and when passing directly to an instance, LXD would check if the eth0.101 interface existed, and if not create it, before passing it to the instance.
For OVN uplink networks, I can't see that LXD would create the eth0.101 interface if it doesn't exist, but if it does exist we would then connect eth0.101 to the intermediate uplink OVS bridge like any other port.
But in this PR you are introducing per-OVN network uplink VLAN settings, so this VLAN setting on the uplink network conceptually conflicts with what we are trying to do, as you are trying to allow multiple OVN networks to trunk multiple VLANs through a single uplink network, whilst at the same time allowing the uplink port to be configured with a single untagged VLAN (which wouldn't work with tagged frames).
But stepping back a bit further, lets forget the uplink's existing vlan
setting for a moment.
Say we go ahead with your proposal here of adding vlan
to the OVN network itself, then if I have two OVN networks both connected to the same uplink but using two different uplink VLAN IDs, how do we allocate an IP for the OVN network's external (volatile) IP on the uplink network, as each OVN network is effectively connected to different uplink networks (because each VLAN on the uplink network is likely going to have different IP ranges, or at least conceptually separate IP ranges).
So going back to my question above:
Should we add a vlan setting to the uplink network or each OVN network?
I actually think we should keep the vlan
setting on the uplink network.
Don't introduce a vlan
setting on the OVN network.
This would then require that the administrator define separate uplink networks in LXD for each VLAN on the parent interface, along with the separate IP range settings (which is what we want).
So the question then becomes: How should we use the vlan
setting on the uplink network?
Also it seems that whilst the OVN network doesn't create the vlan interface (e.g. eth0.101), if the uplink is a physical network it does seem to create it:
https://github.com/canonical/lxd/blob/main/lxd/network/driver_physical.go#L318
So, because we already have uplinkHostName := GetHostDevice(uplinkConfig["parent"], uplinkConfig["vlan"])
in startUplinkPortPhysical
could it be that if you use an OVN network with a physical network as an uplink using a dedicated interface (not a bridge) that VLAN support already works?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could it be that if you use an OVN network with a physical network as an uplink using a dedicated interface (not a bridge) that VLAN support already works?
I've just tested this and it works already, but only for physical uplinks, not bridged uplinks.
We should probably just add the last step from #12234 (comment) startUplinkPortBridgeNative
and the equivalent to startUplinkPortBridgeOVS
to this PR instead:
bridge vlan add dev vid 101
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @tomponline. I've pushed changes which better handle the case where the uplink parent is a bridge and the vlan
config is set -- we now avoid using the physical interface lxd creates on top of the bridge. This is WIP as I have a couple questions:
We should probably just add the last step from #12234 (comment) startUplinkPortBridgeNative and the equivalent to startUplinkPortBridgeOVS to this PR instead:
Can you help me to understand what we would need to add to startUplinkPortBridgeOVS
?
Also, since the vlan
config is set on the uplink network, I'm not sure what the best approach is to ensure ports are reconfigured when the uplink network vlan
config is changed. Would we need to add a check in the network update handler which notifies cluster members to update their ports if (1) the updated network is used as an uplink for an OVN network and (2) the vlan
config is changed? This seems a bit indirect so I'm wondering if there is something better we can do.
61bcd0b
to
0d0a24d
Compare
lxd/network/driver_ovn.go
Outdated
@@ -1853,7 +1866,7 @@ func (n *ovn) deleteUplinkPortPhysical(uplinkNet Network) error { | |||
uplinkHostName := GetHostDevice(uplinkConfig["parent"], uplinkConfig["vlan"]) | |||
|
|||
// Detect if uplink interface is a native bridge. | |||
if IsNativeBridge(uplinkHostName) { | |||
if IsNativeBridge(uplinkHostName) || IsNativeBridge(uplinkConfig["parent"]) && uplinkConfig["vlan"] != "" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need brackets for the logic here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, added parens to improve readability
0d0a24d
to
29cbe12
Compare
…parents Signed-off-by: Mark Bolton <[email protected]>
29cbe12
to
920700b
Compare
This PR adds API extension `network_ovn_uplink_vlan`, which adds support for using a bridge network with a specified VLAN ID as the uplink for an OVN network. Related: canonical/lxd-ci#302, #14196.
This PR adds support for OVN uplink networks attached to a VLAN. The implementation details closely track #12234 (comment).
Testing here: canonical/lxd-ci#302.
Closes #12234.