diff options
-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 | 314 | ||||
-rwxr-xr-x | vhost | bin | 3095650 -> 0 bytes | |||
-rwxr-xr-x | vrouter | bin | 3095650 -> 0 bytes |
19 files changed, 241 insertions, 272 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 030b9c7..e3d9ca2 100644 --- a/pkg/ipstack/ipstack.go +++ b/pkg/ipstack/ipstack.go @@ -12,8 +12,6 @@ import ( "net/netip" "sync" "time" - // "bytes" - // "unicode" ) const ( @@ -23,9 +21,9 @@ const ( MaxEntries = 64 INFINITY = 16 SIZE_OF_RIP_ENTRY = 12 - SIZE_OF_RIP_MESSAGE = 6 RIP_PROTOCOL = 200 TEST_PROTOCOL = 0 + SIZE_OF_RIP_HEADER = 4 ) // STRUCTS --------------------------------------------------------------------- @@ -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()) @@ -193,7 +199,6 @@ func InterfaceListenerRoutine(i *Interface) { // time.Sleep(1 * time.Millisecond) err := RecvIP(i, &isUp) if err != nil { - // fmt.Println("Error receiving IP packet", err) continue } } @@ -201,6 +206,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 +215,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 +224,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 @@ -246,12 +255,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 @@ -269,6 +279,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) } @@ -283,31 +294,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 } @@ -322,22 +308,27 @@ func GetRoutes() map[netip.Prefix]Hop { // ************************************** PRINT FUNCTIONS ********************************************************** +// returns 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 } +// returns 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] { @@ -347,12 +338,15 @@ func SprintNeighbors() string { return tmp } +// returns a string representation of the routingTable data structure func SprintRoutingTable() string { tmp := "" for prefix, hop := range routingTable { if hop.Type == "L" { - tmp += fmt.Sprintf("%s\t%s\tLOCAL:%s\t%d\n", hop.Type, prefix.String(), hop.Interface.Name, 0) + // if the hop is local, print LOCAL + tmp += fmt.Sprintf("%s\t%s\tLOCAL:%s\t%d\n", hop.Type, prefix.String(), hop.Interface.Name, hop.Cost) } else if hop.Type == "S" { + // if the hop is static, don't print the cost tmp += fmt.Sprintf("%s\t%s\t%s\t%s\n", hop.Type, prefix.String(), hop.VIP.String(), "-") } else { tmp += fmt.Sprintf("%s\t%s\t%s\t%d\n", hop.Type, prefix.String(), hop.VIP.String(), hop.Cost) @@ -363,13 +357,17 @@ func SprintRoutingTable() string { // ************************************** BASIC FUNCTIONS ********************************************************** +// cleans up the data structures and closes the UDP sockets func CleanUp() { fmt.Print("Cleaning up...\n") + // go through the interfaces, pop thread & close the UDP FDs for _, iface := range myInterfaces { + // close the channel if iface.SocketChannel != nil { close(iface.SocketChannel) } + // close the UDP FD err := iface.RecvSocket.Close() if err != nil { continue @@ -386,13 +384,14 @@ func CleanUp() { time.Sleep(5 * time.Millisecond) } -// TODO: have it take TTL so we can decrement it when forwarding +// SendIP sends an IP packet to a destination func SendIP(src *netip.Addr, dest *Neighbor, protocolNum int, message []byte, destIP string, hdr *ipv4header.IPv4Header) (int, error) { + // check if the interface is up iface, err := GetInterfaceByName(dest.Name) if !iface.State { return -1, errors.Errorf("error SEND: %s is down", iface.Name) } - + // if the header is nil, create a new one if hdr == nil { hdr = &ipv4header.IPv4Header{ Version: 4, @@ -410,6 +409,7 @@ func SendIP(src *netip.Addr, dest *Neighbor, protocolNum int, message []byte, de Options: []byte{}, } } else { + // if the header is not nil, decrement the TTL hdr = &ipv4header.IPv4Header{ Version: 4, Len: 20, // Header length is always 20 when no IP options @@ -448,13 +448,10 @@ func SendIP(src *netip.Addr, dest *Neighbor, protocolNum int, message []byte, de bytesToSend = append(bytesToSend, []byte(message)...) sendAddr, err := net.ResolveUDPAddr("udp4", dest.UdpAddr.String()) - // tmpConn, err := net.DialUDP("udp4", nil, sendAddr) - // get the interface of this neighbor if err != nil { return -1, errors.WithMessage(err, "Could not bind to UDP port->\t"+dest.UdpAddr.String()) } - // bytesWritten, err := tmpConn.Write(bytesToSend) // TODO: make this faster by removing call bytesWritten, err := iface.RecvSocket.WriteToUDP(bytesToSend, sendAddr) if err != nil { @@ -465,33 +462,31 @@ func SendIP(src *netip.Addr, dest *Neighbor, protocolNum int, message []byte, de return bytesWritten, nil } + +// RecvIP receives an IP packet from a source func RecvIP(iface *Interface, isOpen *bool) error { - buffer := make([]byte, MAX_IP_PACKET_SIZE) // TODO: fix wordking + buffer := make([]byte, MAX_IP_PACKET_SIZE) // TODO: fix wording // Read on the UDP port - // Too much printing so I commented it out // fmt.Println("wating to read from UDP socket") _, _, err := iface.RecvSocket.ReadFromUDP(buffer) if err != nil { return err } + // check if the interface is up if !*isOpen { return errors.Errorf("error RECV: %s is down", iface.Name) } // Marshal the received byte array into a UDP header - // NOTE: This does not validate the checksum or check any fields - // (You'll need to do this part yourself) hdr, err := ipv4header.ParseHeader(buffer) if err != nil { - // What should you if the message fails to parse? - // Your node should not crash or exit when you get a bad message. - // Instead, simply drop the packet and return to processing. fmt.Println("Error parsing header", err) return err } + // checksum validation headerSize := hdr.Len headerBytes := buffer[:headerSize] checksumFromHeader := uint16(hdr.Checksum) @@ -522,11 +517,13 @@ func RecvIP(iface *Interface, isOpen *bool) error { return nil } - // at this point, the packet is valid. next steps consider the forwarding of the packet - // 2) check if the message is for me, if so, sendUP (aka call the correct handler) //if hdr.Protocol != RIP_PROTOCOL { // fmt.Println("I see a non-rip packet") //} + + // at this point, the packet is valid. next steps consider the forwarding of the packet + + // 2) check if the message is for me, if so, sendUP (aka call the correct handler) for _, myIface := range myInterfaces { if hdr.Dst == myIface.IpPrefix.Addr() { // see if there is a handler for this protocol @@ -589,8 +586,8 @@ func RecvIP(iface *Interface, isOpen *bool) error { // ************************************** RIP Routines ******************************************************* +// creates a byte array that represents a RIP message func makeRipMessage(command uint16, entries []RIPEntry) []byte { - SIZE_OF_RIP_HEADER := 2 * 2 // 2 uint16s if command == 1 { // request message buf := make([]byte, SIZE_OF_RIP_HEADER) binary.BigEndian.PutUint16(buf[0:2], command) @@ -599,19 +596,23 @@ func makeRipMessage(command uint16, entries []RIPEntry) []byte { } // else, command == 2, response message + // create the buffer bufLen := SIZE_OF_RIP_HEADER + // sizeof uint16 is 2, we have two of them len(entries)*SIZE_OF_RIP_ENTRY // each entry is 12 buf := make([]byte, bufLen) + // fill in the header binary.BigEndian.PutUint16(buf[0:2], command) binary.BigEndian.PutUint16(buf[2:4], uint16(len(entries))) + // fill in the entries for i, entry := range entries { - offset := 2*2 + i*SIZE_OF_RIP_ENTRY + offset := SIZE_OF_RIP_HEADER + i*SIZE_OF_RIP_ENTRY binary.BigEndian.PutUint32(buf[offset:offset+4], entry.cost) // 0-3 = 4 bytes copy(buf[offset+4:offset+8], entry.prefix.Addr().AsSlice()) // 4-7 = 4 bytes + // convert the prefix to a uint32 ipv4Netmask := uint32(0xffffffff) ipv4Netmask <<= 32 - entry.prefix.Bits() binary.BigEndian.PutUint32(buf[offset+8:offset+12], ipv4Netmask) @@ -620,6 +621,7 @@ func makeRipMessage(command uint16, entries []RIPEntry) []byte { return buf } + func periodicUpdateRoutine() { for { // for each periodic update, we want to send our nodes in the table @@ -781,7 +783,7 @@ func RegisterProtocolHandler(protocolNum int) bool { func handleRIP(src *Interface, dest *Neighbor, message []byte, hdr *ipv4header.IPv4Header) error { // parse the RIP message - SIZE_OF_RIP_HEADER := 2 * 2 + // SIZE_OF_RIP_HEADER := 2 * 2 command := int(binary.BigEndian.Uint16(message[0:2])) switch command { case 1: @@ -962,206 +964,4 @@ func LongestPrefix(src netip.Addr) (Hop, error) { } } return Hop{}, errors.Errorf("No route to ip %s on table.", src) -} - -// -//func SendRIPMessage(src Interface, dest *Neighbor, message *RIPMessage) error { -// hdr := ipv4header.IPv4Header{ -// Version: 4, -// Len: 20, // Header length is always 20 when no IP options -// TOS: 0, -// TotalLen: ipv4header.HeaderLen + 4 + len(message.entries)*SIZE_OF_RIP_ENTRY, -// ID: 0, -// Flags: 0, -// FragOff: 0, -// TTL: 32, -// Protocol: RIP_PROTOCOL, -// Checksum: 0, // Should be 0 until checksum is computed -// Src: src.IpPrefix.Addr(), -// Dst: netip.MustParseAddr(dest.VipAddr.String()), -// Options: []byte{}, -// } -// -// headerBytes, err := hdr.Marshal() -// if err != nil { -// return err -// } -// -// hdr.Checksum = int(ComputeChecksum(headerBytes)) -// -// headerBytes, err = hdr.Marshal() -// if err != nil { -// log.Fatalln("Error marshalling header: ", err) -// } -// -// bytesToSend := make([]byte, 0) -// bytesToSend = append(bytesToSend, headerBytes...) -// -// // make the RIP message -// //buf := make([]byte, SIZE_OF_RIP_MESSAGE+len(message.entries)*SIZE_OF_RIP_ENTRY) -// //buf[0] = message.command -// //buf[1] = message.numEntries -// -// buf := make([]byte, 4) -// binary.BigEndian.PutUint16(buf[0:2], message.command) -// binary.BigEndian.PutUint16(buf[2:], message.numEntries) -// -// bytesToSend = append(bytesToSend, buf...) -// -// for _, entry := range message.entries { -// // offset := SIZE_OF_RIP_MESSAGE + i*SIZE_OF_RIP_ENTRY -// // each field is 4 bytes -// buf := make([]byte, SIZE_OF_RIP_ENTRY) -// binary.BigEndian.PutUint32(buf, entry.address) // 0-3 = 4 bytes -// binary.BigEndian.PutUint32(buf[3:8], entry.mask) // 4-7 = 4 bytes -// binary.BigEndian.PutUint32(buf[8:], entry.cost) // 8-11 = 4 bytes -// -// bytesToSend = append(bytesToSend, buf...) -// } -// -// // send RIP message -// sendAddr, err := net.ResolveUDPAddr("udp4", dest.UdpAddr.String()) -// // tmpConn, err := net.DialUDP("udp4", nil, sendAddr) -// if err != nil { -// return errors.WithMessage(err, "Could not bind to UDP port->\t"+dest.UdpAddr.String()) -// } -// -// iface, err := GetInterfaceByName(dest.Name) -// //_, err = tmpConn.Write(bytesToSend) -// _, err = iface.RecvSocket.WriteToUDP(bytesToSend, sendAddr) -// if err != nil { -// return err -// } -// -// return nil -//} - -//func RequestRip() { -// // create RIP message -// message := NewRIPMessage(1, []RIPEntry{}) -// -// // send RIP message to RIP neighbors -// for _, neighbors := range myNeighbors { -// for _, neighbor := range neighbors { -// // check if neighbor is RIP neighbor -// // if not, continue -// for _, ripNeighbor := range myRIPNeighbors { -// if neighbor.VipAddr.String() == ripNeighbor.String() { -// // send RIP message -// err := SendRIPMessage(myVIP, neighbor, message) -// if err != nil { -// continue -// } -// } -// } -// continue -// } -// } -//} -// -//func BroadcastPeriodicUpdates() { -// // for each periodic update, we want to send our nodes in the table -// entries := make([]RIPEntry, len(routingTable)) -// for prefix, hop := range routingTable { -// entries = append(entries, -// RIPEntry{ -// address: ConvertIPToUint32(prefix.Addr().String()), -// mask: uint32(prefix.Bits()), -// cost: hop.Cost, -// }) -// } -// message := NewRIPMessage(2, entries) -// -// // send to each neighbor -// for _, iface := range myInterfaces { -// for _, n := range myNeighbors[iface.Name] { -// err := SendRIPMessage(*iface, n, message) -// if err != nil { -// fmt.Printf("Error sending RIP message to %s\n", n.VipAddr.String()) -// continue -// } -// } -// } -// -//} - -//// THIS MIGHT BE WRONG... -//func SendUpdates() { -// entries := make([]RIPEntry, len(routingTable)) -// // create RIP entries from its interfaces to one another -// for _, iface := range myInterfaces { -// for _, iface2 := range myInterfaces { -// if iface.Name == iface2.Name { -// continue -// } -// // TODO @ MICHAEL: fix this -// // hardcoded way to get cost to 0, fix if you want a better way -// entry := &RIPEntry{ -// address: ConvertIPToUint32(iface2.IpPrefix.Addr().String()), -// cost: 17, -// mask: ConvertIPToUint32(iface.IpPrefix.Addr().String()), -// } -// entries = append(entries, *entry) -// -// entry = &RIPEntry{ -// address: ConvertIPToUint32(iface.IpPrefix.Addr().String()), -// cost: 17, -// mask: ConvertIPToUint32(iface2.IpPrefix.Addr().String()), -// } -// entries = append(entries, *entry) -// } -// } -// -// // create RIP entries from its neighbors -// for _, neighbors := range myNeighbors { -// for _, neighbor := range neighbors { -// ipUint32 := ConvertIPToUint32(neighbor.VipAddr.String()) -// var neighborUint32 uint32 -// for _, interfaces := range myInterfaces { -// if ifaceContainsIP(*interfaces, neighbor.VipAddr) { -// neighborUint32 = ConvertIPToUint32(interfaces.IpPrefix.Addr().String()) -// break -// } -// } -// -// // create RIP entry -// entry := &RIPEntry{ -// address: ipUint32, -// cost: LOCAL_COST, -// mask: neighborUint32, -// } -// -// // add to entries and create RIP message -// entries = append(entries, *entry) -// message := NewRIPMessage(2, entries) -// -// // send RIP message -// for _, Interfaces := range myInterfaces { -// if Interfaces.Name == neighbor.Name { -// err := SendRIPMessage(myVIP, neighbor, message) -// if err != nil { -// continue -// } -// } -// } -// -// } -// } -//} - -// TODO @ MICHEAL: Handle links going down and link recovery -// func CheckAndUpdateRoutingTable() { -// for { -// time.Sleep(12 * time.Second) -// for prefix, hop := range routingTable { -// // delete route if not refreshed in 12 seconds -// // not sure if there is a better way to do this -// if hop.Type == "R" { -// delete(routingTable, prefix) -// SendUpdates() -// } -// } -// } -// } - -// TODO @ MICHAEL: Triggered Updates and Split Horizon with Poisoned Reverse +}
\ No newline at end of file Binary files differdiff --git a/vrouter b/vrouter Binary files differdeleted file mode 100755 index 1329ee6..0000000 --- a/vrouter +++ /dev/null |