Skip to content

Commit

Permalink
Update netutil and example
Browse files Browse the repository at this point in the history
* Update models
* Add GetPrefix(), GetNetmask()
* Add Cobra  for enhanced CLI argument parsing and help functionality
yunkon-kim committed Jan 10, 2024
1 parent 77fae45 commit 3cad4a0
Showing 6 changed files with 257 additions and 75 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@ src/cb-tumblebug
src/cb-tumblebug-arm
src/cli/tbctl
src/cli/cli
src/examples/netutil/netutil

# AutoGenerated DB data directory
meta_db/
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -44,6 +44,7 @@ require (
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/labstack/gommon v0.4.0 // indirect
@@ -61,6 +62,7 @@ require (
github.com/snowzach/rotatefilehook v0.0.0-20220211133110-53752135082d // indirect
github.com/spf13/afero v1.9.5 // indirect
github.com/spf13/cast v1.5.1 // indirect
github.com/spf13/cobra v1.8.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -78,6 +78,7 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -218,6 +219,8 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
@@ -346,6 +349,7 @@ github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
@@ -360,6 +364,8 @@ github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM=
github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
94 changes: 73 additions & 21 deletions src/core/common/netutil/netutil.go
Original file line number Diff line number Diff line change
@@ -39,26 +39,66 @@ func init() {
}

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

// NetworkInterface defines the methods that both Network and NetworkDetails should implement.
type NetworkInterface interface {
GetCIDRBlock() string
GetSubnets() []Network
}

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
CIDRBlock string `json:"cidrBlock"`
Name string `json:"name,omitempty"`
Subnets []Network `json:"subnets,omitempty"`
}

// New creates a new Network object.
func New(cidrBlock string) (*Network, error) {
network := &Network{
CIDRBlock: cidrBlock,
func (n *Network) GetName() string { return n.Name }
func (n *Network) GetCIDRBlock() string { return n.CIDRBlock }
func (n *Network) GetSubnets() []Network { return n.Subnets }

// New creates a new NetworkDetails object.
func NewNetwork(cidrBlock string) (*Network, error) {

_, _, err := net.ParseCIDR(cidrBlock)
if err != nil {
return nil, err
}
network := new(Network)
network.CIDRBlock = cidrBlock

network.Subnets = []Network{}

return network, nil
}

type NetworkDetails struct {
Network
NetworkAddress string `json:"networkAddress,omitempty"`
BroadcastAddress string `json:"broadcastAddress,omitempty"`
Prefix int `json:"prefix,omitempty"`
Netmask string `json:"netmask,omitempty"`
HostCapacity int `json:"hostCapacity,omitempty"`
}

// Getters
func (n *NetworkDetails) GetNetworkAddress() string { return n.NetworkAddress }
func (n *NetworkDetails) GetBroadcastAddress() string { return n.BroadcastAddress }
func (n *NetworkDetails) GetPrefix() int { return n.Prefix }
func (n *NetworkDetails) GetNetmask() string { return n.Netmask }
func (n *NetworkDetails) GetHostCapacity() int { return n.HostCapacity }

// New creates a new NetworkDetails object.
func NewNetworkDetails(cidrBlock string) (*NetworkDetails, error) {

_, ipNet, err := net.ParseCIDR(cidrBlock)
if err != nil {
return nil, err
}
network := new(NetworkDetails)
network.CIDRBlock = cidrBlock

// Set Netmask
mask := ipNet.Mask
@@ -94,15 +134,6 @@ func New(cidrBlock string) (*Network, error) {
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)
@@ -223,6 +254,27 @@ func GetBroadcastAddr(cidrBlock string) (string, error) {
return CalculateBroadcastAddr(ipNet)
}

// GetPrefix calculates the prefix for a given CIDR block.
func GetPrefix(cidrBlock string) (int, error) {
_, ipNet, err := net.ParseCIDR(cidrBlock)
if err != nil {
return -1, err
}

prefix, _ := ipNet.Mask.Size()
return prefix, nil
}

// GetNetmask calculates the netmask for a given CIDR block.
func GetNetmask(cidrBlock string) (string, error) {
_, ipNet, err := net.ParseCIDR(cidrBlock)
if err != nil {
return "", err
}
mask := ipNet.Mask
return net.IP(mask).String(), nil
}

// CalculateHostCapacity calculates the number of hosts that can be accommodated in a given IPNet.
func CalculateHostCapacity(ipNet *net.IPNet) (int, error) {

@@ -245,7 +297,7 @@ func CalculateHostCapacity(ipNet *net.IPNet) (int, error) {
func GetSizeOfHosts(cidrBlock string) (int, error) {
_, ipNet, err := net.ParseCIDR(cidrBlock)
if err != nil {
return 0, err
return -1, err
}

return CalculateHostCapacity(ipNet)
40 changes: 37 additions & 3 deletions src/examples/netutil/README.md
Original file line number Diff line number Diff line change
@@ -3,16 +3,50 @@
Thia is an example of `netutil` package.
(see [netutil package](https://github.com/cloud-barista/cb-tumblebug/blob/main/src/core/common/netutil/netutil.go))

### How to execute this example
### How to use this example

**Move to the example directory**

```bash
cd PROJECT_ROOT_DIR/src/examples/netutil
```

**Execute the example**
**Build this example**

```bash
go run .
go build .
```

**See help**
```bash
./netutil --help
```

```
This program demonstrates the usage of the netutil package.
Usage:
./netutil [flags]
Examples:
./netutil --cidr "10.0.0.0/16" --minsubnets 4 --hosts 500
or
./netutil -c "10.0.0.0/16" -s 4 -n 500
Flags:
-c, --cidr string Base network CIDR block (default "192.168.0.0/16")
-h, --help help for ./netutil
-n, --hosts int Number of hosts per subnet (default 500)
-s, --minsubnets int Minimum number of subnets required (default 4)
```

**Run example**
```bash
./netutil
```
```bash
./netutil -c "10.0.0.0/16" -s 4 -n 500
```
```bash
./netutil --cidr "10.0.0.0/16" --minsubnets 4 --hosts 500
```
189 changes: 138 additions & 51 deletions src/examples/netutil/netutil.go
Original file line number Diff line number Diff line change
@@ -1,59 +1,48 @@
package main

import (
"encoding/json"
"fmt"
"log"

"github.com/cloud-barista/cb-tumblebug/src/core/common/netutil"
"github.com/spf13/cobra"
)

func main() {
fmt.Println("netuil example")
var exampleCmd = &cobra.Command{
Use: "./netutil",
Short: "Example program for the netutil package",
Long: `
This program demonstrates the usage of the netutil package.`,
Example: `./netutil --cidr "10.0.0.0/16" --minsubnets 4 --hosts 500
or
./netutil -c "10.0.0.0/16" -s 4 -n 500`,
Run: runExample,
}

cidrBlock := "192.168.0.0/16"
// Command-line flags with shorthand
exampleCmd.PersistentFlags().StringP("cidr", "c", "192.168.0.0/16", "Base network CIDR block")
exampleCmd.PersistentFlags().IntP("minsubnets", "s", 4, "Minimum number of subnets required")
exampleCmd.PersistentFlags().IntP("hosts", "n", 500, "Number of hosts per subnet")

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",
},
},
},
},
if err := exampleCmd.Execute(); err != nil {
log.Fatalf("Error executing netutil-example: %s", err)
}
}

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)
}
}
func runExample(cmd *cobra.Command, args []string) {

// Retrieve the flag values
cidrBlock, _ := cmd.Flags().GetString("cidr")
minSubnets, _ := cmd.Flags().GetInt("minsubnets")
hostsPerSubnet, _ := cmd.Flags().GetInt("hosts")

fmt.Println("Starting netuil example")

///////////////////////////////////////////////////////////////////////////////////////////////////
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)
@@ -64,9 +53,9 @@ func main() {
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.Println("\nDivide CIDR block by a specified number of hosts")
fmt.Printf("Number of hosts per subnet: %d\n", hostsPerSubnet)

subnets, err = netutil.SubnettingByHosts(cidrBlock, hostsPerSubnet)
@@ -78,13 +67,15 @@ func main() {
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 {
@@ -93,6 +84,23 @@ func main() {
}
fmt.Printf("Broadcast Address: %s\n", broadcastAddress)

///////////////////////////////////////////////////////////////////////////////////////////////////
fmt.Println("\nGet Prefix")
prefix, err := netutil.GetPrefix(cidrBlock)
if err != nil {
fmt.Println(err)
}
fmt.Printf("Prefix: %d\n", prefix)

///////////////////////////////////////////////////////////////////////////////////////////////////
fmt.Println("\nGet Netmask")
netmask, err := netutil.GetNetmask(cidrBlock)
if err != nil {
fmt.Println(err)
}
fmt.Printf("Netmask: %s\n", netmask)

///////////////////////////////////////////////////////////////////////////////////////////////////
fmt.Println("\nCalculate the number of hosts that can be accomodated in a given CIDR block")

hosts, err := netutil.GetSizeOfHosts(cidrBlock)
@@ -102,15 +110,94 @@ func main() {

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())
net, err := netutil.NewNetwork(cidrBlock)
fmt.Printf(" Network: %+v\n", net)
fmt.Printf(" GetCIDRBlock(): %s\n", net.GetCIDRBlock())
fmt.Printf(" GetSubnets(): %v\n", net.GetSubnets())

networkDetails, err := netutil.NewNetworkDetails(cidrBlock)
fmt.Printf("\n NetworkDetails: %+v\n", networkDetails)
fmt.Printf(" GetCIDRBlock(): %s\n", networkDetails.GetCIDRBlock())
fmt.Printf(" GetNetworkAddress(): %s\n", networkDetails.GetNetworkAddress())
fmt.Printf(" GetBroadcastAddress(): %s\n", networkDetails.GetBroadcastAddress())
fmt.Printf(" GetPrefix(): %d\n", networkDetails.GetPrefix())
fmt.Printf(" GetNetmask(): %s\n", networkDetails.GetNetmask())
fmt.Printf(" GetHostCapacity(): %d\n", networkDetails.GetHostCapacity())
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("\n(Under development) Design multi-cloud network")
jsonData := `{
"baseNetwork": {
"name": "BaseNetwork1",
"cidrBlock": "10.0.0.0/16",
"subnets": [
{
"name": "CloudNetwork1",
"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"}
]
}
]
}
}`

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

prettyConfig, err := json.MarshalIndent(config, "", " ")
if err != nil {
log.Fatalf("marshaling error: %s", err)
}
fmt.Printf("[Configuration]\n%s", string(prettyConfig))
}

0 comments on commit 3cad4a0

Please sign in to comment.