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.mzph.cn/news/24669.shtml

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

相关文章

Linux知识点 -- 进程间通信(二)

Linux知识点 – 进程间通信&#xff08;二&#xff09; 文章目录 Linux知识点 -- 进程间通信&#xff08;二&#xff09;一、System V共享内存1.原理2.申请共享内存3.System V共享内存的使用4.为共享内存添加访问控制 二、信号量&#xff08;概念理解&#xff09;1.概念2.信号量…

OpenCV之信用卡识别实战

文章目录 代码视频讲解模板匹配文件主程序(ocr_template_match.py)myutils.py 代码 链接: https://pan.baidu.com/s/1KjdiqkyYGfHk97wwgF-j3g?pwdhhkf 提取码: hhkf 视频讲解 链接: https://pan.baidu.com/s/1PZ6w5NcSOuKusBTNa3Ng2g?pwd79wr 提取码: 79wr 模板匹配文件 …

Ubuntu开机自启服务systemd.service配置教程(Ubuntu服务)(Linux服务)upstart

文章目录 为什么要将程序配置成服务&#xff1f;1. 自动启动2. 后台运行3. 定时重启4. 简化管理5. 整合系统 版本支持1. Ubuntu 14.04及更早版本&#xff1a;使用upstart作为默认的init系统/etc/rc.local旧版本新版本 2. Ubuntu 15.04到16.04版本&#xff1a;默认使用systemd作…

【敏捷开发】测试驱动开发(TDD)

测试驱动开发&#xff08;Test-Driven Development&#xff0c;简称TDD&#xff09;是敏捷开发模式中的一项核心实践和技术&#xff0c;也是一种设计方法论。TDD有别于以往的“先编码&#xff0c;后测试”的开发模式&#xff0c;要求在设计与编码之前&#xff0c;先编写测试脚本…

1310. 数三角形

题目链接&#xff1a;https://www.acwing.com/problem/content/1312/ 首先不考虑三点共线的情况一共有 种&#xff0c;现在来计算三点共线的情况 1.三点在一条直线上 2.三点在一条竖线上 3.三点在一条斜线上&#xff0c;正反斜线对称&#xff0c;仅需考虑一边的情况 如果…

docker安装mysql

安装mysql docker pull mysql:8.0.31 单机启动&#xff1a; docker run -itd --name mysql1 -p 3305:3306 -e MYSQL_ROOT_PASSWORD123456 mysql:8.0.31 --lower_case_table_names1 单机指定配置文件启动&#xff1a; docker run \ --name mysql-8 \ -d \ -p 3306:3306 …

14-5_Qt 5.9 C++开发指南_基于HTTP 协议的网络应用程序

文章目录 1. 实现高层网络操作的类2. 基于HTTP协议的网络文件下载3.源码3.1 可是化UI设计3.2 mainwindow.h3.3 mainwindow.cpp 1. 实现高层网络操作的类 Qt 网络模块提供一些类实现 OSI 7 层网络模型中高层的网络协议&#xff0c;如 HTTP、FTP、SNMP等&#xff0c;这些类主要是…

Netty使用和常用组件辨析

Netty 使用和常用组件 简述 <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId <version>4.1.42.Final </version> <scope>compile</scope> </dependency> Netty 的优势 1 、 AP…

【小吉带你学Git】idea操作(2)_版本和分支的相关操作

&#x1f38a;专栏【Git】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386;音乐分享【Counting Stars 】 欢迎并且感谢大家指出小吉的问题&#x1f970; 文章目录 &#x1f354;版本⭐首先创建一个项目⭐添加暂存区⭐提交本地库&#x1f33…

压力测试与测试工具jmeter的介绍

目录 一、性能指标 二、jmeter &#xff08;一&#xff09;JMeter 安装 &#xff08;二&#xff09;JMeter 压测示例 1、添加线程组 2、添加 HTTP 请求 3、添加监听器 4、启动压测&查看分析结果 &#xff08;三&#xff09;JMeter Address Already in use 错误解决 压力测…

