CS144 Lab 6 实战记录:构建 IP 路由器

1 实验背景与目标

在 CS144 的 Lab 6 中,我们需要在之前实现的 NetworkInterface(Lab 5)基础上构建一个完整的 IP 路由器。路由器的主要任务是根据路由表将接收到的 IP 数据报转发到正确的网络接口,并发送给正确的下一跳(next hop)。

一个路由器拥有多个网络接口,可以在任何一个接口上接收 Internet 数据报。路由器的主要职责是根据路由表确定两件事:

  • 应该使用哪个出站接口(interface)发送数据报
  • 数据报的下一跳(next hop)IP 地址是什么

与前几个实验不同,IP 路由器的实现不需要了解 TCP、ARP 或以太网的细节,只需专注于 IP 层的转发逻辑。

2 路由器工作原理

2.1 路由器功能概述

IP 路由器主要完成两个关键功能:

  1. 维护路由表:存储一系列路由规则,每条规则包含网络前缀、前缀长度、下一跳信息和出站接口编号
  2. 转发数据报:根据路由表中的规则,将每个接收到的数据报转发到正确的出站接口和下一跳地址
路由表查询
(最长前缀匹配)
Internet数据报
路由器
转发决策
网络接口1
网络接口2
网络接口n
下一跳1
下一跳2
下一跳n

2.2 最长前缀匹配原则

路由器使用最长前缀匹配(Longest Prefix Match)算法来选择最佳路由。这意味着当多个路由规则匹配一个目标 IP 地址时,路由器会选择前缀长度最长的那个规则。这样可以实现更精确的路由控制。例如,对于目标 IP 地址 172.16.10.3,可能匹配的规则有 172.16.0.0/16172.16.10.0/24,路由器会选择前缀长度为 24 的规则,因为它提供了更精确的匹配。

接收数据报
检查目标IP地址
在路由表中查找匹配项
有多个匹配项?
选择前缀长度最长的匹配项
有一个匹配项?
使用该匹配项
丢弃数据报
确定出站接口和下一跳
TTL减1
TTL大于0?
通过选定接口发送到下一跳
丢弃数据报

3 路由器实现

3.1 数据结构设计

将路由表按前缀长度(1-32)分成32个组,方便从长到短进行最长前缀匹配。每个前缀长度组内使用哈希表存储,表示匹配前缀与路由项的映射关系。

struct RouteEntry {size_t interface_num {};      // 出站接口编号std::optional<Address> next_hop {}; // 下一跳地址(如果有)
};// 路由表,按前缀长度分组(最多32个组,对应IPv4地址的32位,逆序表示。例如下标为0代表前缀长度32)
std::array<std::unordered_map<uint32_t, RouteEntry>, 32> routing_table_ {};

3.2 添加路由条目

add_route方法向路由表添加一条新的路由规则,具体处理逻辑:

  1. 前缀计算:使用右移操作获取有效前缀位,例如:对于 192.168.1.0/24,右移 (32-24) = 8 位,保留高 24 位作为匹配前缀。需要特别处理前缀长度为 0 的默认路由,避免右移 32 位导致的未定义行为
  2. 路由条目存储:将路由条目存入对应前缀长度的哈希表中,键是处理后的前缀,值是路由条目信息
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() << "/"<< static_cast<int>(prefix_length) << " => " << (next_hop.has_value() ? next_hop->ip() : "(direct)")<< " on interface " << interface_num << "\n";// 截取route_prefix的前prefix_length位作为有效前缀uint32_t masked_prefix = (prefix_length == 0) ? 0 : (route_prefix >> (32 - prefix_length));// 插入到对应前缀长度的路由表中routing_table_[prefix_length][masked_prefix] = { interface_num, next_hop };
}

3.3 路由匹配查找

match 方法实现最长前缀匹配算法,为每个数据报找到最佳路由:

flowchart TDA[开始匹配] --> B[从前缀长度31开始]B --> C[计算目标IP地址的前len位]C --> D{前缀长度组中\n有匹配项?}D -->|是| E[返回匹配的路由条目]D -->|否| F[前缀长度减1]F --> G{前缀长度≥0?}G -->|是| CG -->|否| H[返回无匹配]
optional<Router::RouteEntry> Router::match(uint32_t dst_addr) const noexcept {for (int len = 31; len >= 0; --len) {uint32_t masked = (len == 0) ? 0 : (dst_addr >> (32 - len));const auto& table = routing_table_[len];auto it = table.find(masked);if (it != table.end()) {return it->second;}}return nullopt;
}

3.4 数据报转发处理

route 方法是路由器的核心功能,负责处理所有接口收到的数据报并进行转发。

