From: Julian Anastasov 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). Up-port of http://www.ssi.bg/~ja/tmp/ops-2.4.32-1.diff to 2.6.18-128.el5 by Simon Horman. Signed-off-by: Simon Horman diff -ur v2.4.32/linux/include/net/ip_vs.h linux/include/net/ip_vs.h --- v2.4.32/linux/include/net/ip_vs.h 2005-11-17 00:18:44.000000000 +0200 +++ linux/include/net/ip_vs.h 2005-11-17 10:36:57.461647080 +0200 @@ -19,6 +19,7 @@ */ #define IP_VS_SVC_F_PERSISTENT 0x0001 /* persistent port */ #define IP_VS_SVC_F_HASHED 0x0002 /* hashed entry */ +#define IP_VS_SVC_F_ONEPACKET 0x0004 /* one-packet scheduling */ /* * Destination Server Flags @@ -83,6 +84,7 @@ #define IP_VS_CONN_F_SEQ_MASK 0x0600 /* in/out sequence mask */ #define IP_VS_CONN_F_NO_CPORT 0x0800 /* no client port set yet */ #define IP_VS_CONN_F_TEMPLATE 0x1000 /* template, not connection */ +#define IP_VS_CONN_F_ONE_PACKET 0x2000 /* forward only one packet */ /* Move it to better place one day, for now keep it unique */ #define NFC_IPVS_PROPERTY 0x10000 diff -ur v2.4.32/linux/net/ipv4/ipvs/ip_vs_conn.c linux/net/ipv4/ipvs/ip_vs_conn.c --- v2.4.32/linux/net/ipv4/ipvs/ip_vs_conn.c 2005-11-17 00:18:44.000000000 +0200 +++ linux/net/ipv4/ipvs/ip_vs_conn.c 2005-11-17 10:39:41.570698712 +0200 @@ -139,6 +139,9 @@ unsigned hash; int ret; + if (cp->flags & IP_VS_CONN_F_ONE_PACKET) + return 0; + /* Hash by protocol, client address and port */ hash = ip_vs_conn_hashkey(cp->protocol, cp->caddr, cp->cport); @@ -327,6 +330,12 @@ */ void ip_vs_conn_put(struct ip_vs_conn *cp) { + if (cp->flags & IP_VS_CONN_F_ONE_PACKET) { + ip_vs_conn_expire_now(cp); + __ip_vs_conn_put(cp); + return; + } + /* reset it expire in its timeout */ mod_timer(&cp->timer, jiffies+cp->timeout); @@ -1240,7 +1249,7 @@ /* * unhash it if it is hashed in the conn table */ - if (!ip_vs_conn_unhash(cp)) + if (!ip_vs_conn_unhash(cp) && !(cp->flags & IP_VS_CONN_F_ONE_PACKET)) goto expire_later; /* diff -ur v2.4.32/linux/net/ipv4/ipvs/ip_vs_core.c linux/net/ipv4/ipvs/ip_vs_core.c --- v2.4.32/linux/net/ipv4/ipvs/ip_vs_core.c 2005-11-17 00:18:44.000000000 +0200 +++ linux/net/ipv4/ipvs/ip_vs_core.c 2005-11-17 10:36:57.463646776 +0200 @@ -159,6 +159,7 @@ const __u16 *portp; struct ip_vs_conn *ct; __u16 dport; /* destination port to forward */ + __u16 flags; __u32 snet; /* source network of the client, after masking */ portp = (__u16 *)&(((char *)iph)[iph->ihl*4]); @@ -290,6 +291,9 @@ dport = portp[1]; } + flags = (svc->flags & IP_VS_SVC_F_ONEPACKET + && iph->protocol == IPPROTO_UDP)? + IP_VS_CONN_F_ONE_PACKET : 0; /* * Create a new connection according to the template */ @@ -297,7 +301,7 @@ iph->saddr, portp[0], iph->daddr, portp[1], dest->addr, dport, - 0, + flags, dest); if (cp == NULL) { ip_vs_conn_put(ct); @@ -332,6 +336,7 @@ struct ip_vs_conn *cp = NULL; struct ip_vs_dest *dest; __u16 _ports[2], *pptr; + __u16 flags; pptr = skb_header_pointer(skb, iph->ihl*4, sizeof(_ports), _ports); @@ -357,6 +362,9 @@ return NULL; } + flags = (svc->flags & IP_VS_SVC_F_ONEPACKET + && iph->protocol == IPPROTO_UDP)? + IP_VS_CONN_F_ONE_PACKET : 0; /* * Create a connection entry. */ @@ -364,7 +372,7 @@ iph->saddr, pptr[0], iph->daddr, pptr[1], dest->addr, dest->port?dest->port:pptr[1], - 0, + flags, dest); if (cp == NULL) return NULL; @@ -404,6 +412,9 @@ && (inet_addr_type(iph->daddr) == RTN_UNICAST)) { int ret; struct ip_vs_conn *cp; + __u16 flags = (svc->flags & IP_VS_SVC_F_ONEPACKET && + iph->protocol == IPPROTO_UDP)? + IP_VS_CONN_F_ONE_PACKET : 0; ip_vs_service_put(svc); @@ -413,7 +424,7 @@ iph->saddr, portp[0], iph->daddr, portp[1], 0, 0, - IP_VS_CONN_F_BYPASS, + IP_VS_CONN_F_BYPASS | flags, NULL); if (cp == NULL) { kfree_skb(skb);