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
中定义了两个私有类 ArpTableEntry
与 ArpWaitingEntry
,分别用来表示 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 队列追踪
- 作者:tangcuyu
- 链接:https://expoli.tech/articles/2023/08/12/CS144-2023-Spring-network_interface.cc-function-part-implementation-explanation
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章