【Linux4.1.12源码分析】二层报文发送之GSO条件判断
2016-09-29 23:45
741 查看
4.1.12内核中,GSO报文的判断和分段的入口函数是validate_xmit_skb,其中使用netif_needs_gso用来判断软件是否要进行GSO分段,skb_gso_segment实现报文的GSO分段,本篇重点讲述GSO分段的判断条件,即netif_needs_gso相关函数。
1、netif_needs_gso函数
从上面的函数可以判断是否需要进行GSO分段,主要 两个参数features(硬件支持的特性)和skb报文。主要判断条件是features是否包含skb->gso_type。那么我们来看下features是怎么得到的,其实是通过netif_skb_features得到的。
netif_skb_features函数
判断GSO分段的条件基本搞清楚了,下一篇将分析报文GSO分段是如何实现的。
1、netif_needs_gso函数
static inline bool netif_needs_gso(struct sk_buff *skb, netdev_features_t features) { return skb_is_gso(skb) && (!skb_gso_ok(skb, features) || //skb 为gso报文,且feature不包含skb->gso_type 或者 //skb 为gso报文,且skb_ipsummed不为CHECKSUM_PARTIAL和CHECKSUM_UNNECESSARY unlikely((skb->ip_summed != CHECKSUM_PARTIAL) && (skb->ip_summed != CHECKSUM_UNNECESSARY))); }2、skb_gso_ok函数
static inline bool skb_gso_ok(struct sk_buff *skb, netdev_features_t features) { return net_gso_ok(features, skb_shinfo(skb)->gso_type) && //feature包含gso_type 并且skb没有frag_list或者feature包含NETIF_F_FRAGLIST (!skb_has_frag_list(skb) || (features & NETIF_F_FRAGLIST)); }3、net_gso_ok函数
static inline bool net_gso_ok(netdev_features_t features, int gso_type) { netdev_features_t feature = gso_type << NETIF_F_GSO_SHIFT; /* check flags correspondence */ BUILD_BUG_ON(SKB_GSO_TCPV4 != (NETIF_F_TSO >> NETIF_F_GSO_SHIFT)); BUILD_BUG_ON(SKB_GSO_UDP != (NETIF_F_UFO >> NETIF_F_GSO_SHIFT)); BUILD_BUG_ON(SKB_GSO_DODGY != (NETIF_F_GSO_ROBUST >> NETIF_F_GSO_SHIFT)); BUILD_BUG_ON(SKB_GSO_TCP_ECN != (NETIF_F_TSO_ECN >> NETIF_F_GSO_SHIFT)); BUILD_BUG_ON(SKB_GSO_TCPV6 != (NETIF_F_TSO6 >> NETIF_F_GSO_SHIFT)); BUILD_BUG_ON(SKB_GSO_FCOE != (NETIF_F_FSO >> NETIF_F_GSO_SHIFT)); BUILD_BUG_ON(SKB_GSO_GRE != (NETIF_F_GSO_GRE >> NETIF_F_GSO_SHIFT)); BUILD_BUG_ON(SKB_GSO_GRE_CSUM != (NETIF_F_GSO_GRE_CSUM >> NETIF_F_GSO_SHIFT)); BUILD_BUG_ON(SKB_GSO_IPIP != (NETIF_F_GSO_IPIP >> NETIF_F_GSO_SHIFT)); BUILD_BUG_ON(SKB_GSO_SIT != (NETIF_F_GSO_SIT >> NETIF_F_GSO_SHIFT)); BUILD_BUG_ON(SKB_GSO_UDP_TUNNEL != (NETIF_F_GSO_UDP_TUNNEL >> NETIF_F_GSO_SHIFT)); BUILD_BUG_ON(SKB_GSO_UDP_TUNNEL_CSUM != (NETIF_F_GSO_UDP_TUNNEL_CSUM >> NETIF_F_GSO_SHIFT)); BUILD_BUG_ON(SKB_GSO_TUNNEL_REMCSUM != (NETIF_F_GSO_TUNNEL_REMCSUM >> NETIF_F_GSO_SHIFT)); return (features & feature) == feature;<span style="white-space:pre"> </span>//features 包含feature }
从上面的函数可以判断是否需要进行GSO分段,主要 两个参数features(硬件支持的特性)和skb报文。主要判断条件是features是否包含skb->gso_type。那么我们来看下features是怎么得到的,其实是通过netif_skb_features得到的。
netif_skb_features函数
netdev_features_t netif_skb_features(struct sk_buff *skb) { struct net_device *dev = skb->dev; netdev_features_t features = dev->features; //获取设备的features u16 gso_segs = skb_shinfo(skb)->gso_segs; if (gso_segs > dev->gso_max_segs || gso_segs < dev->gso_min_segs) features &= ~NETIF_F_GSO_MASK; //如果gso_segs不在规定范围内,则去掉NETIF_F_GSO_MASK标记 /* If encapsulation offload request, verify we are testing * hardware encapsulation features instead of standard * features for the netdev */ if (skb->encapsulation) features &= dev->hw_enc_features; //如果是封装报文,则feature需要和hw_enc_features取交集, 主流设备均不支持gso offload能力 if (skb_vlan_tagged(skb)) //如果是vlan报文,刷新feature值 features = netdev_intersect_features(features, //features与vlan_feature取交集 dev->vlan_features | NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX); if (dev->netdev_ops->ndo_features_check) features &= dev->netdev_ops->ndo_features_check(skb, dev, features); else features &= dflt_features_check(skb, dev, features); //刷新vlan feature,最终会调用netdev_intersect_features函数 return harmonize_features(skb, features); //更新mpls feature 和csum feature }netdev_intersect_features函数
static inline netdev_features_t netdev_intersect_features(netdev_features_t f1, netdev_features_t f2) { if (f1 & NETIF_F_GEN_CSUM) f1 |= (NETIF_F_ALL_CSUM & ~NETIF_F_GEN_CSUM); //添加NETIF_F_V4_CSUM | NETIF_F_V6_CSUM 标记 if (f2 & NETIF_F_GEN_CSUM) f2 |= (NETIF_F_ALL_CSUM & ~NETIF_F_GEN_CSUM); //添加NETIF_F_V4_CSUM | NETIF_F_V6_CSUM 标记 f1 &= f2; //取交集 if (f1 & NETIF_F_GEN_CSUM) f1 &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_GEN_CSUM); //删除NETIF_F_V4_CSUM | NETIF_F_V6_CSUM 标记 return f1; }harmonize_features函数
static netdev_features_t harmonize_features(struct sk_buff *skb, netdev_features_t features) { int tmp; __be16 type; type = skb_network_protocol(skb, &tmp); features = net_mpls_features(skb, features, type); //mpls feature更新 if (skb->ip_summed != CHECKSUM_NONE && !can_checksum_protocol(features, type)) { features &= ~NETIF_F_ALL_CSUM; //去掉NETIF_F_ALL_CSUM标记 } else if (illegal_highdma(skb->dev, skb)) { features &= ~NETIF_F_SG; //去掉NETIF_F_SG标记 } return features; }
判断GSO分段的条件基本搞清楚了,下一篇将分析报文GSO分段是如何实现的。
相关文章推荐
- 【Linux4.1.12源码分析】二层报文发送之报文GSO分段(skb_segment)
- 【Linux4.1.12源码分析】二层报文发送之报文GSO分段(MAC层)
- 【Linux4.1.12源码分析】二层报文发送之报文GSO分段(UDP)
- 【Linux4.1.12源码分析】二层报文发送之报文GSO分段(TCP)
- 【Linux4.1.12源码分析】二层报文发送之报文GSO分段(IP层)
- 【Linux4.1.12源码分析】二层报文发送之dev_queue_xmit
- 【Linux4.1.12源码分析】二层报文发送之qdisc实现分析
- 【Linux4.1.12源码分析】vxlan报文发送之udp_tunnel_xmit_skb
- 【Linux4.1.12源码分析】vxlan报文发送之iptunnel_xmit
- 【Linux4.1.12源码分析】IP层报文发送之ip_output
- 【Linux4.1.12源码分析】IP层报文发送之ip_local_out
- 【Linux4.1.12源码分析】IP层报文发送之ip_local_out
- 【Linux4.1.12源码分析】协议栈报文接收之IP层处理分析(ip_local_deliver)
- 【Linux4.1.12源码分析】协议栈报文接收之IP层处理分析(ip_forward)
- HBase源码分析之MemStore的flush发起时机、判断条件等详情
- 【Linux4.1.12源码分析】协议栈gro收包之IP层处理
- 【Linux4.1.12源码分析】协议栈gro收包之UDP处理
- 【Linux4.1.12源码分析】收包软中断和NAPI
- 【Linux4.1.12源码分析】VXLAN报文内核协议栈处理
- 【Linux4.1.12源码分析】AF_INET raw socket实现原理分析