【斯坦福CS144】Lab5

news2024/10/10 1:33:20

一、实验目的

在现有的NetworkInterface基础上实现一个IP路由器。

二、实验内容

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

发送到哪个接口;

下一跳的IP地址 ;

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

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

三、实验过程

在minnow目录下输入git merge origin/check5-startercode获取Lab5

用文本编辑器打开./src/router.hh

修改代码

用文本编辑器打开./src/router.cc

修改代码

在build目录下输入make进行编译

输入make check5进行测试

测试成功,实验结束

四、实验体会

1.本实验中的 Router 实现比较简单,只需实现一下 IP 最长匹配并将数据包转发即可。

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

五、代码附录

router.hh

#pragma once

#include "network_interface.hh"

#include <optional>
#include <queue>

// A wrapper for NetworkInterface that makes the host-side
// interface asynchronous: instead of returning received datagrams
// immediately (from the `recv_frame` method), it stores them for
// later retrieval. Otherwise, behaves identically to the underlying
// implementation of NetworkInterface.
class AsyncNetworkInterface : public NetworkInterface
{
  std::queue<InternetDatagram> datagrams_in_ {};

public:
  using NetworkInterface::NetworkInterface;

  // Construct from a NetworkInterface
  explicit 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 );
    if ( optional_dgram.has_value() ) {
      datagrams_in_.push( std::move( optional_dgram.value() ) );
    }
  };

  // Access queue of Internet datagrams that have been received
  std::optional<InternetDatagram> maybe_receive()
  {
    if ( datagrams_in_.empty() ) {
      return {};
    }

    InternetDatagram datagram = std::move( datagrams_in_.front() );
    datagrams_in_.pop();
    return datagram;
  }
};

// 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_ {};

//   struct Route_entry//route_entry_
//   {
//     uint32_t route_prefix{};
//     uint8_t prefix_length{};
//     std::optional<Address> next_hop;
//     size_t interface_num{};
//   };
//   //static typedef struct route_entry_ Route_entry;
//   std::vector<Route_entry> route_table_{};
class Router
{
  // The router's collection of network interfaces
  std::vector<AsyncNetworkInterface> interfaces_ {};
  struct Route_entry
  {
    uint32_t route_prefix {};
    uint8_t prefix_length {};
    std::optional<Address> next_hop;
    size_t interface_num {};
  };

  

  std::vector<Route_entry> route_table_ {};

  //std::vector<Route_entry>::iterator longest_prefix_match_( uint32_t dst_ip );

  //static int match_length_( uint32_t src_ip, uint32_t tgt_ip, uint8_t tgt_len );
public:
  // Add an interface to the router
  // 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( size_t N ) { return interfaces_.at( N ); }

  // Add a route (a forwarding rule)
  void add_route( uint32_t route_prefix,
                  uint8_t prefix_length,
                  std::optional<Address> next_hop,
                  size_t interface_num );

  // Route packets between the interfaces. For each interface, use the
  // maybe_receive() method to consume every incoming datagram and
  // send it on one of interfaces to the correct next hop. The router
  // chooses the outbound interface and next-hop as specified by the
  // route with the longest prefix_length that matches the datagram's
  // destination address.
  void route();

  std::vector<Route_entry>::iterator longest_prefix_match_( uint32_t dst_ip );
  int match_length_( uint32_t src_ip, uint32_t tgt_ip, uint8_t tgt_len );
  // std::vector<Route_entry>::iterator longest_prefix_match_( uint32_t dst_ip );
  // int match_length_( uint32_t src_ip, uint32_t tgt_ip, uint8_t tgt_len );
};

router.cc

#include "router.hh"

#include <iostream>
#include <limits>
using namespace std;

// route_prefix: The "up-to-32-bit" IPv4 address prefix to match the datagram's destination address against
// 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?
// 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).
// 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() << "/"
//        << static_cast<int>( prefix_length ) << " => " << ( next_hop.has_value() ? next_hop->ip() : "(direct)" )
//        << " on interface " << interface_num << "\n";

