日期:2014-05-16 浏览次数:21095 次
本文主要讲解了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