Skip to content
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

Add a function to check if a network configuration is vaild #1414

Merged
merged 1 commit into from
Jan 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 52 additions & 1 deletion src/core/common/netutil/netutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func init() {

// Models
type NetworkConfig struct {
BaseNetwork Network `json:"baseNetwork"`
NetworkConfiguration Network `json:"networkConfiguration"`
}

// NetworkInterface defines the methods that both Network and NetworkDetails should implement.
Expand Down Expand Up @@ -302,3 +302,54 @@ func GetSizeOfHosts(cidrBlock string) (int, error) {

return CalculateHostCapacity(ipNet)
}

// ///////////////////////////////////////////////////////////////////
// ValidateNetwork recursively validates the network and its subnets.
func ValidateNetwork(network Network) error {
// Check if the CIDR block is valid
if _, _, err := net.ParseCIDR(network.CIDRBlock); err != nil {
return fmt.Errorf("invalid CIDR block '%s': %w", network.CIDRBlock, err)
}

// Check for overlapping subnets within the same network
if err := hasOverlappingSubnets(network.Subnets); err != nil {
return fmt.Errorf("in network '%s': %w", network.CIDRBlock, err)
}

// Recursively validate each subnet
for _, subnet := range network.Subnets {
if !isSubnetOf(network.CIDRBlock, subnet.CIDRBlock) {
return fmt.Errorf("subnet '%s' is not a valid subnet of '%s'", subnet.CIDRBlock, network.CIDRBlock)
}
if err := ValidateNetwork(subnet); err != nil {
return err
}
}
return nil
}

// isSubnetOf checks if childCIDR is a subnet of parentCIDR.
func isSubnetOf(parentCIDR, childCIDR string) bool {
_, parentNet, _ := net.ParseCIDR(parentCIDR)
_, childNet, _ := net.ParseCIDR(childCIDR)
return parentNet.Contains(childNet.IP)
}

// hasOverlappingSubnets checks if there are overlapping subnets within the same network.
func hasOverlappingSubnets(subnets []Network) error {
for i := 0; i < len(subnets); i++ {
for j := i + 1; j < len(subnets); j++ {
if cidrOverlap(subnets[i].CIDRBlock, subnets[j].CIDRBlock) {
return fmt.Errorf("overlapping subnets found: '%s' and '%s'", subnets[i].CIDRBlock, subnets[j].CIDRBlock)
}
}
}
return nil
}

// cidrOverlap checks if two CIDR blocks overlap.
func cidrOverlap(cidr1, cidr2 string) bool {
_, net1, _ := net.ParseCIDR(cidr1)
_, net2, _ := net.ParseCIDR(cidr2)
return net1.Contains(net2.IP) || net2.Contains(net1.IP)
}
81 changes: 30 additions & 51 deletions src/examples/netutil/netutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,76 +128,55 @@ func runExample(cmd *cobra.Command, args []string) {
fmt.Printf(" GetSubnets(): %v\n", networkDetails.GetSubnets())

///////////////////////////////////////////////////////////////////////////////////////////////////
fmt.Println("\n(Under development) Network template example")
// Define the base network
baseNetwork := netutil.Network{
CIDRBlock: "10.0.0.0/16",
Subnets: []netutil.Network{
{
// Define a VPC Network
CIDRBlock: "10.0.1.0/24",
Subnets: []netutil.Network{
{
// Define a Subnetwork within the VPC
CIDRBlock: "10.0.1.0/28",
},
{
// Another Subnetwork within the VPC
CIDRBlock: "10.0.1.16/28",
},
},
},
{
// Another VPC Network
CIDRBlock: "10.0.2.0/24",
Subnets: []netutil.Network{
{
// Subnetwork within the second VPC
CIDRBlock: "10.0.2.0/28",
},
},
},
},
}

fmt.Println("Base Network CIDR:", baseNetwork.CIDRBlock)
for i, vpc := range baseNetwork.Subnets {
fmt.Printf("VPC Network %d CIDR: %s\n", i+1, vpc.CIDRBlock)
for j, subnet := range vpc.Subnets {
fmt.Printf("\tSubnetwork %d CIDR: %s\n", j+1, subnet.CIDRBlock)
}
}
fmt.Println("\nValidate a network configuration")

///////////////////////////////////////////////////////////////////////////////////////////////////
fmt.Println("\n(Under development) Design multi-cloud network")
jsonData := `{
"baseNetwork": {
"name": "BaseNetwork1",
expectedInput := `{
"networkConfiguration": {
"name": "BaseNetwork (note - a CIDR block of logical global mutli-cloud network)",
"cidrBlock": "10.0.0.0/16",
"subnets": [
{
"name": "CloudNetwork1",
"name": "CloudNetwork1 (note - a CIDR block to be assigned to cloud network such as VPC network)",
"cidrBlock": "10.0.1.0/24",
"subnets": [
{"name": "Subnet1", "cidrBlock": "10.0.1.0/26"},
{"name": "Subnet2", "cidrBlock": "10.0.1.64/26"},
{"name": "Subnet3", "cidrBlock": "10.0.1.128/26"},
{"name": "Subnet4", "cidrBlock": "10.0.1.192/26"}
]
},
{
"name": "CloudNetwork2 (note - a CIDR block to be assigned to cloud network such as VPC network)",
"cidrBlock": "10.0.2.0/24",
"subnets": [
{"name": "Subnet1", "cidrBlock": "10.0.2.0/26"},
{"name": "Subnet2", "cidrBlock": "10.0.2.64/26"},
{"name": "Subnet3", "cidrBlock": "10.0.2.128/26"},
{"name": "Subnet4", "cidrBlock": "10.0.2.192/26"}
]
}
]
}
}`
fmt.Printf("[Expected input]\n%s\n", expectedInput)

var config netutil.NetworkConfig
err = json.Unmarshal([]byte(jsonData), &config)
var netConf netutil.NetworkConfig
err = json.Unmarshal([]byte(expectedInput), &netConf)
if err != nil {
log.Fatalf("Error occurred during unmarshaling. Error: %s", err.Error())
fmt.Printf("Error occurred during unmarshaling. Error: %s\n", err.Error())
}

prettyConfig, err := json.MarshalIndent(config, "", " ")
network := netConf.NetworkConfiguration
pretty, err := json.MarshalIndent(network, "", " ")
if err != nil {
log.Fatalf("marshaling error: %s", err)
fmt.Printf("marshaling error: %s\n", err)
}
fmt.Printf("[Network configuration to validate]\n%s\n", string(pretty))

if err := netutil.ValidateNetwork(network); err != nil {
fmt.Println("Network configuration is valid.")
} else {
fmt.Println("Network configuration is invalid.")
}
fmt.Printf("[Configuration]\n%s", string(prettyConfig))

}