CS 144 Lab Six -- building an IP router

news2024/9/28 7:26:05

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 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);
        // 只会将IPV4数据报放入数据报接收队列中
        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; }
};

这里的 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 interfaces
    void 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_out
    for (auto &interface : _interfaces) {
        auto &queue = interface.datagrams_out();
        // 如果待路由队列不为空,则依次取出进行路由
        while (not queue.empty()) {
            route_one_datagram(queue.front());
            queue.pop();
        }
    }
}

测试

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

在这里插入图片描述


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

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

相关文章

整数线性规划——pulp指南

整数线性规划——pulp指南 PuLP是一个用Python编写的线性规划建模工具。PuLP可以生成MPS或LP文件&#xff0c;并调用GLPK、COIN-OR CLP/CBC、CPLEX、GUROBI、MOSEK、XPRESS、CHOCO、MIPCL、HiGHS、SCIP/FSCIP等求解线性问题。 官方文档地址&#xff1a;https://coin-or.githu…

【ROS】message_filters时间同步

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍message_filters时间同步。 学其所用&#xff0c;用其所学。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c;下次更新不迷…

接口mock常用工具

在进行测试时&#xff0c;我们经常需要模拟接口数据&#xff0c;尤其是在前后端分离项目的开发中&#xff0c;在后端未完成开发时&#xff0c;前端拿不到后端的数据&#xff0c;就需要对后端返回的数据进行模拟。 如下一些工具&#xff0c;可以完成接口的mock。 Yapi 首先添…

算法通关村——轻松搞定两树相等问题

题目 给你两棵二叉树的根节点p和q&#xff0c;编写一个函数来检验这两棵树是否相同。如果两个树在结构上相同&#xff0c;并且节点具有相同的值&#xff0c;则认为他们是相同的。 示例 输入&#xff1a;p[1,2,3] q[1,2,3] 输出&#xff1a;true 如下图所示&#xff1a; 输入&am…

制造执行系统(MES):优化生产管理的关键

制造业是现代经济的重要组成部分&#xff0c;随着技术的发展和市场需求的变化&#xff0c;制造企业面临着越来越大的挑战。为了在竞争激烈的市场中保持竞争力&#xff0c;企业需要实现生产过程的高效管理和优化。这就引入了制造执行系统&#xff08;MES&#xff09;&#xff0c…

【Spring Boot】了解Spring Boot 的日志文件

目录 一、日志的作用 二、日志文件的简单使用 1、Spring Boot中的默认日志 2、自定义日志打印 三、日志级别 1、日志级别分类 2、日志级别的设置 3、日志持久化 四、基于LomBok的日志输出 1、安装Lombok插件 2、使用Lombok添加日志 3、使用Lombok添加getter和setter…

第48节:cesium 面交集计算(含源码+视频)

结果示例: 完整源码: <template><div class="viewer"><vc-viewer @ready="ready" :logo="false"><vc-navigation

13-把矩阵看作是对系统的描述

探索矩阵乘法&#xff1a;更深刻的理解与应用视角 &#x1f9e9;&#x1f50d; 引言 &#x1f4d6; 在我们进一步探讨矩阵乘法之前&#xff0c;让我们从不同的角度来理解什么是矩阵&#xff0c;以及如何将矩阵视为一个系统。我们之前已经介绍了矩阵的基本概念和运算&#xff…

那些没人教你的Jmeter 循环断言,百度不到的,收藏一下吧

前言 对于使用jmeter工具完成接口测试的测试工程师而言。在工作中&#xff0c;或者在面试中&#xff0c;都会遇到一个问题。 CSV文档做了一大笔测试数据后&#xff0c;怎么去校验这个结果呢&#xff1f; 现在大部分测试工程师可能都是通过人工的方法去查看结果&#xff0c;十几…

【3D卡片切换】基于jquery实现3D堆叠卡片切换效果(附完整源码)

