您的位置:首页 > 其它

MIPL程序解读(2)

2008-10-04 10:05 344 查看
这部分对主要的线程进行总体上的分析。

2、runner线程分析

runner是从tq_list链表中,读取一项项的任务,分别执行。tq_list链表中的任务是按时间先后顺序进行排列,最先执行的程序放在前面,只有一个函数对这个链表进行插入操作,就是sorted_insert()。因此,只要看哪些地方调用了sorted_insert(),就可以知道一共有哪些任务会出现在队列中。
只有一个函数调用了sorted_insert(),就是add_task_abs(), 因此,只要看哪些地方调用了add_task_abs (),就可以知道一共有哪些任务会出现在队列中。

序号处理函数说明
1_expire()绑定到期了的超时处理函数
2bu_resend重新发送一个绑定更新报文
3mn_rr_check_entryrr表示Information for return routability,这个函数是对绑定更新选项进行处理,
4nonce_regen随机数重新产生
5md_router_timeout_probe应用在移动检测中,看看路由器是否依旧可以连接。
6mpd_resend_unsol_mpampa是Mobile Prefix Adverisements,mpd是Mobile Prefix Discovery。unsol是unsolicitation。这是重发非请求的mpa。
7mpd_send_unsol_mpa发送非请求的mpa
8ti_resendResend HoTI or CoTI, if we haven't got HoT or CoT
9dhaad_expire_halistdhaad是Dynamic Home Agent Address Discovery。这个函数是删除过期的家乡代理列表。
10dhaad_resend每隔一段时间,重新发送dhaad请求消息。
11md_discover_routermd表示mobile detection,移动检测。每隔一段时间,发送一个路由器发现的icmpv6报文。
12mpd_resend_mpsMPS是Mobile Prefix Solicitation消息,就是重发mps消息。
13mpd_send_first_mpsMPS是Mobile Prefix Solicitation消息,就是发送第一次mps消息。

任务队列的数据结构

跟任务队列相关的数据结构,主要就是一个tq_elem的数据结构。



3、mh_listen线程分析

static void *mh_listen(void *arg)
{
uint8_t msg[MAX_PKT_LEN];
struct in6_pktinfo pktinfo;
struct in6_addr haoa, rta;
struct sockaddr_in6 addr;
struct ip6_mh *mh;
struct in6_addr_bundle addrs;
ssize_t len;
struct mh_handler *h;

pthread_dbg("thread started");

while (1) {
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
//int pthread_setcancelstate(int state, int *oldstate) 设置本线程对Cancel信号的反应,state
//有两种值:PTHREAD_CANCEL_ENABLE(缺省)和PTHREAD_CANCEL_DISABLE,
//分别表示收到信号后设为CANCLED状态和忽略CANCEL信号继续运行
//old_state如果不为NULL则存入原来的Cancel状态以便恢复。
len = mh_recv(msg, sizeof(msg), &addr, &pktinfo, &haoa, &rta);
//从接收移动头部的socket中接收数据,保存在msg中。
//返回值是报文的长度或者错误标志
/* check if socket has closed */
if (len == -EBADF)
break;
//出错,线程退出
/* common validity check */
if (len < sizeof(struct ip6_mh))
continue;
//长度检查不对,跳过,忽略这个报文
addrs.src = &addr.sin6_addr;
addrs.dst = &pktinfo.ipi6_addr;
if (!IN6_IS_ADDR_UNSPECIFIED(&haoa)) {
addrs.remote_coa = &haoa;
} else {
addrs.remote_coa = NULL;
}
if (!IN6_IS_ADDR_UNSPECIFIED(&rta)) {
addrs.local_coa = &rta;
} else {
addrs.local_coa = NULL;
}
addrs.bind_coa = NULL;
mh = (struct ip6_mh *) msg;
//上面是对一些信息进行赋值和检查,都很容易看懂,不一一讲解
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
//对应上面的pthread_setcancelstate 函数说明
pthread_rwlock_rdlock(&handler_lock);
h = mh_handler_get(mh->ip6mh_type);
///mh->ip6mh_type是移动ipv6的移动头部的消息类型。在ip6mh.h中定义了如下类型,
//后面是解释,还有对应的处理函数。
// /* Mobility Header Message Types */
//#define IP6_MH_TYPE_BRR 0 /* Binding Refresh Request */ mn_brr_handler
//#define IP6_MH_TYPE_HOTI 1 /* HOTI Message */ cn_hoti_handler
//#define IP6_MH_TYPE_COTI 2 /* COTI Message */ cn_coti_handler
//#define IP6_MH_TYPE_HOT 3 /* HOT Message */ mn_hot_handler
//#define IP6_MH_TYPE_COT 4 /* COT Message */ mn_cot_handler
//#define IP6_MH_TYPE_BU 5 /* Binding Update */ cn_bu_handler
//#define IP6_MH_TYPE_BACK 6 /* Binding ACK */ mn_ba_handler
//#define IP6_MH_TYPE_BERROR 7 /* Binding Error */ mn_be_handler
//mh_handler_get的返回值是一个struct mh_handler结构,这个结构就是对应移动头部的
//这些消息类型的处理函数,每一个消息类型都定义了一个handler处理函数,
//存放在handler数组中。各自的处理函数在上面都说明了。
//在对icmpv6报文的处理中,也类似的定义了一个handler数组,两者处理很类似。
//但这样处理,决定了每个移动头部只能有一个移动消息类型,不能多个移动消息类型包
//含在一个移动头部中。

if (h)
h->recv(mh, len, &addrs, pktinfo.ipi6_ifindex);
//调用对应的处理函数进行处理
pthread_rwlock_unlock(&handler_lock);
}
pthread_exit(NULL);
}

