首页 > 社交 > 科普中国

25

常驻编辑 科普中国 2022-06-02 子系统   网络   队列   内核   网卡   函数   源码   内存   过程   数据   用户
gEf拜客生活常识网

gEf拜客生活常识网

再通过 ip_local_out 进入到下一步的处理。gEf拜客生活常识网

//file: net/ipv4/ip_output.c    
int ip_local_out(struct sk_buff *skb)  
{  
 //执行 netfilter 过滤  
 err = __ip_local_out(skb);  
  
 //开始发送数据  
 if (likely(err == 1))  
 &nbsnbsp;err = dst_output(skb);  
 ......  

在 ip_local_out => __ip_local_out => nf_hook 会执行 netfilter 过滤。如果你使用 iptables 配置了一些规则,那么这里将检测是否命中规则。如果你设置了非常复杂的 netfilter 规则,在这个函数这里将会导致你的进程 CPU 开销会极大增加gEf拜客生活常识网

还是不多展开说,继续只聊和发送有关的过程 dst_output。gEf拜客生活常识网

//file: include/net/dst.h  
static inline int dst_output(struct sk_buff *skb)  
{  
 return skb_dst(skb)->output(skb);  
}  

此函数找到到这个 skb 的路由表(dst 条目) ,然后调用路由表的 output 方法。这又是一个函数指针,指向的是 ip_output 方法。gEf拜客生活常识网

//file: net/ipv4/ip_output.c  
int ip_output(struct sk_buff *skb)  
{  
 //统计  
 .....  
  
 //再次交给 netfilter,完毕后回调 ip_finish_output  
 return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb, NULL, dev,  
    ip_finish_output,  
    !(IPCB(skb)->flags & IPSKB_REROUTED));  
}  

在 ip_output 中进行一些简单的,统计工作,再次执行 netfilter 过滤。过滤通过之后回调 ip_finish_output。gEf拜客生活常识网

//file: net/ipv4/ip_output.c  
static int ip_finish_output(struct sk_buff *skb)  
{  
 //大于 mtu 的话就要进行分片了  
 if (skb->len > ip_skb_dst_mtu(skb) && !skb_is_gso(skb))  
  return ip_fragment(skb, ip_finish_output2);  
 else  
  return ip_finish_output2(skb);  
}  

在 ip_finish_output 中我们看到,如果数据大于 MTU 的话,是会执行分片的。gEf拜客生活常识网

实际 MTU 大小确定依赖 MTU 发现,以太网帧为 1500 字节。之前 QQ 团队在早期的时候,会尽量控制自己数据包尺寸小于 MTU,通过这种方式来优化网络性能。因为分片会带来两个问题:1、需要进行额外的切分处理,有额外性能开销。2、只要一个分片丢失,整个包都得重传。所以避免分片既杜绝了分片开销,也大大降低了重传率。gEf拜客生活常识网

在 ip_finish_output2 中,终于发送过程会进入到下一层,邻居子系统中。gEf拜客生活常识网

//file: net/ipv4/ip_output.c  
static inline int ip_finish_output2(struct sk_buff *skb)  
{  
 //根据下一跳 IP 地址查找邻居项,找不到就创建一个  
 nexthop = (__force u32) rt_nexthop(rt, ip_hdr(skb)->daddr);    
 neigh = __ipv4_neigh_lookup_noref(dev, nexthop);  
 if (unlikely(!neigh))  
  neigh = __neigh_create(&arp_tbl, &nexthop, dev, false);  
  
 //继续向下层传递  
 int res = dst_neigh_output(dst, neigh, skb);  
}  

4.4 邻居子系统

邻居子系统是位于网络层和数据链路层中间的一个系统,其作用是对网络层提供一个封装,让网络层不必关心下层的地址信息,让下层来决定发送到哪个 MAC 地址。gEf拜客生活常识网

而且这个邻居子系统并不位于协议栈 net/ipv4/ 目录内,而是位于 net/core/neighbour.c。因为无论是对于 IPv4 还是 IPv6 ,都需要使用该模块。gEf拜客生活常识网

gEf拜客生活常识网

在邻居子系统里主要是查找或者创建邻居项,在创造邻居项的时候,有可能会发出实际的 arp 请求。然后封装一下 MAC 头,将发送过程再传递到更下层的网络设备子系统。大致流程如图。gEf拜客生活常识网

gEf拜客生活常识网

理解了大致流程,我们再回头看源码。在上面小节 ip_finish_output2 源码中调用了 __ipv4_neigh_lookup_noref。它是在 arp 缓存中进行查找,其第二个参数传入的是路由下一跳 IP 信息。gEf拜客生活常识网

//file: include/net/arp.h  
extern struct neigh_table arp_tbl;  
static inline struct neighbour *__ipv4_neigh_lookup_noref(  
 struct net_device *dev, u32 key)  
{  
 struct neigh_hash_table *nht = rcu_dereference_bh(arp_tbl.nht);  
  
 //计算 hash 值,加速查找  
 hash_val = arp_hashfn(......);  
 for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);  
   n != NULL;  
   n = rcu_dereference_bh(n->next)) {  
  if (n->dev == dev && *(u32 *)n->primary_key == key)  
   return n;  
 }  
}  
    

相关阅读:

  • 量子子系统的新理论
  • 无法检验的科学是科学吗?
  • 伊朗成功发射太空拖船“萨曼轨道传输器”
  • HUAWEI
  • 纳莱迪人儿童遗骸发现谜团重重
  • 并不是所有的物联网平台都适合系统集成
  • 网络销售怎么去聊客户(网络销售出单难吗)
  • 多益网络怎么样(广州多益网络工作感受)
  • 网络短视频内容审核标准细则发布:短视频节目不得未经
  • 移动网络怎么样(移动300兆相当于电信多少兆)
    • 网站地图 |
    • 声明:登载此文出于传递更多信息之目的,并不意味着赞同其观点或证实其描述。文章内容仅供参考,不做权威认证,如若验证其真实性,请咨询相关权威专业人士。