aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/route.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r--net/ipv6/route.c44
1 files changed, 11 insertions, 33 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index fba54a407bb2..b93ae6a6a31c 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -149,7 +149,8 @@ static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old)
149 unsigned long prev, new; 149 unsigned long prev, new;
150 150
151 p = peer->metrics; 151 p = peer->metrics;
152 if (inet_metrics_new(peer)) 152 if (inet_metrics_new(peer) ||
153 (old & DST_METRICS_FORCE_OVERWRITE))
153 memcpy(p, old_p, sizeof(u32) * RTAX_MAX); 154 memcpy(p, old_p, sizeof(u32) * RTAX_MAX);
154 155
155 new = (unsigned long) p; 156 new = (unsigned long) p;
@@ -857,14 +858,15 @@ EXPORT_SYMBOL(rt6_lookup);
857 be destroyed. 858 be destroyed.
858 */ 859 */
859 860
860static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info) 861static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info,
862 struct nlattr *mx, int mx_len)
861{ 863{
862 int err; 864 int err;
863 struct fib6_table *table; 865 struct fib6_table *table;
864 866
865 table = rt->rt6i_table; 867 table = rt->rt6i_table;
866 write_lock_bh(&table->tb6_lock); 868 write_lock_bh(&table->tb6_lock);
867 err = fib6_add(&table->tb6_root, rt, info); 869 err = fib6_add(&table->tb6_root, rt, info, mx, mx_len);
868 write_unlock_bh(&table->tb6_lock); 870 write_unlock_bh(&table->tb6_lock);
869 871
870 return err; 872 return err;
@@ -875,7 +877,7 @@ int ip6_ins_rt(struct rt6_info *rt)
875 struct nl_info info = { 877 struct nl_info info = {
876 .nl_net = dev_net(rt->dst.dev), 878 .nl_net = dev_net(rt->dst.dev),
877 }; 879 };
878 return __ip6_ins_rt(rt, &info); 880 return __ip6_ins_rt(rt, &info, NULL, 0);
879} 881}
880 882
881static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, 883static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort,
@@ -1543,17 +1545,11 @@ int ip6_route_add(struct fib6_config *cfg)
1543 1545
1544 ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len); 1546 ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
1545 rt->rt6i_dst.plen = cfg->fc_dst_len; 1547 rt->rt6i_dst.plen = cfg->fc_dst_len;
1546 if (rt->rt6i_dst.plen == 128) 1548 if (rt->rt6i_dst.plen == 128) {
1547 rt->dst.flags |= DST_HOST; 1549 rt->dst.flags |= DST_HOST;
1548 1550 dst_metrics_set_force_overwrite(&rt->dst);
1549 if (!(rt->dst.flags & DST_HOST) && cfg->fc_mx) {
1550 u32 *metrics = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
1551 if (!metrics) {
1552 err = -ENOMEM;
1553 goto out;
1554 }
1555 dst_init_metrics(&rt->dst, metrics, 0);
1556 } 1551 }
1552
1557#ifdef CONFIG_IPV6_SUBTREES 1553#ifdef CONFIG_IPV6_SUBTREES
1558 ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len); 1554 ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len);
1559 rt->rt6i_src.plen = cfg->fc_src_len; 1555 rt->rt6i_src.plen = cfg->fc_src_len;
@@ -1672,31 +1668,13 @@ int ip6_route_add(struct fib6_config *cfg)
1672 rt->rt6i_flags = cfg->fc_flags; 1668 rt->rt6i_flags = cfg->fc_flags;
1673 1669
1674install_route: 1670install_route:
1675 if (cfg->fc_mx) {
1676 struct nlattr *nla;
1677 int remaining;
1678
1679 nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) {
1680 int type = nla_type(nla);
1681
1682 if (type) {
1683 if (type > RTAX_MAX) {
1684 err = -EINVAL;
1685 goto out;
1686 }
1687
1688 dst_metric_set(&rt->dst, type, nla_get_u32(nla));
1689 }
1690 }
1691 }
1692
1693 rt->dst.dev = dev; 1671 rt->dst.dev = dev;
1694 rt->rt6i_idev = idev; 1672 rt->rt6i_idev = idev;
1695 rt->rt6i_table = table; 1673 rt->rt6i_table = table;
1696 1674
1697 cfg->fc_nlinfo.nl_net = dev_net(dev); 1675 cfg->fc_nlinfo.nl_net = dev_net(dev);
1698 1676
1699 return __ip6_ins_rt(rt, &cfg->fc_nlinfo); 1677 return __ip6_ins_rt(rt, &cfg->fc_nlinfo, cfg->fc_mx, cfg->fc_mx_len);
1700 1678
1701out: 1679out:
1702 if (dev) 1680 if (dev)