ipv6的移动头部的消息类型,其原理具体可以参考《下一代网络移动IPv6技术》的4.1节。

名称处理函数说明
IP6_MH_TYPE_BRR0mn_brr_handler绑定更新请求消息的处理函数
IP6_MH_TYPE_HOTI1cn_hoti_handler家乡测试初始消息的处理函数
IP6_MH_TYPE_COTI2cn_coti_handler转交测试初始消息的处理函数
IP6_MH_TYPE_HOT3mn_hot_handler家乡测试消息的处理函数
IP6_MH_TYPE_COT4mn_cot_handler转交测试消息的处理函数
IP6_MH_TYPE_BU5cn_bu_handler绑定更新消息的处理函数
IP6_MH_TYPE_BACK6mn_ba_handler绑定确认消息的处理函数
IP6_MH_TYPE_BERROR7mn_be_handler绑定错误消息的处理函数

4、icmp6_listen线程分析

这个线程的结构以及处理流程和mh_listen线程非常类似。不重复了。
仅仅是各自调用的handler处理函数不同而已。下表列出了对应icmpv6的消息类型以及各自的处理函数。

名称值,参考RFC2292和3542 处理函数说明
ICMP6_DST_UNREACH1cn_dst_unreach_handler目的地址不可达的
MIP_HA_DISCOVERY_REQUEST144dhaad_req_handler动态家乡代理发现请求
MIP_HA_DISCOVERY_REPLY145dhaad_rep_handler动态家乡代理发现应答
ND_ROUTER_ADVERT134ha_ra_handler移动代理的路由器广播消息处理函数,这个消息,移动代理和移动节点的处理函数不一样。
ICMP6_PARAM_PROB4mn_param_prob_handler参数探测
ND_NEIGHBOR_ADVERT136md_na_handler邻居通告
ND_ROUTER_ADVERT134md_ra_handler移动节点的路由器广播消息处理函数
MIP_PREFIX_SOLICIT146mpd_mps_handler前缀请求
MIP_PREFIX_ADVERT147mpd_mpa_handler前缀通告

5、各个文件的功能说明

