Chinaunix首页 | 论坛 | 博客
  • 博客访问: 962999
  • 博文数量: 58
  • 博客积分: 10192
  • 博客等级: 上将
  • 技术积分: 1845
  • 用 户 组: 普通用户
  • 注册时间: 2010-11-22 21:24
文章分类

全部博文(58)

文章存档

2011年(11)

2010年(12)

2009年(20)

2008年(15)

分类: LINUX

2010-12-18 12:16:24

.Linux下基于TCP协议和SCTP协议的本地产生的数据包传输是通过调用ip_queue_xmit函数实现的。它们与UDP/ICMP/IGMP的数据包传输调用的函数接口不同。

1.套接字数据结构:因为网络层(TCP/UDP等)信息都存储在sock数据接口中。它被分配成为协议簇专用的结构的一部分。就PF——INET套接字而言,此结构就是inet_sock

 

  1. struct sock {


  2.         struct sock_common __sk_common;


  3. #define sk_family __sk_common.skc_family


  4. #define sk_state __sk_common.skc_state


  5. #define sk_reuse __sk_common.skc_reuse


  6. #define sk_bound_dev_if __sk_common.skc_bound_dev_if


  7. #define sk_node __sk_common.skc_node


  8. #define sk_bind_node __sk_common.skc_bind_node


  9. #define sk_refcnt __sk_common.skc_refcnt


  10.   /*

  11.          * sk_shutdown是一组标志位,SEND_SHUTDOWN and/or RCV_SHUTDOWN。


  12.          * sk_userlocks, SO_SNDBUF and SO_RCVBUF。

  13.          */


  14.         unsigned char sk_shutdown : 2,


  15.                             sk_no_check : 2,


  16.                             sk_userlocks : 4;


  17.         //sk_protocol表示在当前域中套接字所属的协议


  18.         unsigned char sk_protocol;


  19.         //sk_type表示套接字的类型,如SOCK_STREAM


  20.         unsigned short sk_type;


  21.         int sk_rcvbuf;

  22. //sk_rcvbuf表示接收缓冲区的字节长度。


  23.         socket_lock_t sk_lock;


  24.         wait_queue_head_t *sk_sleep;


  25.         struct dst_entry *sk_dst_cache;


  26.         struct xfrm_policy *sk_policy[2];


  27.         rwlock_t sk_dst_lock;


  28.         

  29. //sk_rmem_alloc表示接收队列已提交的字节数


  30.         atomic_t sk_rmem_alloc;

  31.   // sk_wmem_alloc表示发送队列已提交的字节数


  32.         atomic_t sk_wmem_alloc;


  33.         atomic_t sk_omem_alloc;


  34.   //


  35. sk_receive_queue表示接收的数据包的队列

  36.         struct sk_buff_head sk_receive_queue;

  37.         //sk_write_queue表示发送数据包的队列


  38.         struct sk_buff_head sk_write_queue;


  39.         int sk_wmem_queued;


  40.         int sk_forward_alloc;


  41.         unsigned int sk_allocation;


  42.   // sk_sndbuf表示发送缓冲区的字节长度


  43.         int sk_sndbuf;


  44.         int sk_route_caps;


  45.         int sk_hashent;


  46.         // sk_flags,SO_LINGER (l_onoff),SO_BROADCAST,SO_KEEPALIVE,SO_OOBINLINE


  47.         unsigned long sk_flags;


  48.         unsigned long sk_lingertime;


  49.         struct {


  50.             struct sk_buff *head;


  51.             struct sk_buff *tail;


  52.         } sk_backlog;


  53.         struct sk_buff_head sk_error_queue;


  54.         /*

  55.          * sk_prot是指定的域内部的协议处理函数集,

  56.          * 它是套接口层跟传输层之间的一个接口,提供诸如bind, accept, close等操作

  57.          */

  58.         struct proto *sk_prot;


  59.         struct proto *sk_prot_creator;


  60.         rwlock_t sk_callback_lock;


  61.         int sk_err,


  62.                     sk_err_soft;


  63.         // sk_ack_backlog表示当前的侦听队列


  64.         unsigned short sk_ack_backlog;


  65.         // sk_max_ack_backlog表示最大的侦听队列


  66.         unsigned short sk_max_ack_backlog;


  67.         __u32 sk_priority;


  68.         struct ucred sk_peercred;


  69.         int sk_rcvlowat;


  70.         long sk_rcvtimeo;


  71.         long sk_sndtimeo;


  72.         struct sk_filter *sk_filter;


  73.         void *sk_protinfo;


  74.         struct timer_list sk_timer;


  75.         struct timeval sk_stamp;


  76.         struct socket *sk_socket;


  77.         void *sk_user_data;


  78.         struct page *sk_sndmsg_page;


  79.         struct sk_buff *sk_send_head;


  80.         __u32 sk_sndmsg_off;


  81.         int sk_write_pending;


  82.         void *sk_security;

  83.   /*

  84.          * 几个函数指针均属回调函数,分别在套接口状态变化,

  85.          * 有数据到达需要处理,有发送空间可用,有错误等时候被回调。

  86.          * 最后一个函数sk_destruct在套接口释放时被回调。

  87.          */


  88.         void (*sk_state_change)(struct sock *sk);


  89.         void (*sk_data_ready)(struct sock *sk, int bytes);


  90.         void (*sk_write_space)(struct sock *sk);


  91.         void (*sk_error_report)(struct sock *sk);


  92.         int (*sk_backlog_rcv)(struct sock *sk,


  93.                         struct sk_buff *skb);


  94.         void (*sk_destruct)(struct sock *sk);


  95.     };



  96.     __sk_common是套接口在网络层的最小表示。下面是其定义:


  97.     struct sock_common {


  98.         unsigned short skc_family; /*地址族*/


  99.         volatile unsigned char skc_state; /*连接状态*/


  100.         unsigned char skc_reuse; /*SO_REUSEADDR设置*/


  101.         int skc_bound_dev_if;


  102.         struct hlist_node skc_node;


  103.         struct hlist_node skc_bind_node; /*哈希表相关*/


  104.         atomic_t skc_refcnt; /*引用计数*/


  105.     };



  106. struct inet_sock {


  107.     struct sock sk;


  108. #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)


  109.     struct ipv6_pinfo *pinet6;


  110. #endif


  111.     __be32 daddr; //IPv4的目的地址(远程地址)



  112.     __be32 rcv_saddr; //IPv4的本地接收地址



  113.     __be16 dport; //目的端口(远程端口)



  114.     __u16 num; //本地端口(主机字节序)



  115.     __be32 saddr; //本地发送地址



  116.     __s16 uc_ttl; //单播的ttl



  117.     __u16 cmsg_flags;


  118.     struct ip_options *opt;


  119.     __be16 sport; //本地端口



  120.     __u16 id; //单调递增的一个值,用于赋给iphdr的id域



  121.     __u8 tos; //服务类型



  122.     __u8 mc_ttl; //组播的ttl



  123.     __u8 pmtudisc;


  124.     __u8 recverr:1,


  125.                             is_icsk:1,


  126.                             freebind:1,


  127.                             hdrincl:1, //是否自己构建ip首部(用于raw协议)



  128.                             mc_loop:1; //组播是否发向回路



  129.     int mc_index; -//组播使用的本地设备接口的索引



  130.     __be32 mc_addr; //组播源地址



  131.     struct ip_mc_socklist *mc_list; -//组播组列表



  132.     struct {


  133.         unsigned int flags;


  134.         unsigned int fragsize;


  135.         struct ip_options *opt;


  136.         struct rtable *rt;


  137.         int length;


  138.         __be32 addr;


  139.         struct flowi fl;


  140.     } cork;


  141. };

 

