route.c (ddb9e13af3bba3f8c36ccee0eb9563a82b425c12) | route.c (31afeb425f7fad8bcf9561aeb0b8405479f97a98) |
---|---|
1/* 2 * Linux INET6 implementation 3 * FIB front-end. 4 * 5 * Authors: 6 * Pedro Roque <roque@di.fc.ul.pt> 7 * 8 * This program is free software; you can redistribute it and/or --- 172 unchanged lines hidden (view full) --- 181 } 182 } 183 spin_unlock_bh(&ul->lock); 184 } 185} 186 187static u32 *rt6_pcpu_cow_metrics(struct rt6_info *rt) 188{ | 1/* 2 * Linux INET6 implementation 3 * FIB front-end. 4 * 5 * Authors: 6 * Pedro Roque <roque@di.fc.ul.pt> 7 * 8 * This program is free software; you can redistribute it and/or --- 172 unchanged lines hidden (view full) --- 181 } 182 } 183 spin_unlock_bh(&ul->lock); 184 } 185} 186 187static u32 *rt6_pcpu_cow_metrics(struct rt6_info *rt) 188{ |
189 return dst_metrics_write_ptr(rt->dst.from); | 189 return dst_metrics_write_ptr(&rt->from->dst); |
190} 191 192static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old) 193{ 194 struct rt6_info *rt = (struct rt6_info *)dst; 195 196 if (rt->rt6i_flags & RTF_PCPU) 197 return rt6_pcpu_cow_metrics(rt); --- 188 unchanged lines hidden (view full) --- 386 return rt; 387} 388EXPORT_SYMBOL(ip6_dst_alloc); 389 390static void ip6_dst_destroy(struct dst_entry *dst) 391{ 392 struct rt6_info *rt = (struct rt6_info *)dst; 393 struct rt6_exception_bucket *bucket; | 190} 191 192static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old) 193{ 194 struct rt6_info *rt = (struct rt6_info *)dst; 195 196 if (rt->rt6i_flags & RTF_PCPU) 197 return rt6_pcpu_cow_metrics(rt); --- 188 unchanged lines hidden (view full) --- 386 return rt; 387} 388EXPORT_SYMBOL(ip6_dst_alloc); 389 390static void ip6_dst_destroy(struct dst_entry *dst) 391{ 392 struct rt6_info *rt = (struct rt6_info *)dst; 393 struct rt6_exception_bucket *bucket; |
394 struct dst_entry *from = dst->from; | 394 struct rt6_info *from = rt->from; |
395 struct inet6_dev *idev; 396 397 dst_destroy_metrics_generic(dst); 398 free_percpu(rt->rt6i_pcpu); 399 rt6_uncached_list_del(rt); 400 401 idev = rt->rt6i_idev; 402 if (idev) { 403 rt->rt6i_idev = NULL; 404 in6_dev_put(idev); 405 } 406 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket, 1); 407 if (bucket) { 408 rt->rt6i_exception_bucket = NULL; 409 kfree(bucket); 410 } 411 | 395 struct inet6_dev *idev; 396 397 dst_destroy_metrics_generic(dst); 398 free_percpu(rt->rt6i_pcpu); 399 rt6_uncached_list_del(rt); 400 401 idev = rt->rt6i_idev; 402 if (idev) { 403 rt->rt6i_idev = NULL; 404 in6_dev_put(idev); 405 } 406 bucket = rcu_dereference_protected(rt->rt6i_exception_bucket, 1); 407 if (bucket) { 408 rt->rt6i_exception_bucket = NULL; 409 kfree(bucket); 410 } 411 |
412 dst->from = NULL; 413 dst_release(from); | 412 rt->from = NULL; 413 dst_release(&from->dst); |
414} 415 416static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, 417 int how) 418{ 419 struct rt6_info *rt = (struct rt6_info *)dst; 420 struct inet6_dev *idev = rt->rt6i_idev; 421 struct net_device *loopback_dev = --- 16 unchanged lines hidden (view full) --- 438 return false; 439} 440 441static bool rt6_check_expired(const struct rt6_info *rt) 442{ 443 if (rt->rt6i_flags & RTF_EXPIRES) { 444 if (time_after(jiffies, rt->dst.expires)) 445 return true; | 414} 415 416static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, 417 int how) 418{ 419 struct rt6_info *rt = (struct rt6_info *)dst; 420 struct inet6_dev *idev = rt->rt6i_idev; 421 struct net_device *loopback_dev = --- 16 unchanged lines hidden (view full) --- 438 return false; 439} 440 441static bool rt6_check_expired(const struct rt6_info *rt) 442{ 443 if (rt->rt6i_flags & RTF_EXPIRES) { 444 if (time_after(jiffies, rt->dst.expires)) 445 return true; |
446 } else if (rt->dst.from) { | 446 } else if (rt->from) { |
447 return rt->dst.obsolete != DST_OBSOLETE_FORCE_CHK || | 447 return rt->dst.obsolete != DST_OBSOLETE_FORCE_CHK || |
448 rt6_check_expired((struct rt6_info *)rt->dst.from); | 448 rt6_check_expired(rt->from); |
449 } 450 return false; 451} 452 453static struct rt6_info *rt6_multipath_select(struct rt6_info *match, 454 struct flowi6 *fl6, int oif, 455 int strict) 456{ 457 struct rt6_info *sibling, *next_sibling; | 449 } 450 return false; 451} 452 453static struct rt6_info *rt6_multipath_select(struct rt6_info *match, 454 struct flowi6 *fl6, int oif, 455 int strict) 456{ 457 struct rt6_info *sibling, *next_sibling; |
458 int route_choosen; | |
459 460 /* We might have already computed the hash for ICMPv6 errors. In such 461 * case it will always be non-zero. Otherwise now is the time to do it. 462 */ 463 if (!fl6->mp_hash) 464 fl6->mp_hash = rt6_multipath_hash(fl6, NULL); 465 | 458 459 /* We might have already computed the hash for ICMPv6 errors. In such 460 * case it will always be non-zero. Otherwise now is the time to do it. 461 */ 462 if (!fl6->mp_hash) 463 fl6->mp_hash = rt6_multipath_hash(fl6, NULL); 464 |
466 route_choosen = fl6->mp_hash % (match->rt6i_nsiblings + 1); 467 /* Don't change the route, if route_choosen == 0 468 * (siblings does not include ourself) 469 */ 470 if (route_choosen) 471 list_for_each_entry_safe(sibling, next_sibling, 472 &match->rt6i_siblings, rt6i_siblings) { 473 route_choosen--; 474 if (route_choosen == 0) { 475 struct inet6_dev *idev = sibling->rt6i_idev; | 465 if (fl6->mp_hash <= atomic_read(&match->rt6i_nh_upper_bound)) 466 return match; |
476 | 467 |
477 if (!netif_carrier_ok(sibling->dst.dev) && 478 idev->cnf.ignore_routes_with_linkdown) 479 break; 480 if (rt6_score_route(sibling, oif, strict) < 0) 481 break; 482 match = sibling; 483 break; 484 } 485 } | 468 list_for_each_entry_safe(sibling, next_sibling, &match->rt6i_siblings, 469 rt6i_siblings) { 470 if (fl6->mp_hash > atomic_read(&sibling->rt6i_nh_upper_bound)) 471 continue; 472 if (rt6_score_route(sibling, oif, strict) < 0) 473 break; 474 match = sibling; 475 break; 476 } 477 |
486 return match; 487} 488 489/* 490 * Route lookup. rcu_read_lock() should be held. 491 */ 492 493static inline struct rt6_info *rt6_device_match(struct net *net, 494 struct rt6_info *rt, 495 const struct in6_addr *saddr, 496 int oif, 497 int flags) 498{ 499 struct rt6_info *local = NULL; 500 struct rt6_info *sprt; 501 | 478 return match; 479} 480 481/* 482 * Route lookup. rcu_read_lock() should be held. 483 */ 484 485static inline struct rt6_info *rt6_device_match(struct net *net, 486 struct rt6_info *rt, 487 const struct in6_addr *saddr, 488 int oif, 489 int flags) 490{ 491 struct rt6_info *local = NULL; 492 struct rt6_info *sprt; 493 |
502 if (!oif && ipv6_addr_any(saddr)) 503 goto out; | 494 if (!oif && ipv6_addr_any(saddr) && !(rt->rt6i_nh_flags & RTNH_F_DEAD)) 495 return rt; |
504 | 496 |
505 for (sprt = rt; sprt; sprt = rcu_dereference(sprt->dst.rt6_next)) { | 497 for (sprt = rt; sprt; sprt = rcu_dereference(sprt->rt6_next)) { |
506 struct net_device *dev = sprt->dst.dev; 507 | 498 struct net_device *dev = sprt->dst.dev; 499 |
500 if (sprt->rt6i_nh_flags & RTNH_F_DEAD) 501 continue; 502 |
|
508 if (oif) { 509 if (dev->ifindex == oif) 510 return sprt; 511 if (dev->flags & IFF_LOOPBACK) { 512 if (!sprt->rt6i_idev || 513 sprt->rt6i_idev->dev->ifindex != oif) { 514 if (flags & RT6_LOOKUP_F_IFACE) 515 continue; --- 12 unchanged lines hidden (view full) --- 528 529 if (oif) { 530 if (local) 531 return local; 532 533 if (flags & RT6_LOOKUP_F_IFACE) 534 return net->ipv6.ip6_null_entry; 535 } | 503 if (oif) { 504 if (dev->ifindex == oif) 505 return sprt; 506 if (dev->flags & IFF_LOOPBACK) { 507 if (!sprt->rt6i_idev || 508 sprt->rt6i_idev->dev->ifindex != oif) { 509 if (flags & RT6_LOOKUP_F_IFACE) 510 continue; --- 12 unchanged lines hidden (view full) --- 523 524 if (oif) { 525 if (local) 526 return local; 527 528 if (flags & RT6_LOOKUP_F_IFACE) 529 return net->ipv6.ip6_null_entry; 530 } |
536out: 537 return rt; | 531 532 return rt->rt6i_nh_flags & RTNH_F_DEAD ? net->ipv6.ip6_null_entry : rt; |
538} 539 540#ifdef CONFIG_IPV6_ROUTER_PREF 541struct __rt6_probe_work { 542 struct work_struct work; 543 struct in6_addr target; 544 struct net_device *dev; 545}; --- 128 unchanged lines hidden (view full) --- 674 675static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict, 676 int *mpri, struct rt6_info *match, 677 bool *do_rr) 678{ 679 int m; 680 bool match_do_rr = false; 681 struct inet6_dev *idev = rt->rt6i_idev; | 533} 534 535#ifdef CONFIG_IPV6_ROUTER_PREF 536struct __rt6_probe_work { 537 struct work_struct work; 538 struct in6_addr target; 539 struct net_device *dev; 540}; --- 128 unchanged lines hidden (view full) --- 669 670static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict, 671 int *mpri, struct rt6_info *match, 672 bool *do_rr) 673{ 674 int m; 675 bool match_do_rr = false; 676 struct inet6_dev *idev = rt->rt6i_idev; |
682 struct net_device *dev = rt->dst.dev; | |
683 | 677 |
684 if (dev && !netif_carrier_ok(dev) && 685 idev->cnf.ignore_routes_with_linkdown && | 678 if (rt->rt6i_nh_flags & RTNH_F_DEAD) 679 goto out; 680 681 if (idev->cnf.ignore_routes_with_linkdown && 682 rt->rt6i_nh_flags & RTNH_F_LINKDOWN && |
686 !(strict & RT6_LOOKUP_F_IGNORE_LINKSTATE)) 687 goto out; 688 689 if (rt6_check_expired(rt)) 690 goto out; 691 692 m = rt6_score_route(rt, oif, strict); 693 if (m == RT6_NUD_FAIL_DO_RR) { --- 22 unchanged lines hidden (view full) --- 716 u32 metric, int oif, int strict, 717 bool *do_rr) 718{ 719 struct rt6_info *rt, *match, *cont; 720 int mpri = -1; 721 722 match = NULL; 723 cont = NULL; | 683 !(strict & RT6_LOOKUP_F_IGNORE_LINKSTATE)) 684 goto out; 685 686 if (rt6_check_expired(rt)) 687 goto out; 688 689 m = rt6_score_route(rt, oif, strict); 690 if (m == RT6_NUD_FAIL_DO_RR) { --- 22 unchanged lines hidden (view full) --- 713 u32 metric, int oif, int strict, 714 bool *do_rr) 715{ 716 struct rt6_info *rt, *match, *cont; 717 int mpri = -1; 718 719 match = NULL; 720 cont = NULL; |
724 for (rt = rr_head; rt; rt = rcu_dereference(rt->dst.rt6_next)) { | 721 for (rt = rr_head; rt; rt = rcu_dereference(rt->rt6_next)) { |
725 if (rt->rt6i_metric != metric) { 726 cont = rt; 727 break; 728 } 729 730 match = find_match(rt, oif, strict, &mpri, match, do_rr); 731 } 732 733 for (rt = leaf; rt && rt != rr_head; | 722 if (rt->rt6i_metric != metric) { 723 cont = rt; 724 break; 725 } 726 727 match = find_match(rt, oif, strict, &mpri, match, do_rr); 728 } 729 730 for (rt = leaf; rt && rt != rr_head; |
734 rt = rcu_dereference(rt->dst.rt6_next)) { | 731 rt = rcu_dereference(rt->rt6_next)) { |
735 if (rt->rt6i_metric != metric) { 736 cont = rt; 737 break; 738 } 739 740 match = find_match(rt, oif, strict, &mpri, match, do_rr); 741 } 742 743 if (match || !cont) 744 return match; 745 | 732 if (rt->rt6i_metric != metric) { 733 cont = rt; 734 break; 735 } 736 737 match = find_match(rt, oif, strict, &mpri, match, do_rr); 738 } 739 740 if (match || !cont) 741 return match; 742 |
746 for (rt = cont; rt; rt = rcu_dereference(rt->dst.rt6_next)) | 743 for (rt = cont; rt; rt = rcu_dereference(rt->rt6_next)) |
747 match = find_match(rt, oif, strict, &mpri, match, do_rr); 748 749 return match; 750} 751 752static struct rt6_info *rt6_select(struct net *net, struct fib6_node *fn, 753 int oif, int strict) 754{ --- 21 unchanged lines hidden (view full) --- 776#endif 777 if (fn->fn_bit != key_plen) 778 return net->ipv6.ip6_null_entry; 779 780 match = find_rr_leaf(fn, leaf, rt0, rt0->rt6i_metric, oif, strict, 781 &do_rr); 782 783 if (do_rr) { | 744 match = find_match(rt, oif, strict, &mpri, match, do_rr); 745 746 return match; 747} 748 749static struct rt6_info *rt6_select(struct net *net, struct fib6_node *fn, 750 int oif, int strict) 751{ --- 21 unchanged lines hidden (view full) --- 773#endif 774 if (fn->fn_bit != key_plen) 775 return net->ipv6.ip6_null_entry; 776 777 match = find_rr_leaf(fn, leaf, rt0, rt0->rt6i_metric, oif, strict, 778 &do_rr); 779 780 if (do_rr) { |
784 struct rt6_info *next = rcu_dereference(rt0->dst.rt6_next); | 781 struct rt6_info *next = rcu_dereference(rt0->rt6_next); |
785 786 /* no entries matched; do round-robin */ 787 if (!next || next->rt6i_metric != rt0->rt6i_metric) 788 next = leaf; 789 790 if (next != rt0) { 791 spin_lock_bh(&leaf->rt6i_table->tb6_lock); 792 /* make sure next is not being deleted from the tree */ --- 256 unchanged lines hidden (view full) --- 1049 struct net_device *dev; 1050 struct rt6_info *rt; 1051 1052 /* 1053 * Clone the route. 1054 */ 1055 1056 if (ort->rt6i_flags & (RTF_CACHE | RTF_PCPU)) | 782 783 /* no entries matched; do round-robin */ 784 if (!next || next->rt6i_metric != rt0->rt6i_metric) 785 next = leaf; 786 787 if (next != rt0) { 788 spin_lock_bh(&leaf->rt6i_table->tb6_lock); 789 /* make sure next is not being deleted from the tree */ --- 256 unchanged lines hidden (view full) --- 1046 struct net_device *dev; 1047 struct rt6_info *rt; 1048 1049 /* 1050 * Clone the route. 1051 */ 1052 1053 if (ort->rt6i_flags & (RTF_CACHE | RTF_PCPU)) |
1057 ort = (struct rt6_info *)ort->dst.from; | 1054 ort = ort->from; |
1058 1059 rcu_read_lock(); 1060 dev = ip6_rt_get_dev_rcu(ort); 1061 rt = __ip6_dst_alloc(dev_net(dev), dev, 0); 1062 rcu_read_unlock(); 1063 if (!rt) 1064 return NULL; 1065 --- 203 unchanged lines hidden (view full) --- 1269 struct net *net = dev_net(ort->dst.dev); 1270 struct rt6_exception_bucket *bucket; 1271 struct in6_addr *src_key = NULL; 1272 struct rt6_exception *rt6_ex; 1273 int err = 0; 1274 1275 /* ort can't be a cache or pcpu route */ 1276 if (ort->rt6i_flags & (RTF_CACHE | RTF_PCPU)) | 1055 1056 rcu_read_lock(); 1057 dev = ip6_rt_get_dev_rcu(ort); 1058 rt = __ip6_dst_alloc(dev_net(dev), dev, 0); 1059 rcu_read_unlock(); 1060 if (!rt) 1061 return NULL; 1062 --- 203 unchanged lines hidden (view full) --- 1266 struct net *net = dev_net(ort->dst.dev); 1267 struct rt6_exception_bucket *bucket; 1268 struct in6_addr *src_key = NULL; 1269 struct rt6_exception *rt6_ex; 1270 int err = 0; 1271 1272 /* ort can't be a cache or pcpu route */ 1273 if (ort->rt6i_flags & (RTF_CACHE | RTF_PCPU)) |
1277 ort = (struct rt6_info *)ort->dst.from; | 1274 ort = ort->from; |
1278 WARN_ON_ONCE(ort->rt6i_flags & (RTF_CACHE | RTF_PCPU)); 1279 1280 spin_lock_bh(&rt6_exception_lock); 1281 1282 if (ort->exception_bucket_flushed) { 1283 err = -EINVAL; 1284 goto out; 1285 } --- 55 unchanged lines hidden (view full) --- 1341 if (bucket->depth > FIB6_MAX_DEPTH) 1342 rt6_exception_remove_oldest(bucket); 1343 1344out: 1345 spin_unlock_bh(&rt6_exception_lock); 1346 1347 /* Update fn->fn_sernum to invalidate all cached dst */ 1348 if (!err) { | 1275 WARN_ON_ONCE(ort->rt6i_flags & (RTF_CACHE | RTF_PCPU)); 1276 1277 spin_lock_bh(&rt6_exception_lock); 1278 1279 if (ort->exception_bucket_flushed) { 1280 err = -EINVAL; 1281 goto out; 1282 } --- 55 unchanged lines hidden (view full) --- 1338 if (bucket->depth > FIB6_MAX_DEPTH) 1339 rt6_exception_remove_oldest(bucket); 1340 1341out: 1342 spin_unlock_bh(&rt6_exception_lock); 1343 1344 /* Update fn->fn_sernum to invalidate all cached dst */ 1345 if (!err) { |
1346 spin_lock_bh(&ort->rt6i_table->tb6_lock); |
|
1349 fib6_update_sernum(ort); | 1347 fib6_update_sernum(ort); |
1348 spin_unlock_bh(&ort->rt6i_table->tb6_lock); |
|
1350 fib6_force_start_gc(net); 1351 } 1352 1353 return err; 1354} 1355 1356void rt6_flush_exceptions(struct rt6_info *rt) 1357{ --- 52 unchanged lines hidden (view full) --- 1410 res = rt6_ex->rt6i; 1411 1412 return res; 1413} 1414 1415/* Remove the passed in cached rt from the hash table that contains it */ 1416int rt6_remove_exception_rt(struct rt6_info *rt) 1417{ | 1349 fib6_force_start_gc(net); 1350 } 1351 1352 return err; 1353} 1354 1355void rt6_flush_exceptions(struct rt6_info *rt) 1356{ --- 52 unchanged lines hidden (view full) --- 1409 res = rt6_ex->rt6i; 1410 1411 return res; 1412} 1413 1414/* Remove the passed in cached rt from the hash table that contains it */ 1415int rt6_remove_exception_rt(struct rt6_info *rt) 1416{ |
1418 struct rt6_info *from = (struct rt6_info *)rt->dst.from; | |
1419 struct rt6_exception_bucket *bucket; | 1417 struct rt6_exception_bucket *bucket; |
1418 struct rt6_info *from = rt->from; |
|
1420 struct in6_addr *src_key = NULL; 1421 struct rt6_exception *rt6_ex; 1422 int err; 1423 1424 if (!from || 1425 !(rt->rt6i_flags & RTF_CACHE)) 1426 return -EINVAL; 1427 --- 27 unchanged lines hidden (view full) --- 1455 return err; 1456} 1457 1458/* Find rt6_ex which contains the passed in rt cache and 1459 * refresh its stamp 1460 */ 1461static void rt6_update_exception_stamp_rt(struct rt6_info *rt) 1462{ | 1419 struct in6_addr *src_key = NULL; 1420 struct rt6_exception *rt6_ex; 1421 int err; 1422 1423 if (!from || 1424 !(rt->rt6i_flags & RTF_CACHE)) 1425 return -EINVAL; 1426 --- 27 unchanged lines hidden (view full) --- 1454 return err; 1455} 1456 1457/* Find rt6_ex which contains the passed in rt cache and 1458 * refresh its stamp 1459 */ 1460static void rt6_update_exception_stamp_rt(struct rt6_info *rt) 1461{ |
1463 struct rt6_info *from = (struct rt6_info *)rt->dst.from; | |
1464 struct rt6_exception_bucket *bucket; | 1462 struct rt6_exception_bucket *bucket; |
1463 struct rt6_info *from = rt->from; |
|
1465 struct in6_addr *src_key = NULL; 1466 struct rt6_exception *rt6_ex; 1467 1468 if (!from || 1469 !(rt->rt6i_flags & RTF_CACHE)) 1470 return; 1471 1472 rcu_read_lock(); --- 108 unchanged lines hidden (view full) --- 1581 struct rt6_info *rt = rt6_ex->rt6i; 1582 1583 /* we are pruning and obsoleting aged-out and non gateway exceptions 1584 * even if others have still references to them, so that on next 1585 * dst_check() such references can be dropped. 1586 * EXPIRES exceptions - e.g. pmtu-generated ones are pruned when 1587 * expired, independently from their aging, as per RFC 8201 section 4 1588 */ | 1464 struct in6_addr *src_key = NULL; 1465 struct rt6_exception *rt6_ex; 1466 1467 if (!from || 1468 !(rt->rt6i_flags & RTF_CACHE)) 1469 return; 1470 1471 rcu_read_lock(); --- 108 unchanged lines hidden (view full) --- 1580 struct rt6_info *rt = rt6_ex->rt6i; 1581 1582 /* we are pruning and obsoleting aged-out and non gateway exceptions 1583 * even if others have still references to them, so that on next 1584 * dst_check() such references can be dropped. 1585 * EXPIRES exceptions - e.g. pmtu-generated ones are pruned when 1586 * expired, independently from their aging, as per RFC 8201 section 4 1587 */ |
1589 if (!(rt->rt6i_flags & RTF_EXPIRES) && 1590 time_after_eq(now, rt->dst.lastuse + gc_args->timeout)) { 1591 RT6_TRACE("aging clone %p\n", rt); | 1588 if (!(rt->rt6i_flags & RTF_EXPIRES)) { 1589 if (time_after_eq(now, rt->dst.lastuse + gc_args->timeout)) { 1590 RT6_TRACE("aging clone %p\n", rt); 1591 rt6_remove_exception(bucket, rt6_ex); 1592 return; 1593 } 1594 } else if (time_after(jiffies, rt->dst.expires)) { 1595 RT6_TRACE("purging expired route %p\n", rt); |
1592 rt6_remove_exception(bucket, rt6_ex); 1593 return; | 1596 rt6_remove_exception(bucket, rt6_ex); 1597 return; |
1594 } else if (rt->rt6i_flags & RTF_GATEWAY) { | 1598 } 1599 1600 if (rt->rt6i_flags & RTF_GATEWAY) { |
1595 struct neighbour *neigh; 1596 __u8 neigh_flags = 0; 1597 1598 neigh = dst_neigh_lookup(&rt->dst, &rt->rt6i_gateway); 1599 if (neigh) { 1600 neigh_flags = neigh->flags; 1601 neigh_release(neigh); 1602 } 1603 if (!(neigh_flags & NTF_ROUTER)) { 1604 RT6_TRACE("purging route %p via non-router but gateway\n", 1605 rt); 1606 rt6_remove_exception(bucket, rt6_ex); 1607 return; 1608 } | 1601 struct neighbour *neigh; 1602 __u8 neigh_flags = 0; 1603 1604 neigh = dst_neigh_lookup(&rt->dst, &rt->rt6i_gateway); 1605 if (neigh) { 1606 neigh_flags = neigh->flags; 1607 neigh_release(neigh); 1608 } 1609 if (!(neigh_flags & NTF_ROUTER)) { 1610 RT6_TRACE("purging route %p via non-router but gateway\n", 1611 rt); 1612 rt6_remove_exception(bucket, rt6_ex); 1613 return; 1614 } |
1609 } else if (__rt6_check_expired(rt)) { 1610 RT6_TRACE("purging expired route %p\n", rt); 1611 rt6_remove_exception(bucket, rt6_ex); 1612 return; | |
1613 } | 1615 } |
1616 |
|
1614 gc_args->more++; 1615} 1616 1617void rt6_age_exceptions(struct rt6_info *rt, 1618 struct fib6_gc_args *gc_args, 1619 unsigned long now) 1620{ 1621 struct rt6_exception_bucket *bucket; --- 197 unchanged lines hidden (view full) --- 1819 1820/* if skb is set it will be used and fl6 can be NULL */ 1821u32 rt6_multipath_hash(const struct flowi6 *fl6, const struct sk_buff *skb) 1822{ 1823 struct flow_keys hash_keys; 1824 1825 if (skb) { 1826 ip6_multipath_l3_keys(skb, &hash_keys); | 1617 gc_args->more++; 1618} 1619 1620void rt6_age_exceptions(struct rt6_info *rt, 1621 struct fib6_gc_args *gc_args, 1622 unsigned long now) 1623{ 1624 struct rt6_exception_bucket *bucket; --- 197 unchanged lines hidden (view full) --- 1822 1823/* if skb is set it will be used and fl6 can be NULL */ 1824u32 rt6_multipath_hash(const struct flowi6 *fl6, const struct sk_buff *skb) 1825{ 1826 struct flow_keys hash_keys; 1827 1828 if (skb) { 1829 ip6_multipath_l3_keys(skb, &hash_keys); |
1827 return flow_hash_from_keys(&hash_keys); | 1830 return flow_hash_from_keys(&hash_keys) >> 1; |
1828 } 1829 | 1831 } 1832 |
1830 return get_hash_from_flowi6(fl6); | 1833 return get_hash_from_flowi6(fl6) >> 1; |
1831} 1832 1833void ip6_route_input(struct sk_buff *skb) 1834{ 1835 const struct ipv6hdr *iph = ipv6_hdr(skb); 1836 struct net *net = dev_net(skb->dev); 1837 int flags = RT6_LOOKUP_F_HAS_SADDR; 1838 struct ip_tunnel_info *tun_info; --- 85 unchanged lines hidden (view full) --- 1924} 1925 1926/* 1927 * Destination cache support functions 1928 */ 1929 1930static void rt6_dst_from_metrics_check(struct rt6_info *rt) 1931{ | 1834} 1835 1836void ip6_route_input(struct sk_buff *skb) 1837{ 1838 const struct ipv6hdr *iph = ipv6_hdr(skb); 1839 struct net *net = dev_net(skb->dev); 1840 int flags = RT6_LOOKUP_F_HAS_SADDR; 1841 struct ip_tunnel_info *tun_info; --- 85 unchanged lines hidden (view full) --- 1927} 1928 1929/* 1930 * Destination cache support functions 1931 */ 1932 1933static void rt6_dst_from_metrics_check(struct rt6_info *rt) 1934{ |
1932 if (rt->dst.from && 1933 dst_metrics_ptr(&rt->dst) != dst_metrics_ptr(rt->dst.from)) 1934 dst_init_metrics(&rt->dst, dst_metrics_ptr(rt->dst.from), true); | 1935 if (rt->from && 1936 dst_metrics_ptr(&rt->dst) != dst_metrics_ptr(&rt->from->dst)) 1937 dst_init_metrics(&rt->dst, dst_metrics_ptr(&rt->from->dst), true); |
1935} 1936 1937static struct dst_entry *rt6_check(struct rt6_info *rt, u32 cookie) 1938{ 1939 u32 rt_cookie = 0; 1940 1941 if (!rt6_get_cookie_safe(rt, &rt_cookie) || rt_cookie != cookie) 1942 return NULL; 1943 1944 if (rt6_check_expired(rt)) 1945 return NULL; 1946 1947 return &rt->dst; 1948} 1949 1950static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt, u32 cookie) 1951{ 1952 if (!__rt6_check_expired(rt) && 1953 rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK && | 1938} 1939 1940static struct dst_entry *rt6_check(struct rt6_info *rt, u32 cookie) 1941{ 1942 u32 rt_cookie = 0; 1943 1944 if (!rt6_get_cookie_safe(rt, &rt_cookie) || rt_cookie != cookie) 1945 return NULL; 1946 1947 if (rt6_check_expired(rt)) 1948 return NULL; 1949 1950 return &rt->dst; 1951} 1952 1953static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt, u32 cookie) 1954{ 1955 if (!__rt6_check_expired(rt) && 1956 rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK && |
1954 rt6_check((struct rt6_info *)(rt->dst.from), cookie)) | 1957 rt6_check(rt->from, cookie)) |
1955 return &rt->dst; 1956 else 1957 return NULL; 1958} 1959 1960static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie) 1961{ 1962 struct rt6_info *rt; 1963 1964 rt = (struct rt6_info *) dst; 1965 1966 /* All IPV6 dsts are created with ->obsolete set to the value 1967 * DST_OBSOLETE_FORCE_CHK which forces validation calls down 1968 * into this function always. 1969 */ 1970 1971 rt6_dst_from_metrics_check(rt); 1972 1973 if (rt->rt6i_flags & RTF_PCPU || | 1958 return &rt->dst; 1959 else 1960 return NULL; 1961} 1962 1963static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie) 1964{ 1965 struct rt6_info *rt; 1966 1967 rt = (struct rt6_info *) dst; 1968 1969 /* All IPV6 dsts are created with ->obsolete set to the value 1970 * DST_OBSOLETE_FORCE_CHK which forces validation calls down 1971 * into this function always. 1972 */ 1973 1974 rt6_dst_from_metrics_check(rt); 1975 1976 if (rt->rt6i_flags & RTF_PCPU || |
1974 (unlikely(!list_empty(&rt->rt6i_uncached)) && rt->dst.from)) | 1977 (unlikely(!list_empty(&rt->rt6i_uncached)) && rt->from)) |
1975 return rt6_dst_from_check(rt, cookie); 1976 else 1977 return rt6_check(rt, cookie); 1978} 1979 1980static struct dst_entry *ip6_negative_advice(struct dst_entry *dst) 1981{ 1982 struct rt6_info *rt = (struct rt6_info *) dst; --- 166 unchanged lines hidden (view full) --- 2149 * is a bit fuzzy and one might need to check all possible 2150 * routes. 2151 */ 2152 2153 rcu_read_lock(); 2154 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr); 2155restart: 2156 for_each_fib6_node_rt_rcu(fn) { | 1978 return rt6_dst_from_check(rt, cookie); 1979 else 1980 return rt6_check(rt, cookie); 1981} 1982 1983static struct dst_entry *ip6_negative_advice(struct dst_entry *dst) 1984{ 1985 struct rt6_info *rt = (struct rt6_info *) dst; --- 166 unchanged lines hidden (view full) --- 2152 * is a bit fuzzy and one might need to check all possible 2153 * routes. 2154 */ 2155 2156 rcu_read_lock(); 2157 fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr); 2158restart: 2159 for_each_fib6_node_rt_rcu(fn) { |
2160 if (rt->rt6i_nh_flags & RTNH_F_DEAD) 2161 continue; |
|
2157 if (rt6_check_expired(rt)) 2158 continue; 2159 if (rt->dst.error) 2160 break; 2161 if (!(rt->rt6i_flags & RTF_GATEWAY)) 2162 continue; 2163 if (fl6->flowi6_oif != rt->dst.dev->ifindex) 2164 continue; --- 174 unchanged lines hidden (view full) --- 2339 rt->dst.input = ip6_input; 2340 rt->dst.output = ip6_output; 2341 rt->rt6i_gateway = fl6->daddr; 2342 rt->rt6i_dst.addr = fl6->daddr; 2343 rt->rt6i_dst.plen = 128; 2344 rt->rt6i_idev = idev; 2345 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0); 2346 | 2162 if (rt6_check_expired(rt)) 2163 continue; 2164 if (rt->dst.error) 2165 break; 2166 if (!(rt->rt6i_flags & RTF_GATEWAY)) 2167 continue; 2168 if (fl6->flowi6_oif != rt->dst.dev->ifindex) 2169 continue; --- 174 unchanged lines hidden (view full) --- 2344 rt->dst.input = ip6_input; 2345 rt->dst.output = ip6_output; 2346 rt->rt6i_gateway = fl6->daddr; 2347 rt->rt6i_dst.addr = fl6->daddr; 2348 rt->rt6i_dst.plen = 128; 2349 rt->rt6i_idev = idev; 2350 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0); 2351 |
2347 /* Add this dst into uncached_list so that rt6_ifdown() can | 2352 /* Add this dst into uncached_list so that rt6_disable_ip() can |
2348 * do proper release of the net_device 2349 */ 2350 rt6_uncached_list_add(rt); 2351 atomic_inc(&net->ipv6.rt6_stats->fib_rt_uncache); 2352 2353 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0); 2354 2355out: --- 78 unchanged lines hidden (view full) --- 2434 return 0; 2435 err: 2436 kfree(mp); 2437 return -EINVAL; 2438} 2439 2440static struct rt6_info *ip6_nh_lookup_table(struct net *net, 2441 struct fib6_config *cfg, | 2353 * do proper release of the net_device 2354 */ 2355 rt6_uncached_list_add(rt); 2356 atomic_inc(&net->ipv6.rt6_stats->fib_rt_uncache); 2357 2358 dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0); 2359 2360out: --- 78 unchanged lines hidden (view full) --- 2439 return 0; 2440 err: 2441 kfree(mp); 2442 return -EINVAL; 2443} 2444 2445static struct rt6_info *ip6_nh_lookup_table(struct net *net, 2446 struct fib6_config *cfg, |
2442 const struct in6_addr *gw_addr) | 2447 const struct in6_addr *gw_addr, 2448 u32 tbid, int flags) |
2443{ 2444 struct flowi6 fl6 = { 2445 .flowi6_oif = cfg->fc_ifindex, 2446 .daddr = *gw_addr, 2447 .saddr = cfg->fc_prefsrc, 2448 }; 2449 struct fib6_table *table; 2450 struct rt6_info *rt; | 2449{ 2450 struct flowi6 fl6 = { 2451 .flowi6_oif = cfg->fc_ifindex, 2452 .daddr = *gw_addr, 2453 .saddr = cfg->fc_prefsrc, 2454 }; 2455 struct fib6_table *table; 2456 struct rt6_info *rt; |
2451 int flags = RT6_LOOKUP_F_IFACE | RT6_LOOKUP_F_IGNORE_LINKSTATE; | |
2452 | 2457 |
2453 table = fib6_get_table(net, cfg->fc_table); | 2458 table = fib6_get_table(net, tbid); |
2454 if (!table) 2455 return NULL; 2456 2457 if (!ipv6_addr_any(&cfg->fc_prefsrc)) 2458 flags |= RT6_LOOKUP_F_HAS_SADDR; 2459 | 2459 if (!table) 2460 return NULL; 2461 2462 if (!ipv6_addr_any(&cfg->fc_prefsrc)) 2463 flags |= RT6_LOOKUP_F_HAS_SADDR; 2464 |
2465 flags |= RT6_LOOKUP_F_IGNORE_LINKSTATE; |
|
2460 rt = ip6_pol_route(net, table, cfg->fc_ifindex, &fl6, flags); 2461 2462 /* if table lookup failed, fall back to full lookup */ 2463 if (rt == net->ipv6.ip6_null_entry) { 2464 ip6_rt_put(rt); 2465 rt = NULL; 2466 } 2467 2468 return rt; 2469} 2470 | 2466 rt = ip6_pol_route(net, table, cfg->fc_ifindex, &fl6, flags); 2467 2468 /* if table lookup failed, fall back to full lookup */ 2469 if (rt == net->ipv6.ip6_null_entry) { 2470 ip6_rt_put(rt); 2471 rt = NULL; 2472 } 2473 2474 return rt; 2475} 2476 |
2477static int ip6_route_check_nh_onlink(struct net *net, 2478 struct fib6_config *cfg, 2479 struct net_device *dev, 2480 struct netlink_ext_ack *extack) 2481{ 2482 u32 tbid = l3mdev_fib_table(dev) ? : RT_TABLE_LOCAL; 2483 const struct in6_addr *gw_addr = &cfg->fc_gateway; 2484 u32 flags = RTF_LOCAL | RTF_ANYCAST | RTF_REJECT; 2485 struct rt6_info *grt; 2486 int err; 2487 2488 err = 0; 2489 grt = ip6_nh_lookup_table(net, cfg, gw_addr, tbid, 0); 2490 if (grt) { 2491 if (grt->rt6i_flags & flags || dev != grt->dst.dev) { 2492 NL_SET_ERR_MSG(extack, "Nexthop has invalid gateway"); 2493 err = -EINVAL; 2494 } 2495 2496 ip6_rt_put(grt); 2497 } 2498 2499 return err; 2500} 2501 2502static int ip6_route_check_nh(struct net *net, 2503 struct fib6_config *cfg, 2504 struct net_device **_dev, 2505 struct inet6_dev **idev) 2506{ 2507 const struct in6_addr *gw_addr = &cfg->fc_gateway; 2508 struct net_device *dev = _dev ? *_dev : NULL; 2509 struct rt6_info *grt = NULL; 2510 int err = -EHOSTUNREACH; 2511 2512 if (cfg->fc_table) { 2513 int flags = RT6_LOOKUP_F_IFACE; 2514 2515 grt = ip6_nh_lookup_table(net, cfg, gw_addr, 2516 cfg->fc_table, flags); 2517 if (grt) { 2518 if (grt->rt6i_flags & RTF_GATEWAY || 2519 (dev && dev != grt->dst.dev)) { 2520 ip6_rt_put(grt); 2521 grt = NULL; 2522 } 2523 } 2524 } 2525 2526 if (!grt) 2527 grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, 1); 2528 2529 if (!grt) 2530 goto out; 2531 2532 if (dev) { 2533 if (dev != grt->dst.dev) { 2534 ip6_rt_put(grt); 2535 goto out; 2536 } 2537 } else { 2538 *_dev = dev = grt->dst.dev; 2539 *idev = grt->rt6i_idev; 2540 dev_hold(dev); 2541 in6_dev_hold(grt->rt6i_idev); 2542 } 2543 2544 if (!(grt->rt6i_flags & RTF_GATEWAY)) 2545 err = 0; 2546 2547 ip6_rt_put(grt); 2548 2549out: 2550 return err; 2551} 2552 |
|
2471static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg, 2472 struct netlink_ext_ack *extack) 2473{ 2474 struct net *net = cfg->fc_nlinfo.nl_net; 2475 struct rt6_info *rt = NULL; 2476 struct net_device *dev = NULL; 2477 struct inet6_dev *idev = NULL; 2478 struct fib6_table *table; --- 35 unchanged lines hidden (view full) --- 2514 idev = in6_dev_get(dev); 2515 if (!idev) 2516 goto out; 2517 } 2518 2519 if (cfg->fc_metric == 0) 2520 cfg->fc_metric = IP6_RT_PRIO_USER; 2521 | 2553static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg, 2554 struct netlink_ext_ack *extack) 2555{ 2556 struct net *net = cfg->fc_nlinfo.nl_net; 2557 struct rt6_info *rt = NULL; 2558 struct net_device *dev = NULL; 2559 struct inet6_dev *idev = NULL; 2560 struct fib6_table *table; --- 35 unchanged lines hidden (view full) --- 2596 idev = in6_dev_get(dev); 2597 if (!idev) 2598 goto out; 2599 } 2600 2601 if (cfg->fc_metric == 0) 2602 cfg->fc_metric = IP6_RT_PRIO_USER; 2603 |
2604 if (cfg->fc_flags & RTNH_F_ONLINK) { 2605 if (!dev) { 2606 NL_SET_ERR_MSG(extack, 2607 "Nexthop device required for onlink"); 2608 err = -ENODEV; 2609 goto out; 2610 } 2611 2612 if (!(dev->flags & IFF_UP)) { 2613 NL_SET_ERR_MSG(extack, "Nexthop device is not up"); 2614 err = -ENETDOWN; 2615 goto out; 2616 } 2617 } 2618 |
|
2522 err = -ENOBUFS; 2523 if (cfg->fc_nlinfo.nlh && 2524 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) { 2525 table = fib6_get_table(net, cfg->fc_table); 2526 if (!table) { 2527 pr_warn("NLM_F_CREATE should be specified when creating new route\n"); 2528 table = fib6_new_table(net, cfg->fc_table); 2529 } --- 58 unchanged lines hidden (view full) --- 2588 rt->dst.flags |= DST_HOST; 2589 2590#ifdef CONFIG_IPV6_SUBTREES 2591 ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len); 2592 rt->rt6i_src.plen = cfg->fc_src_len; 2593#endif 2594 2595 rt->rt6i_metric = cfg->fc_metric; | 2619 err = -ENOBUFS; 2620 if (cfg->fc_nlinfo.nlh && 2621 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) { 2622 table = fib6_get_table(net, cfg->fc_table); 2623 if (!table) { 2624 pr_warn("NLM_F_CREATE should be specified when creating new route\n"); 2625 table = fib6_new_table(net, cfg->fc_table); 2626 } --- 58 unchanged lines hidden (view full) --- 2685 rt->dst.flags |= DST_HOST; 2686 2687#ifdef CONFIG_IPV6_SUBTREES 2688 ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len); 2689 rt->rt6i_src.plen = cfg->fc_src_len; 2690#endif 2691 2692 rt->rt6i_metric = cfg->fc_metric; |
2693 rt->rt6i_nh_weight = 1; |
|
2596 2597 /* We cannot add true routes via loopback here, 2598 they would result in kernel looping; promote them to reject routes 2599 */ 2600 if ((cfg->fc_flags & RTF_REJECT) || 2601 (dev && (dev->flags & IFF_LOOPBACK) && 2602 !(addr_type & IPV6_ADDR_LOOPBACK) && 2603 !(cfg->fc_flags & RTF_LOCAL))) { --- 53 unchanged lines hidden (view full) --- 2657 gwa_type & IPV6_ADDR_LINKLOCAL ? 2658 dev : NULL, 0, 0)) { 2659 NL_SET_ERR_MSG(extack, "Invalid gateway address"); 2660 goto out; 2661 } 2662 rt->rt6i_gateway = *gw_addr; 2663 2664 if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) { | 2694 2695 /* We cannot add true routes via loopback here, 2696 they would result in kernel looping; promote them to reject routes 2697 */ 2698 if ((cfg->fc_flags & RTF_REJECT) || 2699 (dev && (dev->flags & IFF_LOOPBACK) && 2700 !(addr_type & IPV6_ADDR_LOOPBACK) && 2701 !(cfg->fc_flags & RTF_LOCAL))) { --- 53 unchanged lines hidden (view full) --- 2755 gwa_type & IPV6_ADDR_LINKLOCAL ? 2756 dev : NULL, 0, 0)) { 2757 NL_SET_ERR_MSG(extack, "Invalid gateway address"); 2758 goto out; 2759 } 2760 rt->rt6i_gateway = *gw_addr; 2761 2762 if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) { |
2665 struct rt6_info *grt = NULL; 2666 | |
2667 /* IPv6 strictly inhibits using not link-local 2668 addresses as nexthop address. 2669 Otherwise, router will not able to send redirects. 2670 It is very good, but in some (rare!) circumstances 2671 (SIT, PtP, NBMA NOARP links) it is handy to allow 2672 some exceptions. --ANK 2673 We allow IPv4-mapped nexthops to support RFC4798-type 2674 addressing 2675 */ 2676 if (!(gwa_type & (IPV6_ADDR_UNICAST | 2677 IPV6_ADDR_MAPPED))) { 2678 NL_SET_ERR_MSG(extack, 2679 "Invalid gateway address"); 2680 goto out; 2681 } 2682 | 2763 /* IPv6 strictly inhibits using not link-local 2764 addresses as nexthop address. 2765 Otherwise, router will not able to send redirects. 2766 It is very good, but in some (rare!) circumstances 2767 (SIT, PtP, NBMA NOARP links) it is handy to allow 2768 some exceptions. --ANK 2769 We allow IPv4-mapped nexthops to support RFC4798-type 2770 addressing 2771 */ 2772 if (!(gwa_type & (IPV6_ADDR_UNICAST | 2773 IPV6_ADDR_MAPPED))) { 2774 NL_SET_ERR_MSG(extack, 2775 "Invalid gateway address"); 2776 goto out; 2777 } 2778 |
2683 if (cfg->fc_table) { 2684 grt = ip6_nh_lookup_table(net, cfg, gw_addr); 2685 2686 if (grt) { 2687 if (grt->rt6i_flags & RTF_GATEWAY || 2688 (dev && dev != grt->dst.dev)) { 2689 ip6_rt_put(grt); 2690 grt = NULL; 2691 } 2692 } 2693 } 2694 2695 if (!grt) 2696 grt = rt6_lookup(net, gw_addr, NULL, 2697 cfg->fc_ifindex, 1); 2698 2699 err = -EHOSTUNREACH; 2700 if (!grt) 2701 goto out; 2702 if (dev) { 2703 if (dev != grt->dst.dev) { 2704 ip6_rt_put(grt); 2705 goto out; 2706 } | 2779 if (cfg->fc_flags & RTNH_F_ONLINK) { 2780 err = ip6_route_check_nh_onlink(net, cfg, dev, 2781 extack); |
2707 } else { | 2782 } else { |
2708 dev = grt->dst.dev; 2709 idev = grt->rt6i_idev; 2710 dev_hold(dev); 2711 in6_dev_hold(grt->rt6i_idev); | 2783 err = ip6_route_check_nh(net, cfg, &dev, &idev); |
2712 } | 2784 } |
2713 if (!(grt->rt6i_flags & RTF_GATEWAY)) 2714 err = 0; 2715 ip6_rt_put(grt); 2716 | |
2717 if (err) 2718 goto out; 2719 } 2720 err = -EINVAL; 2721 if (!dev) { 2722 NL_SET_ERR_MSG(extack, "Egress device not specified"); 2723 goto out; 2724 } else if (dev->flags & IFF_LOOPBACK) { 2725 NL_SET_ERR_MSG(extack, 2726 "Egress device can not be loopback device for this route"); 2727 goto out; 2728 } 2729 } 2730 2731 err = -ENODEV; 2732 if (!dev) 2733 goto out; 2734 | 2785 if (err) 2786 goto out; 2787 } 2788 err = -EINVAL; 2789 if (!dev) { 2790 NL_SET_ERR_MSG(extack, "Egress device not specified"); 2791 goto out; 2792 } else if (dev->flags & IFF_LOOPBACK) { 2793 NL_SET_ERR_MSG(extack, 2794 "Egress device can not be loopback device for this route"); 2795 goto out; 2796 } 2797 } 2798 2799 err = -ENODEV; 2800 if (!dev) 2801 goto out; 2802 |
2803 if (!(dev->flags & IFF_UP)) { 2804 NL_SET_ERR_MSG(extack, "Nexthop device is not up"); 2805 err = -ENETDOWN; 2806 goto out; 2807 } 2808 |
|
2735 if (!ipv6_addr_any(&cfg->fc_prefsrc)) { 2736 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) { 2737 NL_SET_ERR_MSG(extack, "Invalid source address"); 2738 err = -EINVAL; 2739 goto out; 2740 } 2741 rt->rt6i_prefsrc.addr = cfg->fc_prefsrc; 2742 rt->rt6i_prefsrc.plen = 128; 2743 } else 2744 rt->rt6i_prefsrc.plen = 0; 2745 2746 rt->rt6i_flags = cfg->fc_flags; 2747 2748install_route: | 2809 if (!ipv6_addr_any(&cfg->fc_prefsrc)) { 2810 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) { 2811 NL_SET_ERR_MSG(extack, "Invalid source address"); 2812 err = -EINVAL; 2813 goto out; 2814 } 2815 rt->rt6i_prefsrc.addr = cfg->fc_prefsrc; 2816 rt->rt6i_prefsrc.plen = 128; 2817 } else 2818 rt->rt6i_prefsrc.plen = 0; 2819 2820 rt->rt6i_flags = cfg->fc_flags; 2821 2822install_route: |
2823 if (!(rt->rt6i_flags & (RTF_LOCAL | RTF_ANYCAST)) && 2824 !netif_carrier_ok(dev)) 2825 rt->rt6i_nh_flags |= RTNH_F_LINKDOWN; 2826 rt->rt6i_nh_flags |= (cfg->fc_flags & RTNH_F_ONLINK); |
|
2749 rt->dst.dev = dev; 2750 rt->rt6i_idev = idev; 2751 rt->rt6i_table = table; 2752 2753 cfg->fc_nlinfo.nl_net = dev_net(dev); 2754 2755 return rt; 2756out: --- 294 unchanged lines hidden (view full) --- 3051} 3052 3053/* 3054 * Misc support functions 3055 */ 3056 3057static void rt6_set_from(struct rt6_info *rt, struct rt6_info *from) 3058{ | 2827 rt->dst.dev = dev; 2828 rt->rt6i_idev = idev; 2829 rt->rt6i_table = table; 2830 2831 cfg->fc_nlinfo.nl_net = dev_net(dev); 2832 2833 return rt; 2834out: --- 294 unchanged lines hidden (view full) --- 3129} 3130 3131/* 3132 * Misc support functions 3133 */ 3134 3135static void rt6_set_from(struct rt6_info *rt, struct rt6_info *from) 3136{ |
3059 BUG_ON(from->dst.from); | 3137 BUG_ON(from->from); |
3060 3061 rt->rt6i_flags &= ~RTF_EXPIRES; 3062 dst_hold(&from->dst); | 3138 3139 rt->rt6i_flags &= ~RTF_EXPIRES; 3140 dst_hold(&from->dst); |
3063 rt->dst.from = &from->dst; | 3141 rt->from = from; |
3064 dst_init_metrics(&rt->dst, dst_metrics_ptr(&from->dst), true); 3065} 3066 3067static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort) 3068{ 3069 rt->dst.input = ort->dst.input; 3070 rt->dst.output = ort->dst.output; 3071 rt->rt6i_dst = ort->rt6i_dst; --- 382 unchanged lines hidden (view full) --- 3454 return 0; 3455} 3456 3457void rt6_clean_tohost(struct net *net, struct in6_addr *gateway) 3458{ 3459 fib6_clean_all(net, fib6_clean_tohost, gateway); 3460} 3461 | 3142 dst_init_metrics(&rt->dst, dst_metrics_ptr(&from->dst), true); 3143} 3144 3145static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort) 3146{ 3147 rt->dst.input = ort->dst.input; 3148 rt->dst.output = ort->dst.output; 3149 rt->rt6i_dst = ort->rt6i_dst; --- 382 unchanged lines hidden (view full) --- 3532 return 0; 3533} 3534 3535void rt6_clean_tohost(struct net *net, struct in6_addr *gateway) 3536{ 3537 fib6_clean_all(net, fib6_clean_tohost, gateway); 3538} 3539 |
3462struct arg_dev_net { 3463 struct net_device *dev; 3464 struct net *net; | 3540struct arg_netdev_event { 3541 const struct net_device *dev; 3542 union { 3543 unsigned int nh_flags; 3544 unsigned long event; 3545 }; |
3465}; 3466 | 3546}; 3547 |
3548static struct rt6_info *rt6_multipath_first_sibling(const struct rt6_info *rt) 3549{ 3550 struct rt6_info *iter; 3551 struct fib6_node *fn; 3552 3553 fn = rcu_dereference_protected(rt->rt6i_node, 3554 lockdep_is_held(&rt->rt6i_table->tb6_lock)); 3555 iter = rcu_dereference_protected(fn->leaf, 3556 lockdep_is_held(&rt->rt6i_table->tb6_lock)); 3557 while (iter) { 3558 if (iter->rt6i_metric == rt->rt6i_metric && 3559 rt6_qualify_for_ecmp(iter)) 3560 return iter; 3561 iter = rcu_dereference_protected(iter->rt6_next, 3562 lockdep_is_held(&rt->rt6i_table->tb6_lock)); 3563 } 3564 3565 return NULL; 3566} 3567 3568static bool rt6_is_dead(const struct rt6_info *rt) 3569{ 3570 if (rt->rt6i_nh_flags & RTNH_F_DEAD || 3571 (rt->rt6i_nh_flags & RTNH_F_LINKDOWN && 3572 rt->rt6i_idev->cnf.ignore_routes_with_linkdown)) 3573 return true; 3574 3575 return false; 3576} 3577 3578static int rt6_multipath_total_weight(const struct rt6_info *rt) 3579{ 3580 struct rt6_info *iter; 3581 int total = 0; 3582 3583 if (!rt6_is_dead(rt)) 3584 total += rt->rt6i_nh_weight; 3585 3586 list_for_each_entry(iter, &rt->rt6i_siblings, rt6i_siblings) { 3587 if (!rt6_is_dead(iter)) 3588 total += iter->rt6i_nh_weight; 3589 } 3590 3591 return total; 3592} 3593 3594static void rt6_upper_bound_set(struct rt6_info *rt, int *weight, int total) 3595{ 3596 int upper_bound = -1; 3597 3598 if (!rt6_is_dead(rt)) { 3599 *weight += rt->rt6i_nh_weight; 3600 upper_bound = DIV_ROUND_CLOSEST_ULL((u64) (*weight) << 31, 3601 total) - 1; 3602 } 3603 atomic_set(&rt->rt6i_nh_upper_bound, upper_bound); 3604} 3605 3606static void rt6_multipath_upper_bound_set(struct rt6_info *rt, int total) 3607{ 3608 struct rt6_info *iter; 3609 int weight = 0; 3610 3611 rt6_upper_bound_set(rt, &weight, total); 3612 3613 list_for_each_entry(iter, &rt->rt6i_siblings, rt6i_siblings) 3614 rt6_upper_bound_set(iter, &weight, total); 3615} 3616 3617void rt6_multipath_rebalance(struct rt6_info *rt) 3618{ 3619 struct rt6_info *first; 3620 int total; 3621 3622 /* In case the entire multipath route was marked for flushing, 3623 * then there is no need to rebalance upon the removal of every 3624 * sibling route. 3625 */ 3626 if (!rt->rt6i_nsiblings || rt->should_flush) 3627 return; 3628 3629 /* During lookup routes are evaluated in order, so we need to 3630 * make sure upper bounds are assigned from the first sibling 3631 * onwards. 3632 */ 3633 first = rt6_multipath_first_sibling(rt); 3634 if (WARN_ON_ONCE(!first)) 3635 return; 3636 3637 total = rt6_multipath_total_weight(first); 3638 rt6_multipath_upper_bound_set(first, total); 3639} 3640 3641static int fib6_ifup(struct rt6_info *rt, void *p_arg) 3642{ 3643 const struct arg_netdev_event *arg = p_arg; 3644 const struct net *net = dev_net(arg->dev); 3645 3646 if (rt != net->ipv6.ip6_null_entry && rt->dst.dev == arg->dev) { 3647 rt->rt6i_nh_flags &= ~arg->nh_flags; 3648 fib6_update_sernum_upto_root(dev_net(rt->dst.dev), rt); 3649 rt6_multipath_rebalance(rt); 3650 } 3651 3652 return 0; 3653} 3654 3655void rt6_sync_up(struct net_device *dev, unsigned int nh_flags) 3656{ 3657 struct arg_netdev_event arg = { 3658 .dev = dev, 3659 { 3660 .nh_flags = nh_flags, 3661 }, 3662 }; 3663 3664 if (nh_flags & RTNH_F_DEAD && netif_carrier_ok(dev)) 3665 arg.nh_flags |= RTNH_F_LINKDOWN; 3666 3667 fib6_clean_all(dev_net(dev), fib6_ifup, &arg); 3668} 3669 3670static bool rt6_multipath_uses_dev(const struct rt6_info *rt, 3671 const struct net_device *dev) 3672{ 3673 struct rt6_info *iter; 3674 3675 if (rt->dst.dev == dev) 3676 return true; 3677 list_for_each_entry(iter, &rt->rt6i_siblings, rt6i_siblings) 3678 if (iter->dst.dev == dev) 3679 return true; 3680 3681 return false; 3682} 3683 3684static void rt6_multipath_flush(struct rt6_info *rt) 3685{ 3686 struct rt6_info *iter; 3687 3688 rt->should_flush = 1; 3689 list_for_each_entry(iter, &rt->rt6i_siblings, rt6i_siblings) 3690 iter->should_flush = 1; 3691} 3692 3693static unsigned int rt6_multipath_dead_count(const struct rt6_info *rt, 3694 const struct net_device *down_dev) 3695{ 3696 struct rt6_info *iter; 3697 unsigned int dead = 0; 3698 3699 if (rt->dst.dev == down_dev || rt->rt6i_nh_flags & RTNH_F_DEAD) 3700 dead++; 3701 list_for_each_entry(iter, &rt->rt6i_siblings, rt6i_siblings) 3702 if (iter->dst.dev == down_dev || 3703 iter->rt6i_nh_flags & RTNH_F_DEAD) 3704 dead++; 3705 3706 return dead; 3707} 3708 3709static void rt6_multipath_nh_flags_set(struct rt6_info *rt, 3710 const struct net_device *dev, 3711 unsigned int nh_flags) 3712{ 3713 struct rt6_info *iter; 3714 3715 if (rt->dst.dev == dev) 3716 rt->rt6i_nh_flags |= nh_flags; 3717 list_for_each_entry(iter, &rt->rt6i_siblings, rt6i_siblings) 3718 if (iter->dst.dev == dev) 3719 iter->rt6i_nh_flags |= nh_flags; 3720} 3721 |
|
3467/* called with write lock held for table with rt */ | 3722/* called with write lock held for table with rt */ |
3468static int fib6_ifdown(struct rt6_info *rt, void *arg) | 3723static int fib6_ifdown(struct rt6_info *rt, void *p_arg) |
3469{ | 3724{ |
3470 const struct arg_dev_net *adn = arg; 3471 const struct net_device *dev = adn->dev; | 3725 const struct arg_netdev_event *arg = p_arg; 3726 const struct net_device *dev = arg->dev; 3727 const struct net *net = dev_net(dev); |
3472 | 3728 |
3473 if ((rt->dst.dev == dev || !dev) && 3474 rt != adn->net->ipv6.ip6_null_entry && 3475 (rt->rt6i_nsiblings == 0 || 3476 (dev && netdev_unregistering(dev)) || 3477 !rt->rt6i_idev->cnf.ignore_routes_with_linkdown)) 3478 return -1; | 3729 if (rt == net->ipv6.ip6_null_entry) 3730 return 0; |
3479 | 3731 |
3732 switch (arg->event) { 3733 case NETDEV_UNREGISTER: 3734 return rt->dst.dev == dev ? -1 : 0; 3735 case NETDEV_DOWN: 3736 if (rt->should_flush) 3737 return -1; 3738 if (!rt->rt6i_nsiblings) 3739 return rt->dst.dev == dev ? -1 : 0; 3740 if (rt6_multipath_uses_dev(rt, dev)) { 3741 unsigned int count; 3742 3743 count = rt6_multipath_dead_count(rt, dev); 3744 if (rt->rt6i_nsiblings + 1 == count) { 3745 rt6_multipath_flush(rt); 3746 return -1; 3747 } 3748 rt6_multipath_nh_flags_set(rt, dev, RTNH_F_DEAD | 3749 RTNH_F_LINKDOWN); 3750 fib6_update_sernum(rt); 3751 rt6_multipath_rebalance(rt); 3752 } 3753 return -2; 3754 case NETDEV_CHANGE: 3755 if (rt->dst.dev != dev || 3756 rt->rt6i_flags & (RTF_LOCAL | RTF_ANYCAST)) 3757 break; 3758 rt->rt6i_nh_flags |= RTNH_F_LINKDOWN; 3759 rt6_multipath_rebalance(rt); 3760 break; 3761 } 3762 |
|
3480 return 0; 3481} 3482 | 3763 return 0; 3764} 3765 |
3483void rt6_ifdown(struct net *net, struct net_device *dev) | 3766void rt6_sync_down_dev(struct net_device *dev, unsigned long event) |
3484{ | 3767{ |
3485 struct arg_dev_net adn = { | 3768 struct arg_netdev_event arg = { |
3486 .dev = dev, | 3769 .dev = dev, |
3487 .net = net, | 3770 { 3771 .event = event, 3772 }, |
3488 }; 3489 | 3773 }; 3774 |
3490 fib6_clean_all(net, fib6_ifdown, &adn); 3491 if (dev) 3492 rt6_uncached_list_flush_dev(net, dev); | 3775 fib6_clean_all(dev_net(dev), fib6_ifdown, &arg); |
3493} 3494 | 3776} 3777 |
3778void rt6_disable_ip(struct net_device *dev, unsigned long event) 3779{ 3780 rt6_sync_down_dev(dev, event); 3781 rt6_uncached_list_flush_dev(dev_net(dev), dev); 3782 neigh_ifdown(&nd_tbl, dev); 3783} 3784 |
|
3495struct rt6_mtu_change_arg { 3496 struct net_device *dev; 3497 unsigned int mtu; 3498}; 3499 3500static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg) 3501{ 3502 struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg; --- 95 unchanged lines hidden (view full) --- 3598 cfg->fc_flags |= RTF_REJECT; 3599 3600 if (rtm->rtm_type == RTN_LOCAL) 3601 cfg->fc_flags |= RTF_LOCAL; 3602 3603 if (rtm->rtm_flags & RTM_F_CLONED) 3604 cfg->fc_flags |= RTF_CACHE; 3605 | 3785struct rt6_mtu_change_arg { 3786 struct net_device *dev; 3787 unsigned int mtu; 3788}; 3789 3790static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg) 3791{ 3792 struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg; --- 95 unchanged lines hidden (view full) --- 3888 cfg->fc_flags |= RTF_REJECT; 3889 3890 if (rtm->rtm_type == RTN_LOCAL) 3891 cfg->fc_flags |= RTF_LOCAL; 3892 3893 if (rtm->rtm_flags & RTM_F_CLONED) 3894 cfg->fc_flags |= RTF_CACHE; 3895 |
3896 cfg->fc_flags |= (rtm->rtm_flags & RTNH_F_ONLINK); 3897 |
|
3606 cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid; 3607 cfg->fc_nlinfo.nlh = nlh; 3608 cfg->fc_nlinfo.nl_net = sock_net(skb->sk); 3609 3610 if (tb[RTA_GATEWAY]) { 3611 cfg->fc_gateway = nla_get_in6_addr(tb[RTA_GATEWAY]); 3612 cfg->fc_flags |= RTF_GATEWAY; 3613 } --- 193 unchanged lines hidden (view full) --- 3807 3808 rt = ip6_route_info_create(&r_cfg, extack); 3809 if (IS_ERR(rt)) { 3810 err = PTR_ERR(rt); 3811 rt = NULL; 3812 goto cleanup; 3813 } 3814 | 3898 cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid; 3899 cfg->fc_nlinfo.nlh = nlh; 3900 cfg->fc_nlinfo.nl_net = sock_net(skb->sk); 3901 3902 if (tb[RTA_GATEWAY]) { 3903 cfg->fc_gateway = nla_get_in6_addr(tb[RTA_GATEWAY]); 3904 cfg->fc_flags |= RTF_GATEWAY; 3905 } --- 193 unchanged lines hidden (view full) --- 4099 4100 rt = ip6_route_info_create(&r_cfg, extack); 4101 if (IS_ERR(rt)) { 4102 err = PTR_ERR(rt); 4103 rt = NULL; 4104 goto cleanup; 4105 } 4106 |
4107 rt->rt6i_nh_weight = rtnh->rtnh_hops + 1; 4108 |
|
3815 err = ip6_route_info_append(&rt6_nh_list, rt, &r_cfg); 3816 if (err) { 3817 dst_release_immediate(&rt->dst); 3818 goto cleanup; 3819 } 3820 3821 rtnh = rtnh_next(rtnh, &remaining); 3822 } --- 164 unchanged lines hidden (view full) --- 3987 + nla_total_size(1) /* RTA_PREF */ 3988 + lwtunnel_get_encap_size(rt->dst.lwtstate) 3989 + nexthop_len; 3990} 3991 3992static int rt6_nexthop_info(struct sk_buff *skb, struct rt6_info *rt, 3993 unsigned int *flags, bool skip_oif) 3994{ | 4109 err = ip6_route_info_append(&rt6_nh_list, rt, &r_cfg); 4110 if (err) { 4111 dst_release_immediate(&rt->dst); 4112 goto cleanup; 4113 } 4114 4115 rtnh = rtnh_next(rtnh, &remaining); 4116 } --- 164 unchanged lines hidden (view full) --- 4281 + nla_total_size(1) /* RTA_PREF */ 4282 + lwtunnel_get_encap_size(rt->dst.lwtstate) 4283 + nexthop_len; 4284} 4285 4286static int rt6_nexthop_info(struct sk_buff *skb, struct rt6_info *rt, 4287 unsigned int *flags, bool skip_oif) 4288{ |
3995 if (!netif_running(rt->dst.dev) || !netif_carrier_ok(rt->dst.dev)) { | 4289 if (rt->rt6i_nh_flags & RTNH_F_DEAD) 4290 *flags |= RTNH_F_DEAD; 4291 4292 if (rt->rt6i_nh_flags & RTNH_F_LINKDOWN) { |
3996 *flags |= RTNH_F_LINKDOWN; 3997 if (rt->rt6i_idev->cnf.ignore_routes_with_linkdown) 3998 *flags |= RTNH_F_DEAD; 3999 } 4000 4001 if (rt->rt6i_flags & RTF_GATEWAY) { 4002 if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->rt6i_gateway) < 0) 4003 goto nla_put_failure; 4004 } 4005 | 4293 *flags |= RTNH_F_LINKDOWN; 4294 if (rt->rt6i_idev->cnf.ignore_routes_with_linkdown) 4295 *flags |= RTNH_F_DEAD; 4296 } 4297 4298 if (rt->rt6i_flags & RTF_GATEWAY) { 4299 if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->rt6i_gateway) < 0) 4300 goto nla_put_failure; 4301 } 4302 |
4303 *flags |= (rt->rt6i_nh_flags & RTNH_F_ONLINK); |
|
4006 if (rt->rt6i_nh_flags & RTNH_F_OFFLOAD) 4007 *flags |= RTNH_F_OFFLOAD; 4008 4009 /* not needed for multipath encoding b/c it has a rtnexthop struct */ 4010 if (!skip_oif && rt->dst.dev && 4011 nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex)) 4012 goto nla_put_failure; 4013 --- 12 unchanged lines hidden (view full) --- 4026{ 4027 struct rtnexthop *rtnh; 4028 unsigned int flags = 0; 4029 4030 rtnh = nla_reserve_nohdr(skb, sizeof(*rtnh)); 4031 if (!rtnh) 4032 goto nla_put_failure; 4033 | 4304 if (rt->rt6i_nh_flags & RTNH_F_OFFLOAD) 4305 *flags |= RTNH_F_OFFLOAD; 4306 4307 /* not needed for multipath encoding b/c it has a rtnexthop struct */ 4308 if (!skip_oif && rt->dst.dev && 4309 nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex)) 4310 goto nla_put_failure; 4311 --- 12 unchanged lines hidden (view full) --- 4324{ 4325 struct rtnexthop *rtnh; 4326 unsigned int flags = 0; 4327 4328 rtnh = nla_reserve_nohdr(skb, sizeof(*rtnh)); 4329 if (!rtnh) 4330 goto nla_put_failure; 4331 |
4034 rtnh->rtnh_hops = 0; | 4332 rtnh->rtnh_hops = rt->rt6i_nh_weight - 1; |
4035 rtnh->rtnh_ifindex = rt->dst.dev ? rt->dst.dev->ifindex : 0; 4036 4037 if (rt6_nexthop_info(skb, rt, &flags, true) < 0) 4038 goto nla_put_failure; 4039 4040 rtnh->rtnh_flags = flags; 4041 4042 /* length of rtnetlink header + attributes */ --- 273 unchanged lines hidden (view full) --- 4316 } 4317 4318 if (rt == net->ipv6.ip6_null_entry) { 4319 err = rt->dst.error; 4320 ip6_rt_put(rt); 4321 goto errout; 4322 } 4323 | 4333 rtnh->rtnh_ifindex = rt->dst.dev ? rt->dst.dev->ifindex : 0; 4334 4335 if (rt6_nexthop_info(skb, rt, &flags, true) < 0) 4336 goto nla_put_failure; 4337 4338 rtnh->rtnh_flags = flags; 4339 4340 /* length of rtnetlink header + attributes */ --- 273 unchanged lines hidden (view full) --- 4614 } 4615 4616 if (rt == net->ipv6.ip6_null_entry) { 4617 err = rt->dst.error; 4618 ip6_rt_put(rt); 4619 goto errout; 4620 } 4621 |
4324 if (fibmatch && rt->dst.from) { 4325 struct rt6_info *ort = container_of(rt->dst.from, 4326 struct rt6_info, dst); | 4622 if (fibmatch && rt->from) { 4623 struct rt6_info *ort = rt->from; |
4327 4328 dst_hold(&ort->dst); 4329 ip6_rt_put(rt); 4330 rt = ort; 4331 } 4332 4333 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); 4334 if (!skb) { --- 87 unchanged lines hidden (view full) --- 4422 4423/* 4424 * /proc 4425 */ 4426 4427#ifdef CONFIG_PROC_FS 4428 4429static const struct file_operations ipv6_route_proc_fops = { | 4624 4625 dst_hold(&ort->dst); 4626 ip6_rt_put(rt); 4627 rt = ort; 4628 } 4629 4630 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); 4631 if (!skb) { --- 87 unchanged lines hidden (view full) --- 4719 4720/* 4721 * /proc 4722 */ 4723 4724#ifdef CONFIG_PROC_FS 4725 4726static const struct file_operations ipv6_route_proc_fops = { |
4430 .owner = THIS_MODULE, | |
4431 .open = ipv6_route_open, 4432 .read = seq_read, 4433 .llseek = seq_lseek, 4434 .release = seq_release_net, 4435}; 4436 4437static int rt6_stats_seq_show(struct seq_file *seq, void *v) 4438{ --- 11 unchanged lines hidden (view full) --- 4450} 4451 4452static int rt6_stats_seq_open(struct inode *inode, struct file *file) 4453{ 4454 return single_open_net(inode, file, rt6_stats_seq_show); 4455} 4456 4457static const struct file_operations rt6_stats_seq_fops = { | 4727 .open = ipv6_route_open, 4728 .read = seq_read, 4729 .llseek = seq_lseek, 4730 .release = seq_release_net, 4731}; 4732 4733static int rt6_stats_seq_show(struct seq_file *seq, void *v) 4734{ --- 11 unchanged lines hidden (view full) --- 4746} 4747 4748static int rt6_stats_seq_open(struct inode *inode, struct file *file) 4749{ 4750 return single_open_net(inode, file, rt6_stats_seq_show); 4751} 4752 4753static const struct file_operations rt6_stats_seq_fops = { |
4458 .owner = THIS_MODULE, | |
4459 .open = rt6_stats_seq_open, 4460 .read = seq_read, 4461 .llseek = seq_lseek, 4462 .release = single_release_net, 4463}; 4464#endif /* CONFIG_PROC_FS */ 4465 4466#ifdef CONFIG_SYSCTL --- 128 unchanged lines hidden (view full) --- 4595 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0) 4596 goto out_ip6_dst_ops; 4597 4598 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template, 4599 sizeof(*net->ipv6.ip6_null_entry), 4600 GFP_KERNEL); 4601 if (!net->ipv6.ip6_null_entry) 4602 goto out_ip6_dst_entries; | 4754 .open = rt6_stats_seq_open, 4755 .read = seq_read, 4756 .llseek = seq_lseek, 4757 .release = single_release_net, 4758}; 4759#endif /* CONFIG_PROC_FS */ 4760 4761#ifdef CONFIG_SYSCTL --- 128 unchanged lines hidden (view full) --- 4890 if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0) 4891 goto out_ip6_dst_ops; 4892 4893 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template, 4894 sizeof(*net->ipv6.ip6_null_entry), 4895 GFP_KERNEL); 4896 if (!net->ipv6.ip6_null_entry) 4897 goto out_ip6_dst_entries; |
4603 net->ipv6.ip6_null_entry->dst.path = 4604 (struct dst_entry *)net->ipv6.ip6_null_entry; | |
4605 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops; 4606 dst_init_metrics(&net->ipv6.ip6_null_entry->dst, 4607 ip6_template_metrics, true); 4608 4609#ifdef CONFIG_IPV6_MULTIPLE_TABLES 4610 net->ipv6.fib6_has_custom_rules = false; 4611 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, 4612 sizeof(*net->ipv6.ip6_prohibit_entry), 4613 GFP_KERNEL); 4614 if (!net->ipv6.ip6_prohibit_entry) 4615 goto out_ip6_null_entry; | 4898 net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops; 4899 dst_init_metrics(&net->ipv6.ip6_null_entry->dst, 4900 ip6_template_metrics, true); 4901 4902#ifdef CONFIG_IPV6_MULTIPLE_TABLES 4903 net->ipv6.fib6_has_custom_rules = false; 4904 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, 4905 sizeof(*net->ipv6.ip6_prohibit_entry), 4906 GFP_KERNEL); 4907 if (!net->ipv6.ip6_prohibit_entry) 4908 goto out_ip6_null_entry; |
4616 net->ipv6.ip6_prohibit_entry->dst.path = 4617 (struct dst_entry *)net->ipv6.ip6_prohibit_entry; | |
4618 net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops; 4619 dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst, 4620 ip6_template_metrics, true); 4621 4622 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, 4623 sizeof(*net->ipv6.ip6_blk_hole_entry), 4624 GFP_KERNEL); 4625 if (!net->ipv6.ip6_blk_hole_entry) 4626 goto out_ip6_prohibit_entry; | 4909 net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops; 4910 dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst, 4911 ip6_template_metrics, true); 4912 4913 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, 4914 sizeof(*net->ipv6.ip6_blk_hole_entry), 4915 GFP_KERNEL); 4916 if (!net->ipv6.ip6_blk_hole_entry) 4917 goto out_ip6_prohibit_entry; |
4627 net->ipv6.ip6_blk_hole_entry->dst.path = 4628 (struct dst_entry *)net->ipv6.ip6_blk_hole_entry; | |
4629 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops; 4630 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst, 4631 ip6_template_metrics, true); 4632#endif 4633 4634 net->ipv6.sysctl.flush_delay = 0; 4635 net->ipv6.sysctl.ip6_rt_max_size = 4096; 4636 net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2; --- 140 unchanged lines hidden (view full) --- 4777 ret = fib6_rules_init(); 4778 if (ret) 4779 goto xfrm6_init; 4780 4781 ret = register_pernet_subsys(&ip6_route_net_late_ops); 4782 if (ret) 4783 goto fib6_rules_init; 4784 | 4918 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops; 4919 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst, 4920 ip6_template_metrics, true); 4921#endif 4922 4923 net->ipv6.sysctl.flush_delay = 0; 4924 net->ipv6.sysctl.ip6_rt_max_size = 4096; 4925 net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2; --- 140 unchanged lines hidden (view full) --- 5066 ret = fib6_rules_init(); 5067 if (ret) 5068 goto xfrm6_init; 5069 5070 ret = register_pernet_subsys(&ip6_route_net_late_ops); 5071 if (ret) 5072 goto fib6_rules_init; 5073 |
4785 ret = -ENOBUFS; 4786 if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL, 0) || 4787 __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL, 0) || 4788 __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL, 4789 RTNL_FLAG_DOIT_UNLOCKED)) | 5074 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_NEWROUTE, 5075 inet6_rtm_newroute, NULL, 0); 5076 if (ret < 0) |
4790 goto out_register_late_subsys; 4791 | 5077 goto out_register_late_subsys; 5078 |
5079 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_DELROUTE, 5080 inet6_rtm_delroute, NULL, 0); 5081 if (ret < 0) 5082 goto out_register_late_subsys; 5083 5084 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_GETROUTE, 5085 inet6_rtm_getroute, NULL, 5086 RTNL_FLAG_DOIT_UNLOCKED); 5087 if (ret < 0) 5088 goto out_register_late_subsys; 5089 |
|
4792 ret = register_netdevice_notifier(&ip6_route_dev_notifier); 4793 if (ret) 4794 goto out_register_late_subsys; 4795 4796 for_each_possible_cpu(cpu) { 4797 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu); 4798 4799 INIT_LIST_HEAD(&ul->head); 4800 spin_lock_init(&ul->lock); 4801 } 4802 4803out: 4804 return ret; 4805 4806out_register_late_subsys: | 5090 ret = register_netdevice_notifier(&ip6_route_dev_notifier); 5091 if (ret) 5092 goto out_register_late_subsys; 5093 5094 for_each_possible_cpu(cpu) { 5095 struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu); 5096 5097 INIT_LIST_HEAD(&ul->head); 5098 spin_lock_init(&ul->lock); 5099 } 5100 5101out: 5102 return ret; 5103 5104out_register_late_subsys: |
5105 rtnl_unregister_all(PF_INET6); |
|
4807 unregister_pernet_subsys(&ip6_route_net_late_ops); 4808fib6_rules_init: 4809 fib6_rules_cleanup(); 4810xfrm6_init: 4811 xfrm6_fini(); 4812out_fib6_init: 4813 fib6_gc_cleanup(); 4814out_register_subsys: --- 22 unchanged lines hidden --- | 5106 unregister_pernet_subsys(&ip6_route_net_late_ops); 5107fib6_rules_init: 5108 fib6_rules_cleanup(); 5109xfrm6_init: 5110 xfrm6_fini(); 5111out_fib6_init: 5112 fib6_gc_cleanup(); 5113out_register_subsys: --- 22 unchanged lines hidden --- |