CS 144 Lab Six -- building an IP router

CS 144 Lab Six -- building an IP router

  • 引言
  • 路由器的实现
  • 测试


对应课程视频: 【计算机网络】 斯坦福大学CS144课程

Lab Six 对应的PDF: Lab Checkpoint 5: building an IP router


引言

在本实验中,你将在现有的NetworkInterface基础上实现一个IP路由器,从而结束本课程。路由器有几个网络接口,可以在其中任何一个接口上接收互联网数据报。路由器的工作是根据路由表转发它得到的数据报:一个规则列表,它告诉路由器,对于任何给定的数据报:

  • 发送到哪个接口;
  • 下一跳的IP地址 ;

你的工作是实现一个路由器,它可以为任何给定的数据报计算出这两件事。(你不需要实现设置路由表的算法,例如RIP、OSPF、BGP或SDN控制器,只需要实现跟随路由表的算法)。

你对路由器的实现将使用带有新的Router类的Sponge库,以及在模拟网络中检查你的路由器功能的测试。实验6建立在你在实验5中对NetworkInterface的实现之上,但不使用你在实验0-4中实现的TCP栈。IP路由器不需要知道任何关于TCP、ARP或以太网的信息(仅限IP)。我们希望你的实现将需要大约25-30行的代码。

在这里插入图片描述

图1:路由器包含多个网络接口,可以在其中任何一个接口上接收IP数据报。路由器将接收到的任何数据报转发到相应出站接口上的下一跳,路由表告诉路由器如何做出这个决定。


路由器的实现

AsyncNetworkInterface:

  • 它是对 NetworkInterface 类的包装,用于使主机端接口变成异步的。
  • 在原始的 NetworkInterface 类的基础上,AsyncNetworkInterface 将接收到的数据报保存在队列中,而不是立即返回给调用者,以便稍后检索。
  • 同时,AsyncNetworkInterface 在其他方面与底层的 NetworkInterface 实现完全相同。
class AsyncNetworkInterface : public NetworkInterface {std::queue<InternetDatagram> _datagrams_out{};public:using NetworkInterface::NetworkInterface;//! Construct from a NetworkInterfaceAsyncNetworkInterface(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 framevoid recv_frame(const EthernetFrame &frame) {auto optional_dgram = NetworkInterface::recv_frame(frame);// 只会将IPV4数据报放入数据报接收队列中if (optional_dgram.has_value()) {_datagrams_out.push(std::move(optional_dgram.value()));}};//! Access queue of Internet datagrams that have been receivedstd::queue<InternetDatagram> &datagrams_out() { return _datagrams_out; }
};

这里的 Router 实现比较简单,只需实现一下 IP 最长匹配并将数据包转发即可:

Router.hh:

//! \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.// 路由一个IP数据报void route_one_datagram(InternetDatagram &dgram);// 路由表条目struct RouterTableEntry {// 路由前缀const uint32_t route_prefix;// 前缀长度const uint8_t prefix_length;// 下一跳的IP地址const std::optional<Address> next_hop;// 对应哪一个网络接口const size_t interface_idx;};// 路由表std::vector<RouterTableEntry> _router_table{};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 interfacesvoid route();
};

Router.cc:

  • add_route : 向路由表中添加路由条目
// 向路由表中添加路由条目
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";_router_table.push_back({route_prefix, prefix_length, next_hop, interface_num});
}
  • route_one_datagram: 根据路由表完成当前IP数据报的路由工作
//! \param[in] dgram The datagram to be routed
// 根据路由表进行路由
void Router::route_one_datagram(InternetDatagram &dgram) {// 获取目的ip地址const uint32_t dst_ip_addr = dgram.header().dst;auto max_matched_entry = _router_table.end();// 开始查询for (auto router_entry_iter = _router_table.begin(); router_entry_iter != _router_table.end();router_entry_iter++) {// 如果前缀匹配匹配长度为 0,或者前缀匹配相同if (router_entry_iter->prefix_length == 0 ||(router_entry_iter->route_prefix ^ dst_ip_addr) >> (32 - router_entry_iter->prefix_length) == 0) {// 如果条件符合,则更新最匹配的条目if (max_matched_entry == _router_table.end() ||max_matched_entry->prefix_length < router_entry_iter->prefix_length)max_matched_entry = router_entry_iter;}}// 将数据包 TTL 减去1// 如果存在最匹配的,并且数据包仍然存活,则将其转发if (max_matched_entry != _router_table.end() && dgram.header().ttl-- > 1) {// 获取下一条IP地址const optional<Address> next_hop = max_matched_entry->next_hop;// 获取对应的网络接口AsyncNetworkInterface &interface = _interfaces[max_matched_entry->interface_idx];// 目标主机是否位于与路由器相同的网络中。// 在这种情况下,下一跳字段可能为空,因为目标主机可以直接通过局域网访问,无需经过路由器。if (next_hop.has_value())// 交给NetworkInterface,将这个数据报发送出去interface.send_datagram(dgram, next_hop.value());else// 目的主机与路由器位于相同的网络中interface.send_datagram(dgram, Address::from_ipv4_numeric(dst_ip_addr));}// 其他情况下则丢弃该数据包
}

上面的代码中,next_hop.has_value()false 表示没有下一跳(next hop)地址,即无法找到用于转发数据包的下一跳。这可能发生在以下情况下:

  1. 直接连接目标主机: 路由表中可能存在直接连接目标主机的路由条目,也就是目标主机位于与路由器相同的网络中。在这种情况下,下一跳字段可能为空,因为目标主机可以直接通过局域网访问,无需经过路由器。

  2. 默认路由: 路由表中通常会包含默认路由(default route),也称为默认网关(default gateway)。默认路由是指当没有更精确的路由匹配时,所有未知目标IP地址的数据包将会通过默认路由进行转发。在这种情况下,下一跳字段可能为空,因为默认路由指定了一个特定的网络接口,将数据包发送到该接口,由默认网关负责将数据包转发到外部网络。

