RIP实验报告(转载自百度文库)
2017-11-24 本文已影响177人
张慕晖
原文地址:https://wenku.baidu.com/view/9ef65744fad6195f312ba65d.html
一、 实验目的
通过简单实现路由协议RIP,深入理解计算机网络中的核心技术——路由技术,并了解计算机网络的路由转发原理。
二、 实验要求
- RIP报文有效性检查
- 处理Request报文
- 处理Response报文
- 路由表项超时删除
- 路由表项定时发送
三、 实验接口
1. RIP报文处理函数
int stud_rip_packet_recv(char *pBuffer, int bufferSize, UINT8 iNo, UINT32 srcAdd)
pBuffer:指向接收到的RIP报文内容的指针
bufferSize:接收到的RIP报文的长度
iNo:接收该报文的接口号
srcAdd:接收到的报文的源IP地址
2. RIP超时处理函数
void stud_rip_route_timeout(UINT32 destAdd, UINT32 mask, unsigned char msgType)
destAdd:路由超时消息中路由的目标地址
mask:路由超时消息中路由的掩码
msgType:消息类型,包括以下两种定义:
#define RIP_MSG_SEND_ROUTE
#define RIP_MSG_DELE_ROUTE
四、 实验基本框架
1. 当系统收到RIP报文时
当系统收到RIP报文时,会调用stud_rip_packet_recv函数,此函数应该实现如下功能:
- 对RIP报文进行合法性检查,若报文存在错误,则调用ip_DiscardPkt函数,并在type参数中传入错误编号。
- 对于Request报文,应该将根据本地的路由表信息组成Response报文,并通过rip_sendIpPkt函数发送出去。注意,由于实现水平分割,组Response报文时应该检查该Request报文的来源接口,Response报文中的路由信息不包括来自该来源接口的路由。
- 对于Response报文,应该提取出该报文中携带的路由信息,对于本地路由表中已存在的项要判断该条路由信息的metric值,若为16,则应置本地路由表中对应路由为无效,否则若更新表项的metric值小于路由表中相应表项metric值时就替代原来的表项。注意要将metric值加1。对于本地路由表中不存在的项,则将metric值加1后将该路由项加入本地路由表,注意,若metric值加1后为16说明路由已经失效,则不用添加。
2. RIP超时处理函数
RIP协议每隔30秒,重新广播一次路由信息,系统调用该函数并置msgType为RIP_MSG_SEND_ROUTE来进行路由信息广播。该函数应该在每个接口上分别广播自己的RIP路由信息,即通过rip_sendIpPkt 函数发送RIP Response报文。由于实现水平分割,报文中的路由信息不包括来自该接口的路由信息。
RIP协议每个路由表项都有相关的路由超时计时器,当路由超时计时器过期时,该路径就标记为失效的,但仍保存在路由表中,直到路由清空计时器过期才被清掉。当超时定时器被触发时,系统会调用该函数并置msgType为RIP_MSG_DELE_ROUTE,并通过destAdd和mask参数传入超时的路由项。该函数应该置本地路由的对应项为无效,即metric值置为16。
五、 源代码及注释
#include "sysinclude.h"
extern void rip_sendIpPkt(unsigned char *pData, UINT16 len,unsigned short dstPort,UINT8 iNo);
extern struct stud_rip_route_node *g_rip_route_table;//路由器表头
void sendTo(UINT8 iNo){//向iNo发送本地路由表表
int cnt = 0;
struct stud_rip_route_node* local_table = g_rip_route_table;//取路由表头
while (local_table != NULL) {
if (local_table->if_no != iNo)//水平分裂算法,不把路由项信息回传给发送者
cnt++;
local_table = local_table->next;
}
char* response_table = new char[4 + cnt * 20];//路由表,包括所有不来自请求者的路由表项
response_table[0] = 2;//标识为一个response
response_table[1] = 2;//版本号
response_table[2] = 0;//要求为0
response_table[3] = 0;//要求为0
local_table = g_rip_route_table;
for (int i = 0; i < cnt; i++)
{
while (local_table->if_no == iNo)//跳过来自请求方的路由项,不发送
local_table = local_table->next;
*(short *)(response_table + 4 + i * 20) = htons(2);//地址类字段,长度为2byte,RIP规定为2
*(short *)(response_table + 6 + i * 20) = htons(0);//IP地址字段,长度为2byte,置为0
*(unsigned int *)(response_table + 8 + i * 20) = htonl(local_table->dest);//长度为4byte,复制并转成网络字节序
*(unsigned int *)(response_table + 12 + i * 20) = htonl(local_table->mask);//长度为4byte,同上
*(unsigned int *)(response_table + 16 + i * 20) = htonl(local_table->nexthop);//长度为4byte,同上
*(unsigned int *)(response_table + 20 + i * 20) = htonl(local_table->metric);//长度为4byte,同上
local_table = local_table->next;
}
rip_sendIpPkt((unsigned char*)response_table, 4 + cnt * 20, 520, iNo);//发送分组
}
int stud_rip_packet_recv(char *pBuffer,int bufferSize,UINT8 iNo,UINT32 srcAdd)
{
if(*pBuffer == 1){////查看命令字段是request,处理请求
sendTo(iNo);
return 0;
}
if(*pBuffer == 2){// 查看命令字段,是response,更新本地路由信息
pBuffer = pBuffer + 4;//跳过RIP头
for (int i = 0; i < (bufferSize-4)/20 ;++i) {//发来的RIP分组的数量,依次检查每一个RIP分组
bool flag = false;//查找成功标志,若查找成功,置为true
struct stud_rip_route_node *local_table = g_rip_route_table;
while (local_table) {//遍历本地路由表,查找是否有当前位置一致的表项
if (local_table->dest == ntohl(*(unsigned int *)(pBuffer+4)) &&
local_table->mask == ntohl(*(unsigned int *)(pBuffer+8))) {//符合(即原路由表中已有),则修改本地路由表信息
flag = true;//查找成功
if (local_table->nexthop == srcAdd) {//已存在
local_table->metric = ntohl(*(unsigned int *)(pBuffer + 16)) + 1;//跳数加1
if (local_table->metric > 16)//大于16,则置成16(RIP最多只能支持16跳)
local_table->metric = 16;
local_table->if_no = iNo;
} else {//未存在
if (ntohl(*(unsigned int *)(pBuffer + 16)) < local_table->metric) {//需要更新
local_table->nexthop = srcAdd;
local_table->metric = ntohl(*(unsigned int *)(pBuffer+16)) + 1;//跳数加1
if (local_table->metric > 16)
local_table->metric = 16;
local_table->if_no = iNo;
}
}
}
local_table = local_table->next;
}
if (!flag) {//查找不成功,local_table到达本地路由表的尾端,增加新的表项
struct stud_rip_route_node *new_item = new struct stud_rip_route_node();
local_table = g_rip_route_table;
while (local_table->next)
local_table = local_table->next;
new_item->dest = ntohl(*(unsigned int *)(pBuffer + 4));
new_item->mask = ntohl(*(unsigned int *)(pBuffer + 8));
new_item->nexthop = srcAdd;
new_item->metric = ntohl(*(unsigned int *)(pBuffer + 16)) + 1;
new_item->next = NULL;
new_item->if_no = iNo;
if (new_item->metric < 16)//查看此表项是否有效,有效则添加
local_table->next = new_item;
}
pBuffer = pBuffer + 20;//移向下一位置
}
return 0;
}
}
void stud_rip_route_timeout(UINT32 destAdd, UINT32 mask, unsigned char msgType)
{
if (msgType == RIP_MSG_SEND_ROUTE){//定时发送
for(int i = 1; i <= 2; i ++)
sendTo(i);
}
else if(msgType == RIP_MSG_DELE_ROUTE) {//删除本地路由表中的超时路由项
stud_rip_route_node *local_table = g_rip_route_table;
while (local_table) {//遍历路由表
if (local_table->dest == destAdd && local_table->mask == mask)
local_table->metric = 16;//置为16,表示无效
local_table = local_table->next;
}
}
}