type
status
slug
summary
tags
category
icon
password
new update day
Property
Oct 22, 2023 01:31 PM
created days
Last edited time
Oct 22, 2023 01:31 PM

类头文件简介

网络接口这个类,涉及到数据包发送(send_datagram)、数据包收取(recv_frame)、时间控制(tick
、尝试发送(maybe_send)、查看 arp 缓存并发送数据包(check_arp_send_frame)这些方法,其中 check_arp_send_frame 是私有工具方法,是我添加到里面辅助处理数据的,具体的定义可以看下面的 .hh 文件。
其中在类 NetworkInterface 中定义了两个私有类 ArpTableEntryArpWaitingEntry ,分别用来表示 arp 表中的一条条目,以及已经发送 arp 请求但是还没有收到对应的回复信息的 ARP 条目。
  • ethernet_address_
    • 该接口的网络地址
  • ip_address_
    • 该接口的 IP 地址
  • arp_table_
    • std::unordered_map<uint32_t, ArpTableEntry> arp_table_
    • arp 缓存表
    • key:ip地址对应的 int 值
    • value:ArpTableEntry
      • time_ticks_
        • 时钟数
        • ip 地址对应的 int 数值
  • waiting_for_arp_queue_
    • std::unordered_map<uint32_t, std::queue<std::shared_ptr<EthernetFrame>>> waiting_for_arp_queue_
    • key:ip地址对应的 int 值
    • value:对应 ip 地址的 arp 请求队列,保存的是对应的以太网请求帧的智能指针。
  • waiting_for_ack_arp_
    • std::unordered_map<uint32_t, std::shared_ptr<ArpWaitingEntry>> waiting_for_ack_arp_
    • key:ip地址对应的 int 值
    • value:已经发送 arp 请求包等待回应的 ArpWaitingEntry
      • time_ticks_
        • 时钟数
      • std::shared_ptr<EthernetFrame> frame_;
        • 发送的以太网帧
  • ethernet_queue_
    • std::queue<std::shared_ptr<EthernetFrame>>
    • 队列内部是排队需要发送的以太网帧
  • arp_entry_timeout_
    • arp 条目默认超时时间:30000
  • arp_request_timeout_
    • arp 以太网请求包超时时间:5000
network_interface.hh

方法简介

send_datagram

方法函数原型如下,即上层应用程序给我一个 IP 数据报文,和报文需要发送到的下一跳地址,我们需要将其发送到对应的地址上去:
算法流程
  • 查看 arp_table_ 是否存在对应 ip 的以太网 mac 地址
  • 查看 waiting_for_ack_arp_ 是否存在已经发送过的对应 ip 地址的 arp 请求包。
  • 如果 两者都不存在
    • 新建一个以太网帧智能指针对象
      • arp 广播请求包
    • 放入到网络接口发送队列 ethernet_queue_
    • 更新 waiting_for_ack_arp_ 对 arp 请求报文进行追踪
  • 如果 arp 请求包已经发送
    • 新建一个以太网帧
    • 如果 arp 条目存在
      • 将以太网帧设置为对应目标的 mac 地址
    • 否则
      • 将目标地址设置为广播地址
    • 解析 ip 数据报内容,设置对应的类型与 payload 信息
    • 如果 arp 条目存在
      • 直接放入发送队列
    • 否则
      • 将对应的帧放入对应 ip 的 arp 等待队列中(都是需要向这个 ip 发送的数据帧)

recv_frame

方法函数原型如下:即在一个以太网帧到来的时候需要采取的动作
optional<InternetDatagram> NetworkInterface::recv_frame( const EthernetFrame& frame )
方法流程:
  • 如果目的地址不对,且不是广播地址
    • 返回空 optional<InternetDatagram>
  • 如果是 ARP 类型的帧
    • 解析 payload
    • 如果是请求帧
      • 如果目标 ip 地址是本机地址
      • 构建以太网 arp 回复帧,智能指针,准备将自己的 mac 地址返回
      • 压入接口的发送缓存队列
      • 调用 check_arp_send_frame 工具函数,检查是否需要更新对应的 arp 缓存项,或者是否有等待 arp 地址的以太网帧队列。
    • 如果是回复帧
      • 更新 arp 缓存表
      • 调用 check_arp_send_frame 工具函数,检查是否需要更新对应的 arp 缓存项,或者是否有等待 arp 地址的以太网帧队列。
  • 如果是 ipv4 类型的数据包
    • 直接解析数据帧,交付将 IP数据报交付上层
  • 如果是其他类型
    • 返回空 optional<InternetDatagram>

tick

函数原型为:用来更新自上次调用此方法以来的毫秒数,用来跟踪与更新数据包的时间,控制超时行为
void NetworkInterface::tick( const size_t ms_since_last_tick )
方法行为
  • 遍历 arp 缓存表,对应的缓存项目
    • 加上 ms_since_last_tick
    • 如果超时
      • 将对应的条目删除,并更新迭代器
    • 否则
      • 更新迭代器
  • 遍历 arp 请求缓存表
    • 加上 ms_since_last_tick
    • 如果超时
      • 将对应的条目删除,并更新迭代器
    • 否则
      • 更新迭代器
maybe_send
函数原型为:如果此网络接口的缓存队列中有数据,直接发送,如果没有就返回空
optional<EthernetFrame> NetworkInterface::maybe_send()

check_arp_send_frame

函数原型:此工具函数输入参数为 mac 地址和 ip 地址
void NetworkInterface::check_arp_send_frame( EthernetAddress& ethernet_address, uint32_t& ip_address )
函数逻辑:
  • 如果 arp 缓存表中包含对应的 ip 条目
    • 如果 arp 缓存表中的 mac 地址与传入的 mac 地址不一致
      • 更新 arp 缓存表
    • 如果等待 arp 确认缓存表中存在此 ip 地址的信息
      • 取消追踪
  • 如果不存在对应 ip 条目
    • 将对应的 ip 、mac 地址对加入到 arp 缓存表中
  • 如果等待 arp 确认的发送队列 waiting_for_arp_queue_ 不为空
    • 取出对应 ip 地址的智能指针队列
    • 遍历队列
      • 取出队列头
      • 如果数据帧的目的地址与 arp 缓存表中的地址不一样(肯定不一样,因为放入队列的时候是广播地址)
      • 更新目的 mac 地址
      • 放入发送缓存队列中
      • 删除队列头
    • 清除对某 ip 的 arp 等待 ack 队列追踪
CS144-2023-Spring router.cc 功能部分实现讲解[MIT 6.s081] Lab: Copy-on-Write Fork for xv6 实验记录