需要注意的是,在实际网络中,路由表会根据网络拓扑和路由策略进行配置,以确保数据包能够正确地转发到目标。路由表中的路由条目根据目标网络地址的前缀匹配来确定数据包的转发规则。当无法找到匹配的路由条目时,数据包将根据默认路由进行转发,或者如果没有默认路由,则会被丢弃。


  • Route: AsyncNetworkInterface会将接收到的IP数据报暂存在队列中,由Route方法负责从队列取出并进行路由
void Router::route() {// Go through all the interfaces, and route every incoming datagram to its proper outgoing interface.// 依次遍历当前路由器内部每个网络接口,依次取出每个AsyncNetworkInterface的待传输队列datagrams_outfor (auto &interface : _interfaces) {auto &queue = interface.datagrams_out();// 如果待路由队列不为空,则依次取出进行路由while (not queue.empty()) {route_one_datagram(queue.front());queue.pop();}}
}

测试

这是 CS144 的测试网络拓扑:
在这里插入图片描述
测试结果:

在这里插入图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/55680.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Shader 挖坑01】Split RGB:从水下焦散到故障效果

写在前面 最近又在写水&#xff0c;在焦散效果这里白白的挺单调&#xff0c;叠了一位大佬的方案&#xff0c;Believable Caustics Reflections - Alan Zucconi RGB通道偏移了一下&#xff1a; 采样了三次带来的消耗还蛮大的。先不说这个&#xff0c;这个RGB通道分别采样吧&…

【雕爷学编程】MicroPython动手做(28)——物联网之Yeelight 4

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…

Web3 solidity编写交易所合约 编写ETH和自定义代币存入逻辑 并带着大家手动测试

上文 Web3 叙述交易所授权置换概念 编写transferFrom与approve函数我们写完一个简单授权交易所的逻辑 但是并没有测试 其实也不是我不想 主要是 交易所也没实例化 现在也测试不了 我们先运行 ganache 启动一个虚拟的区块链环境 先发布 在终端执行 truffle migrate如果你跟着我…

K8S系列文章 之 容器网络基础 Docker0

什么是Docker0 使用ip addr命令看一下网卡&#xff1a; rootKitDevVps:~# ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host…

MyCat核心概念、需求案例讲解、环境准备及分片配置

1.MyCat概念介绍 2.MyCat入门需求 2.1 需求分析 2.2 环境准备 输入以下命令检查服务器防火墙状态 dead代表关闭状态&#xff0c;如果不关闭也可以需要开放特定的端口号&#xff01;&#xff01; systemctl status firewalld接着需要在三台服务器上的MySQL上创建三个数据库db0…

渗透攻击方法:原型链污染

目录 一、什么是原型链 1、原型对象 2、prototype属性 3、原型链 1、显示原型 2、隐式原型 3、原型链 4、constructor属性 二、原型链污染重现 实例 Nodejs沙箱逃逸 1、什么是沙箱&#xff08;sandbox&#xff09; 2、vm模块 一、什么是原型链 1、原型对象 JavaS…

PHP8的循环控制语句-PHP8知识详解

我们在上一节讲的是条件控制语句&#xff0c;本节课程我们讲解循环控制语句。循环控制语句中&#xff0c;主要有for循环、while循环、do...while循环和foreach循环。 在编写代码时&#xff0c;经常需要反复运行同一代码块。我们可以使用循环来执行这样的任务&#xff0c;而不是…

8.物联网操作系统之事件标志组

。事件标志组定义 FreeRTOS事件标志组介绍 FreeRTOS事件标志组工作原理 一。事件标志组定义 信号量信号量只能实现任务与单个事件或任务间的同步。但是某些任务可能会需要与多个事件或任务进行同步&#xff0c;此时就可以使用事件标志组来解决。事件标志组能够实现某个任务与…

高效处理矢量大数据的高可用解决方案

高效处理矢量大数据的高可用解决方案 解决方案目标 存储海量矢量数据实时分析海量矢量数据实现海量矢量数据的可视化提供高可用、高性能和高可拓展性解决方案概述 海量数据查询与可视化 系统技术流程 方案一 数据存储: PostgreSQL+PostGIS(矢量数据存储和空间分析)数据服务…

Total Variation loss

Total Variation loss 适合任务 图像复原、去噪等 处理的问题 图像上的一点点噪声可能就会对复原的结果产生非常大的影响&#xff0c;很多复原算法都会放大噪声。因此需要在最优化问题的模型中添加一些正则项来保持图像的光滑性&#xff0c;图片中相邻像素值的差异可以通过…

高级web前端开发工程师工作的岗位职责(合集)

高级web前端开发工程师工作的岗位职责1 职责&#xff1a; 1、负责产品web端界面设计与用户体验&#xff0c;包括界面操作、用户交互设计; 2、负责基于Html5的web网页前端开发&#xff0c;要求适配主流浏览器; 3、与后端开发工程师合作&#xff0c;高效完成产品模型的展现及交…

pycharm、idea、golang等JetBrains其他IDE修改行分隔符(换行符)

文章目录 pycharm、idea、golang系列修改行分隔符我应该选择什么换行符JetBrains IDE&#xff0c;默认行分隔符 是跟随系统修改JetBrains IDE&#xff0c;默认行分隔符 pycharm、idea、golang系列修改行分隔符 一般来说,不同的开发环境和项目对换行格式的使用偏好不同: Windo…