NetRiver - IPv6协议转发实验

来源:互联网 发布:魔眼软件 编辑:程序博客网 时间:2024/04/24 14:12

IPv6的协议转发实验在收发的基础上增加了转发功能,即要求查询路由表(Route table)并向相应地址转发。需要实现的函数接口也多了两个,一个是路由表的初始化,另一个是向路由表添加元素。路由表其实就是要建立并维护一个检索数据结构。

数据结构的思路有二,其一是通过散列函数实现复杂度为O(1)的快速查找,但缺点也很明显,散列函数的设计比较困难。一旦出现碰撞,不论是用开地址法还是链表法,散列函数查找的效率都有可能退化。其二就是通过树形结构,这也是路由表很经典的检索结构。

本题中需要我们比较的是路由表项的目标地址前缀与IP包的目标地址前缀是否符合,前缀的长度相当于IPv4的子网掩码的定义。考虑到这一点,采用Trie树作为检索结构比较理想,根据最长匹配原则,查询的时候需要遍历对应的分支,查询次数是常数时间复杂度,记录最深的匹配节点即可。维护的复杂度比查询还要略低,同样是常数时间复杂度。因为题目给的路由表很短,树的稀疏度很大,可以进一步采取压缩优化。

不过实验实际给的路由表真的很短,所以这里就直接用数组暴力比较了,毕竟懒癌晚期……另外,本实验添加的路由表项中的masklen(严格来说是prefixlen)经测试不需要转字节序。代码如下。

/** MIT license* Copyright © 2016 Maristie* * Permission is hereby granted, free of charge, to any person obtaining a copy of this software* and associated documentation files (the "Software"), to deal in the Software without restriction,* including without limitation the rights to use, copy, modify, merge, publish, distribute, * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions:* The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software.* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.*/#include "sysinclude.h"extern void ipv6_fwd_DiscardPkt(char *pBuffer, int type);extern void ipv6_fwd_SendtoLower(char *pBuffer, int length, ipv6_addr *nexthop);extern void getIpv6Address(ipv6_addr *pAddr);extern void ipv6_fwd_LocalRcv(char *pBuffer, int length);static stud_ipv6_route_msg route_table[50];static int table_size = 0;void stud_ipv6_Route_Init(){    return;}void stud_ipv6_route_add(stud_ipv6_route_msg *proute){    route_table[table_size++] = *proute;    return;}int stud_ipv6_fwd_deal(char *pBuffer, int length){    // get destination address    BYTE des_addr[16];    memcpy(des_addr, pBuffer + 24, 16);    // counters declaration    int i, j;    // check hoplimit    if (pBuffer[7] == 0)    {        ipv6_fwd_DiscardPkt(pBuffer, STUD_IPV6_FORWARD_TEST_HOPLIMIT_ERROR);        return 1;    }    // check destination    // get local address    ipv6_addr *local_addr = (ipv6_addr*)malloc(sizeof(ipv6_addr));    getIpv6Address(local_addr);    // compare destination and local address    int flag = 0;    for (i = 0; i < 16; ++i)        if (des_addr[i] != local_addr->bAddr[i])        {            flag = 1;            break;        }    if (flag == 0)    {        ipv6_fwd_LocalRcv(pBuffer, length);        return 0;    }    // not local host, then search route table    unsigned int max_masklen = 0;    ipv6_addr *nexthop = (ipv6_addr*)malloc(sizeof(ipv6_addr)); // used to record the next hop    // traverse the route table    for (i = 0; i < table_size; ++i)    {        unsigned int masklen = route_table[i].masklen;        flag = 0; // flag == 0 means they have the same prefix, or else they're different        for (j = 0; j < masklen / 8; ++j)            if (des_addr[j] != route_table[i].dest.bAddr[j])            {                flag = 1;                break;            }        if (flag == 0 && des_addr[j] >> ((j + 1) * 8 - masklen) != route_table[i].dest.bAddr[j] >> ((j + 1) * 8 - masklen))            flag = 1;        // judge flag        if (flag == 0 && masklen > max_masklen)        {            max_masklen = masklen;            *nexthop = route_table[i].nexthop;        }    }    // if no route found    if (max_masklen == 0)    {        fwd_DiscardPkt(pBuffer, STUD_IPV6_FORWARD_TEST_NOROUTE);        return 1;    }    // route found, then prepare for sending    // set hoplimit    --pBuffer[7];    // send    ipv6_fwd_SendtoLower(pBuffer, length, nexthop);    return 0;}
0 0