下面是rip中路由表使用到的hash链表的整理,这部分理解还比较粗糙。
路由表、路由条目
路由协议的最终目的,就是一张路由表。例如,vxWorks协议栈有一个路由表,rip协议有私有的路由表,rm层维护由一个路由表。路由表其实就是一个维护多个路由条目的数据结构。下面就我所了解的路由表的数据结构记录如下,以备忘。
- l2p阶段维护的路由表,使用的是双链表数据结构;
- rm层维护的路由表,使用的是二叉树的数据结构;
- rip私有路由表,使用的是hash链表的数据结构;
每种数据结构组织的路由表,都有其优点和劣势。下面就我接触的hash链表维护的路由表进行一个整理。由于理解有限,结构复杂,现在只能够大致的罗列,如果有必要再深究。
Hash链表
- Table.c文件:对rip私有路由表的操作,例如增删改,查找等,向下调用af.c文件中的哈希操作函数
- af.c文件:对hash操作函数的封装,address family的意思
结构体定义
#define ROUTEHASHSIZ 32 /* must be a power of 2 */ #define ROUTEHASHMASK (ROUTEHASHSIZ - 1) struct rthash { struct rt_entry *rtu_forw; struct rt_entry *rtu_back; }; struct rthash nethash[ROUTEHASHSIZ]; struct rthash hosthash[ROUTEHASHSIZ]; /* * Structure used by kernel to store most * addresses. */ struct sockaddr { u_char sa_len; /* total length */ sa_family_t sa_family; /* address family */ char sa_data[14]; /* actually longer; address value */ }; struct rthash { struct rt_entry *rtu_forw; struct rt_entry *rtu_back; }; struct afhash { u_int afh_hosthash; u_int afh_nethash; };
最重要的hash函数,根据传入的IP地址,获取其位于hash数组中的位置。
LOCAL int inet_hash(sin, hp) register struct sockaddr_in *sin; struct afhash *hp; { register u_long n; n = inet_netof(sin->sin_addr); if (n) while ((n & 0xff) == 0) n >>= 8; hp->afh_nethash = n; hp->afh_hosthash = ntohl(sin->sin_addr.s_addr); hp->afh_hosthash &= 0x7fffffff; return (OK); }
hash链表路由表查找函数,根据传入的IP地址,获得其位于Hash链表中路由条目的指针。
/* * Lookup dst in the tables for an exact match. */ struct rt_entry * rtlookup (dst) struct sockaddr *dst; { register struct rt_entry *rt; register struct rthash *rh; register u_int hash; struct sockaddr target; struct afhash h; int doinghost = 1; if (dst->sa_family >= AF_MAX) return (0); (*afswitch[dst->sa_family].af_hash) (dst, &h); hash = h.afh_hosthash; rh = &hosthash[hash & ROUTEHASHMASK]; /* * The equal() comparison within the following loop expects all * members of the structure except the family, length, and address * fields to be zero. This condition may not be met when processing a * RIPv2 packet. In that case, the destination passed to this routine * accesses a route within the payload of a RIP message, so some * fields of the overlayed structure will not be zero as expected. * Duplicate or incorrect routes will be added because matching routes * are not detected. To avoid this problem, copy the required fields * from the route destination value to a clean structure. */ bzero ( (char *)&target, sizeof (struct sockaddr)); target.sa_family = dst->sa_family; target.sa_len = dst->sa_len; ((struct sockaddr_in *)&target)->sin_addr.s_addr = ((struct sockaddr_in *)dst)->sin_addr.s_addr; again: for (rt = rh->rtu_forw; rt != (struct rt_entry *)rh; rt = rt->rtu_forw) { if (rt->rtu_hash != hash) continue; if (equal (&rt->rtu_dst, &target)) { return (rt); } } if (doinghost) { doinghost = 0; hash = h.afh_nethash; rh = &nethash[hash & ROUTEHASHMASK]; goto again; } return (0); }
hash链表结构示意图
下面摘录一个hash链表示意图。来自《交换机IPv4路由功能研究报告》 黄韬撰写。