CS144 Lab checkpoint 6 starter code
This commit is contained in:
parent
b0006b42f7
commit
cde939183b
@ -8,3 +8,4 @@ add_sponge_exec (tcp_ipv4 stream_copy)
|
|||||||
add_sponge_exec (tcp_ip_ethernet stream_copy)
|
add_sponge_exec (tcp_ip_ethernet stream_copy)
|
||||||
add_sponge_exec (webget)
|
add_sponge_exec (webget)
|
||||||
add_sponge_exec (tcp_benchmark)
|
add_sponge_exec (tcp_benchmark)
|
||||||
|
add_sponge_exec (network_simulator)
|
||||||
|
|||||||
356
apps/network_simulator.cc
Normal file
356
apps/network_simulator.cc
Normal file
@ -0,0 +1,356 @@
|
|||||||
|
#include "arp_message.hh"
|
||||||
|
#include "router.hh"
|
||||||
|
#include "util.hh"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <list>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
auto rd = get_random_generator();
|
||||||
|
|
||||||
|
EthernetAddress random_host_ethernet_address() {
|
||||||
|
EthernetAddress addr;
|
||||||
|
for (auto &byte : addr) {
|
||||||
|
byte = rd(); // use a random local Ethernet address
|
||||||
|
}
|
||||||
|
addr.at(0) |= 0x02; // "10" in last two binary digits marks a private Ethernet address
|
||||||
|
addr.at(0) &= 0xfe;
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
EthernetAddress random_router_ethernet_address() {
|
||||||
|
EthernetAddress addr;
|
||||||
|
for (auto &byte : addr) {
|
||||||
|
byte = rd(); // use a random local Ethernet address
|
||||||
|
}
|
||||||
|
addr.at(0) = 0x02; // "10" in last two binary digits marks a private Ethernet address
|
||||||
|
addr.at(1) = 0;
|
||||||
|
addr.at(2) = 0;
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ip(const string &str) { return Address{str}.ipv4_numeric(); }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void clear(T &queue1, T &queue2) {
|
||||||
|
while (not queue1.empty()) {
|
||||||
|
queue1.pop();
|
||||||
|
queue2.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string summary(const EthernetFrame &frame) {
|
||||||
|
string ret;
|
||||||
|
ret += frame.header().to_string();
|
||||||
|
switch (frame.header().type) {
|
||||||
|
case EthernetHeader::TYPE_IPv4: {
|
||||||
|
InternetDatagram dgram;
|
||||||
|
if (dgram.parse(frame.payload()) == ParseResult::NoError) {
|
||||||
|
ret += " " + dgram.header().summary();
|
||||||
|
ret += " payload=\"" + string(dgram.payload().concatenate()) + "\"";
|
||||||
|
} else {
|
||||||
|
ret += " (bad IPv4)";
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case EthernetHeader::TYPE_ARP: {
|
||||||
|
ARPMessage arp;
|
||||||
|
if (arp.parse(frame.payload()) == ParseResult::NoError) {
|
||||||
|
ret += " " + arp.to_string();
|
||||||
|
} else {
|
||||||
|
ret += " (bad ARP)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Host {
|
||||||
|
string _name;
|
||||||
|
Address _my_address;
|
||||||
|
AsyncNetworkInterface _interface;
|
||||||
|
Address _next_hop;
|
||||||
|
|
||||||
|
std::list<InternetDatagram> _expecting_to_receive{};
|
||||||
|
|
||||||
|
bool expecting(const InternetDatagram &expected) const {
|
||||||
|
for (const auto &x : _expecting_to_receive) {
|
||||||
|
if (x.serialize().concatenate() == expected.serialize().concatenate()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove_expectation(const InternetDatagram &expected) {
|
||||||
|
for (auto it = _expecting_to_receive.begin(); it != _expecting_to_receive.end(); ++it) {
|
||||||
|
if (it->serialize().concatenate() == expected.serialize().concatenate()) {
|
||||||
|
_expecting_to_receive.erase(it);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Host(const string &name, const Address &my_address, const Address &next_hop)
|
||||||
|
: _name(name)
|
||||||
|
, _my_address(my_address)
|
||||||
|
, _interface(random_host_ethernet_address(), _my_address)
|
||||||
|
, _next_hop(next_hop) {}
|
||||||
|
|
||||||
|
InternetDatagram send_to(const Address &destination, const uint8_t ttl = 64) {
|
||||||
|
InternetDatagram dgram;
|
||||||
|
dgram.header().src = _my_address.ipv4_numeric();
|
||||||
|
dgram.header().dst = destination.ipv4_numeric();
|
||||||
|
dgram.payload() = "random payload: {" + to_string(rd()) + "}";
|
||||||
|
dgram.header().len = dgram.header().hlen * 4 + dgram.payload().size();
|
||||||
|
dgram.header().ttl = ttl;
|
||||||
|
|
||||||
|
_interface.send_datagram(dgram, _next_hop);
|
||||||
|
|
||||||
|
cerr << "Host " << _name << " trying to send datagram (with next hop = " << _next_hop.ip()
|
||||||
|
<< "): " << dgram.header().summary() << " payload=\"" << dgram.payload().concatenate() << "\"\n";
|
||||||
|
|
||||||
|
return dgram;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Address &address() { return _my_address; }
|
||||||
|
|
||||||
|
AsyncNetworkInterface &interface() { return _interface; }
|
||||||
|
|
||||||
|
void expect(const InternetDatagram &expected) { _expecting_to_receive.push_back(expected); }
|
||||||
|
|
||||||
|
const string &name() { return _name; }
|
||||||
|
|
||||||
|
void check() {
|
||||||
|
while (not _interface.datagrams_out().empty()) {
|
||||||
|
const auto &dgram_received = _interface.datagrams_out().front();
|
||||||
|
if (not expecting(dgram_received)) {
|
||||||
|
throw runtime_error("Host " + _name +
|
||||||
|
" received unexpected Internet datagram: " + dgram_received.header().summary() +
|
||||||
|
" payload=\"" + dgram_received.payload().concatenate() + "\"");
|
||||||
|
}
|
||||||
|
remove_expectation(dgram_received);
|
||||||
|
_interface.datagrams_out().pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not _expecting_to_receive.empty()) {
|
||||||
|
auto &expected = _expecting_to_receive.front();
|
||||||
|
throw runtime_error("Host " + _name + " did NOT receive an expected Internet datagram: " +
|
||||||
|
expected.header().summary() + " payload=\"" + expected.payload().concatenate() + "\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Network {
|
||||||
|
private:
|
||||||
|
Router _router{};
|
||||||
|
|
||||||
|
size_t default_id, eth0_id, eth1_id, eth2_id, uun3_id, hs4_id, mit5_id;
|
||||||
|
|
||||||
|
std::unordered_map<string, Host> _hosts{};
|
||||||
|
|
||||||
|
void exchange_frames(const string &x_name,
|
||||||
|
AsyncNetworkInterface &x,
|
||||||
|
const string &y_name,
|
||||||
|
AsyncNetworkInterface &y) {
|
||||||
|
auto x_frames = x.frames_out(), y_frames = y.frames_out();
|
||||||
|
|
||||||
|
deliver(x_name, x_frames, y_name, y);
|
||||||
|
deliver(y_name, y_frames, x_name, x);
|
||||||
|
|
||||||
|
clear(x_frames, x.frames_out());
|
||||||
|
clear(y_frames, y.frames_out());
|
||||||
|
}
|
||||||
|
|
||||||
|
void exchange_frames(const string &x_name,
|
||||||
|
AsyncNetworkInterface &x,
|
||||||
|
const string &y_name,
|
||||||
|
AsyncNetworkInterface &y,
|
||||||
|
const string &z_name,
|
||||||
|
AsyncNetworkInterface &z) {
|
||||||
|
auto x_frames = x.frames_out(), y_frames = y.frames_out(), z_frames = z.frames_out();
|
||||||
|
|
||||||
|
deliver(x_name, x_frames, y_name, y);
|
||||||
|
deliver(x_name, x_frames, z_name, z);
|
||||||
|
|
||||||
|
deliver(y_name, y_frames, x_name, x);
|
||||||
|
deliver(y_name, y_frames, z_name, z);
|
||||||
|
|
||||||
|
deliver(z_name, z_frames, x_name, x);
|
||||||
|
deliver(z_name, z_frames, y_name, y);
|
||||||
|
|
||||||
|
clear(x_frames, x.frames_out());
|
||||||
|
clear(y_frames, y.frames_out());
|
||||||
|
clear(z_frames, z.frames_out());
|
||||||
|
}
|
||||||
|
|
||||||
|
void deliver(const string &src_name,
|
||||||
|
const queue<EthernetFrame> &src,
|
||||||
|
const string &dst_name,
|
||||||
|
AsyncNetworkInterface &dst) {
|
||||||
|
queue<EthernetFrame> to_send = src;
|
||||||
|
while (not to_send.empty()) {
|
||||||
|
to_send.front().payload() = to_send.front().payload().concatenate();
|
||||||
|
cerr << "Transferring frame from " << src_name << " to " << dst_name << ": " << summary(to_send.front())
|
||||||
|
<< "\n";
|
||||||
|
dst.recv_frame(move(to_send.front()));
|
||||||
|
to_send.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Network()
|
||||||
|
: default_id(_router.add_interface({random_router_ethernet_address(), {"171.67.76.46"}}))
|
||||||
|
, eth0_id(_router.add_interface({random_router_ethernet_address(), {"10.0.0.1"}}))
|
||||||
|
, eth1_id(_router.add_interface({random_router_ethernet_address(), {"172.16.0.1"}}))
|
||||||
|
, eth2_id(_router.add_interface({random_router_ethernet_address(), {"192.168.0.1"}}))
|
||||||
|
, uun3_id(_router.add_interface({random_router_ethernet_address(), {"198.178.229.1"}}))
|
||||||
|
, hs4_id(_router.add_interface({random_router_ethernet_address(), {"143.195.0.2"}}))
|
||||||
|
, mit5_id(_router.add_interface({random_router_ethernet_address(), {"128.30.76.255"}})) {
|
||||||
|
_hosts.insert({"applesauce", {"applesauce", {"10.0.0.2"}, {"10.0.0.1"}}});
|
||||||
|
_hosts.insert({"default_router", {"default_router", {"171.67.76.1"}, {"0"}}});
|
||||||
|
;
|
||||||
|
_hosts.insert({"cherrypie", {"cherrypie", {"192.168.0.2"}, {"192.168.0.1"}}});
|
||||||
|
_hosts.insert({"hs_router", {"hs_router", {"143.195.0.1"}, {"0"}}});
|
||||||
|
_hosts.insert({"dm42", {"dm42", {"198.178.229.42"}, {"198.178.229.1"}}});
|
||||||
|
_hosts.insert({"dm43", {"dm43", {"198.178.229.43"}, {"198.178.229.1"}}});
|
||||||
|
|
||||||
|
_router.add_route(ip("0.0.0.0"), 0, host("default_router").address(), default_id);
|
||||||
|
_router.add_route(ip("10.0.0.0"), 8, {}, eth0_id);
|
||||||
|
_router.add_route(ip("172.16.0.0"), 16, {}, eth1_id);
|
||||||
|
_router.add_route(ip("192.168.0.0"), 24, {}, eth2_id);
|
||||||
|
_router.add_route(ip("198.178.229.0"), 24, {}, uun3_id);
|
||||||
|
_router.add_route(ip("143.195.0.0"), 17, host("hs_router").address(), hs4_id);
|
||||||
|
_router.add_route(ip("143.195.128.0"), 18, host("hs_router").address(), hs4_id);
|
||||||
|
_router.add_route(ip("143.195.192.0"), 19, host("hs_router").address(), hs4_id);
|
||||||
|
_router.add_route(ip("128.30.76.255"), 16, Address{"128.30.0.1"}, mit5_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void simulate_physical_connections() {
|
||||||
|
exchange_frames(
|
||||||
|
"router.default", _router.interface(default_id), "default_router", host("default_router").interface());
|
||||||
|
exchange_frames("router.eth0", _router.interface(eth0_id), "applesauce", host("applesauce").interface());
|
||||||
|
exchange_frames("router.eth2", _router.interface(eth2_id), "cherrypie", host("cherrypie").interface());
|
||||||
|
exchange_frames("router.hs4", _router.interface(hs4_id), "hs_router", host("hs_router").interface());
|
||||||
|
exchange_frames("router.uun3",
|
||||||
|
_router.interface(uun3_id),
|
||||||
|
"dm42",
|
||||||
|
host("dm42").interface(),
|
||||||
|
"dm43",
|
||||||
|
host("dm43").interface());
|
||||||
|
}
|
||||||
|
|
||||||
|
void simulate() {
|
||||||
|
for (unsigned int i = 0; i < 256; i++) {
|
||||||
|
_router.route();
|
||||||
|
simulate_physical_connections();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &host : _hosts) {
|
||||||
|
host.second.check();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Host &host(const string &name) {
|
||||||
|
auto it = _hosts.find(name);
|
||||||
|
if (it == _hosts.end()) {
|
||||||
|
throw runtime_error("unknown host: " + name);
|
||||||
|
}
|
||||||
|
if (it->second.name() != name) {
|
||||||
|
throw runtime_error("invalid host: " + name);
|
||||||
|
}
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void network_simulator() {
|
||||||
|
const string green = "\033[32;1m", normal = "\033[m";
|
||||||
|
|
||||||
|
cerr << green << "Constructing network." << normal << "\n";
|
||||||
|
|
||||||
|
Network network;
|
||||||
|
|
||||||
|
cout << green << "\n\nTesting traffic between two ordinary hosts (applesauce to cherrypie)..." << normal << "\n\n";
|
||||||
|
{
|
||||||
|
auto dgram_sent = network.host("applesauce").send_to(network.host("cherrypie").address());
|
||||||
|
dgram_sent.header().ttl--;
|
||||||
|
network.host("cherrypie").expect(dgram_sent);
|
||||||
|
network.simulate();
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << green << "\n\nTesting traffic between two ordinary hosts (cherrypie to applesauce)..." << normal << "\n\n";
|
||||||
|
{
|
||||||
|
auto dgram_sent = network.host("cherrypie").send_to(network.host("applesauce").address());
|
||||||
|
dgram_sent.header().ttl--;
|
||||||
|
network.host("applesauce").expect(dgram_sent);
|
||||||
|
network.simulate();
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << green << "\n\nSuccess! Testing applesauce sending to the Internet." << normal << "\n\n";
|
||||||
|
{
|
||||||
|
auto dgram_sent = network.host("applesauce").send_to({"1.2.3.4"});
|
||||||
|
dgram_sent.header().ttl--;
|
||||||
|
network.host("default_router").expect(dgram_sent);
|
||||||
|
network.simulate();
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << green << "\n\nSuccess! Testing sending to the HS network and Internet." << normal << "\n\n";
|
||||||
|
{
|
||||||
|
auto dgram_sent = network.host("applesauce").send_to({"143.195.131.17"});
|
||||||
|
dgram_sent.header().ttl--;
|
||||||
|
network.host("hs_router").expect(dgram_sent);
|
||||||
|
network.simulate();
|
||||||
|
|
||||||
|
dgram_sent = network.host("cherrypie").send_to({"143.195.193.52"});
|
||||||
|
dgram_sent.header().ttl--;
|
||||||
|
network.host("hs_router").expect(dgram_sent);
|
||||||
|
network.simulate();
|
||||||
|
|
||||||
|
dgram_sent = network.host("cherrypie").send_to({"143.195.223.255"});
|
||||||
|
dgram_sent.header().ttl--;
|
||||||
|
network.host("hs_router").expect(dgram_sent);
|
||||||
|
network.simulate();
|
||||||
|
|
||||||
|
dgram_sent = network.host("cherrypie").send_to({"143.195.224.0"});
|
||||||
|
dgram_sent.header().ttl--;
|
||||||
|
network.host("default_router").expect(dgram_sent);
|
||||||
|
network.simulate();
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << green << "\n\nSuccess! Testing two hosts on the same network (dm42 to dm43)..." << normal << "\n\n";
|
||||||
|
{
|
||||||
|
auto dgram_sent = network.host("dm42").send_to(network.host("dm43").address());
|
||||||
|
dgram_sent.header().ttl--;
|
||||||
|
network.host("dm43").expect(dgram_sent);
|
||||||
|
network.simulate();
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << green << "\n\nSuccess! Testing TTL expiration..." << normal << "\n\n";
|
||||||
|
{
|
||||||
|
auto dgram_sent = network.host("applesauce").send_to({"1.2.3.4"}, 1);
|
||||||
|
network.simulate();
|
||||||
|
|
||||||
|
dgram_sent = network.host("applesauce").send_to({"1.2.3.4"}, 0);
|
||||||
|
network.simulate();
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << "\n\n\033[32;1mCongratulations! All datagrams were routed successfully.\033[m\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
try {
|
||||||
|
network_simulator();
|
||||||
|
} catch (const exception &e) {
|
||||||
|
cerr << "\n\n\n";
|
||||||
|
cerr << "\033[31;1mError: " << e.what() << "\033[m\n";
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
51
libsponge/router.cc
Normal file
51
libsponge/router.cc
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#include "router.hh"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
// Dummy implementation of an IP router
|
||||||
|
|
||||||
|
// Given an incoming Internet datagram, the router decides
|
||||||
|
// (1) which interface to send it out on, and
|
||||||
|
// (2) what next hop address to send it to.
|
||||||
|
|
||||||
|
// For Lab 6, please replace with a real implementation that passes the
|
||||||
|
// automated checks run by `make check_lab6`.
|
||||||
|
|
||||||
|
// You will need to add private members to the class declaration in `router.hh`
|
||||||
|
|
||||||
|
template <typename... Targs>
|
||||||
|
void DUMMY_CODE(Targs &&... /* unused */) {}
|
||||||
|
|
||||||
|
//! \param[in] route_prefix The "up-to-32-bit" IPv4 address prefix to match the datagram's destination address against
|
||||||
|
//! \param[in] prefix_length For this route to be applicable, how many high-order (most-significant) bits of the route_prefix will need to match the corresponding bits of the datagram's destination address?
|
||||||
|
//! \param[in] next_hop The IP address of the next hop. Will be empty if the network is directly attached to the router (in which case, the next hop address should be the datagram's final destination).
|
||||||
|
//! \param[in] interface_num The index of the interface to send the datagram out on.
|
||||||
|
void Router::add_route(const uint32_t route_prefix,
|
||||||
|
const uint8_t prefix_length,
|
||||||
|
const optional<Address> next_hop,
|
||||||
|
const size_t interface_num) {
|
||||||
|
cerr << "DEBUG: adding route " << Address::from_ipv4_numeric(route_prefix).ip() << "/" << int(prefix_length)
|
||||||
|
<< " => " << (next_hop.has_value() ? next_hop->ip() : "(direct)") << " on interface " << interface_num << "\n";
|
||||||
|
|
||||||
|
DUMMY_CODE(route_prefix, prefix_length, next_hop, interface_num);
|
||||||
|
// Your code here.
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \param[in] dgram The datagram to be routed
|
||||||
|
void Router::route_one_datagram(InternetDatagram &dgram) {
|
||||||
|
DUMMY_CODE(dgram);
|
||||||
|
// Your code here.
|
||||||
|
}
|
||||||
|
|
||||||
|
void Router::route() {
|
||||||
|
// Go through all the interfaces, and route every incoming datagram to its proper outgoing interface.
|
||||||
|
for (auto &interface : _interfaces) {
|
||||||
|
auto &queue = interface.datagrams_out();
|
||||||
|
while (not queue.empty()) {
|
||||||
|
route_one_datagram(queue.front());
|
||||||
|
queue.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
74
libsponge/router.hh
Normal file
74
libsponge/router.hh
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#ifndef SPONGE_LIBSPONGE_ROUTER_HH
|
||||||
|
#define SPONGE_LIBSPONGE_ROUTER_HH
|
||||||
|
|
||||||
|
#include "network_interface.hh"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
//! \brief A wrapper for NetworkInterface that makes the host-side
|
||||||
|
//! interface asynchronous: instead of returning received datagrams
|
||||||
|
//! immediately (from the `recv_frame` method), it stores them for
|
||||||
|
//! later retrieval. Otherwise, behaves identically to the underlying
|
||||||
|
//! implementation of NetworkInterface.
|
||||||
|
class AsyncNetworkInterface : public NetworkInterface {
|
||||||
|
std::queue<InternetDatagram> _datagrams_out{};
|
||||||
|
|
||||||
|
public:
|
||||||
|
using NetworkInterface::NetworkInterface;
|
||||||
|
|
||||||
|
//! Construct from a NetworkInterface
|
||||||
|
AsyncNetworkInterface(NetworkInterface &&interface) : NetworkInterface(interface) {}
|
||||||
|
|
||||||
|
//! \brief Receives and Ethernet frame and responds appropriately.
|
||||||
|
|
||||||
|
//! - If type is IPv4, pushes to the `datagrams_out` queue for later retrieval by the owner.
|
||||||
|
//! - If type is ARP request, learn a mapping from the "sender" fields, and send an ARP reply.
|
||||||
|
//! - If type is ARP reply, learn a mapping from the "target" fields.
|
||||||
|
//!
|
||||||
|
//! \param[in] frame the incoming Ethernet frame
|
||||||
|
void recv_frame(const EthernetFrame &frame) {
|
||||||
|
auto optional_dgram = NetworkInterface::recv_frame(frame);
|
||||||
|
if (optional_dgram.has_value()) {
|
||||||
|
_datagrams_out.push(std::move(optional_dgram.value()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Access queue of Internet datagrams that have been received
|
||||||
|
std::queue<InternetDatagram> &datagrams_out() { return _datagrams_out; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//! \brief A router that has multiple network interfaces and
|
||||||
|
//! performs longest-prefix-match routing between them.
|
||||||
|
class Router {
|
||||||
|
//! The router's collection of network interfaces
|
||||||
|
std::vector<AsyncNetworkInterface> _interfaces{};
|
||||||
|
|
||||||
|
//! Send a single datagram from the appropriate outbound interface to the next hop,
|
||||||
|
//! as specified by the route with the longest prefix_length that matches the
|
||||||
|
//! datagram's destination address.
|
||||||
|
void route_one_datagram(InternetDatagram &dgram);
|
||||||
|
|
||||||
|
public:
|
||||||
|
//! Add an interface to the router
|
||||||
|
//! \param[in] interface an already-constructed network interface
|
||||||
|
//! \returns The index of the interface after it has been added to the router
|
||||||
|
size_t add_interface(AsyncNetworkInterface &&interface) {
|
||||||
|
_interfaces.push_back(std::move(interface));
|
||||||
|
return _interfaces.size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Access an interface by index
|
||||||
|
AsyncNetworkInterface &interface(const size_t N) { return _interfaces.at(N); }
|
||||||
|
|
||||||
|
//! Add a route (a forwarding rule)
|
||||||
|
void add_route(const uint32_t route_prefix,
|
||||||
|
const uint8_t prefix_length,
|
||||||
|
const std::optional<Address> next_hop,
|
||||||
|
const size_t interface_num);
|
||||||
|
|
||||||
|
//! Route packets between the interfaces
|
||||||
|
void route();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SPONGE_LIBSPONGE_ROUTER_HH
|
||||||
29
writeups/lab6.md
Normal file
29
writeups/lab6.md
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
Lab 6 Writeup
|
||||||
|
=============
|
||||||
|
|
||||||
|
My name: [your name here]
|
||||||
|
|
||||||
|
My SUNet ID: [your sunetid here]
|
||||||
|
|
||||||
|
I collaborated with: [list sunetids here]
|
||||||
|
|
||||||
|
I would like to thank/reward these classmates for their help: [list sunetids here]
|
||||||
|
|
||||||
|
This lab took me about [n] hours to do. I [did/did not] attend the lab session.
|
||||||
|
|
||||||
|
Program Structure and Design of the Router:
|
||||||
|
[]
|
||||||
|
|
||||||
|
Implementation Challenges:
|
||||||
|
[]
|
||||||
|
|
||||||
|
Remaining Bugs:
|
||||||
|
[]
|
||||||
|
|
||||||
|
- Optional: I had unexpected difficulty with: [describe]
|
||||||
|
|
||||||
|
- Optional: I think you could make this lab better by: [describe]
|
||||||
|
|
||||||
|
- Optional: I was surprised by: [describe]
|
||||||
|
|
||||||
|
- Optional: I'm not sure about: [describe]
|
||||||
Loading…
Reference in New Issue
Block a user