//   // (void)route_prefix;
//   // (void)prefix_length;
//   // (void)next_hop;
//   // (void)interface_num;

//   route_table_.emplace_back(route_prefix, prefix_length, next_hop, interface_num);
//   return;
// }

// void Router::route()
// {
//   for ( auto& current_interface : interfaces_ ) {
//     auto received_dgram = current_interface.maybe_receive();
//     if ( received_dgram.has_value() ) {
//       auto& dgram = received_dgram.value();
//       if ( dgram.header.ttl > 1 ) {
//         dgram.header.ttl--;
//         // NOTE: important!!!
//         dgram.header.compute_checksum();
//         auto dst_ip = dgram.header.dst;
//         auto it = longest_prefix_match_( dst_ip );
//         if ( it != route_table_.end() ) {
//           auto& target_interface = interface( it->interface_num );
//           target_interface.send_datagram( dgram, it->next_hop.value_or( Address::from_ipv4_numeric( dst_ip ) ) );
//         }
//       }
//     }
//   }
// }

// std::vector<Router::Route_entry>::iterator Router::longest_prefix_match_( uint32_t dst_ip )
// {
//   auto res = route_table_.end();
//   int max_length = 0;
//   for ( auto it = route_table_.begin(); it != route_table_.end(); ++it ) {
//     int len = match_length_( dst_ip, it->route_prefix, it->prefix_length );
//     if ( len > max_length ) {
//       max_length = len;
//       res = it;
//     }
//   }
//   return res;
// }

// int Router::match_length_( uint32_t src_ip, uint32_t tgt_ip, uint8_t tgt_len )
// {
//   if ( tgt_len == 0 ) {
//     return 0;
//   }

//   if ( tgt_len > 32 ) {
//     return -1;
//   }

//   // tgt_len < 32
//   uint8_t const len = 32U - tgt_len;
//   src_ip = src_ip >> len;
//   tgt_ip = tgt_ip >> len;
//   return src_ip == tgt_ip ? tgt_len : -1;
// }

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_table_.emplace_back( route_prefix, prefix_length, next_hop, interface_num );
}

void Router::route()
{
  for (uint32_t i=0; i<interfaces_.size();i++) {
    auto received_dgram = interface(i).maybe_receive();
    if ( received_dgram.has_value() ) {
      auto dgram = received_dgram.value();
      if ( dgram.header.ttl > 1 ) {
        dgram.header.ttl--;
        dgram.header.compute_checksum();
        auto dst_ip = dgram.header.dst;
        auto it = longest_prefix_match_( dst_ip );
        if ( it != route_table_.end() ) {
          //这里的bug
          interface( it->interface_num ).send_datagram( dgram, it->next_hop.value_or( Address::from_ipv4_numeric( dst_ip ) ) );
        }
      }
    }
  }
}

std::vector<Router::Route_entry>::iterator Router::longest_prefix_match_( uint32_t dst_ip )
{
  auto res = route_table_.end();
  int max_length = -1;
  for ( auto it = route_table_.begin(); it != route_table_.end(); ++it ) {
    int len = match_length_( dst_ip, it->route_prefix, it->prefix_length );
    if ( len > max_length ) {
      max_length = len;
      res = it;
    }
  }
  return res;
}

int Router::match_length_( uint32_t src_ip, uint32_t tgt_ip, uint8_t tgt_len )
{
  if ( tgt_len == 0 ) {
    return 0;
  }

  if ( tgt_len > 32 ) {
    return -1;
  }

  // tgt_len < 32
  uint8_t len = 32U - tgt_len;
  src_ip = src_ip >> len;
  tgt_ip = tgt_ip >> len;
  return src_ip == tgt_ip ? tgt_len : -1;
}

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

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

相关文章

Expectation-Maximization Algorithm(EM算法)

