IPv4转发实验

实验目的

本实验设计模拟实现路由器中的 IPv4 协议,可以在原有 IPv4 分组收发实验的基础上,增加 IPv4 分组的转发功能。对网络的观察视角由主机转移到路由器中,了解路由器是如何为分组选择路由,并逐跳地将分组发送到目的主机。本实验中也会初步接触路由表这一重要的数据结构,认识路由器是如何根据路由表对分组进行转发的。

实验要求

在前面 IPv4 分组收发实验的基础上,增加分组转发功能。具体来说,对于每一个到达本机的 IPv4 分组,根据其目的 IPv4 地址决定分组的处理行为,对该分组进行如下的几类操作:

1) 向上层协议上交目的地址为本机地址的分组;
2) 根据路由查找结果,丢弃查不到路由的分组;
3) 根据路由查找结果,向相应接口转发不是本机接收的分组。

实验内容

实验内容主要包括:

1) 设计路由表数据结构。
2) IPv4 分组的接收和发送。
3) IPv4 分组的转发。

实验过程

  1. 路由表维护
    需要完成下列分组接收处理步骤:
    1) stud_Route_Init()函数中,对路由表进行初始化。
    2) stud_route_add()函数中,完成路由的增加。
  2. 转发处理流程
    stud_fwd_deal()函数中,需要完成下列分组接收处理步骤:
    1) 查找路由表。根据相应路由表项的类型来确定下一步操作,错误分组调用函数 fwd_DiscardPkt()进行丢弃,上交分组调用接口函数 fwd_LocalRcv()提交给上层协议继续处理,转发分组进行转发处理。注意,转发分组还要从路由表项中获取下一跳的 IPv4 地址。
    2) 转发处理流程。对 IPv4 头部中的 TTL 字段减 1,重新计算校验和,然后调用下层接口 fwd_SendtoLower()进行发送处理。

实验源码

代码基于上次作业修改完成,故有较多注释

#include "sysInclude.h"
#include<vector>
#include <iostream>
// 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();
using namespace std;


typedef struct {
    unsigned int nexthop;
    unsigned dest;
} routeItem;


vector<routeItem> myroute;

int stud_fwd_deal(char * pBuffer, int length){
    printf("Check IP Version:\n");
    unsigned int version=(pBuffer[0]>>4);
    printf("IP Version is %d\n", version);
//    if(version!=4){
//        ip_DiscardPkt(pBuffer, STUD_IP_TEST_VERSION_ERROR);
//        return 1;
//    }

    printf("Check Header Length:\n");
    unsigned int len=(pBuffer[0]&0xF);
    printf("Header Length is %d\n", len);
//    if(len<5){
//        ip_DiscardPkt(pBuffer, STUD_IP_TEST_HEADLEN_ERROR);
//        return 1;
//    }



    printf("Check CheckSum:\n");
    unsigned int sum=0;

    for(int i=0;i<len*2;i++){
        sum+=((unsigned short*)pBuffer)[i];
        sum=(sum>>16)+(sum&0xffff);
    }
    cout<<sum<<endl<<~sum<<endl;
    //cout<<bitset<sizeof(short)*8>((unsigned short)sum)<<endl;
    //ut<<bitset<sizeof(short)*8>(~(unsigned short)sum)<<endl;
    printf("Check Sum is %d\n", ~sum);
    printf("CheckSUM is %d\n", ((unsigned short*)pBuffer)[5]);

//    if(((unsigned short)sum)!=0xffff){
//        ip_DiscardPkt(pBuffer, STUD_IP_TEST_CHECKSUM_ERROR);
//        return 1;
//    }

    printf("Check Destination:\n");
    unsigned int destination=ntohl(*(unsigned int*)(pBuffer+16));
    unsigned int ip=getIpv4Address();
    printf("destination is %d, host ip is %d\n", destination, ip);

    if(ip==destination){
        fwd_LocalRcv(pBuffer,length);
        return 0;
    }

    printf("Check Time To Live:\n");
    unsigned int ttl=pBuffer[8];
    printf("Time To Live is %d\n", ttl);
    if(ttl<=0){
        ip_DiscardPkt(pBuffer, STUD_FORWARD_TEST_TTLERROR);
        return 1;
    }

    vector<routeItem>::iterator ii;
    for(ii=myroute.begin();ii!=myroute.end();ii++)
    {
        if(ii->dest==destination)
        {
            char *buffer=new char[length];
            memcpy(buffer,pBuffer,length);
            buffer[8]--;
            int sum=0,i=0;
            unsigned short Local_Checksum=0;
            for(;i<2*len;i++)
            {
                if(i!=5)
                {
                    sum+=(buffer[2*i]<<8)+(buffer[2*i+1]);
                    sum%=65535;
                }
            }
            Local_Checksum=htons(0xffff-(unsigned short)sum);
            memcpy(buffer+10,&Local_Checksum,2);
            fwd_SendtoLower(buffer,length,ii->nexthop);
            return 0;
        }
    }
    fwd_DiscardPkt(pBuffer,STUD_FORWARD_TEST_NOROUTE);

    return -1;
//    printf("Send To UP\n");
//    ip_SendtoUp(pBuffer,length);
//    return 0;

}

void stud_route_add(stud_route_msg *proute){
    routeItem t;
    t.nexthop=proute->nexthop;
    t.dest=ntohl(proute->dest) & (0xffffffff<<(32-ntohl(proute->masklen)));
    myroute.push_back(t);
}

void stud_Route_Init(){
    myroute.clear();
}
最后修改:2020 年 10 月 11 日
如果觉得我的文章对你有用,请随意赞赏