summaryrefslogtreecommitdiff
path: root/net/ipv6/route.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r--net/ipv6/route.c75
1 files changed, 59 insertions, 16 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 1e19508..2ee530d 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -623,7 +623,7 @@ static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict,
goto out;
m = rt6_score_route(rt, oif, strict);
- if (m == RT6_NUD_FAIL_SOFT) {
+ if (m == RT6_NUD_FAIL_SOFT && !IS_ENABLED(CONFIG_IPV6_ROUTER_PREF)) {
match_do_rr = true;
m = 0; /* lowest valid score */
} else if (m < 0) {
@@ -735,11 +735,8 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
prefix = &prefix_buf;
}
- if (rinfo->prefix_len == 0)
- rt = rt6_get_dflt_router(gwaddr, dev);
- else
- rt = rt6_get_route_info(net, prefix, rinfo->prefix_len,
- gwaddr, dev->ifindex);
+ rt = rt6_get_route_info(net, prefix, rinfo->prefix_len, gwaddr,
+ dev->ifindex);
if (rt && !lifetime) {
ip6_del_rt(rt);
@@ -883,9 +880,11 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort,
rt = ip6_rt_copy(ort, daddr);
if (rt) {
- if (ort->rt6i_dst.plen != 128 &&
- ipv6_addr_equal(&ort->rt6i_dst.addr, daddr))
- rt->rt6i_flags |= RTF_ANYCAST;
+ if (!(rt->rt6i_flags & RTF_GATEWAY)) {
+ if (ort->rt6i_dst.plen != 128 &&
+ ipv6_addr_equal(&ort->rt6i_dst.addr, daddr))
+ rt->rt6i_flags |= RTF_ANYCAST;
+ }
rt->rt6i_flags |= RTF_CACHE;
@@ -1098,13 +1097,10 @@ static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
if (rt->rt6i_genid != rt_genid_ipv6(dev_net(rt->dst.dev)))
return NULL;
- if (!rt->rt6i_node || (rt->rt6i_node->fn_sernum != cookie))
- return NULL;
-
- if (rt6_check_expired(rt))
- return NULL;
+ if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie))
+ return dst;
- return dst;
+ return NULL;
}
static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
@@ -1174,6 +1170,7 @@ void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
memset(&fl6, 0, sizeof(fl6));
fl6.flowi6_oif = oif;
fl6.flowi6_mark = mark;
+ fl6.flowi6_flags = 0;
fl6.daddr = iph->daddr;
fl6.saddr = iph->saddr;
fl6.flowlabel = ip6_flowinfo(iph);
@@ -1272,6 +1269,7 @@ void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark)
memset(&fl6, 0, sizeof(fl6));
fl6.flowi6_oif = oif;
fl6.flowi6_mark = mark;
+ fl6.flowi6_flags = 0;
fl6.daddr = iph->daddr;
fl6.saddr = iph->saddr;
fl6.flowlabel = ip6_flowinfo(iph);
@@ -1293,6 +1291,7 @@ void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif,
memset(&fl6, 0, sizeof(fl6));
fl6.flowi6_oif = oif;
fl6.flowi6_mark = mark;
+ fl6.flowi6_flags = 0;
fl6.daddr = msg->dest;
fl6.saddr = iph->daddr;
@@ -2845,12 +2844,56 @@ static int ip6_route_dev_notify(struct notifier_block *this,
#ifdef CONFIG_PROC_FS
+struct rt6_proc_arg
+{
+ char *buffer;
+ int offset;
+ int length;
+ int skip;
+ int len;
+};
+
+static int rt6_info_route(struct rt6_info *rt, void *p_arg)
+{
+ struct seq_file *m = p_arg;
+
+ seq_printf(m, "%pi6 %02x ", &rt->rt6i_dst.addr, rt->rt6i_dst.plen);
+
+#ifdef CONFIG_IPV6_SUBTREES
+ seq_printf(m, "%pi6 %02x ", &rt->rt6i_src.addr, rt->rt6i_src.plen);
+#else
+ seq_puts(m, "00000000000000000000000000000000 00 ");
+#endif
+ if (rt->rt6i_flags & RTF_GATEWAY) {
+ seq_printf(m, "%pi6", &rt->rt6i_gateway);
+ } else {
+ seq_puts(m, "00000000000000000000000000000000");
+ }
+ seq_printf(m, " %08x %08x %08x %08x %8s\n",
+ rt->rt6i_metric, atomic_read(&rt->dst.__refcnt),
+ rt->dst.__use, rt->rt6i_flags,
+ rt->dst.dev ? rt->dst.dev->name : "");
+ return 0;
+}
+
+static int ipv6_route_show(struct seq_file *m, void *v)
+{
+ struct net *net = (struct net *)m->private;
+ fib6_clean_all_ro(net, rt6_info_route, 0, m);
+ return 0;
+}
+
+static int ipv6_route_open(struct inode *inode, struct file *file)
+{
+ return single_open_net(inode, file, ipv6_route_show);
+}
+
static const struct file_operations ipv6_route_proc_fops = {
.owner = THIS_MODULE,
.open = ipv6_route_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release_net,
+ .release = single_release_net,
};
static int rt6_stats_seq_show(struct seq_file *seq, void *v)