diff options
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/ipstack/ipstack.go | 91 |
1 files changed, 39 insertions, 52 deletions
diff --git a/pkg/ipstack/ipstack.go b/pkg/ipstack/ipstack.go index e3d9ca2..d8db8d2 100644 --- a/pkg/ipstack/ipstack.go +++ b/pkg/ipstack/ipstack.go @@ -24,6 +24,7 @@ const ( RIP_PROTOCOL = 200 TEST_PROTOCOL = 0 SIZE_OF_RIP_HEADER = 4 + MAX_TIMEOUT = 12 ) // STRUCTS --------------------------------------------------------------------- @@ -74,6 +75,9 @@ var protocolHandlers = make(map[int]HandlerFunc) var routingTable = make(map[netip.Prefix]Hop) +var mu sync.Mutex +var timeoutTable = make(map[netip.Prefix]int) + // ************************************** INIT FUNCTIONS ********************************************************** // reference: https://github.com/brown-csci1680/lecture-examples/blob/main/ip-demo/cmd/udp-ip-recv/main.go @@ -195,8 +199,6 @@ func InterfaceListenerRoutine(i *Interface) { //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 { continue @@ -355,6 +357,13 @@ func SprintRoutingTable() string { return tmp } +// prints the test packet as per the spec +func handleTestPackets(src *Interface, dest *Neighbor, message []byte, hdr *ipv4header.IPv4Header) error { + fmt.Printf("Received test packet: Src: %s, Dst: %s, TTL: %d, Data: %s\n", + hdr.Src.String(), hdr.Dst.String(), hdr.TTL, string(message)) + return nil +} + // ************************************** BASIC FUNCTIONS ********************************************************** // cleans up the data structures and closes the UDP sockets @@ -453,6 +462,7 @@ func SendIP(src *netip.Addr, dest *Neighbor, protocolNum int, message []byte, de } // TODO: make this faster by removing call + // send the packet bytesWritten, err := iface.RecvSocket.WriteToUDP(bytesToSend, sendAddr) if err != nil { fmt.Println("Error writing to UDP socket") @@ -594,7 +604,8 @@ func makeRipMessage(command uint16, entries []RIPEntry) []byte { binary.BigEndian.PutUint16(buf[2:4], uint16(0)) return buf } - // else, command == 2, response message + + // command == 2, response message // create the buffer bufLen := SIZE_OF_RIP_HEADER + // sizeof uint16 is 2, we have two of them @@ -621,23 +632,24 @@ func makeRipMessage(command uint16, entries []RIPEntry) []byte { return buf } - +// sends updates to neighbors every 5 seconds func periodicUpdateRoutine() { for { // for each periodic update, we want to send our nodes in the table for _, iface := range myInterfaces { for _, n := range myNeighbors[iface.Name] { _, in := myRIPNeighbors[n.VipAddr.String()] + // if the neighbor is not a RIP neighbor, skip it if !in { continue } // TODO: consider making this multithreaded and loops above more efficient - // if we're here, we are sending this to a rip neighbor + // Sending to a rip neighbor + // create the entries entries := make([]RIPEntry, 0) for prefix, hop := range routingTable { // implement split horizon + poison reverse at entry level - // fmt.Println("prefix: ", prefix) var cost uint32 if hop.VIP == n.VipAddr { cost = INFINITY @@ -651,6 +663,7 @@ func periodicUpdateRoutine() { }) } + // make the message and send it message := makeRipMessage(2, entries) addr := iface.IpPrefix.Addr() _, err := SendIP(&addr, n, RIP_PROTOCOL, message, n.VipAddr.String(), nil) @@ -661,23 +674,22 @@ func periodicUpdateRoutine() { } } - // wait 5 sec + // wait 5 sec and repeat time.Sleep(5 * time.Second) } } -var mu sync.Mutex -var timeoutTable = make(map[netip.Prefix]int) -var MAX_TIMEOUT = 12 - +// when triggered, sends updates to neighbors func sendTriggeredUpdates(newEntries []RIPEntry) { for _, iface := range myInterfaces { for _, n := range myNeighbors[iface.Name] { + // only send to RIP neighbors, else skip _, in := myRIPNeighbors[n.VipAddr.String()] if !in { continue } + // send the made entries to the neighbor message := makeRipMessage(2, newEntries) addr := iface.IpPrefix.Addr() _, err := SendIP(&addr, n, RIP_PROTOCOL, message, n.VipAddr.String(), nil) @@ -689,60 +701,41 @@ func sendTriggeredUpdates(newEntries []RIPEntry) { } } -func timeoutKey(prefix netip.Prefix, addr netip.Addr) string { - return prefix.String() + "-" + addr.String() -} - +// manages the timeout table go routine func manageTimeoutsRoutine() { for { time.Sleep(time.Second) - // note: waitgroup causes deadlock then crashing - //wg := &sync.WaitGroup{} - //wg.Add(len(timeoutTable)) - //mu.Lock() - //for prefix, _ := range timeoutTable { - // go func(p netip.Prefix) { - // timeoutTable[p]++ - // if timeoutTable[p] == MAX_TIMEOUT { - // delete(routingTable, p) - // delete(timeoutTable, p) - // // TODO: send triggered update - // } - // - // wg.Done() - // }(prefix) - //} - //wg.Wait() - //mu.Unlock() - mu.Lock() + // check if any timeouts have occurred for key, _ := range timeoutTable { timeoutTable[key]++ + // if the timeout is MAX_TIMEOUT, delete the entry if timeoutTable[key] == MAX_TIMEOUT { delete(timeoutTable, key) newEntries := make([]RIPEntry, 0) delete(routingTable, key) newEntries = append(newEntries, RIPEntry{key, INFINITY}) + // send triggered update on timeout if len(newEntries) > 0 { sendTriggeredUpdates(newEntries) } } } - // fmt.Println("timeout table: ", timeoutTable) mu.Unlock() - //fmt.Println("Timeout table: ", timeoutTable) } } +// go routine to send rip requests to neighbors func startRipRoutines() { // send a request to every neighbor go func() { for _, iface := range myInterfaces { for _, neighbor := range myNeighbors[iface.Name] { + // only send to RIP neighbors, else skip _, in := myRIPNeighbors[neighbor.VipAddr.String()] if !in { continue @@ -758,16 +751,16 @@ func startRipRoutines() { } }() + // start a routine that sends updates every 5 seconds go periodicUpdateRoutine() // make a "timeout" table, for each response we add to the table via rip go manageTimeoutsRoutine() - - // start a routine that sends updates every 10 seconds } // ************************************** Protocol Handlers ******************************************************* +// registers a protocol handler func RegisterProtocolHandler(protocolNum int) bool { if protocolNum == RIP_PROTOCOL { protocolHandlers[protocolNum] = handleRIP @@ -783,24 +776,22 @@ 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 command := int(binary.BigEndian.Uint16(message[0:2])) switch command { + // request message case 1: //fmt.Println("Received RIP command for specific info") + // only send if the person asking is a RIP neighbor neighbor, in := myRIPNeighbors[hdr.Src.String()] if !in { break } - // fmt.Println("he is my rip neighbor ", hdr.Src.String()) - // build the entries entries := make([]RIPEntry, 0) for prefix, hop := range routingTable { // implement split horizon + poison reverse at entry level - // fmt.Println("prefix: ", prefix) var cost uint32 if hop.VIP == hdr.Src { cost = INFINITY @@ -813,15 +804,17 @@ func handleRIP(src *Interface, dest *Neighbor, message []byte, hdr *ipv4header.I cost: cost, }) } + // send the entries res := makeRipMessage(2, entries) _, err := SendIP(&hdr.Dst, neighbor, RIP_PROTOCOL, res, hdr.Src.String(), nil) if err != nil { return err } break + // response message case 2: - numEntries := int(binary.BigEndian.Uint16(message[2:4])) // fmt.Println("Received RIP response with", numEntries, "entries") + numEntries := int(binary.BigEndian.Uint16(message[2:4])) // parse the entries entries := make([]RIPEntry, 0) @@ -929,14 +922,8 @@ func handleRIP(src *Interface, dest *Neighbor, message []byte, hdr *ipv4header.I return nil } -func handleTestPackets(src *Interface, dest *Neighbor, message []byte, hdr *ipv4header.IPv4Header) error { - fmt.Printf("Received test packet: Src: %s, Dst: %s, TTL: %d, Data: %s\n", - hdr.Src.String(), hdr.Dst.String(), hdr.TTL, string(message)) - return nil -} - // ************************************** CHECKSUM FUNCTIONS ****************************************************** - +// reference: https://github.com/brown-csci1680/lecture-examples/blob/main/ip-demo/cmd/udp-ip-recv/main.go func ComputeChecksum(b []byte) uint16 { checksum := header.Checksum(b, 0) checksumInv := checksum ^ 0xffff @@ -950,9 +937,9 @@ func ValidateChecksum(b []byte, fromHeader uint16) uint16 { return checksum } -// ************************************** RIP FUNCTIONS ********************************************************** +// ******************************************* RIP HELPERS ********************************************************** -// TODO @ MICHAEL: LONGEST PREFIX MATCHING +// returns the longest prefix match for a given ip func LongestPrefix(src netip.Addr) (Hop, error) { possibleBits := [2]int{32, 24} for _, bits := range possibleBits { |