]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - net/netfilter/ipvs/ip_vs_xmit.c
net: use the macros defined for the members of flowi
[net-next-2.6.git] / net / netfilter / ipvs / ip_vs_xmit.c
index 8608882f89e38159a64261132a0b589703db6199..5325a3fbe4ac8e8ab5a2e8175f9a5b93e1cc663c 100644 (file)
  *
  * Changes:
  *
+ * Description of forwarding methods:
+ * - all transmitters are called from LOCAL_IN (remote clients) and
+ * LOCAL_OUT (local clients) but for ICMP can be called from FORWARD
+ * - not all connections have destination server, for example,
+ * connections in backup server when fwmark is used
+ * - bypass connections use daddr from packet
+ * LOCAL_OUT rules:
+ * - skb->dev is NULL, skb->protocol is not set (both are set in POST_ROUTING)
+ * - skb->pkt_type is not set yet
+ * - the only place where we can see skb->sk != NULL
  */
 
 #define KMSG_COMPONENT "IPVS"
@@ -86,12 +96,8 @@ __ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest,
                if (!(rt = (struct rtable *)
                      __ip_vs_dst_check(dest, rtos))) {
                        struct flowi fl = {
-                               .oif = 0,
-                               .nl_u = {
-                                       .ip4_u = {
-                                               .daddr = dest->addr.ip,
-                                               .saddr = 0,
-                                               .tos = rtos, } },
+                               .fl4_dst = dest->addr.ip,
+                               .fl4_tos = rtos,
                        };
 
                        if (ip_route_output_key(net, &rt, &fl)) {
@@ -108,12 +114,8 @@ __ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest,
                spin_unlock(&dest->dst_lock);
        } else {
                struct flowi fl = {
-                       .oif = 0,
-                       .nl_u = {
-                               .ip4_u = {
-                                       .daddr = daddr,
-                                       .saddr = 0,
-                                       .tos = rtos, } },
+                       .fl4_dst = daddr,
+                       .fl4_tos = rtos,
                };
 
                if (ip_route_output_key(net, &rt, &fl)) {
@@ -159,7 +161,7 @@ __ip_vs_reroute_locally(struct sk_buff *skb)
        struct net *net = dev_net(dev);
        struct iphdr *iph = ip_hdr(skb);
 
-       if (rt->fl.iif) {
+       if (rt_is_input_route(rt)) {
                unsigned long orefdst = skb->_skb_refdst;
 
                if (ip_route_input(skb, iph->daddr, iph->saddr,
@@ -168,14 +170,9 @@ __ip_vs_reroute_locally(struct sk_buff *skb)
                refdst_drop(orefdst);
        } else {
                struct flowi fl = {
-                       .oif = 0,
-                       .nl_u = {
-                               .ip4_u = {
-                                       .daddr = iph->daddr,
-                                       .saddr = iph->saddr,
-                                       .tos = RT_TOS(iph->tos),
-                               }
-                       },
+                       .fl4_dst = iph->daddr,
+                       .fl4_src = iph->saddr,
+                       .fl4_tos = RT_TOS(iph->tos),
                        .mark = skb->mark,
                };
                struct rtable *rt;
@@ -206,12 +203,7 @@ __ip_vs_route_output_v6(struct net *net, struct in6_addr *daddr,
 {
        struct dst_entry *dst;
        struct flowi fl = {
-               .oif = 0,
-               .nl_u = {
-                       .ip6_u = {
-                               .daddr = *daddr,
-                       },
-               },
+               .fl6_dst = *daddr,
        };
 
        dst = ip6_route_output(net, NULL, &fl);
@@ -452,8 +444,13 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
        /* MTU checking */
        mtu = dst_mtu(&rt->dst);
        if (skb->len > mtu) {
-               dst_release(&rt->dst);
+               if (!skb->dev) {
+                       struct net *net = dev_net(skb_dst(skb)->dev);
+
+                       skb->dev = net->loopback_dev;
+               }
                icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
+               dst_release(&rt->dst);
                IP_VS_DBG_RL("%s(): frag needed\n", __func__);
                goto tx_error;
        }
@@ -528,7 +525,8 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
                struct nf_conn *ct = ct = nf_ct_get(skb, &ctinfo);
 
                if (ct && !nf_ct_is_untracked(ct)) {
-                       IP_VS_DBG_RL_PKT(10, pp, skb, 0, "ip_vs_nat_xmit(): "
+                       IP_VS_DBG_RL_PKT(10, AF_INET, pp, skb, 0,
+                                        "ip_vs_nat_xmit(): "
                                         "stopping DNAT to local address");
                        goto tx_error_put;
                }
@@ -536,8 +534,9 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
 #endif
 
        /* From world but DNAT to loopback address? */
-       if (local && ipv4_is_loopback(rt->rt_dst) && skb_rtable(skb)->fl.iif) {
-               IP_VS_DBG_RL_PKT(1, pp, skb, 0, "ip_vs_nat_xmit(): "
+       if (local && ipv4_is_loopback(rt->rt_dst) &&
+           rt_is_input_route(skb_rtable(skb))) {
+               IP_VS_DBG_RL_PKT(1, AF_INET, pp, skb, 0, "ip_vs_nat_xmit(): "
                                 "stopping DNAT to loopback address");
                goto tx_error_put;
        }
@@ -546,7 +545,8 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
        mtu = dst_mtu(&rt->dst);
        if ((skb->len > mtu) && (iph->frag_off & htons(IP_DF))) {
                icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
-               IP_VS_DBG_RL_PKT(0, pp, skb, 0, "ip_vs_nat_xmit(): frag needed for");
+               IP_VS_DBG_RL_PKT(0, AF_INET, pp, skb, 0,
+                                "ip_vs_nat_xmit(): frag needed for");
                goto tx_error_put;
        }
 
@@ -578,7 +578,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
                        goto tx_error;
        }
 
-       IP_VS_DBG_PKT(10, pp, skb, 0, "After DNAT");
+       IP_VS_DBG_PKT(10, AF_INET, pp, skb, 0, "After DNAT");
 
        /* FIXME: when application helper enlarges the packet and the length
           is larger than the MTU of outgoing device, there will be still
@@ -639,7 +639,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
                struct nf_conn *ct = ct = nf_ct_get(skb, &ctinfo);
 
                if (ct && !nf_ct_is_untracked(ct)) {
-                       IP_VS_DBG_RL_PKT(10, pp, skb, 0,
+                       IP_VS_DBG_RL_PKT(10, AF_INET6, pp, skb, 0,
                                         "ip_vs_nat_xmit_v6(): "
                                         "stopping DNAT to local address");
                        goto tx_error_put;
@@ -650,7 +650,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
        /* From world but DNAT to loopback address? */
        if (local && skb->dev && !(skb->dev->flags & IFF_LOOPBACK) &&
            ipv6_addr_type(&rt->rt6i_dst.addr) & IPV6_ADDR_LOOPBACK) {
-               IP_VS_DBG_RL_PKT(1, pp, skb, 0,
+               IP_VS_DBG_RL_PKT(1, AF_INET6, pp, skb, 0,
                                 "ip_vs_nat_xmit_v6(): "
                                 "stopping DNAT to loopback address");
                goto tx_error_put;
@@ -659,8 +659,13 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
        /* MTU checking */
        mtu = dst_mtu(&rt->dst);
        if (skb->len > mtu) {
+               if (!skb->dev) {
+                       struct net *net = dev_net(skb_dst(skb)->dev);
+
+                       skb->dev = net->loopback_dev;
+               }
                icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
-               IP_VS_DBG_RL_PKT(0, pp, skb, 0,
+               IP_VS_DBG_RL_PKT(0, AF_INET6, pp, skb, 0,
                                 "ip_vs_nat_xmit_v6(): frag needed for");
                goto tx_error_put;
        }
@@ -686,7 +691,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
                dst_release(&rt->dst);
        }
 
-       IP_VS_DBG_PKT(10, pp, skb, 0, "After DNAT");
+       IP_VS_DBG_PKT(10, AF_INET6, pp, skb, 0, "After DNAT");
 
        /* FIXME: when application helper enlarges the packet and the length
           is larger than the MTU of outgoing device, there will be still
@@ -748,13 +753,6 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
 
        EnterFunction(10);
 
-       if (skb->protocol != htons(ETH_P_IP)) {
-               IP_VS_DBG_RL("%s(): protocol error, "
-                            "ETH_P_IP: %d, skb protocol: %d\n",
-                            __func__, htons(ETH_P_IP), skb->protocol);
-               goto tx_error;
-       }
-
        if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip,
                                      RT_TOS(tos), 1|2)))
                goto tx_error_icmp;
@@ -869,13 +867,6 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 
        EnterFunction(10);
 
-       if (skb->protocol != htons(ETH_P_IPV6)) {
-               IP_VS_DBG_RL("%s(): protocol error, "
-                            "ETH_P_IPV6: %d, skb protocol: %d\n",
-                            __func__, htons(ETH_P_IPV6), skb->protocol);
-               goto tx_error;
-       }
-
        if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6,
                                         &saddr, 1, 1|2)))
                goto tx_error_icmp;
@@ -896,6 +887,11 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
                skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu);
 
        if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr)) {
+               if (!skb->dev) {
+                       struct net *net = dev_net(skb_dst(skb)->dev);
+
+                       skb->dev = net->loopback_dev;
+               }
                icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
                IP_VS_DBG_RL("%s(): frag needed\n", __func__);
                goto tx_error_put;
@@ -1053,6 +1049,11 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
        /* MTU checking */
        mtu = dst_mtu(&rt->dst);
        if (skb->len > mtu) {
+               if (!skb->dev) {
+                       struct net *net = dev_net(skb_dst(skb)->dev);
+
+                       skb->dev = net->loopback_dev;
+               }
                icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
                dst_release(&rt->dst);
                IP_VS_DBG_RL("%s(): frag needed\n", __func__);
@@ -1147,7 +1148,8 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
 #endif
 
        /* From world but DNAT to loopback address? */
-       if (local && ipv4_is_loopback(rt->rt_dst) && skb_rtable(skb)->fl.iif) {
+       if (local && ipv4_is_loopback(rt->rt_dst) &&
+           rt_is_input_route(skb_rtable(skb))) {
                IP_VS_DBG(1, "%s(): "
                          "stopping DNAT to loopback %pI4\n",
                          __func__, &cp->daddr.ip);
@@ -1271,6 +1273,11 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
        /* MTU checking */
        mtu = dst_mtu(&rt->dst);
        if (skb->len > mtu) {
+               if (!skb->dev) {
+                       struct net *net = dev_net(skb_dst(skb)->dev);
+
+                       skb->dev = net->loopback_dev;
+               }
                icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
                IP_VS_DBG_RL("%s(): frag needed\n", __func__);
                goto tx_error_put;