aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsotech117 <michael_foiani@brown.edu>2023-10-23 19:02:01 -0400
committersotech117 <michael_foiani@brown.edu>2023-10-23 19:02:01 -0400
commit0798d95168446770e8a22f67483d046aa7f2feb0 (patch)
tree6609899a12f2ac08c41ea9df577f8796089d1e46
parent78de9f539dfbcc7eaf400601c80e24ba7230b910 (diff)
merge with sections of code
-rw-r--r--pkg/ipstack/ipstack.go121
-rwxr-xr-xvhostbin0 -> 3095650 bytes
-rwxr-xr-xvrouterbin0 -> 3095650 bytes
3 files changed, 81 insertions, 40 deletions
diff --git a/pkg/ipstack/ipstack.go b/pkg/ipstack/ipstack.go
index 29a3cb9..c843bee 100644
--- a/pkg/ipstack/ipstack.go
+++ b/pkg/ipstack/ipstack.go
@@ -1,4 +1,5 @@
package ipstack
+
// code begins on line 97 after imports, constants, and structs definitions
// This class is divided as follows:
// 1) INIT FUNCTIONS
@@ -7,11 +8,10 @@ package ipstack
// 4) PRINT FUNCTIONS
// 5) ROUTE FUNCTIONS
// 6) RIP FUNCTIONS
-// 7) PROTOCOL HANDLERS
-// 9) CHECKSUM FUNCTIONS
+// 7) PROTOCOL HANDLERS
+// 8) CHECKSUM FUNCTIONS
// 9) HELPERS
-
import (
"encoding/binary"
"fmt"
@@ -30,7 +30,6 @@ const (
MAX_IP_PACKET_SIZE = 1400
LOCAL_COST uint32 = 0
STATIC_COST uint32 = 4294967295 // 2^32 - 1
- MaxEntries = 64
INFINITY = 16
SIZE_OF_RIP_ENTRY = 12
RIP_PROTOCOL = 200
@@ -76,7 +75,6 @@ type Hop struct {
// GLOBAL VARIABLES (data structures) ------------------------------------------
var myInterfaces []*Interface
-
var myNeighbors = make(map[string][]*Neighbor)
var myRIPNeighbors = make(map[string]*Neighbor)
@@ -87,13 +85,14 @@ var protocolHandlers = make(map[int]HandlerFunc)
var routingTable = make(map[netip.Prefix]Hop)
-var mu sync.Mutex
+var timeoutTableMu 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
-// createUDPListener creates a UDP listener.
+// createUDPListener creates a UDP listener on the given UDP address.
+// It SETS the conn parameter to the created UDP socket.
func createUDPListener(UdpAddr netip.AddrPort, conn *net.UDPConn) error {
listenString := UdpAddr.String()
listenAddr, err := net.ResolveUDPAddr("udp4", listenString)
@@ -109,7 +108,15 @@ func createUDPListener(UdpAddr netip.AddrPort, conn *net.UDPConn) error {
return nil
}
-// initialize parse the lnxfile and initializes the data structures and listener routines
+// Initialize initializes the data structures and creates the UDP sockets.
+//
+// It will return an error if the lnx file is not valid or if a socket fails to be created.
+//
+// After parsing the lnx file, it does the following:
+// 1. adds each local interface to the routing table, as dictated by its subnet
+// 2. adds neighbors to interface->neighbors[] map
+// 3. adds RIP neighbors to RIP neighbor list
+// 4. adds static routes to routing table
func Initialize(lnxFilePath string) error {
// Parse the file
lnxConfig, err := lnxconfig.ParseConfig(lnxFilePath)
@@ -186,7 +193,13 @@ func Initialize(lnxFilePath string) error {
return nil
}
-// defines the go routine that listens on the UDP socket
+// InterfaceListenerRoutine is a go routine for interfaces to listen on a UDP port.
+//
+// It is composed two go routines:
+// 1. a go routine that hangs on the recv and calls RecvIP() when a packet is received
+// 2. a go routine that listens on the channel for a signal to start/stop listening
+//
+// TODO: (performance) remove isUp and use the interface's value instead
func InterfaceListenerRoutine(i *Interface) {
// decompose the interface
socket := i.Socket
@@ -208,9 +221,6 @@ 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
- //}
err := RecvIP(i, &isUp)
if err != nil {
continue
@@ -238,7 +248,12 @@ func InterfaceListenerRoutine(i *Interface) {
// ************************************** DOWN/UP FUNCTIONS ******************************************************
-// sets the interface to be up and sends a triggered update
+// InterfaceUp brings up the link layer
+//
+// It does the following:
+// 1. tells the listener (through a channel) to start listening
+// 2. updates the interface state to up
+// 3. sends RIP request to all neighbors of this iface to quickly update the routing table
func InterfaceUp(iface *Interface) {
// set the state to up and send the signal
iface.State = true
@@ -273,7 +288,12 @@ func InterfaceUpREPL(ifaceName string) {
InterfaceUp(iface)
}
-// sets the interface to be down and sends a triggered update
+// InterfaceDown cuts off the link layer.
+//
+// It does the following:
+// 1. tells the listener (through a channel) to stop listening
+// 2. updates the interface state to down
+// 3. updates the routing table by removing the routes those neighbors connected to, sending triggered updates.
func InterfaceDown(iface *Interface) {
// set the state to down and send the signal
iface.SocketChannel <- false
@@ -322,7 +342,7 @@ func GetRoutes() map[netip.Prefix]Hop {
// ************************************** PRINT FUNCTIONS **********************************************************
-// returns a string representation of the myInterfaces data structure
+// SprintInterfaces returns a string representation of the interfaces data structure
func SprintInterfaces() string {
tmp := ""
for _, iface := range myInterfaces {
@@ -337,7 +357,7 @@ func SprintInterfaces() string {
return tmp
}
-// returns a string representation of the myNeighbors data structure
+// SprintNeighbors returns a string representation of the neighbors data structure
func SprintNeighbors() string {
tmp := ""
for _, iface := range myInterfaces {
@@ -352,7 +372,7 @@ func SprintNeighbors() string {
return tmp
}
-// returns a string representation of the routingTable data structure
+// SprintRoutingTable returns a string representation of the routing table
func SprintRoutingTable() string {
tmp := ""
for prefix, hop := range routingTable {
@@ -369,9 +389,9 @@ func SprintRoutingTable() string {
return tmp
}
-// ************************************** ROUTE FUNCTIONS **********************************************************
+// ************************************** BASIC FUNCTIONS **********************************************************
-// cleans up the data structures and closes the UDP sockets
+// CleanUp cleans up the data structures and closes the UDP sockets
func CleanUp() {
fmt.Print("Cleaning up...\n")
@@ -398,7 +418,14 @@ func CleanUp() {
time.Sleep(5 * time.Millisecond)
}
+// ************************************** ROUTE FUNCTIONS **********************************************************
+
// SendIP sends an IP packet to a destination
+//
+// If the header is nil, then a new header is created
+// If the header is not nil, then it will use that header after decrementing TTL & recomputing checksum
+//
+// TODO: (performance) have this take in an interface instead of src for performance
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)
@@ -466,7 +493,6 @@ func SendIP(src *netip.Addr, dest *Neighbor, protocolNum int, message []byte, de
return -1, errors.WithMessage(err, "Could not bind to UDP port->\t"+dest.UdpAddr.String())
}
- // TODO: make this faster by removing call
// send the packet
bytesWritten, err := iface.Socket.WriteToUDP(bytesToSend, sendAddr)
if err != nil {
@@ -477,9 +503,15 @@ func SendIP(src *netip.Addr, dest *Neighbor, protocolNum int, message []byte, de
return bytesWritten, nil
}
-// RecvIP receives an IP packet from a source
+// RecvIP receives an IP packet from the interface
+// To be called by the listener routine, representing one interface
+// Upon receiving a packet, this function:
+// 1. determines if packet is valid (checksum, TTL)
+// 2. determines if the packet is for me. if so, SENDUP (call correct handler)
+// 3. the packet is not SENTUP, then checks the routing table
+// 4. if there is no route in the routing table, then prints an error and DROPS the packet
func RecvIP(iface *Interface, isOpen *bool) error {
- buffer := make([]byte, MAX_IP_PACKET_SIZE) // TODO: fix wording
+ buffer := make([]byte, MAX_IP_PACKET_SIZE)
// Read on the UDP port
// fmt.Println("wating to read from UDP socket")
@@ -554,9 +586,9 @@ func RecvIP(iface *Interface, isOpen *bool) error {
}
}
- // 4) check forwarding table.
- // if it's a local hop, send to that iface
- // if it's a RIP hop, send to the neighbor with that VIP
+ // 3) check forwarding table.
+ // - if it's a local hop, send to that iface
+ // - if it's a RIP hop, send to the neighbor with that VIP
// fmt.Println("checking routing table")
hop, err := Route(hdr.Dst)
if err == nil { // on no err, found a match
@@ -567,7 +599,7 @@ func RecvIP(iface *Interface, isOpen *bool) error {
return nil
}
- // local hop
+ // - local hop
if hop.Type == "L" {
// if it's a local route, then the name is the interface name
for _, neighbor := range myNeighbors[hop.Interface.Name] {
@@ -580,7 +612,7 @@ func RecvIP(iface *Interface, isOpen *bool) error {
}
}
- // rip hop
+ // - rip hop
if hop.Type == "R" {
// if it's a rip route, then the check is against the hop vip
for _, neighbor := range myNeighbors[hop.Interface.Name] {
@@ -600,7 +632,7 @@ func RecvIP(iface *Interface, isOpen *bool) error {
// ************************************** RIP FUNCTIONS *******************************************************
-// creates a byte array that represents a RIP message
+// MakeRipMessage returns the byte array to be used in SendIp for a RIP packet
func MakeRipMessage(command uint16, entries []RIPEntry) []byte {
if command == 1 { // request message
buf := make([]byte, SIZE_OF_RIP_HEADER)
@@ -636,7 +668,8 @@ func MakeRipMessage(command uint16, entries []RIPEntry) []byte {
return buf
}
-// PeriodicUpdateRoutine sends updates to neighbors every 5 seconds
+// PeriodicUpdateRoutine sends RIP updates to neighbors every 5 seconds
+// TODO: (performace) consider making this multithreaded and loops above more efficient
func PeriodicUpdateRoutine() {
for {
// for each periodic update, we want to send our nodes in the table
@@ -647,7 +680,6 @@ func PeriodicUpdateRoutine() {
if !in {
continue
}
- // TODO: consider making this multithreaded and loops above more efficient
// Sending to a rip neighbor
// create the entries
@@ -683,7 +715,7 @@ func PeriodicUpdateRoutine() {
}
}
-// SendTriggeredUpdates sends updates to ALL neighbors
+// SendTriggeredUpdates sends the entries consumed to ALL neighbors
func SendTriggeredUpdates(newEntries []RIPEntry) {
for _, iface := range myInterfaces {
for _, n := range myNeighbors[iface.Name] {
@@ -705,12 +737,13 @@ func SendTriggeredUpdates(newEntries []RIPEntry) {
}
}
-// manages the timeout table go routine
+// ManageTimeoutsRoutine manages the timeout table by incrementing the timeouts every second.
+// If a timeout reaches MAX_TIMEOUT, then the entry is deleted from the routing table and a triggered update is sent.
func ManageTimeoutsRoutine() {
for {
time.Sleep(time.Second)
- mu.Lock()
+ timeoutTableMu.Lock()
// check if any timeouts have occurred
for key, _ := range timeoutTable {
timeoutTable[key]++
@@ -728,12 +761,15 @@ func ManageTimeoutsRoutine() {
}
}
}
- mu.Unlock()
+ timeoutTableMu.Unlock()
//fmt.Println("Timeout table: ", timeoutTable)
}
}
-// StartRipRoutines routine to send rip requests to neighbors
+// StartRipRoutines handles all the routines for RIP
+// 1. sends a RIP request to every neighbor
+// 2. starts the routine that sends periodic updates every 5 seconds
+// 3. starts the routine that manages the timeout table
func StartRipRoutines() {
// send a request to every neighbor
go func() {
@@ -764,7 +800,7 @@ func StartRipRoutines() {
// ************************************** PROTOCOL HANDLERS *******************************************************
-// registers a protocol handler
+// RegisterProtocolHandler registers a protocol handler for a given protocol number
func RegisterProtocolHandler(protocolNum int) bool {
if protocolNum == RIP_PROTOCOL {
protocolHandlers[protocolNum] = HandleRIP
@@ -778,6 +814,10 @@ func RegisterProtocolHandler(protocolNum int) bool {
return false
}
+// HandleRIP handles incoming RIP packets in the following way:
+// 1. if the command is a request, send a RIP response only to that requestor
+// 2. if the command is a response, parse the entries, update the routing table from them,
+// and send applicable triggered updates (see implementation for how to update)
func HandleRIP(src *Interface, message []byte, hdr *ipv4header.IPv4Header) error {
// parse the RIP message
command := int(binary.BigEndian.Uint16(message[0:2]))
@@ -876,14 +916,14 @@ func HandleRIP(src *Interface, message []byte, hdr *ipv4header.IPv4Header) error
// first, upon an update from this prefix, reset its timeout
if hop.Type == "R" {
- mu.Lock()
+ timeoutTableMu.Lock()
_, in := timeoutTable[destination]
if in {
if routingTable[destination].VIP == hdr.Src {
timeoutTable[destination] = 0
}
}
- mu.Unlock()
+ timeoutTableMu.Unlock()
}
// case 1) the entry SRC == the hop to itself
@@ -900,9 +940,9 @@ func HandleRIP(src *Interface, message []byte, hdr *ipv4header.IPv4Header) error
time.Sleep(time.Second * time.Duration(MAX_TIMEOUT))
if routingTable[destination].Cost == INFINITY {
delete(routingTable, destination)
- mu.Lock()
+ timeoutTableMu.Lock()
delete(timeoutTable, destination)
- mu.Unlock()
+ timeoutTableMu.Unlock()
}
}()
}
@@ -951,6 +991,7 @@ func ValidateChecksum(b []byte, fromHeader uint16) uint16 {
// *********************************************** HELPERS **********************************************************
// Route returns the next HOP, based on longest prefix match for a given ip
+// TODO: revisit how to do this at the bit level, not hardcoded for 32 & 24
func Route(src netip.Addr) (Hop, error) {
possibleBits := [2]int{32, 24}
for _, bits := range possibleBits {
diff --git a/vhost b/vhost
new file mode 100755
index 0000000..90cbbf2
--- /dev/null
+++ b/vhost
Binary files differ
diff --git a/vrouter b/vrouter
new file mode 100755
index 0000000..e8727c5
--- /dev/null
+++ b/vrouter
Binary files differ