IP输出 之 ip_local_out
概述
将要从本地发出的数据包,会在构造了ip头之后,调用ip_local_out函数,该函数设置数据包的总长度和校验和,然后经过netfilter的LOCAL_OUT钩子点进行检查过滤,如果通过,则调用dst_output函数,实际上调用的是ip数据包输出函数ip_output;
源码分析
1 int ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb) 2 { 3 int err; 4 5 /* 设置几个必要字段,经过NF的LOCAL_OUT钩子点 */ 6 err = __ip_local_out(net, sk, skb); 7 8 /* NF允许包通过,但需要显示调用回调函数 */ 9 if (likely(err == 1)) 10 err = dst_output(net, sk, skb); 11 12 return err; 13 }
1 int __ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb) 2 { 3 struct iphdr *iph = ip_hdr(skb); 4 5 /* 设置总长度 */ 6 iph->tot_len = htons(skb->len); 7 /* 计算校验和 */ 8 ip_send_check(iph); 9 10 /* if egress device is enslaved to an L3 master device pass the 11 * skb to its handler for processing 12 */ 13 skb = l3mdev_ip_out(sk, skb); 14 if (unlikely(!skb)) 15 return 0; 16 17 /* 设置ip协议 */ 18 skb->protocol = htons(ETH_P_IP); 19 20 /* 经过NF的LOCAL_OUT钩子点 */ 21 return nf_hook(NFPROTO_IPV4, NF_INET_LOCAL_OUT, 22 net, sk, skb, NULL, skb_dst(skb)->dev, 23 dst_output); 24 }
1 static inline int dst_output(struct net *net, struct sock *sk, struct sk_buff *skb) 2 { 3 return skb_dst(skb)->output(net, sk, skb); 4 }