“目前專門爲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;
}