summaryrefslogtreecommitdiffstats
path: root/net/ipv6/route.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r--net/ipv6/route.c74
1 files changed, 52 insertions, 22 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index bdbc38e8bf29..947ed1ded026 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -102,11 +102,13 @@ static int rt6_score_route(struct rt6_info *rt, int oif, int strict);
102#ifdef CONFIG_IPV6_ROUTE_INFO 102#ifdef CONFIG_IPV6_ROUTE_INFO
103static struct rt6_info *rt6_add_route_info(struct net *net, 103static struct rt6_info *rt6_add_route_info(struct net *net,
104 const struct in6_addr *prefix, int prefixlen, 104 const struct in6_addr *prefix, int prefixlen,
105 const struct in6_addr *gwaddr, int ifindex, 105 const struct in6_addr *gwaddr,
106 struct net_device *dev,
106 unsigned int pref); 107 unsigned int pref);
107static struct rt6_info *rt6_get_route_info(struct net *net, 108static struct rt6_info *rt6_get_route_info(struct net *net,
108 const struct in6_addr *prefix, int prefixlen, 109 const struct in6_addr *prefix, int prefixlen,
109 const struct in6_addr *gwaddr, int ifindex); 110 const struct in6_addr *gwaddr,
111 struct net_device *dev);
110#endif 112#endif
111 113
112struct uncached_list { 114struct uncached_list {
@@ -656,7 +658,8 @@ static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict,
656 struct net_device *dev = rt->dst.dev; 658 struct net_device *dev = rt->dst.dev;
657 659
658 if (dev && !netif_carrier_ok(dev) && 660 if (dev && !netif_carrier_ok(dev) &&
659 idev->cnf.ignore_routes_with_linkdown) 661 idev->cnf.ignore_routes_with_linkdown &&
662 !(strict & RT6_LOOKUP_F_IGNORE_LINKSTATE))
660 goto out; 663 goto out;
661 664
662 if (rt6_check_expired(rt)) 665 if (rt6_check_expired(rt))
@@ -803,7 +806,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
803 rt = rt6_get_dflt_router(gwaddr, dev); 806 rt = rt6_get_dflt_router(gwaddr, dev);
804 else 807 else
805 rt = rt6_get_route_info(net, prefix, rinfo->prefix_len, 808 rt = rt6_get_route_info(net, prefix, rinfo->prefix_len,
806 gwaddr, dev->ifindex); 809 gwaddr, dev);
807 810
808 if (rt && !lifetime) { 811 if (rt && !lifetime) {
809 ip6_del_rt(rt); 812 ip6_del_rt(rt);
@@ -811,8 +814,8 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
811 } 814 }
812 815
813 if (!rt && lifetime) 816 if (!rt && lifetime)
814 rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr, dev->ifindex, 817 rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr,
815 pref); 818 dev, pref);
816 else if (rt) 819 else if (rt)
817 rt->rt6i_flags = RTF_ROUTEINFO | 820 rt->rt6i_flags = RTF_ROUTEINFO |
818 (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref); 821 (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
@@ -1050,6 +1053,7 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
1050 int strict = 0; 1053 int strict = 0;
1051 1054
1052 strict |= flags & RT6_LOOKUP_F_IFACE; 1055 strict |= flags & RT6_LOOKUP_F_IFACE;
1056 strict |= flags & RT6_LOOKUP_F_IGNORE_LINKSTATE;
1053 if (net->ipv6.devconf_all->forwarding == 0) 1057 if (net->ipv6.devconf_all->forwarding == 0)
1054 strict |= RT6_LOOKUP_F_REACHABLE; 1058 strict |= RT6_LOOKUP_F_REACHABLE;
1055 1059
@@ -1789,7 +1793,7 @@ static struct rt6_info *ip6_nh_lookup_table(struct net *net,
1789 }; 1793 };
1790 struct fib6_table *table; 1794 struct fib6_table *table;
1791 struct rt6_info *rt; 1795 struct rt6_info *rt;
1792 int flags = RT6_LOOKUP_F_IFACE; 1796 int flags = RT6_LOOKUP_F_IFACE | RT6_LOOKUP_F_IGNORE_LINKSTATE;
1793 1797
1794 table = fib6_get_table(net, cfg->fc_table); 1798 table = fib6_get_table(net, cfg->fc_table);
1795 if (!table) 1799 if (!table)
@@ -2325,13 +2329,16 @@ static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort)
2325#ifdef CONFIG_IPV6_ROUTE_INFO 2329#ifdef CONFIG_IPV6_ROUTE_INFO
2326static struct rt6_info *rt6_get_route_info(struct net *net, 2330static struct rt6_info *rt6_get_route_info(struct net *net,
2327 const struct in6_addr *prefix, int prefixlen, 2331 const struct in6_addr *prefix, int prefixlen,
2328 const struct in6_addr *gwaddr, int ifindex) 2332 const struct in6_addr *gwaddr,
2333 struct net_device *dev)
2329{ 2334{
2335 u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO;
2336 int ifindex = dev->ifindex;
2330 struct fib6_node *fn; 2337 struct fib6_node *fn;
2331 struct rt6_info *rt = NULL; 2338 struct rt6_info *rt = NULL;
2332 struct fib6_table *table; 2339 struct fib6_table *table;
2333 2340
2334 table = fib6_get_table(net, RT6_TABLE_INFO); 2341 table = fib6_get_table(net, tb_id);
2335 if (!table) 2342 if (!table)
2336 return NULL; 2343 return NULL;
2337 2344
@@ -2357,12 +2364,13 @@ out:
2357 2364
2358static struct rt6_info *rt6_add_route_info(struct net *net, 2365static struct rt6_info *rt6_add_route_info(struct net *net,
2359 const struct in6_addr *prefix, int prefixlen, 2366 const struct in6_addr *prefix, int prefixlen,
2360 const struct in6_addr *gwaddr, int ifindex, 2367 const struct in6_addr *gwaddr,
2368 struct net_device *dev,
2361 unsigned int pref) 2369 unsigned int pref)
2362{ 2370{
2363 struct fib6_config cfg = { 2371 struct fib6_config cfg = {
2364 .fc_metric = IP6_RT_PRIO_USER, 2372 .fc_metric = IP6_RT_PRIO_USER,
2365 .fc_ifindex = ifindex, 2373 .fc_ifindex = dev->ifindex,
2366 .fc_dst_len = prefixlen, 2374 .fc_dst_len = prefixlen,
2367 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO | 2375 .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
2368 RTF_UP | RTF_PREF(pref), 2376 RTF_UP | RTF_PREF(pref),
@@ -2371,7 +2379,7 @@ static struct rt6_info *rt6_add_route_info(struct net *net,
2371 .fc_nlinfo.nl_net = net, 2379 .fc_nlinfo.nl_net = net,
2372 }; 2380 };
2373 2381
2374 cfg.fc_table = l3mdev_fib_table_by_index(net, ifindex) ? : RT6_TABLE_INFO; 2382 cfg.fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO,
2375 cfg.fc_dst = *prefix; 2383 cfg.fc_dst = *prefix;
2376 cfg.fc_gateway = *gwaddr; 2384 cfg.fc_gateway = *gwaddr;
2377 2385
@@ -2381,16 +2389,17 @@ static struct rt6_info *rt6_add_route_info(struct net *net,
2381 2389
2382 ip6_route_add(&cfg); 2390 ip6_route_add(&cfg);
2383 2391
2384 return rt6_get_route_info(net, prefix, prefixlen, gwaddr, ifindex); 2392 return rt6_get_route_info(net, prefix, prefixlen, gwaddr, dev);
2385} 2393}
2386#endif 2394#endif
2387 2395
2388struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev) 2396struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev)
2389{ 2397{
2398 u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT;
2390 struct rt6_info *rt; 2399 struct rt6_info *rt;
2391 struct fib6_table *table; 2400 struct fib6_table *table;
2392 2401
2393 table = fib6_get_table(dev_net(dev), RT6_TABLE_DFLT); 2402 table = fib6_get_table(dev_net(dev), tb_id);
2394 if (!table) 2403 if (!table)
2395 return NULL; 2404 return NULL;
2396 2405
@@ -2424,20 +2433,20 @@ struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
2424 2433
2425 cfg.fc_gateway = *gwaddr; 2434 cfg.fc_gateway = *gwaddr;
2426 2435
2427 ip6_route_add(&cfg); 2436 if (!ip6_route_add(&cfg)) {
2437 struct fib6_table *table;
2438
2439 table = fib6_get_table(dev_net(dev), cfg.fc_table);
2440 if (table)
2441 table->flags |= RT6_TABLE_HAS_DFLT_ROUTER;
2442 }
2428 2443
2429 return rt6_get_dflt_router(gwaddr, dev); 2444 return rt6_get_dflt_router(gwaddr, dev);
2430} 2445}
2431 2446
2432void rt6_purge_dflt_routers(struct net *net) 2447static void __rt6_purge_dflt_routers(struct fib6_table *table)
2433{ 2448{
2434 struct rt6_info *rt; 2449 struct rt6_info *rt;
2435 struct fib6_table *table;
2436
2437 /* NOTE: Keep consistent with rt6_get_dflt_router */
2438 table = fib6_get_table(net, RT6_TABLE_DFLT);
2439 if (!table)
2440 return;
2441 2450
2442restart: 2451restart:
2443 read_lock_bh(&table->tb6_lock); 2452 read_lock_bh(&table->tb6_lock);
@@ -2451,6 +2460,27 @@ restart:
2451 } 2460 }
2452 } 2461 }
2453 read_unlock_bh(&table->tb6_lock); 2462 read_unlock_bh(&table->tb6_lock);
2463
2464 table->flags &= ~RT6_TABLE_HAS_DFLT_ROUTER;
2465}
2466
2467void rt6_purge_dflt_routers(struct net *net)
2468{
2469 struct fib6_table *table;
2470 struct hlist_head *head;
2471 unsigned int h;
2472
2473 rcu_read_lock();
2474
2475 for (h = 0; h < FIB6_TABLE_HASHSZ; h++) {
2476 head = &net->ipv6.fib_table_hash[h];
2477 hlist_for_each_entry_rcu(table, head, tb6_hlist) {
2478 if (table->flags & RT6_TABLE_HAS_DFLT_ROUTER)
2479 __rt6_purge_dflt_routers(table);
2480 }
2481 }
2482
2483 rcu_read_unlock();
2454} 2484}
2455 2485
2456static void rtmsg_to_fib6_config(struct net *net, 2486static void rtmsg_to_fib6_config(struct net *net,