Compare commits

...

2 Commits

Author SHA1 Message Date
Tristan B. Velloza Kildaire 393f975556 DataCallbackFunction
- Added definition

Router

- Documented class
- Removed `ProcMesg` declaration
- Allowed setting of the advertisement frequency
- Added a constructor which accepts a `DataCallbackFunction`
- Added more debug logs in `handle_ARP(Link link, string srcAddr, Message recvMesg)`

Router (unittests)

- Updated to use the new `Router` API
2024-01-18 22:11:17 +02:00
Tristan B. Velloza Kildaire adbbcc478e Docs
- Fixed formatting and typos
2024-01-18 22:05:21 +02:00
3 changed files with 41 additions and 50 deletions

View File

@ -8,14 +8,14 @@ another address, the link-layer address, which we will call $addr_{LL}$.
## Why do we need this?
The reason that we require this $addr_{LL}$ is because when we need
to send data to a hsot we do so over a link which is indicated in the
to send data to a host we do so over a link which is indicated in the
routing table for said packet.
However, links don't speak the same network-layer protocol as twine -
they speak whatever protocol they implement - i.e. Ethernet via `LIInterface`
or the in-memory `PipedLink`. Needless to say there is also always a
requirement of such a mapping mechansim because several links may be
backed by a different link-layer protocols in their `Link` impelemntation
requirement of such a mapping mechanism because several links may be
backed by a different link-layer protocols in their `Link` implementation
and therefore we cannot marry ourselves to only one link-layer protocol
- _we need something dynamic_.
@ -23,10 +23,10 @@ and therefore we cannot marry ourselves to only one link-layer protocol
We now head over to the technical side of things. Before we jump directly
into an analysis of the source code it is worth considering what this
procedure means in a mematheical sense because at a high-level this is
procedure means in a mathematical sense because at a high-level this is
what the code is modeled on.
If we have a router $$r_1$$ which has a set of links $L= \{ l_1, l_2 \}$
If we have a router $r_1$ which has a set of links $L= \{ l_1, l_2 \}$
and we wanted to send a packet to a host addresses $h_1$ and $h_2$ which
are accessible over $l_1$ and $l_2$ respectively then the mapping function
would appear as such:
@ -47,13 +47,13 @@ $$
Therefore we discover that we have the above mapping function which requires
the network-layer $h_i$ address you wish to resolve and the link $l_i$ over
which theresolution must be done, this then mapping to a single scalar -
which the resolution must be done, this then mapping to a single scalar -
the link-layer address, $addr_{LL_i}$.
## Implementation
We will begin the examination of the code at the deepest level which models
this mathematical function earlier, first, afterwhich we will then consider
this mathematical function earlier, first, after which we will then consider
the code which calls it and how that works.
### The entry type
@ -120,7 +120,7 @@ logger.dbg("attach done");
This provides us with a callback method which will be called by the `Link`
whenever it receives _any_ traffic. It is worth noting that such a method
will not run on the thread concerning the code we are looking at now but
rather on the therad of the `Link`'s - we will discuss later how will filter
rather on the thread of the `Link`'s - we will discuss later how will filter
it and deliver the result to us, _but for now - back to the code_.
@ -163,7 +163,7 @@ bool status = waitForLLAddr(addr, llAddr);
```
As you can see we have this call to a method called `waitForLLAddr(addr, llAddr)`.
This method will block for us and can wake up if it is singaled to by
This method will block for us and can wake up if it is signaled to by
the callback method running on the `Link`'s thread (as mentioned previously).
----
@ -200,10 +200,10 @@ return false; // timed out
Because it is implemented using a condition variable, it could potentially
miss a signal from the calling `notify()` if we only call `wait()` on our
thread _after_ the link's thread has called `notify()`. Therefore, we make
our `wait()` wakeup every now and then by using a timed-wait, to check if
our `wait()` wake up every now and then by using a timed-wait, to check if
the data has been filled in by the other thread.
Second of all, what we do after retyurning from `wait(Duration)` is check if
Second of all, what we do after retrying from `wait(Duration)` is check if
the _requested network-layer address_ has been resolved or not - this is that
filtering I was mentioning earlier. This is important as we don't want to
wake up for _any_ ARP response, but only the one which matches our `addr`
@ -259,7 +259,7 @@ instantiation - therefore it works as expected.
We have now discussed the gritty internals which aid us in creating requests,
awaiting replies and then returning the matched entry. We now must move over
to the publically facing API of the `ArpManager`. This really just contains
to the publicly facing API of the `ArpManager`. This really just contains
a single method:
```{.d}