2.ip_queue_xmit的两个参数中,ipfragok主要由SCTP便用的标志,用来指出是否允许分段。

 

  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.        * 当缓冲区由SCTP协议处理过后,有可能skb中包含路由信息,即skb->dst != NULL。

  11.  */


  12. rt = (struct rtable *) skb->dst;


  13. if (rt != NULL)


  14. goto packet_routed;




  15. /* Make sure we can route this packet. */


  16.       /*

  17.        * 在cache中查找是否有记录,没有返回NULL

  18.        * 如果rt==NULL,调用 ip_route_output_flow寻找出一条新路径

  19.        */

  20. rt = (struct rtable *)__sk_dst_check(sk, 0);


  21. if (rt == NULL) {


  22. u32 daddr;




  23. /* Use correct destination address if we have options. */


  24.             /* 从套接字中获取最终目的地址 */

  25. daddr = inet->daddr;


  26.             /* 如果有选项且存在来源地路由,获取下一个跳点的地址 */

  27. if(opt && opt->srr)


  28. daddr = opt->faddr;




  29. {


  30. struct flowi fl = { .oif = sk->sk_bound_dev_if,


  31.     .nl_u = { .ip4_u =


  32.       { .daddr = daddr,


  33. .saddr = inet->saddr,


  34. .tos = RT_CONN_FLAGS(sk) } },


  35.     .proto = sk->sk_protocol,


  36.     .uli_u = { .ports =


  37.        { .sport = inet->sport,


  38.  .dport = inet->dport } } };




  39. /* If this fails, retransmit mechanism of transport layer will


  40.  * keep trying until route appears or the connection times


  41.  * itself out.


  42.  * 如果寻找失败,传输层的重传机制会一直试,

  43.  * 直到寻找到可用路由或者直到该连接超时。

  44.  */


  45. if (ip_route_output_flow(&rt, &fl, sk, 0))


  46. goto no_route;


  47. }


  48.             /*

  49.              * ip_route_output_flow找到新路经后,

  50.              * 调用__sk_dst_set保存到sk数据结构中。

  51.              */

  52. __sk_dst_set(sk, &rt->u.dst);


  53. tcp_v4_setup_caps(sk, &rt->u.dst);


  54. }


  55. skb->dst = dst_clone(&rt->u.dst);




  56. packet_routed:


  57. /* 选项提供的下一个跳点和路由表所传回的下一个跳点不吻合,丢弃该包。*/

  58. if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway)


  59. goto no_route;




  60. /* OK, we know where to send it, allocate and build IP header. */


  61.       /* 创建IP报头 */

  62. iph = (struct iphdr *) skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0));


  63.       /*

  64.        * 4 << 12 version

  65.        * 5 << 8 header length

  66.        * inet->tos&0xff tos type

  67.        */

  68. *((__u16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff));


  69. iph->tot_len = htons(skb->len);

  70. /* 总长度 */

  71. if (ip_dont_fragment(sk, &rt->u.dst) && !ipfragok)


  72. iph->frag_off = htons(IP_DF);


  73. else


  74. iph->frag_off = 0;


  75. iph->ttl = ip_select_ttl(inet, &rt->u.dst);


  76. iph->protocol = sk->sk_protocol;

  77.  /* 协议值 */

  78. iph->saddr = rt->rt_src;


  79.  /* 源地址 */

  80. iph->daddr = rt->rt_dst;


  81.  /* 目的地址 */

  82. skb->nh.iph = iph;


  83. /* Transport layer set skb->h.foo itself. */




  84. if (opt && opt->optlen) {


  85. iph->ihl += opt->optlen >> 2;


  86.             /* 把选项写入IP报头 */

  87. ip_options_build(skb, opt, inet->daddr, rt, 0);


  88. }



  89. /* 根据该封包是否可能被分段而在报头中设定IP ID */

  90. ip_select_ident_more(iph, &rt->u.dst, sk, skb_shinfo(skb)->tso_segs);




  91. /* Add an IP checksum.进行IP校验和 */


  92. ip_send_check(iph);



  93.       /*

  94.        * priority把封包排入那一个外出队列

  95.        * 这个决定该封包多快会被传输

  96.        */

  97. skb->priority = sk->sk_priority;



  98. /* 调用dst_output传出 */

  99. return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,


  100.        dst_output);




  101. no_route:


  102. IP_INC_STATS(IPSTATS_MIB_OUTNOROUTES);


  103. kfree_skb(skb);


  104. return -EHOSTUNREACH;


  105. }

阅读(4215) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~