aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter/ipvs
diff options
context:
space:
mode:
authorJesper Dangaard Brouer <brouer@redhat.com>2012-09-26 08:06:59 -0400
committerSimon Horman <horms@verge.net.au>2012-09-27 22:34:24 -0400
commit2f74713d1436b7d2d0506ba1bc5f10915a73bbec (patch)
tree7443abafe2fed8dc8018fdb6bbd6a6619c11eb24 /net/netfilter/ipvs
parent63dca2c0b0e7a92cb39d1b1ecefa32ffda201975 (diff)
ipvs: Complete IPv6 fragment handling for IPVS
IPVS now supports fragmented packets, with support from nf_conntrack_reasm.c Based on patch from: Hans Schillstrom. IPVS do like conntrack i.e. use the skb->nfct_reasm (i.e. when all fragments is collected, nf_ct_frag6_output() starts a "re-play" of all fragments into the interrupted PREROUTING chain at prio -399 (NF_IP6_PRI_CONNTRACK_DEFRAG+1) with nfct_reasm pointing to the assembled packet.) Notice, module nf_defrag_ipv6 must be loaded for this to work. Report unhandled fragments, and recommend user to load nf_defrag_ipv6. To handle fw-mark for fragments. Add a new IPVS hook into prerouting chain at prio -99 (NF_IP6_PRI_NAT_DST+1) to catch fragments, and copy fw-mark info from the first packet with an upper layer header. IPv6 fragment handling should be the last thing on the IPVS IPv6 missing support list. Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com> Signed-off-by: Hans Schillstrom <hans@schillstrom.com> Acked-by: Julian Anastasov <ja@ssi.bg> Signed-off-by: Simon Horman <horms@verge.net.au>
Diffstat (limited to 'net/netfilter/ipvs')
-rw-r--r--net/netfilter/ipvs/Kconfig6
-rw-r--r--net/netfilter/ipvs/ip_vs_conn.c2
-rw-r--r--net/netfilter/ipvs/ip_vs_core.c117
-rw-r--r--net/netfilter/ipvs/ip_vs_xmit.c36
4 files changed, 126 insertions, 35 deletions
diff --git a/net/netfilter/ipvs/Kconfig b/net/netfilter/ipvs/Kconfig
index a97ae5328ae..0c3b1670b0d 100644
--- a/net/netfilter/ipvs/Kconfig
+++ b/net/netfilter/ipvs/Kconfig
@@ -30,11 +30,9 @@ config IP_VS_IPV6
30 depends on IPV6 = y || IP_VS = IPV6 30 depends on IPV6 = y || IP_VS = IPV6
31 select IP6_NF_IPTABLES 31 select IP6_NF_IPTABLES
32 ---help--- 32 ---help---
33 Add IPv6 support to IPVS. This is incomplete and might be dangerous. 33 Add IPv6 support to IPVS.
34 34
35 See http://www.mindbasket.com/ipvs for more information. 35 Say Y if unsure.
36
37 Say N if unsure.
38 36
39config IP_VS_DEBUG 37config IP_VS_DEBUG
40 bool "IP virtual server debugging" 38 bool "IP virtual server debugging"
diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c
index 1548df9a752..d6c1c2636dd 100644
--- a/net/netfilter/ipvs/ip_vs_conn.c
+++ b/net/netfilter/ipvs/ip_vs_conn.c
@@ -314,7 +314,7 @@ ip_vs_conn_fill_param_proto(int af, const struct sk_buff *skb,
314 __be16 _ports[2], *pptr; 314 __be16 _ports[2], *pptr;
315 struct net *net = skb_net(skb); 315 struct net *net = skb_net(skb);
316 316
317 pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports); 317 pptr = frag_safe_skb_hp(skb, proto_off, sizeof(_ports), _ports, iph);
318 if (pptr == NULL) 318 if (pptr == NULL)
319 return 1; 319 return 1;
320 320
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 19c08425e13..19b89ff94cd 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -402,8 +402,12 @@ ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb,
402 unsigned int flags; 402 unsigned int flags;
403 403
404 *ignored = 1; 404 *ignored = 1;
405
406 /*
407 * IPv6 frags, only the first hit here.
408 */
405 ip_vs_fill_iph_skb(svc->af, skb, &iph); 409 ip_vs_fill_iph_skb(svc->af, skb, &iph);
406 pptr = skb_header_pointer(skb, iph.len, sizeof(_ports), _ports); 410 pptr = frag_safe_skb_hp(skb, iph.len, sizeof(_ports), _ports, &iph);
407 if (pptr == NULL) 411 if (pptr == NULL)
408 return NULL; 412 return NULL;
409 413
@@ -507,8 +511,7 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
507#endif 511#endif
508 512
509 ip_vs_fill_iph_skb(svc->af, skb, &iph); 513 ip_vs_fill_iph_skb(svc->af, skb, &iph);
510 514 pptr = frag_safe_skb_hp(skb, iph.len, sizeof(_ports), _ports, &iph);
511 pptr = skb_header_pointer(skb, iph.len, sizeof(_ports), _ports);
512 if (pptr == NULL) { 515 if (pptr == NULL) {
513 ip_vs_service_put(svc); 516 ip_vs_service_put(svc);
514 return NF_DROP; 517 return NF_DROP;
@@ -654,14 +657,6 @@ static inline int ip_vs_gather_frags(struct sk_buff *skb, u_int32_t user)
654 return err; 657 return err;
655} 658}
656 659
657#ifdef CONFIG_IP_VS_IPV6
658static inline int ip_vs_gather_frags_v6(struct sk_buff *skb, u_int32_t user)
659{
660 /* TODO IPv6: Find out what to do here for IPv6 */
661 return 0;
662}
663#endif
664
665static int ip_vs_route_me_harder(int af, struct sk_buff *skb) 660static int ip_vs_route_me_harder(int af, struct sk_buff *skb)
666{ 661{
667#ifdef CONFIG_IP_VS_IPV6 662#ifdef CONFIG_IP_VS_IPV6
@@ -939,8 +934,7 @@ static int ip_vs_out_icmp_v6(struct sk_buff *skb, int *related,
939 ip_vs_fill_iph_skb(AF_INET6, skb, ipvsh); 934 ip_vs_fill_iph_skb(AF_INET6, skb, ipvsh);
940 935
941 *related = 1; 936 *related = 1;
942 937 ic = frag_safe_skb_hp(skb, ipvsh->len, sizeof(_icmph), &_icmph, ipvsh);
943 ic = skb_header_pointer(skb, ipvsh->len, sizeof(_icmph), &_icmph);
944 if (ic == NULL) 938 if (ic == NULL)
945 return NF_DROP; 939 return NF_DROP;
946 940
@@ -955,6 +949,11 @@ static int ip_vs_out_icmp_v6(struct sk_buff *skb, int *related,
955 *related = 0; 949 *related = 0;
956 return NF_ACCEPT; 950 return NF_ACCEPT;
957 } 951 }
952 /* Fragment header that is before ICMP header tells us that:
953 * it's not an error message since they can't be fragmented.
954 */
955 if (ipvsh->flags & IP6T_FH_F_FRAG)
956 return NF_DROP;
958 957
959 IP_VS_DBG(8, "Outgoing ICMPv6 (%d,%d) %pI6c->%pI6c\n", 958 IP_VS_DBG(8, "Outgoing ICMPv6 (%d,%d) %pI6c->%pI6c\n",
960 ic->icmp6_type, ntohs(icmpv6_id(ic)), 959 ic->icmp6_type, ntohs(icmpv6_id(ic)),
@@ -1117,6 +1116,12 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af)
1117 ip_vs_fill_iph_skb(af, skb, &iph); 1116 ip_vs_fill_iph_skb(af, skb, &iph);
1118#ifdef CONFIG_IP_VS_IPV6 1117#ifdef CONFIG_IP_VS_IPV6
1119 if (af == AF_INET6) { 1118 if (af == AF_INET6) {
1119 if (!iph.fragoffs && skb_nfct_reasm(skb)) {
1120 struct sk_buff *reasm = skb_nfct_reasm(skb);
1121 /* Save fw mark for coming frags */
1122 reasm->ipvs_property = 1;
1123 reasm->mark = skb->mark;
1124 }
1120 if (unlikely(iph.protocol == IPPROTO_ICMPV6)) { 1125 if (unlikely(iph.protocol == IPPROTO_ICMPV6)) {
1121 int related; 1126 int related;
1122 int verdict = ip_vs_out_icmp_v6(skb, &related, 1127 int verdict = ip_vs_out_icmp_v6(skb, &related,
@@ -1124,7 +1129,6 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af)
1124 1129
1125 if (related) 1130 if (related)
1126 return verdict; 1131 return verdict;
1127 ip_vs_fill_iph_skb(af, skb, &iph);
1128 } 1132 }
1129 } else 1133 } else
1130#endif 1134#endif
@@ -1134,7 +1138,6 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af)
1134 1138
1135 if (related) 1139 if (related)
1136 return verdict; 1140 return verdict;
1137 ip_vs_fill_ip4hdr(skb_network_header(skb), &iph);
1138 } 1141 }
1139 1142
1140 pd = ip_vs_proto_data_get(net, iph.protocol); 1143 pd = ip_vs_proto_data_get(net, iph.protocol);
@@ -1167,8 +1170,8 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af)
1167 pp->protocol == IPPROTO_SCTP)) { 1170 pp->protocol == IPPROTO_SCTP)) {
1168 __be16 _ports[2], *pptr; 1171 __be16 _ports[2], *pptr;
1169 1172
1170 pptr = skb_header_pointer(skb, iph.len, 1173 pptr = frag_safe_skb_hp(skb, iph.len,
1171 sizeof(_ports), _ports); 1174 sizeof(_ports), _ports, &iph);
1172 if (pptr == NULL) 1175 if (pptr == NULL)
1173 return NF_ACCEPT; /* Not for me */ 1176 return NF_ACCEPT; /* Not for me */
1174 if (ip_vs_lookup_real_service(net, af, iph.protocol, 1177 if (ip_vs_lookup_real_service(net, af, iph.protocol,
@@ -1468,7 +1471,7 @@ ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, unsigned int hooknum)
1468 1471
1469 *related = 1; 1472 *related = 1;
1470 1473
1471 ic = skb_header_pointer(skb, iph->len, sizeof(_icmph), &_icmph); 1474 ic = frag_safe_skb_hp(skb, iph->len, sizeof(_icmph), &_icmph, iph);
1472 if (ic == NULL) 1475 if (ic == NULL)
1473 return NF_DROP; 1476 return NF_DROP;
1474 1477
@@ -1483,6 +1486,11 @@ ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, unsigned int hooknum)
1483 *related = 0; 1486 *related = 0;
1484 return NF_ACCEPT; 1487 return NF_ACCEPT;
1485 } 1488 }
1489 /* Fragment header that is before ICMP header tells us that:
1490 * it's not an error message since they can't be fragmented.
1491 */
1492 if (iph->flags & IP6T_FH_F_FRAG)
1493 return NF_DROP;
1486 1494
1487 IP_VS_DBG(8, "Incoming ICMPv6 (%d,%d) %pI6c->%pI6c\n", 1495 IP_VS_DBG(8, "Incoming ICMPv6 (%d,%d) %pI6c->%pI6c\n",
1488 ic->icmp6_type, ntohs(icmpv6_id(ic)), 1496 ic->icmp6_type, ntohs(icmpv6_id(ic)),
@@ -1514,10 +1522,20 @@ ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, unsigned int hooknum)
1514 IP_VS_DBG_PKT(11, AF_INET6, pp, skb, offs_ciph, 1522 IP_VS_DBG_PKT(11, AF_INET6, pp, skb, offs_ciph,
1515 "Checking incoming ICMPv6 for"); 1523 "Checking incoming ICMPv6 for");
1516 1524
1517 /* The embedded headers contain source and dest in reverse order */ 1525 /* The embedded headers contain source and dest in reverse order
1518 cp = pp->conn_in_get(AF_INET6, skb, &ciph, ciph.len, 1); 1526 * if not from localhost
1527 */
1528 cp = pp->conn_in_get(AF_INET6, skb, &ciph, ciph.len,
1529 (hooknum == NF_INET_LOCAL_OUT) ? 0 : 1);
1530
1519 if (!cp) 1531 if (!cp)
1520 return NF_ACCEPT; 1532 return NF_ACCEPT;
1533 /* VS/TUN, VS/DR and LOCALNODE just let it go */
1534 if ((hooknum == NF_INET_LOCAL_OUT) &&
1535 (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ)) {
1536 __ip_vs_conn_put(cp);
1537 return NF_ACCEPT;
1538 }
1521 1539
1522 /* do the statistics and put it back */ 1540 /* do the statistics and put it back */
1523 ip_vs_in_stats(cp, skb); 1541 ip_vs_in_stats(cp, skb);
@@ -1590,6 +1608,12 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
1590 1608
1591#ifdef CONFIG_IP_VS_IPV6 1609#ifdef CONFIG_IP_VS_IPV6
1592 if (af == AF_INET6) { 1610 if (af == AF_INET6) {
1611 if (!iph.fragoffs && skb_nfct_reasm(skb)) {
1612 struct sk_buff *reasm = skb_nfct_reasm(skb);
1613 /* Save fw mark for coming frags. */
1614 reasm->ipvs_property = 1;
1615 reasm->mark = skb->mark;
1616 }
1593 if (unlikely(iph.protocol == IPPROTO_ICMPV6)) { 1617 if (unlikely(iph.protocol == IPPROTO_ICMPV6)) {
1594 int related; 1618 int related;
1595 int verdict = ip_vs_in_icmp_v6(skb, &related, hooknum); 1619 int verdict = ip_vs_in_icmp_v6(skb, &related, hooknum);
@@ -1614,13 +1638,16 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
1614 pp = pd->pp; 1638 pp = pd->pp;
1615 /* 1639 /*
1616 * Check if the packet belongs to an existing connection entry 1640 * Check if the packet belongs to an existing connection entry
1617 * Only sched first IPv6 fragment.
1618 */ 1641 */
1619 cp = pp->conn_in_get(af, skb, &iph, iph.len, 0); 1642 cp = pp->conn_in_get(af, skb, &iph, iph.len, 0);
1620 1643
1621 if (unlikely(!cp) && !iph.fragoffs) { 1644 if (unlikely(!cp) && !iph.fragoffs) {
1645 /* No (second) fragments need to enter here, as nf_defrag_ipv6
1646 * replayed fragment zero will already have created the cp
1647 */
1622 int v; 1648 int v;
1623 1649
1650 /* Schedule and create new connection entry into &cp */
1624 if (!pp->conn_schedule(af, skb, pd, &v, &cp)) 1651 if (!pp->conn_schedule(af, skb, pd, &v, &cp))
1625 return v; 1652 return v;
1626 } 1653 }
@@ -1629,6 +1656,14 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
1629 /* sorry, all this trouble for a no-hit :) */ 1656 /* sorry, all this trouble for a no-hit :) */
1630 IP_VS_DBG_PKT(12, af, pp, skb, 0, 1657 IP_VS_DBG_PKT(12, af, pp, skb, 0,
1631 "ip_vs_in: packet continues traversal as normal"); 1658 "ip_vs_in: packet continues traversal as normal");
1659 if (iph.fragoffs && !skb_nfct_reasm(skb)) {
1660 /* Fragment that couldn't be mapped to a conn entry
1661 * and don't have any pointer to a reasm skb
1662 * is missing module nf_defrag_ipv6
1663 */
1664 IP_VS_DBG_RL("Unhandled frag, load nf_defrag_ipv6\n");
1665 IP_VS_DBG_PKT(7, af, pp, skb, 0, "unhandled fragment");
1666 }
1632 return NF_ACCEPT; 1667 return NF_ACCEPT;
1633 } 1668 }
1634 1669
@@ -1713,6 +1748,38 @@ ip_vs_local_request4(unsigned int hooknum, struct sk_buff *skb,
1713#ifdef CONFIG_IP_VS_IPV6 1748#ifdef CONFIG_IP_VS_IPV6
1714 1749
1715/* 1750/*
1751 * AF_INET6 fragment handling
1752 * Copy info from first fragment, to the rest of them.
1753 */
1754static unsigned int
1755ip_vs_preroute_frag6(unsigned int hooknum, struct sk_buff *skb,
1756 const struct net_device *in,
1757 const struct net_device *out,
1758 int (*okfn)(struct sk_buff *))
1759{
1760 struct sk_buff *reasm = skb_nfct_reasm(skb);
1761 struct net *net;
1762
1763 /* Skip if not a "replay" from nf_ct_frag6_output or first fragment.
1764 * ipvs_property is set when checking first fragment
1765 * in ip_vs_in() and ip_vs_out().
1766 */
1767 if (reasm)
1768 IP_VS_DBG(2, "Fragment recv prop:%d\n", reasm->ipvs_property);
1769 if (!reasm || !reasm->ipvs_property)
1770 return NF_ACCEPT;
1771
1772 net = skb_net(skb);
1773 if (!net_ipvs(net)->enable)
1774 return NF_ACCEPT;
1775
1776 /* Copy stored fw mark, saved in ip_vs_{in,out} */
1777 skb->mark = reasm->mark;
1778
1779 return NF_ACCEPT;
1780}
1781
1782/*
1716 * AF_INET6 handler in NF_INET_LOCAL_IN chain 1783 * AF_INET6 handler in NF_INET_LOCAL_IN chain
1717 * Schedule and forward packets from remote clients 1784 * Schedule and forward packets from remote clients
1718 */ 1785 */
@@ -1851,6 +1918,14 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
1851 .priority = 100, 1918 .priority = 100,
1852 }, 1919 },
1853#ifdef CONFIG_IP_VS_IPV6 1920#ifdef CONFIG_IP_VS_IPV6
1921 /* After mangle & nat fetch 2:nd fragment and following */
1922 {
1923 .hook = ip_vs_preroute_frag6,
1924 .owner = THIS_MODULE,
1925 .pf = NFPROTO_IPV6,
1926 .hooknum = NF_INET_PRE_ROUTING,
1927 .priority = NF_IP6_PRI_NAT_DST + 1,
1928 },
1854 /* After packet filtering, change source only for VS/NAT */ 1929 /* After packet filtering, change source only for VS/NAT */
1855 { 1930 {
1856 .hook = ip_vs_reply6, 1931 .hook = ip_vs_reply6,
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
index 428de757957..a8b75fc8e6a 100644
--- a/net/netfilter/ipvs/ip_vs_xmit.c
+++ b/net/netfilter/ipvs/ip_vs_xmit.c
@@ -496,13 +496,15 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
496 struct ip_vs_protocol *pp) 496 struct ip_vs_protocol *pp)
497{ 497{
498 struct rt6_info *rt; /* Route to the other host */ 498 struct rt6_info *rt; /* Route to the other host */
499 struct ipv6hdr *iph = ipv6_hdr(skb); 499 struct ip_vs_iphdr iph;
500 int mtu; 500 int mtu;
501 501
502 EnterFunction(10); 502 EnterFunction(10);
503 ip_vs_fill_iph_skb(cp->af, skb, &iph);
503 504
504 if (!(rt = __ip_vs_get_out_rt_v6(skb, NULL, &iph->daddr, NULL, 0, 505 rt = __ip_vs_get_out_rt_v6(skb, NULL, &iph.daddr.in6, NULL, 0,
505 IP_VS_RT_MODE_NON_LOCAL))) 506 IP_VS_RT_MODE_NON_LOCAL);
507 if (!rt)
506 goto tx_error_icmp; 508 goto tx_error_icmp;
507 509
508 /* MTU checking */ 510 /* MTU checking */
@@ -513,7 +515,9 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
513 515
514 skb->dev = net->loopback_dev; 516 skb->dev = net->loopback_dev;
515 } 517 }
516 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); 518 /* only send ICMP too big on first fragment */
519 if (!iph.fragoffs)
520 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
517 dst_release(&rt->dst); 521 dst_release(&rt->dst);
518 IP_VS_DBG_RL("%s(): frag needed\n", __func__); 522 IP_VS_DBG_RL("%s(): frag needed\n", __func__);
519 goto tx_error; 523 goto tx_error;
@@ -685,7 +689,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
685 ip_vs_fill_iph_skb(cp->af, skb, &iph); 689 ip_vs_fill_iph_skb(cp->af, skb, &iph);
686 690
687 /* check if it is a connection of no-client-port */ 691 /* check if it is a connection of no-client-port */
688 if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT)) { 692 if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT && !iph.fragoffs)) {
689 __be16 _pt, *p; 693 __be16 _pt, *p;
690 p = skb_header_pointer(skb, iph.len, sizeof(_pt), &_pt); 694 p = skb_header_pointer(skb, iph.len, sizeof(_pt), &_pt);
691 if (p == NULL) 695 if (p == NULL)
@@ -735,7 +739,9 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
735 739
736 skb->dev = net->loopback_dev; 740 skb->dev = net->loopback_dev;
737 } 741 }
738 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); 742 /* only send ICMP too big on first fragment */
743 if (!iph.fragoffs)
744 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
739 IP_VS_DBG_RL_PKT(0, AF_INET6, pp, skb, 0, 745 IP_VS_DBG_RL_PKT(0, AF_INET6, pp, skb, 0,
740 "ip_vs_nat_xmit_v6(): frag needed for"); 746 "ip_vs_nat_xmit_v6(): frag needed for");
741 goto tx_error_put; 747 goto tx_error_put;
@@ -940,8 +946,10 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
940 unsigned int max_headroom; /* The extra header space needed */ 946 unsigned int max_headroom; /* The extra header space needed */
941 int mtu; 947 int mtu;
942 int ret; 948 int ret;
949 struct ip_vs_iphdr ipvsh;
943 950
944 EnterFunction(10); 951 EnterFunction(10);
952 ip_vs_fill_iph_skb(cp->af, skb, &ipvsh);
945 953
946 if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, 954 if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6,
947 &saddr, 1, (IP_VS_RT_MODE_LOCAL | 955 &saddr, 1, (IP_VS_RT_MODE_LOCAL |
@@ -970,7 +978,9 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
970 978
971 skb->dev = net->loopback_dev; 979 skb->dev = net->loopback_dev;
972 } 980 }
973 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); 981 /* only send ICMP too big on first fragment */
982 if (!ipvsh.fragoffs)
983 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
974 IP_VS_DBG_RL("%s(): frag needed\n", __func__); 984 IP_VS_DBG_RL("%s(): frag needed\n", __func__);
975 goto tx_error_put; 985 goto tx_error_put;
976 } 986 }
@@ -1116,8 +1126,10 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
1116{ 1126{
1117 struct rt6_info *rt; /* Route to the other host */ 1127 struct rt6_info *rt; /* Route to the other host */
1118 int mtu; 1128 int mtu;
1129 struct ip_vs_iphdr iph;
1119 1130
1120 EnterFunction(10); 1131 EnterFunction(10);
1132 ip_vs_fill_iph_skb(cp->af, skb, &iph);
1121 1133
1122 if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL, 1134 if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL,
1123 0, (IP_VS_RT_MODE_LOCAL | 1135 0, (IP_VS_RT_MODE_LOCAL |
@@ -1136,7 +1148,9 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
1136 1148
1137 skb->dev = net->loopback_dev; 1149 skb->dev = net->loopback_dev;
1138 } 1150 }
1139 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); 1151 /* only send ICMP too big on first fragment */
1152 if (!iph.fragoffs)
1153 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
1140 dst_release(&rt->dst); 1154 dst_release(&rt->dst);
1141 IP_VS_DBG_RL("%s(): frag needed\n", __func__); 1155 IP_VS_DBG_RL("%s(): frag needed\n", __func__);
1142 goto tx_error; 1156 goto tx_error;
@@ -1308,8 +1322,10 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
1308 int rc; 1322 int rc;
1309 int local; 1323 int local;
1310 int rt_mode; 1324 int rt_mode;
1325 struct ip_vs_iphdr iph;
1311 1326
1312 EnterFunction(10); 1327 EnterFunction(10);
1328 ip_vs_fill_iph_skb(cp->af, skb, &iph);
1313 1329
1314 /* The ICMP packet for VS/TUN, VS/DR and LOCALNODE will be 1330 /* The ICMP packet for VS/TUN, VS/DR and LOCALNODE will be
1315 forwarded directly here, because there is no need to 1331 forwarded directly here, because there is no need to
@@ -1372,7 +1388,9 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
1372 1388
1373 skb->dev = net->loopback_dev; 1389 skb->dev = net->loopback_dev;
1374 } 1390 }
1375 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); 1391 /* only send ICMP too big on first fragment */
1392 if (!iph.fragoffs)
1393 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
1376 IP_VS_DBG_RL("%s(): frag needed\n", __func__); 1394 IP_VS_DBG_RL("%s(): frag needed\n", __func__);
1377 goto tx_error_put; 1395 goto tx_error_put;
1378 } 1396 }