Skip to content

Commit

Permalink
cmd/microcloud: Add the detectCollisions function
Browse files Browse the repository at this point in the history
This function detect the local network interface collisions and the global subet collisions

Signed-off-by: Gabriel Mougard <[email protected]>
  • Loading branch information
gabrielmougard committed Feb 10, 2025
1 parent 64fdc39 commit 7efc48f
Showing 1 changed file with 126 additions and 0 deletions.
126 changes: 126 additions & 0 deletions cmd/microcloud/main_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"net"
"os"
"sort"
"strings"
"sync"
"time"
Expand Down Expand Up @@ -551,6 +552,131 @@ func validateGatewayNet(config map[string]string, ipPrefix string, cidrValidator
return ovnIPRanges, nil
}

// detectCollisions checks for network collisions across systems.
// This tracks subnet usage across all systems using a global map and ensure collisions are
// detected when different systems use the same subnet for different network types.
// This also flag interface collisions within each individual system.
func detectCollisions(systems map[string]InitSystem) []string {
// subnetsCollisionMap maps a subnet CIDR notation to a map of subnet type to peer names.
//
// Example:
// {
// "10.0.1.0/24": {
// "OVN underlay": ["system1", "system2"],
// "Ceph cluster network": ["system3"]
// },
// "10.0.2.0/24": {
// "Ceph public network": ["system1", "system2", "system3"],
// }
// }
//
// In this example, we have a collision for the subnet "10.0.1.0/24":
// - system1 and system2 are using it for the OVN underlay, whereas system3 is using it for the Ceph cluster network.
// Everything is fine for the subnet "10.0.2.0/24" as all systems are using it for the Ceph public network.
subnetsCollisionMap := make(map[string]map[string]struct{})
interfaceCollisionMap := make(map[string]map[string]map[string]struct{})
subnetToGlobalTypes := make(map[string]map[string]struct{})

sortedKeys := func(set map[string]struct{}) []string {
keys := make([]string, 0, len(set))
for k := range set {
keys = append(keys, k)
}

sort.Strings(keys)
return keys
}

for sysName, sys := range systems {
netTypeToNet := map[string]*Network{
"Ceph cluster network": sys.MicroCephInternalNetwork,
"OVN underlay network": sys.OVNGeneveNetwork,
"MicroCloud internal network": sys.MicroCloudInternalNetwork,
}

interfaceCollisionMap[sysName] = make(map[string]map[string]struct{})
if sys.MicroCephPublicNetwork != nil {
netTypeToNet["Ceph public network"] = sys.MicroCephPublicNetwork
}

// Track interface collisions (local to each system)
interfaceToTypes := make(map[string][]string)
for netType, net := range netTypeToNet {
if net == nil {
continue
}

interfaceToTypes[net.Interface.Name] = append(interfaceToTypes[net.Interface.Name], netType)
}

for iface, types := range interfaceToTypes {
if len(types) > 1 {
_, ok := interfaceCollisionMap[sysName][iface]
if !ok {
interfaceCollisionMap[sysName][iface] = make(map[string]struct{})
}

for _, t := range types {
interfaceCollisionMap[sysName][iface][t] = struct{}{}
}
}
}

// Track subnets globally across systems
for netType, net := range netTypeToNet {
if net == nil {
continue
}

if net.Subnet == nil {
continue
}

subnetStr := net.Subnet.String()
_, exists := subnetToGlobalTypes[subnetStr]
if !exists {
subnetToGlobalTypes[subnetStr] = make(map[string]struct{})
}

subnetToGlobalTypes[subnetStr][netType] = struct{}{}
}
}

// Build subnet collisions from global subnets
for subnet, types := range subnetToGlobalTypes {
if len(types) > 1 {
subnetsCollisionMap[subnet] = types
}
}

warnings := make([]string, 0)

// Format interface collisions
for sysName, ifaceTotypesSet := range interfaceCollisionMap {
for iface, typesSet := range ifaceTotypesSet {
types := sortedKeys(typesSet)
warnings = append(warnings, tui.Printf(
tui.Fmt{Arg: "%s sharing network interface %q on %q"},
tui.Fmt{Arg: strings.Join(types, ", ")},
tui.Fmt{Arg: iface, Color: tui.Yellow},
tui.Fmt{Arg: sysName, Color: tui.Yellow},
))
}
}

// Format subnet collisions
for subnet, typesSet := range subnetsCollisionMap {
types := sortedKeys(typesSet)
warnings = append(warnings, tui.Printf(
tui.Fmt{Arg: "%s sharing subnet %q"},
tui.Fmt{Arg: strings.Join(types, ", ")},
tui.Fmt{Arg: subnet, Color: tui.Yellow},
))
}

return warnings
}

func (c *initConfig) validateSystems(s *service.Handler) (err error) {
for _, sys := range c.systems {
if sys.MicroCephInternalNetworkSubnet == "" || sys.OVNGeneveAddr == "" {
Expand Down

0 comments on commit 7efc48f

Please sign in to comment.