aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--binaries.example.json17
-rw-r--r--cmd/vhost/main.go71
-rw-r--r--cmd/vrouter/main.go75
-rw-r--r--nodes.json7
-rw-r--r--pkg/ipstack/ipstack.go314
-rwxr-xr-xvhostbin0 -> 3080475 bytes
-rwxr-xr-xvrouterbin0 -> 3080644 bytes
7 files changed, 432 insertions, 52 deletions
diff --git a/binaries.example.json b/binaries.example.json
new file mode 100644
index 0000000..b6ff6d9
--- /dev/null
+++ b/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/cmd/vhost/main.go b/cmd/vhost/main.go
index 82b8195..27e073f 100644
--- a/cmd/vhost/main.go
+++ b/cmd/vhost/main.go
@@ -4,14 +4,83 @@ import (
"bufio"
"fmt"
"os"
+ "iptcp/pkg/ipstack"
+ "strings"
)
func main() {
+ if len(os.Args) != 2 {
+ fmt.Printf("Usage: %s <configFile>\n", os.Args[0])
+ os.Exit(1)
+ }
+
+ fileName := os.Args[1]
+
+ go ipstack.Initialize(fileName)
+
+
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
line := scanner.Text()
- fmt.Println(line)
+
+ if line == "li" {
+ fmt.Println("Name\tAddr/Prefix\tState")
+ ipstack.SprintInterfaces()
+ }
+
+ if line == "ln" {
+ fmt.Println("Iface\tVIP\tUDPAddr")
+ ipstack.SprintNeighbors()
+ }
+
+ if line == "lr" {
+ fmt.Println("T\tPrefix\tNext Hop\tCost")
+ ipstack.SprintRoutingTable()
+ }
+
+ if len(line) > 4 {
+ if line[:4] == "down" {
+ // get interface name
+ ifaceName := line[5:]
+ ipstack.InterfaceDownREPL(ifaceName)
+ }
+
+ if line[:4] == "send" {
+ // get IP address and message that follows it
+ listOfWords := strings.Split(line, " ")
+ ipAddr := listOfWords[1]
+ message := listOfWords[2:]
+ // combine message into one string
+ messageToSend := strings.Join(message, " ")
+ // convert message to byte array
+ messageToSendBytes := []byte(messageToSend)
+ // get interface by ipAddr
+ iface, err := ipstack.GetNeighborByIP(ipAddr)
+ if err != nil {
+ fmt.Println(err)
+ iface, err = ipstack.GetRouteByIP(ipAddr)
+ if err != nil {
+ fmt.Println(err)
+ continue
+ }
+ ipstack.SendIP(ipstack.GetMyVIP(), iface, 0, messageToSendBytes, ipAddr)
+ }
+ ipstack.SendIP(ipstack.GetMyVIP(), iface, 0, messageToSendBytes, ipAddr)
+ }
+ }
+ if len(line) > 2 {
+ if line[:2] == "up" {
+ // get interface name
+ ifaceName := line[3:]
+ ipstack.InterfaceUpREPL(ifaceName)
+ }
+ }
+
+ if line == "q" {
+ ipstack.CleanUp()
+ os.Exit(0)
+ }
}
} \ No newline at end of file
diff --git a/cmd/vrouter/main.go b/cmd/vrouter/main.go
index 158016a..abd0fc0 100644
--- a/cmd/vrouter/main.go
+++ b/cmd/vrouter/main.go
@@ -5,19 +5,25 @@ import (
"fmt"
"os"
"time"
+ "iptcp/pkg/ipstack"
+ "strings"
+
)
func SendUpdates() {
+ myInterfaces := ipstack.GetInterfaces()
+ myNeighbors := ipstack.GetNeighbors()
for _, iface := range myInterfaces {
// send RIP updates to all neighbors
- for _, neighbor := range myNeighbors {
- iface.udp.Write(neighbor, data)
+ for _, _ = range myNeighbors {
+ // iface.udp.Write(neighbor, data)
+ // iface.RecvSocket.Write(neighbor, data)
// wait for response for 12 seconds
response := make([]byte, 512)
- iface.udp.Read(response)
+ iface.RecvSocket.Read(response)
time.Sleep(12 * time.Second)
if len(response) == 0 {
- RemoveNeighbor(neighbor)
+ // ipstack.RemoveNeighbor(neighbor)
}
}
}
@@ -32,7 +38,12 @@ func main() {
fileName := os.Args[1]
- initialize(fileName)
+ // initialize(fileName)
+ go ipstack.Initialize(fileName)
+ // myInterfaces := ipstack.GetInterfaces()
+ // myNeighbors := ipstack.GetNeighbors()
+ // myRoutes := ipstack.GetRoutes()
+
go SendUpdates()
@@ -40,6 +51,58 @@ func main() {
for scanner.Scan() {
line := scanner.Text()
- fmt.Println(line)
+ switch line {
+ case "li":
+ fmt.Println("Name\tAddr/Prefix\tState")
+ ipstack.SprintInterfaces()
+ case "ln":
+ fmt.Println("Iface\tVIP\tUDPAddr")
+ ipstack.SprintNeighbors()
+ case "lr":
+ fmt.Println("T\tPrefix\tNext Hop\tCost")
+ ipstack.SprintRoutingTable()
+ case "q":
+ ipstack.CleanUp()
+ os.Exit(0)
+ default:
+ if len(line) > 4 {
+ if line[:4] == "down" {
+ // get interface name
+ ifaceName := line[5:]
+ ipstack.InterfaceDownREPL(ifaceName)
+ }
+
+ if line[:4] == "send" {
+ // get IP address and message that follows it
+ listOfWords := strings.Split(line, " ")
+ ipAddr := listOfWords[1]
+ message := listOfWords[2:]
+ // combine message into one string
+ messageToSend := strings.Join(message, " ")
+ // convert message to byte array
+ messageToSendBytes := []byte(messageToSend)
+ // get interface by ipAddr
+ iface, err := ipstack.GetNeighborByIP(ipAddr)
+ if err != nil {
+ fmt.Println(err)
+ iface, err = ipstack.GetRouteByIP(ipAddr)
+ if err != nil {
+ fmt.Println(err)
+ continue
+ }
+ ipstack.SendIP(ipstack.GetMyVIP(), iface, 0, messageToSendBytes, ipAddr)
+ }
+ ipstack.SendIP(ipstack.GetMyVIP(), iface, 0, messageToSendBytes, ipAddr)
+ }
+ }
+ if len(line) > 2 {
+ if line[:2] == "up" {
+ // get interface name
+ ifaceName := line[3:]
+ ipstack.InterfaceUpREPL(ifaceName)
+ }
+ }
+ continue
+ }
}
} \ No newline at end of file
diff --git a/nodes.json b/nodes.json
new file mode 100644
index 0000000..7b91355
--- /dev/null
+++ b/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/pkg/ipstack/ipstack.go b/pkg/ipstack/ipstack.go
index be8bc1e..dca19d6 100644
--- a/pkg/ipstack/ipstack.go
+++ b/pkg/ipstack/ipstack.go
@@ -51,11 +51,13 @@ type RIPEntry struct {
type Hop struct {
Cost uint32
- VipAsStr string
+ VipAsStr string
+ Type string
+ // added this for printing purposes
}
// GLOBAL VARIABLES (data structures) ------------------------------------------
-var myVIP netip.Addr
+var myVIP Interface
var myInterfaces []*Interface
var myNeighbors = make(map[string][]*Neighbor)
@@ -68,28 +70,30 @@ var protocolHandlers = make(map[uint16]HandlerFunc)
var routingTable = make(map[netip.Prefix]Hop)
// reference: https://github.com/brown-csci1680/lecture-examples/blob/main/ip-demo/cmd/udp-ip-recv/main.go
-func createUDPConn(UdpAddr netip.AddrPort, conn *net.UDPConn) error {
+func createUDPConn(UdpAddr netip.AddrPort, conn *net.UDPConn, isN bool) error {
listenString := UdpAddr.String()
listenAddr, err := net.ResolveUDPAddr("udp4", listenString)
if err != nil {
return errors.WithMessage(err, "Error resolving address->\t"+listenString)
}
- tmpConn, err := net.ListenUDP("udp4", listenAddr)
- if err != nil {
- return errors.WithMessage(err, "Could not bind to UDP port->\t"+listenString)
+ if !isN {
+ tmpConn, err := net.ListenUDP("udp4", listenAddr)
+ if err != nil {
+ return errors.WithMessage(err, "Could not bind to UDP port->\t"+listenString)
+ }
+ *conn = *tmpConn
+ } else {
+ tmpConn, err := net.DialUDP("udp4", nil, listenAddr)
+ if err != nil {
+ return errors.WithMessage(err, "Could not bind to UDP port->\t"+listenString)
+ }
+ *conn = *tmpConn
}
- *conn = *tmpConn
return nil
}
func Initialize(lnxFilePath string) error {
- //if len(os.Args) != 2 {
- // fmt.Printf("Usage: %s <configFile>\n", os.Args[0])
- // os.Exit(1)
- //}
- //lnxFilePath := os.Args[1]
-
// Parse the file
lnxConfig, err := lnxconfig.ParseConfig(lnxFilePath)
if err != nil {
@@ -97,7 +101,8 @@ func Initialize(lnxFilePath string) error {
}
// 1) initialize the interfaces on this node here and into the routing table
- static := false
+ // static := false
+ interfaceToReturn := Interface{}
for _, iface := range lnxConfig.Interfaces {
prefix := netip.PrefixFrom(iface.AssignedIP, iface.AssignedPrefix.Bits())
i := &Interface{
@@ -106,10 +111,15 @@ func Initialize(lnxFilePath string) error {
UdpAddr: iface.UDPAddr,
RecvSocket: net.UDPConn{},
SocketChannel: make(chan bool),
- State: false,
+ State: true,
+ }
+ if interfaceToReturn == (Interface{}) {
+ interfaceToReturn = *i
+ myVIP = *i
}
+ // Added this for printing purposes for REPL FYI, if you have a better way lmk
- err := createUDPConn(iface.UDPAddr, &i.RecvSocket)
+ err := createUDPConn(iface.UDPAddr, &i.RecvSocket, false)
if err != nil {
return errors.WithMessage(err, "Error creating UDP socket for interface->\t"+iface.Name)
}
@@ -118,11 +128,12 @@ func Initialize(lnxFilePath string) error {
// TODO: (FOR HOSTS ONLY)
// add STATIC to routing table
- if !static {
- ifacePrefix := netip.MustParsePrefix("0.0.0.0/0")
- routingTable[ifacePrefix] = Hop{STATIC_COST, iface.Name}
- static = true
- }
+ // if !static {
+ // ifacePrefix := netip.MustParsePrefix("0.0.0.0/0")
+ // routingTable[ifacePrefix] = Hop{STATIC_COST, iface.Name, "S"}
+ // static = true
+ // }
+ // Took this out for printing purposes for REPL FYI
}
// 2) initialize the neighbors connected to the node and into the routing table
@@ -134,7 +145,7 @@ func Initialize(lnxFilePath string) error {
SocketChannel: make(chan bool),
}
- err := createUDPConn(neighbor.UDPAddr, &n.SendSocket)
+ err := createUDPConn(neighbor.UDPAddr, &n.SendSocket, true)
if err != nil {
return errors.WithMessage(err, "Error creating UDP socket for neighbor->\t"+neighbor.DestAddr.String())
}
@@ -144,14 +155,22 @@ func Initialize(lnxFilePath string) error {
// add to routing table
// TODO: REVISIT AND SEE IF "24" IS CORRECT
neighborPrefix := netip.PrefixFrom(neighbor.DestAddr, 24)
- routingTable[neighborPrefix] = Hop{LOCAL_COST, neighbor.InterfaceName}
+ routingTable[neighborPrefix] = Hop{LOCAL_COST, neighbor.InterfaceName, "L"}
+ }
+
+ for _, route := range lnxConfig.StaticRoutes {
+ // add to routing table
+ prefix := netip.MustParsePrefix("0.0.0.0/0")
+ routingTable[prefix] = Hop{LOCAL_COST, route.String(), "S"}
}
+ // added for printing purposes for REPL FYI
return nil
}
func InterfaceListenerRoutine(socket net.UDPConn, signal <-chan bool) {
- isUp := false
+ isUp := true
+ // testing purposes set to TRUE
closed := false
// go routine that hangs on the recv
@@ -199,11 +218,34 @@ func InterfaceUp(iface *Interface) {
iface.SocketChannel <- true
}
+func InterfaceUpREPL(ifaceName string) {
+ iface, err := GetInterfaceByName(ifaceName)
+ if err != nil {
+ fmt.Println("Error getting interface by name", err)
+ return
+ }
+ iface.State = true
+ iface.SocketChannel <- true
+}
+
+// we could do either of these but the REPL results in less work done in router and host
+
func InterfaceDown(iface *Interface) {
iface.SocketChannel <- false
iface.State = false
}
+func InterfaceDownREPL(ifaceName string) {
+ iface, err := GetInterfaceByName(ifaceName)
+ if err != nil {
+ fmt.Println("Error getting interface by name", err)
+ return
+ }
+ iface.SocketChannel <- false
+ iface.State = false
+}
+// same as above comment
+
func GetInterfaceByName(ifaceName string) (*Interface, error) {
for _, iface := range myInterfaces {
if iface.Name == ifaceName {
@@ -214,6 +256,36 @@ func GetInterfaceByName(ifaceName string) (*Interface, error) {
return nil, errors.Errorf("No interface with name %s", ifaceName)
}
+func GetNeighborByIP(ipAddr string) (*Neighbor, error) {
+ 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 GetRouteByIP(ipAddr string) (*Neighbor, error) {
+ for prefix, hop := range routingTable {
+ if prefix.Contains(netip.MustParseAddr(ipAddr)) {
+ fmt.Println("found route", hop.VipAsStr)
+ neighbors, err := GetNeighborsToInterface(hop.VipAsStr)
+ if err != nil {
+ fmt.Println("Error getting neighbors to interface", err)
+ return nil, err
+ }
+ neighbor := neighbors[0]
+
+ 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
@@ -222,30 +294,38 @@ func GetNeighborsToInterface(ifaceName string) ([]*Neighbor, error) {
return nil, errors.Errorf("No interface with name %s", ifaceName)
}
-func SprintInterfaces() string {
- buf := ""
+func GetMyVIP() Interface {
+ return myVIP
+}
+
+func SprintInterfaces() {
for _, iface := range myInterfaces {
- buf += fmt.Sprintf("%s\t%s\t%t\n", iface.Name, iface.IpPrefix.String(), iface.State)
+ if iface.State {
+ fmt.Printf("%s\t%s\t%s\n", iface.Name, iface.IpPrefix.String(), "UP")
+ } else {
+ fmt.Printf("%s\t%s\t%s\n", iface.Name, iface.IpPrefix.String(), "DOWN")
+ }
}
- return buf
}
-func SprintNeighbors() string {
- buf := ""
+func SprintNeighbors() {
for ifaceName, neighbor := range myNeighbors {
for _, n := range neighbor {
- buf += fmt.Sprintf("%s\t%s\t%s\n", ifaceName, n.UdpAddr.String(), n.VipAddr.String())
+ fmt.Printf("%s\t%s\t%s\n", ifaceName, n.VipAddr.String(), n.UdpAddr.String())
}
}
- return buf
}
-func SprintRoutingTable() string {
- buf := ""
+func SprintRoutingTable() {
for prefix, hop := range routingTable {
- buf += fmt.Sprintf("%s\t%s\t%d\n", prefix.String(), hop.VipAsStr, hop.Cost)
+ if hop.Type == "L" {
+ fmt.Printf("%s\t%s\tLOCAL:%s\t%d\n", hop.Type, prefix.String(), hop.VipAsStr, hop.Cost)
+ } else if hop.Type == "S" {
+ fmt.Printf("%s\t%s\t%s\t%s\n", hop.Type, prefix.String(), hop.VipAsStr, "-")
+ } else {
+ fmt.Printf("%s\t%s\t%s\t%d\n", hop.Type, prefix.String(), hop.VipAsStr, hop.Cost)
+ }
}
- return buf
}
func DebugNeighbors() {
@@ -256,6 +336,27 @@ func DebugNeighbors() {
}
}
+// func RemoveNeighbor(neighbor Neighbor) {
+// // TODO: remove from routing table
+// myRoutes := GetRoutes()
+// for prefix, hop := range myRoutes {
+// if hop.VipAsStr == neighbor.VipAddr.String() {
+// delete(myRoutes, prefix)
+// }
+// }
+
+// // TODO: remove from myNeighbors
+// myNeighbors[neighbor.VipAddr.String()] = nil
+
+// // TODO: close the UDP socket
+// err := neighbor.SendSocket.Close()
+// if err != nil {
+// fmt.Println("Error closing UDP socket", err)
+// }
+
+// }
+// untested function above
+
func CleanUp() {
fmt.Print("Cleaning up...\n")
// go through the interfaces, pop thread & close the UDP FDs
@@ -293,7 +394,7 @@ func CleanUp() {
}
// TODO: have it take TTL so we can decrement it when forwarding
-func SendIP(src Interface, dest Neighbor, protocolNum int, message []byte) error {
+func SendIP(src Interface, dest *Neighbor, protocolNum int, message []byte, destIP string) error {
hdr := ipv4header.IPv4Header{
Version: 4,
Len: 20, // Header length is always 20 when no IP options
@@ -306,7 +407,7 @@ func SendIP(src Interface, dest Neighbor, protocolNum int, message []byte) error
Protocol: protocolNum,
Checksum: 0, // Should be 0 until checksum is computed
Src: src.IpPrefix.Addr(),
- Dst: dest.VipAddr,
+ Dst: netip.MustParseAddr(destIP),
Options: []byte{},
}
@@ -334,10 +435,25 @@ func SendIP(src Interface, dest Neighbor, protocolNum int, message []byte) error
if err != nil {
return err
}
- bytesWritten, err := dest.SendSocket.WriteToUDP(bytesToSend, listenAddr)
+ bytesWritten, err := dest.SendSocket.Write(bytesToSend)
if err != nil {
return err
}
+
+ // send to the dest.UdpAddr without the SendSocket
+ // conn, err := net.DialUDP("udp4", nil, listenAddr)
+ // if err != nil {
+ // fmt.Println(err, "here5")
+ // return err
+ // }
+
+ // bytesWritten, err := conn.Write(bytesToSend)
+ // if err != nil {
+ // fmt.Println(err, "here6")
+ // return err
+ // }
+
+ // what we had previously just in case
fmt.Printf("Sent %d bytes to %s\n", bytesWritten, listenAddr.String())
return nil
@@ -348,7 +464,7 @@ func RecvIP(conn net.UDPConn, isOpen *bool) error {
// Read on the UDP port
fmt.Println("wating to read from UDP socket")
- _, sourceAddr, err := conn.ReadFromUDP(buffer)
+ _, _, err := conn.ReadFromUDP(buffer)
if err != nil {
return err
}
@@ -384,17 +500,94 @@ func RecvIP(conn net.UDPConn, isOpen *bool) error {
// Next, get the message, which starts after the header
message := buffer[headerSize:]
- // Finally, print everything out
- fmt.Printf("Received IP packet from %s\nHeader: %v\nChecksum: %s\nMessage: %s\n",
- sourceAddr.String(), hdr, checksumState, string(message))
-
// TODO: handle the message
// 1) check if the TTL & checksum is valid
+ TTL := hdr.TTL
+ if TTL == 0 {
+ // drop the packet
+ return nil
+ }
+
+ // check if the checksum is valid
+ if checksumState == "FAIL" {
+ // drop the packet
+ return nil
+ }
+
// 2) check if the message is for me, if so, sendUP (aka call the correct handler)
+ if hdr.Dst.String() == myVIP.IpPrefix.Addr().String() {
+ // call the correct handler in our case its just printing out the message
+ fmt.Println("for me")
+ if hdr.Protocol == 0 {
+ 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
+ }
+
+ }
// if not, need to forward the packer to a neighbor or check the table
// after decrementing TTL and updating checksum
+ hdr.TTL--
+ // update checksum
+ headerBytes, err = hdr.Marshal()
+ if err != nil {
+ log.Fatalln("Error marshalling header: ", err)
+ }
+ hdr.Checksum = int(ComputeChecksum(headerBytes))
+ headerBytes, err = hdr.Marshal()
+ if err != nil {
+ log.Fatalln("Error marshalling header: ", err)
+ }
+ bytesToSend := make([]byte, 0, len(headerBytes)+len(message))
+ bytesToSend = append(bytesToSend, headerBytes...)
+ bytesToSend = append(bytesToSend, []byte(message)...)
+
+
// 3) check if message is for a neighbor, if so, sendIP there
- // 4) check if message is for a neighbor, if so, forward to the neighbor with that VIP
+ for _, neighbors := range myNeighbors {
+ // fmt.Println(neighbors)
+ for _, neighbor := range neighbors {
+ if hdr.Dst.String() == neighbor.VipAddr.String() {
+ fmt.Println("for neighbor")
+ // send the packet to the neighbor
+ err := SendIP(myVIP, neighbor, hdr.Protocol, bytesToSend, hdr.Dst.String())
+ if err != nil {
+ fmt.Println("Error sending IP packet", err)
+ return err
+ }
+ return nil
+ }
+ }
+ }
+ fmt.Println("No neighbors, checking Routes")
+ // 4) check forwarding table. if so, forward to the neighbor with that VIP
+
+ // needs RIP Protocol I believed
+
+ for prefix, hop := range routingTable {
+ fmt.Println(prefix)
+ if prefix.Contains(hdr.Dst) {
+ // send the packet to the neighbor
+ fmt.Println("testing", prefix, hdr.Dst.String())
+ neighbors, err := GetNeighborsToInterface(hop.VipAsStr)
+ if err != nil {
+ fmt.Println("Error getting neighbor by IP", err)
+ return err
+ }
+ // get the longest prefix match
+ for _, neighbor := range neighbors {
+ fmt.Println("for neighbor", neighbor.VipAddr.String())
+ // send the packet to the neighbor
+ }
+ // err = SendIP(myVIP, neighbor, hdr.Protocol, bytesToSend, hdr.Dst.String())
+ if err != nil {
+ fmt.Println("Error sending IP packet", err)
+ return err
+ }
+ }
+ }
+ // send 10.2.0.3 hello
+ // 5) if not, drop the packet
return nil
}
@@ -411,3 +604,34 @@ func ValidateChecksum(b []byte, fromHeader uint16) uint16 {
return checksum
}
+
+func GetInterfaces() []*Interface {
+ return myInterfaces
+}
+
+func GetNeighbors() map[string][]*Neighbor {
+ return myNeighbors
+}
+
+func GetRoutes() map[netip.Prefix]Hop {
+ return routingTable
+}
+
+// func LongestPrefixMatch(ipAddr string) (netip.Addr, error) {
+// var longestMatch netip.Addr
+// var longestMatchLength int
+// ip := netip.MustParseAddr(ipAddr)
+// for prefix := range routingTable {
+// // Extract the prefix length using the Bits method
+// prefixLen := prefix.Bits()
+// if prefix.Contains(ip) && prefixLen > longestMatchLength {
+// longestMatch = ip
+// longestMatchLength = prefixLen
+// }
+// }
+// if longestMatch == (netip.Addr{}) {
+// return netip.Addr{}, errors.New("No match found in routing table")
+// }
+// return longestMatch, nil
+// }
+// A possible implementation of LongestPrefixMatch, need RIP Protocol to test? \ No newline at end of file
diff --git a/vhost b/vhost
new file mode 100755
index 0000000..95cf628
--- /dev/null
+++ b/vhost
Binary files differ
diff --git a/vrouter b/vrouter
new file mode 100755
index 0000000..0b2be65
--- /dev/null
+++ b/vrouter
Binary files differ