diff options
Diffstat (limited to 'net/core/skbuff.c')
| -rw-r--r-- | net/core/skbuff.c | 235 | 
1 files changed, 170 insertions, 65 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index c6a6b166f8d..6acbf9e79eb 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -55,6 +55,7 @@  #include <linux/rtnetlink.h>  #include <linux/init.h>  #include <linux/scatterlist.h> +#include <linux/errqueue.h>  #include <net/protocol.h>  #include <net/dst.h> @@ -64,6 +65,7 @@  #include <asm/uaccess.h>  #include <asm/system.h> +#include <trace/skb.h>  #include "kmap_skb.h" @@ -123,6 +125,7 @@ void skb_over_panic(struct sk_buff *skb, int sz, void *here)  	       skb->dev ? skb->dev->name : "<NULL>");  	BUG();  } +EXPORT_SYMBOL(skb_over_panic);  /**   *	skb_under_panic	- 	private function @@ -142,6 +145,7 @@ void skb_under_panic(struct sk_buff *skb, int sz, void *here)  	       skb->dev ? skb->dev->name : "<NULL>");  	BUG();  } +EXPORT_SYMBOL(skb_under_panic);  /* 	Allocate a new skbuff. We do this ourselves so we can fill in a few   *	'private' fields and also do memory statistics to find all the @@ -205,7 +209,9 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,  	shinfo->gso_segs = 0;  	shinfo->gso_type = 0;  	shinfo->ip6_frag_id = 0; +	shinfo->tx_flags.flags = 0;  	shinfo->frag_list = NULL; +	memset(&shinfo->hwtstamps, 0, sizeof(shinfo->hwtstamps));  	if (fclone) {  		struct sk_buff *child = skb + 1; @@ -223,6 +229,7 @@ nodata:  	skb = NULL;  	goto out;  } +EXPORT_SYMBOL(__alloc_skb);  /**   *	__netdev_alloc_skb - allocate an skbuff for rx on a specific device @@ -250,6 +257,7 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev,  	}  	return skb;  } +EXPORT_SYMBOL(__netdev_alloc_skb);  struct page *__netdev_alloc_page(struct net_device *dev, gfp_t gfp_mask)  { @@ -418,6 +426,7 @@ void __kfree_skb(struct sk_buff *skb)  	skb_release_all(skb);  	kfree_skbmem(skb);  } +EXPORT_SYMBOL(__kfree_skb);  /**   *	kfree_skb - free an sk_buff @@ -434,8 +443,30 @@ void kfree_skb(struct sk_buff *skb)  		smp_rmb();  	else if (likely(!atomic_dec_and_test(&skb->users)))  		return; +	trace_kfree_skb(skb, __builtin_return_address(0)); +	__kfree_skb(skb); +} +EXPORT_SYMBOL(kfree_skb); + +/** + *	consume_skb - free an skbuff + *	@skb: buffer to free + * + *	Drop a ref to the buffer and free it if the usage count has hit zero + *	Functions identically to kfree_skb, but kfree_skb assumes that the frame + *	is being dropped after a failure and notes that + */ +void consume_skb(struct sk_buff *skb) +{ +	if (unlikely(!skb)) +		return; +	if (likely(atomic_read(&skb->users) == 1)) +		smp_rmb(); +	else if (likely(!atomic_dec_and_test(&skb->users))) +		return;  	__kfree_skb(skb);  } +EXPORT_SYMBOL(consume_skb);  /**   *	skb_recycle_check - check if skb can be reused for receive @@ -605,6 +636,7 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)  	return __skb_clone(n, skb);  } +EXPORT_SYMBOL(skb_clone);  static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)  { @@ -671,7 +703,7 @@ struct sk_buff *skb_copy(const struct sk_buff *skb, gfp_t gfp_mask)  	copy_skb_header(n, skb);  	return n;  } - +EXPORT_SYMBOL(skb_copy);  /**   *	pskb_copy	-	create copy of an sk_buff with private head. @@ -730,6 +762,7 @@ struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask)  out:  	return n;  } +EXPORT_SYMBOL(pskb_copy);  /**   *	pskb_expand_head - reallocate header of &sk_buff @@ -813,6 +846,7 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,  nodata:  	return -ENOMEM;  } +EXPORT_SYMBOL(pskb_expand_head);  /* Make private copy of skb with writable head and some headroom */ @@ -833,7 +867,7 @@ struct sk_buff *skb_realloc_headroom(struct sk_buff *skb, unsigned int headroom)  	}  	return skb2;  } - +EXPORT_SYMBOL(skb_realloc_headroom);  /**   *	skb_copy_expand	-	copy and expand sk_buff @@ -898,6 +932,7 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb,  	return n;  } +EXPORT_SYMBOL(skb_copy_expand);  /**   *	skb_pad			-	zero pad the tail of an skb @@ -943,6 +978,7 @@ free_skb:  	kfree_skb(skb);  	return err;  } +EXPORT_SYMBOL(skb_pad);  /**   *	skb_put - add data to a buffer @@ -1100,6 +1136,7 @@ done:  	return 0;  } +EXPORT_SYMBOL(___pskb_trim);  /**   *	__pskb_pull_tail - advance tail of skb header @@ -1193,8 +1230,7 @@ unsigned char *__pskb_pull_tail(struct sk_buff *skb, int delta)  					insp = list;  				}  				if (!pskb_pull(list, eat)) { -					if (clone) -						kfree_skb(clone); +					kfree_skb(clone);  					return NULL;  				}  				break; @@ -1238,6 +1274,7 @@ pull_pages:  	return skb_tail_pointer(skb);  } +EXPORT_SYMBOL(__pskb_pull_tail);  /* Copy some data bits from skb to kernel buffer. */ @@ -1315,6 +1352,7 @@ int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len)  fault:  	return -EFAULT;  } +EXPORT_SYMBOL(skb_copy_bits);  /*   * Callback from splice_to_pipe(), if we need to release some pages @@ -1325,14 +1363,39 @@ static void sock_spd_release(struct splice_pipe_desc *spd, unsigned int i)  	put_page(spd->pages[i]);  } -static inline struct page *linear_to_page(struct page *page, unsigned int len, -					  unsigned int offset) +static inline struct page *linear_to_page(struct page *page, unsigned int *len, +					  unsigned int *offset, +					  struct sk_buff *skb)  { -	struct page *p = alloc_pages(GFP_KERNEL, 0); +	struct sock *sk = skb->sk; +	struct page *p = sk->sk_sndmsg_page; +	unsigned int off; -	if (!p) -		return NULL; -	memcpy(page_address(p) + offset, page_address(page) + offset, len); +	if (!p) { +new_page: +		p = sk->sk_sndmsg_page = alloc_pages(sk->sk_allocation, 0); +		if (!p) +			return NULL; + +		off = sk->sk_sndmsg_off = 0; +		/* hold one ref to this page until it's full */ +	} else { +		unsigned int mlen; + +		off = sk->sk_sndmsg_off; +		mlen = PAGE_SIZE - off; +		if (mlen < 64 && mlen < *len) { +			put_page(p); +			goto new_page; +		} + +		*len = min_t(unsigned int, *len, mlen); +	} + +	memcpy(page_address(p) + off, page_address(page) + *offset, *len); +	sk->sk_sndmsg_off += *len; +	*offset = off; +	get_page(p);  	return p;  } @@ -1341,21 +1404,21 @@ static inline struct page *linear_to_page(struct page *page, unsigned int len,   * Fill page/offset/length into spd, if it can hold more pages.   */  static inline int spd_fill_page(struct splice_pipe_desc *spd, struct page *page, -				unsigned int len, unsigned int offset, +				unsigned int *len, unsigned int offset,  				struct sk_buff *skb, int linear)  {  	if (unlikely(spd->nr_pages == PIPE_BUFFERS))  		return 1;  	if (linear) { -		page = linear_to_page(page, len, offset); +		page = linear_to_page(page, len, &offset, skb);  		if (!page)  			return 1;  	} else  		get_page(page);  	spd->pages[spd->nr_pages] = page; -	spd->partial[spd->nr_pages].len = len; +	spd->partial[spd->nr_pages].len = *len;  	spd->partial[spd->nr_pages].offset = offset;  	spd->nr_pages++; @@ -1365,8 +1428,13 @@ static inline int spd_fill_page(struct splice_pipe_desc *spd, struct page *page,  static inline void __segment_seek(struct page **page, unsigned int *poff,  				  unsigned int *plen, unsigned int off)  { +	unsigned long n; +  	*poff += off; -	*page += *poff / PAGE_SIZE; +	n = *poff / PAGE_SIZE; +	if (n) +		*page = nth_page(*page, n); +  	*poff = *poff % PAGE_SIZE;  	*plen -= off;  } @@ -1397,7 +1465,7 @@ static inline int __splice_segment(struct page *page, unsigned int poff,  		/* the linear region may spread across several pages  */  		flen = min_t(unsigned int, flen, PAGE_SIZE - poff); -		if (spd_fill_page(spd, page, flen, poff, skb, linear)) +		if (spd_fill_page(spd, page, &flen, poff, skb, linear))  			return 1;  		__segment_seek(&page, &poff, &plen, flen); @@ -1590,7 +1658,6 @@ int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len)  fault:  	return -EFAULT;  } -  EXPORT_SYMBOL(skb_store_bits);  /* Checksum skb data. */ @@ -1667,6 +1734,7 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset,  	return csum;  } +EXPORT_SYMBOL(skb_checksum);  /* Both of above in one bottle. */ @@ -1748,6 +1816,7 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,  	BUG_ON(len);  	return csum;  } +EXPORT_SYMBOL(skb_copy_and_csum_bits);  void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to)  { @@ -1774,6 +1843,7 @@ void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to)  		*((__sum16 *)(to + csstuff)) = csum_fold(csum);  	}  } +EXPORT_SYMBOL(skb_copy_and_csum_dev);  /**   *	skb_dequeue - remove from the head of the queue @@ -1794,6 +1864,7 @@ struct sk_buff *skb_dequeue(struct sk_buff_head *list)  	spin_unlock_irqrestore(&list->lock, flags);  	return result;  } +EXPORT_SYMBOL(skb_dequeue);  /**   *	skb_dequeue_tail - remove from the tail of the queue @@ -1813,6 +1884,7 @@ struct sk_buff *skb_dequeue_tail(struct sk_buff_head *list)  	spin_unlock_irqrestore(&list->lock, flags);  	return result;  } +EXPORT_SYMBOL(skb_dequeue_tail);  /**   *	skb_queue_purge - empty a list @@ -1828,6 +1900,7 @@ void skb_queue_purge(struct sk_buff_head *list)  	while ((skb = skb_dequeue(list)) != NULL)  		kfree_skb(skb);  } +EXPORT_SYMBOL(skb_queue_purge);  /**   *	skb_queue_head - queue a buffer at the list head @@ -1848,6 +1921,7 @@ void skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk)  	__skb_queue_head(list, newsk);  	spin_unlock_irqrestore(&list->lock, flags);  } +EXPORT_SYMBOL(skb_queue_head);  /**   *	skb_queue_tail - queue a buffer at the list tail @@ -1868,6 +1942,7 @@ void skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk)  	__skb_queue_tail(list, newsk);  	spin_unlock_irqrestore(&list->lock, flags);  } +EXPORT_SYMBOL(skb_queue_tail);  /**   *	skb_unlink	-	remove a buffer from a list @@ -1887,6 +1962,7 @@ void skb_unlink(struct sk_buff *skb, struct sk_buff_head *list)  	__skb_unlink(skb, list);  	spin_unlock_irqrestore(&list->lock, flags);  } +EXPORT_SYMBOL(skb_unlink);  /**   *	skb_append	-	append a buffer @@ -1906,7 +1982,7 @@ void skb_append(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head  	__skb_queue_after(list, old, newsk);  	spin_unlock_irqrestore(&list->lock, flags);  } - +EXPORT_SYMBOL(skb_append);  /**   *	skb_insert	-	insert a buffer @@ -1928,6 +2004,7 @@ void skb_insert(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head  	__skb_insert(newsk, old->prev, old, list);  	spin_unlock_irqrestore(&list->lock, flags);  } +EXPORT_SYMBOL(skb_insert);  static inline void skb_split_inside_header(struct sk_buff *skb,  					   struct sk_buff* skb1, @@ -2006,6 +2083,7 @@ void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len)  	else		/* Second chunk has no header, nothing to copy. */  		skb_split_no_header(skb, skb1, len, pos);  } +EXPORT_SYMBOL(skb_split);  /* Shifting from/to a cloned skb is a no-go.   * @@ -2168,6 +2246,7 @@ void skb_prepare_seq_read(struct sk_buff *skb, unsigned int from,  	st->frag_idx = st->stepped_offset = 0;  	st->frag_data = NULL;  } +EXPORT_SYMBOL(skb_prepare_seq_read);  /**   * skb_seq_read - Sequentially read skb data @@ -2255,6 +2334,7 @@ next_skb:  	return 0;  } +EXPORT_SYMBOL(skb_seq_read);  /**   * skb_abort_seq_read - Abort a sequential read of skb data @@ -2268,6 +2348,7 @@ void skb_abort_seq_read(struct skb_seq_state *st)  	if (st->frag_data)  		kunmap_skb_frag(st->frag_data);  } +EXPORT_SYMBOL(skb_abort_seq_read);  #define TS_SKB_CB(state)	((struct skb_seq_state *) &((state)->cb)) @@ -2310,6 +2391,7 @@ unsigned int skb_find_text(struct sk_buff *skb, unsigned int from,  	ret = textsearch_find(config, state);  	return (ret <= to - from ? ret : UINT_MAX);  } +EXPORT_SYMBOL(skb_find_text);  /**   * skb_append_datato_frags: - append the user data to a skb @@ -2382,6 +2464,7 @@ int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb,  	return 0;  } +EXPORT_SYMBOL(skb_append_datato_frags);  /**   *	skb_pull_rcsum - pull skb and update receive checksum @@ -2569,7 +2652,6 @@ err:  	}  	return ERR_PTR(err);  } -  EXPORT_SYMBOL_GPL(skb_segment);  int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) @@ -2577,17 +2659,23 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)  	struct sk_buff *p = *head;  	struct sk_buff *nskb;  	unsigned int headroom; -	unsigned int hlen = p->data - skb_mac_header(p); -	unsigned int len = skb->len; +	unsigned int len = skb_gro_len(skb); -	if (hlen + p->len + len >= 65536) +	if (p->len + len >= 65536)  		return -E2BIG;  	if (skb_shinfo(p)->frag_list)  		goto merge; -	else if (!skb_headlen(p) && !skb_headlen(skb) && -		 skb_shinfo(p)->nr_frags + skb_shinfo(skb)->nr_frags < -		 MAX_SKB_FRAGS) { +	else if (skb_headlen(skb) <= skb_gro_offset(skb)) { +		if (skb_shinfo(p)->nr_frags + skb_shinfo(skb)->nr_frags > +		    MAX_SKB_FRAGS) +			return -E2BIG; + +		skb_shinfo(skb)->frags[0].page_offset += +			skb_gro_offset(skb) - skb_headlen(skb); +		skb_shinfo(skb)->frags[0].size -= +			skb_gro_offset(skb) - skb_headlen(skb); +  		memcpy(skb_shinfo(p)->frags + skb_shinfo(p)->nr_frags,  		       skb_shinfo(skb)->frags,  		       skb_shinfo(skb)->nr_frags * sizeof(skb_frag_t)); @@ -2604,7 +2692,7 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)  	}  	headroom = skb_headroom(p); -	nskb = netdev_alloc_skb(p->dev, headroom); +	nskb = netdev_alloc_skb(p->dev, headroom + skb_gro_offset(p));  	if (unlikely(!nskb))  		return -ENOMEM; @@ -2612,12 +2700,15 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)  	nskb->mac_len = p->mac_len;  	skb_reserve(nskb, headroom); +	__skb_put(nskb, skb_gro_offset(p)); -	skb_set_mac_header(nskb, -hlen); +	skb_set_mac_header(nskb, skb_mac_header(p) - p->data);  	skb_set_network_header(nskb, skb_network_offset(p));  	skb_set_transport_header(nskb, skb_transport_offset(p)); -	memcpy(skb_mac_header(nskb), skb_mac_header(p), hlen); +	__skb_pull(p, skb_gro_offset(p)); +	memcpy(skb_mac_header(nskb), skb_mac_header(p), +	       p->data - skb_mac_header(p));  	*NAPI_GRO_CB(nskb) = *NAPI_GRO_CB(p);  	skb_shinfo(nskb)->frag_list = p; @@ -2636,6 +2727,17 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)  	p = nskb;  merge: +	if (skb_gro_offset(skb) > skb_headlen(skb)) { +		skb_shinfo(skb)->frags[0].page_offset += +			skb_gro_offset(skb) - skb_headlen(skb); +		skb_shinfo(skb)->frags[0].size -= +			skb_gro_offset(skb) - skb_headlen(skb); +		skb_gro_reset_offset(skb); +		skb_gro_pull(skb, skb_headlen(skb)); +	} + +	__skb_pull(skb, skb_gro_offset(skb)); +  	p->prev->next = skb;  	p->prev = skb;  	skb_header_release(skb); @@ -2747,6 +2849,7 @@ int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int le  	return nsg;  } +EXPORT_SYMBOL_GPL(skb_to_sgvec);  /**   *	skb_cow_data - Check that a socket buffer's data buffers are writable @@ -2856,6 +2959,45 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer)  	return elt;  } +EXPORT_SYMBOL_GPL(skb_cow_data); + +void skb_tstamp_tx(struct sk_buff *orig_skb, +		struct skb_shared_hwtstamps *hwtstamps) +{ +	struct sock *sk = orig_skb->sk; +	struct sock_exterr_skb *serr; +	struct sk_buff *skb; +	int err; + +	if (!sk) +		return; + +	skb = skb_clone(orig_skb, GFP_ATOMIC); +	if (!skb) +		return; + +	if (hwtstamps) { +		*skb_hwtstamps(skb) = +			*hwtstamps; +	} else { +		/* +		 * no hardware time stamps available, +		 * so keep the skb_shared_tx and only +		 * store software time stamp +		 */ +		skb->tstamp = ktime_get_real(); +	} + +	serr = SKB_EXT_ERR(skb); +	memset(serr, 0, sizeof(*serr)); +	serr->ee.ee_errno = ENOMSG; +	serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING; +	err = sock_queue_err_skb(sk, skb); +	if (err) +		kfree_skb(skb); +} +EXPORT_SYMBOL_GPL(skb_tstamp_tx); +  /**   * skb_partial_csum_set - set up and verify partial csum values for packet @@ -2884,6 +3026,7 @@ bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off)  	skb->csum_offset = off;  	return true;  } +EXPORT_SYMBOL_GPL(skb_partial_csum_set);  void __skb_warn_lro_forwarding(const struct sk_buff *skb)  { @@ -2891,42 +3034,4 @@ void __skb_warn_lro_forwarding(const struct sk_buff *skb)  		pr_warning("%s: received packets cannot be forwarded"  			   " while LRO is enabled\n", skb->dev->name);  } - -EXPORT_SYMBOL(___pskb_trim); -EXPORT_SYMBOL(__kfree_skb); -EXPORT_SYMBOL(kfree_skb); -EXPORT_SYMBOL(__pskb_pull_tail); -EXPORT_SYMBOL(__alloc_skb); -EXPORT_SYMBOL(__netdev_alloc_skb); -EXPORT_SYMBOL(pskb_copy); -EXPORT_SYMBOL(pskb_expand_head); -EXPORT_SYMBOL(skb_checksum); -EXPORT_SYMBOL(skb_clone); -EXPORT_SYMBOL(skb_copy); -EXPORT_SYMBOL(skb_copy_and_csum_bits); -EXPORT_SYMBOL(skb_copy_and_csum_dev); -EXPORT_SYMBOL(skb_copy_bits); -EXPORT_SYMBOL(skb_copy_expand); -EXPORT_SYMBOL(skb_over_panic); -EXPORT_SYMBOL(skb_pad); -EXPORT_SYMBOL(skb_realloc_headroom); -EXPORT_SYMBOL(skb_under_panic); -EXPORT_SYMBOL(skb_dequeue); -EXPORT_SYMBOL(skb_dequeue_tail); -EXPORT_SYMBOL(skb_insert); -EXPORT_SYMBOL(skb_queue_purge); -EXPORT_SYMBOL(skb_queue_head); -EXPORT_SYMBOL(skb_queue_tail); -EXPORT_SYMBOL(skb_unlink); -EXPORT_SYMBOL(skb_append); -EXPORT_SYMBOL(skb_split); -EXPORT_SYMBOL(skb_prepare_seq_read); -EXPORT_SYMBOL(skb_seq_read); -EXPORT_SYMBOL(skb_abort_seq_read); -EXPORT_SYMBOL(skb_find_text); -EXPORT_SYMBOL(skb_append_datato_frags);  EXPORT_SYMBOL(__skb_warn_lro_forwarding); - -EXPORT_SYMBOL_GPL(skb_to_sgvec); -EXPORT_SYMBOL_GPL(skb_cow_data); -EXPORT_SYMBOL_GPL(skb_partial_csum_set);  | 
