aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/bonding
diff options
context:
space:
mode:
authorAndy Gospodarek <andy@greyhouse.net>2012-03-22 12:14:29 -0400
committerDavid S. Miller <davem@davemloft.net>2012-03-22 22:36:17 -0400
commiteaddcd76903c28e84bb452a35835babb0800a2c4 (patch)
tree97e512e21955da69d434a34b4e073ba880ec7d3d /drivers/net/bonding
parent523f610e1be2a4afca605962e137064378883c5f (diff)
bonding: remove entries for master_ip and vlan_ip and query devices instead
The following patch aimed to resolve an issue where secondary, tertiary, etc. addresses added to bond interfaces could overwrite the bond->master_ip and vlan_ip values. commit 917fbdb32f37e9a93b00bb12ee83532982982df3 Author: Henrik Saavedra Persson <henrik.e.persson@ericsson.com> Date: Wed Nov 23 23:37:15 2011 +0000 bonding: only use primary address for ARP That patch was good because it prevented bonds using ARP monitoring from sending frames with an invalid source IP address. Unfortunately, it didn't always work as expected. When using an ioctl (like ifconfig does) to set the IP address and netmask, 2 separate ioctls are actually called to set the IP and netmask if the mask chosen doesn't match the standard mask for that class of address. The first ioctl did not have a mask that matched the one in the primary address and would still cause the device address to be overwritten. The second ioctl that was called to set the mask would then detect as secondary and ignored, but the damage was already done. This was not an issue when using an application that used netlink sockets as the setting of IP and netmask came down at once. The inconsistent behavior between those two interfaces was something that needed to be resolved. While I was thinking about how I wanted to resolve this, Ralf Zeidler came with a patch that resolved this on a RHEL kernel by keeping a full shadow of the entries in dev->ifa_list for the bonding device and vlan devices in the bonding driver. I didn't like the duplication of the list as I want to see the 'bonding' struct and code shrink rather than grow, but liked the general idea. As the Subject indicates this patch drops the master_ip and vlan_ip elements from the 'bonding' and 'vlan_entry' structs, respectively. This can be done because a device's address-list is now traversed to determine the optimal source IP address for ARP requests and for checks to see if the bonding device has a particular IP address. This code could have all be contained inside the bonding driver, but it made more sense to me to EXPORT and call inet_confirm_addr since it did exactly what was needed. I tested this and a backported patch and everything works as expected. Ralf also helped with verification of the backported patch. Thanks to Ralf for all his help on this. v2: Whitespace and organizational changes based on suggestions from Jay Vosburgh and Dave Miller. v3: Fixup incorrect usage of rcu_read_unlock based on Dave Miller's suggestion. Signed-off-by: Andy Gospodarek <andy@greyhouse.net> CC: Ralf Zeidler <ralf.zeidler@nsn.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/bonding')
-rw-r--r--drivers/net/bonding/bond_main.c82
-rw-r--r--drivers/net/bonding/bonding.h18
2 files changed, 31 insertions, 69 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 0730203a19f2..b920d829692a 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -2573,12 +2573,16 @@ re_arm:
2573static int bond_has_this_ip(struct bonding *bond, __be32 ip) 2573static int bond_has_this_ip(struct bonding *bond, __be32 ip)
2574{ 2574{
2575 struct vlan_entry *vlan; 2575 struct vlan_entry *vlan;
2576 struct net_device *vlan_dev;
2576 2577
2577 if (ip == bond->master_ip) 2578 if (ip == bond_confirm_addr(bond->dev, 0, ip))
2578 return 1; 2579 return 1;
2579 2580
2580 list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { 2581 list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
2581 if (ip == vlan->vlan_ip) 2582 rcu_read_lock();
2583 vlan_dev = __vlan_find_dev_deep(bond->dev, vlan->vlan_id);
2584 rcu_read_unlock();
2585 if (vlan_dev && ip == bond_confirm_addr(vlan_dev, 0, ip))
2582 return 1; 2586 return 1;
2583 } 2587 }
2584 2588
@@ -2620,17 +2624,19 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
2620 int i, vlan_id; 2624 int i, vlan_id;
2621 __be32 *targets = bond->params.arp_targets; 2625 __be32 *targets = bond->params.arp_targets;
2622 struct vlan_entry *vlan; 2626 struct vlan_entry *vlan;
2623 struct net_device *vlan_dev; 2627 struct net_device *vlan_dev = NULL;
2624 struct rtable *rt; 2628 struct rtable *rt;
2625 2629
2626 for (i = 0; (i < BOND_MAX_ARP_TARGETS); i++) { 2630 for (i = 0; (i < BOND_MAX_ARP_TARGETS); i++) {
2631 __be32 addr;
2627 if (!targets[i]) 2632 if (!targets[i])
2628 break; 2633 break;
2629 pr_debug("basa: target %x\n", targets[i]); 2634 pr_debug("basa: target %x\n", targets[i]);
2630 if (!bond_vlan_used(bond)) { 2635 if (!bond_vlan_used(bond)) {
2631 pr_debug("basa: empty vlan: arp_send\n"); 2636 pr_debug("basa: empty vlan: arp_send\n");
2637 addr = bond_confirm_addr(bond->dev, targets[i], 0);
2632 bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], 2638 bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
2633 bond->master_ip, 0); 2639 addr, 0);
2634 continue; 2640 continue;
2635 } 2641 }
2636 2642
@@ -2655,8 +2661,9 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
2655 if (rt->dst.dev == bond->dev) { 2661 if (rt->dst.dev == bond->dev) {
2656 ip_rt_put(rt); 2662 ip_rt_put(rt);
2657 pr_debug("basa: rtdev == bond->dev: arp_send\n"); 2663 pr_debug("basa: rtdev == bond->dev: arp_send\n");
2664 addr = bond_confirm_addr(bond->dev, targets[i], 0);
2658 bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], 2665 bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
2659 bond->master_ip, 0); 2666 addr, 0);
2660 continue; 2667 continue;
2661 } 2668 }
2662 2669
@@ -2674,10 +2681,11 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
2674 } 2681 }
2675 } 2682 }
2676 2683
2677 if (vlan_id) { 2684 if (vlan_id && vlan_dev) {
2678 ip_rt_put(rt); 2685 ip_rt_put(rt);
2686 addr = bond_confirm_addr(vlan_dev, targets[i], 0);
2679 bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], 2687 bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
2680 vlan->vlan_ip, vlan_id); 2688 addr, vlan_id);
2681 continue; 2689 continue;
2682 } 2690 }
2683 2691
@@ -3299,68 +3307,10 @@ static int bond_netdev_event(struct notifier_block *this,
3299 return NOTIFY_DONE; 3307 return NOTIFY_DONE;
3300} 3308}
3301 3309
3302/*
3303 * bond_inetaddr_event: handle inetaddr notifier chain events.
3304 *
3305 * We keep track of device IPs primarily to use as source addresses in
3306 * ARP monitor probes (rather than spewing out broadcasts all the time).
3307 *
3308 * We track one IP for the main device (if it has one), plus one per VLAN.
3309 */
3310static int bond_inetaddr_event(struct notifier_block *this, unsigned long event, void *ptr)
3311{
3312 struct in_ifaddr *ifa = ptr;
3313 struct net_device *vlan_dev, *event_dev = ifa->ifa_dev->dev;
3314 struct bond_net *bn = net_generic(dev_net(event_dev), bond_net_id);
3315 struct bonding *bond;
3316 struct vlan_entry *vlan;
3317
3318 /* we only care about primary address */
3319 if(ifa->ifa_flags & IFA_F_SECONDARY)
3320 return NOTIFY_DONE;
3321
3322 list_for_each_entry(bond, &bn->dev_list, bond_list) {
3323 if (bond->dev == event_dev) {
3324 switch (event) {
3325 case NETDEV_UP:
3326 bond->master_ip = ifa->ifa_local;
3327 return NOTIFY_OK;
3328 case NETDEV_DOWN:
3329 bond->master_ip = 0;
3330 return NOTIFY_OK;
3331 default:
3332 return NOTIFY_DONE;
3333 }
3334 }
3335
3336 list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
3337 vlan_dev = __vlan_find_dev_deep(bond->dev,
3338 vlan->vlan_id);
3339 if (vlan_dev == event_dev) {
3340 switch (event) {
3341 case NETDEV_UP:
3342 vlan->vlan_ip = ifa->ifa_local;
3343 return NOTIFY_OK;
3344 case NETDEV_DOWN:
3345 vlan->vlan_ip = 0;
3346 return NOTIFY_OK;
3347 default:
3348 return NOTIFY_DONE;
3349 }
3350 }
3351 }
3352 }
3353 return NOTIFY_DONE;
3354}
3355
3356static struct notifier_block bond_netdev_notifier = { 3310static struct notifier_block bond_netdev_notifier = {
3357 .notifier_call = bond_netdev_event, 3311 .notifier_call = bond_netdev_event,
3358}; 3312};
3359 3313
3360static struct notifier_block bond_inetaddr_notifier = {
3361 .notifier_call = bond_inetaddr_event,
3362};
3363
3364/*---------------------------- Hashing Policies -----------------------------*/ 3314/*---------------------------- Hashing Policies -----------------------------*/
3365 3315
3366/* 3316/*
@@ -4929,7 +4879,6 @@ static int __init bonding_init(void)
4929 } 4879 }
4930 4880
4931 register_netdevice_notifier(&bond_netdev_notifier); 4881 register_netdevice_notifier(&bond_netdev_notifier);
4932 register_inetaddr_notifier(&bond_inetaddr_notifier);
4933out: 4882out:
4934 return res; 4883 return res;
4935err: 4884err:
@@ -4943,7 +4892,6 @@ err_link:
4943static void __exit bonding_exit(void) 4892static void __exit bonding_exit(void)
4944{ 4893{
4945 unregister_netdevice_notifier(&bond_netdev_notifier); 4894 unregister_netdevice_notifier(&bond_netdev_notifier);
4946 unregister_inetaddr_notifier(&bond_inetaddr_notifier);
4947 4895
4948 bond_destroy_debugfs(); 4896 bond_destroy_debugfs();
4949 4897
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 1aecc37e5b4d..9f2bae6616d3 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -21,6 +21,7 @@
21#include <linux/cpumask.h> 21#include <linux/cpumask.h>
22#include <linux/in6.h> 22#include <linux/in6.h>
23#include <linux/netpoll.h> 23#include <linux/netpoll.h>
24#include <linux/inetdevice.h>
24#include "bond_3ad.h" 25#include "bond_3ad.h"
25#include "bond_alb.h" 26#include "bond_alb.h"
26 27
@@ -166,7 +167,6 @@ struct bond_parm_tbl {
166 167
167struct vlan_entry { 168struct vlan_entry {
168 struct list_head vlan_list; 169 struct list_head vlan_list;
169 __be32 vlan_ip;
170 unsigned short vlan_id; 170 unsigned short vlan_id;
171}; 171};
172 172
@@ -232,7 +232,6 @@ struct bonding {
232 struct list_head bond_list; 232 struct list_head bond_list;
233 struct netdev_hw_addr_list mc_list; 233 struct netdev_hw_addr_list mc_list;
234 int (*xmit_hash_policy)(struct sk_buff *, int); 234 int (*xmit_hash_policy)(struct sk_buff *, int);
235 __be32 master_ip;
236 u16 rr_tx_counter; 235 u16 rr_tx_counter;
237 struct ad_bond_info ad_info; 236 struct ad_bond_info ad_info;
238 struct alb_bond_info alb_info; 237 struct alb_bond_info alb_info;
@@ -378,6 +377,21 @@ static inline bool bond_is_slave_inactive(struct slave *slave)
378 return slave->inactive; 377 return slave->inactive;
379} 378}
380 379
380static inline __be32 bond_confirm_addr(struct net_device *dev, __be32 dst, __be32 local)
381{
382 struct in_device *in_dev;
383 __be32 addr = 0;
384
385 rcu_read_lock();
386 in_dev = __in_dev_get_rcu(dev);
387
388 if (in_dev)
389 addr = inet_confirm_addr(in_dev, dst, local, RT_SCOPE_HOST);
390
391 rcu_read_unlock();
392 return addr;
393}
394
381struct bond_net; 395struct bond_net;
382 396
383struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr); 397struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr);