diff options
Diffstat (limited to 'net/core/skbuff.c')
| -rw-r--r-- | net/core/skbuff.c | 67 | 
1 files changed, 54 insertions, 13 deletions
| diff --git a/net/core/skbuff.c b/net/core/skbuff.c index dca1fed0d7da..4a71d78d0c6a 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -383,6 +383,8 @@ static void *__netdev_alloc_frag(unsigned int fragsz, gfp_t gfp_mask)   */  void *netdev_alloc_frag(unsigned int fragsz)  { +	fragsz = SKB_DATA_ALIGN(fragsz); +  	return __netdev_alloc_frag(fragsz, GFP_ATOMIC | __GFP_COLD);  }  EXPORT_SYMBOL(netdev_alloc_frag); @@ -396,6 +398,8 @@ static void *__napi_alloc_frag(unsigned int fragsz, gfp_t gfp_mask)  void *napi_alloc_frag(unsigned int fragsz)  { +	fragsz = SKB_DATA_ALIGN(fragsz); +  	return __napi_alloc_frag(fragsz, GFP_ATOMIC | __GFP_COLD);  }  EXPORT_SYMBOL(napi_alloc_frag); @@ -4469,37 +4473,74 @@ unsigned int skb_gso_transport_seglen(const struct sk_buff *skb)  EXPORT_SYMBOL_GPL(skb_gso_transport_seglen);  /** - * skb_gso_validate_mtu - Return in case such skb fits a given MTU + * skb_gso_size_check - check the skb size, considering GSO_BY_FRAGS   * - * @skb: GSO skb - * @mtu: MTU to validate against + * There are a couple of instances where we have a GSO skb, and we + * want to determine what size it would be after it is segmented.   * - * skb_gso_validate_mtu validates if a given skb will fit a wanted MTU - * once split. + * We might want to check: + * -    L3+L4+payload size (e.g. IP forwarding) + * - L2+L3+L4+payload size (e.g. sanity check before passing to driver) + * + * This is a helper to do that correctly considering GSO_BY_FRAGS. + * + * @seg_len: The segmented length (from skb_gso_*_seglen). In the + *           GSO_BY_FRAGS case this will be [header sizes + GSO_BY_FRAGS]. + * + * @max_len: The maximum permissible length. + * + * Returns true if the segmented length <= max length.   */ -bool skb_gso_validate_mtu(const struct sk_buff *skb, unsigned int mtu) -{ +static inline bool skb_gso_size_check(const struct sk_buff *skb, +				      unsigned int seg_len, +				      unsigned int max_len) {  	const struct skb_shared_info *shinfo = skb_shinfo(skb);  	const struct sk_buff *iter; -	unsigned int hlen; - -	hlen = skb_gso_network_seglen(skb);  	if (shinfo->gso_size != GSO_BY_FRAGS) -		return hlen <= mtu; +		return seg_len <= max_len;  	/* Undo this so we can re-use header sizes */ -	hlen -= GSO_BY_FRAGS; +	seg_len -= GSO_BY_FRAGS;  	skb_walk_frags(skb, iter) { -		if (hlen + skb_headlen(iter) > mtu) +		if (seg_len + skb_headlen(iter) > max_len)  			return false;  	}  	return true;  } + +/** + * skb_gso_validate_mtu - Return in case such skb fits a given MTU + * + * @skb: GSO skb + * @mtu: MTU to validate against + * + * skb_gso_validate_mtu validates if a given skb will fit a wanted MTU + * once split. + */ +bool skb_gso_validate_mtu(const struct sk_buff *skb, unsigned int mtu) +{ +	return skb_gso_size_check(skb, skb_gso_network_seglen(skb), mtu); +}  EXPORT_SYMBOL_GPL(skb_gso_validate_mtu); +/** + * skb_gso_validate_mac_len - Will a split GSO skb fit in a given length? + * + * @skb: GSO skb + * @len: length to validate against + * + * skb_gso_validate_mac_len validates if a given skb will fit a wanted + * length once split, including L2, L3 and L4 headers and the payload. + */ +bool skb_gso_validate_mac_len(const struct sk_buff *skb, unsigned int len) +{ +	return skb_gso_size_check(skb, skb_gso_mac_seglen(skb), len); +} +EXPORT_SYMBOL_GPL(skb_gso_validate_mac_len); +  static struct sk_buff *skb_reorder_vlan_header(struct sk_buff *skb)  {  	int mac_len; | 
