日期:2014-05-16 浏览次数:20864 次
本文主要讲解了Linux中处理需要传输的IP报文流程,使用的内核的版本是2.6.32.27
为了方便理解,本文采用整体流程图加伪代码的方式对Linux中处理需要传输的IP报文流程进行了讲解,希望可以对大家有所帮助。阅读本文章假设大家对C语言有了一定的了解
首先从IP的更高层传输层看看是如何管理的
//----------------------------------------------------------------------------------------------- /*四层协议的注册,都注册为net_protocol结构,并hash到inet_protos表中进行统一管理*/ #ifdef CONFIG_IP_MULTICAST static const struct net_protocol igmp_protocol = { .handler = igmp_rcv, .netns_ok = 1, }; #endif static const struct net_protocol tcp_protocol = { .handler = tcp_v4_rcv, .err_handler = tcp_v4_err, .gso_send_check = tcp_v4_gso_send_check, .gso_segment = tcp_tso_segment, .gro_receive = tcp4_gro_receive, .gro_complete = tcp4_gro_complete, .no_policy = 1, .netns_ok = 1, }; static const struct net_protocol udp_protocol = { .handler = udp_rcv, .err_handler = udp_err, .gso_send_check = udp4_ufo_send_check, .gso_segment = udp4_ufo_fragment, .no_policy = 1, .netns_ok = 1, }; static const struct net_protocol icmp_protocol = { .handler = icmp_rcv, .no_policy = 1, .netns_ok = 1, }; static int __init inet_init(void) { /* * Add all the base protocols. */ if (inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) < 0) printk(KERN_CRIT "inet_init: Cannot add ICMP protocol\n"); if (inet_add_protocol(&udp_protocol, IPPROTO_UDP) < 0) printk(KERN_CRIT "inet_init: Cannot add UDP protocol\n"); if (inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0) printk(KERN_CRIT "inet_init: Cannot add TCP protocol\n"); #ifdef CONFIG_IP_MULTICAST if (inet_add_protocol(&igmp_protocol, IPPROTO_IGMP) < 0) printk(KERN_CRIT "inet_init: Cannot add IGMP protocol\n"); #endif }
//----------------------------------------------------------------------------------------------- /*ipv4.c中注册的让上层协议使用的接口*/ static const struct inet_connection_sock_af_ops dccp_ipv4_af_ops = { .queue_xmit = ip_queue_xmit, }; /*将dccp_ipv4_af_ops注册到协议中*/ static int dccp_v4_init_sock(struct sock *sk) { inet_csk(sk)->icsk_af_ops = &dccp_ipv4_af_ops; } /*TCP数据报文发送函数*/ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, gfp_t gfp_mask) { const struct inet_connection_sock *icsk = inet_csk(sk); /*使用ip_queue_xmit发送数据报文*/ err = icsk->icsk_af_ops->queue_xmit(skb, 0); } //----------------------------------------------------------------------------------------------- int ip_queue_xmit(struct sk_buff *skb, int ipfragok) { struct sock *sk = skb->sk; struct inet_sock *inet = inet_sk(sk); struct ip_options *opt = inet->opt; struct rtable *rt; struct iphdr *iph; /*检查套接字结构中sk->dst中是否有一个指针指向路由缓存中的某个入口项 *如果有,再检查这个指针是否有效,由于套接字的所有包都去往同一个目标 *地址,因此路由就存放在skb->_skb_ds