diff options
author | David Doan <daviddoan@Davids-MacBook-Pro-70.local> | 2023-10-23 14:53:30 -0400 |
---|---|---|
committer | David Doan <daviddoan@Davids-MacBook-Pro-70.local> | 2023-10-23 14:53:30 -0400 |
commit | 972cc0287e2e1231b7b67177e5bc89af5dead23c (patch) | |
tree | fe1012417c06775c98e81c4d88372c691f0ba1bd | |
parent | 0d68d5aa82a980b10b8afd00e054f6c126e50d93 (diff) |
comments and refactoring
-rw-r--r-- | cmd/vhost/main.go | 10 | ||||
-rw-r--r-- | cmd/vrouter/main.go | 49 | ||||
-rw-r--r-- | lnxfiles/doc-example/binaries.example.json | 17 | ||||
-rw-r--r-- | lnxfiles/doc-example/nodes.json | 7 | ||||
-rw-r--r-- | lnxfiles/loop/binaries.example.json | 23 | ||||
-rw-r--r-- | lnxfiles/loop/nodes.json | 9 | ||||
-rw-r--r-- | lnxfiles/r1h2/binaries.example.json | 11 | ||||
-rw-r--r-- | lnxfiles/r1h2/nodes.json | 5 | ||||
-rw-r--r-- | lnxfiles/r1h4/binaries.example.json | 17 | ||||
-rw-r--r-- | lnxfiles/r1h4/nodes.json | 7 | ||||
-rw-r--r-- | lnxfiles/r2h2/binaries.example.json | 14 | ||||
-rw-r--r-- | lnxfiles/r2h2/nodes.json | 6 | ||||
-rw-r--r-- | lnxfiles/r3h2/binaries.example.json | 17 | ||||
-rw-r--r-- | lnxfiles/r3h2/nodes.json | 7 | ||||
-rwxr-xr-x | lnxfiles/vhost | bin | 0 -> 3110339 bytes | |||
-rwxr-xr-x | lnxfiles/vrouter | bin | 0 -> 3110339 bytes | |||
-rw-r--r-- | pkg/ipstack/ipstack.go | 67 | ||||
-rwxr-xr-x | vhost | bin | 3105448 -> 3110931 bytes | |||
-rwxr-xr-x | vrouter | bin | 3105440 -> 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 Binary files differnew file mode 100755 index 0000000..b240f26 --- /dev/null +++ b/lnxfiles/vhost diff --git a/lnxfiles/vrouter b/lnxfiles/vrouter Binary files differnew file mode 100755 index 0000000..c89f6fe --- /dev/null +++ b/lnxfiles/vrouter 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 // } Binary files differBinary files differ |