aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Doan <daviddoan@Davids-MacBook-Pro-70.local>2023-10-23 14:53:30 -0400
committerDavid Doan <daviddoan@Davids-MacBook-Pro-70.local>2023-10-23 14:53:30 -0400
commit972cc0287e2e1231b7b67177e5bc89af5dead23c (patch)
treefe1012417c06775c98e81c4d88372c691f0ba1bd
parent0d68d5aa82a980b10b8afd00e054f6c126e50d93 (diff)
comments and refactoring
-rw-r--r--cmd/vhost/main.go10
-rw-r--r--cmd/vrouter/main.go49
-rw-r--r--lnxfiles/doc-example/binaries.example.json17
-rw-r--r--lnxfiles/doc-example/nodes.json7
-rw-r--r--lnxfiles/loop/binaries.example.json23
-rw-r--r--lnxfiles/loop/nodes.json9
-rw-r--r--lnxfiles/r1h2/binaries.example.json11
-rw-r--r--lnxfiles/r1h2/nodes.json5
-rw-r--r--lnxfiles/r1h4/binaries.example.json17
-rw-r--r--lnxfiles/r1h4/nodes.json7
-rw-r--r--lnxfiles/r2h2/binaries.example.json14
-rw-r--r--lnxfiles/r2h2/nodes.json6
-rw-r--r--lnxfiles/r3h2/binaries.example.json17
-rw-r--r--lnxfiles/r3h2/nodes.json7
-rwxr-xr-xlnxfiles/vhostbin0 -> 3110339 bytes
-rwxr-xr-xlnxfiles/vrouterbin0 -> 3110339 bytes
-rw-r--r--pkg/ipstack/ipstack.go67
-rwxr-xr-xvhostbin3105448 -> 3110931 bytes
-rwxr-xr-xvrouterbin3105440 -> 3110947 bytes
19 files changed, 214 insertions, 52 deletions
diff --git a/cmd/vhost/main.go b/cmd/vhost/main.go
index dbf899a..26280ef 100644
--- a/cmd/vhost/main.go
+++ b/cmd/vhost/main.go
@@ -84,6 +84,16 @@ func main() {
ifaceName := line[3:]
ipstack.InterfaceUpREPL(ifaceName)
}
+ } else {
+ fmt.Println("Invalid command: ", line)
+ fmt.Println("Commands: ")
+ fmt.Println(" exit Terminate this program")
+ fmt.Println(" li List interfaces")
+ fmt.Println(" lr List routes")
+ fmt.Println(" ln List available neighbors")
+ fmt.Println(" up Enable an interface")
+ fmt.Println(" down Disable an interface")
+ fmt.Println(" send Send test packet")
}
continue
}
diff --git a/cmd/vrouter/main.go b/cmd/vrouter/main.go
index cde49a8..02104c5 100644
--- a/cmd/vrouter/main.go
+++ b/cmd/vrouter/main.go
@@ -10,57 +10,61 @@ import (
)
func main() {
+ // checks that a config file is passed as an argument
if len(os.Args) == 1 {
fmt.Printf("Usage: %s <configFile>\n", os.Args[0])
os.Exit(1)
}
+ // get config file name from command line argument
fileName := os.Args[2]
+ // initialize the router with its config file
err := ipstack.Initialize(fileName)
if err != nil {
+ // return if there is an error
return
}
+
+ // register the test protocol
ipstack.RegisterProtocolHandler(ipstack.TEST_PROTOCOL)
+ // register the rip protocol for the router
ipstack.RegisterProtocolHandler(ipstack.RIP_PROTOCOL)
- // TODO @ MICHAEL: Dont know why its not running instantly
- //go func() {
- // for {
- // ipstack.RequestRip()
- // // takes time to compute I think
- // // TODO @ MICHAEL
- // time.Sleep(2 * time.Second)
- // }
- //}()
-
- // TODO @ MICHEAL
- // go ipstack.CheckAndUpdateRoutingTable()
-
+ // create a scanner to read from stdin for command-line inputs
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
line := scanner.Text()
switch line {
+ // print the interfaces
case "li":
fmt.Println("Name\tAddr/Prefix\tState")
fmt.Println(ipstack.SprintInterfaces())
+ // print the neighbors
case "ln":
- fmt.Println("Iface\tVIP\tUDPAddr")
+ fmt.Println("Iface\tVIP\t\tUDPAddr")
fmt.Println(ipstack.SprintNeighbors())
+ // print the routing table
case "lr":
- fmt.Println("T\tPrefix\tNext Hop\tCost")
+ fmt.Println("T\tPrefix\t\tNext Hop\tCost")
fmt.Println(ipstack.SprintRoutingTable())
+ // exit the program
case "q":
ipstack.CleanUp()
os.Exit(0)
+ case "exit":
+ ipstack.CleanUp()
+ os.Exit(0)
default:
if len(line) > 4 {
+ // disable an interface
if line[:4] == "down" {
ifaceName := line[5:]
ipstack.InterfaceDownREPL(ifaceName)
}
+ // attempts to send message to destination
if line[:4] == "send" {
// get IP address and message that follows it
IPAndMessage := strings.Split(line, " ")
@@ -71,15 +75,19 @@ func main() {
messageToSend := strings.Join(message, " ")
messageToSendBytes := []byte(messageToSend)
+ // get the longest prefix match for the destination
hop, err := ipstack.LongestPrefix(netip.MustParseAddr(ipAddr))
if err != nil {
fmt.Println(err)
continue
}
+
myAddr := hop.Interface.IpPrefix.Addr()
+ // attempt to send the message to the destination
for _, neighbor := range ipstack.GetNeighbors()[hop.Interface.Name] {
if neighbor.VipAddr == netip.MustParseAddr(ipAddr) ||
neighbor.VipAddr == hop.VIP {
+ // send the message to the neighbor
bytesWritten, err := ipstack.SendIP(&myAddr, neighbor, ipstack.TEST_PROTOCOL, messageToSendBytes, ipAddr, nil)
if err != nil {
fmt.Println(err)
@@ -91,11 +99,22 @@ func main() {
}
}
if len(line) > 2 {
+ // enable an interface
if line[:2] == "up" {
// get interface name
ifaceName := line[3:]
ipstack.InterfaceUpREPL(ifaceName)
}
+ } else {
+ fmt.Println("Invalid command: ", line)
+ fmt.Println("Commands: ")
+ fmt.Println(" exit/q Terminate this program")
+ fmt.Println(" li List interfaces")
+ fmt.Println(" lr List routes")
+ fmt.Println(" ln List available neighbors")
+ fmt.Println(" up Enable an interface")
+ fmt.Println(" down Disable an interface")
+ fmt.Println(" send Send test packet")
}
continue
}
diff --git a/lnxfiles/doc-example/binaries.example.json b/lnxfiles/doc-example/binaries.example.json
new file mode 100644
index 0000000..b6ff6d9
--- /dev/null
+++ b/lnxfiles/doc-example/binaries.example.json
@@ -0,0 +1,17 @@
+{
+ "h1": {
+ "binary_path": "./vhost"
+ },
+ "h2": {
+ "binary_path": "./vhost"
+ },
+ "h3": {
+ "binary_path": "./vhost"
+ },
+ "r1": {
+ "binary_path": "./vrouter"
+ },
+ "r2": {
+ "binary_path": "./vrouter"
+ }
+} \ No newline at end of file
diff --git a/lnxfiles/doc-example/nodes.json b/lnxfiles/doc-example/nodes.json
new file mode 100644
index 0000000..7b91355
--- /dev/null
+++ b/lnxfiles/doc-example/nodes.json
@@ -0,0 +1,7 @@
+{
+ "h1": "host",
+ "h2": "host",
+ "h3": "host",
+ "r1": "router",
+ "r2": "router"
+} \ No newline at end of file
diff --git a/lnxfiles/loop/binaries.example.json b/lnxfiles/loop/binaries.example.json
new file mode 100644
index 0000000..3d0d853
--- /dev/null
+++ b/lnxfiles/loop/binaries.example.json
@@ -0,0 +1,23 @@
+{
+ "h1": {
+ "binary_path": "./vhost"
+ },
+ "h2": {
+ "binary_path": "./vhost"
+ },
+ "r1": {
+ "binary_path": "./vrouter"
+ },
+ "r2": {
+ "binary_path": "./vrouter"
+ },
+ "r3": {
+ "binary_path": "./vrouter"
+ },
+ "r4": {
+ "binary_path": "./vrouter"
+ },
+ "r5": {
+ "binary_path": "./vrouter"
+ }
+} \ No newline at end of file
diff --git a/lnxfiles/loop/nodes.json b/lnxfiles/loop/nodes.json
new file mode 100644
index 0000000..2829f76
--- /dev/null
+++ b/lnxfiles/loop/nodes.json
@@ -0,0 +1,9 @@
+{
+ "h1": "host",
+ "h2": "host",
+ "r1": "router",
+ "r2": "router",
+ "r3": "router",
+ "r4": "router",
+ "r5": "router"
+} \ No newline at end of file
diff --git a/lnxfiles/r1h2/binaries.example.json b/lnxfiles/r1h2/binaries.example.json
new file mode 100644
index 0000000..1888a6b
--- /dev/null
+++ b/lnxfiles/r1h2/binaries.example.json
@@ -0,0 +1,11 @@
+{
+ "h1": {
+ "binary_path": "./vhost"
+ },
+ "h2": {
+ "binary_path": "./vhost"
+ },
+ "r1": {
+ "binary_path": "./vrouter"
+ }
+} \ No newline at end of file
diff --git a/lnxfiles/r1h2/nodes.json b/lnxfiles/r1h2/nodes.json
new file mode 100644
index 0000000..6accf5f
--- /dev/null
+++ b/lnxfiles/r1h2/nodes.json
@@ -0,0 +1,5 @@
+{
+ "h1": "host",
+ "h2": "host",
+ "r1": "router"
+} \ No newline at end of file
diff --git a/lnxfiles/r1h4/binaries.example.json b/lnxfiles/r1h4/binaries.example.json
new file mode 100644
index 0000000..81dd521
--- /dev/null
+++ b/lnxfiles/r1h4/binaries.example.json
@@ -0,0 +1,17 @@
+{
+ "h1": {
+ "binary_path": "./vhost"
+ },
+ "h2": {
+ "binary_path": "./vhost"
+ },
+ "h3": {
+ "binary_path": "./vhost"
+ },
+ "h4": {
+ "binary_path": "./vhost"
+ },
+ "r1": {
+ "binary_path": "./vrouter"
+ }
+} \ No newline at end of file
diff --git a/lnxfiles/r1h4/nodes.json b/lnxfiles/r1h4/nodes.json
new file mode 100644
index 0000000..1927005
--- /dev/null
+++ b/lnxfiles/r1h4/nodes.json
@@ -0,0 +1,7 @@
+{
+ "h1": "host",
+ "h2": "host",
+ "h3": "host",
+ "h4": "host",
+ "r1": "router"
+} \ No newline at end of file
diff --git a/lnxfiles/r2h2/binaries.example.json b/lnxfiles/r2h2/binaries.example.json
new file mode 100644
index 0000000..59223ba
--- /dev/null
+++ b/lnxfiles/r2h2/binaries.example.json
@@ -0,0 +1,14 @@
+{
+ "h1": {
+ "binary_path": "./vhost"
+ },
+ "h2": {
+ "binary_path": "./vhost"
+ },
+ "r1": {
+ "binary_path": "./vrouter"
+ },
+ "r2": {
+ "binary_path": "./vrouter"
+ }
+} \ No newline at end of file
diff --git a/lnxfiles/r2h2/nodes.json b/lnxfiles/r2h2/nodes.json
new file mode 100644
index 0000000..282ab86
--- /dev/null
+++ b/lnxfiles/r2h2/nodes.json
@@ -0,0 +1,6 @@
+{
+ "h1": "host",
+ "h2": "host",
+ "r1": "router",
+ "r2": "router"
+} \ No newline at end of file
diff --git a/lnxfiles/r3h2/binaries.example.json b/lnxfiles/r3h2/binaries.example.json
new file mode 100644
index 0000000..9079242
--- /dev/null
+++ b/lnxfiles/r3h2/binaries.example.json
@@ -0,0 +1,17 @@
+{
+ "h1": {
+ "binary_path": "./vhost"
+ },
+ "h2": {
+ "binary_path": "./vhost"
+ },
+ "r1": {
+ "binary_path": "./vrouter"
+ },
+ "r2": {
+ "binary_path": "./vrouter"
+ },
+ "r3": {
+ "binary_path": "./vrouter"
+ }
+} \ No newline at end of file
diff --git a/lnxfiles/r3h2/nodes.json b/lnxfiles/r3h2/nodes.json
new file mode 100644
index 0000000..27ea8c5
--- /dev/null
+++ b/lnxfiles/r3h2/nodes.json
@@ -0,0 +1,7 @@
+{
+ "h1": "host",
+ "h2": "host",
+ "r1": "router",
+ "r2": "router",
+ "r3": "router"
+} \ No newline at end of file
diff --git a/lnxfiles/vhost b/lnxfiles/vhost
new file mode 100755
index 0000000..b240f26
--- /dev/null
+++ b/lnxfiles/vhost
Binary files differ
diff --git a/lnxfiles/vrouter b/lnxfiles/vrouter
new file mode 100755
index 0000000..c89f6fe
--- /dev/null
+++ b/lnxfiles/vrouter
Binary files differ
diff --git a/pkg/ipstack/ipstack.go b/pkg/ipstack/ipstack.go
index 959e5ff..c2d83ba 100644
--- a/pkg/ipstack/ipstack.go
+++ b/pkg/ipstack/ipstack.go
@@ -12,8 +12,6 @@ import (
"net/netip"
"sync"
"time"
- // "bytes"
- // "unicode"
)
const (
@@ -64,8 +62,8 @@ type Hop struct {
}
// GLOBAL VARIABLES (data structures) ------------------------------------------
-var myVIP Interface
var myInterfaces []*Interface
+
var myNeighbors = make(map[string][]*Neighbor)
var myRIPNeighbors = make(map[string]*Neighbor)
@@ -78,6 +76,8 @@ var routingTable = make(map[netip.Prefix]Hop)
// ************************************** INIT FUNCTIONS **********************************************************
// reference: https://github.com/brown-csci1680/lecture-examples/blob/main/ip-demo/cmd/udp-ip-recv/main.go
+
+// createUDPListener creates a UDP listener.
func createUDPListener(UdpAddr netip.AddrPort, conn *net.UDPConn) error {
listenString := UdpAddr.String()
listenAddr, err := net.ResolveUDPAddr("udp4", listenString)
@@ -93,6 +93,7 @@ func createUDPListener(UdpAddr netip.AddrPort, conn *net.UDPConn) error {
return nil
}
+// initialize parse the lnxfile and initializes the data structures and listener routines
func Initialize(lnxFilePath string) error {
// Parse the file
lnxConfig, err := lnxconfig.ParseConfig(lnxFilePath)
@@ -100,7 +101,7 @@ func Initialize(lnxFilePath string) error {
return errors.WithMessage(err, "Error parsing config file->\t"+lnxFilePath)
}
- // 1) add each local if to the routing table, as dictated by its subnet
+ // 1) add each local "if" to the routing table, as dictated by its subnet
for _, iface := range lnxConfig.Interfaces {
prefix := netip.PrefixFrom(iface.AssignedIP, iface.AssignedPrefix.Bits())
i := &Interface{
@@ -111,16 +112,20 @@ func Initialize(lnxFilePath string) error {
SocketChannel: make(chan bool),
State: true,
}
- // Added this for printing purposes for REPL FYI, if you have a better way lmk
+ // create the UDP listener
err := createUDPListener(iface.UDPAddr, &i.RecvSocket)
if err != nil {
return errors.WithMessage(err, "Error creating UDP socket for interface->\t"+iface.Name)
}
+ // start the listener routine
go InterfaceListenerRoutine(i)
+
+ // add to the list of interfaces
myInterfaces = append(myInterfaces, i)
+ // add to the routing table
routingTable[prefix.Masked()] = Hop{LOCAL_COST, "L", i, prefix.Addr()}
}
@@ -162,10 +167,10 @@ func Initialize(lnxFilePath string) error {
}
}
- // add protocol handlers
return nil
}
+// defines the go routine that listens on the UDP socket
func InterfaceListenerRoutine(i *Interface) {
// decompose the interface
socket := i.RecvSocket
@@ -175,8 +180,9 @@ func InterfaceListenerRoutine(i *Interface) {
isUp := true
closed := false
- // go routine that hangs on the recv
// fmt.Println("MAKING GO ROUTINE TO LISTEN:\t", socket.LocalAddr().String())
+
+ // go routine that hangs on the recv
go func() {
defer func() {
fmt.Println("exiting go routine that listens on ", socket.LocalAddr().String())
@@ -186,14 +192,15 @@ func InterfaceListenerRoutine(i *Interface) {
if closed { // stop this go routine if channel is closed
return
}
+
//if !isUp { // don't call the listeners if interface is down
// continue
//}
+
// TODO: remove these "training wheels"
time.Sleep(1 * time.Millisecond)
err := RecvIP(i, &isUp)
if err != nil {
- // fmt.Println("Error receiving IP packet", err)
continue
}
}
@@ -201,6 +208,7 @@ func InterfaceListenerRoutine(i *Interface) {
for {
select {
+ // if the channel is closed, exit
case sig, ok := <-signal:
if !ok {
fmt.Println("channel closed, exiting")
@@ -209,6 +217,7 @@ func InterfaceListenerRoutine(i *Interface) {
}
// fmt.Println("received isUP SIGNAL with value", sig)
isUp = sig
+ // if the channel is not closed, continue
default:
continue
}
@@ -217,7 +226,9 @@ func InterfaceListenerRoutine(i *Interface) {
// ************************************** DOWN/UP FUNCTIONS ******************************************************
+// sets the interface to be up and sends a triggered update
func InterfaceUp(iface *Interface) {
+ // set the state to up and send the signal
iface.State = true
iface.SocketChannel <- true
@@ -235,12 +246,13 @@ func InterfaceUpREPL(ifaceName string) {
fmt.Println("Error getting interface by name", err)
return
}
+ // set the state to up and send the signal
InterfaceUp(iface)
}
-// we could do either of these but the REPL results in less work done in router and host
-
+// sets the interface to be down and sends a triggered update
func InterfaceDown(iface *Interface) {
+ // set the state to down and send the signal
iface.SocketChannel <- false
iface.State = false
@@ -258,6 +270,7 @@ func InterfaceDownREPL(ifaceName string) {
fmt.Println("Error getting interface by name", err)
return
}
+ // set the state to down and send the signal
InterfaceDown(iface)
}
@@ -272,31 +285,6 @@ func GetInterfaceByName(ifaceName string) (*Interface, error) {
return nil, errors.Errorf("No interface with name %s", ifaceName)
}
-func GetNeighborByIP(ipAddr string) (*Neighbor, error) {
- // iterate through the neighbors and return the one with the same ipAddr
- for _, neighbors := range myNeighbors {
- for _, neighbor := range neighbors {
- if neighbor.VipAddr.String() == ipAddr {
- return neighbor, nil
- }
- }
- }
-
- return nil, errors.Errorf("No interface with ip %s", ipAddr)
-}
-
-func GetNeighborsToInterface(ifaceName string) ([]*Neighbor, error) {
- if neighbors, ok := myNeighbors[ifaceName]; ok {
- return neighbors, nil
- }
-
- return nil, errors.Errorf("No interface with name %s", ifaceName)
-}
-
-func GetMyVIP() Interface {
- return myVIP
-}
-
func GetInterfaces() []*Interface {
return myInterfaces
}
@@ -311,22 +299,27 @@ func GetRoutes() map[netip.Prefix]Hop {
// ************************************** PRINT FUNCTIONS **********************************************************
+// Sprint functions return a string representation of the myInterfaces data structure
func SprintInterfaces() string {
tmp := ""
for _, iface := range myInterfaces {
if iface.State {
+ // if the state is up, print UP
tmp += fmt.Sprintf("%s\t%s\t%s\n", iface.Name, iface.IpPrefix.String(), "UP")
} else {
+ // if the state is down, print DOWN
tmp += fmt.Sprintf("%s\t%s\t%s\n", iface.Name, iface.IpPrefix.String(), "DOWN")
}
}
return tmp
}
+// Sprint functions return a string representation of the myNeighbors data structure
func SprintNeighbors() string {
tmp := ""
for _, iface := range myInterfaces {
if !iface.State {
+ // if the interface is down, skip it
continue
}
for _, n := range myNeighbors[iface.Name] {
@@ -1017,7 +1010,7 @@ func LongestPrefix(src netip.Addr) (Hop, error) {
// for _, ripNeighbor := range myRIPNeighbors {
// if neighbor.VipAddr.String() == ripNeighbor.String() {
// // send RIP message
-// err := SendRIPMessage(myVIP, neighbor, message)
+ // err := SendRIPMessage(myVIP, neighbor, message)
// if err != nil {
// continue
// }
@@ -1107,7 +1100,7 @@ func LongestPrefix(src netip.Addr) (Hop, error) {
// // send RIP message
// for _, Interfaces := range myInterfaces {
// if Interfaces.Name == neighbor.Name {
-// err := SendRIPMessage(myVIP, neighbor, message)
+ // err := SendRIPMessage(myVIP, neighbor, message)
// if err != nil {
// continue
// }
diff --git a/vhost b/vhost
index ac23975..1fdc5aa 100755
--- a/vhost
+++ b/vhost
Binary files differ
diff --git a/vrouter b/vrouter
index 5455b09..e1339b8 100755
--- a/vrouter
+++ b/vrouter
Binary files differ