diff options
-rw-r--r-- | Documentation/networking/ip-sysctl.txt | 10 | ||||
-rw-r--r-- | include/net/netns/ipv4.h | 3 | ||||
-rw-r--r-- | net/ipv4/fib_semantics.c | 34 | ||||
-rw-r--r-- | net/ipv4/sysctl_net_ipv4.c | 11 |
4 files changed, 53 insertions, 5 deletions
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index b183e2b606c8..6c7f365b1515 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt | |||
@@ -63,6 +63,16 @@ fwmark_reflect - BOOLEAN | |||
63 | fwmark of the packet they are replying to. | 63 | fwmark of the packet they are replying to. |
64 | Default: 0 | 64 | Default: 0 |
65 | 65 | ||
66 | fib_multipath_use_neigh - BOOLEAN | ||
67 | Use status of existing neighbor entry when determining nexthop for | ||
68 | multipath routes. If disabled, neighbor information is not used and | ||
69 | packets could be directed to a failed nexthop. Only valid for kernels | ||
70 | built with CONFIG_IP_ROUTE_MULTIPATH enabled. | ||
71 | Default: 0 (disabled) | ||
72 | Possible values: | ||
73 | 0 - disabled | ||
74 | 1 - enabled | ||
75 | |||
66 | route/max_size - INTEGER | 76 | route/max_size - INTEGER |
67 | Maximum number of routes allowed in the kernel. Increase | 77 | Maximum number of routes allowed in the kernel. Increase |
68 | this when using large numbers of interfaces and/or routes. | 78 | this when using large numbers of interfaces and/or routes. |
diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index a69cde3ce460..d061ffeb1e71 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h | |||
@@ -133,6 +133,9 @@ struct netns_ipv4 { | |||
133 | struct fib_rules_ops *mr_rules_ops; | 133 | struct fib_rules_ops *mr_rules_ops; |
134 | #endif | 134 | #endif |
135 | #endif | 135 | #endif |
136 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | ||
137 | int sysctl_fib_multipath_use_neigh; | ||
138 | #endif | ||
136 | atomic_t rt_genid; | 139 | atomic_t rt_genid; |
137 | }; | 140 | }; |
138 | #endif | 141 | #endif |
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 |
1562 | static 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 | ||
1563 | void fib_select_multipath(struct fib_result *res, int hash) | 1581 | void 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 | ||
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 1e1fe6086dd9..bb0419582b8d 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c | |||
@@ -960,6 +960,17 @@ static struct ctl_table ipv4_net_table[] = { | |||
960 | .mode = 0644, | 960 | .mode = 0644, |
961 | .proc_handler = proc_dointvec, | 961 | .proc_handler = proc_dointvec, |
962 | }, | 962 | }, |
963 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | ||
964 | { | ||
965 | .procname = "fib_multipath_use_neigh", | ||
966 | .data = &init_net.ipv4.sysctl_fib_multipath_use_neigh, | ||
967 | .maxlen = sizeof(int), | ||
968 | .mode = 0644, | ||
969 | .proc_handler = proc_dointvec_minmax, | ||
970 | .extra1 = &zero, | ||
971 | .extra2 = &one, | ||
972 | }, | ||
973 | #endif | ||
963 | { } | 974 | { } |
964 | }; | 975 | }; |
965 | 976 | ||