Commit 26ec037f9841e49cc5c615deb8e1e73e5beab2ca

Authored by Nick Chalk
Committed by Patrick McHardy
1 parent c68cd6cc21

IPVS: one-packet scheduling

Allow one-packet scheduling for UDP connections. When the fwmark-based or
normal virtual service is marked with '-o' or '--ops' options all
connections are created only to schedule one packet. Useful to schedule UDP
packets from same client port to different real servers. Recommended with
RR or WRR schedulers (the connections are not visible with ipvsadm -L).

Signed-off-by: Nick Chalk <nick@loadbalancer.org>
Signed-off-by: Simon Horman <horms@verge.net.au>
Signed-off-by: Patrick McHardy <kaber@trash.net>

Showing 4 changed files with 31 additions and 11 deletions Side-by-side Diff

include/linux/ip_vs.h
... ... @@ -19,6 +19,7 @@
19 19 */
20 20 #define IP_VS_SVC_F_PERSISTENT 0x0001 /* persistent port */
21 21 #define IP_VS_SVC_F_HASHED 0x0002 /* hashed entry */
  22 +#define IP_VS_SVC_F_ONEPACKET 0x0004 /* one-packet scheduling */
22 23  
23 24 /*
24 25 * Destination Server Flags
... ... @@ -85,6 +86,7 @@
85 86 #define IP_VS_CONN_F_SEQ_MASK 0x0600 /* in/out sequence mask */
86 87 #define IP_VS_CONN_F_NO_CPORT 0x0800 /* no client port set yet */
87 88 #define IP_VS_CONN_F_TEMPLATE 0x1000 /* template, not connection */
  89 +#define IP_VS_CONN_F_ONE_PACKET 0x2000 /* forward only one packet */
88 90  
89 91 #define IP_VS_SCHEDNAME_MAXLEN 16
90 92 #define IP_VS_IFNAME_MAXLEN 16
net/netfilter/ipvs/ip_vs_conn.c
... ... @@ -158,6 +158,9 @@
158 158 unsigned hash;
159 159 int ret;
160 160  
  161 + if (cp->flags & IP_VS_CONN_F_ONE_PACKET)
  162 + return 0;
  163 +
161 164 /* Hash by protocol, client address and port */
162 165 hash = ip_vs_conn_hashkey(cp->af, cp->protocol, &cp->caddr, cp->cport);
163 166  
... ... @@ -355,8 +358,9 @@
355 358 */
356 359 void ip_vs_conn_put(struct ip_vs_conn *cp)
357 360 {
358   - /* reset it expire in its timeout */
359   - mod_timer(&cp->timer, jiffies+cp->timeout);
  361 + unsigned long t = (cp->flags & IP_VS_CONN_F_ONE_PACKET) ?
  362 + 0 : cp->timeout;
  363 + mod_timer(&cp->timer, jiffies+t);
360 364  
361 365 __ip_vs_conn_put(cp);
362 366 }
... ... @@ -649,7 +653,7 @@
649 653 /*
650 654 * unhash it if it is hashed in the conn table
651 655 */
652   - if (!ip_vs_conn_unhash(cp))
  656 + if (!ip_vs_conn_unhash(cp) && !(cp->flags & IP_VS_CONN_F_ONE_PACKET))
653 657 goto expire_later;
654 658  
655 659 /*
net/netfilter/ipvs/ip_vs_core.c
... ... @@ -194,6 +194,7 @@
194 194 struct ip_vs_dest *dest;
195 195 struct ip_vs_conn *ct;
196 196 __be16 dport; /* destination port to forward */
  197 + __be16 flags;
197 198 union nf_inet_addr snet; /* source network of the client,
198 199 after masking */
199 200  
... ... @@ -340,6 +341,10 @@
340 341 dport = ports[1];
341 342 }
342 343  
  344 + flags = (svc->flags & IP_VS_SVC_F_ONEPACKET
  345 + && iph.protocol == IPPROTO_UDP)?
  346 + IP_VS_CONN_F_ONE_PACKET : 0;
  347 +
