aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJulian Anastasov <ja@ssi.bg>2010-10-17 09:40:51 -0400
committerSimon Horman <horms@verge.net.au>2010-10-21 05:04:01 -0400
commitcb59155f21d4c0507d2034c2953f6a3f7806913d (patch)
tree33e07206b82254ee272cdcf7184467993ecbe8c7 /net
parentfc604767613b6d2036cdc35b660bc39451040a47 (diff)
ipvs: changes for local client
This patch deals with local client processing. Prefer LOCAL_OUT hook for scheduling connections from local clients. LOCAL_IN is still supported if the packets are not marked as processed in LOCAL_OUT. The idea to process requests in LOCAL_OUT is to alter conntrack reply before it is confirmed at POST_ROUTING. If the local requests are processed in LOCAL_IN the conntrack can not be updated and matching by state is impossible. Add the following handlers: - ip_vs_reply[46] at LOCAL_IN:99 to process replies from remote real servers to local clients. Now when both replies from remote real servers (ip_vs_reply*) and local real servers (ip_vs_local_reply*) are handled it is safe to remove the conn_out_get call from ip_vs_in because it does not support related ICMP packets. - ip_vs_local_request[46] at LOCAL_OUT:-98 to process requests from local client Handling in LOCAL_OUT causes some changes: - as skb->dev, skb->protocol and skb->pkt_type are not defined in LOCAL_OUT make sure we set skb->dev before calling icmpv6_send, prefer skb_dst(skb) for struct net and remove the skb->protocol checks from TUN transmitters. [ horms@verge.net.au: removed trailing whitespace ] Signed-off-by: Julian Anastasov <ja@ssi.bg> Signed-off-by: Simon Horman <horms@verge.net.au>
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/ipvs/ip_vs_core.c266
-rw-r--r--net/netfilter/ipvs/ip_vs_xmit.c51
2 files changed, 225 insertions, 92 deletions
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index a6c8aff1b47e..5fbcf67af8ec 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -529,9 +529,14 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
529 * ICMP_PORT_UNREACH is sent here no matter it is TCP/UDP. --WZ 529 * ICMP_PORT_UNREACH is sent here no matter it is TCP/UDP. --WZ
530 */ 530 */
531#ifdef CONFIG_IP_VS_IPV6 531#ifdef CONFIG_IP_VS_IPV6
532 if (svc->af == AF_INET6) 532 if (svc->af == AF_INET6) {
533 if (!skb->dev) {
534 struct net *net = dev_net(skb_dst(skb)->dev);
535
536 skb->dev = net->loopback_dev;
537 }
533 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); 538 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
534 else 539 } else
535#endif 540#endif
536 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 541 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
537 542
@@ -1065,57 +1070,61 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af)
1065 */ 1070 */
1066 cp = pp->conn_out_get(af, skb, pp, &iph, iph.len, 0); 1071 cp = pp->conn_out_get(af, skb, pp, &iph, iph.len, 0);
1067 1072
1068 if (unlikely(!cp)) { 1073 if (likely(cp))
1069 if (sysctl_ip_vs_nat_icmp_send && 1074 return handle_response(af, skb, pp, cp, iph.len);
1070 (pp->protocol == IPPROTO_TCP || 1075 if (sysctl_ip_vs_nat_icmp_send &&
1071 pp->protocol == IPPROTO_UDP || 1076 (pp->protocol == IPPROTO_TCP ||
1072 pp->protocol == IPPROTO_SCTP)) { 1077 pp->protocol == IPPROTO_UDP ||
1073 __be16 _ports[2], *pptr; 1078 pp->protocol == IPPROTO_SCTP)) {
1074 1079 __be16 _ports[2], *pptr;
1075 pptr = skb_header_pointer(skb, iph.len, 1080
1076 sizeof(_ports), _ports); 1081 pptr = skb_header_pointer(skb, iph.len,
1077 if (pptr == NULL) 1082 sizeof(_ports), _ports);
1078 return NF_ACCEPT; /* Not for me */ 1083 if (pptr == NULL)
1079 if (ip_vs_lookup_real_service(af, iph.protocol, 1084 return NF_ACCEPT; /* Not for me */
1080 &iph.saddr, 1085 if (ip_vs_lookup_real_service(af, iph.protocol,
1081 pptr[0])) { 1086 &iph.saddr,
1082 /* 1087 pptr[0])) {
1083 * Notify the real server: there is no 1088 /*
1084 * existing entry if it is not RST 1089 * Notify the real server: there is no
1085 * packet or not TCP packet. 1090 * existing entry if it is not RST
1086 */ 1091 * packet or not TCP packet.
1087 if ((iph.protocol != IPPROTO_TCP && 1092 */
1088 iph.protocol != IPPROTO_SCTP) 1093 if ((iph.protocol != IPPROTO_TCP &&
1089 || ((iph.protocol == IPPROTO_TCP 1094 iph.protocol != IPPROTO_SCTP)
1090 && !is_tcp_reset(skb, iph.len)) 1095 || ((iph.protocol == IPPROTO_TCP
1091 || (iph.protocol == IPPROTO_SCTP 1096 && !is_tcp_reset(skb, iph.len))
1092 && !is_sctp_abort(skb, 1097 || (iph.protocol == IPPROTO_SCTP
1093 iph.len)))) { 1098 && !is_sctp_abort(skb,
1099 iph.len)))) {
1094#ifdef CONFIG_IP_VS_IPV6 1100#ifdef CONFIG_IP_VS_IPV6
1095 if (af == AF_INET6) 1101 if (af == AF_INET6) {
1096 icmpv6_send(skb, 1102 struct net *net =
1097 ICMPV6_DEST_UNREACH, 1103 dev_net(skb_dst(skb)->dev);
1098 ICMPV6_PORT_UNREACH, 1104
1099 0); 1105 if (!skb->dev)
1100 else 1106 skb->dev = net->loopback_dev;
1107 icmpv6_send(skb,
1108 ICMPV6_DEST_UNREACH,
1109 ICMPV6_PORT_UNREACH,
1110 0);
1111 } else
1101#endif 1112#endif
1102 icmp_send(skb, 1113 icmp_send(skb,
1103 ICMP_DEST_UNREACH, 1114 ICMP_DEST_UNREACH,
1104 ICMP_PORT_UNREACH, 0); 1115 ICMP_PORT_UNREACH, 0);
1105 return NF_DROP; 1116 return NF_DROP;
1106 }
1107 } 1117 }
1108 } 1118 }
1109 IP_VS_DBG_PKT(12, pp, skb, 0,
1110 "packet continues traversal as normal");
1111 return NF_ACCEPT;
1112 } 1119 }
1113 1120 IP_VS_DBG_PKT(12, pp, skb, 0,
1114 return handle_response(af, skb, pp, cp, iph.len); 1121 "ip_vs_out: packet continues traversal as normal");
1122 return NF_ACCEPT;
1115} 1123}
1116 1124
1117/* 1125/*
1118 * It is hooked at the NF_INET_FORWARD chain, used only for VS/NAT. 1126 * It is hooked at the NF_INET_FORWARD and NF_INET_LOCAL_IN chain,
1127 * used only for VS/NAT.
1119 * Check if packet is reply for established ip_vs_conn. 1128 * Check if packet is reply for established ip_vs_conn.
1120 */ 1129 */
1121static unsigned int 1130static unsigned int
@@ -1147,7 +1156,8 @@ ip_vs_local_reply4(unsigned int hooknum, struct sk_buff *skb,
1147#ifdef CONFIG_IP_VS_IPV6 1156#ifdef CONFIG_IP_VS_IPV6
1148 1157
1149/* 1158/*
1150 * It is hooked at the NF_INET_FORWARD chain, used only for VS/NAT. 1159 * It is hooked at the NF_INET_FORWARD and NF_INET_LOCAL_IN chain,
1160 * used only for VS/NAT.
1151 * Check if packet is reply for established ip_vs_conn. 1161 * Check if packet is reply for established ip_vs_conn.
1152 */ 1162 */
1153static unsigned int 1163static unsigned int
@@ -1404,34 +1414,43 @@ ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, unsigned int hooknum)
1404 * and send it on its way... 1414 * and send it on its way...
1405 */ 1415 */
1406static unsigned int 1416static unsigned int
1407ip_vs_in(unsigned int hooknum, struct sk_buff *skb, 1417ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
1408 const struct net_device *in, const struct net_device *out,
1409 int (*okfn)(struct sk_buff *))
1410{ 1418{
1411 struct ip_vs_iphdr iph; 1419 struct ip_vs_iphdr iph;
1412 struct ip_vs_protocol *pp; 1420 struct ip_vs_protocol *pp;
1413 struct ip_vs_conn *cp; 1421 struct ip_vs_conn *cp;
1414 int ret, restart, af, pkts; 1422 int ret, restart, pkts;
1415 1423
1416 /* Already marked as IPVS request or reply? */ 1424 /* Already marked as IPVS request or reply? */
1417 if (skb->ipvs_property) 1425 if (skb->ipvs_property)
1418 return NF_ACCEPT; 1426 return NF_ACCEPT;
1419 1427
1420 af = (skb->protocol == htons(ETH_P_IP)) ? AF_INET : AF_INET6;
1421
1422 ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
1423
1424 /* 1428 /*
1425 * Big tappo: only PACKET_HOST, including loopback for local client 1429 * Big tappo:
1426 * Don't handle local packets on IPv6 for now 1430 * - remote client: only PACKET_HOST
1431 * - route: used for struct net when skb->dev is unset
1427 */ 1432 */
1428 if (unlikely(skb->pkt_type != PACKET_HOST)) { 1433 if (unlikely((skb->pkt_type != PACKET_HOST &&
1429 IP_VS_DBG_BUF(12, "packet type=%d proto=%d daddr=%s ignored\n", 1434 hooknum != NF_INET_LOCAL_OUT) ||
1430 skb->pkt_type, 1435 !skb_dst(skb))) {
1431 iph.protocol, 1436 ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
1432 IP_VS_DBG_ADDR(af, &iph.daddr)); 1437 IP_VS_DBG_BUF(12, "packet type=%d proto=%d daddr=%s"
1438 " ignored in hook %u\n",
1439 skb->pkt_type, iph.protocol,
1440 IP_VS_DBG_ADDR(af, &iph.daddr), hooknum);
1433 return NF_ACCEPT; 1441 return NF_ACCEPT;
1434 } 1442 }
1443 ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
1444
1445 /* Bad... Do not break raw sockets */
1446 if (unlikely(skb->sk != NULL && hooknum == NF_INET_LOCAL_OUT &&
1447 af == AF_INET)) {
1448 struct sock *sk = skb->sk;
1449 struct inet_sock *inet = inet_sk(skb->sk);
1450
1451 if (inet && sk->sk_family == PF_INET && inet->nodefrag)
1452 return NF_ACCEPT;
1453 }
1435 1454
1436#ifdef CONFIG_IP_VS_IPV6 1455#ifdef CONFIG_IP_VS_IPV6
1437 if (af == AF_INET6) { 1456 if (af == AF_INET6) {
@@ -1467,11 +1486,6 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
1467 if (unlikely(!cp)) { 1486 if (unlikely(!cp)) {
1468 int v; 1487 int v;
1469 1488
1470 /* For local client packets, it could be a response */
1471 cp = pp->conn_out_get(af, skb, pp, &iph, iph.len, 0);
1472 if (cp)
1473 return handle_response(af, skb, pp, cp, iph.len);
1474
1475 if (!pp->conn_schedule(af, skb, pp, &v, &cp)) 1489 if (!pp->conn_schedule(af, skb, pp, &v, &cp))
1476 return v; 1490 return v;
1477 } 1491 }
@@ -1479,7 +1493,7 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
1479 if (unlikely(!cp)) { 1493 if (unlikely(!cp)) {
1480 /* sorry, all this trouble for a no-hit :) */ 1494 /* sorry, all this trouble for a no-hit :) */
1481 IP_VS_DBG_PKT(12, pp, skb, 0, 1495 IP_VS_DBG_PKT(12, pp, skb, 0,
1482 "packet continues traversal as normal"); 1496 "ip_vs_in: packet continues traversal as normal");
1483 return NF_ACCEPT; 1497 return NF_ACCEPT;
1484 } 1498 }
1485 1499
@@ -1550,6 +1564,72 @@ out:
1550 return ret; 1564 return ret;
1551} 1565}
1552 1566
1567/*
1568 * AF_INET handler in NF_INET_LOCAL_IN chain
1569 * Schedule and forward packets from remote clients
1570 */
1571static unsigned int
1572ip_vs_remote_request4(unsigned int hooknum, struct sk_buff *skb,
1573 const struct net_device *in,
1574 const struct net_device *out,
1575 int (*okfn)(struct sk_buff *))
1576{
1577 return ip_vs_in(hooknum, skb, AF_INET);
1578}
1579
1580/*
1581 * AF_INET handler in NF_INET_LOCAL_OUT chain
1582 * Schedule and forward packets from local clients
1583 */
1584static unsigned int
1585ip_vs_local_request4(unsigned int hooknum, struct sk_buff *skb,
1586 const struct net_device *in, const struct net_device *out,
1587 int (*okfn)(struct sk_buff *))
1588{
1589 unsigned int verdict;
1590
1591 /* Disable BH in LOCAL_OUT until all places are fixed */
1592 local_bh_disable();
1593 verdict = ip_vs_in(hooknum, skb, AF_INET);
1594 local_bh_enable();
1595 return verdict;
1596}
1597
1598#ifdef CONFIG_IP_VS_IPV6
1599
1600/*
1601 * AF_INET6 handler in NF_INET_LOCAL_IN chain
1602 * Schedule and forward packets from remote clients
1603 */
1604static unsigned int
1605ip_vs_remote_request6(unsigned int hooknum, struct sk_buff *skb,
1606 const struct net_device *in,
1607 const struct net_device *out,
1608 int (*okfn)(struct sk_buff *))
1609{
1610 return ip_vs_in(hooknum, skb, AF_INET6);
1611}
1612
1613/*
1614 * AF_INET6 handler in NF_INET_LOCAL_OUT chain
1615 * Schedule and forward packets from local clients
1616 */
1617static unsigned int
1618ip_vs_local_request6(unsigned int hooknum, struct sk_buff *skb,
1619 const struct net_device *in, const struct net_device *out,
1620 int (*okfn)(struct sk_buff *))
1621{
1622 unsigned int verdict;
1623
1624 /* Disable BH in LOCAL_OUT until all places are fixed */
1625 local_bh_disable();
1626 verdict = ip_vs_in(hooknum, skb, AF_INET6);
1627 local_bh_enable();
1628 return verdict;
1629}
1630
1631#endif
1632
1553 1633
1554/* 1634/*
1555 * It is hooked at the NF_INET_FORWARD chain, in order to catch ICMP 1635 * It is hooked at the NF_INET_FORWARD chain, in order to catch ICMP
@@ -1590,15 +1670,23 @@ ip_vs_forward_icmp_v6(unsigned int hooknum, struct sk_buff *skb,
1590 1670
1591 1671
1592static struct nf_hook_ops ip_vs_ops[] __read_mostly = { 1672static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
1673 /* After packet filtering, change source only for VS/NAT */
1674 {
1675 .hook = ip_vs_reply4,
1676 .owner = THIS_MODULE,
1677 .pf = PF_INET,
1678 .hooknum = NF_INET_LOCAL_IN,
1679 .priority = 99,
1680 },
1593 /* After packet filtering, forward packet through VS/DR, VS/TUN, 1681 /* After packet filtering, forward packet through VS/DR, VS/TUN,
1594 * or VS/NAT(change destination), so that filtering rules can be 1682 * or VS/NAT(change destination), so that filtering rules can be
1595 * applied to IPVS. */ 1683 * applied to IPVS. */
1596 { 1684 {
1597 .hook = ip_vs_in, 1685 .hook = ip_vs_remote_request4,
1598 .owner = THIS_MODULE, 1686 .owner = THIS_MODULE,
1599 .pf = PF_INET, 1687 .pf = PF_INET,
1600 .hooknum = NF_INET_LOCAL_IN, 1688 .hooknum = NF_INET_LOCAL_IN,
1601 .priority = 100, 1689 .priority = 101,
1602 }, 1690 },
1603 /* Before ip_vs_in, change source only for VS/NAT */ 1691 /* Before ip_vs_in, change source only for VS/NAT */
1604 { 1692 {
@@ -1608,14 +1696,22 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
1608 .hooknum = NF_INET_LOCAL_OUT, 1696 .hooknum = NF_INET_LOCAL_OUT,
1609 .priority = -99, 1697 .priority = -99,
1610 }, 1698 },
1699 /* After mangle, schedule and forward local requests */
1700 {
1701 .hook = ip_vs_local_request4,
1702 .owner = THIS_MODULE,
1703 .pf = PF_INET,
1704 .hooknum = NF_INET_LOCAL_OUT,
1705 .priority = -98,
1706 },
1611 /* After packet filtering (but before ip_vs_out_icmp), catch icmp 1707 /* After packet filtering (but before ip_vs_out_icmp), catch icmp
1612 * destined for 0.0.0.0/0, which is for incoming IPVS connections */ 1708 * destined for 0.0.0.0/0, which is for incoming IPVS connections */
1613 { 1709 {
1614 .hook = ip_vs_forward_icmp, 1710 .hook = ip_vs_forward_icmp,
1615 .owner = THIS_MODULE, 1711 .owner = THIS_MODULE,
1616 .pf = PF_INET, 1712 .pf = PF_INET,
1617 .hooknum = NF_INET_FORWARD, 1713 .hooknum = NF_INET_FORWARD,
1618 .priority = 99, 1714 .priority = 99,
1619 }, 1715 },
1620 /* After packet filtering, change source only for VS/NAT */ 1716 /* After packet filtering, change source only for VS/NAT */
1621 { 1717 {
@@ -1626,15 +1722,23 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
1626 .priority = 100, 1722 .priority = 100,
1627 }, 1723 },
1628#ifdef CONFIG_IP_VS_IPV6 1724#ifdef CONFIG_IP_VS_IPV6
1725 /* After packet filtering, change source only for VS/NAT */
1726 {
1727 .hook = ip_vs_reply6,
1728 .owner = THIS_MODULE,
1729 .pf = PF_INET6,
1730 .hooknum = NF_INET_LOCAL_IN,
1731 .priority = 99,
1732 },
1629 /* After packet filtering, forward packet through VS/DR, VS/TUN, 1733 /* After packet filtering, forward packet through VS/DR, VS/TUN,
1630 * or VS/NAT(change destination), so that filtering rules can be 1734 * or VS/NAT(change destination), so that filtering rules can be
1631 * applied to IPVS. */ 1735 * applied to IPVS. */
1632 { 1736 {
1633 .hook = ip_vs_in, 1737 .hook = ip_vs_remote_request6,
1634 .owner = THIS_MODULE, 1738 .owner = THIS_MODULE,
1635 .pf = PF_INET6, 1739 .pf = PF_INET6,
1636 .hooknum = NF_INET_LOCAL_IN, 1740 .hooknum = NF_INET_LOCAL_IN,
1637 .priority = 100, 1741 .priority = 101,
1638 }, 1742 },
1639 /* Before ip_vs_in, change source only for VS/NAT */ 1743 /* Before ip_vs_in, change source only for VS/NAT */
1640 { 1744 {
@@ -1644,14 +1748,22 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
1644 .hooknum = NF_INET_LOCAL_OUT, 1748 .hooknum = NF_INET_LOCAL_OUT,
1645 .priority = -99, 1749 .priority = -99,
1646 }, 1750 },
1751 /* After mangle, schedule and forward local requests */
1752 {
1753 .hook = ip_vs_local_request6,
1754 .owner = THIS_MODULE,
1755 .pf = PF_INET6,
1756 .hooknum = NF_INET_LOCAL_OUT,
1757 .priority = -98,
1758 },
1647 /* After packet filtering (but before ip_vs_out_icmp), catch icmp 1759 /* After packet filtering (but before ip_vs_out_icmp), catch icmp
1648 * destined for 0.0.0.0/0, which is for incoming IPVS connections */ 1760 * destined for 0.0.0.0/0, which is for incoming IPVS connections */
1649 { 1761 {
1650 .hook = ip_vs_forward_icmp_v6, 1762 .hook = ip_vs_forward_icmp_v6,
1651 .owner = THIS_MODULE, 1763 .owner = THIS_MODULE,
1652 .pf = PF_INET6, 1764 .pf = PF_INET6,
1653 .hooknum = NF_INET_FORWARD, 1765 .hooknum = NF_INET_FORWARD,
1654 .priority = 99, 1766 .priority = 99,
1655 }, 1767 },
1656 /* After packet filtering, change source only for VS/NAT */ 1768 /* After packet filtering, change source only for VS/NAT */
1657 { 1769 {
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
index 8608882f89e3..97b5361c036e 100644
--- a/net/netfilter/ipvs/ip_vs_xmit.c
+++ b/net/netfilter/ipvs/ip_vs_xmit.c
@@ -11,6 +11,16 @@
11 * 11 *
12 * Changes: 12 * Changes:
13 * 13 *
14 * Description of forwarding methods:
15 * - all transmitters are called from LOCAL_IN (remote clients) and
16 * LOCAL_OUT (local clients) but for ICMP can be called from FORWARD
17 * - not all connections have destination server, for example,
18 * connections in backup server when fwmark is used
19 * - bypass connections use daddr from packet
20 * LOCAL_OUT rules:
21 * - skb->dev is NULL, skb->protocol is not set (both are set in POST_ROUTING)
22 * - skb->pkt_type is not set yet
23 * - the only place where we can see skb->sk != NULL
14 */ 24 */
15 25
16#define KMSG_COMPONENT "IPVS" 26#define KMSG_COMPONENT "IPVS"
@@ -452,8 +462,13 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
452 /* MTU checking */ 462 /* MTU checking */
453 mtu = dst_mtu(&rt->dst); 463 mtu = dst_mtu(&rt->dst);
454 if (skb->len > mtu) { 464 if (skb->len > mtu) {
455 dst_release(&rt->dst); 465 if (!skb->dev) {
466 struct net *net = dev_net(skb_dst(skb)->dev);
467
468 skb->dev = net->loopback_dev;
469 }
456 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); 470 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
471 dst_release(&rt->dst);
457 IP_VS_DBG_RL("%s(): frag needed\n", __func__); 472 IP_VS_DBG_RL("%s(): frag needed\n", __func__);
458 goto tx_error; 473 goto tx_error;
459 } 474 }
@@ -659,6 +674,11 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
659 /* MTU checking */ 674 /* MTU checking */
660 mtu = dst_mtu(&rt->dst); 675 mtu = dst_mtu(&rt->dst);
661 if (skb->len > mtu) { 676 if (skb->len > mtu) {
677 if (!skb->dev) {
678 struct net *net = dev_net(skb_dst(skb)->dev);
679
680 skb->dev = net->loopback_dev;
681 }
662 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); 682 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
663 IP_VS_DBG_RL_PKT(0, pp, skb, 0, 683 IP_VS_DBG_RL_PKT(0, pp, skb, 0,
664 "ip_vs_nat_xmit_v6(): frag needed for"); 684 "ip_vs_nat_xmit_v6(): frag needed for");
@@ -748,13 +768,6 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
748 768
749 EnterFunction(10); 769 EnterFunction(10);
750 770
751 if (skb->protocol != htons(ETH_P_IP)) {
752 IP_VS_DBG_RL("%s(): protocol error, "
753 "ETH_P_IP: %d, skb protocol: %d\n",
754 __func__, htons(ETH_P_IP), skb->protocol);
755 goto tx_error;
756 }
757
758 if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip, 771 if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip,
759 RT_TOS(tos), 1|2))) 772 RT_TOS(tos), 1|2)))
760 goto tx_error_icmp; 773 goto tx_error_icmp;
@@ -869,13 +882,6 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
869 882
870 EnterFunction(10); 883 EnterFunction(10);
871 884
872 if (skb->protocol != htons(ETH_P_IPV6)) {
873 IP_VS_DBG_RL("%s(): protocol error, "
874 "ETH_P_IPV6: %d, skb protocol: %d\n",
875 __func__, htons(ETH_P_IPV6), skb->protocol);
876 goto tx_error;
877 }
878
879 if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, 885 if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6,
880 &saddr, 1, 1|2))) 886 &saddr, 1, 1|2)))
881 goto tx_error_icmp; 887 goto tx_error_icmp;
@@ -896,6 +902,11 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
896 skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); 902 skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu);
897 903
898 if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr)) { 904 if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr)) {
905 if (!skb->dev) {
906 struct net *net = dev_net(skb_dst(skb)->dev);
907
908 skb->dev = net->loopback_dev;
909 }
899 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); 910 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
900 IP_VS_DBG_RL("%s(): frag needed\n", __func__); 911 IP_VS_DBG_RL("%s(): frag needed\n", __func__);
901 goto tx_error_put; 912 goto tx_error_put;
@@ -1053,6 +1064,11 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
1053 /* MTU checking */ 1064 /* MTU checking */
1054 mtu = dst_mtu(&rt->dst); 1065 mtu = dst_mtu(&rt->dst);
1055 if (skb->len > mtu) { 1066 if (skb->len > mtu) {
1067 if (!skb->dev) {
1068 struct net *net = dev_net(skb_dst(skb)->dev);
1069
1070 skb->dev = net->loopback_dev;
1071 }
1056 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); 1072 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
1057 dst_release(&rt->dst); 1073 dst_release(&rt->dst);
1058 IP_VS_DBG_RL("%s(): frag needed\n", __func__); 1074 IP_VS_DBG_RL("%s(): frag needed\n", __func__);
@@ -1271,6 +1287,11 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
1271 /* MTU checking */ 1287 /* MTU checking */
1272 mtu = dst_mtu(&rt->dst); 1288 mtu = dst_mtu(&rt->dst);
1273 if (skb->len > mtu) { 1289 if (skb->len > mtu) {
1290 if (!skb->dev) {
1291 struct net *net = dev_net(skb_dst(skb)->dev);
1292
1293 skb->dev = net->loopback_dev;
1294 }
1274 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); 1295 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
1275 IP_VS_DBG_RL("%s(): frag needed\n", __func__); 1296 IP_VS_DBG_RL("%s(): frag needed\n", __func__);
1276 goto tx_error_put; 1297 goto tx_error_put;