EM算法&#xff08;Expectation-Maximization Algorithm&#xff0c;期望最大化算法&#xff09;是一种迭代优化算法&#xff0c;主要用于在含有隐变量&#xff08;未观测变量&#xff09;或不完全数据的概率模型中&#xff0c;估计参数的最大似然估计&#xff08;Maximum Like…

【Kubernetes】常见面试题汇总(五十七)

目录 125. K8S 创建服务 status 为 ErrlmagePull&#xff1f; 126.不能进入指定容器内部&#xff1f; 特别说明&#xff1a; 题目 1-68 属于【Kubernetes】的常规概念题&#xff0c;即 “ 汇总&#xff08;一&#xff09;~&#xff08;二十二&#xff09;” 。 题目 …

【时时三省】(C语言基础)指针笔试题7

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ----CSDN 时时三省 笔试题7 a是一个数组 a每个元素的类型是char* 它是一个指针数组 它有三个字符串 初始化了三个字符串 这个时候会产生三个字符串的首地址 第二行代码 a数组名 相当于数组名 第一个首元素…

k8s的pod管理及优化

资源管理介绍 资源管理方式 命令式对象管理&#xff1a;直接用命令去操作kubernetes资源 命令式对象配置&#xff1a;通过命令配置和配置文件去操作kubernets资源 声明式对象配置&#xff1a;通过apply命令和配置文件去操作kubernets资源 命令式对象管理&#xff1a; 资源类…

Linux驱动---ADC驱动

文章目录 一、电路图二、将ADC标准驱动选配到内核三、修改设备树文件四、实验现象 一、电路图 由电路图可知&#xff0c;两个电路测量分别通过ANA0和ANA1两个ADC通道完成 查看芯片手册可知&#xff0c;ANA0可作为ADC1的通道0和通道1&#xff0c;或者ADC2的通道0和通道1. ANA1…

如何在 ONLYOFFICE 文档中,将插件添加到右侧面板

通过自定义工具&#xff0c;可以提高您的工作效率。最新更新后&#xff0c;ONLYOFFICE 插件提供了更大的灵活性。在上一篇文章中&#xff0c;我们演示了如何将插件显示为选项卡。您也可以将插件面板放置在编辑器的左侧或右侧。在这篇文章中&#xff0c;我们将深入探讨此功能&am…

选型工单管理系统,从原理到应用全面解读

工单管理系统提升客户支持效率&#xff0c;优化内部协作&#xff0c;强化数据分析。选型需明确需求&#xff0c;比较系统功能和特性&#xff0c;评估试用后选择最适合的系统。ZohoDesk凭其多渠道支持、智能分配、自动化工具、协作工具和数据分析能力&#xff0c;成为企业优选。…

C语言 | Leetcode C语言题解之第449题序列化和反序列化二叉搜索树

题目&#xff1a; 题解&#xff1a; #define MAX_NODE_SIZE 10000void postOrder(struct TreeNode *root, int *arr, int *pos) {if (root NULL) {return;}postOrder(root->left, arr, pos);postOrder(root->right, arr, pos);arr[(*pos)] root->val; }struct Tree…

界面控件DevExpress中文教程 - 如何拓展具有AI功能的文本编辑器(一)

本文重点介绍了DevExpress在近年来最热门领域——人工智能(AI)和自然语言处理(NLP)的改进&#xff01; NLP是人工智能的一个分支&#xff0c;它允许计算机与人类语言进行交互&#xff0c;这包括以有意义/有用的方式理解、解释、生成和回应文本(和语音)的能力。基于NLP的功能允…

ESP32-C3实现GPIO输入-判断高低电平

在 ESP32-C3 上实现 GPIO 输入并判断电平状态相对简单。以下是如何在 Arduino IDE 中配置 GPIO 作为输入&#xff0c;并在循环中检查电平状态的步骤&#xff1a; 1. 定义 GPIO 管脚 首先&#xff0c;定义你将要使用的 GPIO 管脚号。 #define GPIO_INPUT_PIN 2 // 定义一个 GP…

