Skip to content

Commit

Permalink
ipvs: add sync_maxlen parameter for the sync daemon
Browse files Browse the repository at this point in the history
Allow setups with large MTU to send large sync packets by
adding sync_maxlen parameter. The default value is now based
on MTU but no more than 1500 for compatibility reasons.

To avoid problems if MTU changes allow fragmentation by
sending packets with DF=0. Problem reported by Dan Carpenter.

Reported-by: Dan Carpenter <[email protected]>
Signed-off-by: Julian Anastasov <[email protected]>
Signed-off-by: Simon Horman <[email protected]>
  • Loading branch information
Julian Anastasov authored and horms committed Aug 21, 2015
1 parent e0b26cc commit e4ff675
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 102 deletions.
19 changes: 11 additions & 8 deletions include/net/ip_vs.h
Original file line number Diff line number Diff line change
Expand Up @@ -846,6 +846,13 @@ 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 {
int syncid;
u16 sync_maxlen;
/* multicast interface name */
char mcast_ifn[IP_VS_IFNAME_MAXLEN];
};

/* IPVS in network namespace */
struct netns_ipvs {
int gen; /* Generation */
Expand Down Expand Up @@ -961,15 +968,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
Expand Down Expand Up @@ -1408,7 +1410,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);

Expand Down
1 change: 1 addition & 0 deletions include/uapi/linux/ip_vs.h
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,7 @@ 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_MAX,
};

Expand Down
53 changes: 33 additions & 20 deletions net/netfilter/ipvs/ip_vs_ctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -2336,10 +2336,15 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
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, dm->state, dm->mcast_ifn,
dm->syncid);
ret = start_sync_thread(net, &cfg, dm->state);
mutex_unlock(&ipvs->sync_mutex);
rtnl_unlock();
} else {
Expand Down Expand Up @@ -2650,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;
Expand Down Expand Up @@ -2813,6 +2818,7 @@ 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 },
};

/* Policy used for attributes in nested attribute IPVS_CMD_ATTR_SERVICE */
Expand Down Expand Up @@ -3271,7 +3277,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;

Expand All @@ -3280,8 +3286,9 @@ 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))
goto nla_put_failure;
nla_nest_end(skb, nl_daemon);

Expand All @@ -3293,7 +3300,7 @@ static int ip_vs_genl_fill_daemon(struct sk_buff *skb, __u32 state,
}

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;
Expand All @@ -3303,7 +3310,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);
Expand All @@ -3323,17 +3330,15 @@ 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;
}

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;
Expand All @@ -3348,25 +3353,33 @@ static int ip_vs_genl_dump_daemons(struct sk_buff *skb,
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);

/* 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;

rtnl_lock();
mutex_lock(&ipvs->sync_mutex);
ret = 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]));
ret = start_sync_thread(net, &c,
nla_get_u32(attrs[IPVS_DAEMON_ATTR_STATE]));
mutex_unlock(&ipvs->sync_mutex);
rtnl_unlock();
return ret;
Expand Down
Loading

0 comments on commit e4ff675

Please sign in to comment.