History

bonding: add arp_ip_target netlink support

Add IFLA_BOND_ARP_IP_TARGET to allow get/set of bonding parameter arp_ip_target via netlink.

sfeldma@cumulusnetworks.com committed 12 years ago

Commit 7f28fa11 parent 06151db5 files · +187 −68Browse files

Unified · Split

5 files
  1. drivers/net/bonding/bond_netlink.c +36 −0
  2. drivers/net/bonding/bond_options.c +130 −0
  3. drivers/net/bonding/bond_sysfs.c +16 −68
  4. drivers/net/bonding/bonding.h +4 −0
  5. include/uapi/linux/if_link.h +1 −0
drivers/net/bonding/bond_netlink.c+36−0
@@ -29,6 +29,7 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = { · 28 unmodified lines
29 [IFLA_BOND_DOWNDELAY] = { .type = NLA_U32 },29 [IFLA_BOND_DOWNDELAY] = { .type = NLA_U32 },
30 [IFLA_BOND_USE_CARRIER] = { .type = NLA_U8 },30 [IFLA_BOND_USE_CARRIER] = { .type = NLA_U8 },
31 [IFLA_BOND_ARP_INTERVAL] = { .type = NLA_U32 },31 [IFLA_BOND_ARP_INTERVAL] = { .type = NLA_U32 },
32 [IFLA_BOND_ARP_IP_TARGET] = { .type = NLA_NESTED },
32};33};
33 34
34static int bond_validate(struct nlattr *tb[], struct nlattr *data[])35static int bond_validate(struct nlattr *tb[], struct nlattr *data[])
@@ -116,6 +117,20 @@ static int bond_changelink(struct net_device *bond_dev, · 81 unmodified lines
116 if (err)117 if (err)
117 return err;118 return err;
118 }119 }
120 if (data[IFLA_BOND_ARP_IP_TARGET]) {
121 __be32 targets[BOND_MAX_ARP_TARGETS] = { 0, };
122 struct nlattr *attr;
123 int i = 0, rem;
124
125 nla_for_each_nested(attr, data[IFLA_BOND_ARP_IP_TARGET], rem) {
126 __be32 target = nla_get_u32(attr);
127 targets[i++] = target;
128 }
129
130 err = bond_option_arp_ip_targets_set(bond, targets, i);
131 if (err)
132 return err;
133 }
119 return 0;134 return 0;
120}135}
121 136
@@ -140,6 +155,8 @@ static size_t bond_get_size(const struct net_device *bond_dev) · 18 unmodified lines
140 nla_total_size(sizeof(u32)) + /* IFLA_BOND_DOWNDELAY */155 nla_total_size(sizeof(u32)) + /* IFLA_BOND_DOWNDELAY */
141 nla_total_size(sizeof(u8)) + /* IFLA_BOND_USE_CARRIER */156 nla_total_size(sizeof(u8)) + /* IFLA_BOND_USE_CARRIER */
142 nla_total_size(sizeof(u32)) + /* IFLA_BOND_ARP_INTERVAL */157 nla_total_size(sizeof(u32)) + /* IFLA_BOND_ARP_INTERVAL */
158 /* IFLA_BOND_ARP_IP_TARGET */
159 nla_total_size(sizeof(u32)) * BOND_MAX_ARP_TARGETS +
143 0;160 0;
144}161}
145 162
@@ -148,6 +165,8 @@ static int bond_fill_info(struct sk_buff *skb, · 2 unmodified lines
148{165{
149 struct bonding *bond = netdev_priv(bond_dev);166 struct bonding *bond = netdev_priv(bond_dev);
150 struct net_device *slave_dev = bond_option_active_slave_get(bond);167 struct net_device *slave_dev = bond_option_active_slave_get(bond);
168 struct nlattr *targets;
169 int i, targets_added;
151 170
152 if (nla_put_u8(skb, IFLA_BOND_MODE, bond->params.mode))171 if (nla_put_u8(skb, IFLA_BOND_MODE, bond->params.mode))
153 goto nla_put_failure;172 goto nla_put_failure;
@@ -173,6 +192,23 @@ static int bond_fill_info(struct sk_buff *skb, · 19 unmodified lines
173 if (nla_put_u32(skb, IFLA_BOND_ARP_INTERVAL, bond->params.arp_interval))192 if (nla_put_u32(skb, IFLA_BOND_ARP_INTERVAL, bond->params.arp_interval))
174 goto nla_put_failure;193 goto nla_put_failure;
175 194
195 targets = nla_nest_start(skb, IFLA_BOND_ARP_IP_TARGET);
196 if (!targets)
197 goto nla_put_failure;
198
199 targets_added = 0;
200 for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) {
201 if (bond->params.arp_targets[i]) {
202 nla_put_u32(skb, i, bond->params.arp_targets[i]);
203 targets_added = 1;
204 }
205 }
206
207 if (targets_added)
208 nla_nest_end(skb, targets);
209 else
210 nla_nest_cancel(skb, targets);
211
176 return 0;212 return 0;
177 213
178nla_put_failure:214nla_put_failure:
drivers/net/bonding/bond_options.c+130−0
@@ -306,3 +306,133 @@ int bond_option_arp_interval_set(struct bonding *bond, int arp_interval) · 305 unmodified lines
306 306
307 return 0;307 return 0;
308}308}
309
310static void _bond_options_arp_ip_target_set(struct bonding *bond, int slot,
311 __be32 target,
312 unsigned long last_rx)
313{
314 __be32 *targets = bond->params.arp_targets;
315 struct list_head *iter;
316 struct slave *slave;
317
318 if (slot >= 0 && slot < BOND_MAX_ARP_TARGETS) {
319 bond_for_each_slave(bond, slave, iter)
320 slave->target_last_arp_rx[slot] = last_rx;
321 targets[slot] = target;
322 }
323}
324
325static int _bond_option_arp_ip_target_add(struct bonding *bond, __be32 target)
326{
327 __be32 *targets = bond->params.arp_targets;
328 int ind;
329
330 if (IS_IP_TARGET_UNUSABLE_ADDRESS(target)) {
331 pr_err("%s: invalid ARP target %pI4 specified for addition\n",
332 bond->dev->name, &target);
333 return -EINVAL;
334 }
335
336 if (bond_get_targets_ip(targets, target) != -1) { /* dup */
337 pr_err("%s: ARP target %pI4 is already present\n",
338 bond->dev->name, &target);
339 return -EINVAL;
340 }
341
342 ind = bond_get_targets_ip(targets, 0); /* first free slot */
343 if (ind == -1) {
344 pr_err("%s: ARP target table is full!\n",
345 bond->dev->name);
346 return -EINVAL;
347 }
348
349 pr_info("%s: adding ARP target %pI4.\n", bond->dev->name, &target);
350
351 _bond_options_arp_ip_target_set(bond, ind, target, jiffies);
352
353 return 0;
354}
355
356int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target)
357{
358 int ret;
359
360 /* not to race with bond_arp_rcv */
361 write_lock_bh(&bond->lock);
362 ret = _bond_option_arp_ip_target_add(bond, target);
363 write_unlock_bh(&bond->lock);
364
365 return ret;
366}
367
368int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target)
369{
370 __be32 *targets = bond->params.arp_targets;
371 struct list_head *iter;
372 struct slave *slave;
373 unsigned long *targets_rx;
374 int ind, i;
375
376 if (IS_IP_TARGET_UNUSABLE_ADDRESS(target)) {
377 pr_err("%s: invalid ARP target %pI4 specified for removal\n",
378 bond->dev->name, &target);
379 return -EINVAL;
380 }
381
382 ind = bond_get_targets_ip(targets, target);
383 if (ind == -1) {
384 pr_err("%s: unable to remove nonexistent ARP target %pI4.\n",
385 bond->dev->name, &target);
386 return -EINVAL;
387 }
388
389 if (ind == 0 && !targets[1] && bond->params.arp_interval)
390 pr_warn("%s: removing last arp target with arp_interval on\n",
391 bond->dev->name);
392
393 pr_info("%s: removing ARP target %pI4.\n", bond->dev->name,
394 &target);
395
396 /* not to race with bond_arp_rcv */
397 write_lock_bh(&bond->lock);
398
399 bond_for_each_slave(bond, slave, iter) {
400 targets_rx = slave->target_last_arp_rx;
401 for (i = ind; (i < BOND_MAX_ARP_TARGETS-1) && targets[i+1]; i++)
402 targets_rx[i] = targets_rx[i+1];
403 targets_rx[i] = 0;
404 }
405 for (i = ind; (i < BOND_MAX_ARP_TARGETS-1) && targets[i+1]; i++)
406 targets[i] = targets[i+1];
407 targets[i] = 0;
408
409 write_unlock_bh(&bond->lock);
410
411 return 0;
412}
413
414int bond_option_arp_ip_targets_set(struct bonding *bond, __be32 *targets,
415 int count)
416{
417 int i, ret = 0;
418
419 /* not to race with bond_arp_rcv */
420 write_lock_bh(&bond->lock);
421
422 /* clear table */
423 for (i = 0; i < BOND_MAX_ARP_TARGETS; i++)
424 _bond_options_arp_ip_target_set(bond, i, 0, 0);
425
426 if (count == 0 && bond->params.arp_interval)
427 pr_warn("%s: removing last arp target with arp_interval on\n",
428 bond->dev->name);
429
430 for (i = 0; i < count; i++) {
431 ret = _bond_option_arp_ip_target_add(bond, targets[i]);
432 if (ret)
433 break;
434 }
435
436 write_unlock_bh(&bond->lock);
437 return ret;
438}
drivers/net/bonding/bond_sysfs.c+16−68
@@ -552,81 +552,29 @@ static ssize_t bonding_store_arp_targets(struct device *d, · 551 unmodified lines
552 const char *buf, size_t count)552 const char *buf, size_t count)
553{553{
554 struct bonding *bond = to_bond(d);554 struct bonding *bond = to_bond(d);
555 struct list_head *iter;555 __be32 target;
556 struct slave *slave;556 int ret = -EPERM;
557 __be32 newtarget, *targets;
558 unsigned long *targets_rx;
559 int ind, i, j, ret = -EINVAL;
560 557
561 if (!rtnl_trylock())558 if (!in4_pton(buf + 1, -1, (u8 *)&target, -1, NULL)) {
562 return restart_syscall();559 pr_err("%s: invalid ARP target %pI4 specified\n",
563 560 bond->dev->name, &target);
564 targets = bond->params.arp_targets;561 return -EPERM;
565 if (!in4_pton(buf + 1, -1, (u8 *)&newtarget, -1, NULL) ||
566 IS_IP_TARGET_UNUSABLE_ADDRESS(newtarget)) {
567 pr_err("%s: invalid ARP target %pI4 specified for addition\n",
568 bond->dev->name, &newtarget);
569 goto out;
570 }562 }
571 /* look for adds */
572 if (buf[0] == '+') {
573 if (bond_get_targets_ip(targets, newtarget) != -1) { /* dup */
574 pr_err("%s: ARP target %pI4 is already present\n",
575 bond->dev->name, &newtarget);
576 goto out;
577 }
578
579 ind = bond_get_targets_ip(targets, 0); /* first free slot */
580 if (ind == -1) {
581 pr_err("%s: ARP target table is full!\n",
582 bond->dev->name);
583 goto out;
584 }
585
586 pr_info("%s: adding ARP target %pI4.\n", bond->dev->name,
587 &newtarget);
588 /* not to race with bond_arp_rcv */
589 write_lock_bh(&bond->lock);
590 bond_for_each_slave(bond, slave, iter)
591 slave->target_last_arp_rx[ind] = jiffies;
592 targets[ind] = newtarget;
593 write_unlock_bh(&bond->lock);
594 } else if (buf[0] == '-') {
595 ind = bond_get_targets_ip(targets, newtarget);
596 if (ind == -1) {
597 pr_err("%s: unable to remove nonexistent ARP target %pI4.\n",
598 bond->dev->name, &newtarget);
599 goto out;
600 }
601 563
602 if (ind == 0 && !targets[1] && bond->params.arp_interval)564 if (!rtnl_trylock())
603 pr_warn("%s: removing last arp target with arp_interval on\n",565 return restart_syscall();
604 bond->dev->name);
605
606 pr_info("%s: removing ARP target %pI4.\n", bond->dev->name,
607 &newtarget);
608 566
609 write_lock_bh(&bond->lock);567 if (buf[0] == '+')
610 bond_for_each_slave(bond, slave, iter) {568 ret = bond_option_arp_ip_target_add(bond, target);
611 targets_rx = slave->target_last_arp_rx;569 else if (buf[0] == '-')
612 j = ind;570 ret = bond_option_arp_ip_target_rem(bond, target);
613 for (; (j < BOND_MAX_ARP_TARGETS-1) && targets[j+1]; j++)571 else
614 targets_rx[j] = targets_rx[j+1];
615 targets_rx[j] = 0;
616 }
617 for (i = ind; (i < BOND_MAX_ARP_TARGETS-1) && targets[i+1]; i++)
618 targets[i] = targets[i+1];
619 targets[i] = 0;
620 write_unlock_bh(&bond->lock);
621 } else {
622 pr_err("no command found in arp_ip_targets file for bond %s. Use +<addr> or -<addr>.\n",572 pr_err("no command found in arp_ip_targets file for bond %s. Use +<addr> or -<addr>.\n",
623 bond->dev->name);573 bond->dev->name);
624 ret = -EPERM;
625 goto out;
626 }
627 574
628 ret = count;575 if (!ret)
629out:576 ret = count;
577
630 rtnl_unlock();578 rtnl_unlock();
631 return ret;579 return ret;
632}580}
drivers/net/bonding/bonding.h+4−0
@@ -444,6 +444,10 @@ int bond_option_updelay_set(struct bonding *bond, int updelay); · 443 unmodified lines
444int bond_option_downdelay_set(struct bonding *bond, int downdelay);444int bond_option_downdelay_set(struct bonding *bond, int downdelay);
445int bond_option_use_carrier_set(struct bonding *bond, int use_carrier);445int bond_option_use_carrier_set(struct bonding *bond, int use_carrier);
446int bond_option_arp_interval_set(struct bonding *bond, int arp_interval);446int bond_option_arp_interval_set(struct bonding *bond, int arp_interval);
447int bond_option_arp_ip_targets_set(struct bonding *bond, __be32 *targets,
448 int count);
449int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target);
450int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target);
447struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond);451struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond);
448struct net_device *bond_option_active_slave_get(struct bonding *bond);452struct net_device *bond_option_active_slave_get(struct bonding *bond);
449 453
include/uapi/linux/if_link.h+1−0
@@ -336,6 +336,7 @@ enum { · 335 unmodified lines
336 IFLA_BOND_DOWNDELAY,336 IFLA_BOND_DOWNDELAY,
337 IFLA_BOND_USE_CARRIER,337 IFLA_BOND_USE_CARRIER,
338 IFLA_BOND_ARP_INTERVAL,338 IFLA_BOND_ARP_INTERVAL,
339 IFLA_BOND_ARP_IP_TARGET,
339 __IFLA_BOND_MAX,340 __IFLA_BOND_MAX,
340};341};
341 342