343 348 /*
344 349 * Create a new connection according to the template
345 350 */
... ... @@ -347,7 +352,7 @@
347 352 &iph.saddr, ports[0],
348 353 &iph.daddr, ports[1],
349 354 &dest->addr, dport,
350   - 0,
  355 + flags,
351 356 dest);
352 357 if (cp == NULL) {
353 358 ip_vs_conn_put(ct);
... ... @@ -377,7 +382,7 @@
377 382 struct ip_vs_conn *cp = NULL;
378 383 struct ip_vs_iphdr iph;
379 384 struct ip_vs_dest *dest;
380   - __be16 _ports[2], *pptr;
  385 + __be16 _ports[2], *pptr, flags;
381 386  
382 387 ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
383 388 pptr = skb_header_pointer(skb, iph.len, sizeof(_ports), _ports);
... ... @@ -407,6 +412,10 @@
407 412 return NULL;
408 413 }
409 414  
  415 + flags = (svc->flags & IP_VS_SVC_F_ONEPACKET
  416 + && iph.protocol == IPPROTO_UDP)?
  417 + IP_VS_CONN_F_ONE_PACKET : 0;
  418 +
410 419 /*
411 420 * Create a connection entry.
412 421 */
... ... @@ -414,7 +423,7 @@
414 423 &iph.saddr, pptr[0],
415 424 &iph.daddr, pptr[1],
416 425 &dest->addr, dest->port ? dest->port : pptr[1],
417   - 0,
  426 + flags,
418 427 dest);
419 428 if (cp == NULL)
420 429 return NULL;
... ... @@ -464,6 +473,9 @@
464 473 if (sysctl_ip_vs_cache_bypass && svc->fwmark && unicast) {
465 474 int ret, cs;
466 475 struct ip_vs_conn *cp;
  476 + __u16 flags = (svc->flags & IP_VS_SVC_F_ONEPACKET &&
  477 + iph.protocol == IPPROTO_UDP)?
  478 + IP_VS_CONN_F_ONE_PACKET : 0;
467 479 union nf_inet_addr daddr = { .all = { 0, 0, 0, 0 } };
468 480  
469 481 ip_vs_service_put(svc);
... ... @@ -474,7 +486,7 @@
474 486 &iph.saddr, pptr[0],
475 487 &iph.daddr, pptr[1],
476 488 &daddr, 0,
477   - IP_VS_CONN_F_BYPASS,
  489 + IP_VS_CONN_F_BYPASS | flags,
478 490 NULL);
479 491 if (cp == NULL)
480 492 return NF_DROP;
net/netfilter/ipvs/ip_vs_ctl.c
... ... @@ -1864,14 +1864,16 @@
1864 1864 svc->scheduler->name);
1865 1865 else
1866 1866 #endif
1867   - seq_printf(seq, "%s %08X:%04X %s ",
  1867 + seq_printf(seq, "%s %08X:%04X %s %s ",
1868 1868 ip_vs_proto_name(svc->protocol),
1869 1869 ntohl(svc->addr.ip),
1870 1870 ntohs(svc->port),
1871   - svc->scheduler->name);
  1871 + svc->scheduler->name,
  1872 + (svc->flags & IP_VS_SVC_F_ONEPACKET)?"ops ":"");
1872 1873 } else {
1873   - seq_printf(seq, "FWM %08X %s ",
1874   - svc->fwmark, svc->scheduler->name);
  1874 + seq_printf(seq, "FWM %08X %s %s",
  1875 + svc->fwmark, svc->scheduler->name,
  1876 + (svc->flags & IP_VS_SVC_F_ONEPACKET)?"ops ":"");
1875 1877 }
1876 1878  
1877 1879 if (svc->flags & IP_VS_SVC_F_PERSISTENT)