aboutsummaryrefslogtreecommitdiff
path: root/pkg/ipstack
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/ipstack')
-rw-r--r--pkg/ipstack/ipstack.go91
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 {