网络接口 路由器 最长前缀匹配 转发逻辑 遍历所有接口 获取接收到的数据报队列 检查TTL值 丢弃数据报 TTL减1并重新计算校验和 查找最长前缀匹配路由 返回匹配的路由条目 确定目标地址和出站接口 通过对应接口发送数据报 丢弃数据报 alt [有匹配路由] [无匹配路由] alt [TTL ≤ 1] [TTL > 1] loop [对每个数据报] 网络接口 路由器 最长前缀匹配 转发逻辑
void Router::route() {for (const auto& interface : interfaces_) {auto& datagrams_received = interface->datagrams_received();// 处理所有收到的数据报while (!datagrams_received.empty()) {InternetDatagram datagram = move(datagrams_received.front());datagrams_received.pop();// TTL ≤ 1表示不能再转发,直接丢弃if (datagram.header.ttl <= 1) {continue;}// TTL减1并重新计算校验和datagram.header.ttl -= 1;datagram.header.compute_checksum();// 使用最长前缀匹配查找路由条目auto routeEntry = match(datagram.header.dst);if (!routeEntry.has_value()) {continue;}// 如果没有指定下一跳,则直接发送到目标IPAddress target = routeEntry->next_hop.value_or(Address::from_ipv4_numeric(datagram.header.dst));// 通过对应接口发送数据报interfaces_[routeEntry->interface_num]->send_datagram(datagram, target);}}
}

4 调试记录

  1. 最初在计算掩码后的前缀时,使用了按位与操作,但这种方法对于可变长度前缀处理起来比较复杂。改用右移操作后,处理变得更简单高效。

  2. 最初的实现中,先执行路由匹配再检查TTL,这导致一些应该被丢弃的数据报被错误处理。修正为先检查TTL再进行后续处理。

  3. 处理前缀长度为0的默认路由时需要特殊处理,确保将掩码设置为0而不是尝试右移32位(这会导致未定义行为)。

    image-20250424213846855

5 代码仓库

项目代码已上传至GitHub:https://github.com/HeZephyr/minnow

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

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

相关文章

【网络安全】社会工程学策略

1. 社会工程学简介 社会工程攻击是威胁行为者常用的攻击方式。这是因为&#xff0c;诱骗人们提供访问权限、信息或金钱通常比利用软件或网络漏洞更容易。 您可能还记得&#xff0c;社会工程学是一种利用人为错误来获取私人信息、访问权限或贵重物品的操纵技术。它是一个涵盖性…

【含文档+PPT+源码】基于SpringBoot的开放实验管理平台设计与实现

项目介绍 本课程演示的是一款基于SpringBoot的开放实验管理平台设计与实现&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 1.包含&#xff1a;项目源码、项目文档、数据库脚本、软件工具等所有资料 2.带你从零开始部署运行本套系统…

鸿蒙NEXT开发定位工具类 (WGS-84坐标系)(ArkTs)

import geoLocationManager from ohos.geoLocationManager; import { BusinessError, Callback } from ohos.base; import { LogUtil } from ./LogUtil; import { PermissionUtil } from ./PermissionUtil; import { map, mapCommon } from kit.MapKit; /*** 定位工具类 (WGS-8…

SSM从入门到上手-全面讲解SSM框架的使用.

一、SSM框架整合 将Spring、Spring MVC和MyBatis结合在一起&#xff0c;形成一个高效且易于维护的Web应用程序架构。具体整合的方式如下&#xff1a; Spring管理Bean&#xff1a;Spring负责管理所有的Java对象&#xff0c;包括Service层、DAO层等。通过Spring的IoC容器进行依赖…

学员答题pk知识竞赛小程序怎么做

制作学员答题PK知识竞赛小程序&#xff0c;主要有以下步骤&#xff1a; 一、规划设计 明确需求&#xff1a;确定小程序的使用场景是校园知识竞赛、培训机构考核还是企业内部培训等。答题功能&#xff0c;规定答题的具体规则&#xff0c;包括题目类型&#xff08;单选、多选、…

视频分析设备平台EasyCVR视频技术驱动下,监控上墙全组件解析与组网应用方案

随着数字化进程的加速推进&#xff0c;视频监控技术在工业、商业、社区等诸多领域得到了广泛应用。尽管不同场景对监控功能的具体需求存在差异&#xff0c;但底层硬件架构具有显著的共性特征。实际部署中&#xff0c;仅需依据网络环境等实际情况&#xff0c;灵活调整设备的连接…

idea使用docker插件一键部署项目

一、首先保证我们电脑上已经安装了docker docker -v查看docker版本&#xff0c;如果不能识别&#xff0c;需要先下载docker destop&#xff0c;在官网下载正常安装即可。 安装成功就可以使用docker 命令了 二、idea下载docker插件并配置docker参数 我是通过tcp连接docker服务…

SQL Tuning Advisor

什么是SQL Tuning Advisor STA可以用来优化那些已经被发现的高负载SQL. 默认情况下, Oracle数据库在自动维护窗口中自动认证那些有问题的SQL并且执行优化建议&#xff0c;找寻提升高负载SQL执行计划性能的方法. ** 如何查看自动优化维护窗口产生的报告? ** SQL> set ser…

uniapp-商城-31-shop页面中的 我的订单

前面的章节讲了很多关于页面 布局 的知识。 现在来看看其他栏目&#xff0c;我的订单页面。 1 页面样式图 基本的样式包含shop页面 我的订单 点击我的订单&#xff0c;跳转到订单页面 点击订单的每一条订单&#xff0c;跳转到订单详情 2、创建订单页面 2.1 创建sub页面文件…

深入探讨JavaScript性能瓶颈与优化实战指南

JavaScript作为现代Web开发的核心语言,其性能直接影响用户体验与业务指标。随着2025年前端应用的复杂性持续增加,性能优化已成为开发者必须掌握的核心技能。本文将从性能瓶颈分析、优化策略、工具使用三个维度,结合实战案例,系统梳理JavaScript性能优化的关键路径。 一、Ja…

基于AI与drawio的图表生成技术及其在学术研究中的应用前景分析

一、研究背景与冲突 在当今数字化时代&#xff0c;学术研究与信息传播的方式发生了深刻变革。随着数据量的爆炸式增长以及研究内容的日益复杂&#xff0c;高效、精准地呈现研究成果变得至关重要。图表作为一种直观、简洁且信息承载量大的表达方式&#xff0c;在学术研究中扮演着…

uniapp 仿小红书轮播图效果

通过对小红书的轮播图分析&#xff0c;可得出以下总结&#xff1a; 1.单张图片时容器根据图片像素定高 2.多图时轮播图容器高度以首图为锚点 3.比首图长则固高左右留白 4.比首图短则固宽上下留白 代码如下&#xff1a; <template><view> <!--轮播--><s…

【ORACLE】记录一些ORACLE的merge into语句的BUG

【ORACLE】记录一些ORACLE的merge into语句的BUG 一、自相矛盾-DML重启动行为差异,违反acid原则 发现版本&#xff1a;10g ~ 23ai 这个用例在我之前的文章里有提过&#xff0c;ORACLE和PG系关于并发事务行为有一个非常大的差异&#xff0c;就是ORACLE在某些并发冲突的场景下会…

2025上海车展:光峰科技全球首发“灵境”智能车载光学系统

当AI为光赋予思想&#xff0c;汽车将会变成什么样&#xff1f;深圳光峰科技为您揭晓答案。 2025年4月23日&#xff0c;在刚刚开幕的“2025上海车展”上&#xff0c;全球领先的激光核心器件公司光峰科技举办了主题为“AI光影盛宴&#xff0c;智享未来出行”的媒体发布会&#x…

密码学的hash函数,哈希碰撞, collision resistance, BTC用到的SHA-256简介

密码学中的哈希函数、哈希碰撞、抗碰撞性&#xff08;collision resistance&#xff09;以及比特币中使用的 SHA-256 的简明介绍&#xff1a; &#x1f9e9; 一、哈希函数&#xff08;Hash Function&#xff09; 定义&#xff1a; 哈希函数是一种将任意长度的输入&#xff08;…

unity TEngine学习4

上一篇我们学习了UI部分&#xff0c;这一篇我们学习其他部分&#xff0c;按照老规矩还是先打开官方文档 ResourceModule 在官方文档里介绍了当前加载的设置&#xff0c;但是我们是小白看不懂&#xff0c;那就不管他内部怎么实现的&#xff0c;我们主要看下面的代码给的方法&am…

【AI训练环境搭建】在IDE(Pycharm或VSCode)上使用WSL2+Ubuntu22.04+Conda+Tensorflow+GPU进行机器学习训练

本次实践将在IDE&#xff08;Pycharm或VSCode&#xff09;上使用WSL2Ubuntu22.04TensorflowGPU进行机器学习训练。基本原理是在IDE中拉起WSL2中的Python解释器&#xff0c;并运行Python程序。要运行CondaTensorflowGPU你可能需要进行以下准备工作。 1. 此示例中将使用一个mnis…

【华为OD机试真题E卷】521、 机器人可活动的最大网格点数目 | 机试真题+思路参考+代码解析(E卷复用)(C++)

文章目录 一、题目题目描述输入输出样例1 一、代码与思路&#x1f9e0;C语言思路✅C代码 一、题目 参考链接&#xff1a;https://sars2025.blog.csdn.net/article/details/141748083 题目描述 现有一个机器人口&#xff0c;可放置于MxN的网格中任意位置&#xff0c;每个网格包…

windows端远程控制ubuntu运行脚本程序并转发ubuntu端脚本输出的网页

背景 对于一些只能在ubuntu上运行的脚本&#xff0c;并且这个脚本会在ubuntu上通过网页展示运行结果。我们希望可以使用windows远程操控ubuntu&#xff0c;在windows上查看网页内容。 方法 start cmd.exe /k "sshpass -p passwd ssh namexxx.xxx.xxx.xxx "cd /hom…

Vue3集成浏览器API实时语音识别

效果示例 用法 <!-- 浏览器语音识别 --> <BrowserSpeechRecognitionModal v-if"showModal" :isOpen"showModal" close"showModal false" confirm"handleRecognitionResult" />const showModal ref(false); const input…