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

Commit 1b383bf9 authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso
Browse files


Simon Horman says:

====================
Second Round of IPVS Updates for v4.3

I realise these are a little late in the cycle, so if you would prefer
me to repost them for v4.4 then just let me know.

The updates include:
* A new scheduler from Raducu Deaconu
* Enhanced configurability of the sync daemon from Julian Anastasov
====================

Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parents 1afe839e d3328817
Loading
Loading
Loading
Loading
+15 −8
Original line number Diff line number Diff line
@@ -846,6 +846,17 @@ struct ipvs_master_sync_state {
/* How much time to keep dests in trash */
#define IP_VS_DEST_TRASH_PERIOD		(120 * HZ)

struct ipvs_sync_daemon_cfg {
	union nf_inet_addr	mcast_group;
	int			syncid;
	u16			sync_maxlen;
	u16			mcast_port;
	u8			mcast_af;
	u8			mcast_ttl;
	/* multicast interface name */
	char			mcast_ifn[IP_VS_IFNAME_MAXLEN];
};

/* IPVS in network namespace */
struct netns_ipvs {
	int			gen;		/* Generation */
@@ -961,15 +972,10 @@ struct netns_ipvs {
	spinlock_t		sync_buff_lock;
	struct task_struct	**backup_threads;
	int			threads_mask;
	int			send_mesg_maxlen;
	int			recv_mesg_maxlen;
	volatile int		sync_state;
	volatile int		master_syncid;
	volatile int		backup_syncid;
	struct mutex		sync_mutex;
	/* multicast interface name */
	char			master_mcast_ifn[IP_VS_IFNAME_MAXLEN];
	char			backup_mcast_ifn[IP_VS_IFNAME_MAXLEN];
	struct ipvs_sync_daemon_cfg	mcfg;	/* Master Configuration */
	struct ipvs_sync_daemon_cfg	bcfg;	/* Backup Configuration */
	/* net name space ptr */
	struct net		*net;            /* Needed by timer routines */
	/* Number of heterogeneous destinations, needed becaus heterogeneous
@@ -1408,7 +1414,8 @@ static inline void ip_vs_dest_put_and_free(struct ip_vs_dest *dest)
/* IPVS sync daemon data and function prototypes
 * (from ip_vs_sync.c)
 */
int start_sync_thread(struct net *net, int state, char *mcast_ifn, __u8 syncid);
int start_sync_thread(struct net *net, struct ipvs_sync_daemon_cfg *cfg,
		      int state);
int stop_sync_thread(struct net *net, int state);
void ip_vs_sync_conn(struct net *net, struct ip_vs_conn *cp, int pkts);

+5 −0
Original line number Diff line number Diff line
@@ -406,6 +406,11 @@ enum {
	IPVS_DAEMON_ATTR_STATE,		/* sync daemon state (master/backup) */
	IPVS_DAEMON_ATTR_MCAST_IFN,	/* multicast interface name */
	IPVS_DAEMON_ATTR_SYNC_ID,	/* SyncID we belong to */
	IPVS_DAEMON_ATTR_SYNC_MAXLEN,	/* UDP Payload Size */
	IPVS_DAEMON_ATTR_MCAST_GROUP,	/* IPv4 Multicast Address */
	IPVS_DAEMON_ATTR_MCAST_GROUP6,	/* IPv6 Multicast Address */
	IPVS_DAEMON_ATTR_MCAST_PORT,	/* Multicast Port (base) */
	IPVS_DAEMON_ATTR_MCAST_TTL,	/* Multicast TTL */
	__IPVS_DAEMON_ATTR_MAX,
};

+11 −0
Original line number Diff line number Diff line
@@ -162,6 +162,17 @@ config IP_VS_FO
	  If you want to compile it in kernel, say Y. To compile it as a
	  module, choose M here. If unsure, say N.

config  IP_VS_OVF
	tristate "weighted overflow scheduling"
	---help---
	  The weighted overflow scheduling algorithm directs network
	  connections to the server with the highest weight that is
	  currently available and overflows to the next when active
	  connections exceed the node's weight.

	  If you want to compile it in kernel, say Y. To compile it as a
	  module, choose M here. If unsure, say N.

config	IP_VS_LBLC
	tristate "locality-based least-connection scheduling"
	---help---
+1 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ obj-$(CONFIG_IP_VS_WRR) += ip_vs_wrr.o
obj-$(CONFIG_IP_VS_LC) += ip_vs_lc.o
obj-$(CONFIG_IP_VS_WLC) += ip_vs_wlc.o
obj-$(CONFIG_IP_VS_FO) += ip_vs_fo.o
obj-$(CONFIG_IP_VS_OVF) += ip_vs_ovf.o
obj-$(CONFIG_IP_VS_LBLC) += ip_vs_lblc.o
obj-$(CONFIG_IP_VS_LBLCR) += ip_vs_lblcr.o
obj-$(CONFIG_IP_VS_DH) += ip_vs_dh.o
+110 −33
Original line number Diff line number Diff line
@@ -2335,13 +2335,23 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
	    cmd == IP_VS_SO_SET_STOPDAEMON) {
		struct ip_vs_daemon_user *dm = (struct ip_vs_daemon_user *)arg;

		if (cmd == IP_VS_SO_SET_STARTDAEMON) {
			struct ipvs_sync_daemon_cfg cfg;

			memset(&cfg, 0, sizeof(cfg));
			strlcpy(cfg.mcast_ifn, dm->mcast_ifn,
				sizeof(cfg.mcast_ifn));
			cfg.syncid = dm->syncid;
			rtnl_lock();
			mutex_lock(&ipvs->sync_mutex);
			ret = start_sync_thread(net, &cfg, dm->state);
			mutex_unlock(&ipvs->sync_mutex);
			rtnl_unlock();
		} else {
			mutex_lock(&ipvs->sync_mutex);
		if (cmd == IP_VS_SO_SET_STARTDAEMON)
			ret = start_sync_thread(net, dm->state, dm->mcast_ifn,
						dm->syncid);
		else
			ret = stop_sync_thread(net, dm->state);
			mutex_unlock(&ipvs->sync_mutex);
		}
		goto out_dec;
	}

@@ -2645,15 +2655,15 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
		mutex_lock(&ipvs->sync_mutex);
		if (ipvs->sync_state & IP_VS_STATE_MASTER) {
			d[0].state = IP_VS_STATE_MASTER;
			strlcpy(d[0].mcast_ifn, ipvs->master_mcast_ifn,
			strlcpy(d[0].mcast_ifn, ipvs->mcfg.mcast_ifn,
				sizeof(d[0].mcast_ifn));
			d[0].syncid = ipvs->master_syncid;
			d[0].syncid = ipvs->mcfg.syncid;
		}
		if (ipvs->sync_state & IP_VS_STATE_BACKUP) {
			d[1].state = IP_VS_STATE_BACKUP;
			strlcpy(d[1].mcast_ifn, ipvs->backup_mcast_ifn,
			strlcpy(d[1].mcast_ifn, ipvs->bcfg.mcast_ifn,
				sizeof(d[1].mcast_ifn));
			d[1].syncid = ipvs->backup_syncid;
			d[1].syncid = ipvs->bcfg.syncid;
		}
		if (copy_to_user(user, &d, sizeof(d)) != 0)
			ret = -EFAULT;
@@ -2808,6 +2818,11 @@ static const struct nla_policy ip_vs_daemon_policy[IPVS_DAEMON_ATTR_MAX + 1] = {
	[IPVS_DAEMON_ATTR_MCAST_IFN]	= { .type = NLA_NUL_STRING,
					    .len = IP_VS_IFNAME_MAXLEN },
	[IPVS_DAEMON_ATTR_SYNC_ID]	= { .type = NLA_U32 },
	[IPVS_DAEMON_ATTR_SYNC_MAXLEN]	= { .type = NLA_U16 },
	[IPVS_DAEMON_ATTR_MCAST_GROUP]	= { .type = NLA_U32 },
	[IPVS_DAEMON_ATTR_MCAST_GROUP6]	= { .len = sizeof(struct in6_addr) },
	[IPVS_DAEMON_ATTR_MCAST_PORT]	= { .type = NLA_U16 },
	[IPVS_DAEMON_ATTR_MCAST_TTL]	= { .type = NLA_U8 },
};

/* Policy used for attributes in nested attribute IPVS_CMD_ATTR_SERVICE */
@@ -3266,7 +3281,7 @@ static int ip_vs_genl_parse_dest(struct ip_vs_dest_user_kern *udest,
}

static int ip_vs_genl_fill_daemon(struct sk_buff *skb, __u32 state,
				  const char *mcast_ifn, __u32 syncid)
				  struct ipvs_sync_daemon_cfg *c)
{
	struct nlattr *nl_daemon;

@@ -3275,8 +3290,22 @@ static int ip_vs_genl_fill_daemon(struct sk_buff *skb, __u32 state,
		return -EMSGSIZE;

	if (nla_put_u32(skb, IPVS_DAEMON_ATTR_STATE, state) ||
	    nla_put_string(skb, IPVS_DAEMON_ATTR_MCAST_IFN, mcast_ifn) ||
	    nla_put_u32(skb, IPVS_DAEMON_ATTR_SYNC_ID, syncid))
	    nla_put_string(skb, IPVS_DAEMON_ATTR_MCAST_IFN, c->mcast_ifn) ||
	    nla_put_u32(skb, IPVS_DAEMON_ATTR_SYNC_ID, c->syncid) ||
	    nla_put_u16(skb, IPVS_DAEMON_ATTR_SYNC_MAXLEN, c->sync_maxlen) ||
	    nla_put_u16(skb, IPVS_DAEMON_ATTR_MCAST_PORT, c->mcast_port) ||
	    nla_put_u8(skb, IPVS_DAEMON_ATTR_MCAST_TTL, c->mcast_ttl))
		goto nla_put_failure;
#ifdef CONFIG_IP_VS_IPV6
	if (c->mcast_af == AF_INET6) {
		if (nla_put_in6_addr(skb, IPVS_DAEMON_ATTR_MCAST_GROUP6,
				     &c->mcast_group.in6))
			goto nla_put_failure;
	} else
#endif
		if (c->mcast_af == AF_INET &&
		    nla_put_in_addr(skb, IPVS_DAEMON_ATTR_MCAST_GROUP,
				    c->mcast_group.ip))
			goto nla_put_failure;
	nla_nest_end(skb, nl_daemon);

@@ -3288,7 +3317,7 @@ nla_put_failure:
}

static int ip_vs_genl_dump_daemon(struct sk_buff *skb, __u32 state,
				  const char *mcast_ifn, __u32 syncid,
				  struct ipvs_sync_daemon_cfg *c,
				  struct netlink_callback *cb)
{
	void *hdr;
@@ -3298,7 +3327,7 @@ static int ip_vs_genl_dump_daemon(struct sk_buff *skb, __u32 state,
	if (!hdr)
		return -EMSGSIZE;

	if (ip_vs_genl_fill_daemon(skb, state, mcast_ifn, syncid))
	if (ip_vs_genl_fill_daemon(skb, state, c))
		goto nla_put_failure;

	genlmsg_end(skb, hdr);
@@ -3318,8 +3347,7 @@ static int ip_vs_genl_dump_daemons(struct sk_buff *skb,
	mutex_lock(&ipvs->sync_mutex);
	if ((ipvs->sync_state & IP_VS_STATE_MASTER) && !cb->args[0]) {
		if (ip_vs_genl_dump_daemon(skb, IP_VS_STATE_MASTER,
					   ipvs->master_mcast_ifn,
					   ipvs->master_syncid, cb) < 0)
					   &ipvs->mcfg, cb) < 0)
			goto nla_put_failure;

		cb->args[0] = 1;
@@ -3327,8 +3355,7 @@ static int ip_vs_genl_dump_daemons(struct sk_buff *skb,

	if ((ipvs->sync_state & IP_VS_STATE_BACKUP) && !cb->args[1]) {
		if (ip_vs_genl_dump_daemon(skb, IP_VS_STATE_BACKUP,
					   ipvs->backup_mcast_ifn,
					   ipvs->backup_syncid, cb) < 0)
					   &ipvs->bcfg, cb) < 0)
			goto nla_put_failure;

		cb->args[1] = 1;
@@ -3342,30 +3369,83 @@ nla_put_failure:

static int ip_vs_genl_new_daemon(struct net *net, struct nlattr **attrs)
{
	struct netns_ipvs *ipvs = net_ipvs(net);
	struct ipvs_sync_daemon_cfg c;
	struct nlattr *a;
	int ret;

	memset(&c, 0, sizeof(c));
	if (!(attrs[IPVS_DAEMON_ATTR_STATE] &&
	      attrs[IPVS_DAEMON_ATTR_MCAST_IFN] &&
	      attrs[IPVS_DAEMON_ATTR_SYNC_ID]))
		return -EINVAL;
	strlcpy(c.mcast_ifn, nla_data(attrs[IPVS_DAEMON_ATTR_MCAST_IFN]),
		sizeof(c.mcast_ifn));
	c.syncid = nla_get_u32(attrs[IPVS_DAEMON_ATTR_SYNC_ID]);

	a = attrs[IPVS_DAEMON_ATTR_SYNC_MAXLEN];
	if (a)
		c.sync_maxlen = nla_get_u16(a);

	a = attrs[IPVS_DAEMON_ATTR_MCAST_GROUP];
	if (a) {
		c.mcast_af = AF_INET;
		c.mcast_group.ip = nla_get_in_addr(a);
		if (!ipv4_is_multicast(c.mcast_group.ip))
			return -EINVAL;
	} else {
		a = attrs[IPVS_DAEMON_ATTR_MCAST_GROUP6];
		if (a) {
#ifdef CONFIG_IP_VS_IPV6
			int addr_type;

			c.mcast_af = AF_INET6;
			c.mcast_group.in6 = nla_get_in6_addr(a);
			addr_type = ipv6_addr_type(&c.mcast_group.in6);
			if (!(addr_type & IPV6_ADDR_MULTICAST))
				return -EINVAL;
#else
			return -EAFNOSUPPORT;
#endif
		}
	}

	a = attrs[IPVS_DAEMON_ATTR_MCAST_PORT];
	if (a)
		c.mcast_port = nla_get_u16(a);

	a = attrs[IPVS_DAEMON_ATTR_MCAST_TTL];
	if (a)
		c.mcast_ttl = nla_get_u8(a);

	/* The synchronization protocol is incompatible with mixed family
	 * services
	 */
	if (net_ipvs(net)->mixed_address_family_dests > 0)
	if (ipvs->mixed_address_family_dests > 0)
		return -EINVAL;

	return start_sync_thread(net,
				 nla_get_u32(attrs[IPVS_DAEMON_ATTR_STATE]),
				 nla_data(attrs[IPVS_DAEMON_ATTR_MCAST_IFN]),
				 nla_get_u32(attrs[IPVS_DAEMON_ATTR_SYNC_ID]));
	rtnl_lock();
	mutex_lock(&ipvs->sync_mutex);
	ret = start_sync_thread(net, &c,
				nla_get_u32(attrs[IPVS_DAEMON_ATTR_STATE]));
	mutex_unlock(&ipvs->sync_mutex);
	rtnl_unlock();
	return ret;
}

static int ip_vs_genl_del_daemon(struct net *net, struct nlattr **attrs)
{
	struct netns_ipvs *ipvs = net_ipvs(net);
	int ret;

	if (!attrs[IPVS_DAEMON_ATTR_STATE])
		return -EINVAL;

	return stop_sync_thread(net,
	mutex_lock(&ipvs->sync_mutex);
	ret = stop_sync_thread(net,
			       nla_get_u32(attrs[IPVS_DAEMON_ATTR_STATE]));
	mutex_unlock(&ipvs->sync_mutex);
	return ret;
}

static int ip_vs_genl_set_config(struct net *net, struct nlattr **attrs)
@@ -3389,7 +3469,7 @@ static int ip_vs_genl_set_config(struct net *net, struct nlattr **attrs)

static int ip_vs_genl_set_daemon(struct sk_buff *skb, struct genl_info *info)
{
	int ret = 0, cmd;
	int ret = -EINVAL, cmd;
	struct net *net;
	struct netns_ipvs *ipvs;

@@ -3400,22 +3480,19 @@ static int ip_vs_genl_set_daemon(struct sk_buff *skb, struct genl_info *info)
	if (cmd == IPVS_CMD_NEW_DAEMON || cmd == IPVS_CMD_DEL_DAEMON) {
		struct nlattr *daemon_attrs[IPVS_DAEMON_ATTR_MAX + 1];

		mutex_lock(&ipvs->sync_mutex);
		if (!info->attrs[IPVS_CMD_ATTR_DAEMON] ||
		    nla_parse_nested(daemon_attrs, IPVS_DAEMON_ATTR_MAX,
				     info->attrs[IPVS_CMD_ATTR_DAEMON],
				     ip_vs_daemon_policy)) {
			ret = -EINVAL;
				     ip_vs_daemon_policy))
			goto out;
		}

		if (cmd == IPVS_CMD_NEW_DAEMON)
			ret = ip_vs_genl_new_daemon(net, daemon_attrs);
		else
			ret = ip_vs_genl_del_daemon(net, daemon_attrs);
out:
		mutex_unlock(&ipvs->sync_mutex);
	}

out:
	return ret;
}

Loading