NS3-虚拟网络与物理网络的交互-3Netmap和DPDK网络设备
 
目录
- 1. Netmap NetDevice
 - 1.1 概述
 - 1.2 设计
 - 1.2.1 设计思路
 - 1.2.2 初始化阶段
 - 1.2.3 线程功能
 - 1.2.4 读写方法实现
 - 1.2.5 队列控制与流量管理
 - 1.2.6 性能优化
 
- 2. DPDK NetDevice
 - 2.1 模型描述
 - 2.1.1 设计
 - 1. 初始化
 - 2. 数据包传输
 - 3. 终止
 
- 2.2 DPDK 安装
 - 1. 检查 NIC 支持性
 - 2. 替代方案:虚拟机配置
 - 3. 安装方式
 - 方式一:Ubuntu 包安装
 - 方式二:源码编译
 
- 4. 加载 DPDK 驱动
 - 5. 配置大页内存
 
- 2.3 使用指南
 - 1. 验证 DPDK 支持
 - 2. 配置示例
 - 3. 核心属性
 - 4. 示例程序
 
- 2.5 限制与扩展方向
 
1. Netmap NetDevice
fd-net-device 模块提供了 NetmapNetDevice 类,该类派生自 FdNetDevice,能够使用 netmap 文件描述符读写流量。此 netmap 文件描述符必须与主机中的真实以太网设备关联。NetmapNetDeviceHelper 类支持对 NetmapNetDevice 的配置。
1.1 概述
Netmap 是一种快速数据包处理功能,它绕过了 Host 网络堆栈并获得对网络设备的直接访问。 netmap 由 Luigi Rizzo [Rizzo2012] 开发,并维护为 GitHub 上的 https://github.com/luigirizzo/netmap 上的开源项目。
用于 ns-3 [Imputato2019] 由 Pasquale Imputato 在 2017-19 年开发。使用 NetmapNetDevice 需要 Host System 支持 NetMap(为了获得最佳性能,驱动程序 必须支持 NetMap,并且必须使用支持 NetMap 的设备驱动程序)。用户 可以预期使用 Netmap 的仿真比使用 FdNetDevice 和原始套接字(将 通过 Linux 网络内核)的仿真,将支持更高的数据包 。
1.2 设计
1.2.1 设计思路
- 继承与扩展: 
- 基于 
FdNetDevice实现NetmapNetDevice,利用文件描述符(FD)机制与真实设备交互。 - 需定制专用于 netmap 的操作:初始化(切换 NIC 至 netmap 模式)和 读写方法(通过 netmap API 协调数据包与环的交互)。
 
 - 基于 
 
1.2.2 初始化阶段
- 模式切换: 
- 将网络设备切换至 netmap 模式,使 ns-3 可通过 netmap 环直接读写真实设备的收发数据。
 
 - 线程启动: 
- 读线程:独立运行,监视 netmap 接收环中的新数据包,触发接收事件。
 - 同步线程(Sync Thread):专用于周期同步 netmap 环状态,支持流量控制与 BQL 通知。
 
 
1.2.3 线程功能
- 读线程: 
- 从 netmap 接收环提取新数据包,传递至 ns-3 协议栈处理。
 - 读取完成后,同步接收环以释放已处理数据包的槽位。
 
 - 同步线程: 
- 周期同步:通过 
TXSYNCioctl 请求,将 netmap 发送环中的待发数据包传输至:- 原生模式:直接推送至 NIC 发送环。
 - 通用模式:提交至已安装的 qdisc(队列规则)。
 
 - 队列管理: 
- 若发送环空间不足导致队列暂停,当空闲槽位超过阈值时,重启队列并唤醒 ns-3 qdisc。
 
 - BQL 支持:向字节队列限制(BQL)库通知已传输至 NIC 的字节量。
 
 - 周期同步:通过 
 
1.2.4 读写方法实现
- 写方法: 
- 将上层(ns-3 流量控制层)下发的数据包写入 netmap 发送环的空闲槽位。
 - 空间检查:若发送环剩余空间不足,立即暂停队列,阻止 ns-3 继续下发数据包。
 
 - 读方法: 
- 由读线程调用,负责提取接收环数据包并触发协议栈处理。
 
 
1.2.5 队列控制与流量管理
- 队列暂停与重启: 
- 暂停条件:发送环空间不足时主动暂停队列。
 - 重启条件:同步线程检测到发送环空闲槽位恢复至阈值以上时,自动重启队列。
 
 - BQL 集成: 
- 写方法:通知 BQL 已写入发送环的字节量。
 - 同步线程:通知 BQL 已从发送环移除并传输至 NIC 的字节量。
 
 
1.2.6 性能优化
- 减少系统调用:通过同步线程周期批量处理 netmap 环同步,避免频繁系统调用开销。
 - 零拷贝机制:直接操作 netmap 环的槽位,减少数据包在内核与用户空间间的复制。
 
