netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [patch v5 00/12] IPVS: SIP Persistence Engine
@ 2010-10-04 13:46 Simon Horman
  2010-10-04 13:46 ` [patch v5 01/12] netfilter: nf_conntrack_sip: Allow ct_sip_get_header() to be called with a null ct argument Simon Horman
                   ` (12 more replies)
  0 siblings, 13 replies; 18+ messages in thread
From: Simon Horman @ 2010-10-04 13:46 UTC (permalink / raw)
  To: lvs-devel, netdev, netfilter, netfilter-devel
  Cc: Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
	Julian Anastasov, Patrick McHardy

This patch series adds load-balancing of UDP SIP based on Call-ID to
IPVS as well as a frame-work for extending IPVS to handle alternate
persistence requirements.

REVISIONS

This is v5 of the patch series which fixes a typo introduced in v4.

v4 of the patch series which addressed the following concerns
raised by Julian Anastasov:
 - initialize compat structures to avoid crash in
   ip_vs_add_service for pe_name
 - fix ip_vs_conn_out_get_proto to properly check the
   ip_vs_conn_fill_param_proto result

These changes and changes from previous revisions of this patch series
are noted on a per-patch basis.

I have taken the liberty of including Acked-by: Julian Anastasov <ja@ssi.bg>
although the ack was provided before the v4 and v5 above were discovered.

OVERVIEW

The approach that I have taken is what I call persistence engines.
The basic idea being that you can provide a module to LVS that alters
the way that it handles connection templates, which are at the core
of persistence. In particular, an additional key can be added, and
any of the normal IP address, port and protocol information can either
be used or ignored.

In the case of the SIP persistence engine, the only persistence engine, all
the keys used by the default persistence behaviour are used and the callid
is added as an extra key. I originally intended to ignore the cip, but this
can optionally be done by setting the persistence mask (-M) to 0.0.0.0
while allowing the flexibility of other mask values.

It is envisaged that the SIP persistence engine will be used in conjunction
with one-packet scheduling. I'm interested to hear if that doesn't fit your
needs.


CONFIGURATION

A persistence engine is associated with a virtual service
(as are schedulers). I have added the --pe option to the
ivpsadm -A and -E commands to allow the persistence engine
of a virtual service to be added, changed, or deleted.

e.g. ipvsadm -A -u 10.4.3.192:5060 -p 60 -M 0.0.0.0 -o --pe sip

There are no other configuration parameters at this time.


RUNNING

When a connection template is created, if its virtual service
has a persistence engine, then the persistence engine can add
an extra key to the connection template. For the SIP module this
is the callid. More generically, it is known as "pe data". And
both the name of the persistence engine, "pe name", and "pe data"
can be viewed in /proc/net/ip_vs_conn and by passing the
--persistent-conn option to ipvsadm -Lc.

e.g.
# ipvsadm -Lcn --persistent-conn
UDP 00:38  UDP         10.4.3.0:0         10.4.3.192:5060    127.0.0.1:5060 sip 193373839

Here we see a single persistence template (cport is 0), which has been
handled by the sip persistence engine. The pe data (callid) is 193373839.

In the case where the persistence engine can't match a packet for some
reason, the connection will fall back to the normal persistence handling.
This seems reasonable, as that if the packet ought to be dropped, iptables
could be used.

A limited amount of debugging information has been added which
can be enabled using a value of 9 or greater in
/proc/sys/net/ipv4/vs/debug_level

CODE AVAILABILITY

The kernel patches (12) are available in git as the pe-5 branch of
git://git.kernel.org/pub/scm/linux/kernel/git/horms/lvs-test-2.6.git

The ipvsadm patches (2) are available in git as the pe-5 branch of
git://github.com/horms/ipvsadm-test.git

There is no change to the ipvsadm patches since the v2 series
so I will not repost them.


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [patch v5 01/12] netfilter: nf_conntrack_sip: Allow ct_sip_get_header() to be called with a null ct argument
  2010-10-04 13:46 [patch v5 00/12] IPVS: SIP Persistence Engine Simon Horman
@ 2010-10-04 13:46 ` Simon Horman
  2010-10-04 13:46 ` [patch v5 02/12] netfilter: nf_conntrack_sip: Add callid parser Simon Horman
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 18+ messages in thread
From: Simon Horman @ 2010-10-04 13:46 UTC (permalink / raw)
  To: lvs-devel, netdev, netfilter, netfilter-devel
  Cc: Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
	Julian Anastasov, Patrick McHardy

