Hi, This patch enables TSO over IPv6. Currently Linux network stacks restricts TSO over IPv6 by clearing of the NETIF_F_TSO bit from "dev->features". This patch will remove this restriction.
This patch will introduce a new flag NETIF_F_TSO6 which will be used to check whether device supports TSO over IPv6. If device support TSO over IPv6 then we don't clear of NETIF_F_TSO and which will make the TCP layer to create TSO packets. Any device supporting TSO over IPv6 will set NETIF_F_TSO6 flag in "dev->features" along with NETIF_F_TSO. In case when user disables TSO using ethtool, NETIF_F_TSO will get cleared from "dev->features". So even if we have NETIF_F_TSO6 we don't get TSO packets created by TCP layer. SKB_GSO_TCPV4 renamed to SKB_GSO_TCP to make it generic GSO packet. SKB_GSO_UDPV4 renamed to SKB_GSO_UDP as UFO is not a IPv4 feature. UFO is supported over IPv6 also The following table shows there is significant improvement in throughput with normal frames and CPU usage for both normal and jumbo. -------------------------------------------------- | | 1500 | 9600 | | ------------------|-------------------| | | thru CPU | thru CPU | -------------------------------------------------- | TSO OFF | 2.00 5.5% id | 5.66 20.0% id | -------------------------------------------------- | TSO ON | 2.63 78.0 id | 5.67 39.0% id | -------------------------------------------------- Please review the patch. Signed-off-by: Ananda Raju <[EMAIL PROTECTED]> --- diff -upNr netdev.org/drivers/net/s2io.c netdev.ipv6_tso/drivers/net/s2io.c --- netdev.org/drivers/net/s2io.c 2006-06-27 07:30:36.000000000 -0700 +++ netdev.ipv6_tso/drivers/net/s2io.c 2006-06-27 07:38:48.000000000 -0700 @@ -3960,7 +3960,7 @@ static int s2io_xmit(struct sk_buff *skb txdp->Control_2 = 0; #ifdef NETIF_F_TSO mss = skb_shinfo(skb)->gso_size; - if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV4) { + if (skb_shinfo(skb)->gso_type == SKB_GSO_TCP) { txdp->Control_1 |= TXD_TCP_LSO_EN; txdp->Control_1 |= TXD_TCP_LSO_MSS(mss); } @@ -3980,7 +3980,7 @@ static int s2io_xmit(struct sk_buff *skb } frg_len = skb->len - skb->data_len; - if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4) { + if (skb_shinfo(skb)->gso_type == SKB_GSO_UDP) { int ufo_size; ufo_size = skb_shinfo(skb)->gso_size; @@ -4009,7 +4009,7 @@ static int s2io_xmit(struct sk_buff *skb txdp->Host_Control = (unsigned long) skb; txdp->Control_1 |= TXD_BUFFER0_SIZE(frg_len); - if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4) + if (skb_shinfo(skb)->gso_type == SKB_GSO_UDP) txdp->Control_1 |= TXD_UFO_EN; frg_cnt = skb_shinfo(skb)->nr_frags; @@ -4024,12 +4024,12 @@ static int s2io_xmit(struct sk_buff *skb (sp->pdev, frag->page, frag->page_offset, frag->size, PCI_DMA_TODEVICE); txdp->Control_1 = TXD_BUFFER0_SIZE(frag->size); - if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4) + if (skb_shinfo(skb)->gso_type == SKB_GSO_UDP) txdp->Control_1 |= TXD_UFO_EN; } txdp->Control_1 |= TXD_GATHER_CODE_LAST; - if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4) + if (skb_shinfo(skb)->gso_type == SKB_GSO_UDP) frg_cnt++; /* as Txd0 was used for inband header */ tx_fifo = mac_control->tx_FIFO_start[queue]; @@ -4043,7 +4043,7 @@ static int s2io_xmit(struct sk_buff *skb if (mss) val64 |= TX_FIFO_SPECIAL_FUNC; #endif - if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4) + if (skb_shinfo(skb)->gso_type == SKB_GSO_UDP) val64 |= TX_FIFO_SPECIAL_FUNC; writeq(val64, &tx_fifo->List_Control); @@ -7021,6 +7021,9 @@ s2io_init_nic(struct pci_dev *pdev, cons #ifdef NETIF_F_TSO dev->features |= NETIF_F_TSO; #endif +#ifdef NETIF_F_TSO6 + dev->features |= NETIF_F_TSO6; +#endif if (sp->device_type & XFRAME_II_DEVICE) { dev->features |= NETIF_F_UFO; dev->features |= NETIF_F_HW_CSUM; diff -upNr netdev.org/include/linux/netdevice.h netdev.ipv6_tso/include/linux/netdevice.h --- netdev.org/include/linux/netdevice.h 2006-06-27 07:30:36.000000000 -0700 +++ netdev.ipv6_tso/include/linux/netdevice.h 2006-06-27 07:38:48.000000000 -0700 @@ -313,8 +313,9 @@ struct net_device /* Segmentation offload features */ #define NETIF_F_GSO_SHIFT 16 -#define NETIF_F_TSO (SKB_GSO_TCPV4 << NETIF_F_GSO_SHIFT) -#define NETIF_F_UFO (SKB_GSO_UDPV4 << NETIF_F_GSO_SHIFT) +#define NETIF_F_TSO (SKB_GSO_TCP << NETIF_F_GSO_SHIFT) +#define NETIF_F_UFO (SKB_GSO_UDP << NETIF_F_GSO_SHIFT) +#define NETIF_F_TSO6 (SKB_GSO_TCPV6 << NETIF_F_GSO_SHIFT) #define NETIF_F_GEN_CSUM (NETIF_F_NO_CSUM | NETIF_F_HW_CSUM) #define NETIF_F_ALL_CSUM (NETIF_F_IP_CSUM | NETIF_F_GEN_CSUM) diff -upNr netdev.org/include/linux/skbuff.h netdev.ipv6_tso/include/linux/skbuff.h --- netdev.org/include/linux/skbuff.h 2006-06-27 07:30:36.000000000 -0700 +++ netdev.ipv6_tso/include/linux/skbuff.h 2006-06-27 07:38:48.000000000 -0700 @@ -170,8 +170,9 @@ enum { }; enum { - SKB_GSO_TCPV4 = 1 << 0, - SKB_GSO_UDPV4 = 1 << 1, + SKB_GSO_TCP = 1 << 0, + SKB_GSO_UDP = 1 << 1, + SKB_GSO_TCPV6 = 1 << 2, }; /** diff -upNr netdev.org/net/ipv4/ip_output.c netdev.ipv6_tso/net/ipv4/ip_output.c --- netdev.org/net/ipv4/ip_output.c 2006-06-27 07:30:36.000000000 -0700 +++ netdev.ipv6_tso/net/ipv4/ip_output.c 2006-06-27 07:38:48.000000000 -0700 @@ -744,7 +744,7 @@ static inline int ip_ufo_append_data(str if (!err) { /* specify the length of each IP datagram fragment*/ skb_shinfo(skb)->gso_size = mtu - fragheaderlen; - skb_shinfo(skb)->gso_type = SKB_GSO_UDPV4; + skb_shinfo(skb)->gso_type = SKB_GSO_UDP; __skb_queue_tail(&sk->sk_write_queue, skb); return 0; @@ -1089,7 +1089,7 @@ ssize_t ip_append_page(struct sock *sk, if ((sk->sk_protocol == IPPROTO_UDP) && (rt->u.dst.dev->features & NETIF_F_UFO)) { skb_shinfo(skb)->gso_size = mtu - fragheaderlen; - skb_shinfo(skb)->gso_type = SKB_GSO_UDPV4; + skb_shinfo(skb)->gso_type = SKB_GSO_UDP; } diff -upNr netdev.org/net/ipv4/tcp_output.c netdev.ipv6_tso/net/ipv4/tcp_output.c --- netdev.org/net/ipv4/tcp_output.c 2006-06-27 07:30:36.000000000 -0700 +++ netdev.ipv6_tso/net/ipv4/tcp_output.c 2006-06-27 07:38:48.000000000 -0700 @@ -525,7 +525,7 @@ static void tcp_set_skb_tso_segs(struct factor /= mss_now; skb_shinfo(skb)->gso_segs = factor; skb_shinfo(skb)->gso_size = mss_now; - skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; + skb_shinfo(skb)->gso_type = SKB_GSO_TCP; } } diff -upNr netdev.org/net/ipv6/af_inet6.c netdev.ipv6_tso/net/ipv6/af_inet6.c --- netdev.org/net/ipv6/af_inet6.c 2006-06-27 07:30:36.000000000 -0700 +++ netdev.ipv6_tso/net/ipv6/af_inet6.c 2006-06-27 07:38:48.000000000 -0700 @@ -660,8 +660,11 @@ int inet6_sk_rebuild_header(struct sock } ip6_dst_store(sk, dst, NULL); - sk->sk_route_caps = dst->dev->features & - ~(NETIF_F_IP_CSUM | NETIF_F_TSO); + if (dst->dev->features & NETIF_F_TSO6) + sk->sk_route_caps = dst->dev->features; + else + sk->sk_route_caps = dst->dev->features & + ~(NETIF_F_IP_CSUM | NETIF_F_TSO); } return 0; diff -upNr netdev.org/net/ipv6/inet6_connection_sock.c netdev.ipv6_tso/net/ipv6/inet6_connection_sock.c --- netdev.org/net/ipv6/inet6_connection_sock.c 2006-06-27 07:30:36.000000000 -0700 +++ netdev.ipv6_tso/net/ipv6/inet6_connection_sock.c 2006-06-27 07:38:48.000000000 -0700 @@ -187,8 +187,11 @@ int inet6_csk_xmit(struct sk_buff *skb, } ip6_dst_store(sk, dst, NULL); - sk->sk_route_caps = dst->dev->features & - ~(NETIF_F_IP_CSUM | NETIF_F_TSO); + if (dst->dev->features & NETIF_F_TSO6) + sk->sk_route_caps = dst->dev->features; + else + sk->sk_route_caps = dst->dev->features & + ~(NETIF_F_IP_CSUM | NETIF_F_TSO); } skb->dst = dst_clone(dst); diff -upNr netdev.org/net/ipv6/ip6_output.c netdev.ipv6_tso/net/ipv6/ip6_output.c --- netdev.org/net/ipv6/ip6_output.c 2006-06-27 07:30:36.000000000 -0700 +++ netdev.ipv6_tso/net/ipv6/ip6_output.c 2006-06-27 07:38:48.000000000 -0700 @@ -230,7 +230,7 @@ int ip6_xmit(struct sock *sk, struct sk_ skb->priority = sk->sk_priority; mtu = dst_mtu(dst); - if ((skb->len <= mtu) || ipfragok) { + if ((skb->len <= mtu) || ipfragok || skb_shinfo(skb)->gso_size) { IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS); return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output); @@ -835,7 +835,7 @@ static inline int ip6_ufo_append_data(st /* specify the length of each IP datagram fragment*/ skb_shinfo(skb)->gso_size = mtu - fragheaderlen - sizeof(struct frag_hdr); - skb_shinfo(skb)->gso_type = SKB_GSO_UDPV4; + skb_shinfo(skb)->gso_type = SKB_GSO_UDP; ipv6_select_ident(skb, &fhdr); skb_shinfo(skb)->ip6_frag_id = fhdr.identification; __skb_queue_tail(&sk->sk_write_queue, skb); diff -upNr netdev.org/net/ipv6/tcp_ipv6.c netdev.ipv6_tso/net/ipv6/tcp_ipv6.c --- netdev.org/net/ipv6/tcp_ipv6.c 2006-06-27 07:30:36.000000000 -0700 +++ netdev.ipv6_tso/net/ipv6/tcp_ipv6.c 2006-06-27 07:38:48.000000000 -0700 @@ -271,8 +271,11 @@ static int tcp_v6_connect(struct sock *s inet->rcv_saddr = LOOPBACK4_IPV6; ip6_dst_store(sk, dst, NULL); - sk->sk_route_caps = dst->dev->features & - ~(NETIF_F_IP_CSUM | NETIF_F_TSO); + if (dst->dev->features & NETIF_F_TSO6) + sk->sk_route_caps = dst->dev->features; + else + sk->sk_route_caps = dst->dev->features & + ~(NETIF_F_IP_CSUM | NETIF_F_TSO); icsk->icsk_ext_hdr_len = 0; if (np->opt) @@ -931,8 +934,11 @@ static struct sock * tcp_v6_syn_recv_soc */ ip6_dst_store(newsk, dst, NULL); - newsk->sk_route_caps = dst->dev->features & - ~(NETIF_F_IP_CSUM | NETIF_F_TSO); + if (dst->dev->features & NETIF_F_TSO6) + sk->sk_route_caps = dst->dev->features; + else + newsk->sk_route_caps = dst->dev->features & + ~(NETIF_F_IP_CSUM | NETIF_F_TSO); newtcp6sk = (struct tcp6_sock *)newsk; inet_sk(newsk)->pinet6 = &newtcp6sk->inet6; - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html