不落辰

知不可乎骤得,托遗响于悲风

0%

计算机网络-CS144-lab6

build a Router based on Network Interface

  • 在Network Interface的基础上实现一个Router
    • 功能 : 根据 forwarding table (<ip_prefix - interface(port)>). 将来自ip的分组从正确的网卡接口转发出去.
    • 匹配规则 : 最长前缀匹配
    • 注意entry中需要记录next_hop_ip
  • 我们的Router只实现了数据平面(转发),并没有实现控制平面(路由选择)
    • 控制平面的路由选择算法有 LS , DV , RIP , OSPF. 详情见《自顶向下》

背景

  • 本周在NetworkInterface之上实现一个IP Router. IP Router的任务是根据routing table转发. 对于收到的dgram,router有一系列规则

    • 转发到正确的interface
    • 获知下一跳的IP地址(为了使得Router将其传递给NetWork Interface , NetWork Interface根据ip获取下一跳的mac地址)
  • 概述图

我们的任务是 实现一个router. 去解决上述两个事情.

  • 我们只实现了router的数据平面 , 并没有实现router的控制平面.
  • 也即我们只实现了根据router的forwarding table,并没有实现生成forwarding_table的routing algorithm路由选择算法
    • You will not need to implement the algorithms that make the routing table, e.g. RIP, OSPF,BGP, or an SDN controller—just the algorithm that follows the routing table.
  • IP router不必关系任何有关TCP,ARP,Ethernet协议字段的任何东西. 只关心IP协议字段即可.

接口

  • Router class 应该负责
    • 维护forwarding table
    • Router负责处理收到的网络层的datagram. 对于每个datagram
      • 正确的发到下一跳
      • 转发到正确的NetworkInterface
  • 重要成员 forwarding_table的entry
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    struct RouterEntry{
    const uint32_t route_prefix; // ip
    const uint8_t prefix_length; // ip_perfix_len
    const std::optional<Address> next_hop; // 下一跳的ip地址
    const size_t interface_num; // 从哪个网卡转发出去 编号
    RouterEntry(const uint32_t ip , const uint8_t prefix , const std::optional<Address> ne , const size_t interface_idx):
    route_prefix(ip),prefix_length(prefix),next_hop(ne),interface_num(interface_idx)
    {}
    };
    std::vector<RouterEntry> _forwarding_table{};

    一来开始以为 既然我们的router只需要维护forwarding table并转发到正确的Interface. 因此forwarding table的entry并不需要记录next_hop_ip。只需要记录 <ip_perfix , interface>. 但由于之后forwarding_table要调用interface接口进行发送.为了使得interface可以获取到mac地址,需要传递给下一跳的ip地址, 故forwarding table的entry中还需要记录next_hop_ip
  • void add_route(const uint32_t route_prefix, const uint8_t prefix_length, const optional< Address > next_hop, const size_t interface_num);
    • 保存一条 {ip_perfix,network_interface}到forwarding_table中
  • void route_one_datagram(InternetDatagram &dgram);
    • “match-action” rule :
      • 依据我们在《自顶向下》中所学,router应当对收到的dgram执行 匹配加动作 规则。而传统路由器的动作就是根据目的地转发. 也即本lab中实现的 匹配加转发
      • 匹配 : 将dgram中的ip和forwarding_table中的ip进行 最长前缀匹配
      • 动作 : 转发
        • 如果router和dst ip在同一网络中(If the router is directly attached to the network in question) , 那么forwarding_table中的entry记录的next_hop_ip为empty, router传递给network_interface的next_hop_ip为dgram_dst_ip
        • 如果router和dst ip不在同一网络中(But if the router is connected to the network in question through some other router) , 那么entry中会记录路径上的下一跳ip地址(应该是个router ip)
    • 步骤如下 , 根据forwarding_table找到最长前缀匹配的entry
      • 没找到 , drop the dgram
      • 找到 , dgram TTL –.
        • 如果TTL已经 <= 0 则 drop the dgram
        • 否则 , 将dgram转发给正确的interface , 由interface将其封装成frame发送出去.
  • void Router::route()

    • (Linker) 从network interface取出dgrams , (Internet) 调用route_one_datagram(dgram) , (Linker) 进而转发到正确的network interface 发送出去
    • Linker -> Internet -> Linker
  • 网络协议巧妙设计 : 分层. router只关注网络层.

    • Router不必关注frame中封装的TCP 还是ARP ,也不必关注link layer frame类型.
    • Router只需要关注 网络层的Internet datagram , 然后通过NetworkInterface 来和 链路层link layer进行交互
    • When it comes to questions like, “How are link-layer addresses resolved?” or “Does the link layer even have its own addressing scheme distinct from IP?” or “What’s the format of the link-layer frames?” or “What’s the meaning of the datagram’s payload?”, the router just doesn’t care.
  • 代码略 简单

  • ques : 如果router drop dgram : 没有找到对应entry , 或者ttl = 0 . 是否需要发送icmp 报文给源主机 ?

    • 在真实生活中 , router需要发哦是那个icmp给源主机 . 但lab中这不是必需的.即便在真实生活中 , 不是所有router都需要发送icmp报文给源地址的.

测试

  • 测试原理. test code中的NetWork 模拟的就是下图交互情况. NetWork中的_router就是图中中间的路由器
  • apleasure to cherry

  • app to internet

    1
    2
    3
    4
    5
    6
    7
    cout << green << "\n\nSuccess! Testing applesauce sending to the Internet." << normal << "\n\n";
    {
    auto dgram_sent = network.host("applesauce").send_to({"1.2.3.4"});
    dgram_sent.header().ttl--;
    network.host("default_router").expect(dgram_sent);
    network.simulate();
    }
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    cout << green << "\n\nSuccess! Testing sending to the HS network and Internet." << normal << "\n\n";
    {
    auto dgram_sent = network.host("applesauce").send_to({"143.195.131.17"});
    dgram_sent.header().ttl--;
    network.host("hs_router").expect(dgram_sent);
    network.simulate();

    dgram_sent = network.host("cherrypie").send_to({"143.195.193.52"});
    dgram_sent.header().ttl--;
    network.host("hs_router").expect(dgram_sent);
    network.simulate();

    dgram_sent = network.host("cherrypie").send_to({"143.195.223.255"});
    dgram_sent.header().ttl--;
    network.host("hs_router").expect(dgram_sent);
    network.simulate();

    dgram_sent = network.host("cherrypie").send_to({"143.195.224.0"});
    dgram_sent.header().ttl--;
    network.host("default_router").expect(dgram_sent);
    network.simulate();
    }
  • 同一LAN

    1
    2
    3
    4
    auto dgram_sent = network.host("dm42").send_to(network.host("dm43").address());
    dgram_sent.header().ttl--;
    network.host("dm43").expect(dgram_sent);
    network.simulate();