aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/fib_semantics.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/fib_semantics.c')
-rw-r--r--net/ipv4/fib_semantics.c34
1 files changed, 29 insertions, 5 deletions
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index d97268e8ff10..ab64d9f2eef9 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -1559,21 +1559,45 @@ int fib_sync_up(struct net_device *dev, unsigned int nh_flags)
1559} 1559}
1560 1560
1561#ifdef CONFIG_IP_ROUTE_MULTIPATH 1561#ifdef CONFIG_IP_ROUTE_MULTIPATH
1562static bool fib_good_nh(const struct fib_nh *nh)
1563{
1564 int state = NUD_REACHABLE;
1565
1566 if (nh->nh_scope == RT_SCOPE_LINK) {
1567 struct neighbour *n;
1568
1569 rcu_read_lock_bh();
1570
1571 n = __ipv4_neigh_lookup_noref(nh->nh_dev, nh->nh_gw);
1572 if (n)
1573 state = n->nud_state;
1574
1575 rcu_read_unlock_bh();
1576 }
1577
1578 return !!(state & NUD_VALID);
1579}
1562 1580
1563void fib_select_multipath(struct fib_result *res, int hash) 1581void fib_select_multipath(struct fib_result *res, int hash)
1564{ 1582{
1565 struct fib_info *fi = res->fi; 1583 struct fib_info *fi = res->fi;
1584 struct net *net = fi->fib_net;
1585 bool first = false;
1566 1586
1567 for_nexthops(fi) { 1587 for_nexthops(fi) {
1568 if (hash > atomic_read(&nh->nh_upper_bound)) 1588 if (hash > atomic_read(&nh->nh_upper_bound))
1569 continue; 1589 continue;
1570 1590
1571 res->nh_sel = nhsel; 1591 if (!net->ipv4.sysctl_fib_multipath_use_neigh ||
1572 return; 1592 fib_good_nh(nh)) {
1593 res->nh_sel = nhsel;
1594 return;
1595 }
1596 if (!first) {
1597 res->nh_sel = nhsel;
1598 first = true;
1599 }
1573 } endfor_nexthops(fi); 1600 } endfor_nexthops(fi);
1574
1575 /* Race condition: route has just become dead. */
1576 res->nh_sel = 0;
1577} 1601}
1578#endif 1602#endif
1579 1603