日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

ip_queue_xmit簡單注釋

 enchen008 2013-09-11

在ULNI上圖中寫的清楚,此函數(shù)一般由tcp或sctp調(diào)用
上層工作都已經(jīng)做好了,只差ip頭及以下部分的填充
tcp可以做到這一點,因為有mss的限制以及自己的一些控制包大小的算法

而udp不一樣,它的數(shù)據(jù)包分段沒有完成需要下層幫忙,
因此udp使用的ip_append_data函數(shù)要復雜得多。
下面簡單注釋ip_queue_xmit函數(shù)

 
  1. int ip_queue_xmit(struct sk_buff *skb, int ipfragok)  
  2. {  
  3.     struct sock *sk = skb->sk;  
  4.     struct inet_sock *inet = inet_sk(sk);  
  5.     struct ip_options *opt = inet->opt;  
  6.     struct rtable *rt;  
  7.     struct iphdr *iph;  
  8.     /* Skip all of this if the packet is already routed, 
  9.      * f.e. by something like SCTP. 
  10.      */  
  11.     //首先檢測skb->rtable是否為空,不為空說明已經(jīng)指定了路由,跳到packet_routed繼續(xù)執(zhí)行   
  12.     //根據(jù)上面注釋,似乎sctp可能提前指定路由   
  13.     rt = skb->rtable;  
  14.     if (rt != NULL)  
  15.         goto packet_routed;  
  16.     /* Make sure we can route this packet. */  
  17.     //檢測socket路由合法性,如果不合法也需要重新查找路由   
  18.     rt = (struct rtable *)__sk_dst_check(sk, 0);  
  19.     if (rt == NULL) {  
  20.         __be32 daddr;  
  21.         /* Use correct destination address if we have options. */  
  22.         daddr = inet->daddr;  
  23.         if(opt && opt->srr)  
  24.             daddr = opt->faddr;  
  25.         {  
  26.             struct flowi fl = { .oif = sk->sk_bound_dev_if,  
  27.                         .nl_u = { .ip4_u =  
  28.                               { .daddr = daddr,  
  29.                             .saddr = inet->saddr,  
  30.                             .tos = RT_CONN_FLAGS(sk) } },  
  31.                         .proto = sk->sk_protocol,  
  32.                         .flags = inet_sk_flowi_flags(sk),  
  33.                         .uli_u = { .ports =  
  34.                                { .sport = inet->sport,  
  35.                              .dport = inet->dport } } };  
  36.             /* If this fails, retransmit mechanism of transport layer will 
  37.              * keep trying until route appears or the connection times 
  38.              * itself out. 
  39.              */  
  40.             security_sk_classify_flow(sk, &fl);  
  41.             //下面是主要的出口路由查找函數(shù),等看完路由這一章再回來補充   
  42.             if (ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 0))  
  43.                 goto no_route;  
  44.         }  
  45.         //下面函數(shù)做的其中一件事是sk->sk_dst_cache = dst;并釋放舊的dst緩存   
  46.         sk_setup_caps(sk, &rt->u.dst);  
  47.     }  
  48.     //增加路由緩存引用計數(shù)   
  49.     skb->dst = dst_clone(&rt->u.dst);  
  50. packet_routed:  
  51.     //如果sk_buff指向的sock的opt中包含嚴格源站路由選項,   
  52.     //而剛剛查找到的路由項目標地址又不等于網(wǎng)關(guān)地址的話前往no_route   
  53.     //說明嚴格源站路由無法滿足   
  54.     if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway)  
  55.         goto no_route;  
  56.     /* OK, we know where to send it, allocate and build IP header. */  
  57.     //在skb的數(shù)據(jù)中預留出ip首部包括選項的空間給ip報頭,并將   
  58.     //skb->network_header指向它   
  59.     skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0));  
  60.     skb_reset_network_header(skb);  
  61.     iph = ip_hdr(skb);  
  62.     //在ip首部填入版本號4,ip首部長度5(20字節(jié),這個值在后面要根據(jù)選項   
  63.     //的長度增加),以及服務類型   
  64.     *((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff));  
  65.     //如果socket要求ip不分片(這是通過檢測sock->pmtudisc做到的,   
  66.     //如果使用路徑mtu發(fā)現(xiàn)則說明要求不分片,否則允許分片)并且參數(shù)ipfragok等于0,   
  67.     //那么將DF標志置1,否則清0   
  68.     if (ip_dont_fragment(sk, &rt->u.dst) && !ipfragok)  
  69.         iph->frag_off = htons(IP_DF);  
  70.     else  
  71.         iph->frag_off = 0;  
  72.     //設(shè)置ip首部的ttl(從sock的uc_ttl獲得,如果小于0則從路由項的metrics獲得),   
  73.     //protocol(從sock->sk_protocol),源地址,目標地址(兩者都從路由項獲得)   
  74.     iph->ttl      = ip_select_ttl(inet, &rt->u.dst);  
  75.     iph->protocol = sk->sk_protocol;  
  76.     iph->saddr    = rt->rt_src;  
  77.     iph->daddr    = rt->rt_dst;  
  78.     /* Transport layer set skb->h.foo itself. */  
  79.     //若opt不為NULL,則在ip首部長度中加上選項長度,   
  80.     //并且調(diào)用ip_options_build向IP首部中寫入ip選項   
  81.     if (opt && opt->optlen) {  
  82.         iph->ihl += opt->optlen >> 2;  
  83.         //這個函數(shù)值得一看,opt是從inet_sock中獲得的   
  84.         ip_options_build(skb, opt, inet->daddr, rt, 0);  
  85.     }  
  86.     //調(diào)用ip_select_ident_more填入IP首部的id字段   
  87.     //關(guān)于ip的id在ULNI上講得很清楚,Linux為了防止id回繞采取的策略是對于每一個ip   
  88.     //分配一個inet_peer結(jié)構(gòu),在這個inet_peer中記錄針對這個ip的id號,   
  89.     //這樣可以很大程度上減緩id回繞的速度,但是仍不能完全避免   
  90.     ip_select_ident_more(iph, &rt->u.dst, sk,  
  91.                  (skb_shinfo(skb)->gso_segs ?: 1) - 1);  
  92.     skb->priority = sk->sk_priority;  
  93.     skb->mark = sk->sk_mark;  
  94.     return ip_local_out(skb);  
  95. no_route:  
  96.     IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES);  
  97.     kfree_skb(skb);  
  98.     return -EHOSTUNREACH;  
  99. }  

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多