Binary file not shown.

View File

@ -38,6 +38,7 @@ public struct UserDataPkt
import std.functional : toDelegate;
public alias DataCallbackDelegate = void delegate(UserDataPkt);
public alias DataCallbackFunction = void function(UserDataPkt);
private void nopHandler(UserDataPkt u)
{
@ -45,41 +46,21 @@ private void nopHandler(UserDataPkt u)
logger.dbg("NOP handler: ", cast(string)u.getPayload());
}
/**
* The router which is responsible for
* sending routing advertisements,
* receiving routes advertised by others,
* managing the routing table and
* providing a way to send, receive
* packets for the user.
*
* It also manages the forwarding of
* packets
*/
public class Router : Receiver
{
private bool running;
// todo, make use of this in the future with a message processing thread
// offload, from on-link processing
private struct ProcMesg
{
private Link link;
private byte[] data;
private string llSrcAddr;
this(Link from, byte[] recv, string llSrcAddr)
{
this.link = from;
this.data = recv;
this.llSrcAddr = llSrcAddr;
}
public Link getLink()
{
return this.link;
}
public byte[] getData()
{
return this.data;
}
public string getLLSource()
{
return this.llSrcAddr;
}
}
// link management
private const LinkManager linkMan; // const, never should be changed besides during construction
private Thread advThread;
@ -96,13 +77,14 @@ public class Router : Receiver
// incoming message handler
private const DataCallbackDelegate messageHandler;
this(string[] keyPairs, DataCallbackDelegate messageHandler = toDelegate(&nopHandler))
// todo, set advFreq back to 5 seconds
this(string[] keyPairs, DataCallbackDelegate messageHandler = toDelegate(&nopHandler), Duration advFreq = dur!("seconds")(100))
{
this.linkMan = new LinkManager(this);
this.arp = new ArpManager();
this.advThread = new Thread(&advertiseLoop);
this.advFreq = dur!("seconds")(5);
this.advFreq = advFreq;
this.keyPairs = keyPairs;
this.messageHandler = messageHandler;
@ -113,6 +95,12 @@ public class Router : Receiver
installSelfRoute();
}
// todo, set advFreq back to 5 seconds
this(string[] keyPairs, DataCallbackFunction messageHandler, Duration advFreq = dur!("seconds")(100))
{
this(keyPairs, toDelegate(messageHandler), advFreq);
}
public void start()
{
this.running = true;
@ -258,6 +246,8 @@ public class Router : Receiver
Arp arpMesg;
if(recvMesg.decodeAs(arpMesg))
{
logger.dbg("arpMesg: ", arpMesg);
if(arpMesg.isRequest())
{
string requestedL3Addr;
@ -274,6 +264,7 @@ public class Router : Receiver
Message mesgOut;
if(toMessage(arpRep, mesgOut))
{
logger.dbg("Sending out ARP response: ", arpRep);
link.transmit(mesgOut.encode(), srcAddr);
}
else
@ -719,11 +710,11 @@ unittest
p2.connect(p1, p1.getAddress());
Router r1 = new Router(["p1Pub", "p1Priv"]);
Router r1 = new Router(["p1Pub", "p1Priv"], toDelegate(&nopHandler), dur!("seconds")(5));
r1.getLinkMan().addLink(p1);
r1.start();
Router r2 = new Router(["p2Pub", "p2Priv"]);
Router r2 = new Router(["p2Pub", "p2Priv"], toDelegate(&nopHandler), dur!("seconds")(5));
r2.getLinkMan().addLink(p2);
r2.start();
@ -841,16 +832,16 @@ unittest
}
Router r1 = new Router(["p1Pub", "p1Priv"], &r1_msg_handler);
Router r1 = new Router(["p1Pub", "p1Priv"], &r1_msg_handler, dur!("seconds")(5));
r1.getLinkMan().addLink(p1_to_p2);
r1.getLinkMan().addLink(p1_to_p3);
r1.start();
Router r2 = new Router(["p2Pub", "p2Priv"], &r2_msg_handler);
Router r2 = new Router(["p2Pub", "p2Priv"], &r2_msg_handler, dur!("seconds")(5));
r2.getLinkMan().addLink(p2_to_p1);
r2.start();
Router r3 = new Router(["p3Pub", "p3Priv"]);
Router r3 = new Router(["p3Pub", "p3Priv"], toDelegate(&nopHandler), dur!("seconds")(5));
r3.getLinkMan().addLink(p3_to_p1);
r3.start();