aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesper Dangaard Brouer <brouer@redhat.com>2012-08-28 16:05:51 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2012-08-29 20:55:39 -0400
commit590e3f79a21edd2e9857ac3ced25ba6b2a491ef8 (patch)
tree68633cd1cb811aee21c3a3bd5b8433281187a2de
parent5f2d04f1f9b52604fca6ee08a77972c0df67e082 (diff)
ipvs: IPv6 MTU checking cleanup and bugfix
Cleaning up the IPv6 MTU checking in the IPVS xmit code, by using a common helper function __mtu_check_toobig_v6(). The MTU check for tunnel mode can also use this helper as ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr) is qual to skb->len. And the 'mtu' variable have been adjusted before calling helper. Notice, this also fixes a bug, as the the MTU check in ip_vs_dr_xmit_v6() were missing a check for skb_is_gso(). This bug e.g. caused issues for KVM IPVS setups, where different Segmentation Offloading techniques are utilized, between guests, via the virtio driver. This resulted in very bad performance, due to the ICMPv6 "too big" messages didn't affect the sender. Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com> Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r--net/netfilter/ipvs/ip_vs_xmit.c21
1 files changed, 15 insertions, 6 deletions
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
index 543a554008a..67a39786b0a 100644
--- a/net/netfilter/ipvs/ip_vs_xmit.c
+++ b/net/netfilter/ipvs/ip_vs_xmit.c
@@ -85,6 +85,15 @@ __ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos)
85 return dst; 85 return dst;
86} 86}
87 87
88static inline bool
89__mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu)
90{
91 if (skb->len > mtu && !skb_is_gso(skb)) {
92 return true; /* Packet size violate MTU size */
93 }
94 return false;
95}
96
88/* Get route to daddr, update *saddr, optionally bind route to saddr */ 97/* Get route to daddr, update *saddr, optionally bind route to saddr */
89static struct rtable *do_output_route4(struct net *net, __be32 daddr, 98static struct rtable *do_output_route4(struct net *net, __be32 daddr,
90 u32 rtos, int rt_mode, __be32 *saddr) 99 u32 rtos, int rt_mode, __be32 *saddr)
@@ -491,7 +500,7 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
491 500
492 /* MTU checking */ 501 /* MTU checking */
493 mtu = dst_mtu(&rt->dst); 502 mtu = dst_mtu(&rt->dst);
494 if (skb->len > mtu && !skb_is_gso(skb)) { 503 if (__mtu_check_toobig_v6(skb, mtu)) {
495 if (!skb->dev) { 504 if (!skb->dev) {
496 struct net *net = dev_net(skb_dst(skb)->dev); 505 struct net *net = dev_net(skb_dst(skb)->dev);
497 506
@@ -712,7 +721,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
712 721
713 /* MTU checking */ 722 /* MTU checking */
714 mtu = dst_mtu(&rt->dst); 723 mtu = dst_mtu(&rt->dst);
715 if (skb->len > mtu && !skb_is_gso(skb)) { 724 if (__mtu_check_toobig_v6(skb, mtu)) {
716 if (!skb->dev) { 725 if (!skb->dev) {
717 struct net *net = dev_net(skb_dst(skb)->dev); 726 struct net *net = dev_net(skb_dst(skb)->dev);
718 727
@@ -946,8 +955,8 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
946 if (skb_dst(skb)) 955 if (skb_dst(skb))
947 skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu); 956 skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu);
948 957
949 if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr) && 958 /* MTU checking: Notice that 'mtu' have been adjusted before hand */
950 !skb_is_gso(skb)) { 959 if (__mtu_check_toobig_v6(skb, mtu)) {
951 if (!skb->dev) { 960 if (!skb->dev) {
952 struct net *net = dev_net(skb_dst(skb)->dev); 961 struct net *net = dev_net(skb_dst(skb)->dev);
953 962
@@ -1113,7 +1122,7 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
1113 1122
1114 /* MTU checking */ 1123 /* MTU checking */
1115 mtu = dst_mtu(&rt->dst); 1124 mtu = dst_mtu(&rt->dst);
1116 if (skb->len > mtu) { 1125 if (__mtu_check_toobig_v6(skb, mtu)) {
1117 if (!skb->dev) { 1126 if (!skb->dev) {
1118 struct net *net = dev_net(skb_dst(skb)->dev); 1127 struct net *net = dev_net(skb_dst(skb)->dev);
1119 1128
@@ -1349,7 +1358,7 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
1349 1358
1350 /* MTU checking */ 1359 /* MTU checking */
1351 mtu = dst_mtu(&rt->dst); 1360 mtu = dst_mtu(&rt->dst);
1352 if (skb->len > mtu && !skb_is_gso(skb)) { 1361 if (__mtu_check_toobig_v6(skb, mtu)) {
1353 if (!skb->dev) { 1362 if (!skb->dev) {
1354 struct net *net = dev_net(skb_dst(skb)->dev); 1363 struct net *net = dev_net(skb_dst(skb)->dev);
1355 1364