-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add
netutil
pacakge and example initially
- Loading branch information
1 parent
f747646
commit 78bf735
Showing
2 changed files
with
368 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/cloud-barista/cb-tumblebug/src/core/common/netutil" | ||
) | ||
|
||
func main() { | ||
fmt.Println("netuil example") | ||
|
||
cidrBlock := "192.168.0.0/16" | ||
|
||
fmt.Println("\nNetwork 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("\nDivide CIDR block into subnets to accommodate at least minimum number of subnets") | ||
|
||
minSubnets := 4 // Minimum number of subnets required | ||
fmt.Printf("Minimum number of subnets: %d\n", minSubnets) | ||
|
||
subnets, err := netutil.SubnettingByMininumSubnetCount(cidrBlock, minSubnets) | ||
if err != nil { | ||
fmt.Println(err) | ||
} | ||
|
||
for _, subnet := range subnets { | ||
fmt.Println(subnet) | ||
} | ||
fmt.Println("\nDivide CIDR block by a specified number of hosts") | ||
|
||
hostsPerSubnet := 500 // number of hosts you want in each subnet | ||
fmt.Printf("Number of hosts per subnet: %d\n", hostsPerSubnet) | ||
|
||
subnets, err = netutil.SubnettingByHosts(cidrBlock, hostsPerSubnet) | ||
if err != nil { | ||
fmt.Println(err) | ||
} | ||
|
||
for _, subnet := range subnets { | ||
fmt.Println(subnet) | ||
} | ||
|
||
fmt.Println("\nGet Network Address") | ||
networkAddress, err := netutil.GetNetworkAddr(cidrBlock) | ||
if err != nil { | ||
fmt.Println(err) | ||
} | ||
fmt.Printf("Network Address: %s\n", networkAddress) | ||
|
||
fmt.Println("\nGet Broadcast Address") | ||
broadcastAddress, err := netutil.GetBroadcastAddr(cidrBlock) | ||
if err != nil { | ||
fmt.Println(err) | ||
|
||
} | ||
fmt.Printf("Broadcast Address: %s\n", broadcastAddress) | ||
|
||
fmt.Println("\nCalculate the number of hosts that can be accomodated in a given CIDR block") | ||
|
||
hosts, err := netutil.GetSizeOfHosts(cidrBlock) | ||
if err != nil { | ||
fmt.Println(err) | ||
} | ||
|
||
fmt.Printf("The CIDR block %s can accommodate %d hosts.\n", cidrBlock, hosts) | ||
|
||
fmt.Println("\nNew network") | ||
baseNet, err := netutil.New(cidrBlock) | ||
fmt.Printf("Base Network: %+v\n", baseNet) | ||
fmt.Printf("GetCIDRBlock(): %s\n", baseNet.GetCIDRBlock()) | ||
fmt.Printf("GetNetworkAddress(): %s\n", baseNet.GetNetworkAddress()) | ||
fmt.Printf("GetBroadcastAddress(): %s\n", baseNet.GetBroadcastAddress()) | ||
fmt.Printf("GetPrefix(): %d\n", baseNet.GetPrefix()) | ||
fmt.Printf("GetNetmask(): %s\n", baseNet.GetNetmask()) | ||
fmt.Printf("GetHostCapacity(): %d\n", baseNet.GetHostCapacity()) | ||
fmt.Printf("GetSubnets(): %v\n", baseNet.GetSubnets()) | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,252 @@ | ||
package netutil | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"math" | ||
"net" | ||
) | ||
|
||
var ( | ||
privateNetworks []*net.IPNet | ||
ip10, ip172, ip192 net.IP | ||
ipnet10, ipnet172, ipnet192 *net.IPNet | ||
) | ||
|
||
func init() { | ||
// Initialize private networks | ||
for _, IPNetwork := range []string{ | ||
"127.0.0.0/8", // IPv4 loopback | ||
"10.0.0.0/8", // RFC1918 | ||
"172.16.0.0/12", // RFC1918 | ||
"192.168.0.0/16", // RFC1918 | ||
"169.254.0.0/16", // RFC3927 link-local | ||
"::1/128", // IPv6 loopback | ||
"fe80::/10", // IPv6 link-local | ||
"fc00::/7", // IPv6 unique local addr | ||
} { | ||
_, privateNetwork, err := net.ParseCIDR(IPNetwork) | ||
if err != nil { | ||
log.Fatalf("parse error on %q: %v", IPNetwork, err) | ||
} | ||
privateNetworks = append(privateNetworks, privateNetwork) | ||
} | ||
|
||
// Initialize IPs and networks of each private network | ||
ip10, ipnet10, _ = net.ParseCIDR("10.0.0.0/8") | ||
ip172, ipnet172, _ = net.ParseCIDR("172.16.0.0/12") | ||
ip192, ipnet192, _ = net.ParseCIDR("192.168.0.0/16") | ||
} | ||
|
||
// Models | ||
type Network struct { | ||
CIDRBlock string // 192.168.0.0/24 | ||
NetworkAddress string // 192.168.0.0 | ||
BroadcastAddress string // 192.168.0.255 | ||
Prefix int // 24 | ||
Netmask string // 255.255.255.0 | ||
HostCapacity int // 254 | ||
Subnets []Network // Subnets within this network | ||
} | ||
|
||
// New creates a new Network object. | ||
func New(cidrBlock string) (*Network, error) { | ||
network := &Network{ | ||
CIDRBlock: cidrBlock, | ||
} | ||
|
||
_, ipNet, err := net.ParseCIDR(cidrBlock) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// Set Netmask | ||
mask := ipNet.Mask | ||
network.Netmask = net.IP(mask).String() | ||
|
||
// Set Prefix | ||
_, prefix := ipNet.Mask.Size() | ||
network.Prefix = prefix | ||
|
||
// Set NetworkAddress | ||
netAddr, err := CalculateNetworkAddr(ipNet) | ||
if err != nil { | ||
return nil, err | ||
} | ||
network.NetworkAddress = netAddr | ||
|
||
// Set BroadcastAddress | ||
broadcastAddr, err := CalculateBroadcastAddr(ipNet) | ||
if err != nil { | ||
return nil, err | ||
} | ||
network.BroadcastAddress = broadcastAddr | ||
|
||
// Set Hosts | ||
hosts, err := CalculateHostCapacity(ipNet) | ||
if err != nil { | ||
return nil, err | ||
} | ||
network.HostCapacity = hosts | ||
|
||
network.Subnets = []Network{} | ||
|
||
return network, nil | ||
} | ||
|
||
// Getters | ||
func (n *Network) GetCIDRBlock() string { return n.CIDRBlock } | ||
func (n *Network) GetNetworkAddress() string { return n.NetworkAddress } | ||
func (n *Network) GetBroadcastAddress() string { return n.BroadcastAddress } | ||
func (n *Network) GetPrefix() int { return n.Prefix } | ||
func (n *Network) GetNetmask() string { return n.Netmask } | ||
func (n *Network) GetHostCapacity() int { return n.HostCapacity } | ||
func (n *Network) GetSubnets() []Network { return n.Subnets } | ||
|
||
// SubnettingByMininumSubnetCount divides the CIDR block into subnets to accommodate the minimum number of subnets entered. | ||
func SubnettingByMininumSubnetCount(cidrBlock string, minSubnets int) ([]string, error) { | ||
_, network, err := net.ParseCIDR(cidrBlock) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// Calculate the new subnet mask size | ||
maskSize, _ := network.Mask.Size() | ||
subnetBits := int(math.Ceil(math.Log2(float64(minSubnets)))) | ||
newMaskSize := maskSize + subnetBits | ||
|
||
if newMaskSize > 32 { | ||
return nil, fmt.Errorf("cannot split %s to accommodate at least %d subnets", cidrBlock, minSubnets) | ||
} | ||
|
||
// Calculate the actual number of subnets that can be created with the new mask size | ||
numSubnets := int(math.Pow(2, float64(subnetBits))) | ||
|
||
var subnets []string | ||
for i := 0; i < numSubnets; i++ { | ||
ip := make(net.IP, len(network.IP)) | ||
copy(ip, network.IP) | ||
|
||
// Calculate the offset to apply to the base IP address | ||
offset := int64(i) << (32 - newMaskSize) | ||
for j := 3; j >= 0; j-- { | ||
shift := uint((3 - j) * 8) | ||
ip[j] += byte((offset >> shift) & 0xff) | ||
} | ||
|
||
subnets = append(subnets, fmt.Sprintf("%s/%d", ip.String(), newMaskSize)) | ||
} | ||
|
||
return subnets, nil | ||
} | ||
|
||
// IpToUint32 converts an IP address to a uint32. | ||
func IpToUint32(ip net.IP) uint32 { | ||
ip = ip.To4() | ||
return uint32(ip[0])<<24 + uint32(ip[1])<<16 + uint32(ip[2])<<8 + uint32(ip[3]) | ||
} | ||
|
||
// Uint32ToIP converts a uint32 to an IP address. | ||
func Uint32ToIP(n uint32) net.IP { | ||
return net.IPv4(byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) | ||
} | ||
|
||
// SubnettingByHosts divides a CIDR block into subnets based on the number of hosts required for one subnet. | ||
func SubnettingByHosts(cidrBlock string, hostsPerSubnet int) ([]string, error) { | ||
if hostsPerSubnet < 2 { | ||
return nil, fmt.Errorf("number of hosts per subnet should be at least 2") | ||
} | ||
|
||
_, network, err := net.ParseCIDR(cidrBlock) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
maskSize, bits := network.Mask.Size() | ||
// Adjusting for network and broadcast addresses | ||
hostBits := int(math.Ceil(math.Log2(float64(hostsPerSubnet + 2)))) | ||
newMaskSize := bits - hostBits | ||
|
||
if newMaskSize <= maskSize { | ||
return nil, fmt.Errorf("not enough room to create subnets for %d hosts in %s", hostsPerSubnet, cidrBlock) | ||
} | ||
|
||
baseIP := IpToUint32(network.IP) | ||
subnetMask := uint32(math.Pow(2, float64(hostBits)) - 1) | ||
var subnets []string | ||
|
||
for currentIP := baseIP; currentIP < baseIP+uint32(math.Pow(2, float64(bits-maskSize))); currentIP += subnetMask + 1 { | ||
subnetIP := Uint32ToIP(currentIP) | ||
subnets = append(subnets, fmt.Sprintf("%s/%d", subnetIP.String(), newMaskSize)) | ||
} | ||
|
||
return subnets, nil | ||
} | ||
|
||
// CalculateNetworkAddr calculates the network address for a given IPNet. | ||
func CalculateNetworkAddr(ipNet *net.IPNet) (string, error) { | ||
ip := ipNet.IP | ||
networkIP := ip.Mask(ipNet.Mask) | ||
return networkIP.String(), nil | ||
} | ||
|
||
// GetNetworkAddr calculates the network address for a given CIDR block. | ||
func GetNetworkAddr(cidrBlock string) (string, error) { | ||
_, ipNet, err := net.ParseCIDR(cidrBlock) | ||
if err != nil { | ||
return "", err | ||
} | ||
return CalculateNetworkAddr(ipNet) | ||
} | ||
|
||
// CalculateBroadcastAddr calculates the broadcast address for a given IPNet. | ||
func CalculateBroadcastAddr(ipNet *net.IPNet) (string, error) { | ||
// Calculate network and broadcast addresses | ||
ip := ipNet.IP | ||
mask := ipNet.Mask | ||
broadcast := make(net.IP, len(ip)) | ||
for i := 0; i < len(ip); i++ { | ||
broadcast[i] = ip[i] | ^mask[i] | ||
} | ||
broadcastAddress := broadcast.String() | ||
|
||
return broadcastAddress, nil | ||
} | ||
|
||
// GetBroadcastAddr calculates the broadcast address for a given CIDR block. | ||
func GetBroadcastAddr(cidrBlock string) (string, error) { | ||
_, ipNet, err := net.ParseCIDR(cidrBlock) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
return CalculateBroadcastAddr(ipNet) | ||
} | ||
|
||
// CalculateHostCapacity calculates the number of hosts that can be accommodated in a given IPNet. | ||
func CalculateHostCapacity(ipNet *net.IPNet) (int, error) { | ||
|
||
maskSize, bits := ipNet.Mask.Size() | ||
switch maskSize { | ||
case 31: | ||
// Special case for /31 subnets, typically used in point-to-point links (RFC 3021) | ||
return 2, nil | ||
case 32: | ||
// /32 subnets represent a single host (commonly used for loopback addresses) | ||
return 1, nil | ||
default: | ||
hostBits := bits - maskSize | ||
hosts := int(math.Pow(2, float64(hostBits))) - 2 | ||
return hosts, nil | ||
} | ||
} | ||
|
||
// GetSizeOfHosts calculates the number of hosts that can be accommodated in a given CIDR block. | ||
func GetSizeOfHosts(cidrBlock string) (int, error) { | ||
_, ipNet, err := net.ParseCIDR(cidrBlock) | ||
if err != nil { | ||
return 0, err | ||
} | ||
|
||
return CalculateHostCapacity(ipNet) | ||
} |