通过上述设计,NetmapNetDevice 实现了高效、低延迟的物理网络设备模拟,同时兼容 ns-3 流量控制与 Linux 内核特性(如 BQL)。
2. DPDK NetDevice
数据平面开发套件(DPDK) 是由 Linux 基金会托管的库,旨在加速数据包处理任务(官网链接)。
DpdkNetDevice 类实现了基于 DPDK 的网络设备,绕过内核直接使用 DPDK 的高速数据包处理能力。该类位于 src/fd-net-device 模块中,继承自 FdNetDevice,并重写了 ns-3 与 DPDK 环境交互所需的函数。
2.1 模型描述
DpdkNetDevice 提供网络仿真能力,允许模拟节点与真实主机交互。其核心功能是通过 DPDK 的 环境抽象层(EAL) 实现高速数据包处理。EAL 隐藏设备细节,为应用提供与网卡(NIC)直接交互的接口,使 ns-3 可绕过内核直接收发数据包。
2.1.1 设计
DpdkNetDevice 作为 ns-3 与 DPDK 的桥梁,生命周期分为三个阶段:
1. 初始化
- 责任方:
DpdkNetDeviceHelper模型。 - 步骤: 
- 初始化 EAL。
 - 分配内存池(mempool)。
 - 获取并初始化网卡端口。
 - 设置端口的接收(Rx)和发送(Tx)队列。
 - 调用 
LaunchCore启动HandleRx方法,批量读取数据包。 
 
2. 数据包传输
- 数据格式转换: 
- DPDK 使用 
mbuf结构体,ns-3 使用原始缓冲区。 
 - DPDK 使用 
 - 读操作: 
HandleRx从 NIC 的 Rx 环批量读取mbuf,转换为 ns-3 缓冲区后传递至协议栈。
 - 写操作: 
- 将 ns-3 缓冲区转换为 
mbuf存入 Tx 缓冲区。 - 批量发送:当 Tx 缓冲区满时,将数据包传输至 NIC 的 Tx 环。
 - 超时刷新:若 Tx 缓冲区未满,默认 2ms 后手动刷新残留 
mbuf。 
 - 将 ns-3 缓冲区转换为 
 
3. 终止
- 停止 Rx 轮询。
 - 释放分配的 
mbuf和内存池。 - 关闭网卡端口。
 
2.2 DPDK 安装
1. 检查 NIC 支持性
- 查看 DPDK 支持的设备列表。
 
2. 替代方案:虚拟机配置
- 环境:Oracle VM VirtualBox + Ubuntu。
 - 网卡配置: 
- 桥接模式(Bridged Adapter)。
 - 适配器类型:支持 DPDK 的 NIC(如 Intel PRO/1000 MT Server)。
 - 混杂模式:允许所有。
 
 
3. 安装方式
方式一:Ubuntu 包安装
apt-get install dpdk dpdk-dev libdpdk-dev dpdk-igb-uio-dkms
 
- 版本要求:Ubuntu 20.04(默认 DPDK v19.11 LTS)。
 
方式二:源码编译
- 下载源码:从 DPDK 下载页 获取 v19.11 LTS。
 - 配置为共享库:编辑 
config/common_base,设置:CONFIG_RTE_BUILD_SHARED_LIB=y - 编译安装:
make install T=x86_64-native-linuxapp-gcc DESTDIR=install - 设置环境变量:
export RTE_SDK=/path/to/dpdk-source export RTE_TARGET=x86_64-native-linuxapp-gcc 
4. 加载 DPDK 驱动
sudo modprobe uio_pci_generic uio vfio-pci
sudo modprobe igb_uio       # Ubuntu 包安装
sudo insmod $RTE_SDK/$RTE_TARGET/kmod/igb_uio.ko  # 源码编译
 
5. 配置大页内存
- 运行时分配:
echo 256 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages - 启动时分配:编辑 
/etc/default/grub,添加:hugepages=256 - 挂载大页文件系统:
sudo mkdir /mnt/huge sudo mount -t hugetlbfs nodev /mnt/huge 
2.3 使用指南
1. 验证 DPDK 支持
运行 ./ns3 configure,若输出包含 DPDK NetDevice : enabled 表示支持。
 DPDK网络拓扑示例:
 
2. 配置示例
DpdkNetDeviceHelper* dpdk = new DpdkNetDeviceHelper();
dpdk->SetPmdLibrary("librte_pmd_e1000.so");  // 设置 PMD 驱动库
dpdk->SetDpdkDriver("igb_uio");              // 设置 DPDK 驱动类型
 
3. 核心属性
| 属性名 | 描述 | 默认值 | 适用场景 | 
|---|---|---|---|
TxTimeout | Tx 缓冲区刷新超时(微秒) | 2000 | 低流量场景可调低 | 
MaxRxBurst | Rx 批量大小 | 64 | 高流量可增大 | 
MaxTxBurst | Tx 批量大小 | 64 | 高流量可增大 | 
MempoolCacheSize | 内存池缓存大小 | 256 | 高流量可增大 | 
NbRxDesc | Rx 描述符数量 | 1024 | 高流量可增大 | 
NbTxDesc | Tx 描述符数量 | 1024 | 高流量可增大 | 
4. 示例程序
fd-emu-ping.cc:通过 DPDK 发送 ICMP 流量,绕过内核。fd-emu-onoff.cc:利用 DPDK 高速处理能力,测量 TCP/UDP 吞吐量。
2.5 限制与扩展方向
- 当前限制: 
- 仅支持单 NIC 单 Rx/Tx 队列。
 - 不支持巨型帧(Jumbo Frames)。
 - 无流量控制或 qdisc 支持。
 
 - 未来扩展: 
- 多 NIC 与多队列支持。
 - 添加卸载(Offloading)和调度功能。
 
 
