|
@@ -148,6 +148,42 @@ static unsigned int ip_vs_conn_hashkey(int af, unsigned proto,
|
|
& ip_vs_conn_tab_mask;
|
|
& 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.
|
|
* 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 ip_vs_conn *cp)
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
/* Hash by protocol, client address and port */
|
|
/* 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);
|
|
ct_write_lock(hash);
|
|
spin_lock(&cp->lock);
|
|
spin_lock(&cp->lock);
|
|
@@ -195,7 +231,7 @@ static inline int ip_vs_conn_unhash(struct ip_vs_conn *cp)
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
/* unhash it and decrease its reference counter */
|
|
/* 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);
|
|
ct_write_lock(hash);
|
|
spin_lock(&cp->lock);
|
|
spin_lock(&cp->lock);
|
|
@@ -227,7 +263,7 @@ __ip_vs_conn_in_get(const struct ip_vs_conn_param *p)
|
|
unsigned hash;
|
|
unsigned hash;
|
|
struct ip_vs_conn *cp;
|
|
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);
|
|
ct_read_lock(hash);
|
|
|
|
|
|
@@ -312,11 +348,17 @@ struct ip_vs_conn *ip_vs_ct_in_get(const struct ip_vs_conn_param *p)
|
|
unsigned hash;
|
|
unsigned hash;
|
|
struct ip_vs_conn *cp;
|
|
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);
|
|
ct_read_lock(hash);
|
|
|
|
|
|
list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
|
|
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 &&
|
|
if (cp->af == p->af &&
|
|
ip_vs_addr_equal(p->af, p->caddr, &cp->caddr) &&
|
|
ip_vs_addr_equal(p->af, p->caddr, &cp->caddr) &&
|
|
/* protocol should only be IPPROTO_IP if
|
|
/* protocol should only be IPPROTO_IP if
|
|
@@ -325,15 +367,14 @@ struct ip_vs_conn *ip_vs_ct_in_get(const struct ip_vs_conn_param *p)
|
|
p->af, p->vaddr, &cp->vaddr) &&
|
|
p->af, p->vaddr, &cp->vaddr) &&
|
|
p->cport == cp->cport && p->vport == cp->vport &&
|
|
p->cport == cp->cport && p->vport == cp->vport &&
|
|
cp->flags & IP_VS_CONN_F_TEMPLATE &&
|
|
cp->flags & IP_VS_CONN_F_TEMPLATE &&
|
|
- p->protocol == cp->protocol) {
|
|
|
|
- /* HIT */
|
|
|
|
- atomic_inc(&cp->refcnt);
|
|
|
|
|
|
+ p->protocol == cp->protocol)
|
|
goto out;
|
|
goto out;
|
|
- }
|
|
|
|
}
|
|
}
|
|
cp = NULL;
|
|
cp = NULL;
|
|
|
|
|
|
out:
|
|
out:
|
|
|
|
+ if (cp)
|
|
|
|
+ atomic_inc(&cp->refcnt);
|
|
ct_read_unlock(hash);
|
|
ct_read_unlock(hash);
|
|
|
|
|
|
IP_VS_DBG_BUF(9, "template lookup/in %s %s:%d->%s:%d %s\n",
|
|
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(const struct ip_vs_conn_param *p)
|
|
/*
|
|
/*
|
|
* Check for "full" addressed entries
|
|
* 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);
|
|
ct_read_lock(hash);
|
|
|
|
|
|
@@ -722,6 +763,7 @@ static void ip_vs_conn_expire(unsigned long data)
|
|
if (cp->flags & IP_VS_CONN_F_NFCT)
|
|
if (cp->flags & IP_VS_CONN_F_NFCT)
|
|
ip_vs_conn_drop_conntrack(cp);
|
|
ip_vs_conn_drop_conntrack(cp);
|
|
|
|
|
|
|
|
+ kfree(cp->pe_data);
|
|
if (unlikely(cp->app != NULL))
|
|
if (unlikely(cp->app != NULL))
|
|
ip_vs_unbind_app(cp);
|
|
ip_vs_unbind_app(cp);
|
|
ip_vs_unbind_dest(cp);
|
|
ip_vs_unbind_dest(cp);
|
|
@@ -782,6 +824,10 @@ ip_vs_conn_new(const struct ip_vs_conn_param *p,
|
|
&cp->daddr, daddr);
|
|
&cp->daddr, daddr);
|
|
cp->dport = dport;
|
|
cp->dport = dport;
|
|
cp->flags = flags;
|
|
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);
|
|
spin_lock_init(&cp->lock);
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -832,7 +878,6 @@ ip_vs_conn_new(const struct ip_vs_conn_param *p,
|
|
return cp;
|
|
return cp;
|
|
}
|
|
}
|
|
|
|
|
|
-
|
|
|
|
/*
|
|
/*
|
|
* /proc/net/ip_vs_conn entries
|
|
* /proc/net/ip_vs_conn entries
|
|
*/
|
|
*/
|
|
@@ -848,7 +893,7 @@ static void *ip_vs_conn_array(struct seq_file *seq, loff_t pos)
|
|
list_for_each_entry(cp, &ip_vs_conn_tab[idx], c_list) {
|
|
list_for_each_entry(cp, &ip_vs_conn_tab[idx], c_list) {
|
|
if (pos-- == 0) {
|
|
if (pos-- == 0) {
|
|
seq->private = &ip_vs_conn_tab[idx];
|
|
seq->private = &ip_vs_conn_tab[idx];
|
|
- return cp;
|
|
|
|
|
|
+ return cp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ct_read_unlock_bh(idx);
|
|
ct_read_unlock_bh(idx);
|