81 lines
3.1 KiB
C++
81 lines
3.1 KiB
C++
#ifndef SPONGE_LIBSPONGE_ROUTER_HH
|
|
#define SPONGE_LIBSPONGE_ROUTER_HH
|
|
|
|
#include "address.hh"
|
|
#include "network_interface.hh"
|
|
|
|
#include <cstdint>
|
|
#include <optional>
|
|
#include <queue>
|
|
#include <tuple>
|
|
|
|
//! \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{};
|
|
|
|
//! Internal routing table. Tuple(prefix, prefix_length, next_hop, interface, mask)
|
|
std::vector<std::tuple<uint32_t, uint8_t,std::optional<Address>, size_t, uint32_t>> _route_table {};
|
|
|
|
//! 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
|