From: Thomas Graf <tgraf@redhat.com> Date: Thu, 16 Sep 2010 07:56:34 -0400 Subject: [net] ipvs: add one-packet scheduler Message-id: <20100916075634.GA17860@lsx.localdomain> Patchwork-id: 28255 O-Subject: [PATCH RHEL5.6] ipvs: add one-packet scheduler (BZ578836) Bugzilla: 578836 RH-Acked-by: Neil Horman <nhorman@redhat.com> RH-Acked-by: David S. Miller <davem@redhat.com> RH-Acked-by: Amerigo Wang <amwang@redhat.com> A customer requested the inclusion of the one-packet scheduler for ipvs as found in RHEL6 and upstream kernel. This patch backports the one-packet scheduler. Brew: https://brewweb.devel.redhat.com/taskinfo?taskID=2764178 Tested by Jan Friesse. Resolves BZ578836 Signed-off-by: Jarod Wilson <jarod@redhat.com> diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index 8616dab..25f6d3f 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -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 @@ -85,6 +86,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 --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c index 87b8381..3a0bb85 100644 --- a/net/ipv4/ipvs/ip_vs_conn.c +++ b/net/ipv4/ipvs/ip_vs_conn.c @@ -131,6 +131,9 @@ static inline int ip_vs_conn_hash(struct ip_vs_conn *cp) 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); @@ -314,6 +317,11 @@ struct ip_vs_conn *ip_vs_conn_out_get */ 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); + return; + } + /* reset it expire in its timeout */ mod_timer(&cp->timer, jiffies+cp->timeout); @@ -547,7 +555,7 @@ static void ip_vs_conn_expire(unsigned long data) /* * 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 --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c index 4efefd9..49c6efa 100644 --- a/net/ipv4/ipvs/ip_vs_core.c +++ b/net/ipv4/ipvs/ip_vs_core.c @@ -216,6 +216,7 @@ ip_vs_sched_persist(struct ip_vs_service *svc, struct ip_vs_dest *dest; struct ip_vs_conn *ct; __u16 dport; /* destination port to forward */ + __u16 flags; __u32 snet; /* source network of the client, after masking */ /* Mask saddr with the netmask to adjust template granularity */ @@ -346,6 +347,9 @@ ip_vs_sched_persist(struct ip_vs_service *svc, dport = ports[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 */ @@ -353,7 +357,7 @@ ip_vs_sched_persist(struct ip_vs_service *svc, iph->saddr, ports[0], iph->daddr, ports[1], dest->addr, dport, - 0, + flags, dest); if (cp == NULL) { ip_vs_conn_put(ct); @@ -384,6 +388,7 @@ ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) struct iphdr *iph = skb->nh.iph; struct ip_vs_dest *dest; __u16 _ports[2], *pptr; + __u16 flags; pptr = skb_header_pointer(skb, iph->ihl*4, sizeof(_ports), _ports); @@ -413,6 +418,9 @@ ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) 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. */ @@ -420,7 +428,7 @@ ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) iph->saddr, pptr[0], iph->daddr, pptr[1], dest->addr, dest->port?dest->port:pptr[1], - 0, + flags, dest); if (cp == NULL) return NULL; @@ -463,6 +471,9 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb, && (inet_addr_type(iph->daddr) == RTN_UNICAST)) { int ret, cs; 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); @@ -472,7 +483,7 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb, iph->saddr, pptr[0], iph->daddr, pptr[1], 0, 0, - IP_VS_CONN_F_BYPASS, + IP_VS_CONN_F_BYPASS | flags, NULL); if (cp == NULL) return NF_DROP; diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c index 6a28faf..c47c415 100644 --- a/net/ipv4/ipvs/ip_vs_ctl.c +++ b/net/ipv4/ipvs/ip_vs_ctl.c @@ -1754,14 +1754,18 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v) const struct ip_vs_dest *dest; if (iter->table == ip_vs_svc_table) - seq_printf(seq, "%s %08X:%04X %s ", + seq_printf(seq, "%s %08X:%04X %s%s ", ip_vs_proto_name(svc->protocol), ntohl(svc->addr), ntohs(svc->port), - svc->scheduler->name); + svc->scheduler->name, + (svc->flags & IP_VS_SVC_F_ONEPACKET)? + " ops":""); else - seq_printf(seq, "FWM %08X %s ", - svc->fwmark, svc->scheduler->name); + seq_printf(seq, "FWM %08X %s%s ", + svc->fwmark, svc->scheduler->name, + (svc->flags & IP_VS_SVC_F_ONEPACKET)? + " ops":""); if (svc->flags & IP_VS_SVC_F_PERSISTENT) seq_printf(seq, "persistent %d %08X\n",