Commit 85999283 authored by Simon Horman's avatar Simon Horman

IPVS: Add struct ip_vs_pe

Signed-off-by: default avatarSimon Horman <horms@verge.net.au>
Acked-by: default avatarJulian Anastasov <ja@ssi.bg>
parent 2fabf35b
...@@ -99,8 +99,10 @@ ...@@ -99,8 +99,10 @@
0) 0)
#define IP_VS_SCHEDNAME_MAXLEN 16 #define IP_VS_SCHEDNAME_MAXLEN 16
#define IP_VS_PENAME_MAXLEN 16
#define IP_VS_IFNAME_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 * The struct ip_vs_service_user and struct ip_vs_dest_user are
......
...@@ -364,6 +364,10 @@ struct ip_vs_conn_param { ...@@ -364,6 +364,10 @@ struct ip_vs_conn_param {
__be16 vport; __be16 vport;
__u16 protocol; __u16 protocol;
u16 af; u16 af;
const struct ip_vs_pe *pe;
char *pe_data;
__u8 pe_data_len;
}; };
/* /*
...@@ -416,6 +420,9 @@ struct ip_vs_conn { ...@@ -416,6 +420,9 @@ struct ip_vs_conn {
void *app_data; /* Application private data */ void *app_data; /* Application private data */
struct ip_vs_seq in_seq; /* incoming seq. struct */ struct ip_vs_seq in_seq; /* incoming seq. struct */
struct ip_vs_seq out_seq; /* outgoing 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 { ...@@ -486,6 +493,9 @@ struct ip_vs_service {
struct ip_vs_scheduler *scheduler; /* bound scheduler object */ struct ip_vs_scheduler *scheduler; /* bound scheduler object */
rwlock_t sched_lock; /* lock sched_data */ rwlock_t sched_lock; /* lock sched_data */
void *sched_data; /* scheduler application data */ void *sched_data; /* scheduler application data */
/* alternate persistence engine */
struct ip_vs_pe *pe;
}; };
...@@ -549,6 +559,20 @@ struct ip_vs_scheduler { ...@@ -549,6 +559,20 @@ struct ip_vs_scheduler {
const struct sk_buff *skb); 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) * The application module object (a.k.a. app incarnation)
...@@ -648,6 +672,8 @@ static inline void ip_vs_conn_fill_param(int af, int protocol, ...@@ -648,6 +672,8 @@ static inline void ip_vs_conn_fill_param(int af, int protocol,
p->cport = cport; p->cport = cport;
p->vaddr = vaddr; p->vaddr = vaddr;
p->vport = vport; 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); 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 ip_vs_service *svc); ...@@ -803,7 +829,7 @@ extern int ip_vs_unbind_scheduler(struct ip_vs_service *svc);
extern struct ip_vs_scheduler *ip_vs_scheduler_get(const char *sched_name); 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 void ip_vs_scheduler_put(struct ip_vs_scheduler *scheduler);
extern struct ip_vs_conn * 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, extern int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
struct ip_vs_protocol *pp); struct ip_vs_protocol *pp);
......
...@@ -148,6 +148,42 @@ static unsigned int ip_vs_conn_hashkey(int af, unsigned proto, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) { p->protocol == cp->protocol)
/* HIT */
atomic_inc(&cp->refcnt);
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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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
*/ */
......
...@@ -176,6 +176,19 @@ ip_vs_set_state(struct ip_vs_conn *cp, int direction, ...@@ -176,6 +176,19 @@ ip_vs_set_state(struct ip_vs_conn *cp, int direction,
return pp->state_transition(cp, direction, skb, pp); 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 * IPVS persistent scheduling function
...@@ -186,7 +199,7 @@ ip_vs_set_state(struct ip_vs_conn *cp, int direction, ...@@ -186,7 +199,7 @@ ip_vs_set_state(struct ip_vs_conn *cp, int direction,
*/ */
static struct ip_vs_conn * static struct ip_vs_conn *
ip_vs_sched_persist(struct ip_vs_service *svc, ip_vs_sched_persist(struct ip_vs_service *svc,
const struct sk_buff *skb, struct sk_buff *skb,
__be16 ports[2]) __be16 ports[2])
{ {
struct ip_vs_conn *cp = NULL; struct ip_vs_conn *cp = NULL;
...@@ -255,8 +268,9 @@ ip_vs_sched_persist(struct ip_vs_service *svc, ...@@ -255,8 +268,9 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
vaddr = &fwmark; vaddr = &fwmark;
} }
} }
ip_vs_conn_fill_param(svc->af, protocol, &snet, 0, if (ip_vs_conn_fill_param_persist(svc, skb, protocol, &snet, 0,
vaddr, vport, &param); vaddr, vport, &param))
return NULL;
} }
/* Check if a template already exists */ /* Check if a template already exists */
...@@ -268,22 +282,30 @@ ip_vs_sched_persist(struct ip_vs_service *svc, ...@@ -268,22 +282,30 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
dest = svc->scheduler->schedule(svc, skb); dest = svc->scheduler->schedule(svc, skb);
if (!dest) { if (!dest) {
IP_VS_DBG(1, "p-schedule: no dest found.\n"); IP_VS_DBG(1, "p-schedule: no dest found.\n");
kfree(param.pe_data);
return NULL; return NULL;
} }
if (ports[1] == svc->port && svc->port != FTPPORT) if (ports[1] == svc->port && svc->port != FTPPORT)
dport = dest->port; 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, ct = ip_vs_conn_new(&param, &dest->addr, dport,
IP_VS_CONN_F_TEMPLATE, dest); IP_VS_CONN_F_TEMPLATE, dest);
if (ct == NULL) if (ct == NULL) {
kfree(param.pe_data);
return NULL; return NULL;
}
ct->timeout = svc->timeout; ct->timeout = svc->timeout;
} else } else {
/* set destination with the found template */ /* set destination with the found template */
dest = ct->dest; dest = ct->dest;
kfree(param.pe_data);
}
dport = ports[1]; dport = ports[1];
if (dport == svc->port && dest->port) if (dport == svc->port && dest->port)
...@@ -322,7 +344,7 @@ ip_vs_sched_persist(struct ip_vs_service *svc, ...@@ -322,7 +344,7 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
* Protocols supported: TCP, UDP * Protocols supported: TCP, UDP
*/ */
struct ip_vs_conn * 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_conn *cp = NULL;
struct ip_vs_iphdr iph; struct ip_vs_iphdr iph;
......
...@@ -288,6 +288,16 @@ void ip_vs_sync_conn(struct ip_vs_conn *cp) ...@@ -288,6 +288,16 @@ void ip_vs_sync_conn(struct ip_vs_conn *cp)
ip_vs_sync_conn(cp->control); 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 * Process received multicast message and create the corresponding
...@@ -372,11 +382,14 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen) ...@@ -372,11 +382,14 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
} }
{ {
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, (union nf_inet_addr *)&s->caddr,
s->cport, s->cport,
(union nf_inet_addr *)&s->vaddr, (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)) if (!(flags & IP_VS_CONN_F_TEMPLATE))
cp = ip_vs_conn_in_get(&param); cp = ip_vs_conn_in_get(&param);
else else
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment