aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/inetdevice.h3
-rw-r--r--include/net/fib_rules.h3
-rw-r--r--include/net/ip_fib.h20
-rw-r--r--include/uapi/linux/ip.h1
-rw-r--r--include/uapi/linux/rtnetlink.h3
-rw-r--r--net/ipv4/devinet.c2
-rw-r--r--net/ipv4/fib_frontend.c29
-rw-r--r--net/ipv4/fib_rules.c5
-rw-r--r--net/ipv4/fib_semantics.c93
-rw-r--r--net/ipv4/fib_trie.c6
-rw-r--r--net/ipv4/netfilter/ipt_rpfilter.c2
-rw-r--r--net/ipv4/route.c10
12 files changed, 130 insertions, 47 deletions
diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
index 0a21fbefdfbe..a4328cea376a 100644
--- a/include/linux/inetdevice.h
+++ b/include/linux/inetdevice.h
@@ -120,6 +120,9 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev)
120 || (!IN_DEV_FORWARD(in_dev) && \ 120 || (!IN_DEV_FORWARD(in_dev) && \
121 IN_DEV_ORCONF((in_dev), ACCEPT_REDIRECTS))) 121 IN_DEV_ORCONF((in_dev), ACCEPT_REDIRECTS)))
122 122
123#define IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev) \
124 IN_DEV_CONF_GET((in_dev), IGNORE_ROUTES_WITH_LINKDOWN)
125
123#define IN_DEV_ARPFILTER(in_dev) IN_DEV_ORCONF((in_dev), ARPFILTER) 126#define IN_DEV_ARPFILTER(in_dev) IN_DEV_ORCONF((in_dev), ARPFILTER)
124#define IN_DEV_ARP_ACCEPT(in_dev) IN_DEV_ORCONF((in_dev), ARP_ACCEPT) 127#define IN_DEV_ARP_ACCEPT(in_dev) IN_DEV_ORCONF((in_dev), ARP_ACCEPT)
125#define IN_DEV_ARP_ANNOUNCE(in_dev) IN_DEV_MAXCONF((in_dev), ARP_ANNOUNCE) 128#define IN_DEV_ARP_ANNOUNCE(in_dev) IN_DEV_MAXCONF((in_dev), ARP_ANNOUNCE)
diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h
index 6d67383a5114..903a55efbffe 100644
--- a/include/net/fib_rules.h
+++ b/include/net/fib_rules.h
@@ -36,7 +36,8 @@ struct fib_lookup_arg {
36 void *result; 36 void *result;
37 struct fib_rule *rule; 37 struct fib_rule *rule;
38 int flags; 38 int flags;
39#define FIB_LOOKUP_NOREF 1 39#define FIB_LOOKUP_NOREF 1
40#define FIB_LOOKUP_IGNORE_LINKSTATE 2
40}; 41};
41 42
42struct fib_rules_ops { 43struct fib_rules_ops {
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index 54271ed0ed45..49c142bdf01e 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -226,7 +226,7 @@ static inline struct fib_table *fib_new_table(struct net *net, u32 id)
226} 226}
227 227
228static inline int fib_lookup(struct net *net, const struct flowi4 *flp, 228static inline int fib_lookup(struct net *net, const struct flowi4 *flp,
229 struct fib_result *res) 229 struct fib_result *res, unsigned int flags)
230{ 230{
231 struct fib_table *tb; 231 struct fib_table *tb;
232 int err = -ENETUNREACH; 232 int err = -ENETUNREACH;
@@ -234,7 +234,7 @@ static inline int fib_lookup(struct net *net, const struct flowi4 *flp,
234 rcu_read_lock(); 234 rcu_read_lock();
235 235
236 tb = fib_get_table(net, RT_TABLE_MAIN); 236 tb = fib_get_table(net, RT_TABLE_MAIN);
237 if (tb && !fib_table_lookup(tb, flp, res, FIB_LOOKUP_NOREF)) 237 if (tb && !fib_table_lookup(tb, flp, res, flags | FIB_LOOKUP_NOREF))
238 err = 0; 238 err = 0;
239 239
240 rcu_read_unlock(); 240 rcu_read_unlock();
@@ -249,16 +249,18 @@ void __net_exit fib4_rules_exit(struct net *net);
249struct fib_table *fib_new_table(struct net *net, u32 id); 249struct fib_table *fib_new_table(struct net *net, u32 id);
250struct fib_table *fib_get_table(struct net *net, u32 id); 250struct fib_table *fib_get_table(struct net *net, u32 id);
251 251
252int __fib_lookup(struct net *net, struct flowi4 *flp, struct fib_result *res); 252int __fib_lookup(struct net *net, struct flowi4 *flp,
253 struct fib_result *res, unsigned int flags);
253 254
254static inline int fib_lookup(struct net *net, struct flowi4 *flp, 255static inline int fib_lookup(struct net *net, struct flowi4 *flp,
255 struct fib_result *res) 256 struct fib_result *res, unsigned int flags)
256{ 257{
257 struct fib_table *tb; 258 struct fib_table *tb;
258 int err; 259 int err;
259 260
261 flags |= FIB_LOOKUP_NOREF;
260 if (net->ipv4.fib_has_custom_rules) 262 if (net->ipv4.fib_has_custom_rules)
261 return __fib_lookup(net, flp, res); 263 return __fib_lookup(net, flp, res, flags);
262 264
263 rcu_read_lock(); 265 rcu_read_lock();
264 266
@@ -266,11 +268,11 @@ static inline int fib_lookup(struct net *net, struct flowi4 *flp,
266 268
267 for (err = 0; !err; err = -ENETUNREACH) { 269 for (err = 0; !err; err = -ENETUNREACH) {
268 tb = rcu_dereference_rtnl(net->ipv4.fib_main); 270 tb = rcu_dereference_rtnl(net->ipv4.fib_main);
269 if (tb && !fib_table_lookup(tb, flp, res, FIB_LOOKUP_NOREF)) 271 if (tb && !fib_table_lookup(tb, flp, res, flags))
270 break; 272 break;
271 273
272 tb = rcu_dereference_rtnl(net->ipv4.fib_default); 274 tb = rcu_dereference_rtnl(net->ipv4.fib_default);
273 if (tb && !fib_table_lookup(tb, flp, res, FIB_LOOKUP_NOREF)) 275 if (tb && !fib_table_lookup(tb, flp, res, flags))
274 break; 276 break;
275 } 277 }
276 278
@@ -305,9 +307,9 @@ void fib_flush_external(struct net *net);
305 307
306/* Exported by fib_semantics.c */ 308/* Exported by fib_semantics.c */
307int ip_fib_check_default(__be32 gw, struct net_device *dev); 309int ip_fib_check_default(__be32 gw, struct net_device *dev);
308int fib_sync_down_dev(struct net_device *dev, int force); 310int fib_sync_down_dev(struct net_device *dev, unsigned long event);
309int fib_sync_down_addr(struct net *net, __be32 local); 311int fib_sync_down_addr(struct net *net, __be32 local);
310int fib_sync_up(struct net_device *dev); 312int fib_sync_up(struct net_device *dev, unsigned int nh_flags);
311void fib_select_multipath(struct fib_result *res); 313void fib_select_multipath(struct fib_result *res);
312 314
313/* Exported by fib_trie.c */ 315/* Exported by fib_trie.c */
diff --git a/include/uapi/linux/ip.h b/include/uapi/linux/ip.h
index 411959405ab6..08f894d2ddbd 100644
--- a/include/uapi/linux/ip.h
+++ b/include/uapi/linux/ip.h
@@ -164,6 +164,7 @@ enum
164 IPV4_DEVCONF_ROUTE_LOCALNET, 164 IPV4_DEVCONF_ROUTE_LOCALNET,
165 IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL, 165 IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL,
166 IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL, 166 IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL,
167 IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN,
167 __IPV4_DEVCONF_MAX 168 __IPV4_DEVCONF_MAX
168}; 169};
169 170
diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h
index 17fb02f488da..fdd8f07f1d34 100644
--- a/include/uapi/linux/rtnetlink.h
+++ b/include/uapi/linux/rtnetlink.h
@@ -338,6 +338,9 @@ struct rtnexthop {
338#define RTNH_F_PERVASIVE 2 /* Do recursive gateway lookup */ 338#define RTNH_F_PERVASIVE 2 /* Do recursive gateway lookup */
339#define RTNH_F_ONLINK 4 /* Gateway is forced on link */ 339#define RTNH_F_ONLINK 4 /* Gateway is forced on link */
340#define RTNH_F_OFFLOAD 8 /* offloaded route */ 340#define RTNH_F_OFFLOAD 8 /* offloaded route */
341#define RTNH_F_LINKDOWN 16 /* carrier-down on nexthop */
342
343#define RTNH_COMPARE_MASK (RTNH_F_DEAD | RTNH_F_LINKDOWN)
341 344
342/* Macros to handle hexthops */ 345/* Macros to handle hexthops */
343 346
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 419d23c53ec7..7498716e8f54 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -2169,6 +2169,8 @@ static struct devinet_sysctl_table {
2169 "igmpv2_unsolicited_report_interval"), 2169 "igmpv2_unsolicited_report_interval"),
2170 DEVINET_SYSCTL_RW_ENTRY(IGMPV3_UNSOLICITED_REPORT_INTERVAL, 2170 DEVINET_SYSCTL_RW_ENTRY(IGMPV3_UNSOLICITED_REPORT_INTERVAL,
2171 "igmpv3_unsolicited_report_interval"), 2171 "igmpv3_unsolicited_report_interval"),
2172 DEVINET_SYSCTL_RW_ENTRY(IGNORE_ROUTES_WITH_LINKDOWN,
2173 "ignore_routes_with_linkdown"),
2172 2174
2173 DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"), 2175 DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
2174 DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"), 2176 DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 872494e6e6eb..6bbc54940eb4 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -280,7 +280,7 @@ __be32 fib_compute_spec_dst(struct sk_buff *skb)
280 fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos); 280 fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos);
281 fl4.flowi4_scope = scope; 281 fl4.flowi4_scope = scope;
282 fl4.flowi4_mark = IN_DEV_SRC_VMARK(in_dev) ? skb->mark : 0; 282 fl4.flowi4_mark = IN_DEV_SRC_VMARK(in_dev) ? skb->mark : 0;
283 if (!fib_lookup(net, &fl4, &res)) 283 if (!fib_lookup(net, &fl4, &res, 0))
284 return FIB_RES_PREFSRC(net, res); 284 return FIB_RES_PREFSRC(net, res);
285 } else { 285 } else {
286 scope = RT_SCOPE_LINK; 286 scope = RT_SCOPE_LINK;
@@ -319,7 +319,7 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
319 fl4.flowi4_mark = IN_DEV_SRC_VMARK(idev) ? skb->mark : 0; 319 fl4.flowi4_mark = IN_DEV_SRC_VMARK(idev) ? skb->mark : 0;
320 320
321 net = dev_net(dev); 321 net = dev_net(dev);
322 if (fib_lookup(net, &fl4, &res)) 322 if (fib_lookup(net, &fl4, &res, 0))
323 goto last_resort; 323 goto last_resort;
324 if (res.type != RTN_UNICAST && 324 if (res.type != RTN_UNICAST &&
325 (res.type != RTN_LOCAL || !IN_DEV_ACCEPT_LOCAL(idev))) 325 (res.type != RTN_LOCAL || !IN_DEV_ACCEPT_LOCAL(idev)))
@@ -354,7 +354,7 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
354 fl4.flowi4_oif = dev->ifindex; 354 fl4.flowi4_oif = dev->ifindex;
355 355
356 ret = 0; 356 ret = 0;
357 if (fib_lookup(net, &fl4, &res) == 0) { 357 if (fib_lookup(net, &fl4, &res, FIB_LOOKUP_IGNORE_LINKSTATE) == 0) {
358 if (res.type == RTN_UNICAST) 358 if (res.type == RTN_UNICAST)
359 ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; 359 ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
360 } 360 }
@@ -1063,9 +1063,9 @@ static void nl_fib_lookup_exit(struct net *net)
1063 net->ipv4.fibnl = NULL; 1063 net->ipv4.fibnl = NULL;
1064} 1064}
1065 1065
1066static void fib_disable_ip(struct net_device *dev, int force) 1066static void fib_disable_ip(struct net_device *dev, unsigned long event)
1067{ 1067{
1068 if (fib_sync_down_dev(dev, force)) 1068 if (fib_sync_down_dev(dev, event))
1069 fib_flush(dev_net(dev)); 1069 fib_flush(dev_net(dev));
1070 rt_cache_flush(dev_net(dev)); 1070 rt_cache_flush(dev_net(dev));
1071 arp_ifdown(dev); 1071 arp_ifdown(dev);
@@ -1081,7 +1081,7 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event,
1081 case NETDEV_UP: 1081 case NETDEV_UP:
1082 fib_add_ifaddr(ifa); 1082 fib_add_ifaddr(ifa);
1083#ifdef CONFIG_IP_ROUTE_MULTIPATH 1083#ifdef CONFIG_IP_ROUTE_MULTIPATH
1084 fib_sync_up(dev); 1084 fib_sync_up(dev, RTNH_F_DEAD);
1085#endif 1085#endif
1086 atomic_inc(&net->ipv4.dev_addr_genid); 1086 atomic_inc(&net->ipv4.dev_addr_genid);
1087 rt_cache_flush(dev_net(dev)); 1087 rt_cache_flush(dev_net(dev));
@@ -1093,7 +1093,7 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event,
1093 /* Last address was deleted from this interface. 1093 /* Last address was deleted from this interface.
1094 * Disable IP. 1094 * Disable IP.
1095 */ 1095 */
1096 fib_disable_ip(dev, 1); 1096 fib_disable_ip(dev, event);
1097 } else { 1097 } else {
1098 rt_cache_flush(dev_net(dev)); 1098 rt_cache_flush(dev_net(dev));
1099 } 1099 }
@@ -1107,9 +1107,10 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo
1107 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 1107 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
1108 struct in_device *in_dev; 1108 struct in_device *in_dev;
1109 struct net *net = dev_net(dev); 1109 struct net *net = dev_net(dev);
1110 unsigned int flags;
1110 1111
1111 if (event == NETDEV_UNREGISTER) { 1112 if (event == NETDEV_UNREGISTER) {
1112 fib_disable_ip(dev, 2); 1113 fib_disable_ip(dev, event);
1113 rt_flush_dev(dev); 1114 rt_flush_dev(dev);
1114 return NOTIFY_DONE; 1115 return NOTIFY_DONE;
1115 } 1116 }
@@ -1124,16 +1125,22 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo
1124 fib_add_ifaddr(ifa); 1125 fib_add_ifaddr(ifa);
1125 } endfor_ifa(in_dev); 1126 } endfor_ifa(in_dev);
1126#ifdef CONFIG_IP_ROUTE_MULTIPATH 1127#ifdef CONFIG_IP_ROUTE_MULTIPATH
1127 fib_sync_up(dev); 1128 fib_sync_up(dev, RTNH_F_DEAD);
1128#endif 1129#endif
1129 atomic_inc(&net->ipv4.dev_addr_genid); 1130 atomic_inc(&net->ipv4.dev_addr_genid);
1130 rt_cache_flush(net); 1131 rt_cache_flush(net);
1131 break; 1132 break;
1132 case NETDEV_DOWN: 1133 case NETDEV_DOWN:
1133 fib_disable_ip(dev, 0); 1134 fib_disable_ip(dev, event);
1134 break; 1135 break;
1135 case NETDEV_CHANGEMTU:
1136 case NETDEV_CHANGE: 1136 case NETDEV_CHANGE:
1137 flags = dev_get_flags(dev);
1138 if (flags & (IFF_RUNNING | IFF_LOWER_UP))
1139 fib_sync_up(dev, RTNH_F_LINKDOWN);
1140 else
1141 fib_sync_down_dev(dev, event);
1142 /* fall through */
1143 case NETDEV_CHANGEMTU:
1137 rt_cache_flush(net); 1144 rt_cache_flush(net);
1138 break; 1145 break;
1139 } 1146 }
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
index 56151982f74e..18123d50f576 100644
--- a/net/ipv4/fib_rules.c
+++ b/net/ipv4/fib_rules.c
@@ -47,11 +47,12 @@ struct fib4_rule {
47#endif 47#endif
48}; 48};
49 49
50int __fib_lookup(struct net *net, struct flowi4 *flp, struct fib_result *res) 50int __fib_lookup(struct net *net, struct flowi4 *flp,
51 struct fib_result *res, unsigned int flags)
51{ 52{
52 struct fib_lookup_arg arg = { 53 struct fib_lookup_arg arg = {
53 .result = res, 54 .result = res,
54 .flags = FIB_LOOKUP_NOREF, 55 .flags = flags,
55 }; 56 };
56 int err; 57 int err;
57 58
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 28ec3c1823bf..3bfccd83551c 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -266,7 +266,7 @@ static inline int nh_comp(const struct fib_info *fi, const struct fib_info *ofi)
266#ifdef CONFIG_IP_ROUTE_CLASSID 266#ifdef CONFIG_IP_ROUTE_CLASSID
267 nh->nh_tclassid != onh->nh_tclassid || 267 nh->nh_tclassid != onh->nh_tclassid ||
268#endif 268#endif
269 ((nh->nh_flags ^ onh->nh_flags) & ~RTNH_F_DEAD)) 269 ((nh->nh_flags ^ onh->nh_flags) & ~RTNH_COMPARE_MASK))
270 return -1; 270 return -1;
271 onh++; 271 onh++;
272 } endfor_nexthops(fi); 272 } endfor_nexthops(fi);
@@ -318,7 +318,7 @@ static struct fib_info *fib_find_info(const struct fib_info *nfi)
318 nfi->fib_type == fi->fib_type && 318 nfi->fib_type == fi->fib_type &&
319 memcmp(nfi->fib_metrics, fi->fib_metrics, 319 memcmp(nfi->fib_metrics, fi->fib_metrics,
320 sizeof(u32) * RTAX_MAX) == 0 && 320 sizeof(u32) * RTAX_MAX) == 0 &&
321 ((nfi->fib_flags ^ fi->fib_flags) & ~RTNH_F_DEAD) == 0 && 321 !((nfi->fib_flags ^ fi->fib_flags) & ~RTNH_COMPARE_MASK) &&
322 (nfi->fib_nhs == 0 || nh_comp(fi, nfi) == 0)) 322 (nfi->fib_nhs == 0 || nh_comp(fi, nfi) == 0))
323 return fi; 323 return fi;
324 } 324 }
@@ -604,6 +604,8 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
604 return -ENODEV; 604 return -ENODEV;
605 if (!(dev->flags & IFF_UP)) 605 if (!(dev->flags & IFF_UP))
606 return -ENETDOWN; 606 return -ENETDOWN;
607 if (!netif_carrier_ok(dev))
608 nh->nh_flags |= RTNH_F_LINKDOWN;
607 nh->nh_dev = dev; 609 nh->nh_dev = dev;
608 dev_hold(dev); 610 dev_hold(dev);
609 nh->nh_scope = RT_SCOPE_LINK; 611 nh->nh_scope = RT_SCOPE_LINK;
@@ -621,7 +623,8 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
621 /* It is not necessary, but requires a bit of thinking */ 623 /* It is not necessary, but requires a bit of thinking */
622 if (fl4.flowi4_scope < RT_SCOPE_LINK) 624 if (fl4.flowi4_scope < RT_SCOPE_LINK)
623 fl4.flowi4_scope = RT_SCOPE_LINK; 625 fl4.flowi4_scope = RT_SCOPE_LINK;
624 err = fib_lookup(net, &fl4, &res); 626 err = fib_lookup(net, &fl4, &res,
627 FIB_LOOKUP_IGNORE_LINKSTATE);
625 if (err) { 628 if (err) {
626 rcu_read_unlock(); 629 rcu_read_unlock();
627 return err; 630 return err;
@@ -636,6 +639,8 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
636 if (!dev) 639 if (!dev)
637 goto out; 640 goto out;
638 dev_hold(dev); 641 dev_hold(dev);
642 if (!netif_carrier_ok(dev))
643 nh->nh_flags |= RTNH_F_LINKDOWN;
639 err = (dev->flags & IFF_UP) ? 0 : -ENETDOWN; 644 err = (dev->flags & IFF_UP) ? 0 : -ENETDOWN;
640 } else { 645 } else {
641 struct in_device *in_dev; 646 struct in_device *in_dev;
@@ -654,6 +659,8 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
654 nh->nh_dev = in_dev->dev; 659 nh->nh_dev = in_dev->dev;
655 dev_hold(nh->nh_dev); 660 dev_hold(nh->nh_dev);
656 nh->nh_scope = RT_SCOPE_HOST; 661 nh->nh_scope = RT_SCOPE_HOST;
662 if (!netif_carrier_ok(nh->nh_dev))
663 nh->nh_flags |= RTNH_F_LINKDOWN;
657 err = 0; 664 err = 0;
658 } 665 }
659out: 666out:
@@ -920,11 +927,17 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
920 if (!nh->nh_dev) 927 if (!nh->nh_dev)
921 goto failure; 928 goto failure;
922 } else { 929 } else {
930 int linkdown = 0;
931
923 change_nexthops(fi) { 932 change_nexthops(fi) {
924 err = fib_check_nh(cfg, fi, nexthop_nh); 933 err = fib_check_nh(cfg, fi, nexthop_nh);
925 if (err != 0) 934 if (err != 0)
926 goto failure; 935 goto failure;
936 if (nexthop_nh->nh_flags & RTNH_F_LINKDOWN)
937 linkdown++;
927 } endfor_nexthops(fi) 938 } endfor_nexthops(fi)
939 if (linkdown == fi->fib_nhs)
940 fi->fib_flags |= RTNH_F_LINKDOWN;
928 } 941 }
929 942
930 if (fi->fib_prefsrc) { 943 if (fi->fib_prefsrc) {
@@ -1023,12 +1036,20 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
1023 nla_put_in_addr(skb, RTA_PREFSRC, fi->fib_prefsrc)) 1036 nla_put_in_addr(skb, RTA_PREFSRC, fi->fib_prefsrc))
1024 goto nla_put_failure; 1037 goto nla_put_failure;
1025 if (fi->fib_nhs == 1) { 1038 if (fi->fib_nhs == 1) {
1039 struct in_device *in_dev;
1040
1026 if (fi->fib_nh->nh_gw && 1041 if (fi->fib_nh->nh_gw &&
1027 nla_put_in_addr(skb, RTA_GATEWAY, fi->fib_nh->nh_gw)) 1042 nla_put_in_addr(skb, RTA_GATEWAY, fi->fib_nh->nh_gw))
1028 goto nla_put_failure; 1043 goto nla_put_failure;
1029 if (fi->fib_nh->nh_oif && 1044 if (fi->fib_nh->nh_oif &&
1030 nla_put_u32(skb, RTA_OIF, fi->fib_nh->nh_oif)) 1045 nla_put_u32(skb, RTA_OIF, fi->fib_nh->nh_oif))
1031 goto nla_put_failure; 1046 goto nla_put_failure;
1047 if (fi->fib_nh->nh_flags & RTNH_F_LINKDOWN) {
1048 in_dev = __in_dev_get_rcu(fi->fib_nh->nh_dev);
1049 if (in_dev &&
1050 IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev))
1051 rtm->rtm_flags |= RTNH_F_DEAD;
1052 }
1032#ifdef CONFIG_IP_ROUTE_CLASSID 1053#ifdef CONFIG_IP_ROUTE_CLASSID
1033 if (fi->fib_nh[0].nh_tclassid && 1054 if (fi->fib_nh[0].nh_tclassid &&
1034 nla_put_u32(skb, RTA_FLOW, fi->fib_nh[0].nh_tclassid)) 1055 nla_put_u32(skb, RTA_FLOW, fi->fib_nh[0].nh_tclassid))
@@ -1045,11 +1066,19 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
1045 goto nla_put_failure; 1066 goto nla_put_failure;
1046 1067
1047 for_nexthops(fi) { 1068 for_nexthops(fi) {
1069 struct in_device *in_dev;
1070
1048 rtnh = nla_reserve_nohdr(skb, sizeof(*rtnh)); 1071 rtnh = nla_reserve_nohdr(skb, sizeof(*rtnh));
1049 if (!rtnh) 1072 if (!rtnh)
1050 goto nla_put_failure; 1073 goto nla_put_failure;
1051 1074
1052 rtnh->rtnh_flags = nh->nh_flags & 0xFF; 1075 rtnh->rtnh_flags = nh->nh_flags & 0xFF;
1076 if (nh->nh_flags & RTNH_F_LINKDOWN) {
1077 in_dev = __in_dev_get_rcu(nh->nh_dev);
1078 if (in_dev &&
1079 IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev))
1080 rtnh->rtnh_flags |= RTNH_F_DEAD;
1081 }
1053 rtnh->rtnh_hops = nh->nh_weight - 1; 1082 rtnh->rtnh_hops = nh->nh_weight - 1;
1054 rtnh->rtnh_ifindex = nh->nh_oif; 1083 rtnh->rtnh_ifindex = nh->nh_oif;
1055 1084
@@ -1103,7 +1132,7 @@ int fib_sync_down_addr(struct net *net, __be32 local)
1103 return ret; 1132 return ret;
1104} 1133}
1105 1134
1106int fib_sync_down_dev(struct net_device *dev, int force) 1135int fib_sync_down_dev(struct net_device *dev, unsigned long event)
1107{ 1136{
1108 int ret = 0; 1137 int ret = 0;
1109 int scope = RT_SCOPE_NOWHERE; 1138 int scope = RT_SCOPE_NOWHERE;
@@ -1112,7 +1141,8 @@ int fib_sync_down_dev(struct net_device *dev, int force)
1112 struct hlist_head *head = &fib_info_devhash[hash]; 1141 struct hlist_head *head = &fib_info_devhash[hash];
1113 struct fib_nh *nh; 1142 struct fib_nh *nh;
1114 1143
1115 if (force) 1144 if (event == NETDEV_UNREGISTER ||
1145 event == NETDEV_DOWN)
1116 scope = -1; 1146 scope = -1;
1117 1147
1118 hlist_for_each_entry(nh, head, nh_hash) { 1148 hlist_for_each_entry(nh, head, nh_hash) {
@@ -1129,7 +1159,15 @@ int fib_sync_down_dev(struct net_device *dev, int force)
1129 dead++; 1159 dead++;
1130 else if (nexthop_nh->nh_dev == dev && 1160 else if (nexthop_nh->nh_dev == dev &&
1131 nexthop_nh->nh_scope != scope) { 1161 nexthop_nh->nh_scope != scope) {
1132 nexthop_nh->nh_flags |= RTNH_F_DEAD; 1162 switch (event) {
1163 case NETDEV_DOWN:
1164 case NETDEV_UNREGISTER:
1165 nexthop_nh->nh_flags |= RTNH_F_DEAD;
1166 /* fall through */
1167 case NETDEV_CHANGE:
1168 nexthop_nh->nh_flags |= RTNH_F_LINKDOWN;
1169 break;
1170 }
1133#ifdef CONFIG_IP_ROUTE_MULTIPATH 1171#ifdef CONFIG_IP_ROUTE_MULTIPATH
1134 spin_lock_bh(&fib_multipath_lock); 1172 spin_lock_bh(&fib_multipath_lock);
1135 fi->fib_power -= nexthop_nh->nh_power; 1173 fi->fib_power -= nexthop_nh->nh_power;
@@ -1139,14 +1177,23 @@ int fib_sync_down_dev(struct net_device *dev, int force)
1139 dead++; 1177 dead++;
1140 } 1178 }
1141#ifdef CONFIG_IP_ROUTE_MULTIPATH 1179#ifdef CONFIG_IP_ROUTE_MULTIPATH
1142 if (force > 1 && nexthop_nh->nh_dev == dev) { 1180 if (event == NETDEV_UNREGISTER &&
1181 nexthop_nh->nh_dev == dev) {
1143 dead = fi->fib_nhs; 1182 dead = fi->fib_nhs;
1144 break; 1183 break;
1145 } 1184 }
1146#endif 1185#endif
1147 } endfor_nexthops(fi) 1186 } endfor_nexthops(fi)
1148 if (dead == fi->fib_nhs) { 1187 if (dead == fi->fib_nhs) {
1149 fi->fib_flags |= RTNH_F_DEAD; 1188 switch (event) {
1189 case NETDEV_DOWN:
1190 case NETDEV_UNREGISTER:
1191 fi->fib_flags |= RTNH_F_DEAD;
1192 /* fall through */
1193 case NETDEV_CHANGE:
1194 fi->fib_flags |= RTNH_F_LINKDOWN;
1195 break;
1196 }
1150 ret++; 1197 ret++;
1151 } 1198 }
1152 } 1199 }
@@ -1210,13 +1257,11 @@ out:
1210 return; 1257 return;
1211} 1258}
1212 1259
1213#ifdef CONFIG_IP_ROUTE_MULTIPATH
1214
1215/* 1260/*
1216 * Dead device goes up. We wake up dead nexthops. 1261 * Dead device goes up. We wake up dead nexthops.
1217 * It takes sense only on multipath routes. 1262 * It takes sense only on multipath routes.
1218 */ 1263 */
1219int fib_sync_up(struct net_device *dev) 1264int fib_sync_up(struct net_device *dev, unsigned int nh_flags)
1220{ 1265{
1221 struct fib_info *prev_fi; 1266 struct fib_info *prev_fi;
1222 unsigned int hash; 1267 unsigned int hash;
@@ -1243,7 +1288,7 @@ int fib_sync_up(struct net_device *dev)
1243 prev_fi = fi; 1288 prev_fi = fi;
1244 alive = 0; 1289 alive = 0;
1245 change_nexthops(fi) { 1290 change_nexthops(fi) {
1246 if (!(nexthop_nh->nh_flags & RTNH_F_DEAD)) { 1291 if (!(nexthop_nh->nh_flags & nh_flags)) {
1247 alive++; 1292 alive++;
1248 continue; 1293 continue;
1249 } 1294 }
@@ -1254,14 +1299,18 @@ int fib_sync_up(struct net_device *dev)
1254 !__in_dev_get_rtnl(dev)) 1299 !__in_dev_get_rtnl(dev))
1255 continue; 1300 continue;
1256 alive++; 1301 alive++;
1302#ifdef CONFIG_IP_ROUTE_MULTIPATH
1257 spin_lock_bh(&fib_multipath_lock); 1303 spin_lock_bh(&fib_multipath_lock);
1258 nexthop_nh->nh_power = 0; 1304 nexthop_nh->nh_power = 0;
1259 nexthop_nh->nh_flags &= ~RTNH_F_DEAD; 1305 nexthop_nh->nh_flags &= ~nh_flags;
1260 spin_unlock_bh(&fib_multipath_lock); 1306 spin_unlock_bh(&fib_multipath_lock);
1307#else
1308 nexthop_nh->nh_flags &= ~nh_flags;
1309#endif
1261 } endfor_nexthops(fi) 1310 } endfor_nexthops(fi)
1262 1311
1263 if (alive > 0) { 1312 if (alive > 0) {
1264 fi->fib_flags &= ~RTNH_F_DEAD; 1313 fi->fib_flags &= ~nh_flags;
1265 ret++; 1314 ret++;
1266 } 1315 }
1267 } 1316 }
@@ -1269,6 +1318,8 @@ int fib_sync_up(struct net_device *dev)
1269 return ret; 1318 return ret;
1270} 1319}
1271 1320
1321#ifdef CONFIG_IP_ROUTE_MULTIPATH
1322
1272/* 1323/*
1273 * The algorithm is suboptimal, but it provides really 1324 * The algorithm is suboptimal, but it provides really
1274 * fair weighted route distribution. 1325 * fair weighted route distribution.
@@ -1276,16 +1327,22 @@ int fib_sync_up(struct net_device *dev)
1276void fib_select_multipath(struct fib_result *res) 1327void fib_select_multipath(struct fib_result *res)
1277{ 1328{
1278 struct fib_info *fi = res->fi; 1329 struct fib_info *fi = res->fi;
1330 struct in_device *in_dev;
1279 int w; 1331 int w;
1280 1332
1281 spin_lock_bh(&fib_multipath_lock); 1333 spin_lock_bh(&fib_multipath_lock);
1282 if (fi->fib_power <= 0) { 1334 if (fi->fib_power <= 0) {
1283 int power = 0; 1335 int power = 0;
1284 change_nexthops(fi) { 1336 change_nexthops(fi) {
1285 if (!(nexthop_nh->nh_flags & RTNH_F_DEAD)) { 1337 in_dev = __in_dev_get_rcu(nexthop_nh->nh_dev);
1286 power += nexthop_nh->nh_weight; 1338 if (nexthop_nh->nh_flags & RTNH_F_DEAD)
1287 nexthop_nh->nh_power = nexthop_nh->nh_weight; 1339 continue;
1288 } 1340 if (in_dev &&
1341 IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev) &&
1342 nexthop_nh->nh_flags & RTNH_F_LINKDOWN)
1343 continue;
1344 power += nexthop_nh->nh_weight;
1345 nexthop_nh->nh_power = nexthop_nh->nh_weight;
1289 } endfor_nexthops(fi); 1346 } endfor_nexthops(fi);
1290 fi->fib_power = power; 1347 fi->fib_power = power;
1291 if (power <= 0) { 1348 if (power <= 0) {
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 6c666a9f1bd5..15d32612e3c6 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -1412,9 +1412,15 @@ found:
1412 continue; 1412 continue;
1413 for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) { 1413 for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) {
1414 const struct fib_nh *nh = &fi->fib_nh[nhsel]; 1414 const struct fib_nh *nh = &fi->fib_nh[nhsel];
1415 struct in_device *in_dev = __in_dev_get_rcu(nh->nh_dev);
1415 1416
1416 if (nh->nh_flags & RTNH_F_DEAD) 1417 if (nh->nh_flags & RTNH_F_DEAD)
1417 continue; 1418 continue;
1419 if (in_dev &&
1420 IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev) &&
1421 nh->nh_flags & RTNH_F_LINKDOWN &&
1422 !(fib_flags & FIB_LOOKUP_IGNORE_LINKSTATE))
1423 continue;
1418 if (flp->flowi4_oif && flp->flowi4_oif != nh->nh_oif) 1424 if (flp->flowi4_oif && flp->flowi4_oif != nh->nh_oif)
1419 continue; 1425 continue;
1420 1426
diff --git a/net/ipv4/netfilter/ipt_rpfilter.c b/net/ipv4/netfilter/ipt_rpfilter.c
index 4bfaedf9b34e..8618fd150c96 100644
--- a/net/ipv4/netfilter/ipt_rpfilter.c
+++ b/net/ipv4/netfilter/ipt_rpfilter.c
@@ -40,7 +40,7 @@ static bool rpfilter_lookup_reverse(struct flowi4 *fl4,
40 struct net *net = dev_net(dev); 40 struct net *net = dev_net(dev);
41 int ret __maybe_unused; 41 int ret __maybe_unused;
42 42
43 if (fib_lookup(net, fl4, &res)) 43 if (fib_lookup(net, fl4, &res, FIB_LOOKUP_IGNORE_LINKSTATE))
44 return false; 44 return false;
45 45
46 if (res.type != RTN_UNICAST) { 46 if (res.type != RTN_UNICAST) {
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index f6055984c307..d0362a2de3d3 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -747,7 +747,7 @@ static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flow
747 if (!(n->nud_state & NUD_VALID)) { 747 if (!(n->nud_state & NUD_VALID)) {
748 neigh_event_send(n, NULL); 748 neigh_event_send(n, NULL);
749 } else { 749 } else {
750 if (fib_lookup(net, fl4, &res) == 0) { 750 if (fib_lookup(net, fl4, &res, 0) == 0) {
751 struct fib_nh *nh = &FIB_RES_NH(res); 751 struct fib_nh *nh = &FIB_RES_NH(res);
752 752
753 update_or_create_fnhe(nh, fl4->daddr, new_gw, 753 update_or_create_fnhe(nh, fl4->daddr, new_gw,
@@ -975,7 +975,7 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu)
975 return; 975 return;
976 976
977 rcu_read_lock(); 977 rcu_read_lock();
978 if (fib_lookup(dev_net(dst->dev), fl4, &res) == 0) { 978 if (fib_lookup(dev_net(dst->dev), fl4, &res, 0) == 0) {
979 struct fib_nh *nh = &FIB_RES_NH(res); 979 struct fib_nh *nh = &FIB_RES_NH(res);
980 980
981 update_or_create_fnhe(nh, fl4->daddr, 0, mtu, 981 update_or_create_fnhe(nh, fl4->daddr, 0, mtu,
@@ -1186,7 +1186,7 @@ void ip_rt_get_source(u8 *addr, struct sk_buff *skb, struct rtable *rt)
1186 fl4.flowi4_mark = skb->mark; 1186 fl4.flowi4_mark = skb->mark;
1187 1187
1188 rcu_read_lock(); 1188 rcu_read_lock();
1189 if (fib_lookup(dev_net(rt->dst.dev), &fl4, &res) == 0) 1189 if (fib_lookup(dev_net(rt->dst.dev), &fl4, &res, 0) == 0)
1190 src = FIB_RES_PREFSRC(dev_net(rt->dst.dev), res); 1190 src = FIB_RES_PREFSRC(dev_net(rt->dst.dev), res);
1191 else 1191 else
1192 src = inet_select_addr(rt->dst.dev, 1192 src = inet_select_addr(rt->dst.dev,
@@ -1716,7 +1716,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
1716 fl4.flowi4_scope = RT_SCOPE_UNIVERSE; 1716 fl4.flowi4_scope = RT_SCOPE_UNIVERSE;
1717 fl4.daddr = daddr; 1717 fl4.daddr = daddr;
1718 fl4.saddr = saddr; 1718 fl4.saddr = saddr;
1719 err = fib_lookup(net, &fl4, &res); 1719 err = fib_lookup(net, &fl4, &res, 0);
1720 if (err != 0) { 1720 if (err != 0) {
1721 if (!IN_DEV_FORWARD(in_dev)) 1721 if (!IN_DEV_FORWARD(in_dev))
1722 err = -EHOSTUNREACH; 1722 err = -EHOSTUNREACH;
@@ -2123,7 +2123,7 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4)
2123 goto make_route; 2123 goto make_route;
2124 } 2124 }
2125 2125
2126 if (fib_lookup(net, fl4, &res)) { 2126 if (fib_lookup(net, fl4, &res, 0)) {
2127 res.fi = NULL; 2127 res.fi = NULL;
2128 res.table = NULL; 2128 res.table = NULL;
2129 if (fl4->flowi4_oif) { 2129 if (fl4->flowi4_oif) {