【Linux4.1.12源码分析】二层报文发送之GSO条件判断

来源:互联网 发布:网络授权书制作免费 编辑:程序博客网 时间:2024/05/17 23:05

4.1.12内核中,GSO报文的判断和分段的入口函数是validate_xmit_skb,其中使用netif_needs_gso用来判断软件是否要进行GSO分段,skb_gso_segment实现报文的GSO分段,本篇重点讲述GSO分段的判断条件,即netif_needs_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_UNNECESSARYunlikely((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;//获取设备的featuresu16 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);elsefeatures &= 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分段是如何实现的。

0 0
原创粉丝点击