Skip to content

Commit

Permalink
Merge pull request #1414 from yunkon-kim/yunkon-kim-patch-240111
Browse files Browse the repository at this point in the history
Add a function to check if a network configuration is vaild
  • Loading branch information
seokho-son authored Jan 11, 2024
2 parents 7489bff + b06b533 commit 29e2ee3
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 52 deletions.
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))

}

0 comments on commit 29e2ee3

Please sign in to comment.