DAMA数据管理知识体系(第13章 数据质量)

课本内容 13.1 引言 语境图 图13-1 语境关系图&#xff1a;数据质量业务驱动因素 1&#xff09;提高组织数据价值和数据利用的机会。2&#xff09;降低低质量数据导致的风险和成本。3&#xff09;提高组织效率和生产力。4&#xff09;保护和提高组织的声誉。 提机会、降成本、增…

django(三):创建第一个django的app和url的两种获取参数的方式

一.创建第一个django的app 1.1 在终端根目录下执行命令 ## 创建一个app python manage.py startapp <app名称>例&#xff1a;python manage.py startapp book1.2创建成功后生成文件如下 二.url两种获取参数的方式 book/views.py from django.shortcuts import …

HTB:Markup[WriteUP]

目录 连接至HTB服务器并启动靶机 1.What version of Apache is running on the targets port 80? 2.What username:password combination logs in successfully? 使用Yakit并使用TOP1000字典对密码进行爆破 3.What is the word at the top of the page that accepts use…

二叉搜索树(BST)简单讲解

概念&#xff1a; 二叉搜索树是一棵二叉树或者空树&#xff0c;又名二叉排序树&#xff0c;英文简写为 BST &#xff08;Binary Search Tree&#xff09; 性质&#xff1a; 若它的左子树不为空&#xff0c;则左子树上所有节点的值都小于根节点的值若它的右子树不为空&#xf…

使用C++写一个自己定义的图像格式,写入磁盘

看到OpenCV的Image类实例一副图像&#xff0c;觉得挺好玩&#xff0c;因此想自己定义一个自己的图像类&#xff0c;让后完成写盘&#xff0c;并且读取出来。没有办法&#xff0c;再利用一下OpenCV的imshow显示一下&#xff0c;看看和自己的预期是否一样。 首先要先定义一个图像…

养猫家庭有什么宠物空气净化器推荐吗?哪款吸毛效果最好?

不知道你们家的猫最近有没有大量掉毛&#xff1f;还是今早穿短袖感觉到有点冷&#xff0c;我才意识到秋天到了&#xff0c;新一轮的换毛季又来了。不仅和猫咪玩耍的时候可以“采摘”不少毛毛&#xff0c;而且家里的衣服上、地板上也被毛发入侵&#xff0c;感觉用不了多久&#…

Python基础之List列表用法

1、创建列表 names ["张三","李四","王五","Mary"] 2、列表分片 names[1]&#xff1a;获取数组的第2个元素。 names[1:3]&#xff1a;获取数组的第2、第3个元素。包含左侧&#xff0c;不包含右侧。 names[:3]等同于names[0:3]&…

DAY3 JAVA基本语法

了解注释 注释是写在程序中对代码进行解释说明的文字,方便自己和其他人查看,以便理解程序的。 注释不影响程序的运行,编译后的class文件夹没有内容 字面量 在Java中,字面量(literal)是用来表示源代码中常量值的符号。 这些字面量可以直接出现在Java源代码中,并且它们代…

搜狗翻译体验,2024四大翻译工具解析!

为了满足广大用户的需求&#xff0c;市面上涌现出了众多优秀的翻译工具&#xff0c;福昕在线翻译、福昕翻译客户端、海鲸AI翻译、搜狗翻译等。今天&#xff0c;我们就来对比一下这些翻译工具&#xff0c;看看它们各自的特点和优势。 福昕在线翻译&#xff1a;专业精准&#xf…

前端初识之一

网页 什么是网页 网站是指在因特网上根据一定的规则&#xff0c;使用 HTML等制作的用于展示特定内容相关的网页集合。 网页是网站中的一“页”&#xff0c;通常是HTML格式的文件&#xff0c;它要通过浏览器来阅读&#xff0c; 网页是构成网站的基本元素&#xff0c;它通常由…