mirror of
https://github.com/lxc/incus
synced 2026-08-02 05:26:46 +00:00
Merge pull request #3587 from stgraber/ovn
Some checks are pending
Build / Build (${{ matrix.architecture }}) (amd64) (push) Waiting to run
Build / Build (${{ matrix.architecture }}) (arm64) (push) Waiting to run
Tests / Code (oldstable) (push) Waiting to run
Tests / Code (stable) (push) Waiting to run
Tests / Code (tip) (push) Waiting to run
Tests / System (btrfs, stable, ubuntu-24.04, cluster) (push) Waiting to run
Tests / System (btrfs, stable, ubuntu-24.04, standalone_storage) (push) Waiting to run
Tests / System (ceph, stable, ubuntu-24.04, cluster) (push) Waiting to run
Tests / System (ceph, stable, ubuntu-24.04, standalone_storage) (push) Waiting to run
Tests / System (dir, oldstable, ubuntu-24.04, cluster) (push) Waiting to run
Tests / System (dir, oldstable, ubuntu-24.04, standalone_container) (push) Waiting to run
Tests / System (dir, oldstable, ubuntu-24.04, standalone_core) (push) Waiting to run
Tests / System (dir, oldstable, ubuntu-24.04, standalone_network) (push) Waiting to run
Tests / System (dir, oldstable, ubuntu-24.04, standalone_storage) (push) Waiting to run
Tests / System (dir, oldstable, ubuntu-24.04-arm, cluster) (push) Waiting to run
Tests / System (dir, oldstable, ubuntu-24.04-arm, standalone_container) (push) Waiting to run
Tests / System (dir, oldstable, ubuntu-24.04-arm, standalone_core) (push) Waiting to run
Tests / System (dir, oldstable, ubuntu-24.04-arm, standalone_network) (push) Waiting to run
Tests / System (dir, oldstable, ubuntu-24.04-arm, standalone_storage) (push) Waiting to run
Tests / System (dir, stable, ubuntu-24.04, cluster) (push) Waiting to run
Tests / System (dir, stable, ubuntu-24.04, standalone_container) (push) Waiting to run
Tests / System (dir, stable, ubuntu-24.04, standalone_core) (push) Waiting to run
Tests / System (dir, stable, ubuntu-24.04, standalone_network) (push) Waiting to run
Tests / System (dir, stable, ubuntu-24.04, standalone_storage) (push) Waiting to run
Tests / System (dir, stable, ubuntu-24.04-arm, cluster) (push) Waiting to run
Tests / System (dir, stable, ubuntu-24.04-arm, standalone_container) (push) Waiting to run
Tests / System (dir, stable, ubuntu-24.04-arm, standalone_core) (push) Waiting to run
Tests / System (dir, stable, ubuntu-24.04-arm, standalone_network) (push) Waiting to run
Tests / System (dir, stable, ubuntu-24.04-arm, standalone_storage) (push) Waiting to run
Tests / System (dir, tip, ubuntu-24.04, cluster) (push) Waiting to run
Tests / System (dir, tip, ubuntu-24.04, standalone_container) (push) Waiting to run
Tests / System (dir, tip, ubuntu-24.04, standalone_core) (push) Waiting to run
Tests / System (dir, tip, ubuntu-24.04, standalone_network) (push) Waiting to run
Tests / System (dir, tip, ubuntu-24.04, standalone_storage) (push) Waiting to run
Tests / System (dir, tip, ubuntu-24.04-arm, cluster) (push) Waiting to run
Tests / System (dir, tip, ubuntu-24.04-arm, standalone_container) (push) Waiting to run
Tests / System (dir, tip, ubuntu-24.04-arm, standalone_core) (push) Waiting to run
Tests / System (dir, tip, ubuntu-24.04-arm, standalone_network) (push) Waiting to run
Tests / System (dir, tip, ubuntu-24.04-arm, standalone_storage) (push) Waiting to run
Tests / System (linstor, stable, ubuntu-24.04, cluster) (push) Waiting to run
Tests / System (linstor, stable, ubuntu-24.04, standalone_storage) (push) Waiting to run
Tests / System (lvm, stable, ubuntu-24.04, cluster) (push) Waiting to run
Tests / System (lvm, stable, ubuntu-24.04, standalone_storage) (push) Waiting to run
Tests / System (random, stable, ubuntu-24.04, cluster) (push) Waiting to run
Tests / System (random, stable, ubuntu-24.04, standalone_storage) (push) Waiting to run
Tests / System (zfs, stable, ubuntu-24.04, cluster) (push) Waiting to run
Tests / System (zfs, stable, ubuntu-24.04, standalone_storage) (push) Waiting to run
Tests / Client (oldstable, macos-latest) (push) Waiting to run
Tests / Client (oldstable, ubuntu-latest) (push) Waiting to run
Tests / Client (oldstable, windows-latest) (push) Waiting to run
Tests / Client (stable, macos-latest) (push) Waiting to run
Tests / Client (stable, ubuntu-latest) (push) Waiting to run
Tests / Client (stable, windows-latest) (push) Waiting to run
Tests / Documentation (push) Waiting to run
Some checks are pending
Build / Build (${{ matrix.architecture }}) (amd64) (push) Waiting to run
Build / Build (${{ matrix.architecture }}) (arm64) (push) Waiting to run
Tests / Code (oldstable) (push) Waiting to run
Tests / Code (stable) (push) Waiting to run
Tests / Code (tip) (push) Waiting to run
Tests / System (btrfs, stable, ubuntu-24.04, cluster) (push) Waiting to run
Tests / System (btrfs, stable, ubuntu-24.04, standalone_storage) (push) Waiting to run
Tests / System (ceph, stable, ubuntu-24.04, cluster) (push) Waiting to run
Tests / System (ceph, stable, ubuntu-24.04, standalone_storage) (push) Waiting to run
Tests / System (dir, oldstable, ubuntu-24.04, cluster) (push) Waiting to run
Tests / System (dir, oldstable, ubuntu-24.04, standalone_container) (push) Waiting to run
Tests / System (dir, oldstable, ubuntu-24.04, standalone_core) (push) Waiting to run
Tests / System (dir, oldstable, ubuntu-24.04, standalone_network) (push) Waiting to run
Tests / System (dir, oldstable, ubuntu-24.04, standalone_storage) (push) Waiting to run
Tests / System (dir, oldstable, ubuntu-24.04-arm, cluster) (push) Waiting to run
Tests / System (dir, oldstable, ubuntu-24.04-arm, standalone_container) (push) Waiting to run
Tests / System (dir, oldstable, ubuntu-24.04-arm, standalone_core) (push) Waiting to run
Tests / System (dir, oldstable, ubuntu-24.04-arm, standalone_network) (push) Waiting to run
Tests / System (dir, oldstable, ubuntu-24.04-arm, standalone_storage) (push) Waiting to run
Tests / System (dir, stable, ubuntu-24.04, cluster) (push) Waiting to run
Tests / System (dir, stable, ubuntu-24.04, standalone_container) (push) Waiting to run
Tests / System (dir, stable, ubuntu-24.04, standalone_core) (push) Waiting to run
Tests / System (dir, stable, ubuntu-24.04, standalone_network) (push) Waiting to run
Tests / System (dir, stable, ubuntu-24.04, standalone_storage) (push) Waiting to run
Tests / System (dir, stable, ubuntu-24.04-arm, cluster) (push) Waiting to run
Tests / System (dir, stable, ubuntu-24.04-arm, standalone_container) (push) Waiting to run
Tests / System (dir, stable, ubuntu-24.04-arm, standalone_core) (push) Waiting to run
Tests / System (dir, stable, ubuntu-24.04-arm, standalone_network) (push) Waiting to run
Tests / System (dir, stable, ubuntu-24.04-arm, standalone_storage) (push) Waiting to run
Tests / System (dir, tip, ubuntu-24.04, cluster) (push) Waiting to run
Tests / System (dir, tip, ubuntu-24.04, standalone_container) (push) Waiting to run
Tests / System (dir, tip, ubuntu-24.04, standalone_core) (push) Waiting to run
Tests / System (dir, tip, ubuntu-24.04, standalone_network) (push) Waiting to run
Tests / System (dir, tip, ubuntu-24.04, standalone_storage) (push) Waiting to run
Tests / System (dir, tip, ubuntu-24.04-arm, cluster) (push) Waiting to run
Tests / System (dir, tip, ubuntu-24.04-arm, standalone_container) (push) Waiting to run
Tests / System (dir, tip, ubuntu-24.04-arm, standalone_core) (push) Waiting to run
Tests / System (dir, tip, ubuntu-24.04-arm, standalone_network) (push) Waiting to run
Tests / System (dir, tip, ubuntu-24.04-arm, standalone_storage) (push) Waiting to run
Tests / System (linstor, stable, ubuntu-24.04, cluster) (push) Waiting to run
Tests / System (linstor, stable, ubuntu-24.04, standalone_storage) (push) Waiting to run
Tests / System (lvm, stable, ubuntu-24.04, cluster) (push) Waiting to run
Tests / System (lvm, stable, ubuntu-24.04, standalone_storage) (push) Waiting to run
Tests / System (random, stable, ubuntu-24.04, cluster) (push) Waiting to run
Tests / System (random, stable, ubuntu-24.04, standalone_storage) (push) Waiting to run
Tests / System (zfs, stable, ubuntu-24.04, cluster) (push) Waiting to run
Tests / System (zfs, stable, ubuntu-24.04, standalone_storage) (push) Waiting to run
Tests / Client (oldstable, macos-latest) (push) Waiting to run
Tests / Client (oldstable, ubuntu-latest) (push) Waiting to run
Tests / Client (oldstable, windows-latest) (push) Waiting to run
Tests / Client (stable, macos-latest) (push) Waiting to run
Tests / Client (stable, ubuntu-latest) (push) Waiting to run
Tests / Client (stable, windows-latest) (push) Waiting to run
Tests / Documentation (push) Waiting to run
Use persistent Logical Switch Ports with OVN
This commit is contained in:
commit
7d65db474c
@ -4224,7 +4224,7 @@ func (n *ovn) Update(newNetwork api.NetworkPut, targetNode string, clientType re
|
||||
removeChangeSet := map[networkOVN.OVNPortGroup][]networkOVN.OVNSwitchPortUUID{}
|
||||
|
||||
// Get list of active switch ports (avoids repeated querying of OVN NB).
|
||||
activePorts, err := n.ovnnb.GetLogicalSwitchPorts(context.TODO(), n.getIntSwitchName())
|
||||
activePorts, err := n.ovnnb.GetLogicalSwitchActivePorts(context.TODO(), n.getIntSwitchName())
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed getting active ports: %w", err)
|
||||
}
|
||||
@ -4637,9 +4637,82 @@ func (n *ovn) InstanceDevicePortValidateExternalRoutes(deviceInstance instance.I
|
||||
return nil
|
||||
}
|
||||
|
||||
// InstanceDevicePortAdd adds empty DNS record (to indicate port has been added) and any DHCP reservations for
|
||||
// instance device port.
|
||||
// instanceDevicePortOpts derives the logical switch port options for an instance NIC device.
|
||||
func (n *ovn) instanceDevicePortOpts(instanceUUID string, deviceName string, devConfig deviceConfig.Device, ipv4 string, ipv6 string, enabled bool, location string) (*networkOVN.OVNSwitchPortOpts, error) {
|
||||
mac, err := net.ParseMAC(devConfig["hwaddr"])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dhcpv4Subnet := n.DHCPv4Subnet()
|
||||
dhcpv6Subnet := n.DHCPv6Subnet()
|
||||
var dhcpV4UUID, dhcpV6UUID networkOVN.OVNDHCPOptionsUUID
|
||||
|
||||
if dhcpv4Subnet != nil || dhcpv6Subnet != nil {
|
||||
dhcpV4UUID, dhcpV6UUID, err = n.getDhcpOptionUUIDs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if dhcpv4Subnet != nil && dhcpV4UUID == "" {
|
||||
return nil, fmt.Errorf("Could not find DHCPv4 options for instance port for subnet %q", dhcpv4Subnet.String())
|
||||
}
|
||||
|
||||
if dhcpv6Subnet != nil {
|
||||
if dhcpV6UUID == "" {
|
||||
return nil, fmt.Errorf("Could not find DHCPv6 options for instance port for subnet %q", dhcpv6Subnet.String())
|
||||
}
|
||||
|
||||
// If port isn't going to have fully dynamic IPs allocated by OVN, and instead only static
|
||||
// IPv4 addresses have been added, then add an EUI64 static IPv6 address so that the switch
|
||||
// port has an IPv6 address that will be used to generate a DNS record. This works around a
|
||||
// limitation in OVN that prevents us requesting dynamic IPv6 address allocation when
|
||||
// static IPv4 allocation is used.
|
||||
if ipv4 != "" && ipv6 == "" {
|
||||
eui64IP, err := eui64.ParseMAC(dhcpv6Subnet.IP, mac)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed generating EUI64 for instance port %q: %w", mac.String(), err)
|
||||
}
|
||||
|
||||
// Add EUI64 as the IPv6 address.
|
||||
ipv6 = eui64IP.String()
|
||||
}
|
||||
}
|
||||
|
||||
var nestedPortParentName networkOVN.OVNSwitchPort
|
||||
var nestedPortVLAN uint16
|
||||
if devConfig["nested"] != "" {
|
||||
nestedPortParentName = n.getInstanceDevicePortName(instanceUUID, devConfig["nested"])
|
||||
nestedPortVLANInt64, err := strconv.ParseUint(devConfig["vlan"], 10, 16)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Invalid VLAN ID %q: %w", devConfig["vlan"], err)
|
||||
}
|
||||
|
||||
nestedPortVLAN = uint16(nestedPortVLANInt64)
|
||||
}
|
||||
|
||||
return &networkOVN.OVNSwitchPortOpts{
|
||||
DHCPv4OptsID: dhcpV4UUID,
|
||||
DHCPv6OptsID: dhcpV6UUID,
|
||||
MAC: mac,
|
||||
IPV4: ipv4,
|
||||
IPV6: ipv6,
|
||||
Parent: nestedPortParentName,
|
||||
VLAN: nestedPortVLAN,
|
||||
Location: location,
|
||||
Promiscuous: util.IsTrue(devConfig["security.promiscuous"]),
|
||||
Enabled: &enabled,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// InstanceDevicePortAdd creates the disabled logical switch port, empty DNS record and any DHCP
|
||||
// reservations for an instance device port.
|
||||
func (n *ovn) InstanceDevicePortAdd(instanceUUID string, deviceName string, devConfig deviceConfig.Device) error {
|
||||
if instanceUUID == "" {
|
||||
return errors.New("Instance UUID is required")
|
||||
}
|
||||
|
||||
instancePortName := n.getInstanceDevicePortName(instanceUUID, deviceName)
|
||||
|
||||
reverter := revert.New()
|
||||
@ -4673,6 +4746,21 @@ func (n *ovn) InstanceDevicePortAdd(instanceUUID string, deviceName string, devC
|
||||
}
|
||||
}
|
||||
|
||||
// Create the logical switch port in disabled state.
|
||||
portOpts, err := n.instanceDevicePortOpts(instanceUUID, deviceName, devConfig, devConfig["ipv4.address"], devConfig["ipv6.address"], false, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = n.ovnnb.CreateLogicalSwitchPort(context.TODO(), n.getIntSwitchName(), instancePortName, portOpts, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
reverter.Add(func() {
|
||||
_ = n.ovnnb.DeleteLogicalSwitchPort(context.TODO(), n.getIntSwitchName(), instancePortName)
|
||||
})
|
||||
|
||||
reverter.Success()
|
||||
return nil
|
||||
}
|
||||
@ -4715,7 +4803,7 @@ func (n *ovn) forwardHasDefaultTarget(listenAddress string) (bool, error) {
|
||||
return hasDefaultTarget, nil
|
||||
}
|
||||
|
||||
// InstanceDevicePortStart sets up an instance device port to the internal logical switch.
|
||||
// InstanceDevicePortStart sets up and enables an instance device port on the internal logical switch.
|
||||
// Accepts a list of ACLs being removed from the NIC device (if called as part of a NIC update).
|
||||
// Returns the logical switch port name and a list of IPs that were allocated to the port for DNS.
|
||||
func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACLsRemove []string) (networkOVN.OVNSwitchPort, []net.IP, error) {
|
||||
@ -4723,11 +4811,6 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL
|
||||
return "", nil, errors.New("Instance UUID is required")
|
||||
}
|
||||
|
||||
mac, err := net.ParseMAC(opts.DeviceConfig["hwaddr"])
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
ipv4 := opts.DeviceConfig["ipv4.address"]
|
||||
ipv6 := opts.DeviceConfig["ipv6.address"]
|
||||
|
||||
@ -4736,9 +4819,19 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL
|
||||
return "", nil, fmt.Errorf("Failed parsing NIC device routes: %w", err)
|
||||
}
|
||||
|
||||
instancePortName := n.getInstanceDevicePortName(opts.InstanceUUID, opts.DeviceName)
|
||||
|
||||
reverter := revert.New()
|
||||
defer reverter.Fail()
|
||||
|
||||
// Check if the persistent port already exists (may be missing after an upgrade or database restore).
|
||||
existingPortUUID, err := n.ovnnb.GetLogicalSwitchPortUUID(context.TODO(), instancePortName)
|
||||
if err != nil && !errors.Is(err, networkOVN.ErrNotFound) {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
portExists := existingPortUUID != ""
|
||||
|
||||
// Get existing DHCPv4 static reservations.
|
||||
// This is used for both checking sticky DHCPv4 allocation availability and for ensuring static DHCP
|
||||
// reservations exist.
|
||||
@ -4749,19 +4842,9 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL
|
||||
|
||||
dhcpv4Subnet := n.DHCPv4Subnet()
|
||||
dhcpv6Subnet := n.DHCPv6Subnet()
|
||||
var dhcpV4UUID, dhcpV6UUID networkOVN.OVNDHCPOptionsUUID
|
||||
|
||||
if dhcpv4Subnet != nil || dhcpv6Subnet != nil {
|
||||
dhcpV4UUID, dhcpV6UUID, err = n.getDhcpOptionUUIDs()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
}
|
||||
if dhcpv4Subnet != nil {
|
||||
if dhcpV4UUID == "" {
|
||||
return "", nil, fmt.Errorf("Could not find DHCPv4 options for instance port for subnet %q", dhcpv4Subnet.String())
|
||||
}
|
||||
|
||||
// Sticky IPs are only needed when re-creating the port as an existing port keeps its allocation.
|
||||
if dhcpv4Subnet != nil && !portExists {
|
||||
// If using dynamic IPv4, look for previously used sticky IPs from the NIC's last state.
|
||||
var dhcpV4StickyIP net.IP
|
||||
if opts.DeviceConfig["ipv4.address"] == "" {
|
||||
@ -4800,62 +4883,27 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL
|
||||
}
|
||||
}
|
||||
|
||||
if dhcpv6Subnet != nil {
|
||||
if dhcpV6UUID == "" {
|
||||
return "", nil, fmt.Errorf("Could not find DHCPv6 options for instance port for subnet %q", dhcpv6Subnet.String())
|
||||
}
|
||||
|
||||
// If port isn't going to have fully dynamic IPs allocated by OVN, and instead only static
|
||||
// IPv4 addresses have been added, then add an EUI64 static IPv6 address so that the switch
|
||||
// port has an IPv6 address that will be used to generate a DNS record. This works around a
|
||||
// limitation in OVN that prevents us requesting dynamic IPv6 address allocation when
|
||||
// static IPv4 allocation is used.
|
||||
if ipv4 != "" && ipv6 == "" {
|
||||
eui64IP, err := eui64.ParseMAC(dhcpv6Subnet.IP, mac)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("Failed generating EUI64 for instance port %q: %w", mac.String(), err)
|
||||
}
|
||||
|
||||
// Add EUI64 as the IPv6 address.
|
||||
ipv6 = eui64IP.String()
|
||||
}
|
||||
portOpts, err := n.instanceDevicePortOpts(opts.InstanceUUID, opts.DeviceName, opts.DeviceConfig, ipv4, ipv6, true, n.state.ServerName)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
instancePortName := n.getInstanceDevicePortName(opts.InstanceUUID, opts.DeviceName)
|
||||
// Pick up any address override from the port options (such as the EUI64 IPv6 address).
|
||||
ipv4 = portOpts.IPV4
|
||||
ipv6 = portOpts.IPV6
|
||||
|
||||
var nestedPortParentName networkOVN.OVNSwitchPort
|
||||
var nestedPortVLAN uint16
|
||||
if opts.DeviceConfig["nested"] != "" {
|
||||
nestedPortParentName = n.getInstanceDevicePortName(opts.InstanceUUID, opts.DeviceConfig["nested"])
|
||||
nestedPortVLANInt64, err := strconv.ParseUint(opts.DeviceConfig["vlan"], 10, 16)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("Invalid VLAN ID %q: %w", opts.DeviceConfig["vlan"], err)
|
||||
}
|
||||
|
||||
nestedPortVLAN = uint16(nestedPortVLANInt64)
|
||||
}
|
||||
|
||||
// Add port with mayExist set to true, so that if instance port exists, we don't fail and continue below
|
||||
// to configure the port as needed. This is required in case the OVN northbound database was unavailable
|
||||
// when the instance NIC was stopped and was unable to remove the port on last stop, which would otherwise
|
||||
// prevent future NIC starts.
|
||||
err = n.ovnnb.CreateLogicalSwitchPort(context.TODO(), n.getIntSwitchName(), instancePortName, &networkOVN.OVNSwitchPortOpts{
|
||||
DHCPv4OptsID: dhcpV4UUID,
|
||||
DHCPv6OptsID: dhcpV6UUID,
|
||||
MAC: mac,
|
||||
IPV4: ipv4,
|
||||
IPV6: ipv6,
|
||||
Parent: nestedPortParentName,
|
||||
VLAN: nestedPortVLAN,
|
||||
Location: n.state.ServerName,
|
||||
Promiscuous: util.IsTrue(opts.DeviceConfig["security.promiscuous"]),
|
||||
}, true)
|
||||
// Create the port if missing, otherwise update its configuration, and enable it.
|
||||
err = n.ovnnb.CreateLogicalSwitchPort(context.TODO(), n.getIntSwitchName(), instancePortName, portOpts, true)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
reverter.Add(func() {
|
||||
_ = n.ovnnb.DeleteLogicalSwitchPort(context.TODO(), n.getIntSwitchName(), instancePortName)
|
||||
if portExists {
|
||||
_ = n.ovnnb.UpdateLogicalSwitchPortEnabled(context.TODO(), instancePortName, false)
|
||||
} else {
|
||||
_ = n.ovnnb.DeleteLogicalSwitchPort(context.TODO(), n.getIntSwitchName(), instancePortName)
|
||||
}
|
||||
})
|
||||
|
||||
// Add DNS records for port's IPs, and retrieve the IP addresses used.
|
||||
@ -5327,6 +5375,21 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the persistent port from any port group no longer requested above.
|
||||
currentPortGroups, err := n.ovnnb.GetPortGroupsByPort(context.TODO(), portUUID)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("Failed getting port groups for instance NIC port: %w", err)
|
||||
}
|
||||
|
||||
for _, portGroup := range currentPortGroups {
|
||||
_, foundAdd := addChangeSet[portGroup]
|
||||
_, foundRemove := removeChangeSet[portGroup]
|
||||
if !foundAdd && !foundRemove {
|
||||
acl.OVNPortGroupInstanceNICSchedule(portUUID, removeChangeSet, portGroup)
|
||||
n.logger.Debug("Scheduled logical port for port group removal", logger.Ctx{"portGroup": portGroup, "port": instancePortName})
|
||||
}
|
||||
}
|
||||
|
||||
// Add instance NIC switch port to port groups required. Always run this as the addChangeSet should always
|
||||
// be populated even if no ACLs being applied, because the NIC port needs to be added to the network level
|
||||
// port group.
|
||||
@ -5421,7 +5484,7 @@ func (n *ovn) InstanceDevicePortStart(opts *OVNInstanceNICSetupOpts, securityACL
|
||||
rules = append(rules, ingressRule)
|
||||
}
|
||||
|
||||
err = n.ovnnb.AddLogicalSwitchQoSRules(context.TODO(), n.getIntSwitchName(), instancePortName, rules...)
|
||||
err = n.ovnnb.SetLogicalSwitchQoSRules(context.TODO(), n.getIntSwitchName(), instancePortName, rules...)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
@ -5467,7 +5530,7 @@ func (n *ovn) InstanceDevicePortIPs(instanceUUID string, deviceName string) ([]n
|
||||
return devIPs, nil
|
||||
}
|
||||
|
||||
// InstanceDevicePortStop deletes an instance device port from the internal logical switch.
|
||||
// InstanceDevicePortStop disables an instance device port and removes its routes and NAT rules.
|
||||
func (n *ovn) InstanceDevicePortStop(ovsExternalOVNPort networkOVN.OVNSwitchPort, opts *OVNInstanceNICStopOpts) error {
|
||||
// Decide whether to use OVS provided OVN port name or internally derived OVN port name.
|
||||
instancePortName := ovsExternalOVNPort
|
||||
@ -5486,12 +5549,12 @@ func (n *ovn) InstanceDevicePortStop(ovsExternalOVNPort networkOVN.OVNSwitchPort
|
||||
return fmt.Errorf("Failed getting instance switch port options: %w", err)
|
||||
}
|
||||
|
||||
// Don't delete logical switch port if already active on another chassis (i.e during live cluster move).
|
||||
// Don't disable logical switch port if already active on another chassis (i.e during live cluster move).
|
||||
if portLocation != "" && portLocation != n.state.ServerName {
|
||||
return nil
|
||||
}
|
||||
|
||||
n.logger.Debug("Deleting instance port", logger.Ctx{"port": instancePortName, "source": source})
|
||||
n.logger.Debug("Disabling instance port", logger.Ctx{"port": instancePortName, "source": source})
|
||||
|
||||
internalRoutes, externalRoutes, err := n.instanceDevicePortRoutesParse(opts.DeviceConfig)
|
||||
if err != nil {
|
||||
@ -5513,38 +5576,14 @@ func (n *ovn) InstanceDevicePortStop(ovsExternalOVNPort networkOVN.OVNSwitchPort
|
||||
}
|
||||
|
||||
// Get DNS records.
|
||||
dnsUUID, _, dnsIPs, err := n.ovnnb.GetLogicalSwitchPortDNS(context.TODO(), instancePortName)
|
||||
_, _, dnsIPs, err := n.ovnnb.GetLogicalSwitchPortDNS(context.TODO(), instancePortName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
portUUID, err := n.ovnnb.GetLogicalSwitchPortUUID(context.TODO(), instancePortName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed getting logical port UUID for port group removal: %w", err)
|
||||
}
|
||||
|
||||
if portUUID != "" {
|
||||
portGroups, err := n.ovnnb.GetPortGroupsByPort(context.TODO(), portUUID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed getting port groups for instance NIC port: %w", err)
|
||||
}
|
||||
|
||||
if len(portGroups) > 0 {
|
||||
removeChangeSet := map[networkOVN.OVNPortGroup][]networkOVN.OVNSwitchPortUUID{}
|
||||
for _, pg := range portGroups {
|
||||
acl.OVNPortGroupInstanceNICSchedule(portUUID, removeChangeSet, pg)
|
||||
}
|
||||
|
||||
err = n.ovnnb.UpdatePortGroupMembers(context.TODO(), map[networkOVN.OVNPortGroup][]networkOVN.OVNSwitchPortUUID{}, removeChangeSet)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed removing instance NIC port from port groups: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup logical switch port and associated config.
|
||||
err = n.ovnnb.CleanupLogicalSwitchPort(context.TODO(), instancePortName, n.getIntSwitchName(), acl.OVNIntSwitchPortGroupName(n.ID()), dnsUUID)
|
||||
if err != nil {
|
||||
// Disable the logical switch port.
|
||||
err = n.ovnnb.UpdateLogicalSwitchPortEnabled(context.TODO(), instancePortName, false)
|
||||
if err != nil && !errors.Is(err, networkOVN.ErrNotFound) {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -5647,9 +5686,7 @@ func (n *ovn) InstanceDevicePortStop(ovsExternalOVNPort networkOVN.OVNSwitchPort
|
||||
return nil
|
||||
}
|
||||
|
||||
// InstanceDevicePortRemove unregisters the NIC device in the OVN database by removing the DNS entry that should
|
||||
// have been created during InstanceDevicePortAdd(). If the DNS record exists at remove time then this indicates
|
||||
// the NIC device was successfully added and this function also clears any DHCP reservations for the NIC's IPs.
|
||||
// InstanceDevicePortRemove deletes an instance device port and all its associated OVN config.
|
||||
func (n *ovn) InstanceDevicePortRemove(instanceUUID string, devName string, devConfig deviceConfig.Device, hasDuplicate bool) error {
|
||||
instancePortName := n.getInstanceDevicePortName(instanceUUID, devName)
|
||||
|
||||
@ -5687,17 +5724,41 @@ func (n *ovn) InstanceDevicePortRemove(instanceUUID string, devName string, devC
|
||||
}
|
||||
}
|
||||
|
||||
// Remove DNS record if exists.
|
||||
// Remove the port from any port groups it is a member of.
|
||||
portUUID, err := n.ovnnb.GetLogicalSwitchPortUUID(context.TODO(), instancePortName)
|
||||
if err != nil && !errors.Is(err, networkOVN.ErrNotFound) {
|
||||
return fmt.Errorf("Failed getting logical port UUID for port group removal: %w", err)
|
||||
}
|
||||
|
||||
if portUUID != "" {
|
||||
portGroups, err := n.ovnnb.GetPortGroupsByPort(context.TODO(), portUUID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed getting port groups for instance NIC port: %w", err)
|
||||
}
|
||||
|
||||
if len(portGroups) > 0 {
|
||||
removeChangeSet := map[networkOVN.OVNPortGroup][]networkOVN.OVNSwitchPortUUID{}
|
||||
for _, pg := range portGroups {
|
||||
acl.OVNPortGroupInstanceNICSchedule(portUUID, removeChangeSet, pg)
|
||||
}
|
||||
|
||||
err = n.ovnnb.UpdatePortGroupMembers(context.TODO(), map[networkOVN.OVNPortGroup][]networkOVN.OVNSwitchPortUUID{}, removeChangeSet)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed removing instance NIC port from port groups: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get DNS records.
|
||||
dnsUUID, _, _, err := n.ovnnb.GetLogicalSwitchPortDNS(context.TODO(), instancePortName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if dnsUUID != "" {
|
||||
err = n.ovnnb.DeleteLogicalSwitchPortDNS(context.TODO(), n.getIntSwitchName(), dnsUUID, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed deleting DNS record: %w", err)
|
||||
}
|
||||
// Cleanup logical switch port and associated config.
|
||||
err = n.ovnnb.CleanupLogicalSwitchPort(context.TODO(), instancePortName, n.getIntSwitchName(), acl.OVNIntSwitchPortGroupName(n.ID()), dnsUUID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
reverter.Success()
|
||||
@ -5963,7 +6024,7 @@ func (n *ovn) handleDependencyChange(uplinkName string, uplinkConfig map[string]
|
||||
|
||||
if slices.Contains([]string{"l2proxy", ""}, uplinkConfig["ovn.ingress_mode"]) {
|
||||
// Get list of active switch ports (avoids repeated querying of OVN NB).
|
||||
activePorts, err := n.ovnnb.GetLogicalSwitchPorts(context.TODO(), n.getIntSwitchName())
|
||||
activePorts, err := n.ovnnb.GetLogicalSwitchActivePorts(context.TODO(), n.getIntSwitchName())
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed getting active ports: %w", err)
|
||||
}
|
||||
@ -7273,7 +7334,7 @@ func (n *ovn) localPeerCreate(peer api.NetworkPeersPost) error {
|
||||
return fmt.Errorf("Failed applying local router security policy: %w", err)
|
||||
}
|
||||
|
||||
activeLocalNICPorts, err := n.ovnnb.GetLogicalSwitchPorts(context.TODO(), n.getIntSwitchName())
|
||||
activeLocalNICPorts, err := n.ovnnb.GetLogicalSwitchActivePorts(context.TODO(), n.getIntSwitchName())
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed getting active NIC ports: %w", err)
|
||||
}
|
||||
@ -7809,7 +7870,7 @@ func (n *ovn) peerSetup(ovnnb *networkOVN.NB, targetOVNNet *ovn, opts networkOVN
|
||||
}
|
||||
|
||||
// Get list of active switch ports (avoids repeated querying of OVN NB).
|
||||
activeTargetNICPorts, err := n.ovnnb.GetLogicalSwitchPorts(context.TODO(), targetOVNNet.getIntSwitchName())
|
||||
activeTargetNICPorts, err := n.ovnnb.GetLogicalSwitchActivePorts(context.TODO(), targetOVNNet.getIntSwitchName())
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed getting active NIC ports: %w", err)
|
||||
}
|
||||
|
||||
@ -136,6 +136,7 @@ type OVNSwitchPortOpts struct {
|
||||
Location string // Optional, use to indicate the name of the server this port is bound to.
|
||||
RouterPort OVNRouterPort // Optional, the name of the associated logical router port.
|
||||
Promiscuous bool // Optional, controls whether to allow unknown traffic on the port.
|
||||
Enabled *bool // Optional, if set controls the administrative state of the port.
|
||||
}
|
||||
|
||||
// OVNACLRule represents an ACL rule that can be added to a logical switch or port group.
|
||||
@ -1734,6 +1735,36 @@ func (o *NB) GetLogicalSwitchPorts(ctx context.Context, switchName OVNSwitch) (m
|
||||
return ports, nil
|
||||
}
|
||||
|
||||
// GetLogicalSwitchActivePorts returns a map of enabled logical switch ports (name and UUID) for a switch.
|
||||
func (o *NB) GetLogicalSwitchActivePorts(ctx context.Context, switchName OVNSwitch) (map[OVNSwitchPort]OVNSwitchPortUUID, error) {
|
||||
// Get the logical switch.
|
||||
logicalSwitch, err := o.GetLogicalSwitch(ctx, switchName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ports := make(map[OVNSwitchPort]OVNSwitchPortUUID, len(logicalSwitch.Ports))
|
||||
for _, portUUID := range logicalSwitch.Ports {
|
||||
// Get the logical switch port.
|
||||
lsp := ovnNB.LogicalSwitchPort{
|
||||
UUID: portUUID,
|
||||
}
|
||||
|
||||
err := o.get(ctx, &lsp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if lsp.Enabled != nil && !*lsp.Enabled {
|
||||
continue
|
||||
}
|
||||
|
||||
ports[OVNSwitchPort(lsp.Name)] = OVNSwitchPortUUID(lsp.UUID)
|
||||
}
|
||||
|
||||
return ports, nil
|
||||
}
|
||||
|
||||
// GetLogicalSwitchIPs returns a list of IPs associated to each port connected to switch.
|
||||
func (o *NB) GetLogicalSwitchIPs(ctx context.Context, switchName OVNSwitch) (map[OVNSwitchPort][]net.IP, error) {
|
||||
lsps := []ovnNB.LogicalSwitchPort{}
|
||||
@ -1875,6 +1906,10 @@ func (o *NB) CreateLogicalSwitchPort(ctx context.Context, switchName OVNSwitch,
|
||||
if opts.Location != "" {
|
||||
logicalSwitchPort.ExternalIDs[ovnExtIDIncusLocation] = opts.Location
|
||||
}
|
||||
|
||||
if opts.Enabled != nil {
|
||||
logicalSwitchPort.Enabled = opts.Enabled
|
||||
}
|
||||
}
|
||||
|
||||
logicalSwitchPort.ExternalIDs[ovnExtIDIncusSwitch] = string(switchName)
|
||||
@ -2095,6 +2130,40 @@ func (o *NB) UpdateLogicalSwitchPortOptions(ctx context.Context, portName OVNSwi
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateLogicalSwitchPortEnabled sets the administrative state of a logical switch port.
|
||||
func (o *NB) UpdateLogicalSwitchPortEnabled(ctx context.Context, portName OVNSwitchPort, enabled bool) error {
|
||||
// Get the logical switch port.
|
||||
lsp := ovnNB.LogicalSwitchPort{
|
||||
Name: string(portName),
|
||||
}
|
||||
|
||||
err := o.get(ctx, &lsp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lsp.Enabled = &enabled
|
||||
|
||||
// Update the record.
|
||||
operations, err := o.client.Where(&lsp).Update(&lsp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Apply the changes.
|
||||
resp, err := o.client.Transact(ctx, operations...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = ovsdb.CheckOperationResults(resp, operations)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateLogicalSwitchPortDNS sets up the switch port DNS records for the DNS name.
|
||||
// Returns the DNS record UUID, IPv4 and IPv6 addresses used for DNS records.
|
||||
func (o *NB) UpdateLogicalSwitchPortDNS(ctx context.Context, switchName OVNSwitch, portName OVNSwitchPort, dnsName string, dnsIPs []net.IP) (OVNDNSUUID, error) {
|
||||
@ -2987,10 +3056,23 @@ func (o *NB) UpdatePortGroupACLRules(ctx context.Context, portGroupName OVNPortG
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddLogicalSwitchQoSRules applies a set of rules to the specified logical switch port.
|
||||
func (o *NB) AddLogicalSwitchQoSRules(ctx context.Context, switchName OVNSwitch, switchPortName OVNSwitchPort, qosRules ...OVNQoSRule) error {
|
||||
// SetLogicalSwitchQoSRules replaces the set of QoS rules assigned to the specified logical switch port.
|
||||
func (o *NB) SetLogicalSwitchQoSRules(ctx context.Context, switchName OVNSwitch, switchPortName OVNSwitchPort, qosRules ...OVNQoSRule) error {
|
||||
var operations []ovsdb.Operation
|
||||
|
||||
// Remove any existing rules for the port.
|
||||
removeQoSRuleUUIDs, err := o.logicalSwitchPortQoSRules(ctx, switchPortName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
deleteOps, err := o.qosRuleDeleteOperations(ctx, "logical_switch", string(switchName), removeQoSRuleUUIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
operations = append(operations, deleteOps...)
|
||||
|
||||
// Add new rules.
|
||||
externalIDs := map[string]string{
|
||||
ovnExtIDIncusSwitch: string(switchName),
|
||||
|
||||
Loading…
Reference in New Issue
Block a user