aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/skbuff.c
diff options
context:
space:
mode:
authorAnanda Raju <ananda.raju@neterion.com>2005-10-18 18:46:41 -0400
committerArnaldo Carvalho de Melo <acme@mandriva.com>2005-10-28 14:30:00 -0400
commite89e9cf539a28df7d0eb1d0a545368e9920b34ac (patch)
treeaae6a825f351ce931fcd30f1a865ebe65227c4b8 /net/core/skbuff.c
parentde5144164f6242ccfa8c9b64eec570564f5eaf14 (diff)
[IPv4/IPv6]: UFO Scatter-gather approach
Attached is kernel patch for UDP Fragmentation Offload (UFO) feature. 1. This patch incorporate the review comments by Jeff Garzik. 2. Renamed USO as UFO (UDP Fragmentation Offload) 3. udp sendfile support with UFO This patches uses scatter-gather feature of skb to generate large UDP datagram. Below is a "how-to" on changes required in network device driver to use the UFO interface. UDP Fragmentation Offload (UFO) Interface: ------------------------------------------- UFO is a feature wherein the Linux kernel network stack will offload the IP fragmentation functionality of large UDP datagram to hardware. This will reduce the overhead of stack in fragmenting the large UDP datagram to MTU sized packets 1) Drivers indicate their capability of UFO using dev->features |= NETIF_F_UFO | NETIF_F_HW_CSUM | NETIF_F_SG NETIF_F_HW_CSUM is required for UFO over ipv6. 2) UFO packet will be submitted for transmission using driver xmit routine. UFO packet will have a non-zero value for "skb_shinfo(skb)->ufo_size" skb_shinfo(skb)->ufo_size will indicate the length of data part in each IP fragment going out of the adapter after IP fragmentation by hardware. skb->data will contain MAC/IP/UDP header and skb_shinfo(skb)->frags[] contains the data payload. The skb->ip_summed will be set to CHECKSUM_HW indicating that hardware has to do checksum calculation. Hardware should compute the UDP checksum of complete datagram and also ip header checksum of each fragmented IP packet. For IPV6 the UFO provides the fragment identification-id in skb_shinfo(skb)->ip6_frag_id. The adapter should use this ID for generating IPv6 fragments. Signed-off-by: Ananda Raju <ananda.raju@neterion.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> (forwarded) Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Diffstat (limited to 'net/core/skbuff.c')
-rw-r--r--net/core/skbuff.c75
1 files changed, 75 insertions, 0 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index ef9d46b91eb9..95501e40100e 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -176,6 +176,8 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
176 skb_shinfo(skb)->tso_size = 0; 176 skb_shinfo(skb)->tso_size = 0;
177 skb_shinfo(skb)->tso_segs = 0; 177 skb_shinfo(skb)->tso_segs = 0;
178 skb_shinfo(skb)->frag_list = NULL; 178 skb_shinfo(skb)->frag_list = NULL;
179 skb_shinfo(skb)->ufo_size = 0;
180 skb_shinfo(skb)->ip6_frag_id = 0;
179out: 181out:
180 return skb; 182 return skb;
181nodata: 183nodata:
@@ -1696,6 +1698,78 @@ unsigned int skb_find_text(struct sk_buff *skb, unsigned int from,
1696 return textsearch_find(config, state); 1698 return textsearch_find(config, state);
1697} 1699}
1698 1700
1701/**
1702 * skb_append_datato_frags: - append the user data to a skb
1703 * @sk: sock structure
1704 * @skb: skb structure to be appened with user data.
1705 * @getfrag: call back function to be used for getting the user data
1706 * @from: pointer to user message iov
1707 * @length: length of the iov message
1708 *
1709 * Description: This procedure append the user data in the fragment part
1710 * of the skb if any page alloc fails user this procedure returns -ENOMEM
1711 */
1712int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb,
1713 int getfrag(void *from, char *to, int offset,
1714 int len, int odd, struct sk_buff *skb),
1715 void *from, int length)
1716{
1717 int frg_cnt = 0;
1718 skb_frag_t *frag = NULL;
1719 struct page *page = NULL;
1720 int copy, left;
1721 int offset = 0;
1722 int ret;
1723
1724 do {
1725 /* Return error if we don't have space for new frag */
1726 frg_cnt = skb_shinfo(skb)->nr_frags;
1727 if (frg_cnt >= MAX_SKB_FRAGS)
1728 return -EFAULT;
1729
1730 /* allocate a new page for next frag */
1731 page = alloc_pages(sk->sk_allocation, 0);
1732
1733 /* If alloc_page fails just return failure and caller will
1734 * free previous allocated pages by doing kfree_skb()
1735 */
1736 if (page == NULL)
1737 return -ENOMEM;
1738
1739 /* initialize the next frag */
1740 sk->sk_sndmsg_page = page;
1741 sk->sk_sndmsg_off = 0;
1742 skb_fill_page_desc(skb, frg_cnt, page, 0, 0);
1743 skb->truesize += PAGE_SIZE;
1744 atomic_add(PAGE_SIZE, &sk->sk_wmem_alloc);
1745
1746 /* get the new initialized frag */
1747 frg_cnt = skb_shinfo(skb)->nr_frags;
1748 frag = &skb_shinfo(skb)->frags[frg_cnt - 1];
1749
1750 /* copy the user data to page */
1751 left = PAGE_SIZE - frag->page_offset;
1752 copy = (length > left)? left : length;
1753
1754 ret = getfrag(from, (page_address(frag->page) +
1755 frag->page_offset + frag->size),
1756 offset, copy, 0, skb);
1757 if (ret < 0)
1758 return -EFAULT;
1759
1760 /* copy was successful so update the size parameters */
1761 sk->sk_sndmsg_off += copy;
1762 frag->size += copy;
1763 skb->len += copy;
1764 skb->data_len += copy;
1765 offset += copy;
1766 length -= copy;
1767
1768 } while (length > 0);
1769
1770 return 0;
1771}
1772
1699void __init skb_init(void) 1773void __init skb_init(void)
1700{ 1774{
1701 skbuff_head_cache = kmem_cache_create("skbuff_head_cache", 1775 skbuff_head_cache = kmem_cache_create("skbuff_head_cache",
@@ -1747,3 +1821,4 @@ EXPORT_SYMBOL(skb_prepare_seq_read);
1747EXPORT_SYMBOL(skb_seq_read); 1821EXPORT_SYMBOL(skb_seq_read);
1748EXPORT_SYMBOL(skb_abort_seq_read); 1822EXPORT_SYMBOL(skb_abort_seq_read);
1749EXPORT_SYMBOL(skb_find_text); 1823EXPORT_SYMBOL(skb_find_text);
1824EXPORT_SYMBOL(skb_append_datato_frags);