static struct list_head *ip_vs_conn_tab;
/* SLAB cache for IPVS connections */
-static kmem_cache_t *ip_vs_conn_cachep;
+static kmem_cache_t *ip_vs_conn_cachep __read_mostly;
/* counter for current IPVS connections */
static atomic_t ip_vs_conn_count = ATOMIC_INIT(0);
list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
if (s_addr==cp->caddr && s_port==cp->cport &&
d_port==cp->vport && d_addr==cp->vaddr &&
+ ((!s_port) ^ (!(cp->flags & IP_VS_CONN_F_NO_CPORT))) &&
protocol==cp->protocol) {
/* HIT */
atomic_inc(&cp->refcnt);
return cp;
}
+/* Get reference to connection template */
+struct ip_vs_conn *ip_vs_ct_in_get
+(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
+{
+ unsigned hash;
+ struct ip_vs_conn *cp;
+
+ hash = ip_vs_conn_hashkey(protocol, s_addr, s_port);
+
+ ct_read_lock(hash);
+
+ list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
+ if (s_addr==cp->caddr && s_port==cp->cport &&
+ d_port==cp->vport && d_addr==cp->vaddr &&
+ cp->flags & IP_VS_CONN_F_TEMPLATE &&
+ protocol==cp->protocol) {
+ /* HIT */
+ atomic_inc(&cp->refcnt);
+ goto out;
+ }
+ }
+ cp = NULL;
+
+ out:
+ ct_read_unlock(hash);
+
+ IP_VS_DBG(7, "template lookup/in %s %u.%u.%u.%u:%d->%u.%u.%u.%u:%d %s\n",
+ ip_vs_proto_name(protocol),
+ NIPQUAD(s_addr), ntohs(s_port),
+ NIPQUAD(d_addr), ntohs(d_port),
+ cp?"hit":"not hit");
+
+ return cp;
+}
/*
* Gets ip_vs_conn associated with supplied parameters in the ip_vs_conn_tab.
atomic_read(&dest->refcnt));
/* Update the connection counters */
- if (cp->cport || (cp->flags & IP_VS_CONN_F_NO_CPORT)) {
+ if (!(cp->flags & IP_VS_CONN_F_TEMPLATE)) {
/* It is a normal connection, so increase the inactive
connection counter because it is in TCP SYNRECV
state (inactive) or other protocol inacive state */
atomic_read(&dest->refcnt));
/* Update the connection counters */
- if (cp->cport || (cp->flags & IP_VS_CONN_F_NO_CPORT)) {
+ if (!(cp->flags & IP_VS_CONN_F_TEMPLATE)) {
/* It is a normal connection, so decrease the inactconns
or activeconns counter */
if (cp->flags & IP_VS_CONN_F_INACTIVE) {
/*
* Invalidate the connection template
*/
- if (ct->cport) {
+ if (ct->vport != 65535) {
if (ip_vs_conn_unhash(ct)) {
ct->dport = 65535;
ct->vport = 65535;
{
if (del_timer(&cp->timer))
mod_timer(&cp->timer, jiffies);
- __ip_vs_conn_put(cp);
}
return 1;
}
-
+/* Called from keventd and must protect itself from softirqs */
void ip_vs_random_dropentry(void)
{
int idx;
struct ip_vs_conn *cp;
- struct ip_vs_conn *ct;
/*
* Randomly scan 1/32 of the whole table every second
/*
* Lock is actually needed in this loop.
*/
- ct_write_lock(hash);
+ ct_write_lock_bh(hash);
list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
- if (!cp->cport && !(cp->flags & IP_VS_CONN_F_NO_CPORT))
+ if (cp->flags & IP_VS_CONN_F_TEMPLATE)
/* connection template */
continue;
continue;
}
- /*
- * Drop the entry, and drop its ct if not referenced
- */
- atomic_inc(&cp->refcnt);
- ct_write_unlock(hash);
-
- if ((ct = cp->control))
- atomic_inc(&ct->refcnt);
IP_VS_DBG(4, "del connection\n");
ip_vs_conn_expire_now(cp);
- if (ct) {
+ if (cp->control) {
IP_VS_DBG(4, "del conn template\n");
- ip_vs_conn_expire_now(ct);
+ ip_vs_conn_expire_now(cp->control);
}
- ct_write_lock(hash);
}
- ct_write_unlock(hash);
+ ct_write_unlock_bh(hash);
}
}
{
int idx;
struct ip_vs_conn *cp;
- struct ip_vs_conn *ct;
flush_again:
for (idx=0; idx<IP_VS_CONN_TAB_SIZE; idx++) {
ct_write_lock_bh(idx);
list_for_each_entry(cp, &ip_vs_conn_tab[idx], c_list) {
- atomic_inc(&cp->refcnt);
- ct_write_unlock(idx);
- if ((ct = cp->control))
- atomic_inc(&ct->refcnt);
IP_VS_DBG(4, "del connection\n");
ip_vs_conn_expire_now(cp);
- if (ct) {
+ if (cp->control) {
IP_VS_DBG(4, "del conn template\n");
- ip_vs_conn_expire_now(ct);
+ ip_vs_conn_expire_now(cp->control);
}
- ct_write_lock(idx);
}
ct_write_unlock_bh(idx);
}