IPv4 协议转发实验报告
一、
实验目的
通过前面的实验,我们已经深入了解了 IPv4 协议的分组接收和发送处理流程。本实验
需要将实验模块的角色定位从通信两端的主机转移到作为中间节点的路由器上,在 IPv4 分
组收发处理的基础上,实现分组的路由转发功能。
网络层协议最为关注的是如何将 IPv4 分组从源主机通过网络送达目的主机,这个任务
就是由路由器中的 IPv4 协议模块所承担。路由器根据自身所获得的路由信息,将收到的 IPv4
分组转发给正确的下一跳路由器。如此逐跳地对分组进行转发,直至该分组抵达目的主机。
IPv4 分组转发是路由器最为重要的功能。
本实验设计模拟实现路由器中的 IPv4 协议,可以在原有 IPv4 分组收发实验的基础上,
增加 IPv4 分组的转发功能。对网络的观察视角由主机转移到路由器中,了解路由器是如何
为分组选择路由,并逐跳地将分组发送到目的主机。本实验中也会初步接触路由表这一重要
的数据结构,认识路由器是如何根据路由表对分组进行转发的。
二、
实验要求
在前面 IPv4 分组收发实验的基础上,增加分组转发功能。具体来说,对于每一个到达
本机的 IPv4 分组,根据其目的 IPv4 地址决定分组的处理行为,对该分组进行如下的几类操
作:
1) 向上层协议上交目的地址为本机地址的分组;
2) 根据路由查找结果,丢弃查不到路由的分组;
3) 根据路由查找结果,向相应接口转发不是本机接收的分组。
三、
实验内容
实验内容主要包括:
1) 设计路由表数据结构。
设计路由表所采用的数据结构。要求能够根据目的 IPv4 地址来确定分组处理行为(转
发情况下需获得下一跳的 IPv4 地址)。
2) IPv4 分组的接收和发送。
对前面实验(IP 实验)中所完成的代码进行修改,在路由器协议栈的 IPv4 模块中能够
正确完成分组的接收和发送处理。
3) IPv4 分组的转发。
对于需要转发的分组进行处理,获得下一跳的 IP 地址,然后调用发送接口函数做进一
步处理。
四、
实验结果及讨论
实验代码见附录,结果如下图所示。
由于上一个实验的错误经验,本实验中修改了校验和的产生过程,实验十分顺利。不过,
对于 TTL 的检验,发现不管是 0 的时候丢弃还是 1 的时候丢弃,实验结果都正确,应该是
实验系统没有考虑到检验这一点,经过与老师讨论,得出结论是,收到的一个 IP 包如果是
要转发的,则 TTL=1 时要丢弃。
通过本次实验,我对于路由器的路由和转发过程有了更加深刻的理解。
附录:
/*
* THIS FILE IS FOR IP FORWARD TEST
*/
#include "sysInclude.h"
#include
using namespace std;
// system support
extern void fwd_LocalRcv(char *pBuffer, int length);
extern void fwd_SendtoLower(char *pBuffer, int length, unsigned int nexthop);
extern void fwd_DiscardPkt(char *pBuffer, int type);
extern unsigned int getIpv4Address( );
// implemented by students
/*
typedef struct stud_route_msg
{
unsigned int dest;
unsigned int masklen;
unsigned int nexthop;
} stud_route_msg;
*/
struct rt_tb
{
//路由表
unsigned int dst;
unsigned int masklen;
unsigned int nexthop;
};
vector router;
void stud_Route_Init()
{
router.clear();
return;
}
//初始化清空路由表
void stud_route_add(stud_route_msg *proute)
{
rt_tb nrt;
nrt.dst = ntohl(proute->dest) & ((1 << 31) >> (ntohl(proute->masklen)-1));
nrt.masklen = ntohl(proute->masklen);
nrt.nexthop = ntohl(proute->nexthop);
router.push_back(nrt);
return;
}
int stud_fwd_deal(char *pBuffer, int length)
{
//int version = pBuffer[0] >> 4;
int IHL = pBuffer[0] & 0x0f;
int TTL = (unsigned int)pBuffer[8];
//int header_checksum = ntohs(*(unsigned short int*)(pBuffer + 10));
int des_add = ntohl(*(unsigned int*)(pBuffer + 16));
if(des_add == getIpv4Address())
{
//destination 地址和本机地址相同
fwd_LocalRcv(pBuffer, length);
return 0;
}
if (TTL == 1)
{
//TTL 等于 1 时丢弃该包
fwd_DiscardPkt(pBuffer, STUD_FORWARD_TEST_TTLERROR);
return 1;
}
vector::iterator it;
bool match = 0;
unsigned int max_matchlen = 0;
vector::iterator find;
for(it = router.begin(); it != router.end(); it++)
{
if(it->masklen > max_matchlen && it->dst == (des_add & ((1 << 31) >> (it->masklen -
find = it;
match = true;
max_matchlen = it->masklen;
1))))
{
}
}
if(match)
{
char* send = new char[length];
memcpy(send, pBuffer,length);
send[8]--;
send[10] = 0;
//TTL-1
send[11] = 0;
unsigned int sum = 0;
for(int i = 0; i < 2 * IHL; i++)
{
sum += *(unsigned short int*)(send + i * 2);
sum = (sum >> 16) + (sum & 0xffff);
}
sum = (sum >> 16) + (sum & 0xffff);
unsigned short int check_sum = 0xffff - (unsigned short int)sum;
memcpy(send + 10, &check_sum, sizeof(unsigned short int));
fwd_SendtoLower(send, length, find->nexthop);
return 0;
}
else
{
fwd_DiscardPkt(pBuffer, STUD_FORWARD_TEST_NOROUTE);
return 1;
}
return 1;
}