Commit 1471f35efa86407fc180ca6d55363c684d166ef6
Committed by
Simon Horman
1 parent
3481894fcb
ipvs: sh: support scheduling icmp/inverse packets consistently
"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>
Showing 1 changed file with 21 additions and 24 deletions Side-by-side Diff
net/netfilter/ipvs/ip_vs_sh.c
... | ... | @@ -280,35 +280,29 @@ |
280 | 280 | static inline __be16 |
281 | 281 | ip_vs_sh_get_port(const struct sk_buff *skb, struct ip_vs_iphdr *iph) |
282 | 282 | { |
283 | - __be16 port; | |
284 | - struct tcphdr _tcph, *th; | |
285 | - struct udphdr _udph, *uh; | |
286 | - sctp_sctphdr_t _sctph, *sh; | |
283 | + __be16 _ports[2], *ports; | |
287 | 284 | |
285 | + /* At this point we know that we have a valid packet of some kind. | |
286 | + * Because ICMP packets are only guaranteed to have the first 8 | |
287 | + * bytes, let's just grab the ports. Fortunately they're in the | |
288 | + * same position for all three of the protocols we care about. | |
289 | + */ | |
288 | 290 | switch (iph->protocol) { |
289 | 291 | case IPPROTO_TCP: |
290 | - th = skb_header_pointer(skb, iph->len, sizeof(_tcph), &_tcph); | |
291 | - if (unlikely(th == NULL)) | |
292 | - return 0; | |
293 | - port = th->source; | |
294 | - break; | |
295 | 292 | case IPPROTO_UDP: |
296 | - uh = skb_header_pointer(skb, iph->len, sizeof(_udph), &_udph); | |
297 | - if (unlikely(uh == NULL)) | |
298 | - return 0; | |
299 | - port = uh->source; | |
300 | - break; | |
301 | 293 | case IPPROTO_SCTP: |
302 | - sh = skb_header_pointer(skb, iph->len, sizeof(_sctph), &_sctph); | |
303 | - if (unlikely(sh == NULL)) | |
294 | + ports = skb_header_pointer(skb, iph->len, sizeof(_ports), | |
295 | + &_ports); | |
296 | + if (unlikely(!ports)) | |
304 | 297 | return 0; |
305 | - port = sh->source; | |
306 | - break; | |
298 | + | |
299 | + if (likely(!ip_vs_iph_inverse(iph))) | |
300 | + return ports[0]; | |
301 | + else | |
302 | + return ports[1]; | |
307 | 303 | default: |
308 | - port = 0; | |
304 | + return 0; | |
309 | 305 | } |
310 | - | |
311 | - return port; | |
312 | 306 | } |
313 | 307 | |
314 | 308 | |
315 | 309 | |
... | ... | @@ -322,7 +316,10 @@ |
322 | 316 | struct ip_vs_dest *dest; |
323 | 317 | struct ip_vs_sh_state *s; |
324 | 318 | __be16 port = 0; |
319 | + const union nf_inet_addr *hash_addr; | |
325 | 320 | |
321 | + hash_addr = ip_vs_iph_inverse(iph) ? &iph->daddr : &iph->saddr; | |
322 | + | |
326 | 323 | IP_VS_DBG(6, "ip_vs_sh_schedule(): Scheduling...\n"); |
327 | 324 | |
328 | 325 | if (svc->flags & IP_VS_SVC_F_SCHED_SH_PORT) |
329 | 326 | |
... | ... | @@ -331,9 +328,9 @@ |
331 | 328 | s = (struct ip_vs_sh_state *) svc->sched_data; |
332 | 329 | |
333 | 330 | if (svc->flags & IP_VS_SVC_F_SCHED_SH_FALLBACK) |
334 | - dest = ip_vs_sh_get_fallback(svc, s, &iph->saddr, port); | |
331 | + dest = ip_vs_sh_get_fallback(svc, s, hash_addr, port); | |
335 | 332 | else |
336 | - dest = ip_vs_sh_get(svc, s, &iph->saddr, port); | |
333 | + dest = ip_vs_sh_get(svc, s, hash_addr, port); | |
337 | 334 | |
338 | 335 | if (!dest) { |
339 | 336 | ip_vs_scheduler_err(svc, "no destination available"); |
... | ... | @@ -341,7 +338,7 @@ |
341 | 338 | } |
342 | 339 | |
343 | 340 | IP_VS_DBG_BUF(6, "SH: source IP address %s --> server %s:%d\n", |
344 | - IP_VS_DBG_ADDR(svc->af, &iph->saddr), | |
341 | + IP_VS_DBG_ADDR(svc->af, hash_addr), | |
345 | 342 | IP_VS_DBG_ADDR(dest->af, &dest->addr), |
346 | 343 | ntohs(dest->port)); |
347 | 344 |