ipv6: Enable enough of the code to handle GSO when disabled.
Subsystems (5)
A message that is not in the archive (sent off-list or not yet received): [email protected]
PATCH 1/1 ipv6: Enable enough of the code to handle GSO when disabled.
When a guest using virtio is attempting to use IPv6 on a host where IPv6 module is administratively disabled, the tcp bulk thransfer rate drops down to 10kbps. The problem is that when IPv6 is disabled, none of the protocol handlers are registered. When the guest attempts to send an IPv6 packet with GSO (which is the default), this packet is dropped by the host stack because there are no gso handlers registered. Thus a retransmit is triggerd for ever GSO packet, reducing the transfer rate.
This patch attempts to solve this by enabling just enough code that GSO is correctly processed. However, I should point out that if IPv6 is simply blacklisted or not build for the kernel, this problem will still persist.
This problem also exists for AF_PACKET sockets, so it is not limited to guests using virtio.
--- include/linux/ipv6.h | 1 + include/net/ipv6.h | 5 +++ net/ipv6/af_inet6.c | 69 +++++++++++++++++++++++++++++++++++++++++++++--- net/ipv6/ip6_input.c | 5 +++ net/ipv6/reassembly.c | 11 +++++-- net/ipv6/tcp_ipv6.c | 9 +++++- net/ipv6/udp.c | 6 +++- 7 files changed, 95 insertions(+), 11 deletions(-)
include/linux/ipv6.h +1 -0
@@ -176,6 +176,7 @@ struct ipv6_devconf { };struct ipv6_params { +__s32 disable_ipv6_mod;__s32 disable_ipv6;__s32 autoconf; };
include/net/ipv6.h +5 -0
@@ -550,6 +550,11 @@ extern int ipv6_rcv(struct sk_buff *skb,struct packet_type *pt, struct net_device *orig_dev); +extern int ipv6_rcv_stub (struct sk_buff *skb, +struct net_device *dev, +struct packet_type *pt, +struct net_device *orig_dev); +extern int ip6_rcv_finish (struct sk_buff *skb);/*
net/ipv6/af_inet6.c +64 -5
102 lines not on this page · raw message
net/ipv6/ip6_input.c +5 -0
@@ -74,6 +74,11 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptreturn NET_RX_DROP ; } +if (ipv6_defaults.disable_ipv6_mod) { +kfree_skb (skb); +return NET_RX_DROP ; + } +rcu_read_lock (); idev =__in6_dev_get (skb->dev);
net/ipv6/reassembly.c +8 -3
@@ -705,6 +705,9 @@ int __init ipv6_frag_init(void)if (ret) goto out; +if (ipv6_defaults.disable_ipv6_mod) + goto out; + ret =ip6_frags_sysctl_register ();if (ret) goto err_sysctl;
@@ -734,8 +737,10 @@ err_sysctl:void ipv6_frag_exit (void ) { -inet_frags_fini (&ip6_frags); -ip6_frags_sysctl_unregister (); -unregister_pernet_subsys (&ip6_frags_ops); +if (!ipv6_defaults.disable_ipv6_mod) { +inet_frags_fini (&ip6_frags); +ip6_frags_sysctl_unregister (); +unregister_pernet_subsys (&ip6_frags_ops); + }inet6_del_protocol (&frag_protocol,IPPROTO_FRAGMENT ); }
net/ipv6/tcp_ipv6.c +7 -2
@@ -2109,6 +2109,9 @@ int __init tcpv6_init(void)if (ret) goto out; +if (ipv6_defaults.disable_ipv6_mod) + goto out; +/* register inet6 protocol */ ret =inet6_register_protosw (&tcpv6_protosw);if (ret)
@@ -2129,7 +2132,9 @@ out_tcpv6_protosw:void tcpv6_exit (void ) { -unregister_pernet_subsys (&tcpv6_net_ops); -inet6_unregister_protosw (&tcpv6_protosw); +if (!ipv6_defaults.disable_ipv6_mod) { +unregister_pernet_subsys (&tcpv6_net_ops); +inet6_unregister_protosw (&tcpv6_protosw); + }inet6_del_protocol (&tcpv6_protocol,IPPROTO_TCP ); }
net/ipv6/udp.c +5 -1
@@ -1569,6 +1569,9 @@ int __init udpv6_init(void)if (ret) goto out; +if (ipv6_defaults.disable_ipv6_mod) + goto out; + ret =inet6_register_protosw (&udpv6_protosw);if (ret) goto out_udpv6_protocol;
@@ -1582,6 +1585,7 @@ out_udpv6_protocol:void udpv6_exit (void ) { -inet6_unregister_protosw (&udpv6_protosw); +if (!ipv6_defaults.disable_ipv6_mod) +inet6_unregister_protosw (&udpv6_protosw);inet6_del_protocol (&udpv6_protocol,IPPROTO_UDP ); }
Signature · 1 line
1.7.7.6