Commit f73181c8 authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso

ipvs: add support for sync threads

	Allow master and backup servers to use many threads
for sync traffic. Add sysctl var "sync_ports" to define the
number of threads. Every thread will use single UDP port,
thread 0 will use the default port 8848 while last thread
will use port 8848+sync_ports-1.

	The sync traffic for connections is scheduled to many
master threads based on the cp address but one connection is
always assigned to same thread to avoid reordering of the
sync messages.

	Remove ip_vs_sync_switch_mode because this check
for sync mode change is still risky. Instead, check for mode
change under sync_buff_lock.

	Make sure the backup socks do not block on reading.

Special thanks to Aleksey Chudov for helping in all tests.
Signed-off-by: default avatarJulian Anastasov <ja@ssi.bg>
Tested-by: default avatarAleksey Chudov <aleksey.chudov@gmail.com>
Signed-off-by: default avatarSimon Horman <horms@verge.net.au>
parent 749c42b6
...@@ -784,6 +784,16 @@ struct ip_vs_app { ...@@ -784,6 +784,16 @@ struct ip_vs_app {
void (*timeout_change)(struct ip_vs_app *app, int flags); void (*timeout_change)(struct ip_vs_app *app, int flags);
}; };
struct ipvs_master_sync_state {
struct list_head sync_queue;
struct ip_vs_sync_buff *sync_buff;
int sync_queue_len;
unsigned int sync_queue_delay;
struct task_struct *master_thread;
struct delayed_work master_wakeup_work;
struct netns_ipvs *ipvs;
};
/* IPVS in network namespace */ /* IPVS in network namespace */
struct netns_ipvs { struct netns_ipvs {
int gen; /* Generation */ int gen; /* Generation */
...@@ -870,6 +880,7 @@ struct netns_ipvs { ...@@ -870,6 +880,7 @@ struct netns_ipvs {
#endif #endif
int sysctl_snat_reroute; int sysctl_snat_reroute;
int sysctl_sync_ver; int sysctl_sync_ver;
int sysctl_sync_ports;
int sysctl_sync_qlen_max; int sysctl_sync_qlen_max;
int sysctl_sync_sock_size; int sysctl_sync_sock_size;
int sysctl_cache_bypass; int sysctl_cache_bypass;
...@@ -893,16 +904,11 @@ struct netns_ipvs { ...@@ -893,16 +904,11 @@ struct netns_ipvs {
spinlock_t est_lock; spinlock_t est_lock;
struct timer_list est_timer; /* Estimation timer */ struct timer_list est_timer; /* Estimation timer */
/* ip_vs_sync */ /* ip_vs_sync */
struct list_head sync_queue;
int sync_queue_len;
unsigned int sync_queue_delay;
struct delayed_work master_wakeup_work;
spinlock_t sync_lock; spinlock_t sync_lock;
struct ip_vs_sync_buff *sync_buff; struct ipvs_master_sync_state *ms;
spinlock_t sync_buff_lock; spinlock_t sync_buff_lock;
struct sockaddr_in sync_mcast_addr; struct task_struct **backup_threads;
struct task_struct *master_thread; int threads_mask;
struct task_struct *backup_thread;
int send_mesg_maxlen; int send_mesg_maxlen;
int recv_mesg_maxlen; int recv_mesg_maxlen;
volatile int sync_state; volatile int sync_state;
...@@ -926,6 +932,7 @@ struct netns_ipvs { ...@@ -926,6 +932,7 @@ struct netns_ipvs {
#define IPVS_SYNC_SEND_DELAY (HZ / 50) #define IPVS_SYNC_SEND_DELAY (HZ / 50)
#define IPVS_SYNC_CHECK_PERIOD HZ #define IPVS_SYNC_CHECK_PERIOD HZ
#define IPVS_SYNC_FLUSH_TIME (HZ * 2) #define IPVS_SYNC_FLUSH_TIME (HZ * 2)
#define IPVS_SYNC_PORTS_MAX (1 << 6)
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
...@@ -954,6 +961,11 @@ static inline int sysctl_sync_ver(struct netns_ipvs *ipvs) ...@@ -954,6 +961,11 @@ static inline int sysctl_sync_ver(struct netns_ipvs *ipvs)
return ipvs->sysctl_sync_ver; return ipvs->sysctl_sync_ver;
} }
static inline int sysctl_sync_ports(struct netns_ipvs *ipvs)
{
return ACCESS_ONCE(ipvs->sysctl_sync_ports);
}
static inline int sysctl_sync_qlen_max(struct netns_ipvs *ipvs) static inline int sysctl_sync_qlen_max(struct netns_ipvs *ipvs)
{ {
return ipvs->sysctl_sync_qlen_max; return ipvs->sysctl_sync_qlen_max;
...@@ -991,6 +1003,11 @@ static inline int sysctl_sync_ver(struct netns_ipvs *ipvs) ...@@ -991,6 +1003,11 @@ static inline int sysctl_sync_ver(struct netns_ipvs *ipvs)
return DEFAULT_SYNC_VER; return DEFAULT_SYNC_VER;
} }
static inline int sysctl_sync_ports(struct netns_ipvs *ipvs)
{
return 1;
}
static inline int sysctl_sync_qlen_max(struct netns_ipvs *ipvs) static inline int sysctl_sync_qlen_max(struct netns_ipvs *ipvs)
{ {
return IPVS_SYNC_QLEN_MAX; return IPVS_SYNC_QLEN_MAX;
...@@ -1240,7 +1257,6 @@ extern void ip_vs_scheduler_err(struct ip_vs_service *svc, const char *msg); ...@@ -1240,7 +1257,6 @@ extern void ip_vs_scheduler_err(struct ip_vs_service *svc, const char *msg);
extern struct ip_vs_stats ip_vs_stats; extern struct ip_vs_stats ip_vs_stats;
extern int sysctl_ip_vs_sync_ver; extern int sysctl_ip_vs_sync_ver;
extern void ip_vs_sync_switch_mode(struct net *net, int mode);
extern struct ip_vs_service * extern struct ip_vs_service *
ip_vs_service_get(struct net *net, int af, __u32 fwmark, __u16 protocol, ip_vs_service_get(struct net *net, int af, __u32 fwmark, __u16 protocol,
const union nf_inet_addr *vaddr, __be16 vport); const union nf_inet_addr *vaddr, __be16 vport);
......
...@@ -619,12 +619,19 @@ struct ip_vs_dest *ip_vs_try_bind_dest(struct ip_vs_conn *cp) ...@@ -619,12 +619,19 @@ struct ip_vs_dest *ip_vs_try_bind_dest(struct ip_vs_conn *cp)
if (dest) { if (dest) {
struct ip_vs_proto_data *pd; struct ip_vs_proto_data *pd;
spin_lock(&cp->lock);
if (cp->dest) {
spin_unlock(&cp->lock);
return dest;
}
/* Applications work depending on the forwarding method /* Applications work depending on the forwarding method
* but better to reassign them always when binding dest */ * but better to reassign them always when binding dest */
if (cp->app) if (cp->app)
ip_vs_unbind_app(cp); ip_vs_unbind_app(cp);
ip_vs_bind_dest(cp, dest); ip_vs_bind_dest(cp, dest);
spin_unlock(&cp->lock);
/* Update its packet transmitter */ /* Update its packet transmitter */
cp->packet_xmit = NULL; cp->packet_xmit = NULL;
......
...@@ -1657,9 +1657,24 @@ proc_do_sync_mode(ctl_table *table, int write, ...@@ -1657,9 +1657,24 @@ proc_do_sync_mode(ctl_table *table, int write,
if ((*valp < 0) || (*valp > 1)) { if ((*valp < 0) || (*valp > 1)) {
/* Restore the correct value */ /* Restore the correct value */
*valp = val; *valp = val;
} else { }
struct net *net = current->nsproxy->net_ns; }
ip_vs_sync_switch_mode(net, val); return rc;
}
static int
proc_do_sync_ports(ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
int *valp = table->data;
int val = *valp;
int rc;
rc = proc_dointvec(table, write, buffer, lenp, ppos);
if (write && (*valp != val)) {
if (*valp < 1 || !is_power_of_2(*valp)) {
/* Restore the correct value */
*valp = val;
} }
} }
return rc; return rc;
...@@ -1722,6 +1737,12 @@ static struct ctl_table vs_vars[] = { ...@@ -1722,6 +1737,12 @@ static struct ctl_table vs_vars[] = {
.mode = 0644, .mode = 0644,
.proc_handler = &proc_do_sync_mode, .proc_handler = &proc_do_sync_mode,
}, },
{
.procname = "sync_ports",
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_do_sync_ports,
},
{ {
.procname = "sync_qlen_max", .procname = "sync_qlen_max",
.maxlen = sizeof(int), .maxlen = sizeof(int),
...@@ -3686,6 +3707,8 @@ int __net_init ip_vs_control_net_init_sysctl(struct net *net) ...@@ -3686,6 +3707,8 @@ int __net_init ip_vs_control_net_init_sysctl(struct net *net)
tbl[idx++].data = &ipvs->sysctl_snat_reroute; tbl[idx++].data = &ipvs->sysctl_snat_reroute;
ipvs->sysctl_sync_ver = 1; ipvs->sysctl_sync_ver = 1;
tbl[idx++].data = &ipvs->sysctl_sync_ver; tbl[idx++].data = &ipvs->sysctl_sync_ver;
ipvs->sysctl_sync_ports = 1;
tbl[idx++].data = &ipvs->sysctl_sync_ports;
ipvs->sysctl_sync_qlen_max = nr_free_buffer_pages() / 32; ipvs->sysctl_sync_qlen_max = nr_free_buffer_pages() / 32;
tbl[idx++].data = &ipvs->sysctl_sync_qlen_max; tbl[idx++].data = &ipvs->sysctl_sync_qlen_max;
ipvs->sysctl_sync_sock_size = 0; ipvs->sysctl_sync_sock_size = 0;
......
This diff is collapsed.
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