ipvs: sh: support scheduling icmp/inverse packets consistently
authorAlex Gartrell <agartrell@fb.com>
Wed, 26 Aug 2015 16:40:36 +0000 (09:40 -0700)
committerSimon Horman <horms@verge.net.au>
Tue, 1 Sep 2015 01:33:52 +0000 (10:33 +0900)
"source_hash" the dest fields if it's an inverse packet.

Signed-off-by: Alex Gartrell <agartrell@fb.com>
Acked-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Simon Horman <horms@verge.net.au>
net/netfilter/ipvs/ip_vs_sh.c

index 98a13433b68c226fee24e3421d5c46c5f0cc8a75..1e373a5e44e34cf172f3843b1fcc700ed3a57cbc 100644 (file)
@@ -280,35 +280,29 @@ static int ip_vs_sh_dest_changed(struct ip_vs_service *svc,
 static inline __be16
 ip_vs_sh_get_port(const struct sk_buff *skb, struct ip_vs_iphdr *iph)
 {
-       __be16 port;
-       struct tcphdr _tcph, *th;
-       struct udphdr _udph, *uh;
-       sctp_sctphdr_t _sctph, *sh;
+       __be16 _ports[2], *ports;
 
+       /* At this point we know that we have a valid packet of some kind.
+        * Because ICMP packets are only guaranteed to have the first 8
+        * bytes, let's just grab the ports.  Fortunately they're in the
+        * same position for all three of the protocols we care about.
+        */
        switch (iph->protocol) {
        case IPPROTO_TCP:
-               th = skb_header_pointer(skb, iph->len, sizeof(_tcph), &_tcph);
-               if (unlikely(th == NULL))
-                       return 0;
-               port = th->source;
-               break;
        case IPPROTO_UDP:
-               uh = skb_header_pointer(skb, iph->len, sizeof(_udph), &_udph);
-               if (unlikely(uh == NULL))
-                       return 0;
-               port = uh->source;
-               break;
        case IPPROTO_SCTP:
-               sh = skb_header_pointer(skb, iph->len, sizeof(_sctph), &_sctph);
-               if (unlikely(sh == NULL))
+               ports = skb_header_pointer(skb, iph->len, sizeof(_ports),
+                                          &_ports);
+               if (unlikely(!ports))
                        return 0;
-               port = sh->source;
-               break;
+
+               if (likely(!ip_vs_iph_inverse(iph)))
+                       return ports[0];
+               else
+                       return ports[1];
        default:
-               port = 0;
+               return 0;
        }
-
-       return port;
 }
 
 
@@ -322,6 +316,9 @@ ip_vs_sh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
        struct ip_vs_dest *dest;
        struct ip_vs_sh_state *s;
        __be16 port = 0;
+       const union nf_inet_addr *hash_addr;
+
+       hash_addr = ip_vs_iph_inverse(iph) ? &iph->daddr : &iph->saddr;
 
        IP_VS_DBG(6, "ip_vs_sh_schedule(): Scheduling...\n");
 
@@ -331,9 +328,9 @@ ip_vs_sh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
        s = (struct ip_vs_sh_state *) svc->sched_data;
 
        if (svc->flags & IP_VS_SVC_F_SCHED_SH_FALLBACK)
-               dest = ip_vs_sh_get_fallback(svc, s, &iph->saddr, port);
+               dest = ip_vs_sh_get_fallback(svc, s, hash_addr, port);
        else
-               dest = ip_vs_sh_get(svc, s, &iph->saddr, port);
+               dest = ip_vs_sh_get(svc, s, hash_addr, port);
 
        if (!dest) {
                ip_vs_scheduler_err(svc, "no destination available");
@@ -341,7 +338,7 @@ ip_vs_sh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
        }
 
        IP_VS_DBG_BUF(6, "SH: source IP address %s --> server %s:%d\n",
-                     IP_VS_DBG_ADDR(svc->af, &iph->saddr),
+                     IP_VS_DBG_ADDR(svc->af, hash_addr),
                      IP_VS_DBG_ADDR(dest->af, &dest->addr),
                      ntohs(dest->port));