struct sk_buff *skb, u32 mtu);
static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk,
struct sk_buff *skb);
+static int rt6_score_route(struct rt6_info *rt, int oif, int strict);
#ifdef CONFIG_IPV6_ROUTE_INFO
static struct rt6_info *rt6_add_route_info(struct net *net,
}
static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
- struct flowi6 *fl6)
+ struct flowi6 *fl6, int oif,
+ int strict)
{
struct rt6_info *sibling, *next_sibling;
int route_choosen;
&match->rt6i_siblings, rt6i_siblings) {
route_choosen--;
if (route_choosen == 0) {
+ if (rt6_score_route(sibling, oif, strict) < 0)
+ break;
match = sibling;
break;
}
ret = true;
#endif
read_unlock(&neigh->lock);
+ } else if (IS_ENABLED(CONFIG_IPV6_ROUTER_PREF)) {
+ ret = true;
}
rcu_read_unlock_bh();
rt = fn->leaf;
rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags);
if (rt->rt6i_nsiblings && fl6->flowi6_oif == 0)
- rt = rt6_multipath_select(rt, fl6);
+ rt = rt6_multipath_select(rt, fl6, fl6->flowi6_oif, flags);
BACKTRACK(net, &fl6->saddr);
out:
dst_use(&rt->dst, jiffies);
restart:
rt = rt6_select(fn, oif, strict | reachable);
- if (rt->rt6i_nsiblings && oif == 0)
- rt = rt6_multipath_select(rt, fl6);
+ if (rt->rt6i_nsiblings)
+ rt = rt6_multipath_select(rt, fl6, oif, strict | reachable);
BACKTRACK(net, &fl6->saddr);
if (rt == net->ipv6.ip6_null_entry ||
rt->rt6i_flags & RTF_CACHE)
int optlen, on_link;
u8 *lladdr;
- optlen = skb->tail - skb->transport_header;
+ optlen = skb_tail_pointer(skb) - skb_transport_header(skb);
optlen -= sizeof(*msg);
if (optlen < 0) {
}
static int ip6_route_dev_notify(struct notifier_block *this,
- unsigned long event, void *data)
+ unsigned long event, void *ptr)
{
- struct net_device *dev = (struct net_device *)data;
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct net *net = dev_net(dev);
if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) {
#ifdef CONFIG_SYSCTL
static
-int ipv6_sysctl_rtcache_flush(ctl_table *ctl, int write,
+int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
struct net *net;
return 0;
}
-ctl_table ipv6_route_table_template[] = {
+struct ctl_table ipv6_route_table_template[] = {
{
.procname = "flush",
.data = &init_net.ipv6.sysctl.flush_delay,