diff --git a/cmd/incusd/networks.go b/cmd/incusd/networks.go index 86086359196..3edaaefc548 100644 --- a/cmd/incusd/networks.go +++ b/cmd/incusd/networks.go @@ -1059,7 +1059,7 @@ func networkDelete(d *Daemon, r *http.Request) response.Response { clusterNotification := isClusterNotification(r) if !clusterNotification { // Quick checks. - inUse, err := n.IsUsed() + inUse, err := n.IsUsed(false) if err != nil { return response.SmartError(err) } @@ -1208,7 +1208,7 @@ func networkPost(d *Daemon, r *http.Request) response.Response { } // Check network isn't in use. - inUse, err := n.IsUsed() + inUse, err := n.IsUsed(false) if err != nil { return response.InternalError(fmt.Errorf("Failed checking network in use: %w", err)) } diff --git a/internal/server/network/driver_common.go b/internal/server/network/driver_common.go index a4e385e7b17..f4d6fd536d2 100644 --- a/internal/server/network/driver_common.go +++ b/internal/server/network/driver_common.go @@ -298,8 +298,21 @@ func (n *common) Locations() []string { return locations } -// IsUsed returns whether the network is used by any instances or profiles. -func (n *common) IsUsed() (bool, error) { +// IsUsed returns whether the network is in use by instances or by downstream networks. +func (n *common) IsUsed(instanceOnly bool) (bool, error) { + if instanceOnly { + usedBy := 0 + err := UsedByInstanceDevices(n.state, n.project, n.name, n.netType, func(inst db.InstanceArgs, nicName string, nicConfig map[string]string) error { + usedBy++ + return nil + }) + if err != nil { + return false, err + } + + return usedBy > 0, nil + } + usedBy, err := UsedBy(n.state, n.project, n.id, n.name, n.netType, true) if err != nil { return false, err diff --git a/internal/server/network/driver_physical.go b/internal/server/network/driver_physical.go index 6d85adeee1c..c1b820c9e90 100644 --- a/internal/server/network/driver_physical.go +++ b/internal/server/network/driver_physical.go @@ -11,6 +11,7 @@ import ( "github.com/lxc/incus/v6/internal/server/cluster/request" "github.com/lxc/incus/v6/internal/server/db" "github.com/lxc/incus/v6/internal/server/ip" + "github.com/lxc/incus/v6/internal/server/network/ovs" "github.com/lxc/incus/v6/shared/api" "github.com/lxc/incus/v6/shared/logger" "github.com/lxc/incus/v6/shared/util" @@ -297,7 +298,7 @@ func (n *physical) Update(newNetwork api.NetworkPut, targetNode string, clientTy // We only need to check in the database once, not on every clustered node. if clientType == request.ClientTypeNormal { if hostNameChanged { - isUsed, err := n.IsUsed() + isUsed, err := n.IsUsed(true) if isUsed || err != nil { return fmt.Errorf("Cannot update network parent interface when in use") } @@ -329,7 +330,7 @@ func (n *physical) Update(newNetwork api.NetworkPut, targetNode string, clientTy _ = n.common.update(oldNetwork, targetNode, clientType) }) - // Apply changes to all nodes and databse. + // Apply changes to all nodes and database. err = n.common.update(newNetwork, targetNode, clientType) if err != nil { return err @@ -340,6 +341,24 @@ func (n *physical) Update(newNetwork api.NetworkPut, targetNode string, clientTy return err } + // Update OVS bridge entries (for dependent OVN networks). + if hostNameChanged { + vswitch, err := n.state.OVS() + if err == nil { + ovsBridge := fmt.Sprintf("incusovn%d", n.id) + + err := vswitch.DeleteBridgePort(context.TODO(), ovsBridge, oldNetwork.Config["parent"]) + if err != nil && err != ovs.ErrNotFound { + return err + } + + err = vswitch.CreateBridgePort(context.TODO(), ovsBridge, newNetwork.Config["parent"], true) + if err != nil && err != ovs.ErrNotFound { + return err + } + } + } + revert.Success() // Notify dependent networks (those using this network as their uplink) of the changes. diff --git a/internal/server/network/network_interface.go b/internal/server/network/network_interface.go index 35e50972068..49311574ac4 100644 --- a/internal/server/network/network_interface.go +++ b/internal/server/network/network_interface.go @@ -37,7 +37,7 @@ type Network interface { LocalStatus() string Config() map[string]string Locations() []string - IsUsed() (bool, error) + IsUsed(instanceOnly bool) (bool, error) IsManaged() bool DHCPv4Subnet() *net.IPNet DHCPv6Subnet() *net.IPNet