The task of forwarding was pretty simple. Just recreate the 4th lab using the provided routing tables and ARP table.
Key steps:
Parse packetChecksumTTLPerform table lookupModify original packetDecrement TTLUpdate checksumChange Ethernet header for the next hop
Forward the packet to the next hop
There was a crucial mistake I made that caused me to lose half a day debugging though.
The LPM algorithm.Simple enough to implement, but I forgot to also check the masks' lengths when two prefixes are equal, causing all packets that have to go from
r1tor0to be lost.
This one was easy to implement, just read the provided docs and make sure to fill the packet with the correct options.
My implementation has this flow:
-
Try to find the hardware address of the next hopIf found, good. Send the packet
-
Address not foundStore the packet as pending inside a queueCreate an ARP request for the required IP address
-
ARP reply receivedSave the reply inside the ARP tableProcess any pending packets from the queue with the provided address
-
ARP request receivedModify original packetSet my own address as the sourceReverse Ethernet header
Send back reply
One thing I did which I consider a dirty hack (but the
router_arp_requestwouldn't pass without) is to also add the incoming packet's IP and hardware address to my ARP table.I know that the source address might not be from the sending machine (e.g.
r0->r1) but the lookup happens only for addresses directly connected to the router. So any addresses not belonging to a directly connected host just sit there.
One problem encountered here was that I wasn't updating an entry if it already was there. I was just adding another element to my table, which caused some not so pretty debugging sessions.
This one was the easiest:
Create buffer for the packetCopy most of the original packet's headers and the first 8 bytes if it's a bad responseSet the type and code accordinglyCalculate checksum for the entire packetSend it back to the source address
The only problem here was actually calculating the checksum. I didn't know that it included the whole packet, not just the header like IP
Here I'll be straight forward: I took inspiration from the web (mainly ChatGPT), but I also tried to understand how the trie works:
The mask becomes the height of the prefix branch in the current entryInserting a prefix just means taking every bit of the prefix and going left or right in the tree based on itFinding the longest prefix match means going bit by bit in the given IP addressWhen a route is found, save it and continueIf a leaf node is hit, the last match is the longest
Because the maximum height of the tree is the number of bits in a mask or IP address, the maximum number of steps to take is the number of bits of the longest prefix. Because of this, the time complexity of the search goes from
O(N)down toO(32)which is constant.
Throughout this homework you will see that I've used numerous
LOGstatements. They came in handy for debugging, because of my setup. Most of the errors were caught while going through these logs inside the output files.
To enable them just uncomment the define from
utils.h
NOTE:I know that there are memory leaks, mostly coming fromip_to_strandmac_strwhich callstrdup, but freeing those when logging, would've made the code pretty ugly. They are only called if logging is enabled though.Also, the trie is never freed, because that would need the while loop to end.
Please note that these are just things I found annoying while solving this assignment and can be skipped
Some comments in the checker scripts would be greatly appreciated. I often found myself looking inside
tests.pyfor clues as to why a certain test failed, only to stare at the screen for a good minute.
For example:
# tests.py:302 if (hs in {0, 1} and hr in {2, 3}) or (hs in {2, 3} and hs in {0, 1}): nr_pkts += 2What's this supposed to mean ?? I spent around 2 hours trying to understand why I was getting excess packets on my tests.
Another thing I found annoying was using the mininet. I understand that the homework was made to work with the provided VM, but my laptop needs to run my IDE, the checker and at least a browser with only 5GB of available RAM (which CLion kindly takes about 3.5GB from)
My problem is that the checker expects an X11 backend, which my machine has, but my main compositor only uses Wayland with an X11 emulator. So when I run
topo.py, the script tries to launchxtermbut it's not compatible with Wayland. In the labs I got around this by launchingtermitemanually from the mininet console, but here that didn't appear to work.This was solved by switching to an older compositor I still had installed. (I use arch btw)
While on the topic of
mininet, I hope that in the next years this method of manually testing will get less tedious. Due to my bigger desktop monitor, I chose to work on this homework through SSH because my machine runs Windows and a VM would put a lot of strain on it. Because of this I had to go back and forth to my laptop to do the mininet tests, because I couldn't multiplex my terminal.
On a positive note, this assigment was pretty helpful in better understanding the inner workings of the devices we use daily and which we take for granted. If I had to grade this assignment, I would give it a solid
8/10.The deduction comes from the aforementioned points and from the vague error messages given by the checker when something went terribly wrong.