[-- Attachment #1: 0001-netfilter-nf_conntrack_sip-Allow-ct_sip_get_header-t.patch --]
[-- Type: text/plain, Size: 515 bytes --]

Signed-off-by: Simon Horman <horms@verge.net.au>
Acked-by: Julian Anastasov <ja@ssi.bg>

diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 53d8922..2fd1ea2 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -152,6 +152,9 @@ static int parse_addr(const struct nf_conn *ct, const char *cp,
 	const char *end;
 	int ret = 0;
 
+	if (!ct)
+		return 0;
+
 	memset(addr, 0, sizeof(*addr));
 	switch (nf_ct_l3num(ct)) {
 	case AF_INET:
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [patch v5 02/12] netfilter: nf_conntrack_sip: Add callid parser
  2010-10-04 13:46 [patch v5 00/12] IPVS: SIP Persistence Engine Simon Horman
  2010-10-04 13:46 ` [patch v5 01/12] netfilter: nf_conntrack_sip: Allow ct_sip_get_header() to be called with a null ct argument Simon Horman
@ 2010-10-04 13:46 ` Simon Horman
  2010-10-04 13:46 ` [patch v5 03/12] IPVS: compact ip_vs_sched_persist() Simon Horman
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 18+ messages in thread
From: Simon Horman @ 2010-10-04 13:46 UTC (permalink / raw)
  To: lvs-devel, netdev, netfilter, netfilter-devel
  Cc: Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
	Julian Anastasov, Patrick McHardy

[-- Attachment #1: 0002-netfilter-nf_conntrack_sip-Add-callid-parser.patch --]
[-- Type: text/plain, Size: 2483 bytes --]

Signed-off-by: Simon Horman <horms@verge.net.au>
Acked-by: Julian Anastasov <ja@ssi.bg>

--- 

The motivation for this is for it to be used by LVS as per
subsequent patches.

* Patrick McHardy suggested changing word_len to check for the
  next newline or whitespace. But I believe this is incorrect.
  For example '#' would be permitted but it is invalid
  in a word according to RFC3261.


diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h
index ff8cfbc..0ce91d5 100644
--- a/include/linux/netfilter/nf_conntrack_sip.h
+++ b/include/linux/netfilter/nf_conntrack_sip.h
@@ -89,6 +89,7 @@ enum sip_header_types {
 	SIP_HDR_VIA_TCP,
 	SIP_HDR_EXPIRES,
 	SIP_HDR_CONTENT_LENGTH,
+	SIP_HDR_CALL_ID,
 };
 
 enum sdp_header_types {
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 2fd1ea2..715ce54 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -130,6 +130,44 @@ static int digits_len(const struct nf_conn *ct, const char *dptr,
 	return len;
 }
 
+static int iswordc(const char c)
+{
+	if (isalnum(c) || c == '!' || c == '"' || c == '%' ||
+	    (c >= '(' && c <= '/') || c == ':' || c == '<' || c == '>' ||
+	    c == '?' || (c >= '[' && c <= ']') || c == '_' || c == '`' ||
+	    c == '{' || c == '}' || c == '~')
+		return 1;
+	return 0;
+}
+
+static int word_len(const char *dptr, const char *limit)
+{
+	int len = 0;
+	while (dptr < limit && iswordc(*dptr)) {
+		dptr++;
+		len++;
+	}
+	return len;
+}
+
+static int callid_len(const struct nf_conn *ct, const char *dptr,
+		      const char *limit, int *shift)
+{
+	int len, domain_len;
+
+	len = word_len(dptr, limit);
+	dptr += len;
+	if (!len || dptr == limit || *dptr != '@')
+		return len;
+	dptr++;
+	len++;
+
+	domain_len = word_len(dptr, limit);
+	if (!domain_len)
+		return 0;
+	return len + domain_len;
+}
+
 /* get media type + port length */
 static int media_len(const struct nf_conn *ct, const char *dptr,
 		     const char *limit, int *shift)
@@ -299,6 +337,7 @@ static const struct sip_header ct_sip_hdrs[] = {
 	[SIP_HDR_VIA_TCP]		= SIP_HDR("Via", "v", "TCP ", epaddr_len),
 	[SIP_HDR_EXPIRES]		= SIP_HDR("Expires", NULL, NULL, digits_len),
 	[SIP_HDR_CONTENT_LENGTH]	= SIP_HDR("Content-Length", "l", NULL, digits_len),
+	[SIP_HDR_CALL_ID]		= SIP_HDR("Call-Id", "i", NULL, callid_len),
 };
 
 static const char *sip_follow_continuation(const char *dptr, const char *limit)
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [patch v5 03/12] IPVS: compact ip_vs_sched_persist()
  2010-10-04 13:46 [patch v5 00/12] IPVS: SIP Persistence Engine Simon Horman
  2010-10-04 13:46 ` [patch v5 01/12] netfilter: nf_conntrack_sip: Allow ct_sip_get_header() to be called with a null ct argument Simon Horman
  2010-10-04 13:46 ` [patch v5 02/12] netfilter: nf_conntrack_sip: Add callid parser Simon Horman
@ 2010-10-04 13:46 ` Simon Horman
  2010-10-04 13:46 ` [patch v5 04/12] IPVS: Add struct ip_vs_conn_param Simon Horman
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 18+ messages in thread
From: Simon Horman @ 2010-10-04 13:46 UTC (permalink / raw)
  To: lvs-devel, netdev, netfilter, netfilter-devel
  Cc: Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
	Julian Anastasov, Patrick McHardy

[-- Attachment #1: 0003-IPVS-compact-ip_vs_sched_persist.patch --]
[-- Type: text/plain, Size: 5897 bytes --]

Compact ip_vs_sched_persist() by setting up parameters
and calling functions once.

Signed-off-by: Simon Horman <horms@verge.net.au>
Acked-by: Julian Anastasov <ja@ssi.bg>

---

v2
* Make "union nf_inet_addr fwmark" const
* Don't remove the comment next to the declaration of dport
* Add a comment to the declaration of vport

v3
* As suggested by Julian Anastasov
  - Correct dport logic

Index: lvs-test-2.6/net/netfilter/ipvs/ip_vs_core.c
===================================================================
--- lvs-test-2.6.orig/net/netfilter/ipvs/ip_vs_core.c	2010-10-02 10:54:57.000000000 +0900
+++ lvs-test-2.6/net/netfilter/ipvs/ip_vs_core.c	2010-10-02 11:04:04.000000000 +0900
@@ -193,10 +193,14 @@ ip_vs_sched_persist(struct ip_vs_service
 	struct ip_vs_iphdr iph;
 	struct ip_vs_dest *dest;
 	struct ip_vs_conn *ct;
-	__be16  dport;			/* destination port to forward */
+	int protocol = iph.protocol;
+	__be16 dport = 0;		/* destination port to forward */
+	__be16 vport = 0;		/* virtual service port */
 	unsigned int flags;
 	union nf_inet_addr snet;	/* source network of the client,
 					   after masking */
+	const union nf_inet_addr fwmark = { .ip = htonl(svc->fwmark) };
+	const union nf_inet_addr *vaddr = &iph.daddr;
 
 	ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
 
@@ -227,119 +231,61 @@ ip_vs_sched_persist(struct ip_vs_service
 	 * service, and a template like <caddr, 0, vaddr, vport, daddr, dport>
 	 * is created for other persistent services.
 	 */
-	if (ports[1] == svc->port) {
-		/* Check if a template already exists */
-		if (svc->port != FTPPORT)
-			ct = ip_vs_ct_in_get(svc->af, iph.protocol, &snet, 0,
-					     &iph.daddr, ports[1]);
-		else
-			ct = ip_vs_ct_in_get(svc->af, iph.protocol, &snet, 0,
-					     &iph.daddr, 0);
-
-		if (!ct || !ip_vs_check_template(ct)) {
-			/*
-			 * No template found or the dest of the connection
-			 * template is not available.
-			 */
-			dest = svc->scheduler->schedule(svc, skb);
-			if (dest == NULL) {
-				IP_VS_DBG(1, "p-schedule: no dest found.\n");
-				return NULL;
-			}
-
-			/*
-			 * Create a template like <protocol,caddr,0,
-			 * vaddr,vport,daddr,dport> for non-ftp service,
-			 * and <protocol,caddr,0,vaddr,0,daddr,0>
-			 * for ftp service.
+	{
+		if (ports[1] == svc->port) {
+			/* non-FTP template:
+			 * <protocol, caddr, 0, vaddr, vport, daddr, dport>
+			 * FTP template:
+			 * <protocol, caddr, 0, vaddr, 0, daddr, 0>
 			 */
 			if (svc->port != FTPPORT)
-				ct = ip_vs_conn_new(svc->af, iph.protocol,
-						    &snet, 0,
-						    &iph.daddr,
-						    ports[1],
-						    &dest->addr, dest->port,
-						    IP_VS_CONN_F_TEMPLATE,
-						    dest);
-			else
-				ct = ip_vs_conn_new(svc->af, iph.protocol,
-						    &snet, 0,
-						    &iph.daddr, 0,
-						    &dest->addr, 0,
-						    IP_VS_CONN_F_TEMPLATE,
-						    dest);
-			if (ct == NULL)
-				return NULL;
-
-			ct->timeout = svc->timeout;
+				vport = ports[1];
 		} else {
-			/* set destination with the found template */
-			dest = ct->dest;
-		}
-		dport = dest->port;
-	} else {
-		/*
-		 * Note: persistent fwmark-based services and persistent
-		 * port zero service are handled here.
-		 * fwmark template: <IPPROTO_IP,caddr,0,fwmark,0,daddr,0>
-		 * port zero template: <protocol,caddr,0,vaddr,0,daddr,0>
-		 */
-		if (svc->fwmark) {
-			union nf_inet_addr fwmark = {
-				.ip = htonl(svc->fwmark)
-			};
-
-			ct = ip_vs_ct_in_get(svc->af, IPPROTO_IP, &snet, 0,
-					     &fwmark, 0);
-		} else
-			ct = ip_vs_ct_in_get(svc->af, iph.protocol, &snet, 0,
-					     &iph.daddr, 0);
-
-		if (!ct || !ip_vs_check_template(ct)) {
-			/*
-			 * If it is not persistent port zero, return NULL,
-			 * otherwise create a connection template.
+			/* Note: persistent fwmark-based services and
+			 * persistent port zero service are handled here.
+			 * fwmark template:
+			 * <IPPROTO_IP,caddr,0,fwmark,0,daddr,0>
+			 * port zero template:
+			 * <protocol,caddr,0,vaddr,0,daddr,0>
 			 */
-			if (svc->port)
-				return NULL;
-
-			dest = svc->scheduler->schedule(svc, skb);
-			if (dest == NULL) {
-				IP_VS_DBG(1, "p-schedule: no dest found.\n");
-				return NULL;
+			if (svc->fwmark) {
+				protocol = IPPROTO_IP;
+				vaddr = &fwmark;
 			}
+		}
+	}
 
-			/*
-			 * Create a template according to the service
-			 */
-			if (svc->fwmark) {
-				union nf_inet_addr fwmark = {
-					.ip = htonl(svc->fwmark)
-				};
-
-				ct = ip_vs_conn_new(svc->af, IPPROTO_IP,
-						    &snet, 0,
-						    &fwmark, 0,
-						    &dest->addr, 0,
-						    IP_VS_CONN_F_TEMPLATE,
-						    dest);
-			} else
-				ct = ip_vs_conn_new(svc->af, iph.protocol,
-						    &snet, 0,
-						    &iph.daddr, 0,
-						    &dest->addr, 0,
-						    IP_VS_CONN_F_TEMPLATE,
-						    dest);
-			if (ct == NULL)
-				return NULL;
+	/* Check if a template already exists */
+	ct = ip_vs_ct_in_get(svc->af, protocol, &snet, 0, vaddr, vport);
 
-			ct->timeout = svc->timeout;
-		} else {
-			/* set destination with the found template */
-			dest = ct->dest;
+	if (!ct || !ip_vs_check_template(ct)) {
+		/* No template found or the dest of the connection
+		 * template is not available.
+		 */
+		dest = svc->scheduler->schedule(svc, skb);
+		if (!dest) {
+			IP_VS_DBG(1, "p-schedule: no dest found.\n");
+			return NULL;
 		}
-		dport = ports[1];
-	}
+
+		if (ports[1] == svc->port && svc->port != FTPPORT)
+			dport = dest->port;
+
+		/* Create a template */
+		ct = ip_vs_conn_new(svc->af, protocol, &snet, 0,vaddr, vport,
+				    &dest->addr, dport,
+				    IP_VS_CONN_F_TEMPLATE, dest);
+		if (ct == NULL)
+			return NULL;
+
+		ct->timeout = svc->timeout;
+	} else
+		/* set destination with the found template */
+		dest = ct->dest;
+
+	dport = ports[1];
+	if (dport == svc->port && dest->port)
+		dport = dest->port;
 
 	flags = (svc->flags & IP_VS_SVC_F_ONEPACKET
 		 && iph.protocol == IPPROTO_UDP)?


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [patch v5 04/12] IPVS: Add struct ip_vs_conn_param
  2010-10-04 13:46 [patch v5 00/12] IPVS: SIP Persistence Engine Simon Horman
                   ` (2 preceding siblings ...)
  2010-10-04 13:46 ` [patch v5 03/12] IPVS: compact ip_vs_sched_persist() Simon Horman
@ 2010-10-04 13:46 ` Simon Horman
  2010-10-19  9:41   ` [patch v5 04/12] IPVS: Add struct ip_vs_conn_param, IPv6 forgotten ? Hans Schillstrom
  2010-10-04 13:46 ` [patch v5 05/12] IPVS: Allow null argument to ip_vs_scheduler_put() Simon Horman
                   ` (8 subsequent siblings)
  12 siblings, 1 reply; 18+ messages in thread
From: Simon Horman @ 2010-10-04 13:46 UTC (permalink / raw)
  To: lvs-devel, netdev, netfilter, netfilter-devel
  Cc: Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
	Julian Anastasov, Patrick McHardy

[-- Attachment #1: 0004-IPVS-Add-struct-ip_vs_conn_param.patch --]
[-- Type: text/plain, Size: 26203 bytes --]

Signed-off-by: Simon Horman <horms@verge.net.au>
Acked-by: Julian Anastasov <ja@ssi.bg>

---

The motivation for this is to allow persistence engine modules to
fill in the parameters.

v0.3
* Add missing changes to ip_vs_ftp.c

v2
* make "union nf_inet_addr fwmark" const
* Update for the recent addition of ip_vs_nfct.c

v3
* As suggested by Julian Anastasov
  - Correct logic for inverse case in ip_vs_conn_fill_param_proto()
    and ah_esp_conn_fill_param_proto()
  - Update ip_vs_conn_out_get()'s comments as its parameters have changed
  - Add missing call to ip_vs_conn_fill_param() before the second
    invocation of ip_vs_conn_new() in ip_vs_sched_persist()
* Trivial re-diff

v4
* As suggested by Julian Anastasov
  - Fix logic in ip_vs_conn_out_get_proto()
    + An error occurs if ip_vs_conn_fill_param_proto is non-zero,
      not if it is zero

Index: lvs-test-2.6/include/net/ip_vs.h
===================================================================
--- lvs-test-2.6.orig/include/net/ip_vs.h	2010-10-04 17:00:28.000000000 +0900
+++ lvs-test-2.6/include/net/ip_vs.h	2010-10-04 17:49:20.000000000 +0900
@@ -357,6 +357,15 @@ struct ip_vs_protocol {
 
 extern struct ip_vs_protocol * ip_vs_proto_get(unsigned short proto);
 
+struct ip_vs_conn_param {
+	const union nf_inet_addr	*caddr;
+	const union nf_inet_addr	*vaddr;
+	__be16				cport;
+	__be16				vport;
+	__u16				protocol;
+	u16				af;
+};
+
 /*
  *	IP_VS structure allocated for each dynamically scheduled connection
  */
@@ -626,13 +635,23 @@ enum {
 	IP_VS_DIR_LAST,
 };
 
-extern struct ip_vs_conn *ip_vs_conn_in_get
-(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
- const union nf_inet_addr *d_addr, __be16 d_port);
-
-extern struct ip_vs_conn *ip_vs_ct_in_get
-(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
- const union nf_inet_addr *d_addr, __be16 d_port);
+static inline void ip_vs_conn_fill_param(int af, int protocol,
+					 const union nf_inet_addr *caddr,
+					 __be16 cport,
+					 const union nf_inet_addr *vaddr,
+					 __be16 vport,
+					 struct ip_vs_conn_param *p)
+{
+	p->af = af;
+	p->protocol = protocol;
+	p->caddr = caddr;
+	p->cport = cport;
+	p->vaddr = vaddr;
+	p->vport = vport;
+}
+
+struct ip_vs_conn *ip_vs_conn_in_get(const struct ip_vs_conn_param *p);
+struct ip_vs_conn *ip_vs_ct_in_get(const struct ip_vs_conn_param *p);
 
 struct ip_vs_conn * ip_vs_conn_in_get_proto(int af, const struct sk_buff *skb,
 					    struct ip_vs_protocol *pp,
@@ -640,9 +659,7 @@ struct ip_vs_conn * ip_vs_conn_in_get_pr
 					    unsigned int proto_off,
 					    int inverse);
 
-extern struct ip_vs_conn *ip_vs_conn_out_get
-(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
- const union nf_inet_addr *d_addr, __be16 d_port);
+struct ip_vs_conn *ip_vs_conn_out_get(const struct ip_vs_conn_param *p);
 
 struct ip_vs_conn * ip_vs_conn_out_get_proto(int af, const struct sk_buff *skb,
 					     struct ip_vs_protocol *pp,
@@ -658,11 +675,10 @@ static inline void __ip_vs_conn_put(stru
 extern void ip_vs_conn_put(struct ip_vs_conn *cp);
 extern void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __be16 cport);
 
-extern struct ip_vs_conn *
-ip_vs_conn_new(int af, int proto, const union nf_inet_addr *caddr, __be16 cport,
-	       const union nf_inet_addr *vaddr, __be16 vport,
-	       const union nf_inet_addr *daddr, __be16 dport, unsigned flags,
-	       struct ip_vs_dest *dest);
+struct ip_vs_conn *ip_vs_conn_new(const struct ip_vs_conn_param *p,
+				  const union nf_inet_addr *daddr,
+				  __be16 dport, unsigned flags,
+				  struct ip_vs_dest *dest);
 extern void ip_vs_conn_expire_now(struct ip_vs_conn *cp);
 
 extern const char * ip_vs_state_name(__u16 proto, int state);
Index: lvs-test-2.6/net/netfilter/ipvs/ip_vs_conn.c
===================================================================
--- lvs-test-2.6.orig/net/netfilter/ipvs/ip_vs_conn.c	2010-10-04 17:00:28.000000000 +0900
+++ lvs-test-2.6/net/netfilter/ipvs/ip_vs_conn.c	2010-10-04 17:49:20.000000000 +0900
@@ -218,27 +218,26 @@ static inline int ip_vs_conn_unhash(stru
 /*
  *  Gets ip_vs_conn associated with supplied parameters in the ip_vs_conn_tab.
  *  Called for pkts coming from OUTside-to-INside.
- *	s_addr, s_port: pkt source address (foreign host)
- *	d_addr, d_port: pkt dest address (load balancer)
+ *	p->caddr, p->cport: pkt source address (foreign host)
+ *	p->vaddr, p->vport: pkt dest address (load balancer)
  */
-static inline struct ip_vs_conn *__ip_vs_conn_in_get
-(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
- const union nf_inet_addr *d_addr, __be16 d_port)
+static inline struct ip_vs_conn *
+__ip_vs_conn_in_get(const struct ip_vs_conn_param *p)
 {
 	unsigned hash;
 	struct ip_vs_conn *cp;
 
-	hash = ip_vs_conn_hashkey(af, protocol, s_addr, s_port);
+	hash = ip_vs_conn_hashkey(p->af, p->protocol, p->caddr, p->cport);
 
 	ct_read_lock(hash);
 
 	list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
-		if (cp->af == af &&
-		    ip_vs_addr_equal(af, s_addr, &cp->caddr) &&
-		    ip_vs_addr_equal(af, d_addr, &cp->vaddr) &&
-		    s_port == cp->cport && d_port == cp->vport &&
-		    ((!s_port) ^ (!(cp->flags & IP_VS_CONN_F_NO_CPORT))) &&
-		    protocol == cp->protocol) {
+		if (cp->af == p->af &&
+		    ip_vs_addr_equal(p->af, p->caddr, &cp->caddr) &&
+		    ip_vs_addr_equal(p->af, p->vaddr, &cp->vaddr) &&
+		    p->cport == cp->cport && p->vport == cp->vport &&
+		    ((!p->cport) ^ (!(cp->flags & IP_VS_CONN_F_NO_CPORT))) &&
+		    p->protocol == cp->protocol) {
 			/* HIT */
 			atomic_inc(&cp->refcnt);
 			ct_read_unlock(hash);
@@ -251,71 +250,82 @@ static inline struct ip_vs_conn *__ip_vs
 	return NULL;
 }
 
-struct ip_vs_conn *ip_vs_conn_in_get
-(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
- const union nf_inet_addr *d_addr, __be16 d_port)
+struct ip_vs_conn *ip_vs_conn_in_get(const struct ip_vs_conn_param *p)
 {
 	struct ip_vs_conn *cp;
 
-	cp = __ip_vs_conn_in_get(af, protocol, s_addr, s_port, d_addr, d_port);
-	if (!cp && atomic_read(&ip_vs_conn_no_cport_cnt))
-		cp = __ip_vs_conn_in_get(af, protocol, s_addr, 0, d_addr,
-					 d_port);
+	cp = __ip_vs_conn_in_get(p);
+	if (!cp && atomic_read(&ip_vs_conn_no_cport_cnt)) {
+		struct ip_vs_conn_param cport_zero_p = *p;
+		cport_zero_p.cport = 0;
+		cp = __ip_vs_conn_in_get(&cport_zero_p);
+	}
 
 	IP_VS_DBG_BUF(9, "lookup/in %s %s:%d->%s:%d %s\n",
-		      ip_vs_proto_name(protocol),
-		      IP_VS_DBG_ADDR(af, s_addr), ntohs(s_port),
-		      IP_VS_DBG_ADDR(af, d_addr), ntohs(d_port),
+		      ip_vs_proto_name(p->protocol),
+		      IP_VS_DBG_ADDR(p->af, p->caddr), ntohs(p->cport),
+		      IP_VS_DBG_ADDR(p->af, p->vaddr), ntohs(p->vport),
 		      cp ? "hit" : "not hit");
 
 	return cp;
 }
 
+static int
+ip_vs_conn_fill_param_proto(int af, const struct sk_buff *skb,
+			    const struct ip_vs_iphdr *iph,
+			    unsigned int proto_off, int inverse,
+			    struct ip_vs_conn_param *p)
+{
+	__be16 _ports[2], *pptr;
+
+	pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
+	if (pptr == NULL)
+		return 1;
+
+	if (likely(!inverse))
+		ip_vs_conn_fill_param(af, iph->protocol, &iph->saddr, pptr[0],
+				      &iph->daddr, pptr[1], p);
+	else
+		ip_vs_conn_fill_param(af, iph->protocol, &iph->daddr, pptr[1],
+				      &iph->saddr, pptr[0], p);
+	return 0;
+}
+
 struct ip_vs_conn *
 ip_vs_conn_in_get_proto(int af, const struct sk_buff *skb,
 			struct ip_vs_protocol *pp,
 			const struct ip_vs_iphdr *iph,
 			unsigned int proto_off, int inverse)
 {
-	__be16 _ports[2], *pptr;
+	struct ip_vs_conn_param p;
 
-	pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
-	if (pptr == NULL)
+	if (ip_vs_conn_fill_param_proto(af, skb, iph, proto_off, inverse, &p))
 		return NULL;
 
-	if (likely(!inverse))
-		return ip_vs_conn_in_get(af, iph->protocol,
-					 &iph->saddr, pptr[0],
-					 &iph->daddr, pptr[1]);
-	else
-		return ip_vs_conn_in_get(af, iph->protocol,
-					 &iph->daddr, pptr[1],
-					 &iph->saddr, pptr[0]);
+	return ip_vs_conn_in_get(&p);
 }
 EXPORT_SYMBOL_GPL(ip_vs_conn_in_get_proto);
 
 /* Get reference to connection template */
-struct ip_vs_conn *ip_vs_ct_in_get
-(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
- const union nf_inet_addr *d_addr, __be16 d_port)
+struct ip_vs_conn *ip_vs_ct_in_get(const struct ip_vs_conn_param *p)
 {
 	unsigned hash;
 	struct ip_vs_conn *cp;
 
-	hash = ip_vs_conn_hashkey(af, protocol, s_addr, s_port);
+	hash = ip_vs_conn_hashkey(p->af, p->protocol, p->caddr, p->cport);
 
 	ct_read_lock(hash);
 
 	list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
-		if (cp->af == af &&
-		    ip_vs_addr_equal(af, s_addr, &cp->caddr) &&
+		if (cp->af == p->af &&
+		    ip_vs_addr_equal(p->af, p->caddr, &cp->caddr) &&
 		    /* protocol should only be IPPROTO_IP if
-		     * d_addr is a fwmark */
-		    ip_vs_addr_equal(protocol == IPPROTO_IP ? AF_UNSPEC : af,
-		                     d_addr, &cp->vaddr) &&
-		    s_port == cp->cport && d_port == cp->vport &&
+		     * p->vaddr is a fwmark */
+		    ip_vs_addr_equal(p->protocol == IPPROTO_IP ? AF_UNSPEC :
+				     p->af, p->vaddr, &cp->vaddr) &&
+		    p->cport == cp->cport && p->vport == cp->vport &&
 		    cp->flags & IP_VS_CONN_F_TEMPLATE &&
-		    protocol == cp->protocol) {
+		    p->protocol == cp->protocol) {
 			/* HIT */
 			atomic_inc(&cp->refcnt);
 			goto out;
@@ -327,23 +337,19 @@ struct ip_vs_conn *ip_vs_ct_in_get
 	ct_read_unlock(hash);
 
 	IP_VS_DBG_BUF(9, "template lookup/in %s %s:%d->%s:%d %s\n",
-		      ip_vs_proto_name(protocol),
-		      IP_VS_DBG_ADDR(af, s_addr), ntohs(s_port),
-		      IP_VS_DBG_ADDR(af, d_addr), ntohs(d_port),
+		      ip_vs_proto_name(p->protocol),
+		      IP_VS_DBG_ADDR(p->af, p->caddr), ntohs(p->cport),
+		      IP_VS_DBG_ADDR(p->af, p->vaddr), ntohs(p->vport),
 		      cp ? "hit" : "not hit");
 
 	return cp;
 }
 
-/*
- *  Gets ip_vs_conn associated with supplied parameters in the ip_vs_conn_tab.
- *  Called for pkts coming from inside-to-OUTside.
- *	s_addr, s_port: pkt source address (inside host)
- *	d_addr, d_port: pkt dest address (foreign host)
- */
-struct ip_vs_conn *ip_vs_conn_out_get
-(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
- const union nf_inet_addr *d_addr, __be16 d_port)
+/* Gets ip_vs_conn associated with supplied parameters in the ip_vs_conn_tab.
+ * Called for pkts coming from inside-to-OUTside.
+ *	p->caddr, p->cport: pkt source address (inside host)
+ *	p->vaddr, p->vport: pkt dest address (foreign host) */
+struct ip_vs_conn *ip_vs_conn_out_get(const struct ip_vs_conn_param *p)
 {
 	unsigned hash;
 	struct ip_vs_conn *cp, *ret=NULL;
@@ -351,16 +357,16 @@ struct ip_vs_conn *ip_vs_conn_out_get
 	/*
 	 *	Check for "full" addressed entries
 	 */
-	hash = ip_vs_conn_hashkey(af, protocol, d_addr, d_port);
+	hash = ip_vs_conn_hashkey(p->af, p->protocol, p->vaddr, p->vport);
 
 	ct_read_lock(hash);
 
 	list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
-		if (cp->af == af &&
-		    ip_vs_addr_equal(af, d_addr, &cp->caddr) &&
-		    ip_vs_addr_equal(af, s_addr, &cp->daddr) &&
-		    d_port == cp->cport && s_port == cp->dport &&
-		    protocol == cp->protocol) {
+		if (cp->af == p->af &&
+		    ip_vs_addr_equal(p->af, p->vaddr, &cp->caddr) &&
+		    ip_vs_addr_equal(p->af, p->caddr, &cp->daddr) &&
+		    p->vport == cp->cport && p->cport == cp->dport &&
+		    p->protocol == cp->protocol) {
 			/* HIT */
 			atomic_inc(&cp->refcnt);
 			ret = cp;
@@ -371,9 +377,9 @@ struct ip_vs_conn *ip_vs_conn_out_get
 	ct_read_unlock(hash);
 
 	IP_VS_DBG_BUF(9, "lookup/out %s %s:%d->%s:%d %s\n",
-		      ip_vs_proto_name(protocol),
-		      IP_VS_DBG_ADDR(af, s_addr), ntohs(s_port),
-		      IP_VS_DBG_ADDR(af, d_addr), ntohs(d_port),
+		      ip_vs_proto_name(p->protocol),
+		      IP_VS_DBG_ADDR(p->af, p->caddr), ntohs(p->cport),
+		      IP_VS_DBG_ADDR(p->af, p->vaddr), ntohs(p->vport),
 		      ret ? "hit" : "not hit");
 
 	return ret;
@@ -385,20 +391,12 @@ ip_vs_conn_out_get_proto(int af, const s
 			 const struct ip_vs_iphdr *iph,
 			 unsigned int proto_off, int inverse)
 {
-	__be16 _ports[2], *pptr;
+	struct ip_vs_conn_param p;
 
-	pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
-	if (pptr == NULL)
+	if (ip_vs_conn_fill_param_proto(af, skb, iph, proto_off, inverse, &p))
 		return NULL;
 
-	if (likely(!inverse))
-		return ip_vs_conn_out_get(af, iph->protocol,
-					  &iph->saddr, pptr[0],
-					  &iph->daddr, pptr[1]);
-	else
-		return ip_vs_conn_out_get(af, iph->protocol,
-					  &iph->daddr, pptr[1],
-					  &iph->saddr, pptr[0]);
+	return ip_vs_conn_out_get(&p);
 }
 EXPORT_SYMBOL_GPL(ip_vs_conn_out_get_proto);
 
@@ -758,13 +756,12 @@ void ip_vs_conn_expire_now(struct ip_vs_
  *	Create a new connection entry and hash it into the ip_vs_conn_tab
  */
 struct ip_vs_conn *
-ip_vs_conn_new(int af, int proto, const union nf_inet_addr *caddr, __be16 cport,
-	       const union nf_inet_addr *vaddr, __be16 vport,
+ip_vs_conn_new(const struct ip_vs_conn_param *p,
 	       const union nf_inet_addr *daddr, __be16 dport, unsigned flags,
 	       struct ip_vs_dest *dest)
 {
 	struct ip_vs_conn *cp;
-	struct ip_vs_protocol *pp = ip_vs_proto_get(proto);
+	struct ip_vs_protocol *pp = ip_vs_proto_get(p->protocol);
 
 	cp = kmem_cache_zalloc(ip_vs_conn_cachep, GFP_ATOMIC);
 	if (cp == NULL) {
@@ -774,14 +771,14 @@ ip_vs_conn_new(int af, int proto, const
 
 	INIT_LIST_HEAD(&cp->c_list);
 	setup_timer(&cp->timer, ip_vs_conn_expire, (unsigned long)cp);
-	cp->af		   = af;
-	cp->protocol	   = proto;
-	ip_vs_addr_copy(af, &cp->caddr, caddr);
-	cp->cport	   = cport;
-	ip_vs_addr_copy(af, &cp->vaddr, vaddr);
-	cp->vport	   = vport;
+	cp->af		   = p->af;
+	cp->protocol	   = p->protocol;
+	ip_vs_addr_copy(p->af, &cp->caddr, p->caddr);
+	cp->cport	   = p->cport;
+	ip_vs_addr_copy(p->af, &cp->vaddr, p->vaddr);
+	cp->vport	   = p->vport;
 	/* proto should only be IPPROTO_IP if d_addr is a fwmark */
-	ip_vs_addr_copy(proto == IPPROTO_IP ? AF_UNSPEC : af,
+	ip_vs_addr_copy(p->protocol == IPPROTO_IP ? AF_UNSPEC : p->af,
 			&cp->daddr, daddr);
 	cp->dport          = dport;
 	cp->flags	   = flags;
@@ -810,7 +807,7 @@ ip_vs_conn_new(int af, int proto, const
 
 	/* Bind its packet transmitter */
 #ifdef CONFIG_IP_VS_IPV6
-	if (af == AF_INET6)
+	if (p->af == AF_INET6)
 		ip_vs_bind_xmit_v6(cp);
 	else
 #endif
Index: lvs-test-2.6/net/netfilter/ipvs/ip_vs_core.c
===================================================================
--- lvs-test-2.6.orig/net/netfilter/ipvs/ip_vs_core.c	2010-10-04 17:00:45.000000000 +0900
+++ lvs-test-2.6/net/netfilter/ipvs/ip_vs_core.c	2010-10-04 17:49:20.000000000 +0900
@@ -193,14 +193,11 @@ ip_vs_sched_persist(struct ip_vs_service
 	struct ip_vs_iphdr iph;
 	struct ip_vs_dest *dest;
 	struct ip_vs_conn *ct;
-	int protocol = iph.protocol;
 	__be16 dport = 0;		/* destination port to forward */
-	__be16 vport = 0;		/* virtual service port */
 	unsigned int flags;
+	struct ip_vs_conn_param param;
 	union nf_inet_addr snet;	/* source network of the client,
 					   after masking */
-	const union nf_inet_addr fwmark = { .ip = htonl(svc->fwmark) };
-	const union nf_inet_addr *vaddr = &iph.daddr;
 
 	ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
 
@@ -232,6 +229,11 @@ ip_vs_sched_persist(struct ip_vs_service
 	 * is created for other persistent services.
 	 */
 	{
+		int protocol = iph.protocol;
+		const union nf_inet_addr *vaddr = &iph.daddr;
+		const union nf_inet_addr fwmark = { .ip = htonl(svc->fwmark) };
+		__be16 vport = 0;
+
 		if (ports[1] == svc->port) {
 			/* non-FTP template:
 			 * <protocol, caddr, 0, vaddr, vport, daddr, dport>
@@ -253,11 +255,12 @@ ip_vs_sched_persist(struct ip_vs_service
 				vaddr = &fwmark;
 			}
 		}
+		ip_vs_conn_fill_param(svc->af, protocol, &snet, 0,
+				      vaddr, vport, &param);
 	}
 
 	/* Check if a template already exists */
-	ct = ip_vs_ct_in_get(svc->af, protocol, &snet, 0, vaddr, vport);
-
+	ct = ip_vs_ct_in_get(&param);
 	if (!ct || !ip_vs_check_template(ct)) {
 		/* No template found or the dest of the connection
 		 * template is not available.
@@ -272,8 +275,7 @@ ip_vs_sched_persist(struct ip_vs_service
 			dport = dest->port;
 
 		/* Create a template */
-		ct = ip_vs_conn_new(svc->af, protocol, &snet, 0,vaddr, vport,
-				    &dest->addr, dport,
+		ct = ip_vs_conn_new(&param, &dest->addr, dport,
 				    IP_VS_CONN_F_TEMPLATE, dest);
 		if (ct == NULL)
 			return NULL;
@@ -294,12 +296,9 @@ ip_vs_sched_persist(struct ip_vs_service
 	/*
 	 *    Create a new connection according to the template
 	 */
-	cp = ip_vs_conn_new(svc->af, iph.protocol,
-			    &iph.saddr, ports[0],
-			    &iph.daddr, ports[1],
-			    &dest->addr, dport,
-			    flags,
-			    dest);
+	ip_vs_conn_fill_param(svc->af, iph.protocol, &iph.saddr, ports[0],
+			      &iph.daddr, ports[1], &param);
+	cp = ip_vs_conn_new(&param, &dest->addr, dport, flags, dest);
 	if (cp == NULL) {
 		ip_vs_conn_put(ct);
 		return NULL;
@@ -366,14 +365,16 @@ ip_vs_schedule(struct ip_vs_service *svc
 	/*
 	 *    Create a connection entry.
 	 */
-	cp = ip_vs_conn_new(svc->af, iph.protocol,
-			    &iph.saddr, pptr[0],
-			    &iph.daddr, pptr[1],
-			    &dest->addr, dest->port ? dest->port : pptr[1],
-			    flags,
-			    dest);
-	if (cp == NULL)
-		return NULL;
+	{
+		struct ip_vs_conn_param p;
+		ip_vs_conn_fill_param(svc->af, iph.protocol, &iph.saddr,
+				      pptr[0], &iph.daddr, pptr[1], &p);
+		cp = ip_vs_conn_new(&p, &dest->addr,
+				    dest->port ? dest->port : pptr[1],
+				    flags, dest);
+		if (!cp)
+			return NULL;
+	}
 
 	IP_VS_DBG_BUF(6, "Schedule fwd:%c c:%s:%u v:%s:%u "
 		      "d:%s:%u conn->flags:%X conn->refcnt:%d\n",
@@ -429,14 +430,17 @@ int ip_vs_leave(struct ip_vs_service *sv
 
 		/* create a new connection entry */
 		IP_VS_DBG(6, "%s(): create a cache_bypass entry\n", __func__);
-		cp = ip_vs_conn_new(svc->af, iph.protocol,
-				    &iph.saddr, pptr[0],
-				    &iph.daddr, pptr[1],
-				    &daddr, 0,
-				    IP_VS_CONN_F_BYPASS | flags,
-				    NULL);
-		if (cp == NULL)
-			return NF_DROP;
+		{
+			struct ip_vs_conn_param p;
+			ip_vs_conn_fill_param(svc->af, iph.protocol,
+					      &iph.saddr, pptr[0],
+					      &iph.daddr, pptr[1], &p);
+			cp = ip_vs_conn_new(&p, &daddr, 0,
+					    IP_VS_CONN_F_BYPASS | flags,
+					    NULL);
+			if (!cp)
+				return NF_DROP;
+		}
 
 		/* statistics */
 		ip_vs_in_stats(cp, skb);
Index: lvs-test-2.6/net/netfilter/ipvs/ip_vs_ftp.c
===================================================================
--- lvs-test-2.6.orig/net/netfilter/ipvs/ip_vs_ftp.c	2010-10-04 16:58:31.000000000 +0900
+++ lvs-test-2.6/net/netfilter/ipvs/ip_vs_ftp.c	2010-10-04 17:00:45.000000000 +0900
@@ -195,13 +195,17 @@ static int ip_vs_ftp_out(struct ip_vs_ap
 		/*
 		 * Now update or create an connection entry for it
 		 */
-		n_cp = ip_vs_conn_out_get(AF_INET, iph->protocol, &from, port,
-					  &cp->caddr, 0);
+		{
+			struct ip_vs_conn_param p;
+			ip_vs_conn_fill_param(AF_INET, iph->protocol,
+					      &from, port, &cp->caddr, 0, &p);
+			n_cp = ip_vs_conn_out_get(&p);
+		}
 		if (!n_cp) {
-			n_cp = ip_vs_conn_new(AF_INET, IPPROTO_TCP,
-					      &cp->caddr, 0,
-					      &cp->vaddr, port,
-					      &from, port,
+			struct ip_vs_conn_param p;
+			ip_vs_conn_fill_param(AF_INET, IPPROTO_TCP, &cp->caddr,
+					      0, &cp->vaddr, port, &p);
+			n_cp = ip_vs_conn_new(&p, &from, port,
 					      IP_VS_CONN_F_NO_CPORT |
 					      IP_VS_CONN_F_NFCT,
 					      cp->dest);
@@ -347,21 +351,22 @@ static int ip_vs_ftp_in(struct ip_vs_app
 		  ip_vs_proto_name(iph->protocol),
 		  &to.ip, ntohs(port), &cp->vaddr.ip, 0);
 
-	n_cp = ip_vs_conn_in_get(AF_INET, iph->protocol,
-				 &to, port,
-				 &cp->vaddr, htons(ntohs(cp->vport)-1));
-	if (!n_cp) {
-		n_cp = ip_vs_conn_new(AF_INET, IPPROTO_TCP,
-				      &to, port,
+	{
+		struct ip_vs_conn_param p;
+		ip_vs_conn_fill_param(AF_INET, iph->protocol, &to, port,
 				      &cp->vaddr, htons(ntohs(cp->vport)-1),
-				      &cp->daddr, htons(ntohs(cp->dport)-1),
-				      IP_VS_CONN_F_NFCT,
-				      cp->dest);
-		if (!n_cp)
-			return 0;
+				      &p);
+		n_cp = ip_vs_conn_in_get(&p);
+		if (!n_cp) {
+			n_cp = ip_vs_conn_new(&p, &cp->daddr,
+					      htons(ntohs(cp->dport)-1),
+					      IP_VS_CONN_F_NFCT, cp->dest);
+			if (!n_cp)
+				return 0;
 
-		/* add its controller */
-		ip_vs_control_add(n_cp, cp);
+			/* add its controller */
+			ip_vs_control_add(n_cp, cp);
+		}
 	}
 
 	/*
Index: lvs-test-2.6/net/netfilter/ipvs/ip_vs_nfct.c
===================================================================
--- lvs-test-2.6.orig/net/netfilter/ipvs/ip_vs_nfct.c	2010-10-04 16:58:31.000000000 +0900
+++ lvs-test-2.6/net/netfilter/ipvs/ip_vs_nfct.c	2010-10-04 17:00:45.000000000 +0900
@@ -140,6 +140,7 @@ static void ip_vs_nfct_expect_callback(s
 {
 	struct nf_conntrack_tuple *orig, new_reply;
 	struct ip_vs_conn *cp;
+	struct ip_vs_conn_param p;
 
 	if (exp->tuple.src.l3num != PF_INET)
 		return;
@@ -154,9 +155,10 @@ static void ip_vs_nfct_expect_callback(s
 
 	/* RS->CLIENT */
 	orig = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
-	cp = ip_vs_conn_out_get(exp->tuple.src.l3num, orig->dst.protonum,
-				&orig->src.u3, orig->src.u.tcp.port,
-				&orig->dst.u3, orig->dst.u.tcp.port);
+	ip_vs_conn_fill_param(exp->tuple.src.l3num, orig->dst.protonum,
+			      &orig->src.u3, orig->src.u.tcp.port,
+			      &orig->dst.u3, orig->dst.u.tcp.port, &p);
+	cp = ip_vs_conn_out_get(&p);
 	if (cp) {
 		/* Change reply CLIENT->RS to CLIENT->VS */
 		new_reply = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
@@ -176,9 +178,7 @@ static void ip_vs_nfct_expect_callback(s
 	}
 
 	/* CLIENT->VS */
-	cp = ip_vs_conn_in_get(exp->tuple.src.l3num, orig->dst.protonum,
-			       &orig->src.u3, orig->src.u.tcp.port,
-			       &orig->dst.u3, orig->dst.u.tcp.port);
+	cp = ip_vs_conn_in_get(&p);
 	if (cp) {
 		/* Change reply VS->CLIENT to RS->CLIENT */
 		new_reply = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
Index: lvs-test-2.6/net/netfilter/ipvs/ip_vs_proto_ah_esp.c
===================================================================
--- lvs-test-2.6.orig/net/netfilter/ipvs/ip_vs_proto_ah_esp.c	2010-10-04 16:58:31.000000000 +0900
+++ lvs-test-2.6/net/netfilter/ipvs/ip_vs_proto_ah_esp.c	2010-10-04 17:00:45.000000000 +0900
@@ -40,6 +40,19 @@ struct isakmp_hdr {
 
 #define PORT_ISAKMP	500
 
+static void
+ah_esp_conn_fill_param_proto(int af, const struct ip_vs_iphdr *iph,
+			     int inverse, struct ip_vs_conn_param *p)
+{
+	if (likely(!inverse))
+		ip_vs_conn_fill_param(af, IPPROTO_UDP,
+				      &iph->saddr, htons(PORT_ISAKMP),
+				      &iph->daddr, htons(PORT_ISAKMP), p);
+	else
+		ip_vs_conn_fill_param(af, IPPROTO_UDP,
+				      &iph->daddr, htons(PORT_ISAKMP),
+				      &iph->saddr, htons(PORT_ISAKMP), p);
+}
 
 static struct ip_vs_conn *
 ah_esp_conn_in_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
@@ -47,21 +60,10 @@ ah_esp_conn_in_get(int af, const struct
 		   int inverse)
 {
 	struct ip_vs_conn *cp;
+	struct ip_vs_conn_param p;
 
-	if (likely(!inverse)) {
-		cp = ip_vs_conn_in_get(af, IPPROTO_UDP,
-				       &iph->saddr,
-				       htons(PORT_ISAKMP),
-				       &iph->daddr,
-				       htons(PORT_ISAKMP));
-	} else {
-		cp = ip_vs_conn_in_get(af, IPPROTO_UDP,
-				       &iph->daddr,
-				       htons(PORT_ISAKMP),
-				       &iph->saddr,
-				       htons(PORT_ISAKMP));
-	}
-
+	ah_esp_conn_fill_param_proto(af, iph, inverse, &p);
+	cp = ip_vs_conn_in_get(&p);
 	if (!cp) {
 		/*
 		 * We are not sure if the packet is from our
@@ -87,21 +89,10 @@ ah_esp_conn_out_get(int af, const struct
 		    int inverse)
 {
 	struct ip_vs_conn *cp;
+	struct ip_vs_conn_param p;
 
-	if (likely(!inverse)) {
-		cp = ip_vs_conn_out_get(af, IPPROTO_UDP,
-					&iph->saddr,
-					htons(PORT_ISAKMP),
-					&iph->daddr,
-					htons(PORT_ISAKMP));
-	} else {
-		cp = ip_vs_conn_out_get(af, IPPROTO_UDP,
-					&iph->daddr,
-					htons(PORT_ISAKMP),
-					&iph->saddr,
-					htons(PORT_ISAKMP));
-	}
-
+	ah_esp_conn_fill_param_proto(af, iph, inverse, &p);
+	cp = ip_vs_conn_out_get(&p);
 	if (!cp) {
 		IP_VS_DBG_BUF(12, "Unknown ISAKMP entry for inout packet "
 			      "%s%s %s->%s\n",
Index: lvs-test-2.6/net/netfilter/ipvs/ip_vs_sync.c
===================================================================
--- lvs-test-2.6.orig/net/netfilter/ipvs/ip_vs_sync.c	2010-10-04 16:58:31.000000000 +0900
+++ lvs-test-2.6/net/netfilter/ipvs/ip_vs_sync.c	2010-10-04 17:49:20.000000000 +0900
@@ -301,6 +301,7 @@ static void ip_vs_process_message(const
 	struct ip_vs_conn *cp;
 	struct ip_vs_protocol *pp;
 	struct ip_vs_dest *dest;
+	struct ip_vs_conn_param param;
 	char *p;
 	int i;
 
@@ -370,18 +371,17 @@ static void ip_vs_process_message(const
 			}
 		}
 
-		if (!(flags & IP_VS_CONN_F_TEMPLATE))
-			cp = ip_vs_conn_in_get(AF_INET, s->protocol,
-					       (union nf_inet_addr *)&s->caddr,
-					       s->cport,
-					       (union nf_inet_addr *)&s->vaddr,
-					       s->vport);
-		else
-			cp = ip_vs_ct_in_get(AF_INET, s->protocol,
-					     (union nf_inet_addr *)&s->caddr,
-					     s->cport,
-					     (union nf_inet_addr *)&s->vaddr,
-					     s->vport);
+		{
+			ip_vs_conn_fill_param(AF_INET, s->protocol,
+					      (union nf_inet_addr *)&s->caddr,
+					      s->cport,
+					      (union nf_inet_addr *)&s->vaddr,
+					      s->vport, &param);
+			if (!(flags & IP_VS_CONN_F_TEMPLATE))
+				cp = ip_vs_conn_in_get(&param);
+			else
+				cp = ip_vs_ct_in_get(&param);
+		}
 		if (!cp) {
 			/*
 			 * Find the appropriate destination for the connection.
@@ -406,14 +406,9 @@ static void ip_vs_process_message(const
 				else
 					flags &= ~IP_VS_CONN_F_INACTIVE;
 			}
-			cp = ip_vs_conn_new(AF_INET, s->protocol,
-					    (union nf_inet_addr *)&s->caddr,
-					    s->cport,
-					    (union nf_inet_addr *)&s->vaddr,
-					    s->vport,
+			cp = ip_vs_conn_new(&param,
 					    (union nf_inet_addr *)&s->daddr,
-					    s->dport,
-					    flags, dest);
+					    s->dport, flags, dest);
 			if (dest)
 				atomic_dec(&dest->refcnt);
 			if (!cp) {


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [patch v5 05/12] IPVS: Allow null argument to ip_vs_scheduler_put()
  2010-10-04 13:46 [patch v5 00/12] IPVS: SIP Persistence Engine Simon Horman
                   ` (3 preceding siblings ...)
  2010-10-04 13:46 ` [patch v5 04/12] IPVS: Add struct ip_vs_conn_param Simon Horman
@ 2010-10-04 13:46 ` Simon Horman
  2010-10-04 13:46 ` [patch v5 06/12] IPVS: ip_vs_{un,}bind_scheduler NULL arguments Simon Horman
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 18+ messages in thread
From: Simon Horman @ 2010-10-04 13:46 UTC (permalink / raw)
  To: lvs-devel, netdev, netfilter, netfilter-devel
  Cc: Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
	Julian Anastasov, Patrick McHardy

[-- Attachment #1: 0005-IPVS-Allow-null-argument-to-ip_vs_scheduler_put.patch --]
[-- Type: text/plain, Size: 2081 bytes --]

This simplifies caller logic sightly.

Signed-off-by: Simon Horman <horms@verge.net.au>
Acked-by: Julian Anastasov <ja@ssi.bg>

---

v2
* Trivial rediff

Index: lvs-test-2.6/net/netfilter/ipvs/ip_vs_ctl.c
===================================================================
--- lvs-test-2.6.orig/net/netfilter/ipvs/ip_vs_ctl.c	2010-10-01 22:25:53.000000000 +0900
+++ lvs-test-2.6/net/netfilter/ipvs/ip_vs_ctl.c	2010-10-01 22:26:10.000000000 +0900
@@ -1144,7 +1144,7 @@ ip_vs_add_service(struct ip_vs_service_u
 	if (sched == NULL) {
 		pr_info("Scheduler module ip_vs_%s not found\n", u->sched_name);
 		ret = -ENOENT;
-		goto out_mod_dec;
+		goto out_err;
 	}
 
 #ifdef CONFIG_IP_VS_IPV6
@@ -1204,7 +1204,7 @@ ip_vs_add_service(struct ip_vs_service_u
 	*svc_p = svc;
 	return 0;
 
-  out_err:
+ out_err:
 	if (svc != NULL) {
 		if (svc->scheduler)
 			ip_vs_unbind_scheduler(svc);
@@ -1217,7 +1217,6 @@ ip_vs_add_service(struct ip_vs_service_u
 	}
 	ip_vs_scheduler_put(sched);
 
-  out_mod_dec:
 	/* decrease the module use count */
 	ip_vs_use_count_dec();
 
@@ -1300,10 +1299,7 @@ ip_vs_edit_service(struct ip_vs_service
 #ifdef CONFIG_IP_VS_IPV6
   out:
 #endif
-
-	if (old_sched)
-		ip_vs_scheduler_put(old_sched);
-
+	ip_vs_scheduler_put(old_sched);
 	return ret;
 }
 
@@ -1327,8 +1323,7 @@ static void __ip_vs_del_service(struct i
 	/* Unbind scheduler */
 	old_sched = svc->scheduler;
 	ip_vs_unbind_scheduler(svc);
-	if (old_sched)
-		ip_vs_scheduler_put(old_sched);
+	ip_vs_scheduler_put(old_sched);
 
 	/* Unbind app inc */
 	if (svc->inc) {
Index: lvs-test-2.6/net/netfilter/ipvs/ip_vs_sched.c
===================================================================
--- lvs-test-2.6.orig/net/netfilter/ipvs/ip_vs_sched.c	2010-10-01 22:25:53.000000000 +0900
+++ lvs-test-2.6/net/netfilter/ipvs/ip_vs_sched.c	2010-10-01 22:26:10.000000000 +0900
@@ -159,7 +159,7 @@ struct ip_vs_scheduler *ip_vs_scheduler_
 
 void ip_vs_scheduler_put(struct ip_vs_scheduler *scheduler)
 {
-	if (scheduler->module)
+	if (scheduler && scheduler->module)
 		module_put(scheduler->module);
 }
 


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [patch v5 06/12] IPVS: ip_vs_{un,}bind_scheduler NULL arguments
  2010-10-04 13:46 [patch v5 00/12] IPVS: SIP Persistence Engine Simon Horman
                   ` (4 preceding siblings ...)
  2010-10-04 13:46 ` [patch v5 05/12] IPVS: Allow null argument to ip_vs_scheduler_put() Simon Horman
@ 2010-10-04 13:46 ` Simon Horman
  2010-10-04 13:46 ` [patch v5 07/12] IPVS: Add struct ip_vs_pe Simon Horman
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 18+ messages in thread
From: Simon Horman @ 2010-10-04 13:46 UTC (permalink / raw)
  To: lvs-devel, netdev, netfilter, netfilter-devel
  Cc: Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
	Julian Anastasov, Patrick McHardy

[-- Attachment #1: 0006-IPVS-ip_vs_-un-bind_scheduler-NULL-arguments.patch --]
[-- Type: text/plain, Size: 1790 bytes --]

In general NULL arguments aren't passed by the few callers that exist,
so don't test for them.

The exception is to make passing NULL to ip_vs_unbind_scheduler() a noop.

Signed-off-by: Simon Horman <horms@verge.net.au>
Acked-by: Julian Anastasov <ja@ssi.bg>

--- 

v2
* Trivial rediff

v3
* Trivial rediff

Index: lvs-test-2.6/net/netfilter/ipvs/ip_vs_ctl.c
===================================================================
--- lvs-test-2.6.orig/net/netfilter/ipvs/ip_vs_ctl.c	2010-10-02 10:15:45.000000000 +0900
+++ lvs-test-2.6/net/netfilter/ipvs/ip_vs_ctl.c	2010-10-02 10:15:47.000000000 +0900
@@ -1206,8 +1206,7 @@ ip_vs_add_service(struct ip_vs_service_u
 
  out_err:
 	if (svc != NULL) {
-		if (svc->scheduler)
-			ip_vs_unbind_scheduler(svc);
+		ip_vs_unbind_scheduler(svc);
 		if (svc->inc) {
 			local_bh_disable();
 			ip_vs_app_inc_put(svc->inc);
Index: lvs-test-2.6/net/netfilter/ipvs/ip_vs_sched.c
===================================================================
--- lvs-test-2.6.orig/net/netfilter/ipvs/ip_vs_sched.c	2010-10-02 10:15:45.000000000 +0900
+++ lvs-test-2.6/net/netfilter/ipvs/ip_vs_sched.c	2010-10-02 10:15:47.000000000 +0900
@@ -46,15 +46,6 @@ int ip_vs_bind_scheduler(struct ip_vs_se
 {
 	int ret;
 
-	if (svc == NULL) {
-		pr_err("%s(): svc arg NULL\n", __func__);
-		return -EINVAL;
-	}
-	if (scheduler == NULL) {
-		pr_err("%s(): scheduler arg NULL\n", __func__);
-		return -EINVAL;
-	}
-
 	svc->scheduler = scheduler;
 
 	if (scheduler->init_service) {
@@ -74,18 +65,10 @@ int ip_vs_bind_scheduler(struct ip_vs_se
  */
 int ip_vs_unbind_scheduler(struct ip_vs_service *svc)
 {
-	struct ip_vs_scheduler *sched;
+	struct ip_vs_scheduler *sched = svc->scheduler;
 
-	if (svc == NULL) {
-		pr_err("%s(): svc arg NULL\n", __func__);
-		return -EINVAL;
-	}

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [patch v5 07/12] IPVS: Add struct ip_vs_pe
  2010-10-04 13:46 [patch v5 00/12] IPVS: SIP Persistence Engine Simon Horman
                   ` (5 preceding siblings ...)
  2010-10-04 13:46 ` [patch v5 06/12] IPVS: ip_vs_{un,}bind_scheduler NULL arguments Simon Horman
@ 2010-10-04 13:46 ` Simon Horman
  2010-10-04 13:46 ` [patch v5 08/12] IPVS: Add persistence engine data to /proc/net/ip_vs_conn Simon Horman
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 18+ messages in thread
From: Simon Horman @ 2010-10-04 13:46 UTC (permalink / raw)
  To: lvs-devel, netdev, netfilter, netfilter-devel
  Cc: Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
	Julian Anastasov, Patrick McHardy

[-- Attachment #1: 0007-IPVS-Add-struct-ip_vs_pe.patch --]
[-- Type: text/plain, Size: 12003 bytes --]

Signed-off-by: Simon Horman <horms@verge.net.au>
Acked-by: Julian Anastasov <ja@ssi.bg>

--- 

This the first of several patches that add persistence engines.

v2
* Don't leak pe_data
  - It wasn't being freed anywhere, ever
* Trivial rediff

v3
* As suggested by Julian Anastasov
  - ip_vs_conn_fill_param(): cp->dest is optional
    so check for its presence accordingly
  - ip_vs_conn_out_get() needs to hash on vaddr/vport 
    whereas ip_vs_conn_hash() hashes on caddr/cport.
    Add an inverse parameter to ip_vs_conn_hashkey_param()
    to allow it to handle both cases.
* Rediff for dport logic fix in "IPVS: compact ip_vs_sched_persist()"

Index: lvs-test-2.6/include/linux/ip_vs.h
===================================================================
--- lvs-test-2.6.orig/include/linux/ip_vs.h	2010-10-02 10:59:26.000000000 +0900
+++ lvs-test-2.6/include/linux/ip_vs.h	2010-10-02 11:09:03.000000000 +0900
@@ -99,8 +99,10 @@
 				0)
 
 #define IP_VS_SCHEDNAME_MAXLEN	16
+#define IP_VS_PENAME_MAXLEN	16
 #define IP_VS_IFNAME_MAXLEN	16
 
+#define IP_VS_PEDATA_MAXLEN     255
 
 /*
  *	The struct ip_vs_service_user and struct ip_vs_dest_user are
Index: lvs-test-2.6/include/net/ip_vs.h
===================================================================
--- lvs-test-2.6.orig/include/net/ip_vs.h	2010-10-02 11:05:43.000000000 +0900
+++ lvs-test-2.6/include/net/ip_vs.h	2010-10-02 11:09:03.000000000 +0900
@@ -364,6 +364,10 @@ struct ip_vs_conn_param {
 	__be16				vport;
 	__u16				protocol;
 	u16				af;
+
+	const struct ip_vs_pe		*pe;
+	char				*pe_data;
+	__u8				pe_data_len;
 };
 
 /*
@@ -416,6 +420,9 @@ struct ip_vs_conn {
 	void                    *app_data;      /* Application private data */
 	struct ip_vs_seq        in_seq;         /* incoming seq. struct */
 	struct ip_vs_seq        out_seq;        /* outgoing seq. struct */
+
+	char			*pe_data;
+	__u8			pe_data_len;
 };
 
 
@@ -486,6 +493,9 @@ struct ip_vs_service {
 	struct ip_vs_scheduler	*scheduler;    /* bound scheduler object */
 	rwlock_t		sched_lock;    /* lock sched_data */
 	void			*sched_data;   /* scheduler application data */
+
+	/* alternate persistence engine */
+	struct ip_vs_pe		*pe;
 };
 
 
@@ -549,6 +559,20 @@ struct ip_vs_scheduler {
 				       const struct sk_buff *skb);
 };
 
+/* The persistence engine object */
+struct ip_vs_pe {
+	struct list_head	n_list;		/* d-linked list head */
+	char			*name;		/* scheduler name */
+	atomic_t		refcnt;		/* reference counter */
+	struct module		*module;	/* THIS_MODULE/NULL */
+
+	/* get the connection template, if any */
+	int (*fill_param)(struct ip_vs_conn_param *p, struct sk_buff *skb);
+	bool (*ct_match)(const struct ip_vs_conn_param *p,
+			 struct ip_vs_conn *ct);
+	u32 (*hashkey_raw)(const struct ip_vs_conn_param *p, u32 initval,
+			   bool inverse);
+};
 
 /*
  *	The application module object (a.k.a. app incarnation)
@@ -648,6 +672,8 @@ static inline void ip_vs_conn_fill_param
 	p->cport = cport;
 	p->vaddr = vaddr;
 	p->vport = vport;
+	p->pe = NULL;
+	p->pe_data = NULL;
 }
 
 struct ip_vs_conn *ip_vs_conn_in_get(const struct ip_vs_conn_param *p);
@@ -803,7 +829,7 @@ extern int ip_vs_unbind_scheduler(struct
 extern struct ip_vs_scheduler *ip_vs_scheduler_get(const char *sched_name);
 extern void ip_vs_scheduler_put(struct ip_vs_scheduler *scheduler);
 extern struct ip_vs_conn *
-ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb);
+ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb);
 extern int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
 			struct ip_vs_protocol *pp);
 
Index: lvs-test-2.6/net/netfilter/ipvs/ip_vs_conn.c
===================================================================
--- lvs-test-2.6.orig/net/netfilter/ipvs/ip_vs_conn.c	2010-10-02 11:05:43.000000000 +0900
+++ lvs-test-2.6/net/netfilter/ipvs/ip_vs_conn.c	2010-10-02 11:09:03.000000000 +0900
@@ -148,6 +148,42 @@ static unsigned int ip_vs_conn_hashkey(i
 		& ip_vs_conn_tab_mask;
 }
 
+static unsigned int ip_vs_conn_hashkey_param(const struct ip_vs_conn_param *p,
+					     bool inverse)
+{
+	const union nf_inet_addr *addr;
+	__be16 port;
+
+	if (p->pe && p->pe->hashkey_raw)
+		return p->pe->hashkey_raw(p, ip_vs_conn_rnd, inverse) &
+			ip_vs_conn_tab_mask;
+
+	if (likely(!inverse)) {
+		addr = p->caddr;
+		port = p->cport;
+	} else {
+		addr = p->vaddr;
+		port = p->vport;
+	}
+
+	return ip_vs_conn_hashkey(p->af, p->protocol, addr, port);
+}
+
+static unsigned int ip_vs_conn_hashkey_conn(const struct ip_vs_conn *cp)
+{
+	struct ip_vs_conn_param p;
+
+	ip_vs_conn_fill_param(cp->af, cp->protocol, &cp->caddr, cp->cport,
+			      NULL, 0, &p);
+
+	if (cp->dest && cp->dest->svc->pe) {
+		p.pe = cp->dest->svc->pe;
+		p.pe_data = cp->pe_data;
+		p.pe_data_len = cp->pe_data_len;
+	}
+
+	return ip_vs_conn_hashkey_param(&p, false);
+}
 
 /*
  *	Hashes ip_vs_conn in ip_vs_conn_tab by proto,addr,port.
@@ -162,7 +198,7 @@ static inline int ip_vs_conn_hash(struct
 		return 0;
 
 	/* Hash by protocol, client address and port */
-	hash = ip_vs_conn_hashkey(cp->af, cp->protocol, &cp->caddr, cp->cport);
+	hash = ip_vs_conn_hashkey_conn(cp);
 
 	ct_write_lock(hash);
 	spin_lock(&cp->lock);
@@ -195,7 +231,7 @@ static inline int ip_vs_conn_unhash(stru
 	int ret;
 
 	/* unhash it and decrease its reference counter */
-	hash = ip_vs_conn_hashkey(cp->af, cp->protocol, &cp->caddr, cp->cport);
+	hash = ip_vs_conn_hashkey_conn(cp);
 
 	ct_write_lock(hash);
 	spin_lock(&cp->lock);
@@ -227,7 +263,7 @@ __ip_vs_conn_in_get(const struct ip_vs_c
 	unsigned hash;
 	struct ip_vs_conn *cp;
 
-	hash = ip_vs_conn_hashkey(p->af, p->protocol, p->caddr, p->cport);
+	hash = ip_vs_conn_hashkey_param(p, false);
 
 	ct_read_lock(hash);
 
@@ -312,11 +348,17 @@ struct ip_vs_conn *ip_vs_ct_in_get(const
 	unsigned hash;
 	struct ip_vs_conn *cp;
 
-	hash = ip_vs_conn_hashkey(p->af, p->protocol, p->caddr, p->cport);
+	hash = ip_vs_conn_hashkey_param(p, false);
 
 	ct_read_lock(hash);
 
 	list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
+		if (p->pe && p->pe->ct_match) {
+			if (p->pe->ct_match(p, cp))
+				goto out;
+			continue;
+		}
+
 		if (cp->af == p->af &&
 		    ip_vs_addr_equal(p->af, p->caddr, &cp->caddr) &&
 		    /* protocol should only be IPPROTO_IP if
@@ -325,15 +367,14 @@ struct ip_vs_conn *ip_vs_ct_in_get(const
 				     p->af, p->vaddr, &cp->vaddr) &&
 		    p->cport == cp->cport && p->vport == cp->vport &&
 		    cp->flags & IP_VS_CONN_F_TEMPLATE &&
-		    p->protocol == cp->protocol) {
-			/* HIT */
-			atomic_inc(&cp->refcnt);
+		    p->protocol == cp->protocol)
 			goto out;
-		}
 	}
 	cp = NULL;
 
   out:
+	if (cp)
+		atomic_inc(&cp->refcnt);
 	ct_read_unlock(hash);
 
 	IP_VS_DBG_BUF(9, "template lookup/in %s %s:%d->%s:%d %s\n",
@@ -357,7 +398,7 @@ struct ip_vs_conn *ip_vs_conn_out_get(co
 	/*
 	 *	Check for "full" addressed entries
 	 */
-	hash = ip_vs_conn_hashkey(p->af, p->protocol, p->vaddr, p->vport);
+	hash = ip_vs_conn_hashkey_param(p, true);
 
 	ct_read_lock(hash);
 
@@ -722,6 +763,7 @@ static void ip_vs_conn_expire(unsigned l
 		if (cp->flags & IP_VS_CONN_F_NFCT)
 			ip_vs_conn_drop_conntrack(cp);
 
+		kfree(cp->pe_data);
 		if (unlikely(cp->app != NULL))
 			ip_vs_unbind_app(cp);
 		ip_vs_unbind_dest(cp);
@@ -782,6 +824,10 @@ ip_vs_conn_new(const struct ip_vs_conn_p
 			&cp->daddr, daddr);
 	cp->dport          = dport;
 	cp->flags	   = flags;
+	if (flags & IP_VS_CONN_F_TEMPLATE && p->pe_data) {
+		cp->pe_data = p->pe_data;
+		cp->pe_data_len = p->pe_data_len;
+	}
 	spin_lock_init(&cp->lock);
 
 	/*
@@ -832,7 +878,6 @@ ip_vs_conn_new(const struct ip_vs_conn_p
 	return cp;
 }
 
-
 /*
  *	/proc/net/ip_vs_conn entries
  */
@@ -848,7 +893,7 @@ static void *ip_vs_conn_array(struct seq
 		list_for_each_entry(cp, &ip_vs_conn_tab[idx], c_list) {
 			if (pos-- == 0) {
 				seq->private = &ip_vs_conn_tab[idx];
-				return cp;
+			return cp;
 			}
 		}
 		ct_read_unlock_bh(idx);
Index: lvs-test-2.6/net/netfilter/ipvs/ip_vs_core.c
===================================================================
--- lvs-test-2.6.orig/net/netfilter/ipvs/ip_vs_core.c	2010-10-02 11:05:43.000000000 +0900
+++ lvs-test-2.6/net/netfilter/ipvs/ip_vs_core.c	2010-10-02 11:09:03.000000000 +0900
@@ -176,6 +176,19 @@ ip_vs_set_state(struct ip_vs_conn *cp, i
 	return pp->state_transition(cp, direction, skb, pp);
 }
 
+static inline int
+ip_vs_conn_fill_param_persist(const struct ip_vs_service *svc,
+			      struct sk_buff *skb, int protocol,
+			      const union nf_inet_addr *caddr, __be16 cport,
+			      const union nf_inet_addr *vaddr, __be16 vport,
+			      struct ip_vs_conn_param *p)
+{
+	ip_vs_conn_fill_param(svc->af, protocol, caddr, cport, vaddr, vport, p);
+	p->pe = svc->pe;
+	if (p->pe && p->pe->fill_param)
+		return p->pe->fill_param(p, skb);
+	return 0;
+}
 
 /*
  *  IPVS persistent scheduling function
@@ -186,7 +199,7 @@ ip_vs_set_state(struct ip_vs_conn *cp, i
  */
 static struct ip_vs_conn *
 ip_vs_sched_persist(struct ip_vs_service *svc,
-		    const struct sk_buff *skb,
+		    struct sk_buff *skb,
 		    __be16 ports[2])
 {
 	struct ip_vs_conn *cp = NULL;
@@ -255,8 +268,9 @@ ip_vs_sched_persist(struct ip_vs_service
 				vaddr = &fwmark;
 			}
 		}
-		ip_vs_conn_fill_param(svc->af, protocol, &snet, 0,
-				      vaddr, vport, &param);
+		if (ip_vs_conn_fill_param_persist(svc, skb, protocol, &snet, 0,
+						  vaddr, vport, &param))
+			return NULL;
 	}
 
 	/* Check if a template already exists */
@@ -268,22 +282,30 @@ ip_vs_sched_persist(struct ip_vs_service
 		dest = svc->scheduler->schedule(svc, skb);
 		if (!dest) {
 			IP_VS_DBG(1, "p-schedule: no dest found.\n");
+			kfree(param.pe_data);
 			return NULL;
 		}
 
 		if (ports[1] == svc->port && svc->port != FTPPORT)
 			dport = dest->port;
 
-		/* Create a template */
+		/* Create a template
+		 * This adds param.pe_data to the template,
+		 * and thus param.pe_data will be destroyed
+		 * when the template expires */
 		ct = ip_vs_conn_new(&param, &dest->addr, dport,
 				    IP_VS_CONN_F_TEMPLATE, dest);
-		if (ct == NULL)
+		if (ct == NULL) {
+			kfree(param.pe_data);
 			return NULL;
+		}
 
 		ct->timeout = svc->timeout;
-	} else
+	} else {
 		/* set destination with the found template */
 		dest = ct->dest;
+		kfree(param.pe_data);
+	}
 
 	dport = ports[1];
 	if (dport == svc->port && dest->port)
@@ -322,7 +344,7 @@ ip_vs_sched_persist(struct ip_vs_service
  *  Protocols supported: TCP, UDP
  */
 struct ip_vs_conn *
-ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
+ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb)
 {
 	struct ip_vs_conn *cp = NULL;
 	struct ip_vs_iphdr iph;
Index: lvs-test-2.6/net/netfilter/ipvs/ip_vs_sync.c
===================================================================
--- lvs-test-2.6.orig/net/netfilter/ipvs/ip_vs_sync.c	2010-10-02 11:05:43.000000000 +0900
+++ lvs-test-2.6/net/netfilter/ipvs/ip_vs_sync.c	2010-10-02 11:09:03.000000000 +0900
@@ -288,6 +288,16 @@ void ip_vs_sync_conn(struct ip_vs_conn *
 		ip_vs_sync_conn(cp->control);
 }
 
+static inline int
+ip_vs_conn_fill_param_sync(int af, int protocol,
+			   const union nf_inet_addr *caddr, __be16 cport,
+			   const union nf_inet_addr *vaddr, __be16 vport,
+			   struct ip_vs_conn_param *p)
+{
+	/* XXX: Need to take into account persistence engine */
+	ip_vs_conn_fill_param(af, protocol, caddr, cport, vaddr, vport, p);
+	return 0;
+}
 
 /*
  *      Process received multicast message and create the corresponding
@@ -372,11 +382,14 @@ static void ip_vs_process_message(const
 		}
 
 		{
-			ip_vs_conn_fill_param(AF_INET, s->protocol,
+			if (ip_vs_conn_fill_param_sync(AF_INET, s->protocol,
 					      (union nf_inet_addr *)&s->caddr,
 					      s->cport,
 					      (union nf_inet_addr *)&s->vaddr,
-					      s->vport, &param);
+					      s->vport, &param)) {
+				pr_err("ip_vs_conn_fill_param_sync failed");
+				return;
+			}
 			if (!(flags & IP_VS_CONN_F_TEMPLATE))
 				cp = ip_vs_conn_in_get(&param);
 			else


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [patch v5 08/12] IPVS: Add persistence engine data to /proc/net/ip_vs_conn
  2010-10-04 13:46 [patch v5 00/12] IPVS: SIP Persistence Engine Simon Horman
                   ` (6 preceding siblings ...)
  2010-10-04 13:46 ` [patch v5 07/12] IPVS: Add struct ip_vs_pe Simon Horman
@ 2010-10-04 13:46 ` Simon Horman
  2010-10-04 13:46 ` [patch v5 09/12] IPVS: management of persistence engine modules Simon Horman
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 18+ messages in thread
From: Simon Horman @ 2010-10-04 13:46 UTC (permalink / raw)
  To: lvs-devel, netdev, netfilter, netfilter-devel
  Cc: Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
	Julian Anastasov, Patrick McHardy

[-- Attachment #1: 0008-IPVS-Add-persistence-engine-data-to-proc-net-ip_vs_c.patch --]
[-- Type: text/plain, Size: 3131 bytes --]

This shouldn't break compatibility with userspace as the new data
is at the end of the line.

I have confirmed that this doesn't break ipvsadm, the main (only?)
user-space user of this data.

Signed-off-by: Simon Horman <horms@verge.net.au>
Acked-by: Julian Anastasov <ja@ssi.bg>

---

* Jan Engelhardt suggested using netlink to do this, but it seems like
  overkill to me. I'm willing to be convinced otherwise.

v2
* Trivial rediff

v3
* As suggested by Julian Anastasov
  - ip_vs_conn_seq_show(): cp->dest is optional
    so test for its presence accordingly
  - Re-diff for addition of inverse parameter to ip_vs_conn_hashkey_param()

Index: lvs-test-2.6/include/net/ip_vs.h
===================================================================
--- lvs-test-2.6.orig/include/net/ip_vs.h	2010-10-02 10:55:43.000000000 +0900
+++ lvs-test-2.6/include/net/ip_vs.h	2010-10-02 10:55:49.000000000 +0900
@@ -572,6 +572,7 @@ struct ip_vs_pe {
 			 struct ip_vs_conn *ct);
 	u32 (*hashkey_raw)(const struct ip_vs_conn_param *p, u32 initval,
 			   bool inverse);
+	int (*show_pe_data)(const struct ip_vs_conn *cp, char *buf);
 };
 
 /*
Index: lvs-test-2.6/net/netfilter/ipvs/ip_vs_conn.c
===================================================================
--- lvs-test-2.6.orig/net/netfilter/ipvs/ip_vs_conn.c	2010-10-02 10:55:43.000000000 +0900
+++ lvs-test-2.6/net/netfilter/ipvs/ip_vs_conn.c	2010-10-02 10:57:00.000000000 +0900
@@ -950,30 +950,45 @@ static int ip_vs_conn_seq_show(struct se
 
 	if (v == SEQ_START_TOKEN)
 		seq_puts(seq,
-   "Pro FromIP   FPrt ToIP     TPrt DestIP   DPrt State       Expires\n");
+   "Pro FromIP   FPrt ToIP     TPrt DestIP   DPrt State       Expires PEName PEData\n");
 	else {
 		const struct ip_vs_conn *cp = v;
+		char pe_data[IP_VS_PENAME_MAXLEN + IP_VS_PEDATA_MAXLEN + 3];
+		size_t len = 0;
+
+		if (cp->dest && cp->dest->svc->pe &&
+		    cp->dest->svc->pe->show_pe_data) {
+			pe_data[0] = ' ';
+			len = strlen(cp->dest->svc->pe->name);
+			memcpy(pe_data + 1, cp->dest->svc->pe->name, len);
+			pe_data[len + 1] = ' ';
+			len += 2;
+			len += cp->dest->svc->pe->show_pe_data(cp,
+							       pe_data + len);
+		}
+		pe_data[len] = '\0';
 
 #ifdef CONFIG_IP_VS_IPV6
 		if (cp->af == AF_INET6)
-			seq_printf(seq, "%-3s %pI6 %04X %pI6 %04X %pI6 %04X %-11s %7lu\n",
+			seq_printf(seq, "%-3s %pI6 %04X %pI6 %04X "
+				"%pI6 %04X %-11s %7lu%s\n",
 				ip_vs_proto_name(cp->protocol),
 				&cp->caddr.in6, ntohs(cp->cport),
 				&cp->vaddr.in6, ntohs(cp->vport),
 				&cp->daddr.in6, ntohs(cp->dport),
 				ip_vs_state_name(cp->protocol, cp->state),
-				(cp->timer.expires-jiffies)/HZ);
+				(cp->timer.expires-jiffies)/HZ, pe_data);
 		else
 #endif
 			seq_printf(seq,
 				"%-3s %08X %04X %08X %04X"
-				" %08X %04X %-11s %7lu\n",
+				" %08X %04X %-11s %7lu%s\n",
 				ip_vs_proto_name(cp->protocol),
 				ntohl(cp->caddr.ip), ntohs(cp->cport),
 				ntohl(cp->vaddr.ip), ntohs(cp->vport),
 				ntohl(cp->daddr.ip), ntohs(cp->dport),
 				ip_vs_state_name(cp->protocol, cp->state),
-				(cp->timer.expires-jiffies)/HZ);
+				(cp->timer.expires-jiffies)/HZ, pe_data);
 	}
 	return 0;
 }


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [patch v5 09/12] IPVS: management of persistence engine modules
  2010-10-04 13:46 [patch v5 00/12] IPVS: SIP Persistence Engine Simon Horman
                   ` (7 preceding siblings ...)
  2010-10-04 13:46 ` [patch v5 08/12] IPVS: Add persistence engine data to /proc/net/ip_vs_conn Simon Horman
@ 2010-10-04 13:46 ` Simon Horman
  2010-10-04 13:46 ` [patch v5 10/12] IPVS: Allow configuration of persistence engines Simon Horman
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 18+ messages in thread
From: Simon Horman @ 2010-10-04 13:46 UTC (permalink / raw)
  To: lvs-devel, netdev, netfilter, netfilter-devel
  Cc: Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
	Julian Anastasov, Patrick McHardy

[-- Attachment #1: 0009-IPVS-management-of-persistence-engine-modules.patch --]
[-- Type: text/plain, Size: 5764 bytes --]

This is based heavily on the scheduler management code

Signed-off-by: Simon Horman <horms@verge.net.au>
Acked-by: Julian Anastasov <ja@ssi.bg>

---

v0.4
* Export register_ip_vs_pe and unregister_ip_vs_pe
* Use one line comment format for one line comments.
* Only use at most one blank line consecutively

v1
* As suggested by Stephen Hemminger
  - Convert __ip_vs_pe_lock from a rwlock to a spinlock.
    This code isn't performance-critical, so there is no need for RCU.
  - Rename __ip_vs_pe_lock as ip_vs_pe_lock
* Stephen also suggested open-coding ip_vs_{un,}bind_pe()
  as they are very short. But I would prefer to keep them as they are used
  along side ip_vs_{un,}bind_scheduler which are too long to be open-coded.

v2
* Update for recent addition of ip_vs_nfct.c
* Trivial rediff

v3
* Trivial rediff

Index: lvs-test-2.6/include/net/ip_vs.h
===================================================================
--- lvs-test-2.6.orig/include/net/ip_vs.h	2010-10-02 10:45:06.000000000 +0900
+++ lvs-test-2.6/include/net/ip_vs.h	2010-10-02 10:45:41.000000000 +0900
@@ -796,6 +796,12 @@ extern int ip_vs_app_pkt_in(struct ip_vs
 extern int ip_vs_app_init(void);
 extern void ip_vs_app_cleanup(void);
 
+void ip_vs_bind_pe(struct ip_vs_service *svc, struct ip_vs_pe *pe);
+void ip_vs_unbind_pe(struct ip_vs_service *svc);
+int register_ip_vs_pe(struct ip_vs_pe *pe);
+int unregister_ip_vs_pe(struct ip_vs_pe *pe);
+extern struct ip_vs_pe *ip_vs_pe_get(const char *name);
+extern void ip_vs_pe_put(struct ip_vs_pe *pe);
 
 /*
  *	IPVS protocol functions (from ip_vs_proto.c)
Index: lvs-test-2.6/net/netfilter/ipvs/ip_vs_pe.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ lvs-test-2.6/net/netfilter/ipvs/ip_vs_pe.c	2010-10-02 10:45:41.000000000 +0900
@@ -0,0 +1,147 @@
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <asm/string.h>
+#include <linux/kmod.h>
+#include <linux/sysctl.h>
+
+#include <net/ip_vs.h>
+
+/* IPVS pe list */
+static LIST_HEAD(ip_vs_pe);
+
+/* lock for service table */
+static DEFINE_SPINLOCK(ip_vs_pe_lock);
+
+/* Bind a service with a pe */
+void ip_vs_bind_pe(struct ip_vs_service *svc, struct ip_vs_pe *pe)
+{
+	svc->pe = pe;
+}
+
+/* Unbind a service from its pe */
+void ip_vs_unbind_pe(struct ip_vs_service *svc)
+{
+	svc->pe = NULL;
+}
+
+/* Get pe in the pe list by name */
+static struct ip_vs_pe *
+ip_vs_pe_getbyname(const char *pe_name)
+{
+	struct ip_vs_pe *pe;
+
+	IP_VS_DBG(2, "%s(): pe_name \"%s\"\n", __func__,
+		  pe_name);
+
+	spin_lock_bh(&ip_vs_pe_lock);
+
+	list_for_each_entry(pe, &ip_vs_pe, n_list) {
+		/* Test and get the modules atomically */
+		if (pe->module &&
+		    !try_module_get(pe->module)) {
+			/* This pe is just deleted */
+			continue;
+		}
+		if (strcmp(pe_name, pe->name)==0) {
+			/* HIT */
+			spin_unlock_bh(&ip_vs_pe_lock);
+			return pe;
+		}
+		if (pe->module)
+			module_put(pe->module);
+	}
+
+	spin_unlock_bh(&ip_vs_pe_lock);
+	return NULL;
+}
+
+/* Lookup pe and try to load it if it doesn't exist */
+struct ip_vs_pe *ip_vs_pe_get(const char *name)
+{
+	struct ip_vs_pe *pe;
+
+	/* Search for the pe by name */
+	pe = ip_vs_pe_getbyname(name);
+
+	/* If pe not found, load the module and search again */
+	if (!pe) {
+		request_module("ip_vs_pe_%s", name);
+		pe = ip_vs_pe_getbyname(name);
+	}
+
+	return pe;
+}
+
+void ip_vs_pe_put(struct ip_vs_pe *pe)
+{
+	if (pe && pe->module)
+		module_put(pe->module);
+}
+
+/* Register a pe in the pe list */
+int register_ip_vs_pe(struct ip_vs_pe *pe)
+{
+	struct ip_vs_pe *tmp;
+
+	/* increase the module use count */
+	ip_vs_use_count_inc();
+
+	spin_lock_bh(&ip_vs_pe_lock);
+
+	if (!list_empty(&pe->n_list)) {
+		spin_unlock_bh(&ip_vs_pe_lock);
+		ip_vs_use_count_dec();
+		pr_err("%s(): [%s] pe already linked\n",
+		       __func__, pe->name);
+		return -EINVAL;
+	}
+
+	/* Make sure that the pe with this name doesn't exist
+	 * in the pe list.
+	 */
+	list_for_each_entry(tmp, &ip_vs_pe, n_list) {
+		if (strcmp(tmp->name, pe->name) == 0) {
+			spin_unlock_bh(&ip_vs_pe_lock);
+			ip_vs_use_count_dec();
+			pr_err("%s(): [%s] pe already existed "
+			       "in the system\n", __func__, pe->name);
+			return -EINVAL;
+		}
+	}
+	/* Add it into the d-linked pe list */
+	list_add(&pe->n_list, &ip_vs_pe);
+	spin_unlock_bh(&ip_vs_pe_lock);
+
+	pr_info("[%s] pe registered.\n", pe->name);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(register_ip_vs_pe);
+
+/* Unregister a pe from the pe list */
+int unregister_ip_vs_pe(struct ip_vs_pe *pe)
+{
+	spin_lock_bh(&ip_vs_pe_lock);
+	if (list_empty(&pe->n_list)) {
+		spin_unlock_bh(&ip_vs_pe_lock);
+		pr_err("%s(): [%s] pe is not in the list. failed\n",
+		       __func__, pe->name);
+		return -EINVAL;
+	}
+
+	/* Remove it from the d-linked pe list */
+	list_del(&pe->n_list);
+	spin_unlock_bh(&ip_vs_pe_lock);
+
+	/* decrease the module use count */
+	ip_vs_use_count_dec();
+
+	pr_info("[%s] pe unregistered.\n", pe->name);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(unregister_ip_vs_pe);
Index: lvs-test-2.6/net/netfilter/ipvs/Makefile
===================================================================
--- lvs-test-2.6.orig/net/netfilter/ipvs/Makefile	2010-10-02 10:29:43.000000000 +0900
+++ lvs-test-2.6/net/netfilter/ipvs/Makefile	2010-10-02 10:45:41.000000000 +0900
@@ -14,7 +14,7 @@ ip_vs-extra_objs-$(CONFIG_IP_VS_NFCT) +=
 
 ip_vs-objs :=	ip_vs_conn.o ip_vs_core.o ip_vs_ctl.o ip_vs_sched.o	   \
 		ip_vs_xmit.o ip_vs_app.o ip_vs_sync.o	   		   \
-		ip_vs_est.o ip_vs_proto.o 				   \
+		ip_vs_est.o ip_vs_proto.o ip_vs_pe.o			   \
 		$(ip_vs_proto-objs-y) $(ip_vs-extra_objs-y)
 
 


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [patch v5 10/12] IPVS: Allow configuration of persistence engines
  2010-10-04 13:46 [patch v5 00/12] IPVS: SIP Persistence Engine Simon Horman
                   ` (8 preceding siblings ...)
  2010-10-04 13:46 ` [patch v5 09/12] IPVS: management of persistence engine modules Simon Horman
@ 2010-10-04 13:46 ` Simon Horman
  2010-10-04 13:46 ` [patch v5 11/12] IPVS: Fallback if persistence engine fails Simon Horman
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 18+ messages in thread
From: Simon Horman @ 2010-10-04 13:46 UTC (permalink / raw)
  To: lvs-devel, netdev, netfilter, netfilter-devel
  Cc: Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
	Julian Anastasov, Patrick McHardy

[-- Attachment #1: 0010-IPVS-Allow-configuration-of-persistence-engines.patch --]
[-- Type: text/plain, Size: 7233 bytes --]

Allow the persistence engine of a virtual service to be set, edited
and unset.

This feature only works with the netlink user-space interface.

Signed-off-by: Simon Horman <horms@verge.net.au>
Acked-by: Julian Anastasov <ja@ssi.bg>

---

v2
* Dereference persistence engine when a service is deleted.
  This allows persistence modules to be removed from the kernel
  once they are no longer used.
* Update for the recent "ipvs: changes related to service usecnt" change
* Trivial rediff

v4
* As suggested by  Julian Anastasov <ja@ssi.bg>
  - Initialise ip_vs_service_user_kern to zero in ip_vs_copy_usvc_compat()
    to avoid a crash caused by the pe_name element being uninitialised.

v5
* Fix typo introduced by me when making the change for v4

Index: lvs-test-2.6/include/linux/ip_vs.h
===================================================================
--- lvs-test-2.6.orig/include/linux/ip_vs.h	2010-10-04 22:41:04.000000000 +0900
+++ lvs-test-2.6/include/linux/ip_vs.h	2010-10-04 22:41:28.000000000 +0900
@@ -336,6 +336,9 @@ enum {
 	IPVS_SVC_ATTR_NETMASK,		/* persistent netmask */
 
 	IPVS_SVC_ATTR_STATS,		/* nested attribute for service stats */
+
+	IPVS_SVC_ATTR_PE_NAME,		/* name of ct retriever */
+
 	__IPVS_SVC_ATTR_MAX,
 };
 
Index: lvs-test-2.6/include/net/ip_vs.h
===================================================================
--- lvs-test-2.6.orig/include/net/ip_vs.h	2010-10-04 22:41:20.000000000 +0900
+++ lvs-test-2.6/include/net/ip_vs.h	2010-10-04 22:41:28.000000000 +0900
@@ -444,6 +444,7 @@ struct ip_vs_service_user_kern {
 
 	/* virtual service options */
 	char			*sched_name;
+	char			*pe_name;
 	unsigned		flags;		/* virtual service flags */
 	unsigned		timeout;	/* persistent timeout in sec */
 	u32			netmask;	/* persistent netmask */
Index: lvs-test-2.6/net/netfilter/ipvs/ip_vs_ctl.c
===================================================================
--- lvs-test-2.6.orig/net/netfilter/ipvs/ip_vs_ctl.c	2010-10-04 22:40:58.000000000 +0900
+++ lvs-test-2.6/net/netfilter/ipvs/ip_vs_ctl.c	2010-10-04 22:42:24.000000000 +0900
@@ -1134,6 +1134,7 @@ ip_vs_add_service(struct ip_vs_service_u
 {
 	int ret = 0;
 	struct ip_vs_scheduler *sched = NULL;
+	struct ip_vs_pe *pe = NULL;
 	struct ip_vs_service *svc = NULL;
 
 	/* increase the module use count */
@@ -1147,6 +1148,16 @@ ip_vs_add_service(struct ip_vs_service_u
 		goto out_err;
 	}
 
+	if (u->pe_name && *u->pe_name) {
+		pe = ip_vs_pe_get(u->pe_name);
+		if (pe == NULL) {
+			pr_info("persistence engine module ip_vs_pe_%s "
+				"not found\n", u->pe_name);
+			ret = -ENOENT;
+			goto out_err;
+		}
+	}
+
 #ifdef CONFIG_IP_VS_IPV6
 	if (u->af == AF_INET6 && (u->netmask < 1 || u->netmask > 128)) {
 		ret = -EINVAL;
@@ -1184,6 +1195,10 @@ ip_vs_add_service(struct ip_vs_service_u
 		goto out_err;
 	sched = NULL;
 
+	/* Bind the ct retriever */
+	ip_vs_bind_pe(svc, pe);
+	pe = NULL;
+
 	/* Update the virtual service counters */
 	if (svc->port == FTPPORT)
 		atomic_inc(&ip_vs_ftpsvc_counter);
@@ -1215,6 +1230,7 @@ ip_vs_add_service(struct ip_vs_service_u
 		kfree(svc);
 	}
 	ip_vs_scheduler_put(sched);
+	ip_vs_pe_put(pe);
 
 	/* decrease the module use count */
 	ip_vs_use_count_dec();
@@ -1230,6 +1246,7 @@ static int
 ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u)
 {
 	struct ip_vs_scheduler *sched, *old_sched;
+	struct ip_vs_pe *pe = NULL, *old_pe = NULL;
 	int ret = 0;
 
 	/*
@@ -1242,6 +1259,17 @@ ip_vs_edit_service(struct ip_vs_service
 	}
 	old_sched = sched;
 
+	if (u->pe_name && *u->pe_name) {
+		pe = ip_vs_pe_get(u->pe_name);
+		if (pe == NULL) {
+			pr_info("persistence engine module ip_vs_pe_%s "
+				"not found\n", u->pe_name);
+			ret = -ENOENT;
+			goto out;
+		}
+		old_pe = pe;
+	}
+
 #ifdef CONFIG_IP_VS_IPV6
 	if (u->af == AF_INET6 && (u->netmask < 1 || u->netmask > 128)) {
 		ret = -EINVAL;
@@ -1293,12 +1321,17 @@ ip_vs_edit_service(struct ip_vs_service
 		}
 	}
 
+	old_pe = svc->pe;
+	if (pe != old_pe) {
+		ip_vs_unbind_pe(svc);
+		ip_vs_bind_pe(svc, pe);
+	}
+
   out_unlock:
 	write_unlock_bh(&__ip_vs_svc_lock);
-#ifdef CONFIG_IP_VS_IPV6
   out:
-#endif
 	ip_vs_scheduler_put(old_sched);
+	ip_vs_pe_put(old_pe);
 	return ret;
 }
 
@@ -1312,6 +1345,9 @@ static void __ip_vs_del_service(struct i
 {
 	struct ip_vs_dest *dest, *nxt;
 	struct ip_vs_scheduler *old_sched;
+	struct ip_vs_pe *old_pe;
+
+	pr_info("%s: enter\n", __func__);
 
 	/* Count only IPv4 services for old get/setsockopt interface */
 	if (svc->af == AF_INET)
@@ -1324,6 +1360,11 @@ static void __ip_vs_del_service(struct i
 	ip_vs_unbind_scheduler(svc);
 	ip_vs_scheduler_put(old_sched);
 
+	/* Unbind persistence engine */
+	old_pe = svc->pe;
+	ip_vs_unbind_pe(svc);
+	ip_vs_pe_put(old_pe);
+
 	/* Unbind app inc */
 	if (svc->inc) {
 		ip_vs_app_inc_put(svc->inc);
@@ -2026,6 +2067,8 @@ static const unsigned char set_arglen[SE
 static void ip_vs_copy_usvc_compat(struct ip_vs_service_user_kern *usvc,
 				  struct ip_vs_service_user *usvc_compat)
 {
+	memset(usvc, 0, sizeof(*usvc));
+
 	usvc->af		= AF_INET;
 	usvc->protocol		= usvc_compat->protocol;
 	usvc->addr.ip		= usvc_compat->addr;
@@ -2043,6 +2086,8 @@ static void ip_vs_copy_usvc_compat(struc
 static void ip_vs_copy_udest_compat(struct ip_vs_dest_user_kern *udest,
 				   struct ip_vs_dest_user *udest_compat)
 {
+	memset(udest, 0, sizeof(*udest));
+
 	udest->addr.ip		= udest_compat->addr;
 	udest->port		= udest_compat->port;
 	udest->conn_flags	= udest_compat->conn_flags;
@@ -2539,6 +2584,8 @@ static const struct nla_policy ip_vs_svc
 	[IPVS_SVC_ATTR_FWMARK]		= { .type = NLA_U32 },
 	[IPVS_SVC_ATTR_SCHED_NAME]	= { .type = NLA_NUL_STRING,
 					    .len = IP_VS_SCHEDNAME_MAXLEN },
+	[IPVS_SVC_ATTR_PE_NAME]		= { .type = NLA_NUL_STRING,
+					    .len = IP_VS_PENAME_MAXLEN },
 	[IPVS_SVC_ATTR_FLAGS]		= { .type = NLA_BINARY,
 					    .len = sizeof(struct ip_vs_flags) },
 	[IPVS_SVC_ATTR_TIMEOUT]		= { .type = NLA_U32 },
@@ -2615,6 +2662,8 @@ static int ip_vs_genl_fill_service(struc
 	}
 
 	NLA_PUT_STRING(skb, IPVS_SVC_ATTR_SCHED_NAME, svc->scheduler->name);
+	if (svc->pe)
+		NLA_PUT_STRING(skb, IPVS_SVC_ATTR_PE_NAME, svc->pe->name);
 	NLA_PUT(skb, IPVS_SVC_ATTR_FLAGS, sizeof(flags), &flags);
 	NLA_PUT_U32(skb, IPVS_SVC_ATTR_TIMEOUT, svc->timeout / HZ);
 	NLA_PUT_U32(skb, IPVS_SVC_ATTR_NETMASK, svc->netmask);
@@ -2741,11 +2790,12 @@ static int ip_vs_genl_parse_service(stru
 
 	/* If a full entry was requested, check for the additional fields */
 	if (full_entry) {
-		struct nlattr *nla_sched, *nla_flags, *nla_timeout,
+		struct nlattr *nla_sched, *nla_flags, *nla_pe, *nla_timeout,
 			      *nla_netmask;
 		struct ip_vs_flags flags;
 
 		nla_sched = attrs[IPVS_SVC_ATTR_SCHED_NAME];
+		nla_pe = attrs[IPVS_SVC_ATTR_PE_NAME];
 		nla_flags = attrs[IPVS_SVC_ATTR_FLAGS];
 		nla_timeout = attrs[IPVS_SVC_ATTR_TIMEOUT];
 		nla_netmask = attrs[IPVS_SVC_ATTR_NETMASK];
@@ -2763,6 +2813,7 @@ static int ip_vs_genl_parse_service(stru
 		usvc->flags = (usvc->flags & ~flags.mask) |
 			      (flags.flags & flags.mask);
 		usvc->sched_name = nla_data(nla_sched);
+		usvc->pe_name = nla_pe ? nla_data(nla_pe) : NULL;
 		usvc->timeout = nla_get_u32(nla_timeout);
 		usvc->netmask = nla_get_u32(nla_netmask);
 	}


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [patch v5 11/12] IPVS: Fallback if persistence engine fails
  2010-10-04 13:46 [patch v5 00/12] IPVS: SIP Persistence Engine Simon Horman
                   ` (9 preceding siblings ...)
  2010-10-04 13:46 ` [patch v5 10/12] IPVS: Allow configuration of persistence engines Simon Horman
@ 2010-10-04 13:46 ` Simon Horman
  2010-10-04 13:46 ` [patch v5 12/12] IPVS: sip persistence engine Simon Horman
  2010-10-04 18:47 ` [patch v5 00/12] IPVS: SIP Persistence Engine Patrick McHardy
  12 siblings, 0 replies; 18+ messages in thread
From: Simon Horman @ 2010-10-04 13:46 UTC (permalink / raw)
  To: lvs-devel, netdev, netfilter, netfilter-devel
  Cc: Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
	Julian Anastasov, Patrick McHardy

[-- Attachment #1: 0011-IPVS-Fallback-if-persistence-engine-fails.patch --]
[-- Type: text/plain, Size: 3034 bytes --]

Fall back to normal persistence handling if the persistence
engine fails to recognise a packet.

This way, at least the packet will go somewhere.

It is envisaged that iptables could be used to block packets
such if this is not desired although nf_conntrack_sip would
likely need to be enhanced first.

Signed-off-by: Simon Horman <horms@verge.net.au>
Acked-by: Julian Anastasov <ja@ssi.bg>

---

v2
* Trivial rediff

v3
* Re-diff for addition of inverse parameter to ip_vs_conn_hashkey_param()
  and checking of cp->dest in ip_vs_conn_seq_show()

Index: lvs-test-2.6/net/netfilter/ipvs/ip_vs_conn.c
===================================================================
--- lvs-test-2.6.orig/net/netfilter/ipvs/ip_vs_conn.c	2010-10-02 10:48:09.000000000 +0900
+++ lvs-test-2.6/net/netfilter/ipvs/ip_vs_conn.c	2010-10-02 10:48:35.000000000 +0900
@@ -154,7 +154,7 @@ static unsigned int ip_vs_conn_hashkey_p
 	const union nf_inet_addr *addr;
 	__be16 port;
 
-	if (p->pe && p->pe->hashkey_raw)
+	if (p->pe_data && p->pe->hashkey_raw)
 		return p->pe->hashkey_raw(p, ip_vs_conn_rnd, inverse) &
 			ip_vs_conn_tab_mask;
 
@@ -353,7 +353,7 @@ struct ip_vs_conn *ip_vs_ct_in_get(const
 	ct_read_lock(hash);
 
 	list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
-		if (p->pe && p->pe->ct_match) {
+		if (p->pe_data && p->pe->ct_match) {
 			if (p->pe->ct_match(p, cp))
 				goto out;
 			continue;
@@ -956,7 +956,7 @@ static int ip_vs_conn_seq_show(struct se
 		char pe_data[IP_VS_PENAME_MAXLEN + IP_VS_PEDATA_MAXLEN + 3];
 		size_t len = 0;
 
-		if (cp->dest && cp->dest->svc->pe &&
+		if (cp->dest && cp->pe_data &&
 		    cp->dest->svc->pe->show_pe_data) {
 			pe_data[0] = ' ';
 			len = strlen(cp->dest->svc->pe->name);
 			memcpy(pe_data + 1, cp->dest->svc->pe->name, len);
Index: lvs-test-2.6/net/netfilter/ipvs/ip_vs_core.c
===================================================================
--- lvs-test-2.6.orig/net/netfilter/ipvs/ip_vs_core.c	2010-10-02 10:48:09.000000000 +0900
+++ lvs-test-2.6/net/netfilter/ipvs/ip_vs_core.c	2010-10-02 10:48:35.000000000 +0900
@@ -176,7 +176,7 @@ ip_vs_set_state(struct ip_vs_conn *cp, i
 	return pp->state_transition(cp, direction, skb, pp);
 }
 
-static inline int
+static inline void
 ip_vs_conn_fill_param_persist(const struct ip_vs_service *svc,
 			      struct sk_buff *skb, int protocol,
 			      const union nf_inet_addr *caddr, __be16 cport,
@@ -186,8 +186,7 @@ ip_vs_conn_fill_param_persist(const stru
 	ip_vs_conn_fill_param(svc->af, protocol, caddr, cport, vaddr, vport, p);
 	p->pe = svc->pe;
 	if (p->pe && p->pe->fill_param)
-		return p->pe->fill_param(p, skb);
-	return 0;
+		p->pe->fill_param(p, skb);
 }
 
 /*
@@ -268,9 +267,8 @@ ip_vs_sched_persist(struct ip_vs_service
 				vaddr = &fwmark;
 			}
 		}
-		if (ip_vs_conn_fill_param_persist(svc, skb, protocol, &snet, 0,
-						  vaddr, vport, &param))
-			return NULL;
+		ip_vs_conn_fill_param_persist(svc, skb, protocol, &snet, 0,
+					      vaddr, vport, &param);
 	}
 
 	/* Check if a template already exists */


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [patch v5 12/12] IPVS: sip persistence engine
  2010-10-04 13:46 [patch v5 00/12] IPVS: SIP Persistence Engine Simon Horman
                   ` (10 preceding siblings ...)
  2010-10-04 13:46 ` [patch v5 11/12] IPVS: Fallback if persistence engine fails Simon Horman
@ 2010-10-04 13:46 ` Simon Horman
  2010-10-04 18:47 ` [patch v5 00/12] IPVS: SIP Persistence Engine Patrick McHardy
  12 siblings, 0 replies; 18+ messages in thread
From: Simon Horman @ 2010-10-04 13:46 UTC (permalink / raw)
  To: lvs-devel, netdev, netfilter, netfilter-devel
  Cc: Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
	Julian Anastasov, Patrick McHardy

[-- Attachment #1: 0012-IPVS-sip-persistence-engine.patch --]
[-- Type: text/plain, Size: 7221 bytes --]

Add the SIP callid as a key for persistence.

This allows multiple connections from the same IP address to be
differentiated on the basis of the callid.

When used in conjunction with the persistence mask, it allows connections
from different  IP addresses to be aggregated on the basis of the callid.

It is envisaged that a persistence mask of 0.0.0.0 will be a useful
setting.  That is, ignore the source IP address when checking for
persistence.

It is envisaged that this option will be used in conjunction with
one-packet scheduling.

This only works with UDP and cannot be made to work with TCP
within the current framework.

Signed-off-by: Simon Horman <horms@verge.net.au>
Acked-by: Julian Anastasov <ja@ssi.bg>

---

v1
* Use buf[] instead of poiter arithmetic in ip_vs_dbg_callid()
  As suggested by Jan Engelhardt

v2
* Use GFP_ATOMIC for allocations inside of ip_vs_sip_fill_param()
  which is called in an atomic context. This resolves the
  "scheduling while atomic" problem.
* As noted by Julian Anastasov RFC 3261 section 8.1.1.4 says
  "Call-IDs are case-sensitive and are simply compared byte-by-byte",
  so may be memcmp should be used instead of strnicmp() in
  ip_vs_sip_ct_match().
* Spelling fix in comment: persistance -> persistence
* Trivial rediff

v3
* Trivial whitespace fixes
* Update for addition of inverse parameter to ip_vs_conn_hashkey_param()

Index: lvs-test-2.6/net/netfilter/ipvs/Kconfig
===================================================================
--- lvs-test-2.6.orig/net/netfilter/ipvs/Kconfig	2010-10-02 10:49:37.000000000 +0900
+++ lvs-test-2.6/net/netfilter/ipvs/Kconfig	2010-10-02 10:50:16.000000000 +0900
@@ -256,4 +256,11 @@ config	IP_VS_NFCT
 	  connection state to be exported to the Netfilter framework
 	  for filtering purposes.
 
+config	IP_VS_PE_SIP
+	tristate "SIP persistence engine"
+        depends on IP_VS_PROTO_UDP
+	depends on NF_CONNTRACK_SIP
+	---help---
+	  Allow persistence based on the SIP Call-ID
+
 endif # IP_VS
Index: lvs-test-2.6/net/netfilter/ipvs/Makefile
===================================================================
--- lvs-test-2.6.orig/net/netfilter/ipvs/Makefile	2010-10-02 10:50:16.000000000 +0900
+++ lvs-test-2.6/net/netfilter/ipvs/Makefile	2010-10-02 10:50:16.000000000 +0900
@@ -35,3 +35,6 @@ obj-$(CONFIG_IP_VS_NQ) += ip_vs_nq.o
 
 # IPVS application helpers
 obj-$(CONFIG_IP_VS_FTP) += ip_vs_ftp.o
+
+# IPVS connection template retrievers
+obj-$(CONFIG_IP_VS_PE_SIP) += ip_vs_pe_sip.o
Index: lvs-test-2.6/net/netfilter/ipvs/ip_vs_pe_sip.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ lvs-test-2.6/net/netfilter/ipvs/ip_vs_pe_sip.c	2010-10-02 10:52:08.000000000 +0900
@@ -0,0 +1,167 @@
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <net/ip_vs.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <linux/netfilter/nf_conntrack_sip.h>
+
+static const char *ip_vs_dbg_callid(char *buf, size_t buf_len,
+				    const char *callid, size_t callid_len,
+				    int *idx)
+{
+	size_t len = min(min(callid_len, (size_t)64), buf_len - *idx - 1);
+	memcpy(buf + *idx, callid, len);
+	buf[*idx+len] = '\0';
+	*idx += len + 1;
+	return buf + *idx - len;
+}
+
+#define IP_VS_DEBUG_CALLID(callid, len)					\
+	ip_vs_dbg_callid(ip_vs_dbg_buf, sizeof(ip_vs_dbg_buf),		\
+			 callid, len, &ip_vs_dbg_idx)
+
+static int get_callid(const char *dptr, unsigned int dataoff,
+		      unsigned int datalen,
+		      unsigned int *matchoff, unsigned int *matchlen)
+{
+	/* Find callid */
+	while (1) {
+		int ret = ct_sip_get_header(NULL, dptr, dataoff, datalen,
+					    SIP_HDR_CALL_ID, matchoff,
+					    matchlen);
+		if (ret > 0)
+			break;
+		if (!ret)
+			return 0;
+		dataoff += *matchoff;
+	}
+
+	/* Empty callid is useless */
+	if (!*matchlen)
+		return -EINVAL;
+
+	/* Too large is useless */
+	if (*matchlen > IP_VS_PEDATA_MAXLEN)
+		return -EINVAL;
+
+	/* SIP headers are always followed by a line terminator */
+	if (*matchoff + *matchlen == datalen)
+		return -EINVAL;
+
+	/* RFC 2543 allows lines to be terminated with CR, LF or CRLF,
+	 * RFC 3261 allows only CRLF, we support both. */
+	if (*(dptr + *matchoff + *matchlen) != '\r' &&
+	    *(dptr + *matchoff + *matchlen) != '\n')
+		return -EINVAL;
+
+	IP_VS_DBG_BUF(9, "SIP callid %s (%d bytes)\n",
+		      IP_VS_DEBUG_CALLID(dptr + *matchoff, *matchlen),
+		      *matchlen);
+	return 0;
+}
+
+static int
+ip_vs_sip_fill_param(struct ip_vs_conn_param *p, struct sk_buff *skb)
+{
+	struct ip_vs_iphdr iph;
+	unsigned int dataoff, datalen, matchoff, matchlen;
+	const char *dptr;
+
+	ip_vs_fill_iphdr(p->af, skb_network_header(skb), &iph);
+
+	/* Only useful with UDP */
+	if (iph.protocol != IPPROTO_UDP)
+		return -EINVAL;
+
+	/* No Data ? */
+	dataoff = iph.len + sizeof(struct udphdr);
+	if (dataoff >= skb->len)
+		return -EINVAL;
+
+	dptr = skb->data + dataoff;
+	datalen = skb->len - dataoff;
+
+	if (get_callid(dptr, dataoff, datalen, &matchoff, &matchlen))
+		return -EINVAL;
+
+	p->pe_data = kmalloc(matchlen, GFP_ATOMIC);
+	if (!p->pe_data)
+		return -ENOMEM;
+
+	/* N.B: pe_data is only set on success,
+	 * this allows fallback to the default persistence logic on failure
+	 */
+	memcpy(p->pe_data, dptr + matchoff, matchlen);
+	p->pe_data_len = matchlen;
+
+	return 0;
+}
+
+static bool ip_vs_sip_ct_match(const struct ip_vs_conn_param *p,
+				  struct ip_vs_conn *ct)
+
+{
+	bool ret = 0;
+
+	if (ct->af == p->af &&
+	    ip_vs_addr_equal(p->af, p->caddr, &ct->caddr) &&
+	    /* protocol should only be IPPROTO_IP if
+	     * d_addr is a fwmark */
+	    ip_vs_addr_equal(p->protocol == IPPROTO_IP ? AF_UNSPEC : p->af,
+			     p->vaddr, &ct->vaddr) &&
+	    ct->vport == p->vport &&
+	    ct->flags & IP_VS_CONN_F_TEMPLATE &&
+	    ct->protocol == p->protocol &&
+	    ct->pe_data && ct->pe_data_len == p->pe_data_len &&
+	    !memcmp(ct->pe_data, p->pe_data, p->pe_data_len))
+		ret = 1;
+
+	IP_VS_DBG_BUF(9, "SIP template match %s %s->%s:%d %s\n",
+		      ip_vs_proto_name(p->protocol),
+		      IP_VS_DEBUG_CALLID(p->pe_data, p->pe_data_len),
+		      IP_VS_DBG_ADDR(p->af, p->vaddr), ntohs(p->vport),
+		      ret ? "hit" : "not hit");
+
+	return ret;
+}
+
+static u32 ip_vs_sip_hashkey_raw(const struct ip_vs_conn_param *p,
+				 u32 initval, bool inverse)
+{
+	return jhash(p->pe_data, p->pe_data_len, initval);
+}
+
+static int ip_vs_sip_show_pe_data(const struct ip_vs_conn *cp, char *buf)
+{
+	memcpy(buf, cp->pe_data, cp->pe_data_len);
+	return cp->pe_data_len;
+}
+
+static struct ip_vs_pe ip_vs_sip_pe =
+{
+	.name =			"sip",
+	.refcnt =		ATOMIC_INIT(0),
+	.module =		THIS_MODULE,
+	.n_list =		LIST_HEAD_INIT(ip_vs_sip_pe.n_list),
+	.fill_param =		ip_vs_sip_fill_param,
+	.ct_match =		ip_vs_sip_ct_match,
+	.hashkey_raw =		ip_vs_sip_hashkey_raw,
+	.show_pe_data =		ip_vs_sip_show_pe_data,
+};
+
+static int __init ip_vs_sip_init(void)
+{
+	return register_ip_vs_pe(&ip_vs_sip_pe);
+}
+
+static void __exit ip_vs_sip_cleanup(void)
+{
+	unregister_ip_vs_pe(&ip_vs_sip_pe);
+}
+
+module_init(ip_vs_sip_init);
+module_exit(ip_vs_sip_cleanup);
+MODULE_LICENSE("GPL");


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [patch v5 00/12] IPVS: SIP Persistence Engine
  2010-10-04 13:46 [patch v5 00/12] IPVS: SIP Persistence Engine Simon Horman
                   ` (11 preceding siblings ...)
  2010-10-04 13:46 ` [patch v5 12/12] IPVS: sip persistence engine Simon Horman
@ 2010-10-04 18:47 ` Patrick McHardy
  2010-10-05 10:00   ` Simon Horman
  12 siblings, 1 reply; 18+ messages in thread
From: Patrick McHardy @ 2010-10-04 18:47 UTC (permalink / raw)
  To: Simon Horman
  Cc: lvs-devel, netdev, netfilter, netfilter-devel, Jan Engelhardt,
	Stephen Hemminger, Wensong Zhang, Julian Anastasov

Am 04.10.2010 15:46, schrieb Simon Horman:
> CODE AVAILABILITY
> 
> The kernel patches (12) are available in git as the pe-5 branch of
> git://git.kernel.org/pub/scm/linux/kernel/git/horms/lvs-test-2.6.git

Pulled, thanks Simon. I get a warning in ip_vs_pe_sip.c however,
please send a fix for this on top.

net/netfilter/ipvs/ip_vs_pe_sip.c:11: warning: 'ip_vs_dbg_callid'
defined but not used

Thanks!

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [patch v5 00/12] IPVS: SIP Persistence Engine
  2010-10-04 18:47 ` [patch v5 00/12] IPVS: SIP Persistence Engine Patrick McHardy
@ 2010-10-05 10:00   ` Simon Horman
  0 siblings, 0 replies; 18+ messages in thread
From: Simon Horman @ 2010-10-05 10:00 UTC (permalink / raw)
  To: Patrick McHardy
  Cc: lvs-devel, netdev, netfilter, netfilter-devel, Jan Engelhardt,
	Stephen Hemminger, Wensong Zhang, Julian Anastasov

On Mon, Oct 04, 2010 at 08:47:56PM +0200, Patrick McHardy wrote:
> Am 04.10.2010 15:46, schrieb Simon Horman:
> > CODE AVAILABILITY
> > 
> > The kernel patches (12) are available in git as the pe-5 branch of
> > git://git.kernel.org/pub/scm/linux/kernel/git/horms/lvs-test-2.6.git
> 
> Pulled, thanks Simon. I get a warning in ip_vs_pe_sip.c however,
> please send a fix for this on top.
> 
> net/netfilter/ipvs/ip_vs_pe_sip.c:11: warning: 'ip_vs_dbg_callid'
> defined but not used

Sorry about that, I will investigate and send a fix.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [patch v5 04/12] IPVS: Add struct ip_vs_conn_param, IPv6 forgotten ?
  2010-10-04 13:46 ` [patch v5 04/12] IPVS: Add struct ip_vs_conn_param Simon Horman
@ 2010-10-19  9:41   ` Hans Schillstrom
  2010-10-19  9:56     ` [patch v5 04/12] IPVS: Add struct ip_vs_conn_param, IPv6 forgotten No Hans Schillstrom
  0 siblings, 1 reply; 18+ messages in thread
From: Hans Schillstrom @ 2010-10-19  9:41 UTC (permalink / raw)
  To: Simon Horman
  Cc: lvs-devel@vger.kernel.org, netdev@vger.kernel.org,
	netfilter@vger.kernel.org, netfilter-devel@vger.kernel.org,
	Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
	Julian Anastasov, Patrick McHardy

Hi Simon,
There is a show stopper for IPv6 in this patch.
ip_vs_conn_fill_param() doesn't handle IPv6.

On Monday 04 October 2010 15:46:28 Simon Horman wrote:
> Signed-off-by: Simon Horman <horms@verge.net.au>
> Acked-by: Julian Anastasov <ja@ssi.bg>
>
> ---
>
> The motivation for this is to allow persistence engine modules to
> fill in the parameters.
>
> v0.3
> * Add missing changes to ip_vs_ftp.c
>
> v2
> * make "union nf_inet_addr fwmark" const
> * Update for the recent addition of ip_vs_nfct.c
>
> v3
> * As suggested by Julian Anastasov
>   - Correct logic for inverse case in ip_vs_conn_fill_param_proto()
>     and ah_esp_conn_fill_param_proto()
>   - Update ip_vs_conn_out_get()'s comments as its parameters have changed
>   - Add missing call to ip_vs_conn_fill_param() before the second
>     invocation of ip_vs_conn_new() in ip_vs_sched_persist()
> * Trivial re-diff
>
> v4
> * As suggested by Julian Anastasov
>   - Fix logic in ip_vs_conn_out_get_proto()
>     + An error occurs if ip_vs_conn_fill_param_proto is non-zero,
>       not if it is zero
>
  v5+
   * IPv6 addr copy in  ip_vs_conn_fill_param()

> Index: lvs-test-2.6/include/net/ip_vs.h
> ===================================================================
> --- lvs-test-2.6.orig/include/net/ip_vs.h       2010-10-04 17:00:28.000000000 +0900
> +++ lvs-test-2.6/include/net/ip_vs.h    2010-10-04 17:49:20.000000000 +0900
> @@ -357,6 +357,15 @@ struct ip_vs_protocol {
>
>  extern struct ip_vs_protocol * ip_vs_proto_get(unsigned short proto);
>
> +struct ip_vs_conn_param {
> +       const union nf_inet_addr        *caddr;
> +       const union nf_inet_addr        *vaddr;
> +       __be16                          cport;
> +       __be16                          vport;
> +       __u16                           protocol;
> +       u16                             af;
> +};
> +
>  /*
>   *     IP_VS structure allocated for each dynamically scheduled connection
>   */
> @@ -626,13 +635,23 @@ enum {
>         IP_VS_DIR_LAST,
>  };
>
> -extern struct ip_vs_conn *ip_vs_conn_in_get
> -(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
> - const union nf_inet_addr *d_addr, __be16 d_port);
> -
> -extern struct ip_vs_conn *ip_vs_ct_in_get
> -(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
> - const union nf_inet_addr *d_addr, __be16 d_port);
> +static inline void ip_vs_conn_fill_param(int af, int protocol,
> +                                        const union nf_inet_addr *caddr,
> +                                        __be16 cport,
> +                                        const union nf_inet_addr *vaddr,
> +                                        __be16 vport,
> +                                        struct ip_vs_conn_param *p)
> +{
> +       p->af = af;
> +       p->protocol = protocol;

#ifdef CONFIG_IP_VS_IPV6
	if (af == AF_INET6) {
		ipv6_addr_copy(&p->caddr, caddr);
		ipv6_addr_copy(&p->caddr, caddr);
	}
	else
#else
	}
		p->caddr = caddr;
		p->vaddr = vaddr;
	}
+#endif

> +       p->caddr = caddr;
remove line above
> +       p->cport = cport;

> +       p->vaddr = vaddr;
> +       p->vport = vport;
remove line above
> +}
> +
> +struct ip_vs_conn *ip_vs_conn_in_get(const struct ip_vs_conn_param *p);
> +struct ip_vs_conn *ip_vs_ct_in_get(const struct ip_vs_conn_param *p);
>
>  struct ip_vs_conn * ip_vs_conn_in_get_proto(int af, const struct sk_buff *skb,
>                                             struct ip_vs_protocol *pp,
> @@ -640,9 +659,7 @@ struct ip_vs_conn * ip_vs_conn_in_get_pr
>                                             unsigned int proto_off,
>                                             int inverse);
>
> -extern struct ip_vs_conn *ip_vs_conn_out_get
> -(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
> - const union nf_inet_addr *d_addr, __be16 d_port);
> +struct ip_vs_conn *ip_vs_conn_out_get(const struct ip_vs_conn_param *p);
>
>  struct ip_vs_conn * ip_vs_conn_out_get_proto(int af, const struct sk_buff *skb,
>                                              struct ip_vs_protocol *pp,
> @@ -658,11 +675,10 @@ static inline void __ip_vs_conn_put(stru
>  extern void ip_vs_conn_put(struct ip_vs_conn *cp);
>  extern void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __be16 cport);
>
> -extern struct ip_vs_conn *
> -ip_vs_conn_new(int af, int proto, const union nf_inet_addr *caddr, __be16 cport,
> -              const union nf_inet_addr *vaddr, __be16 vport,
> -              const union nf_inet_addr *daddr, __be16 dport, unsigned flags,
> -              struct ip_vs_dest *dest);
> +struct ip_vs_conn *ip_vs_conn_new(const struct ip_vs_conn_param *p,
> +                                 const union nf_inet_addr *daddr,
> +                                 __be16 dport, unsigned flags,
> +                                 struct ip_vs_dest *dest);
>  extern void ip_vs_conn_expire_now(struct ip_vs_conn *cp);
>
>  extern const char * ip_vs_state_name(__u16 proto, int state);
> Index: lvs-test-2.6/net/netfilter/ipvs/ip_vs_conn.c
> ===================================================================
> --- lvs-test-2.6.orig/net/netfilter/ipvs/ip_vs_conn.c   2010-10-04 17:00:28.000000000 +0900
> +++ lvs-test-2.6/net/netfilter/ipvs/ip_vs_conn.c        2010-10-04 17:49:20.000000000 +0900
> @@ -218,27 +218,26 @@ static inline int ip_vs_conn_unhash(stru
>  /*
>   *  Gets ip_vs_conn associated with supplied parameters in the ip_vs_conn_tab.
>   *  Called for pkts coming from OUTside-to-INside.
> - *     s_addr, s_port: pkt source address (foreign host)
> - *     d_addr, d_port: pkt dest address (load balancer)
> + *     p->caddr, p->cport: pkt source address (foreign host)
> + *     p->vaddr, p->vport: pkt dest address (load balancer)
>   */
> -static inline struct ip_vs_conn *__ip_vs_conn_in_get
> -(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
> - const union nf_inet_addr *d_addr, __be16 d_port)
> +static inline struct ip_vs_conn *
> +__ip_vs_conn_in_get(const struct ip_vs_conn_param *p)
>  {
>         unsigned hash;
>         struct ip_vs_conn *cp;
>
> -       hash = ip_vs_conn_hashkey(af, protocol, s_addr, s_port);
> +       hash = ip_vs_conn_hashkey(p->af, p->protocol, p->caddr, p->cport);
>
>         ct_read_lock(hash);
>
>         list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
> -               if (cp->af == af &&
> -                   ip_vs_addr_equal(af, s_addr, &cp->caddr) &&
> -                   ip_vs_addr_equal(af, d_addr, &cp->vaddr) &&
> -                   s_port == cp->cport && d_port == cp->vport &&
> -                   ((!s_port) ^ (!(cp->flags & IP_VS_CONN_F_NO_CPORT))) &&
> -                   protocol == cp->protocol) {
> +               if (cp->af == p->af &&
> +                   ip_vs_addr_equal(p->af, p->caddr, &cp->caddr) &&
> +                   ip_vs_addr_equal(p->af, p->vaddr, &cp->vaddr) &&
> +                   p->cport == cp->cport && p->vport == cp->vport &&
> +                   ((!p->cport) ^ (!(cp->flags & IP_VS_CONN_F_NO_CPORT))) &&
> +                   p->protocol == cp->protocol) {
>                         /* HIT */
>                         atomic_inc(&cp->refcnt);
>                         ct_read_unlock(hash);
> @@ -251,71 +250,82 @@ static inline struct ip_vs_conn *__ip_vs
>         return NULL;
>  }
>
> -struct ip_vs_conn *ip_vs_conn_in_get
> -(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
> - const union nf_inet_addr *d_addr, __be16 d_port)
> +struct ip_vs_conn *ip_vs_conn_in_get(const struct ip_vs_conn_param *p)
>  {
>         struct ip_vs_conn *cp;
>
> -       cp = __ip_vs_conn_in_get(af, protocol, s_addr, s_port, d_addr, d_port);
> -       if (!cp && atomic_read(&ip_vs_conn_no_cport_cnt))
> -               cp = __ip_vs_conn_in_get(af, protocol, s_addr, 0, d_addr,
> -                                        d_port);
> +       cp = __ip_vs_conn_in_get(p);
> +       if (!cp && atomic_read(&ip_vs_conn_no_cport_cnt)) {
> +               struct ip_vs_conn_param cport_zero_p = *p;
> +               cport_zero_p.cport = 0;
> +               cp = __ip_vs_conn_in_get(&cport_zero_p);
> +       }
>
>         IP_VS_DBG_BUF(9, "lookup/in %s %s:%d->%s:%d %s\n",
> -                     ip_vs_proto_name(protocol),
> -                     IP_VS_DBG_ADDR(af, s_addr), ntohs(s_port),
> -                     IP_VS_DBG_ADDR(af, d_addr), ntohs(d_port),
> +                     ip_vs_proto_name(p->protocol),
> +                     IP_VS_DBG_ADDR(p->af, p->caddr), ntohs(p->cport),
> +                     IP_VS_DBG_ADDR(p->af, p->vaddr), ntohs(p->vport),
>                       cp ? "hit" : "not hit");
>
>         return cp;
>  }
>
> +static int
> +ip_vs_conn_fill_param_proto(int af, const struct sk_buff *skb,
> +                           const struct ip_vs_iphdr *iph,
> +                           unsigned int proto_off, int inverse,
> +                           struct ip_vs_conn_param *p)
> +{
> +       __be16 _ports[2], *pptr;
> +
> +       pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
> +       if (pptr == NULL)
> +               return 1;
> +
> +       if (likely(!inverse))
> +               ip_vs_conn_fill_param(af, iph->protocol, &iph->saddr, pptr[0],
> +                                     &iph->daddr, pptr[1], p);
> +       else
> +               ip_vs_conn_fill_param(af, iph->protocol, &iph->daddr, pptr[1],
> +                                     &iph->saddr, pptr[0], p);
> +       return 0;
> +}
> +
>  struct ip_vs_conn *
>  ip_vs_conn_in_get_proto(int af, const struct sk_buff *skb,
>                         struct ip_vs_protocol *pp,
>                         const struct ip_vs_iphdr *iph,
>                         unsigned int proto_off, int inverse)
>  {
> -       __be16 _ports[2], *pptr;
> +       struct ip_vs_conn_param p;
>
> -       pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
> -       if (pptr == NULL)
> +       if (ip_vs_conn_fill_param_proto(af, skb, iph, proto_off, inverse, &p))
>                 return NULL;
>
> -       if (likely(!inverse))
> -               return ip_vs_conn_in_get(af, iph->protocol,
> -                                        &iph->saddr, pptr[0],
> -                                        &iph->daddr, pptr[1]);
> -       else
> -               return ip_vs_conn_in_get(af, iph->protocol,
> -                                        &iph->daddr, pptr[1],
> -                                        &iph->saddr, pptr[0]);
> +       return ip_vs_conn_in_get(&p);
>  }
>  EXPORT_SYMBOL_GPL(ip_vs_conn_in_get_proto);
>
>  /* Get reference to connection template */
> -struct ip_vs_conn *ip_vs_ct_in_get
> -(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
> - const union nf_inet_addr *d_addr, __be16 d_port)
> +struct ip_vs_conn *ip_vs_ct_in_get(const struct ip_vs_conn_param *p)
>  {
>         unsigned hash;
>         struct ip_vs_conn *cp;
>
> -       hash = ip_vs_conn_hashkey(af, protocol, s_addr, s_port);
> +       hash = ip_vs_conn_hashkey(p->af, p->protocol, p->caddr, p->cport);
>
>         ct_read_lock(hash);
>
>         list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
> -               if (cp->af == af &&
> -                   ip_vs_addr_equal(af, s_addr, &cp->caddr) &&
> +               if (cp->af == p->af &&
> +                   ip_vs_addr_equal(p->af, p->caddr, &cp->caddr) &&
>                     /* protocol should only be IPPROTO_IP if
> -                    * d_addr is a fwmark */
> -                   ip_vs_addr_equal(protocol == IPPROTO_IP ? AF_UNSPEC : af,
> -                                    d_addr, &cp->vaddr) &&
> -                   s_port == cp->cport && d_port == cp->vport &&
> +                    * p->vaddr is a fwmark */
> +                   ip_vs_addr_equal(p->protocol == IPPROTO_IP ? AF_UNSPEC :
> +                                    p->af, p->vaddr, &cp->vaddr) &&
> +                   p->cport == cp->cport && p->vport == cp->vport &&
>                     cp->flags & IP_VS_CONN_F_TEMPLATE &&
> -                   protocol == cp->protocol) {
> +                   p->protocol == cp->protocol) {
>                         /* HIT */
>                         atomic_inc(&cp->refcnt);
>                         goto out;
> @@ -327,23 +337,19 @@ struct ip_vs_conn *ip_vs_ct_in_get
>         ct_read_unlock(hash);
>
>         IP_VS_DBG_BUF(9, "template lookup/in %s %s:%d->%s:%d %s\n",
> -                     ip_vs_proto_name(protocol),
> -                     IP_VS_DBG_ADDR(af, s_addr), ntohs(s_port),
> -                     IP_VS_DBG_ADDR(af, d_addr), ntohs(d_port),
> +                     ip_vs_proto_name(p->protocol),
> +                     IP_VS_DBG_ADDR(p->af, p->caddr), ntohs(p->cport),
> +                     IP_VS_DBG_ADDR(p->af, p->vaddr), ntohs(p->vport),
>                       cp ? "hit" : "not hit");
>
>         return cp;
>  }
>
> -/*
> - *  Gets ip_vs_conn associated with supplied parameters in the ip_vs_conn_tab.
> - *  Called for pkts coming from inside-to-OUTside.
> - *     s_addr, s_port: pkt source address (inside host)
> - *     d_addr, d_port: pkt dest address (foreign host)
> - */
> -struct ip_vs_conn *ip_vs_conn_out_get
> -(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
> - const union nf_inet_addr *d_addr, __be16 d_port)
> +/* Gets ip_vs_conn associated with supplied parameters in the ip_vs_conn_tab.
> + * Called for pkts coming from inside-to-OUTside.
> + *     p->caddr, p->cport: pkt source address (inside host)
> + *     p->vaddr, p->vport: pkt dest address (foreign host) */
> +struct ip_vs_conn *ip_vs_conn_out_get(const struct ip_vs_conn_param *p)
>  {
>         unsigned hash;
>         struct ip_vs_conn *cp, *ret=NULL;
> @@ -351,16 +357,16 @@ struct ip_vs_conn *ip_vs_conn_out_get
>         /*
>          *      Check for "full" addressed entries
>          */
> -       hash = ip_vs_conn_hashkey(af, protocol, d_addr, d_port);
> +       hash = ip_vs_conn_hashkey(p->af, p->protocol, p->vaddr, p->vport);
>
>         ct_read_lock(hash);
>
>         list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
> -               if (cp->af == af &&
> -                   ip_vs_addr_equal(af, d_addr, &cp->caddr) &&
> -                   ip_vs_addr_equal(af, s_addr, &cp->daddr) &&
> -                   d_port == cp->cport && s_port == cp->dport &&
> -                   protocol == cp->protocol) {
> +               if (cp->af == p->af &&
> +                   ip_vs_addr_equal(p->af, p->vaddr, &cp->caddr) &&
> +                   ip_vs_addr_equal(p->af, p->caddr, &cp->daddr) &&
> +                   p->vport == cp->cport && p->cport == cp->dport &&
> +                   p->protocol == cp->protocol) {
>                         /* HIT */
>                         atomic_inc(&cp->refcnt);
>                         ret = cp;
> @@ -371,9 +377,9 @@ struct ip_vs_conn *ip_vs_conn_out_get
>         ct_read_unlock(hash);
>
>         IP_VS_DBG_BUF(9, "lookup/out %s %s:%d->%s:%d %s\n",
> -                     ip_vs_proto_name(protocol),
> -                     IP_VS_DBG_ADDR(af, s_addr), ntohs(s_port),
> -                     IP_VS_DBG_ADDR(af, d_addr), ntohs(d_port),
> +                     ip_vs_proto_name(p->protocol),
> +                     IP_VS_DBG_ADDR(p->af, p->caddr), ntohs(p->cport),
> +                     IP_VS_DBG_ADDR(p->af, p->vaddr), ntohs(p->vport),
>                       ret ? "hit" : "not hit");
>
>         return ret;
> @@ -385,20 +391,12 @@ ip_vs_conn_out_get_proto(int af, const s
>                          const struct ip_vs_iphdr *iph,
>                          unsigned int proto_off, int inverse)
>  {
> -       __be16 _ports[2], *pptr;
> +       struct ip_vs_conn_param p;
>
> -       pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
> -       if (pptr == NULL)
> +       if (ip_vs_conn_fill_param_proto(af, skb, iph, proto_off, inverse, &p))
>                 return NULL;
>
> -       if (likely(!inverse))
> -               return ip_vs_conn_out_get(af, iph->protocol,
> -                                         &iph->saddr, pptr[0],
> -                                         &iph->daddr, pptr[1]);
> -       else
> -               return ip_vs_conn_out_get(af, iph->protocol,
> -                                         &iph->daddr, pptr[1],
> -                                         &iph->saddr, pptr[0]);
> +       return ip_vs_conn_out_get(&p);
>  }
>  EXPORT_SYMBOL_GPL(ip_vs_conn_out_get_proto);
>
> @@ -758,13 +756,12 @@ void ip_vs_conn_expire_now(struct ip_vs_
>   *     Create a new connection entry and hash it into the ip_vs_conn_tab
>   */
>  struct ip_vs_conn *
> -ip_vs_conn_new(int af, int proto, const union nf_inet_addr *caddr, __be16 cport,
> -              const union nf_inet_addr *vaddr, __be16 vport,
> +ip_vs_conn_new(const struct ip_vs_conn_param *p,
>                const union nf_inet_addr *daddr, __be16 dport, unsigned flags,
>                struct ip_vs_dest *dest)
>  {
>         struct ip_vs_conn *cp;
> -       struct ip_vs_protocol *pp = ip_vs_proto_get(proto);
> +       struct ip_vs_protocol *pp = ip_vs_proto_get(p->protocol);
>
>         cp = kmem_cache_zalloc(ip_vs_conn_cachep, GFP_ATOMIC);
>         if (cp == NULL) {
> @@ -774,14 +771,14 @@ ip_vs_conn_new(int af, int proto, const
>
>         INIT_LIST_HEAD(&cp->c_list);
>         setup_timer(&cp->timer, ip_vs_conn_expire, (unsigned long)cp);
> -       cp->af             = af;
> -       cp->protocol       = proto;
> -       ip_vs_addr_copy(af, &cp->caddr, caddr);
> -       cp->cport          = cport;
> -       ip_vs_addr_copy(af, &cp->vaddr, vaddr);
> -       cp->vport          = vport;
> +       cp->af             = p->af;
> +       cp->protocol       = p->protocol;
> +       ip_vs_addr_copy(p->af, &cp->caddr, p->caddr);
> +       cp->cport          = p->cport;
> +       ip_vs_addr_copy(p->af, &cp->vaddr, p->vaddr);
> +       cp->vport          = p->vport;
>         /* proto should only be IPPROTO_IP if d_addr is a fwmark */
> -       ip_vs_addr_copy(proto == IPPROTO_IP ? AF_UNSPEC : af,
> +       ip_vs_addr_copy(p->protocol == IPPROTO_IP ? AF_UNSPEC : p->af,
>                         &cp->daddr, daddr);
>         cp->dport          = dport;
>         cp->flags          = flags;
> @@ -810,7 +807,7 @@ ip_vs_conn_new(int af, int proto, const
>
>         /* Bind its packet transmitter */
>  #ifdef CONFIG_IP_VS_IPV6
> -       if (af == AF_INET6)
> +       if (p->af == AF_INET6)
>                 ip_vs_bind_xmit_v6(cp);
>         else
>  #endif
> Index: lvs-test-2.6/net/netfilter/ipvs/ip_vs_core.c
> ===================================================================
> --- lvs-test-2.6.orig/net/netfilter/ipvs/ip_vs_core.c   2010-10-04 17:00:45.000000000 +0900
> +++ lvs-test-2.6/net/netfilter/ipvs/ip_vs_core.c        2010-10-04 17:49:20.000000000 +0900
> @@ -193,14 +193,11 @@ ip_vs_sched_persist(struct ip_vs_service
>         struct ip_vs_iphdr iph;
>         struct ip_vs_dest *dest;
>         struct ip_vs_conn *ct;
> -       int protocol = iph.protocol;
>         __be16 dport = 0;               /* destination port to forward */
> -       __be16 vport = 0;               /* virtual service port */
>         unsigned int flags;
> +       struct ip_vs_conn_param param;
>         union nf_inet_addr snet;        /* source network of the client,
>                                            after masking */
> -       const union nf_inet_addr fwmark = { .ip = htonl(svc->fwmark) };
> -       const union nf_inet_addr *vaddr = &iph.daddr;
>
>         ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
>
> @@ -232,6 +229,11 @@ ip_vs_sched_persist(struct ip_vs_service
>          * is created for other persistent services.
>          */
>         {
> +               int protocol = iph.protocol;
> +               const union nf_inet_addr *vaddr = &iph.daddr;
> +               const union nf_inet_addr fwmark = { .ip = htonl(svc->fwmark) };
> +               __be16 vport = 0;
> +
>                 if (ports[1] == svc->port) {
>                         /* non-FTP template:
>                          * <protocol, caddr, 0, vaddr, vport, daddr, dport>
> @@ -253,11 +255,12 @@ ip_vs_sched_persist(struct ip_vs_service
>                                 vaddr = &fwmark;
>                         }
>                 }
> +               ip_vs_conn_fill_param(svc->af, protocol, &snet, 0,
> +                                     vaddr, vport, &param);
>         }
>
>         /* Check if a template already exists */
> -       ct = ip_vs_ct_in_get(svc->af, protocol, &snet, 0, vaddr, vport);
> -
> +       ct = ip_vs_ct_in_get(&param);
>         if (!ct || !ip_vs_check_template(ct)) {
>                 /* No template found or the dest of the connection
>                  * template is not available.
> @@ -272,8 +275,7 @@ ip_vs_sched_persist(struct ip_vs_service
>                         dport = dest->port;
>
>                 /* Create a template */
> -               ct = ip_vs_conn_new(svc->af, protocol, &snet, 0,vaddr, vport,
> -                                   &dest->addr, dport,
> +               ct = ip_vs_conn_new(&param, &dest->addr, dport,
>                                     IP_VS_CONN_F_TEMPLATE, dest);
>                 if (ct == NULL)
>                         return NULL;
> @@ -294,12 +296,9 @@ ip_vs_sched_persist(struct ip_vs_service
>         /*
>          *    Create a new connection according to the template
>          */
> -       cp = ip_vs_conn_new(svc->af, iph.protocol,
> -                           &iph.saddr, ports[0],
> -                           &iph.daddr, ports[1],
> -                           &dest->addr, dport,
> -                           flags,
> -                           dest);
> +       ip_vs_conn_fill_param(svc->af, iph.protocol, &iph.saddr, ports[0],
> +                             &iph.daddr, ports[1], &param);
> +       cp = ip_vs_conn_new(&param, &dest->addr, dport, flags, dest);
>         if (cp == NULL) {
>                 ip_vs_conn_put(ct);
>                 return NULL;
> @@ -366,14 +365,16 @@ ip_vs_schedule(struct ip_vs_service *svc
>         /*
>          *    Create a connection entry.
>          */
> -       cp = ip_vs_conn_new(svc->af, iph.protocol,
> -                           &iph.saddr, pptr[0],
> -                           &iph.daddr, pptr[1],
> -                           &dest->addr, dest->port ? dest->port : pptr[1],
> -                           flags,
> -                           dest);
> -       if (cp == NULL)
> -               return NULL;
> +       {
> +               struct ip_vs_conn_param p;
> +               ip_vs_conn_fill_param(svc->af, iph.protocol, &iph.saddr,
> +                                     pptr[0], &iph.daddr, pptr[1], &p);
> +               cp = ip_vs_conn_new(&p, &dest->addr,
> +                                   dest->port ? dest->port : pptr[1],
> +                                   flags, dest);
> +               if (!cp)
> +                       return NULL;
> +       }
>
>         IP_VS_DBG_BUF(6, "Schedule fwd:%c c:%s:%u v:%s:%u "
>                       "d:%s:%u conn->flags:%X conn->refcnt:%d\n",
> @@ -429,14 +430,17 @@ int ip_vs_leave(struct ip_vs_service *sv
>
>                 /* create a new connection entry */
>                 IP_VS_DBG(6, "%s(): create a cache_bypass entry\n", __func__);
> -               cp = ip_vs_conn_new(svc->af, iph.protocol,
> -                                   &iph.saddr, pptr[0],
> -                                   &iph.daddr, pptr[1],
> -                                   &daddr, 0,
> -                                   IP_VS_CONN_F_BYPASS | flags,
> -                                   NULL);
> -               if (cp == NULL)
> -                       return NF_DROP;
> +               {
> +                       struct ip_vs_conn_param p;
> +                       ip_vs_conn_fill_param(svc->af, iph.protocol,
> +                                             &iph.saddr, pptr[0],
> +                                             &iph.daddr, pptr[1], &p);
> +                       cp = ip_vs_conn_new(&p, &daddr, 0,
> +                                           IP_VS_CONN_F_BYPASS | flags,
> +                                           NULL);
> +                       if (!cp)
> +                               return NF_DROP;
> +               }
>
>                 /* statistics */
>                 ip_vs_in_stats(cp, skb);
> Index: lvs-test-2.6/net/netfilter/ipvs/ip_vs_ftp.c
> ===================================================================
> --- lvs-test-2.6.orig/net/netfilter/ipvs/ip_vs_ftp.c    2010-10-04 16:58:31.000000000 +0900
> +++ lvs-test-2.6/net/netfilter/ipvs/ip_vs_ftp.c 2010-10-04 17:00:45.000000000 +0900
> @@ -195,13 +195,17 @@ static int ip_vs_ftp_out(struct ip_vs_ap
>                 /*
>                  * Now update or create an connection entry for it
>                  */
> -               n_cp = ip_vs_conn_out_get(AF_INET, iph->protocol, &from, port,
> -                                         &cp->caddr, 0);
> +               {
> +                       struct ip_vs_conn_param p;
> +                       ip_vs_conn_fill_param(AF_INET, iph->protocol,
> +                                             &from, port, &cp->caddr, 0, &p);
> +                       n_cp = ip_vs_conn_out_get(&p);
> +               }
>                 if (!n_cp) {
> -                       n_cp = ip_vs_conn_new(AF_INET, IPPROTO_TCP,
> -                                             &cp->caddr, 0,
> -                                             &cp->vaddr, port,
> -                                             &from, port,
> +                       struct ip_vs_conn_param p;
> +                       ip_vs_conn_fill_param(AF_INET, IPPROTO_TCP, &cp->caddr,
> +                                             0, &cp->vaddr, port, &p);
> +                       n_cp = ip_vs_conn_new(&p, &from, port,
>                                               IP_VS_CONN_F_NO_CPORT |
>                                               IP_VS_CONN_F_NFCT,
>                                               cp->dest);
> @@ -347,21 +351,22 @@ static int ip_vs_ftp_in(struct ip_vs_app
>                   ip_vs_proto_name(iph->protocol),
>                   &to.ip, ntohs(port), &cp->vaddr.ip, 0);
>
> -       n_cp = ip_vs_conn_in_get(AF_INET, iph->protocol,
> -                                &to, port,
> -                                &cp->vaddr, htons(ntohs(cp->vport)-1));
> -       if (!n_cp) {
> -               n_cp = ip_vs_conn_new(AF_INET, IPPROTO_TCP,
> -                                     &to, port,
> +       {
> +               struct ip_vs_conn_param p;
> +               ip_vs_conn_fill_param(AF_INET, iph->protocol, &to, port,
>                                       &cp->vaddr, htons(ntohs(cp->vport)-1),
> -                                     &cp->daddr, htons(ntohs(cp->dport)-1),
> -                                     IP_VS_CONN_F_NFCT,
> -                                     cp->dest);
> -               if (!n_cp)
> -                       return 0;
> +                                     &p);
> +               n_cp = ip_vs_conn_in_get(&p);
> +               if (!n_cp) {
> +                       n_cp = ip_vs_conn_new(&p, &cp->daddr,
> +                                             htons(ntohs(cp->dport)-1),
> +                                             IP_VS_CONN_F_NFCT, cp->dest);
> +                       if (!n_cp)
> +                               return 0;
>
> -               /* add its controller */
> -               ip_vs_control_add(n_cp, cp);
> +                       /* add its controller */
> +                       ip_vs_control_add(n_cp, cp);
> +               }
>         }
>
>         /*
> Index: lvs-test-2.6/net/netfilter/ipvs/ip_vs_nfct.c
> ===================================================================
> --- lvs-test-2.6.orig/net/netfilter/ipvs/ip_vs_nfct.c   2010-10-04 16:58:31.000000000 +0900
> +++ lvs-test-2.6/net/netfilter/ipvs/ip_vs_nfct.c        2010-10-04 17:00:45.000000000 +0900
> @@ -140,6 +140,7 @@ static void ip_vs_nfct_expect_callback(s
>  {
>         struct nf_conntrack_tuple *orig, new_reply;
>         struct ip_vs_conn *cp;
> +       struct ip_vs_conn_param p;
>
>         if (exp->tuple.src.l3num != PF_INET)
>                 return;
> @@ -154,9 +155,10 @@ static void ip_vs_nfct_expect_callback(s
>
>         /* RS->CLIENT */
>         orig = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
> -       cp = ip_vs_conn_out_get(exp->tuple.src.l3num, orig->dst.protonum,
> -                               &orig->src.u3, orig->src.u.tcp.port,
> -                               &orig->dst.u3, orig->dst.u.tcp.port);
> +       ip_vs_conn_fill_param(exp->tuple.src.l3num, orig->dst.protonum,
> +                             &orig->src.u3, orig->src.u.tcp.port,
> +                             &orig->dst.u3, orig->dst.u.tcp.port, &p);
> +       cp = ip_vs_conn_out_get(&p);
>         if (cp) {
>                 /* Change reply CLIENT->RS to CLIENT->VS */
>                 new_reply = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
> @@ -176,9 +178,7 @@ static void ip_vs_nfct_expect_callback(s
>         }
>
>         /* CLIENT->VS */
> -       cp = ip_vs_conn_in_get(exp->tuple.src.l3num, orig->dst.protonum,
> -                              &orig->src.u3, orig->src.u.tcp.port,
> -                              &orig->dst.u3, orig->dst.u.tcp.port);
> +       cp = ip_vs_conn_in_get(&p);
>         if (cp) {
>                 /* Change reply VS->CLIENT to RS->CLIENT */
>                 new_reply = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
> Index: lvs-test-2.6/net/netfilter/ipvs/ip_vs_proto_ah_esp.c
> ===================================================================
> --- lvs-test-2.6.orig/net/netfilter/ipvs/ip_vs_proto_ah_esp.c   2010-10-04 16:58:31.000000000 +0900
> +++ lvs-test-2.6/net/netfilter/ipvs/ip_vs_proto_ah_esp.c        2010-10-04 17:00:45.000000000 +0900
> @@ -40,6 +40,19 @@ struct isakmp_hdr {
>
>  #define PORT_ISAKMP    500
>
> +static void
> +ah_esp_conn_fill_param_proto(int af, const struct ip_vs_iphdr *iph,
> +                            int inverse, struct ip_vs_conn_param *p)
> +{
> +       if (likely(!inverse))
> +               ip_vs_conn_fill_param(af, IPPROTO_UDP,
> +                                     &iph->saddr, htons(PORT_ISAKMP),
> +                                     &iph->daddr, htons(PORT_ISAKMP), p);
> +       else
> +               ip_vs_conn_fill_param(af, IPPROTO_UDP,
> +                                     &iph->daddr, htons(PORT_ISAKMP),
> +                                     &iph->saddr, htons(PORT_ISAKMP), p);
> +}
>
>  static struct ip_vs_conn *
>  ah_esp_conn_in_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
> @@ -47,21 +60,10 @@ ah_esp_conn_in_get(int af, const struct
>                    int inverse)
>  {
>         struct ip_vs_conn *cp;
> +       struct ip_vs_conn_param p;
>
> -       if (likely(!inverse)) {
> -               cp = ip_vs_conn_in_get(af, IPPROTO_UDP,
> -                                      &iph->saddr,
> -                                      htons(PORT_ISAKMP),
> -                                      &iph->daddr,
> -                                      htons(PORT_ISAKMP));
> -       } else {
> -               cp = ip_vs_conn_in_get(af, IPPROTO_UDP,
> -                                      &iph->daddr,
> -                                      htons(PORT_ISAKMP),
> -                                      &iph->saddr,
> -                                      htons(PORT_ISAKMP));
> -       }
> -
> +       ah_esp_conn_fill_param_proto(af, iph, inverse, &p);
> +       cp = ip_vs_conn_in_get(&p);
>         if (!cp) {
>                 /*
>                  * We are not sure if the packet is from our
> @@ -87,21 +89,10 @@ ah_esp_conn_out_get(int af, const struct
>                     int inverse)
>  {
>         struct ip_vs_conn *cp;
> +       struct ip_vs_conn_param p;
>
> -       if (likely(!inverse)) {
> -               cp = ip_vs_conn_out_get(af, IPPROTO_UDP,
> -                                       &iph->saddr,
> -                                       htons(PORT_ISAKMP),
> -                                       &iph->daddr,
> -                                       htons(PORT_ISAKMP));
> -       } else {
> -               cp = ip_vs_conn_out_get(af, IPPROTO_UDP,
> -                                       &iph->daddr,
> -                                       htons(PORT_ISAKMP),
> -                                       &iph->saddr,
> -                                       htons(PORT_ISAKMP));
> -       }
> -
> +       ah_esp_conn_fill_param_proto(af, iph, inverse, &p);
> +       cp = ip_vs_conn_out_get(&p);
>         if (!cp) {
>                 IP_VS_DBG_BUF(12, "Unknown ISAKMP entry for inout packet "
>                               "%s%s %s->%s\n",
> Index: lvs-test-2.6/net/netfilter/ipvs/ip_vs_sync.c
> ===================================================================
> --- lvs-test-2.6.orig/net/netfilter/ipvs/ip_vs_sync.c   2010-10-04 16:58:31.000000000 +0900
> +++ lvs-test-2.6/net/netfilter/ipvs/ip_vs_sync.c        2010-10-04 17:49:20.000000000 +0900
> @@ -301,6 +301,7 @@ static void ip_vs_process_message(const
>         struct ip_vs_conn *cp;
>         struct ip_vs_protocol *pp;
>         struct ip_vs_dest *dest;
> +       struct ip_vs_conn_param param;
>         char *p;
>         int i;
>
> @@ -370,18 +371,17 @@ static void ip_vs_process_message(const
>                         }
>                 }
>
> -               if (!(flags & IP_VS_CONN_F_TEMPLATE))
> -                       cp = ip_vs_conn_in_get(AF_INET, s->protocol,
> -                                              (union nf_inet_addr *)&s->caddr,
> -                                              s->cport,
> -                                              (union nf_inet_addr *)&s->vaddr,
> -                                              s->vport);
> -               else
> -                       cp = ip_vs_ct_in_get(AF_INET, s->protocol,
> -                                            (union nf_inet_addr *)&s->caddr,
> -                                            s->cport,
> -                                            (union nf_inet_addr *)&s->vaddr,
> -                                            s->vport);
> +               {
> +                       ip_vs_conn_fill_param(AF_INET, s->protocol,
> +                                             (union nf_inet_addr *)&s->caddr,
> +                                             s->cport,
> +                                             (union nf_inet_addr *)&s->vaddr,
> +                                             s->vport, &param);
> +                       if (!(flags & IP_VS_CONN_F_TEMPLATE))
> +                               cp = ip_vs_conn_in_get(&param);
> +                       else
> +                               cp = ip_vs_ct_in_get(&param);
> +               }
>                 if (!cp) {
>                         /*
>                          * Find the appropriate destination for the connection.
> @@ -406,14 +406,9 @@ static void ip_vs_process_message(const
>                                 else
>                                         flags &= ~IP_VS_CONN_F_INACTIVE;
>                         }
> -                       cp = ip_vs_conn_new(AF_INET, s->protocol,
> -                                           (union nf_inet_addr *)&s->caddr,
> -                                           s->cport,
> -                                           (union nf_inet_addr *)&s->vaddr,
> -                                           s->vport,
> +                       cp = ip_vs_conn_new(&param,
>                                             (union nf_inet_addr *)&s->daddr,
> -                                           s->dport,
> -                                           flags, dest);
> +                                           s->dport, flags, dest);
>                         if (dest)
>                                 atomic_dec(&dest->refcnt);
>                         if (!cp) {
>
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

Patch applied for patch :-)

iff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 52fbe23..7646ff7 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -670,9 +670,19 @@ static inline void ip_vs_conn_fill_param(int af, int protocol,
 {
 	p->af = af;
 	p->protocol = protocol;
-	p->caddr = caddr;
 	p->cport = cport;
-	p->vaddr = vaddr;
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6) {
+		ipv6_addr_copy(&p->caddr, caddr);
+		ipv6_addr_copy(&p->caddr, caddr);
+	}
+	else
+#else
+	}
+		p->caddr = caddr;
+		p->vaddr = vaddr;
+	}
+#endif
 	p->vport = vport;
 	p->pe = NULL;
 	p->pe_data = NULL;


--
Regards
Hans Schillstrom <hans.schillstrom@ericsson.com>

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [patch v5 04/12] IPVS: Add struct ip_vs_conn_param, IPv6 forgotten No
  2010-10-19  9:41   ` [patch v5 04/12] IPVS: Add struct ip_vs_conn_param, IPv6 forgotten ? Hans Schillstrom
@ 2010-10-19  9:56     ` Hans Schillstrom
  2010-10-19 10:03       ` Simon Horman
  0 siblings, 1 reply; 18+ messages in thread
From: Hans Schillstrom @ 2010-10-19  9:56 UTC (permalink / raw)
  To: Simon Horman
  Cc: lvs-devel@vger.kernel.org, netdev@vger.kernel.org,
	netfilter@vger.kernel.org, netfilter-devel@vger.kernel.org,
	Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
	Julian Anastasov, Patrick McHardy

Hi Simon
I'm sorry it's not a bug it works perfectly OK.
(I didn't see that it was a pointer, It was another bug in my test code...)
so forget about the last mail

On Tuesday 19 October 2010 11:41:21 Hans Schillstrom wrote:
> Hi Simon,
> There is a show stopper for IPv6 in this patch.
> ip_vs_conn_fill_param() doesn't handle IPv6.
>
> On Monday 04 October 2010 15:46:28 Simon Horman wrote:
> > Signed-off-by: Simon Horman <horms@verge.net.au>
> > Acked-by: Julian Anastasov <ja@ssi.bg>
> >
> > ---
> >
> > The motivation for this is to allow persistence engine modules to
> > fill in the parameters.


--
Regards
Hans Schillstrom <hans.schillstrom@ericsson.com>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [patch v5 04/12] IPVS: Add struct ip_vs_conn_param, IPv6 forgotten No
  2010-10-19  9:56     ` [patch v5 04/12] IPVS: Add struct ip_vs_conn_param, IPv6 forgotten No Hans Schillstrom
@ 2010-10-19 10:03       ` Simon Horman
  0 siblings, 0 replies; 18+ messages in thread
From: Simon Horman @ 2010-10-19 10:03 UTC (permalink / raw)
  To: Hans Schillstrom
  Cc: lvs-devel@vger.kernel.org, netdev@vger.kernel.org,
	netfilter@vger.kernel.org, netfilter-devel@vger.kernel.org,
	Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
	Julian Anastasov, Patrick McHardy

On Tue, Oct 19, 2010 at 11:56:43AM +0200, Hans Schillstrom wrote:
> Hi Simon
> I'm sorry it's not a bug it works perfectly OK.
> (I didn't see that it was a pointer, It was another bug in my test code...)
> so forget about the last mail

No problem, thanks for looking over things :-)


^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2010-10-19 10:03 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-10-04 13:46 [patch v5 00/12] IPVS: SIP Persistence Engine Simon Horman
2010-10-04 13:46 ` [patch v5 01/12] netfilter: nf_conntrack_sip: Allow ct_sip_get_header() to be called with a null ct argument Simon Horman
2010-10-04 13:46 ` [patch v5 02/12] netfilter: nf_conntrack_sip: Add callid parser Simon Horman
2010-10-04 13:46 ` [patch v5 03/12] IPVS: compact ip_vs_sched_persist() Simon Horman
2010-10-04 13:46 ` [patch v5 04/12] IPVS: Add struct ip_vs_conn_param Simon Horman
2010-10-19  9:41   ` [patch v5 04/12] IPVS: Add struct ip_vs_conn_param, IPv6 forgotten ? Hans Schillstrom
2010-10-19  9:56     ` [patch v5 04/12] IPVS: Add struct ip_vs_conn_param, IPv6 forgotten No Hans Schillstrom
2010-10-19 10:03       ` Simon Horman
2010-10-04 13:46 ` [patch v5 05/12] IPVS: Allow null argument to ip_vs_scheduler_put() Simon Horman
2010-10-04 13:46 ` [patch v5 06/12] IPVS: ip_vs_{un,}bind_scheduler NULL arguments Simon Horman
2010-10-04 13:46 ` [patch v5 07/12] IPVS: Add struct ip_vs_pe Simon Horman
2010-10-04 13:46 ` [patch v5 08/12] IPVS: Add persistence engine data to /proc/net/ip_vs_conn Simon Horman
2010-10-04 13:46 ` [patch v5 09/12] IPVS: management of persistence engine modules Simon Horman
2010-10-04 13:46 ` [patch v5 10/12] IPVS: Allow configuration of persistence engines Simon Horman
2010-10-04 13:46 ` [patch v5 11/12] IPVS: Fallback if persistence engine fails Simon Horman
2010-10-04 13:46 ` [patch v5 12/12] IPVS: sip persistence engine Simon Horman
2010-10-04 18:47 ` [patch v5 00/12] IPVS: SIP Persistence Engine Patrick McHardy
2010-10-05 10:00   ` Simon Horman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).