Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f11017ec authored by Simon Horman's avatar Simon Horman
Browse files

IPVS: Add struct ip_vs_conn_param

parent 5b57a98c
Loading
Loading
Loading
Loading
+30 −14
Original line number Diff line number Diff line
@@ -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);
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;
}

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);
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_proto(int af, const struct sk_buff *skb,
					    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,10 +675,9 @@ static inline void __ip_vs_conn_put(struct ip_vs_conn *cp)
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_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);

+84 −87
Original line number Diff line number Diff line
@@ -218,27 +218,26 @@ static inline int ip_vs_conn_unhash(struct ip_vs_conn *cp)
/*
 *  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_conn_in_get
	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;
}

struct ip_vs_conn *
ip_vs_conn_in_get_proto(int af, const struct sk_buff *skb,
			struct ip_vs_protocol *pp,
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)
			    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 NULL;
		return 1;

	if (likely(!inverse))
		return ip_vs_conn_in_get(af, iph->protocol,
					 &iph->saddr, pptr[0],
					 &iph->daddr, pptr[1]);
		ip_vs_conn_fill_param(af, iph->protocol, &iph->saddr, pptr[0],
				      &iph->daddr, pptr[1], p);
	else
		return ip_vs_conn_in_get(af, iph->protocol,
					 &iph->daddr, pptr[1],
					 &iph->saddr, pptr[0]);
		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)
{
	struct ip_vs_conn_param p;

	if (ip_vs_conn_fill_param_proto(af, skb, iph, proto_off, inverse, &p))
		return NULL;

	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.
/* 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)
 *	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 struct sk_buff *skb,
			 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_conn *cp)
 *	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 union nf_inet_addr *caddr, __be16 cport,

	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 union nf_inet_addr *caddr, __be16 cport,

	/* 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
+34 −30
Original line number Diff line number Diff line
@@ -193,14 +193,11 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
	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 *svc,
	 * 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 *svc,
				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 *svc,
			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 *svc,
	/*
	 *    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, const struct sk_buff *skb)
	/*
	 *    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)
	{
		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 *svc, struct sk_buff *skb,

		/* 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,
		{
			struct ip_vs_conn_param p;
			ip_vs_conn_fill_param(svc->af, iph.protocol,
					      &iph.saddr, pptr[0],
				    &iph.daddr, pptr[1],
				    &daddr, 0,
					      &iph.daddr, pptr[1], &p);
			cp = ip_vs_conn_new(&p, &daddr, 0,
					    IP_VS_CONN_F_BYPASS | flags,
					    NULL);
		if (cp == NULL)
			if (!cp)
				return NF_DROP;
		}

		/* statistics */
		ip_vs_in_stats(cp, skb);
+24 −19
Original line number Diff line number Diff line
@@ -195,13 +195,17 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
		/*
		 * 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,22 +351,23 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp,
		  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);
				      &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);
		}
	}

	/*
	 *	Move tunnel to listen state
+6 −6
Original line number Diff line number Diff line
@@ -140,6 +140,7 @@ static void ip_vs_nfct_expect_callback(struct nf_conn *ct,
{
	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(struct nf_conn *ct,

	/* RS->CLIENT */
	orig = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
	cp = ip_vs_conn_out_get(exp->tuple.src.l3num, orig->dst.protonum,
	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);
			      &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(struct nf_conn *ct,
	}

	/* 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;
Loading