文章目录 写在前面涉及知识点实现效果1、搭建页面1.1 创建ul li节点1.2 丰富元素Html代码所示CSS代码所示 2、JS实现堆叠切换3、源码分享3.1 百度网盘3.2 123云盘3.3 邮箱留言 总结 写在前面 其实3D卡片堆叠切换效果&#xff0c;从我入前端坑以来就一直喜欢的一种轮播效果&…

护网行动 | AD360 在网络安全中的重要作用

随着数字化时代的来临&#xff0c;网络已经成为了人们生活和工作中不可或缺的一部分。然而&#xff0c;随之而来的是网络安全问题日益突出。为了应对这些安全威胁&#xff0c;护网行动应运而生&#xff0c;其中AD360在保障网络安全方面扮演着至关重要的角色。 AD360是一个集成的…

封装上传组件(axios,进度条onUploadProgress,取消请求)

目录 定时模拟进度条 方法 A.axios B.xhr 取消请求​​​​​​​cancelToken A.axios.canceltoken B.source对象创建canceltoken 完整代码 A.自定义上传组件 B.二次封装组件 情况 增加cancelToken不生效&#xff0c;刷新页面 进度条太快->设置浏览器网速 定时…

发布属于自己的 npm 包

1 创建文件夹&#xff0c;并创建 index.js 在文件中声明函数&#xff0c;使用module.exports 导出 2 npm 初始化工具包&#xff0c;package.json 填写包的信息&#xff08;包的名字是唯一的&#xff09; npm init 可在这里写包的名字&#xff0c;或者一路按回车&#xff0c;后…

JedisDataException DENIED Redis is running in protected mode...异常的解决办法

一. 异常现象 壹哥最近在带学生做项目的过程中&#xff0c;有学生在使用Redis的时候&#xff0c;产生了如下这样的异常信息&#xff1a; com.yyg.demo.Demo01Exception in thread "main" redis.clients.jedis.exceptions.JedisDataException: DENIED Redis is runni…

企业邮箱安全对比:哪家公司的产品更可靠?

邮箱仍然是企业沟通的关键组成部分&#xff0c;但往往容易受到安全威胁。为了保护敏感信息&#xff0c;企业需要采取措施使企业邮箱更加安全。这可以通过投资先进的安全解决方案&#xff0c;创建限制或控制访问的策略&#xff0c;并定期对员工进行最佳实践培训来实现。 1、投资…

Java实战:高效提取PDF文件指定坐标的文本内容

前言 临时接到一个紧急需要处理的事项。业务侧一个同事有几千个PDF文件需要整理&#xff1a;需要从文件中的指定位置获取对应的编号和地址。 要的急&#xff0c;工作量大。所以就问到技术部有没有好的解决方案。 问技术的话就只能写个demo跑下了。 解决办法 1. 研究下PDF文档…

B站又添黑马UP主,首发创下1800万播放

众所周知&#xff0c;ACG类是B站最受欢迎的内容&#xff0c;毕竟B站由二次元内容为起点发展至今&#xff0c;吸引了众多年轻一代的用户群体。 而B站又是一个“来自用户”的平台&#xff0c;由用户转变成UP主自发投稿作品&#xff0c;构建出现在这个存在着大大小小几十个分区的…

固定资产管理工作总结

固定资产管理是现代企业管理工作的重点。在过去的一段时间里&#xff0c;企业专注于固定资产管理&#xff0c;以达到节约企业资源的效果。 企业要坚持以标准化管理为载体&#xff0c;制定完善的固定资产管理制度&#xff0c;全面规范固定资产进出口、汇总、储存、维护、损坏等…

利用 3D 地理空间数据实现Cesium的沉浸式环境

推荐&#xff1a;使用 NSDT场景编辑器 助你快速搭建可编辑的3D应用场景 为了将大量异构 3D 地理空间数据处理和分散到各行各业的地理空间应用程序和运行时引擎&#xff0c;Cesium 创建了 3D Tiles&#xff0c;这是一种用于高效流式传输和渲染大量异构数据集的开放标准。3D Tile…

《Python入门到精通》函数详解

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;小白零基础《Python入门到精通》 函数 1、函数的调用2、函数的参数2.1、变量的就近原则2.2、传递参数2.3、形参和实…