“目前专门为LoWPAN设计的路由协议(RPL协议)尚在制定完善中,很有可很成为6LoWPAN中使用的标准路由协议”
一 RPL处理数据包:
1 代码流程:
Ieee802.15.4mac层
\/
\/
6lowpan子系统,
\/
\/
Ipv6-->ipv6_rcv():
---->ip6_input()--->ip6_input_finish(){
….
nexthdr = skb_network_header(skb)[nhoff];//取出ipv6包头,判断出要使用那个上层协议(tcp,udp,icmp6等)
raw= raw6_local_deliver(skb, nexthdr);
if((ipprot = rcu_dereference(inet6_protos[nexthdr])) != NULL) {
ret = ipprot->handler(skb);---传递给上一层协议(tcp,udp,icmp6等)处理
\/
\/
2 下面是icmp6模块:
首先注册协议到inet6_protos[]
int __initicmpv6_init(void)
{
interr;
err= register_pernet_subsys(&icmpv6_sk_ops);
if(err < 0)
returnerr;
err= -EAGAIN;
if(inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6)< 0)
gotofail;
…
其次,handler定义:
static const structinet6_protocol icmpv6_protocol = {
.handler = icmpv6_rcv,
.err_handler = icmpv6_err,
.flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
};
补充认识icmp6:
功能:ICMPv6向源节点报告关于目的地址传输IPv6包的错误和信息,具有差错报告、网络诊断、邻节点发现和多播实现等功能。在IPv6中,ICMPv6实现IPv4中ICMP、ARP和IGMP的功能。ND和NI协议也是基于ICMPv6。
ND协议定义了5种ICMPV6报文类型,包括RS、RA、NS、NA和Redirect报文:
icmpv6_rcv(){
….
caseNDISC_ROUTER_SOLICITATION://RS
case NDISC_ROUTER_ADVERTISEMENT:
caseNDISC_NEIGHBOUR_SOLICITATION:
caseNDISC_NEIGHBOUR_ADVERTISEMENT:
case NDISC_REDIRECT:
ndisc_rcv(skb);
…..
3 RPL是通过icmpv6来接受数据包:参考RPL协议规范定义,如下图:
下面分析代码
icmpv6_rcv(){
…
完成icmp的处理之后。
…..
#ifdefCONFIG_IPV6_RPL//linux_rpl
caseICMPV6_RPL:
rpl_rcv(skb);
break;
#endif /*CONFIG_IPV6_RPL */
rpl_rcv(){}------》rpl_rx_worker()----》_rpl_rcv(rw->dev,skb){
…..
根据RPL组网过程基本原理,其基本消息处理如下:
//处理如下消息:DIS、DIO、DAO
switch(msg->icmp6_code){
caseICMPV6_RPL_DIS:
rpl_recv_dis(dev,skb);
break;
caseICMPV6_RPL_DIO:
rpl_recv_dio(dev,skb);
break;
caseICMPV6_RPL_DAO:
rpl_recv_dao(dev,skb);
break;
caseICMPV6_RPL_DAO_ACK:
//rpl_recv_dao_ack();
break;
caseICMPV6_RPL_CC:
//rpl_recv_cc();
break;
caseICMPV6_RPL_SEC_DIS:
caseICMPV6_RPL_SEC_DIO:
caseICMPV6_RPL_SEC_DAO:
caseICMPV6_RPL_SEC_DAO_ACK:
……
…...
}
逐个函数分析:
1)rpl_recv_dis(dev,skb);
{
//step1.找到节点信息,就是找路由信息。
icmpv6_rpl_find_option()
//step2:新节点,则加入
rpl_dag_inconsistent()---》trickle_hear_inconsistent()---》_trickle_start()---》trickle_threadfn()
------》trickle->trickle_fn(trickle->trickle_fn_arg);----》rpl_dag_dio_timer_handler()
{
发送出DIO:rpl_send_dio(dag,NULL,NULL,true,false);----dag处理---icmp处理---》dst_output()--》
ipV6层:rt->dst.output =ip6_output;
---->ip6_finish_output()---->ip6_finish_output2()----->
ND系统---mac层---》物理层
}
dio timer什么时候建立?
Dio timer是基于The Trickle Algorithm算法的定时器,参考rfc6206.pdf
当检测到netdev和netevent的时候
static structnotifier_block rpl_netdev_notifier = {
.notifier_call= rpl_netdev_event,
};
static structnotifier_block rpl_netevent_notifier = {
.notifier_call= rpl_netevent_event,
};
…/…./….--->rpl_dag_start_root()----…/….--->rpl_dag_dio_timer_reset(dag);
2)rpl_recv_dio(dev,skb);
这里只关注更新节点更新“自身邻居表”,并选择合适的节点发送数据包。
rpl_dag_update_upward_routes()---
-1)rpl_node_set_default_route()
-2)rpl_node_unset_default_route()
首先调用rt6_get_dflt_router()获取ipv6的路由缓存表信息
其次dst_neigh_lookup()更新自身的(ipv6)邻居表。---->….----->ip6_neigh_lookup();
3)rpl_recv_dao(dev,skb);
父节点更新了自身的路由表后,再向”父节点的父节点““发DAO”,最后到达sink点后双向链路最终形成。
//for each target intargets
rpl_recv_dao(dev,skb)
{
…..
rpl_dag_add_target()
{
..
..
rpl_target_check_routes()---->rpl_add_route_nexthop()
{
interr = -EINVAL;
intpref = 0;
structfib6_config cfg;
//FIXMEcheck expires!!
memset(&cfg,0, sizeof(cfg));
cfg.fc_table = RT6_TABLE_DFLT;
cfg.fc_metric =IP6_RT_PRIO_USER;
cfg.fc_ifindex =dev->ifindex;
cfg.fc_flags =RTF_GATEWAY | RTF_PREF(pref);
cfg.fc_nlinfo.portid= 0;
cfg.fc_nlinfo.nlh= NULL;
cfg.fc_nlinfo.nl_net= dev_net(dev);
cfg.fc_dst= *prefix;
cfg.fc_dst_len= prefix_len;
cfg.fc_gateway= *next_hop;
err =ip6_route_add(&cfg);//增加路由表项
returnerr;
}