diff options
Diffstat (limited to 'drivers/net/bonding/bond_main.c')
-rw-r--r-- | drivers/net/bonding/bond_main.c | 394 |
1 files changed, 172 insertions, 222 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index a641eeaa2a2f..c792138511e6 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c | |||
@@ -2223,272 +2223,217 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in | |||
2223 | 2223 | ||
2224 | /*-------------------------------- Monitoring -------------------------------*/ | 2224 | /*-------------------------------- Monitoring -------------------------------*/ |
2225 | 2225 | ||
2226 | /* | ||
2227 | * if !have_locks, return nonzero if a failover is necessary. if | ||
2228 | * have_locks, do whatever failover activities are needed. | ||
2229 | * | ||
2230 | * This is to separate the inspection and failover steps for locking | ||
2231 | * purposes; failover requires rtnl, but acquiring it for every | ||
2232 | * inspection is undesirable, so a wrapper first does inspection, and | ||
2233 | * the acquires the necessary locks and calls again to perform | ||
2234 | * failover if needed. Since all locks are dropped, a complete | ||
2235 | * restart is needed between calls. | ||
2236 | */ | ||
2237 | static int __bond_mii_monitor(struct bonding *bond, int have_locks) | ||
2238 | { | ||
2239 | struct slave *slave, *oldcurrent; | ||
2240 | int do_failover = 0; | ||
2241 | int i; | ||
2242 | |||
2243 | if (bond->slave_cnt == 0) | ||
2244 | goto out; | ||
2245 | 2226 | ||
2246 | /* we will try to read the link status of each of our slaves, and | 2227 | static int bond_miimon_inspect(struct bonding *bond) |
2247 | * set their IFF_RUNNING flag appropriately. For each slave not | 2228 | { |
2248 | * supporting MII status, we won't do anything so that a user-space | 2229 | struct slave *slave; |
2249 | * program could monitor the link itself if needed. | 2230 | int i, link_state, commit = 0; |
2250 | */ | ||
2251 | |||
2252 | read_lock(&bond->curr_slave_lock); | ||
2253 | oldcurrent = bond->curr_active_slave; | ||
2254 | read_unlock(&bond->curr_slave_lock); | ||
2255 | 2231 | ||
2256 | bond_for_each_slave(bond, slave, i) { | 2232 | bond_for_each_slave(bond, slave, i) { |
2257 | struct net_device *slave_dev = slave->dev; | 2233 | slave->new_link = BOND_LINK_NOCHANGE; |
2258 | int link_state; | ||
2259 | u16 old_speed = slave->speed; | ||
2260 | u8 old_duplex = slave->duplex; | ||
2261 | 2234 | ||
2262 | link_state = bond_check_dev_link(bond, slave_dev, 0); | 2235 | link_state = bond_check_dev_link(bond, slave->dev, 0); |
2263 | 2236 | ||
2264 | switch (slave->link) { | 2237 | switch (slave->link) { |
2265 | case BOND_LINK_UP: /* the link was up */ | 2238 | case BOND_LINK_UP: |
2266 | if (link_state == BMSR_LSTATUS) { | 2239 | if (link_state) |
2267 | if (!oldcurrent) { | 2240 | continue; |
2268 | if (!have_locks) | ||
2269 | return 1; | ||
2270 | do_failover = 1; | ||
2271 | } | ||
2272 | break; | ||
2273 | } else { /* link going down */ | ||
2274 | slave->link = BOND_LINK_FAIL; | ||
2275 | slave->delay = bond->params.downdelay; | ||
2276 | |||
2277 | if (slave->link_failure_count < UINT_MAX) { | ||
2278 | slave->link_failure_count++; | ||
2279 | } | ||
2280 | 2241 | ||
2281 | if (bond->params.downdelay) { | 2242 | slave->link = BOND_LINK_FAIL; |
2282 | printk(KERN_INFO DRV_NAME | 2243 | slave->delay = bond->params.downdelay; |
2283 | ": %s: link status down for %s " | 2244 | if (slave->delay) { |
2284 | "interface %s, disabling it in " | 2245 | printk(KERN_INFO DRV_NAME |
2285 | "%d ms.\n", | 2246 | ": %s: link status down for %s" |
2286 | bond->dev->name, | 2247 | "interface %s, disabling it in %d ms.\n", |
2287 | IS_UP(slave_dev) | 2248 | bond->dev->name, |
2288 | ? ((bond->params.mode == BOND_MODE_ACTIVEBACKUP) | 2249 | (bond->params.mode == |
2289 | ? ((slave == oldcurrent) | 2250 | BOND_MODE_ACTIVEBACKUP) ? |
2290 | ? "active " : "backup ") | 2251 | ((slave->state == BOND_STATE_ACTIVE) ? |
2291 | : "") | 2252 | "active " : "backup ") : "", |
2292 | : "idle ", | 2253 | slave->dev->name, |
2293 | slave_dev->name, | 2254 | bond->params.downdelay * bond->params.miimon); |
2294 | bond->params.downdelay * bond->params.miimon); | ||
2295 | } | ||
2296 | } | 2255 | } |
2297 | /* no break ! fall through the BOND_LINK_FAIL test to | 2256 | /*FALLTHRU*/ |
2298 | ensure proper action to be taken | 2257 | case BOND_LINK_FAIL: |
2299 | */ | 2258 | if (link_state) { |
2300 | case BOND_LINK_FAIL: /* the link has just gone down */ | 2259 | /* |
2301 | if (link_state != BMSR_LSTATUS) { | 2260 | * recovered before downdelay expired |
2302 | /* link stays down */ | 2261 | */ |
2303 | if (slave->delay <= 0) { | 2262 | slave->link = BOND_LINK_UP; |
2304 | if (!have_locks) | ||
2305 | return 1; | ||
2306 | |||
2307 | /* link down for too long time */ | ||
2308 | slave->link = BOND_LINK_DOWN; | ||
2309 | |||
2310 | /* in active/backup mode, we must | ||
2311 | * completely disable this interface | ||
2312 | */ | ||
2313 | if ((bond->params.mode == BOND_MODE_ACTIVEBACKUP) || | ||
2314 | (bond->params.mode == BOND_MODE_8023AD)) { | ||
2315 | bond_set_slave_inactive_flags(slave); | ||
2316 | } | ||
2317 | |||
2318 | printk(KERN_INFO DRV_NAME | ||
2319 | ": %s: link status definitely " | ||
2320 | "down for interface %s, " | ||
2321 | "disabling it\n", | ||
2322 | bond->dev->name, | ||
2323 | slave_dev->name); | ||
2324 | |||
2325 | /* notify ad that the link status has changed */ | ||
2326 | if (bond->params.mode == BOND_MODE_8023AD) { | ||
2327 | bond_3ad_handle_link_change(slave, BOND_LINK_DOWN); | ||
2328 | } | ||
2329 | |||
2330 | if ((bond->params.mode == BOND_MODE_TLB) || | ||
2331 | (bond->params.mode == BOND_MODE_ALB)) { | ||
2332 | bond_alb_handle_link_change(bond, slave, BOND_LINK_DOWN); | ||
2333 | } | ||
2334 | |||
2335 | if (slave == oldcurrent) { | ||
2336 | do_failover = 1; | ||
2337 | } | ||
2338 | } else { | ||
2339 | slave->delay--; | ||
2340 | } | ||
2341 | } else { | ||
2342 | /* link up again */ | ||
2343 | slave->link = BOND_LINK_UP; | ||
2344 | slave->jiffies = jiffies; | 2263 | slave->jiffies = jiffies; |
2345 | printk(KERN_INFO DRV_NAME | 2264 | printk(KERN_INFO DRV_NAME |
2346 | ": %s: link status up again after %d " | 2265 | ": %s: link status up again after %d " |
2347 | "ms for interface %s.\n", | 2266 | "ms for interface %s.\n", |
2348 | bond->dev->name, | 2267 | bond->dev->name, |
2349 | (bond->params.downdelay - slave->delay) * bond->params.miimon, | 2268 | (bond->params.downdelay - slave->delay) * |
2350 | slave_dev->name); | 2269 | bond->params.miimon, |
2270 | slave->dev->name); | ||
2271 | continue; | ||
2351 | } | 2272 | } |
2352 | break; | ||
2353 | case BOND_LINK_DOWN: /* the link was down */ | ||
2354 | if (link_state != BMSR_LSTATUS) { | ||
2355 | /* the link stays down, nothing more to do */ | ||
2356 | break; | ||
2357 | } else { /* link going up */ | ||
2358 | slave->link = BOND_LINK_BACK; | ||
2359 | slave->delay = bond->params.updelay; | ||
2360 | 2273 | ||
2361 | if (bond->params.updelay) { | 2274 | if (slave->delay <= 0) { |
2362 | /* if updelay == 0, no need to | 2275 | slave->new_link = BOND_LINK_DOWN; |
2363 | advertise about a 0 ms delay */ | 2276 | commit++; |
2364 | printk(KERN_INFO DRV_NAME | 2277 | continue; |
2365 | ": %s: link status up for " | ||
2366 | "interface %s, enabling it " | ||
2367 | "in %d ms.\n", | ||
2368 | bond->dev->name, | ||
2369 | slave_dev->name, | ||
2370 | bond->params.updelay * bond->params.miimon); | ||
2371 | } | ||
2372 | } | 2278 | } |
2373 | /* no break ! fall through the BOND_LINK_BACK state in | ||
2374 | case there's something to do. | ||
2375 | */ | ||
2376 | case BOND_LINK_BACK: /* the link has just come back */ | ||
2377 | if (link_state != BMSR_LSTATUS) { | ||
2378 | /* link down again */ | ||
2379 | slave->link = BOND_LINK_DOWN; | ||
2380 | 2279 | ||
2280 | slave->delay--; | ||
2281 | break; | ||
2282 | |||
2283 | case BOND_LINK_DOWN: | ||
2284 | if (!link_state) | ||
2285 | continue; | ||
2286 | |||
2287 | slave->link = BOND_LINK_BACK; | ||
2288 | slave->delay = bond->params.updelay; | ||
2289 | |||
2290 | if (slave->delay) { | ||
2291 | printk(KERN_INFO DRV_NAME | ||
2292 | ": %s: link status up for " | ||
2293 | "interface %s, enabling it in %d ms.\n", | ||
2294 | bond->dev->name, slave->dev->name, | ||
2295 | bond->params.updelay * | ||
2296 | bond->params.miimon); | ||
2297 | } | ||
2298 | /*FALLTHRU*/ | ||
2299 | case BOND_LINK_BACK: | ||
2300 | if (!link_state) { | ||
2301 | slave->link = BOND_LINK_DOWN; | ||
2381 | printk(KERN_INFO DRV_NAME | 2302 | printk(KERN_INFO DRV_NAME |
2382 | ": %s: link status down again after %d " | 2303 | ": %s: link status down again after %d " |
2383 | "ms for interface %s.\n", | 2304 | "ms for interface %s.\n", |
2384 | bond->dev->name, | 2305 | bond->dev->name, |
2385 | (bond->params.updelay - slave->delay) * bond->params.miimon, | 2306 | (bond->params.updelay - slave->delay) * |
2386 | slave_dev->name); | 2307 | bond->params.miimon, |
2387 | } else { | 2308 | slave->dev->name); |
2388 | /* link stays up */ | ||
2389 | if (slave->delay == 0) { | ||
2390 | if (!have_locks) | ||
2391 | return 1; | ||
2392 | |||
2393 | /* now the link has been up for long time enough */ | ||
2394 | slave->link = BOND_LINK_UP; | ||
2395 | slave->jiffies = jiffies; | ||
2396 | |||
2397 | if (bond->params.mode == BOND_MODE_8023AD) { | ||
2398 | /* prevent it from being the active one */ | ||
2399 | slave->state = BOND_STATE_BACKUP; | ||
2400 | } else if (bond->params.mode != BOND_MODE_ACTIVEBACKUP) { | ||
2401 | /* make it immediately active */ | ||
2402 | slave->state = BOND_STATE_ACTIVE; | ||
2403 | } else if (slave != bond->primary_slave) { | ||
2404 | /* prevent it from being the active one */ | ||
2405 | slave->state = BOND_STATE_BACKUP; | ||
2406 | } | ||
2407 | 2309 | ||
2408 | printk(KERN_INFO DRV_NAME | 2310 | continue; |
2409 | ": %s: link status definitely " | ||
2410 | "up for interface %s.\n", | ||
2411 | bond->dev->name, | ||
2412 | slave_dev->name); | ||
2413 | |||
2414 | /* notify ad that the link status has changed */ | ||
2415 | if (bond->params.mode == BOND_MODE_8023AD) { | ||
2416 | bond_3ad_handle_link_change(slave, BOND_LINK_UP); | ||
2417 | } | ||
2418 | |||
2419 | if ((bond->params.mode == BOND_MODE_TLB) || | ||
2420 | (bond->params.mode == BOND_MODE_ALB)) { | ||
2421 | bond_alb_handle_link_change(bond, slave, BOND_LINK_UP); | ||
2422 | } | ||
2423 | |||
2424 | if ((!oldcurrent) || | ||
2425 | (slave == bond->primary_slave)) { | ||
2426 | do_failover = 1; | ||
2427 | } | ||
2428 | } else { | ||
2429 | slave->delay--; | ||
2430 | } | ||
2431 | } | 2311 | } |
2312 | |||
2313 | if (slave->delay <= 0) { | ||
2314 | slave->new_link = BOND_LINK_UP; | ||
2315 | commit++; | ||
2316 | continue; | ||
2317 | } | ||
2318 | |||
2319 | slave->delay--; | ||
2432 | break; | 2320 | break; |
2433 | default: | 2321 | } |
2434 | /* Should not happen */ | 2322 | } |
2435 | printk(KERN_ERR DRV_NAME | ||
2436 | ": %s: Error: %s Illegal value (link=%d)\n", | ||
2437 | bond->dev->name, | ||
2438 | slave->dev->name, | ||
2439 | slave->link); | ||
2440 | goto out; | ||
2441 | } /* end of switch (slave->link) */ | ||
2442 | 2323 | ||
2443 | bond_update_speed_duplex(slave); | 2324 | return commit; |
2325 | } | ||
2444 | 2326 | ||
2445 | if (bond->params.mode == BOND_MODE_8023AD) { | 2327 | static void bond_miimon_commit(struct bonding *bond) |
2446 | if (old_speed != slave->speed) { | 2328 | { |
2447 | bond_3ad_adapter_speed_changed(slave); | 2329 | struct slave *slave; |
2448 | } | 2330 | int i; |
2331 | |||
2332 | bond_for_each_slave(bond, slave, i) { | ||
2333 | switch (slave->new_link) { | ||
2334 | case BOND_LINK_NOCHANGE: | ||
2335 | continue; | ||
2336 | |||
2337 | case BOND_LINK_UP: | ||
2338 | slave->link = BOND_LINK_UP; | ||
2339 | slave->jiffies = jiffies; | ||
2449 | 2340 | ||
2450 | if (old_duplex != slave->duplex) { | 2341 | if (bond->params.mode == BOND_MODE_8023AD) { |
2451 | bond_3ad_adapter_duplex_changed(slave); | 2342 | /* prevent it from being the active one */ |
2343 | slave->state = BOND_STATE_BACKUP; | ||
2344 | } else if (bond->params.mode != BOND_MODE_ACTIVEBACKUP) { | ||
2345 | /* make it immediately active */ | ||
2346 | slave->state = BOND_STATE_ACTIVE; | ||
2347 | } else if (slave != bond->primary_slave) { | ||
2348 | /* prevent it from being the active one */ | ||
2349 | slave->state = BOND_STATE_BACKUP; | ||
2452 | } | 2350 | } |
2453 | } | ||
2454 | 2351 | ||
2455 | } /* end of for */ | 2352 | printk(KERN_INFO DRV_NAME |
2353 | ": %s: link status definitely " | ||
2354 | "up for interface %s.\n", | ||
2355 | bond->dev->name, slave->dev->name); | ||
2456 | 2356 | ||
2457 | if (do_failover) { | 2357 | /* notify ad that the link status has changed */ |
2458 | ASSERT_RTNL(); | 2358 | if (bond->params.mode == BOND_MODE_8023AD) |
2359 | bond_3ad_handle_link_change(slave, BOND_LINK_UP); | ||
2459 | 2360 | ||
2460 | write_lock_bh(&bond->curr_slave_lock); | 2361 | if ((bond->params.mode == BOND_MODE_TLB) || |
2362 | (bond->params.mode == BOND_MODE_ALB)) | ||
2363 | bond_alb_handle_link_change(bond, slave, | ||
2364 | BOND_LINK_UP); | ||
2461 | 2365 | ||
2462 | bond_select_active_slave(bond); | 2366 | if (!bond->curr_active_slave || |
2367 | (slave == bond->primary_slave)) | ||
2368 | goto do_failover; | ||
2463 | 2369 | ||
2464 | write_unlock_bh(&bond->curr_slave_lock); | 2370 | continue; |
2465 | 2371 | ||
2466 | } else | 2372 | case BOND_LINK_DOWN: |
2467 | bond_set_carrier(bond); | 2373 | slave->link = BOND_LINK_DOWN; |
2468 | 2374 | ||
2469 | out: | 2375 | if (bond->params.mode == BOND_MODE_ACTIVEBACKUP || |
2470 | return 0; | 2376 | bond->params.mode == BOND_MODE_8023AD) |
2377 | bond_set_slave_inactive_flags(slave); | ||
2378 | |||
2379 | printk(KERN_INFO DRV_NAME | ||
2380 | ": %s: link status definitely down for " | ||
2381 | "interface %s, disabling it\n", | ||
2382 | bond->dev->name, slave->dev->name); | ||
2383 | |||
2384 | if (bond->params.mode == BOND_MODE_8023AD) | ||
2385 | bond_3ad_handle_link_change(slave, | ||
2386 | BOND_LINK_DOWN); | ||
2387 | |||
2388 | if (bond->params.mode == BOND_MODE_TLB || | ||
2389 | bond->params.mode == BOND_MODE_ALB) | ||
2390 | bond_alb_handle_link_change(bond, slave, | ||
2391 | BOND_LINK_DOWN); | ||
2392 | |||
2393 | if (slave == bond->curr_active_slave) | ||
2394 | goto do_failover; | ||
2395 | |||
2396 | continue; | ||
2397 | |||
2398 | default: | ||
2399 | printk(KERN_ERR DRV_NAME | ||
2400 | ": %s: invalid new link %d on slave %s\n", | ||
2401 | bond->dev->name, slave->new_link, | ||
2402 | slave->dev->name); | ||
2403 | slave->new_link = BOND_LINK_NOCHANGE; | ||
2404 | |||
2405 | continue; | ||
2406 | } | ||
2407 | |||
2408 | do_failover: | ||
2409 | ASSERT_RTNL(); | ||
2410 | write_lock_bh(&bond->curr_slave_lock); | ||
2411 | bond_select_active_slave(bond); | ||
2412 | write_unlock_bh(&bond->curr_slave_lock); | ||
2413 | } | ||
2414 | |||
2415 | bond_set_carrier(bond); | ||
2471 | } | 2416 | } |
2472 | 2417 | ||
2473 | /* | 2418 | /* |
2474 | * bond_mii_monitor | 2419 | * bond_mii_monitor |
2475 | * | 2420 | * |
2476 | * Really a wrapper that splits the mii monitor into two phases: an | 2421 | * Really a wrapper that splits the mii monitor into two phases: an |
2477 | * inspection, then (if inspection indicates something needs to be | 2422 | * inspection, then (if inspection indicates something needs to be done) |
2478 | * done) an acquisition of appropriate locks followed by another pass | 2423 | * an acquisition of appropriate locks followed by a commit phase to |
2479 | * to implement whatever link state changes are indicated. | 2424 | * implement whatever link state changes are indicated. |
2480 | */ | 2425 | */ |
2481 | void bond_mii_monitor(struct work_struct *work) | 2426 | void bond_mii_monitor(struct work_struct *work) |
2482 | { | 2427 | { |
2483 | struct bonding *bond = container_of(work, struct bonding, | 2428 | struct bonding *bond = container_of(work, struct bonding, |
2484 | mii_work.work); | 2429 | mii_work.work); |
2485 | unsigned long delay; | ||
2486 | 2430 | ||
2487 | read_lock(&bond->lock); | 2431 | read_lock(&bond->lock); |
2488 | if (bond->kill_timers) { | 2432 | if (bond->kill_timers) |
2489 | read_unlock(&bond->lock); | 2433 | goto out; |
2490 | return; | 2434 | |
2491 | } | 2435 | if (bond->slave_cnt == 0) |
2436 | goto re_arm; | ||
2492 | 2437 | ||
2493 | if (bond->send_grat_arp) { | 2438 | if (bond->send_grat_arp) { |
2494 | read_lock(&bond->curr_slave_lock); | 2439 | read_lock(&bond->curr_slave_lock); |
@@ -2496,19 +2441,24 @@ void bond_mii_monitor(struct work_struct *work) | |||
2496 | read_unlock(&bond->curr_slave_lock); | 2441 | read_unlock(&bond->curr_slave_lock); |
2497 | } | 2442 | } |
2498 | 2443 | ||
2499 | if (__bond_mii_monitor(bond, 0)) { | 2444 | if (bond_miimon_inspect(bond)) { |
2500 | read_unlock(&bond->lock); | 2445 | read_unlock(&bond->lock); |
2501 | rtnl_lock(); | 2446 | rtnl_lock(); |
2502 | read_lock(&bond->lock); | 2447 | read_lock(&bond->lock); |
2503 | __bond_mii_monitor(bond, 1); | 2448 | |
2449 | bond_miimon_commit(bond); | ||
2450 | |||
2504 | read_unlock(&bond->lock); | 2451 | read_unlock(&bond->lock); |
2505 | rtnl_unlock(); /* might sleep, hold no other locks */ | 2452 | rtnl_unlock(); /* might sleep, hold no other locks */ |
2506 | read_lock(&bond->lock); | 2453 | read_lock(&bond->lock); |
2507 | } | 2454 | } |
2508 | 2455 | ||
2509 | delay = msecs_to_jiffies(bond->params.miimon); | 2456 | re_arm: |
2457 | if (bond->params.miimon) | ||
2458 | queue_delayed_work(bond->wq, &bond->mii_work, | ||
2459 | msecs_to_jiffies(bond->params.miimon)); | ||
2460 | out: | ||
2510 | read_unlock(&bond->lock); | 2461 | read_unlock(&bond->lock); |
2511 | queue_delayed_work(bond->wq, &bond->mii_work, delay); | ||
2512 | } | 2462 | } |
2513 | 2463 | ||
2514 | static __be32 bond_glean_dev_ip(struct net_device *dev) | 2464 | static __be32 bond_glean_dev_ip(struct net_device *dev) |