Skip to content

Commit

Permalink
cmd/microcloud: detect local net interface collisions within a member…
Browse files Browse the repository at this point in the history
… and global subnet collisions in a cluster of members

* If a member have multiple network types going through the same interface, show a warning.
* If multiple subnet types are detected to use the same subnet at a cluster level, show a warning.

Signed-off-by: Gabriel Mougard <gabriel.mougard@canonical.com>
  • Loading branch information
gabrielmougard committed Dec 5, 2024
1 parent 0098725 commit a9f6ca7
Showing 1 changed file with 70 additions and 4 deletions.
74 changes: 70 additions & 4 deletions cmd/microcloud/main_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -515,15 +515,81 @@ func validateGatewayNet(config map[string]string, ipPrefix string, cidrValidator
}

func (c *initConfig) validateSystems(s *service.Handler) (err error) {
for _, sys := range c.systems {
// 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][]string)
for peer, sys := range c.systems {
if sys.MicroCephInternalNetwork == nil || sys.OVNGeneveNetwork == nil {
continue
}

if sys.MicroCephInternalNetwork.Subnet.Contains(sys.OVNGeneveNetwork.IP) {
fmt.Printf("Warning: OVN underlay IP (%s) is shared with the Ceph cluster network (%s)\n", sys.OVNGeneveNetwork.IP.String(), sys.MicroCephInternalNetwork.Subnet.String())
// We also check for interface collisions at a local level.
// This means that we check if the same interface is used for multiple networks in a member.
netTypeToNet := map[string]*Network{
"Ceph cluster network": sys.MicroCephInternalNetwork,
"OVN underlay": sys.OVNGeneveNetwork,
}

break
// The public Ceph network is not always present (partially disaggregated setup) but we still
// wish to check for interface collisions between OVN and the Ceph cluster network.
// If it is present though, add it to the list of interfaces to check for collisions.
if sys.MicroCephPublicNetwork != nil {
netTypeToNet["Ceph public network"] = sys.MicroCephPublicNetwork
}

// This is checking the local collisions (whether the same interface is used for multiple networks in a member).
for typeLeft, netLeft := range netTypeToNet {
for typeRight, netRight := range netTypeToNet {
// Skip self-comparison and already processed pairs
// (e.g. if we already compared "A vs B", we don't need to compare "B vs A").
if typeLeft >= typeRight {
continue
}

if netLeft.Interface == netRight.Interface {
fmt.Printf("Warning: %s is shared on the same network interface %q with the %s\n", typeLeft, netLeft.Interface, typeRight)
}

// Populate the subnetsCollisionMap with the subnet type and the peer using it.
subnetTypeToPeers, ok := subnetsCollisionMap[netLeft.Subnet.String()]
if !ok {
subnetTypeToPeers = make(map[string][]string)
subnetTypeToPeers[typeLeft] = make([]string, 0)
subnetTypeToPeers[typeLeft] = append(subnetTypeToPeers[typeLeft], peer)
subnetsCollisionMap[netLeft.Subnet.String()] = subnetTypeToPeers
} else {
subnetTypeToPeers[typeLeft] = append(subnetTypeToPeers[typeLeft], peer)
}
}
}
}

// Check for subnet collisions at the cluster level.
for subnet, subnetTypeToPeers := range subnetsCollisionMap {
// If there are multiple subnet types on the same subnet, we have a collision.
if len(subnetTypeToPeers) > 1 {
var sb strings.Builder
sb.WriteString("WARNING: Subnet collision detected:\n")
for subnetType, peers := range subnetTypeToPeers {
sb.WriteString(fmt.Sprintf("- Members %s are using the %q subnet for %s\n", strings.Join(peers, ", "), subnet, subnetType))
}

sb.WriteString("Please ensure that each subnet is used for a single network type.")
fmt.Printf("%s\n", sb.String())
}
}

Expand Down

0 comments on commit a9f6ca7

Please sign in to comment.