Compare commits

...

6 Commits

Author SHA1 Message Date
Tristan B. Velloza Kildaire 0d8d2ec242 Route
- Finished all documentation
2024-01-21 15:28:59 +02:00
Tristan B. Velloza Kildaire 311f4d388f Route
- Documented
2024-01-21 14:15:02 +02:00
Tristan B. Velloza Kildaire ffef54d98f Route
- Removed `const`
2024-01-21 14:09:53 +02:00
Tristan B. Velloza Kildaire 7c38b56384 Route
- Documented
2024-01-21 14:09:37 +02:00
Tristan B. Velloza Kildaire 3acc85093b Docs
- Removed TODO
2024-01-21 12:16:56 +02:00
Tristan B. Velloza Kildaire 5501d5f23b Docs
- Added more information about arp
2024-01-21 12:14:57 +02:00
3 changed files with 217 additions and 6 deletions

View File

@ -244,6 +244,115 @@ to return _some_ `ArpEntry` because that is the signature of our method,
one generated by `ArpEntry.empty()`, else we return the actual entry that
we received.
#### Catching responses
I have mentioned that the thread which waits for a matching ARP response
to come in (the one which calls the `wait(Duration)`) above. So then,
the question is - which thread is the one calling `notify()` on the
condition variable and under which scenarios?
---
Recall that we attached the `ArpManager` as a `Receiver` to the `Link`
object which was passed into the `regen(Target)` method:
```{.d}
// use this link
Link link = target.getLink();
// address we want to resolve
string addr = target.getAddr();
// attach as a receiver to this link
link.attachReceiver(this);
logger.dbg("attach done");
```
---
Now the reason for this is that whenever traffic is received on a `Link`
it will copy the `byte[]` containing the payload to each attached `Receiver`.
This means that the `ArpManager` will receive all packets from a given
link, the question is - which ones to we react to? Well that's easy. Below
I show you the `onReceive(Link src, byte[] data, string srcAddr)` method
which the arp manager overrides. This is called every time a given link
receives data:
```{.numberLines .d}
/**
* Called by the `Link` which received a packet which
* may be of interest to us
*
* Params:
* src = the `Link` from where the packet came from
* data = the packet's data
* srcAddr = the link-layer source address
*/
public override void onReceive(Link src, byte[] data, string srcAddr)
{
Message recvMesg;
if(Message.decode(data, recvMesg))
{
// payload type
if(recvMesg.getType() == MType.ARP)
{
Arp arpMesg;
if(recvMesg.decodeAs(arpMesg))
{
logger.dbg("arpMesg, received: ", arpMesg, "from: ", srcAddr);
ArpReply reply;
if(arpMesg.getReply(reply))
{
logger.info("ArpReply: ", reply);
// place and wakeup waiters
placeLLAddr(reply.networkAddr(), reply.llAddr());
}
...
...
...
...
}
```
What we do here is we attempt to decode each incoming packet
into our `Message` type, then further check if it is an ARP-typed
message. If this is the case then we check if it is an ARP request
(because as we have seen, ARP requests are **not** handled here).
```{.numberLines .d}
/**
* Called by the thread which has an ARP response
* it would like to pass off to the thread waiting
* on the condition variable
*
* Params:
* l3Addr = the network layer address
* llAddr = the link-layer address
*/
private void placeLLAddr(string l3Addr, string llAddr)
{
this.waitLock.lock();
scope(exit)
{
this.waitLock.unlock();
}
this.waitSig.notify(); // todo, more than one or never?
this.addrIncome[l3Addr] = llAddr;
}
```
If this is the case then we will place the link-layer address into
a key-value map where the key is the network-layer address and the
value is the link-layer address. After this we wake up the sleeping
thread by calling `notify()`.
### Caching
I mentioned that there is caching involved. The involvement is that all

Binary file not shown.

View File

@ -4,6 +4,9 @@ import twine.links.link;
import std.datetime.stopwatch : StopWatch, AutoStart;
import std.datetime : Duration, dur;
/**
* Represents a route
*/
public struct Route
{
private string dstKey; // destination
@ -14,13 +17,38 @@ public struct Route
private StopWatch lifetime;
private Duration expirationTime;
// direct route (reachable over the given link)
/**
* Constructs a route to a destination
* over a given link with a given metric.
*
* The destination of this route is
* directly reachable over the link.
*
* Params:
* dst = the destination network-layer
* address
* link = the `Link`
* distance = the distance
*/
this(string dst, Link link, ubyte distance)
{
this(dst, link, dst, distance);
}
// indirect route (reachable via the `via`)
/**
* Constructs a route to a destination
* over a link with a given metric.
*
* This also let's you set the next-hop
* gateway that should be used.
*
* Params:
* dst = the destination network-layer
* address
* link = the `Link`
* via = the next-hop gateway's address
* distance = the distance
*/
this(string dst, Link link, string via, ubyte distance, Duration expirationTime = dur!("seconds")(60))
{
this.dstKey = dst;
@ -32,50 +60,115 @@ public struct Route
this.expirationTime = expirationTime;
}
/**
* Is this route direct? As
* in the destination is
* directly reachable via
* the gateway (i.e. the
* destination matches the
* gateway)
*
* Returns: `true` if so,
* otherwise `false`
*/
public bool isDirect()
{
return this.dstKey == this.viaKey; // todo, should we ever use cmp?
}
/**
* Checks if this route
* has expired
*
* Returns: `true` if so,
* `false` otherwise
*/
public bool hasExpired()
{
return this.lifetime.peek() > this.expirationTime;
}
/**
* Resets the expiration
* timer for this route
*/
public void refresh()
{
this.lifetime.reset();
}
/**
* Retrieves this route's
* destination address
*
* Returns: the address
*/
public string destination()
{
return this.dstKey;
}
/**
* Retrieves this route's
* associated link
*
* Returns: a `Link`, or
* `null` if this is a
* self-route
*/
public Link link()
{
return this.ll;
}
/**
* Retirns whether or not
* this route is a self-route
* (i.e. the link set was
* `null`)
*
* Returns: `true` if so,
* otherwise `false`
*/
public bool isSelfRoute()
{
return this.ll is null;
}
/**
* Retrieves the gateway
* of this route
*
* Returns: the gateway's
* address
*/
public string gateway()
{
return this.viaKey;
}
/**
* Retrieves the distance
*
* Returns: the distance
* metric
*/
public ubyte distance()
{
return this.dst;
}
// two routes are considered the same if they
// are to the same destination using the same
// gateway, distance and link
public static isSameRoute(Route r1, Route r2)
/**
* Compares two routes with one
* another
*
* Params:
* r1 = first route
* r2 = second route
* Returns: `true` if the routes
* match exactly, otherwise `false`
*/
public static bool isSameRoute(Route r1, Route r2)
{
return r1.destination() == r2.destination() &&
@ -84,6 +177,15 @@ public struct Route
r1.link() == r2.link();
}
/**
* Compares this `Route` with
* another
*
* Params:
* rhs = the other route
* Returns: `true` if the routes
* are identical, `false` otherwise
*/
public bool opEquals(Route rhs)
{
return isSameRoute(this, rhs);