yum出现Could not retrieve mirrorlist解决方法

Loaded plugins: fastestmirror, security Loading mirror speeds from cached hostfile Could not retrieve mirrorlist http://mirrorlist.centos.org/?release6&archi386&repoos error was 14: PYCURL ERROR 6 - “Couldn’t resolve host ‘mirrorlist.centos.org…

monaco,monaco-editor,monaco-editor-webpack-plugin,

Monaco "Monaco"是包含了Monaco Editor和Monaco Language Server两个项目的总称&#xff0c;而"Monaco Editor"是Monaco项目中的一个部分&#xff0c;它是一款基于Web技术的高性能代码编辑器。 Monaco Language Server是一个支持多种语言的语言服务器&am…

【web逆向】全报文加密及其登录流程的分析案例

aHR0cHM6Ly9oZWFsdGguZWxkZXIuY2NiLmNvbS9zaWduX2luLw 涉及加密库jsencrypt 定位加密点 先看加密的请求和响应&#xff1a; 全局搜索加密字段jsondata&#xff0c;这种非特定参数的一般一搜一个准&#xff0c;搜到就是断点。起初下的断点没停住&#xff0c;转而从调用栈单步…

HJ52 计算字符串的编辑距离

题目&#xff1a;HJ52 计算字符串的编辑距离 题解&#xff1a; 定义dp方程&#xff0c;dp[i][j] 表示字符串s1(1-i)&#xff0c;到字符串s2(1-j)的编辑距离&#xff1b; 如果s1[i] s2[j] 证明当前位置的字符相等&#xff0c;无需操作&#xff0c;即dp[i][j] dp[i-1][j-1]; …

K8S系列文章之 kubeasz部署K8S环境

自动化安装方式&#xff08;kubeasz&#xff09;* 生产环境推荐&#xff08;首次安装下载相关配置和安装包&#xff09;是基于Ansible实现的部署工具 简单介绍 每一具体k8s集群的详细配置参数文件 Ansible 任务配置文件 镜像安装包 安装部署步骤 前提 &#xff1a; 保证Ansib…

Python web实战之 Django 的模板语言详解

关键词&#xff1a; Python、web开发、Django、模板语言 概要 作为 Python Web 开发的框架之一&#xff0c;Django 提供了一套完整的 MVC 模式&#xff0c;其中的模板语言为开发者提供了强大的渲染和控制前端的能力。本文介绍 Django 的模板语言。 1. Django 模板语言入门 Dj…

npm发布包

1.npm 登录 在控制台输入命令 npm login 按提示输入用户名&#xff0c;密码&#xff0c;邮箱后登录 如果出现如下提示 需要将淘宝镜像源切换为npm源&#xff0c;删除或注释以下内容就行 2.发布 进入准备发布的代码的根目录下&#xff0c;输入命令 npm publish 3.删除已发…

PostgreSql pg_ctl 命令

一、概述 控制 PostgreSQL 服务的工具。 二、语法 --初始化数据库实例 pg_ctl init[db] [-D datadir] [-s] [-o initdb-options]--启动数据库实例 pg_ctl start [-D datadir] [-l filename] [-W] [-t seconds] [-s] [-o options] [-p path] [-c]--停止数据库实例 pg_ctl sto…

区块链和WEB3.0有哪些基础知识呢

区块链基础知识 常用区块链基础知识包括&#xff1a; &#xff08;1&#xff09;区块链概念&#xff1a;区块链是一种去中心化的分布式账本技术&#xff0c;它通过加密算法和共识机制保证了数据的安全性和不可篡改性。区块链中的每一个区块都包含了前一个区块的哈希值&#x…

怎么学习CSS相关技术知识? - 易智编译EaseEditing

学习CSS技术是前端开发中的重要一环&#xff0c;它用于控制网页的样式和布局&#xff0c;使网页更加美观和易于使用。以下是学习CSS技术的几个方面&#xff1a; 基本语法和选择器&#xff1a; 了解CSS的基本语法&#xff0c;学习如何使用选择器来选择HTML元素并应用样式。 样…