(1) bcache.c:绑定缓存(binding cache)的相关操作函数,操作的数据结构是struct bcentry。
(2) bul.c:绑定更新列表(binding update list )的相关操作函数,操作的数据结构是struct bulentry。
(3) cn.c:对端节点的操作处理函数。
(4) conf.c:一些配置函数。主要是对用户输入的命令行进行解析,配置MIPv6的一些参数。
(5) crypto.c:跟加密相关的一些函数。
(6) debug.c:打印函数,调试时输出一些打印信息。
(7) defpath.h:缺省时候的MIPv6配置文件的位置。
(8) dhaad_ha.c:dhaad是Dynamic Home Agent Address Discovery的简写,这个文件是家乡代理的动态家乡代理地址发现方面的操作函数。对应的,dhaad_mn.c是移动节点的动态家乡代理地址发现有关的操作函数。
(9) gram.c:这个文件跟数据库有关。在PostgreSQL 中,分析器必须检查(以纯 ASCII 文本方式到来的)查询字串的语法。 如果语法正确,则创建一个分析树并将之传回, 否则,返回一个错误。实现分析器和词法器我们使用了著名的 Unix 工具 lex 和 yacc。词法器在文件 scan.l里定义,负责识别标识符,SQL 关键字等。 对于发现的每个关键字或者标识符都会生成一个记号并且传递给分析器。 分析器在文件 gram.y 里定义并且包含一套语法规则和触发规则时执行的动作。 动作代码(实际上是 C 代码)用于建立分析树。 文件 scan.l 用 lex 转换成 C 源文件 scan.c 而 gram.y 用 yacc 转换成 gram.c。 在完成这些转换后,一个通用的 C 编译器就可以用于创建分析器。 千万不要对生成的 C 源文件做修改,因为下一次调用 lex 或 yacc 时会把它们覆盖。 注意: 上面提到的转换和编译是使用跟随 PostgreSQL 发布的 makefiles 自动完成的。具体可以查yacc的相关资料。另外 gram.c文件里面会涉及到一个RHS,这里也顺便提一下,这是跟MIPv6 DNS相关的,具体可以查看相关的RFC。IPv6的DNS 的记录格式是(LHS IN RR RHS)。其中LHS, 表示我们想定义的资料项目。 RR 分別为底下的 A, CNAME, ... 等关键字。 RHS 可能表示为一个网址 (IP address), 或另一个domain name。关于lex和yacc的内容可以参照o’reilly出版的一本书《lex和yacc》。
(10) ha.c:家乡代理的有关操作函数
(11) hash.c:hash表的有关操作函数
(12) icmp6.c:icmpv6的相关操作函数。
(13) in.h:Mipv6中有关socket的一些参数定义和函数说明。定义的函数是供其他用户程序调用的。一般说来,其他应用程序就是包含这个头文件,然后应用这个文件定义的一些函数进行编程。这个文件是暴露给第三者来进行应用程序编程的。
(14) inet6_opt_find.c:这个文件只有一个函数inet6_opt_find(),而且这个函数只在mh.c中被调用了一次。这个函数应该是对某个报头的选项进行处理。看程序应该是对IPV6_DSTOPTS报头选项进行处理。mh.c中,将IPV6_DSTOPTS定义成59,是不是错了?应该定义成60才对??但看处理过程,好像并不是对目的报头进行处理。看起来像是对59号报头进行处理,59号报头表示后面没有再跟其他报头了,处理函数仅仅进行一些位置的偏移。这个后面需要仔细看一下。顺便提示一下,mh_recv()函数里面涉及的haoaddr中的hao表示home address option。里面有一句话:表示内核部分已经处理了第二类路由头部,应用程序空间这部分代码就没有再涉及第二类路由头部了。
(15) inet6_rth_add.c:只有一个函数inet6_rth_add(),添加路由头部信息。在发送数据报文的时候调用。在in.h中定义了几个操作函数,这些操作函数每个占用了一个文件,分别是:inet6_opt_find( ),inet6_rth_space( ),inet6_rth_init( ),inet6_rth_add( ), inet6_rth_getaddr( )和 inet6_rth_gettype(const void *)。这几个函数应该非常类似。分析清楚inet6_opt_find( )和inet6_rth_add( ),就都清楚了。这几个函数的文件就不再写了。后面还需要根据MIPv6协议规定的操作,理解这几个函数的作用和应用场合,现在还不是特别清楚。
(16) ip6.h:ipv6一些数据结构的定义。
(17) ip6mh.h:ipv6移动头部的一些格式定义。
(18) ipsec.c:涉及ipsec的一些函数。
(19) keygen.c:移动IPv6协议在注册消息中添加了序列号,并且在协议报文中引入了时间随机数(Nonce)。这个文件主要就是涉及nonce的一些操作函数。
(20) libnetlink.c:netlink使用的一些通用的功能函数。
(21) list.h:队列的一些定义和通用操作函数。
(22) main.c:主函数。
(23) mh.c:移动头部的一些操作处理函数。
(24) mipv6.h:MIPv6的一些数据和常数定义。
(25) mn.c:移动节点的一些操作处理函数。
(26) movement.c:移动检测函数。包括对漫游的检测以及对漫游的一些处理函数。
(27) mpdisc_ha.c:这是对MPD的一些操作函数。mpd是Mobile Prefix Discovery的简写。这部分是家乡代理的mpd操作函数,对应的mpdisc_mn.c是移动节点的mpd操作函数。
(28) ndisc.c:邻居发现算法的相关操作函数。
(29) pmgr.c:pmgr是pure-micro gateway router 的简写。这是对pmgr相关的操作函数,
(30) policy.c:主要是跟绑定策略相关的一些函数,很多跟ACL即访问控制列表相关。程序命名中常用的几个简写:hoa: own home address。 cn: CN address。coa: care-of address
(31) prefix.c:网络前缀的一些操作函数
(32) proc_sys.c:/proc文件系统的一些操作函数。通过/proc文件系统,可以将程序状态和网络配置信息从内核空间反映到用户空间,用户也可以通过/proc文件系统来改变其中的参数。
(33) retrout:retrout是返回路由(Return Routability)的简写。这个文件是RRP(Return Routability Procedure)相关的一些操作函数。RRP过程可以到网上查相关的文档。这里不再进行说明。
(34) rtnl.c:netlink的操作函数,包括地址的配置、前缀的配置和路由表的修改。
(35) scan.c:跟前面说的gram.c类似。上面已经说了,这里不再重复。
(36) tqueue.c:任务队列的操作函数。tqueue是task queue的简写。
(37) tunnelctl.c:隧道的操作函数。tunnel control的简写。
(38) util.h:一些大家都要用的公共的功能函数。
(39) vars.c:一些变量和参数的设置。更像一个头文件。
(40) vt.c:控制台的一些函数。通过vt来显示一些调试信息,监控程序状态。并对程序进行控制。
(41) xfrm.c:xfrm的相关操作函数。xfrm是2.6内核的一个网络架构,可以对数据包进行安全检测。

6、MIPL和NEMO两个程序的关系

程序对应RFC说明
MIPLRFC3775这个是最基本的MIPv6的程序。nemo和umip程序,都是在它的基础上进行修改得来的。nemo和umip都只是修改了mipl实现代码中的一些操作逻辑流程。我建议我们也是在这个基础上进行修改。按照ad hoc中应用MIPv6的要求,先设计好操作流程,然后跟MIPL程序中的操作流程进行比较,对需要修改的操作流程进行修改。
NEMORFC 3963支持无线路由器的移动,即子网的移动。
radvdRFC 2461专门负责维护路由器通告和路由器请求方面的一个daemon程序。用于网络的无状态自动配置。
umipRFC3775好像就是nemo程序?还没有仔细分析。nemo对基本的MIPL做了哪些修改,还没有进行仔细的对比分析。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: