%# -*- coding: utf-8-unix -*- \section{三层路由器实现} \label{sec:c:router-ob:s:router} \subsection{实验目的} \label{subsec:c:router-ob:s:router_object} 本实验的主要目的是让学生掌握二层以太网帧、ARP协议和三层IP协议等的数据结构, 熟悉各协议的解析与封装过程, 掌握三层路由器的工作原理、分组处理流程、FIB表和邻接表生成与使用。 熟悉路由器数据平面与控制平面的切分及不同的工作处理流程。 \subsection{实验内容} \label{subsec:c:router-ob:s:router_content} 使用可编程网络平台及三层路由器示例框架源码, 设计完成一个三层路由器原型系统。主要完成以下内容: \begin{enumerate} \item \textbf{系统路由验证:}搭建测试环境, 验证系统自带三层路由原型系统的功能,实现不同网段主机的相互通信功能; \item \textbf{逻辑设计与实现:}基于路由器示例框架代码, 分别设计完成路由器的分组解析、FIB同步与查表、 二层与三层数据更新、ARP请求与响应等模块功能; \item \textbf{功能调试与验证:}根据路由器分组处理流程, 分别调试每一类分组的处理逻辑。如ARP请求类分组、 ARP响应类分组、控制平面分组和数据平面分组; 组网测试路由器功能,实现不同网段内主机之间的相互通信功能。 \end{enumerate} \subsection{实验原理、方法和手段} \label{subsec:c:router-ob:s:router_principle} \subsubsection{系统路由验证} 请参考附件《可编程网络平台-操作手册》完成。 \subsubsection{三层路由器工作原理} 三层路由器工作于OSI模型的第3层(网络层),根据网络层中的目的IP地址进行查表, 获得分组转发的下一跳输出端口及下一跳的IP地址。更新网络层的TTL值与CSUM值, 并在输出端口对二层数据进行重新封装二层数据后转发。 路由器还具备ARP响应与请求功能, 支持响应请求自己IP的MAC信息与请求路由下一跳IP的MAC信息。 \subsubsection{路由器分组处理流程} \begin{enumerate} \item \textbf{线程同步系统FIB表:}通过一个独立线程,读取内核FIB表信息, 保存到路由器的FIB表结构中;循环不断的获取内核FIB表, 一但有更新,则刷新自己的FIB表内容; \item \textbf{输入分组解析:}接收各端口输入分组信息,并进行分组解析处理, 根据MAC地址信息和目的IP地址信息判断分组为控制平面分组还是数据平面分组; \item \textbf{控制平面与数据平面分流:}将控制平面数据转发到协议栈进行处理, 将数据平台数据转发到路由器数据转发逻辑中处理。 若是本机MAC的ARP请求,则构造ARP响应进行回复; \item \textbf{提取目的IP并查表:}路由器数据转发逻辑进一步解析数据, 解析提取目的IP地址,送入FIB查表引擎进行匹配, 获取分组的下一跳IP地址及输出端口信息; \item \textbf{更新三层数据:}更新分组TTL值与CSUM值,根据FIB表结果, 将分组转发至对应端口输出队列; \item \textbf{更新二层数据:}更新FIB查表下一跳IP的MAC地址信息, 查表无结果,则启动ARP请求模块;若查到对应MAC信息,则更新二层数据后直接转发; \item \textbf{ARP请求:}根据请求的IP地址与发送端口信息构造ARP协议的请求报文, 发送到端口进行学习,并将学习结果保存到该端口的邻接表中; \item \textbf{端口队列输出:}抽取端口输出队列内的发送分组, 更新二层数据后由端口直接发送。 \end{enumerate} \subsection{实验条件} \label{subsec:c:router-ob:s:router_requirement} \begin{itemize} \item 可编程网络平台一个,路由测试主机两台, IP配置及连接拓扑如图\ref{fig:c:router-ob_router-topo}所示; \item 串口线一根,网线两根; \item 三层路由器框架源代码(开发环境与编译工具系统自带)。 \end{itemize} \begin{figure}[!ht] \centering \includegraphics[width=8cm]{router-topo} \caption{三层路由器实验拓扑图} \label{fig:c:router-ob_router-topo} \end{figure} \subsection{实验步骤} \label{subsec:c:router-ob:s:router_procedure} \subsubsection{系统路由验证} 1. 登录可编程网络平台,启动系统自带三层路由器命令, 系统输出如下信息说明已正常启动且进入工作模式; \begin{code}[console] root@HNXS-FAST:/mnt/openbox# l3router Port[0]->obx0,MAC->00:0A:35:01:00:5B,IPv4->192.168.0.1, IPv6->0000:0000:0000:0000:0000:0000:0000:0000 Port[1]->obx1,MAC->00:0A:35:00:00:02,IPv4->192.168.1.1, IPv6->0000:0000:0000:0000:0000:0000:0000:0000 Port[2]->obx2,MAC->00:0A:35:00:00:03,IPv4->192.168.2.1, IPv6->0000:0000:0000:0000:0000:0000:0000:0000 Port[3]->obx3,MAC->00:0A:35:00:00:04,IPv4->192.168.3.1, IPv6->0000:0000:0000:0000:0000:0000:0000:0000 Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT Port obx0 0000A8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 0 obx1 0001A8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 1 obx2 0002A8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 2 obx3 0003A8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 3 Create update_fib4_thread OK! Create handle_queue_packet on Port[0] thread OK! handle_queue_packet on port[0] handle_queue_packet[0]->Wait pkt INQUEUE... Create handle_queue_packet on Port[1] thread OK! handle_queue_packet on port[1] handle_queue_packet[1]->Wait pkt INQUEUE... Create handle_queue_packet on Port[2] thread OK! handle_queue_packet on port[2] handle_queue_packet[2]->Wait pkt INQUEUE... Create handle_queue_packet on Port[3] thread OK! handle_queue_packet on port[3] handle_queue_packet[3]->Wait pkt INQUEUE... fastU->REG Version:20180827,OpenBox HW Version:2030200722 FAST UA REG->from pid:907,state:21,mid:132 fastU->Register UA to FAST Kernel! Wait Reply...... fastU->UA->pid:907,mid:132,Register OK! fastU->libua version:20180827 fastU->fast_ua_recv...... \end{code} \subsubsection{设计开发三层路由器} \begin{enumerate} \item 阅读三层路由器框架源代码文件, 根据三层路由工作原理及分组处理流程设计完成框架源代码中的TODO部分内容; \item 编译自己的三层路由器源码,生成相应的路由器系统命令user\_l3router; \end{enumerate} \subsubsection{调试与验证} \begin{enumerate} \item 运行自己的三层路由器代码,验证路由器的功能; \item 路由器正常工作后,可以显示如下信息; \begin{itemize} \item 加载路由器接口地址信息 \begin{code}[text] Port[0]->obx0,MAC->00:0A:35:01:00:5B,IPv4->192.168.0.1, IPv6->0000:0000:0000:0000:0000:0000:0000:0000 Port[1]->obx1,MAC->00:0A:35:00:00:02,IPv4->192.168.1.1, IPv6->0000:0000:0000:0000:0000:0000:0000:0000 Port[2]->obx2,MAC->00:0A:35:00:00:03,IPv4->192.168.2.1, IPv6->0000:0000:0000:0000:0000:0000:0000:0000 Port[3]->obx3,MAC->00:0A:35:00:00:04,IPv4->192.168.3.1, IPv6->0000:0000:0000:0000:0000:0000:0000:0000 \end{code} \item 同步内核FIB表 \begin{code}[text] Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT Port obx0 0000A8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 0 obx1 0001A8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 1 obx2 0002A8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 2 obx3 0003A8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 3 \end{code} \item 启动端口输出队列线程 \begin{code}[text] Create handle_queue_packet on Port[0] thread OK! handle_queue_packet on port[0] handle_queue_packet[0]->Wait pkt INQUEUE... Create handle_queue_packet on Port[1] thread OK! handle_queue_packet on port[1] handle_queue_packet[1]->Wait pkt INQUEUE... Create handle_queue_packet on Port[2] thread OK! handle_queue_packet on port[2] handle_queue_packet[2]->Wait pkt INQUEUE... Create handle_queue_packet on Port[3] thread OK! handle_queue_packet on port[3] handle_queue_packet[3]->Wait pkt INQUEUE... \end{code} \item 开始接收分组处理 \begin{code}[text] fastU->REG Version:20180827,OpenBox HW Version:2030200722 FAST UA REG->from pid:923,state:21,mid:132 fastU->Register UA to FAST Kernel! Wait Reply...... fastU->UA->pid:923,mid:132,Register OK! fastU->libua version:20180827 fastU->fast_ua_recv...... \end{code} \item 控制平面分组处理 \begin{code}[text] UA Recv ptk 0xb2c00468,len:130,inport:0 Recv IPv4 Packet! Recv Unicast Host Packet,Dispatch Packet! Control Plane->Send to Protocol Stack[128]! \end{code} \item 数据平面分组处理 \begin{code}[text] UA Recv ptk 0xb2c00468,len:130,inport:2 Recv IPv4 Packet! Recv Unicast Host Packet,Dispatch Packet! Data Plane->FIB(dst:192.168.0.111) tblidx:0 Data Plane->Next Hop:192.168.0.111,outport:0 //查不到MAC,入队后学习MAC Data Plane->port[0],NEIGH[1],IN QUEUE[1] Data Plane->Active Thread on Port[0],QUEUE[1] len:2 //查询到MAC,直接封闭二层数据后发送 Data Plane->port[2],NEIGH[0],DMAC->B8:27:EB:C1:D1:39 Pack L2 on Port[2] pkt_send_normal->0xb2c00468,outport:2,len:130 \end{code} \item ARP请求处理 \begin{code}[text] send_arp_request 192.168.2.119 on Port[2] pkt_send_normal->0xb2b00468,outport:2,len:74 pkt_send_normal->0xb2b00468,outport:2,len:74 pkt_send_normal->0xb2b00468,outport:2,len:74 \end{code} \item ARP响应处理 \begin{code}[text] UA Recv ptk 0xb2c00468,len:92,inport:0 Recv ARP Packet! ARP->Host IPv4 ARP->Response,192.168.0.111[B8:27:EB:D8:83:20]--> 192.168.0.1[00:0A:35:01:00:5B] Learn SMAC Port[0],B8:27:EB:D8:83:20 Learn SMAC Port[0],NEIGH[0],Update[B8:27:EB:D8:83:20]! \end{code} \item 路由不可达 \begin{code}[text] ICMP Report and Drop! \end{code} \item FIB表刷新 \begin{code}[text] FIB4 fresh... \end{code} \end{itemize} \item 路由器工作不正确时,使用\texttt{xprintf}函数打印调试, 建议根据不同类别数据流进行打印分析,调试某一些报文时,其他无关内容均不打印; \item 在任意一台测试主机\texttt{ping 8.8.8.8}, 观察路由器分组处理流程及FIB表查找结果变化; \item 路由器正常工作后,复制保留程序输出日志信息。 \end{enumerate} \subsection{思考题} \label{subsec:c:router-ob:s:router_rethink} \begin{enumerate} \item 系统内核的FIB表是如何生成的?生成FIB表的路由协议有哪些,各适应哪些环境? \item 什么是静态路由表?什么是动态路由表? \item FIB表查表不命中如何处理? FIB表指示的下一跳IP的MAC地址不存在如何处理当前分组数据? \item 本程序采用单核单线程处理多个端口的数据转发,如何改成多核多线程方式? \end{enumerate} \subsection{注意事项及有关说明} \label{subsec:c:router-ob:s:router_notice} \begin{enumerate} \item 可编程网络平台的路由器只是一个基础的路由器原型, 分组处理方法与流程设计并不是规范,学生可根据自己理解创新实现; \item 控制平面的数据是通过平台开发环境重新导入到了系统内核处理, 目的是为了支持该系统上的其他正常SOCKET应用,如Quagga路由软件。 \end{enumerate} \subsection{考核方法} \label{subsec:c:router-ob:s:router_criterion} 完成本次实验,需要提交一份实验报告、一份程序源代码和一分程序输出日志。 程序源代码中用户添加的代码需要有详细的注释说明。 \begin{enumerate} \item (20分)在规定时间内完成实验,并提交实验成果; \item (40分)实验报告中有详细的路由逻辑设计分析与实现说明; \item (10分)程序正常运行,测试主机可以ping通或抓包接收到对端报文; \item (10分)ARP请求与响应功能正常工作; \item (10分)测试主机可以ping通路由器端口的IP地址; \item (10分)实验报告与源代码内容完整、格式整洁。 \end{enumerate}