diff options
author | Nicolas Dichtel <nicolas.dichtel@6wind.com> | 2012-09-04 22:12:42 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-09-05 17:49:28 -0400 |
commit | ef2c7d7b59708d54213c7556a82d14de9a7e4475 (patch) | |
tree | ffbcd9a25aeeef8e73faf8650605abb2dcdb6fb4 /net/ipv6/route.c | |
parent | d6b6d987787876fd381bfeda310c6682d425c0a2 (diff) |
ipv6: fix handling of blackhole and prohibit routes
When adding a blackhole or a prohibit route, they were handling like classic
routes. Moreover, it was only possible to add this kind of routes by specifying
an interface.
Bug already reported here:
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=498498
Before the patch:
$ ip route add blackhole 2001::1/128
RTNETLINK answers: No such device
$ ip route add blackhole 2001::1/128 dev eth0
$ ip -6 route | grep 2001
2001::1 dev eth0 metric 1024
After:
$ ip route add blackhole 2001::1/128
$ ip -6 route | grep 2001
blackhole 2001::1 dev lo metric 1024 error -22
v2: wrong patch
v3: add a field fc_type in struct fib6_config to store RTN_* type
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r-- | net/ipv6/route.c | 32 |
1 files changed, 28 insertions, 4 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 0ddf2d132e7f..fa264447a751 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -1463,8 +1463,18 @@ int ip6_route_add(struct fib6_config *cfg) | |||
1463 | } | 1463 | } |
1464 | rt->dst.output = ip6_pkt_discard_out; | 1464 | rt->dst.output = ip6_pkt_discard_out; |
1465 | rt->dst.input = ip6_pkt_discard; | 1465 | rt->dst.input = ip6_pkt_discard; |
1466 | rt->dst.error = -ENETUNREACH; | ||
1467 | rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP; | 1466 | rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP; |
1467 | switch (cfg->fc_type) { | ||
1468 | case RTN_BLACKHOLE: | ||
1469 | rt->dst.error = -EINVAL; | ||
1470 | break; | ||
1471 | case RTN_PROHIBIT: | ||
1472 | rt->dst.error = -EACCES; | ||
1473 | break; | ||
1474 | default: | ||
1475 | rt->dst.error = -ENETUNREACH; | ||
1476 | break; | ||
1477 | } | ||
1468 | goto install_route; | 1478 | goto install_route; |
1469 | } | 1479 | } |
1470 | 1480 | ||
@@ -2261,8 +2271,11 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
2261 | cfg->fc_src_len = rtm->rtm_src_len; | 2271 | cfg->fc_src_len = rtm->rtm_src_len; |
2262 | cfg->fc_flags = RTF_UP; | 2272 | cfg->fc_flags = RTF_UP; |
2263 | cfg->fc_protocol = rtm->rtm_protocol; | 2273 | cfg->fc_protocol = rtm->rtm_protocol; |
2274 | cfg->fc_type = rtm->rtm_type; | ||
2264 | 2275 | ||
2265 | if (rtm->rtm_type == RTN_UNREACHABLE) | 2276 | if (rtm->rtm_type == RTN_UNREACHABLE || |
2277 | rtm->rtm_type == RTN_BLACKHOLE || | ||
2278 | rtm->rtm_type == RTN_PROHIBIT) | ||
2266 | cfg->fc_flags |= RTF_REJECT; | 2279 | cfg->fc_flags |= RTF_REJECT; |
2267 | 2280 | ||
2268 | if (rtm->rtm_type == RTN_LOCAL) | 2281 | if (rtm->rtm_type == RTN_LOCAL) |
@@ -2391,8 +2404,19 @@ static int rt6_fill_node(struct net *net, | |||
2391 | rtm->rtm_table = table; | 2404 | rtm->rtm_table = table; |
2392 | if (nla_put_u32(skb, RTA_TABLE, table)) | 2405 | if (nla_put_u32(skb, RTA_TABLE, table)) |
2393 | goto nla_put_failure; | 2406 | goto nla_put_failure; |
2394 | if (rt->rt6i_flags & RTF_REJECT) | 2407 | if (rt->rt6i_flags & RTF_REJECT) { |
2395 | rtm->rtm_type = RTN_UNREACHABLE; | 2408 | switch (rt->dst.error) { |
2409 | case -EINVAL: | ||
2410 | rtm->rtm_type = RTN_BLACKHOLE; | ||
2411 | break; | ||
2412 | case -EACCES: | ||
2413 | rtm->rtm_type = RTN_PROHIBIT; | ||
2414 | break; | ||
2415 | default: | ||
2416 | rtm->rtm_type = RTN_UNREACHABLE; | ||
2417 | break; | ||
2418 | } | ||
2419 | } | ||
2396 | else if (rt->rt6i_flags & RTF_LOCAL) | 2420 | else if (rt->rt6i_flags & RTF_LOCAL) |
2397 | rtm->rtm_type = RTN_LOCAL; | 2421 | rtm->rtm_type = RTN_LOCAL; |
2398 | else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK)) | 2422 | else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK)) |