|
@@ -2143,6 +2143,34 @@ int ip6_del_rt(struct rt6_info *rt)
|
|
|
return __ip6_del_rt(rt, &info);
|
|
|
}
|
|
|
|
|
|
+static int __ip6_del_rt_siblings(struct rt6_info *rt, struct fib6_config *cfg)
|
|
|
+{
|
|
|
+ struct nl_info *info = &cfg->fc_nlinfo;
|
|
|
+ struct fib6_table *table;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ table = rt->rt6i_table;
|
|
|
+ write_lock_bh(&table->tb6_lock);
|
|
|
+
|
|
|
+ if (rt->rt6i_nsiblings && cfg->fc_delete_all_nh) {
|
|
|
+ struct rt6_info *sibling, *next_sibling;
|
|
|
+
|
|
|
+ list_for_each_entry_safe(sibling, next_sibling,
|
|
|
+ &rt->rt6i_siblings,
|
|
|
+ rt6i_siblings) {
|
|
|
+ err = fib6_del(sibling, info);
|
|
|
+ if (err)
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ err = fib6_del(rt, info);
|
|
|
+out:
|
|
|
+ write_unlock_bh(&table->tb6_lock);
|
|
|
+ ip6_rt_put(rt);
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
static int ip6_route_del(struct fib6_config *cfg)
|
|
|
{
|
|
|
struct fib6_table *table;
|
|
@@ -2179,7 +2207,11 @@ static int ip6_route_del(struct fib6_config *cfg)
|
|
|
dst_hold(&rt->dst);
|
|
|
read_unlock_bh(&table->tb6_lock);
|
|
|
|
|
|
- return __ip6_del_rt(rt, &cfg->fc_nlinfo);
|
|
|
+ /* if gateway was specified only delete the one hop */
|
|
|
+ if (cfg->fc_flags & RTF_GATEWAY)
|
|
|
+ return __ip6_del_rt(rt, &cfg->fc_nlinfo);
|
|
|
+
|
|
|
+ return __ip6_del_rt_siblings(rt, cfg);
|
|
|
}
|
|
|
}
|
|
|
read_unlock_bh(&table->tb6_lock);
|
|
@@ -3142,8 +3174,10 @@ static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|
|
|
|
|
if (cfg.fc_mp)
|
|
|
return ip6_route_multipath_del(&cfg);
|
|
|
- else
|
|
|
+ else {
|
|
|
+ cfg.fc_delete_all_nh = 1;
|
|
|
return ip6_route_del(&cfg);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh)
|