RIP实验报告(转载自百度文库)

2017-11-24  本文已影响177人  张慕晖

原文地址:https://wenku.baidu.com/view/9ef65744fad6195f312ba65d.html

一、 实验目的

通过简单实现路由协议RIP,深入理解计算机网络中的核心技术——路由技术,并了解计算机网络的路由转发原理。

二、 实验要求

  1. RIP报文有效性检查
  2. 处理Request报文
  3. 处理Response报文
  4. 路由表项超时删除
  5. 路由表项定时发送

三、 实验接口

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函数,此函数应该实现如下功能:

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;
        }
    }
}
上一篇下一篇

猜你喜欢

热点阅读