CS144Lab/libsponge/router.cc
2023-02-18 14:51:28 +00:00

75 lines
3.1 KiB
C++

#include "router.hh"
#include <iostream>
#include <tuple>
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";
uint32_t mask = 0;
if (prefix_length > 0) mask = (1 << 31) >> (prefix_length - 1);
_route_table.push_back(std::make_tuple(route_prefix, prefix_length, next_hop, interface_num, mask));
}
//! \param[in] dgram The datagram to be routed
void Router::route_one_datagram(InternetDatagram &dgram) {
auto dst_ip = dgram.header().dst;
auto best_match = _route_table.end();
int longest_prefix = 0;
for (auto rule = _route_table.begin(); rule != _route_table.end(); ++ rule) {
auto route_prefix = std::get<0>(*rule);
auto prefix_length = std::get<1>(*rule);
auto mask = std::get<4>(*rule);
if ((mask & route_prefix) == (mask & dst_ip)) {
if (longest_prefix <= prefix_length) {
longest_prefix = prefix_length;
best_match = rule;
}
}
}
if (best_match != _route_table.end()) {
if (dgram.header().ttl <= 1) {
return;
}
else {
dgram.header().ttl --;
}
auto next_hop = std::get<2>(*best_match).value_or(Address::from_ipv4_numeric(dgram.header().dst));
_interfaces[std::get<3>(*best_match)].send_datagram(dgram, next_hop);
}
}
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();
}
}
}