Release 4.11 net/ipv6/route.c
/*
* Linux INET6 implementation
* FIB front-end.
*
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
/* Changes:
*
* YOSHIFUJI Hideaki @USAGI
* reworked default router selection.
* - respect outgoing interface
* - select from (probably) reachable routers (i.e.
* routers in REACHABLE, STALE, DELAY or PROBE states).
* - always select the same router if it is (probably)
* reachable. otherwise, round-robin the list.
* Ville Nuorvala
* Fixed routing subtrees.
*/
#define pr_fmt(fmt) "IPv6: " fmt
#include <linux/capability.h>
#include <linux/errno.h>
#include <linux/export.h>
#include <linux/types.h>
#include <linux/times.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <linux/route.h>
#include <linux/netdevice.h>
#include <linux/in6.h>
#include <linux/mroute6.h>
#include <linux/init.h>
#include <linux/if_arp.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/nsproxy.h>
#include <linux/slab.h>
#include <net/net_namespace.h>
#include <net/snmp.h>
#include <net/ipv6.h>
#include <net/ip6_fib.h>
#include <net/ip6_route.h>
#include <net/ndisc.h>
#include <net/addrconf.h>
#include <net/tcp.h>
#include <linux/rtnetlink.h>
#include <net/dst.h>
#include <net/dst_metadata.h>
#include <net/xfrm.h>
#include <net/netevent.h>
#include <net/netlink.h>
#include <net/nexthop.h>
#include <net/lwtunnel.h>
#include <net/ip_tunnels.h>
#include <net/l3mdev.h>
#include <trace/events/fib6.h>
#include <linux/uaccess.h>
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
#endif
enum rt6_nud_state {
RT6_NUD_FAIL_HARD = -3,
RT6_NUD_FAIL_PROBE = -2,
RT6_NUD_FAIL_DO_RR = -1,
RT6_NUD_SUCCEED = 1
};
static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort);
static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie);
static unsigned int ip6_default_advmss(const struct dst_entry *dst);
static unsigned int ip6_mtu(const struct dst_entry *dst);
static struct dst_entry *ip6_negative_advice(struct dst_entry *);
static void ip6_dst_destroy(struct dst_entry *);
static void ip6_dst_ifdown(struct dst_entry *,
struct net_device *dev, int how);
static int ip6_dst_gc(struct dst_ops *ops);
static int ip6_pkt_discard(struct sk_buff *skb);
static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb);
static int ip6_pkt_prohibit(struct sk_buff *skb);
static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb);
static void ip6_link_failure(struct sk_buff *skb);
static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
struct sk_buff *skb, u32 mtu);
static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk,
struct sk_buff *skb);
static void rt6_dst_from_metrics_check(struct rt6_info *rt);
static int rt6_score_route(struct rt6_info *rt, int oif, int strict);
static size_t rt6_nlmsg_size(struct rt6_info *rt);
static int rt6_fill_node(struct net *net,
struct sk_buff *skb, struct rt6_info *rt,
struct in6_addr *dst, struct in6_addr *src,
int iif, int type, u32 portid, u32 seq,
unsigned int flags);
#ifdef CONFIG_IPV6_ROUTE_INFO
static struct rt6_info *rt6_add_route_info(struct net *net,
const struct in6_addr *prefix, int prefixlen,
const struct in6_addr *gwaddr,
struct net_device *dev,
unsigned int pref);
static struct rt6_info *rt6_get_route_info(struct net *net,
const struct in6_addr *prefix, int prefixlen,
const struct in6_addr *gwaddr,
struct net_device *dev);
#endif
struct uncached_list {
spinlock_t lock;
struct list_head head;
};
static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt6_uncached_list);
static void rt6_uncached_list_add(struct rt6_info *rt)
{
struct uncached_list *ul = raw_cpu_ptr(&rt6_uncached_list);
rt->dst.flags |= DST_NOCACHE;
rt->rt6i_uncached_list = ul;
spin_lock_bh(&ul->lock);
list_add_tail(&rt->rt6i_uncached, &ul->head);
spin_unlock_bh(&ul->lock);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin KaFai Lau | 65 | 100.00% | 1 | 100.00% |
Total | 65 | 100.00% | 1 | 100.00% |
static void rt6_uncached_list_del(struct rt6_info *rt)
{
if (!list_empty(&rt->rt6i_uncached)) {
struct uncached_list *ul = rt->rt6i_uncached_list;
spin_lock_bh(&ul->lock);
list_del(&rt->rt6i_uncached);
spin_unlock_bh(&ul->lock);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin KaFai Lau | 57 | 100.00% | 1 | 100.00% |
Total | 57 | 100.00% | 1 | 100.00% |
static void rt6_uncached_list_flush_dev(struct net *net, struct net_device *dev)
{
struct net_device *loopback_dev = net->loopback_dev;
int cpu;
if (dev == loopback_dev)
return;
for_each_possible_cpu(cpu) {
struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
struct rt6_info *rt;
spin_lock_bh(&ul->lock);
list_for_each_entry(rt, &ul->head, rt6i_uncached) {
struct inet6_dev *rt_idev = rt->rt6i_idev;
struct net_device *rt_dev = rt->dst.dev;
if (rt_idev->dev == dev) {
rt->rt6i_idev = in6_dev_get(loopback_dev);
in6_dev_put(rt_idev);
}
if (rt_dev == dev) {
rt->dst.dev = loopback_dev;
dev_hold(rt->dst.dev);
dev_put(rt_dev);
}
}
spin_unlock_bh(&ul->lock);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin KaFai Lau | 152 | 95.60% | 1 | 50.00% |
Eric W. Biedermann | 7 | 4.40% | 1 | 50.00% |
Total | 159 | 100.00% | 2 | 100.00% |
static u32 *rt6_pcpu_cow_metrics(struct rt6_info *rt)
{
return dst_metrics_write_ptr(rt->dst.from);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin KaFai Lau | 22 | 100.00% | 1 | 100.00% |
Total | 22 | 100.00% | 1 | 100.00% |
static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old)
{
struct rt6_info *rt = (struct rt6_info *)dst;
if (rt->rt6i_flags & RTF_PCPU)
return rt6_pcpu_cow_metrics(rt);
else if (rt->rt6i_flags & RTF_CACHE)
return NULL;
else
return dst_cow_metrics_generic(dst, old);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 30 | 47.62% | 1 | 20.00% |
Martin KaFai Lau | 27 | 42.86% | 3 | 60.00% |
Zheng Yan | 6 | 9.52% | 1 | 20.00% |
Total | 63 | 100.00% | 5 | 100.00% |
static inline const void *choose_neigh_daddr(struct rt6_info *rt,
struct sk_buff *skb,
const void *daddr)
{
struct in6_addr *p = &rt->rt6i_gateway;
if (!ipv6_addr_any(p))
return (const void *) p;
else if (skb)
return &ipv6_hdr(skb)->daddr;
return daddr;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 67 | 100.00% | 3 | 100.00% |
Total | 67 | 100.00% | 3 | 100.00% |
static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst,
struct sk_buff *skb,
const void *daddr)
{
struct rt6_info *rt = (struct rt6_info *) dst;
struct neighbour *n;
daddr = choose_neigh_daddr(rt, skb, daddr);
n = __ipv6_neigh_lookup(dst->dev, daddr);
if (n)
return n;
return neigh_create(&nd_tbl, daddr, dst->dev);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 83 | 100.00% | 4 | 100.00% |
Total | 83 | 100.00% | 4 | 100.00% |
static void ip6_confirm_neigh(const struct dst_entry *dst, const void *daddr)
{
struct net_device *dev = dst->dev;
struct rt6_info *rt = (struct rt6_info *)dst;
daddr = choose_neigh_daddr(rt, NULL, daddr);
if (!daddr)
return;
if (dev->flags & (IFF_NOARP | IFF_LOOPBACK))
return;
if (ipv6_addr_is_multicast((const struct in6_addr *)daddr))
return;
__ipv6_confirm_neigh(dev, daddr);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Julian Anastasov | 89 | 100.00% | 1 | 100.00% |
Total | 89 | 100.00% | 1 | 100.00% |
static struct dst_ops ip6_dst_ops_template = {
.family = AF_INET6,
.gc = ip6_dst_gc,
.gc_thresh = 1024,
.check = ip6_dst_check,
.default_advmss = ip6_default_advmss,
.mtu = ip6_mtu,
.cow_metrics = ipv6_cow_metrics,
.destroy = ip6_dst_destroy,
.ifdown = ip6_dst_ifdown,
.negative_advice = ip6_negative_advice,
.link_failure = ip6_link_failure,
.update_pmtu = ip6_rt_update_pmtu,
.redirect = rt6_do_redirect,
.local_out = __ip6_local_out,
.neigh_lookup = ip6_neigh_lookup,
.confirm_neigh = ip6_confirm_neigh,
};
static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst)
{
unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
return mtu ? : dst->dev->mtu;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Steffen Klassert | 20 | 58.82% | 3 | 75.00% |
Roland Dreier | 14 | 41.18% | 1 | 25.00% |
Total | 34 | 100.00% | 4 | 100.00% |
static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk,
struct sk_buff *skb, u32 mtu)
{
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 23 | 100.00% | 2 | 100.00% |
Total | 23 | 100.00% | 2 | 100.00% |
static void ip6_rt_blackhole_redirect(struct dst_entry *dst, struct sock *sk,
struct sk_buff *skb)
{
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 20 | 100.00% | 2 | 100.00% |
Total | 20 | 100.00% | 2 | 100.00% |
static struct dst_ops ip6_dst_blackhole_ops = {
.family = AF_INET6,
.destroy = ip6_dst_destroy,
.check = ip6_dst_check,
.mtu = ip6_blackhole_mtu,
.default_advmss = ip6_default_advmss,
.update_pmtu = ip6_rt_blackhole_update_pmtu,
.redirect = ip6_rt_blackhole_redirect,
.cow_metrics = dst_cow_metrics_generic,
.neigh_lookup = ip6_neigh_lookup,
};
static const u32 ip6_template_metrics[RTAX_MAX] = {
[RTAX_HOPLIMIT - 1] = 0,
};
static const struct rt6_info ip6_null_entry_template = {
.dst = {
.__refcnt = ATOMIC_INIT(1),
.__use = 1,
.obsolete = DST_OBSOLETE_FORCE_CHK,
.error = -ENETUNREACH,
.input = ip6_pkt_discard,
.output = ip6_pkt_discard_out,
},
.rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
.rt6i_protocol = RTPROT_KERNEL,
.rt6i_metric = ~(u32) 0,
.rt6i_ref = ATOMIC_INIT(1),
};
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
static const struct rt6_info ip6_prohibit_entry_template = {
.dst = {
.__refcnt = ATOMIC_INIT(1),
.__use = 1,
.obsolete = DST_OBSOLETE_FORCE_CHK,
.error = -EACCES,
.input = ip6_pkt_prohibit,
.output = ip6_pkt_prohibit_out,
},
.rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
.rt6i_protocol = RTPROT_KERNEL,
.rt6i_metric = ~(u32) 0,
.rt6i_ref = ATOMIC_INIT(1),
};
static const struct rt6_info ip6_blk_hole_entry_template = {
.dst = {
.__refcnt = ATOMIC_INIT(1),
.__use = 1,
.obsolete = DST_OBSOLETE_FORCE_CHK,
.error = -EINVAL,
.input = dst_discard,
.output = dst_discard_out,
},
.rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
.rt6i_protocol = RTPROT_KERNEL,
.rt6i_metric = ~(u32) 0,
.rt6i_ref = ATOMIC_INIT(1),
};
#endif
static void rt6_info_init(struct rt6_info *rt)
{
struct dst_entry *dst = &rt->dst;
memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst));
INIT_LIST_HEAD(&rt->rt6i_siblings);
INIT_LIST_HEAD(&rt->rt6i_uncached);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David S. Miller | 21 | 36.21% | 2 | 22.22% |
Steffen Klassert | 14 | 24.14% | 1 | 11.11% |
Martin KaFai Lau | 11 | 18.97% | 2 | 22.22% |
Nicolas Dichtel | 8 | 13.79% | 1 | 11.11% |
Hideaki Yoshifuji / 吉藤英明 | 2 | 3.45% | 2 | 22.22% |
Benjamin Thery | 2 | 3.45% | 1 | 11.11% |
Total | 58 | 100.00% | 9 | 100.00% |
/* allocate dst with ip6_dst_ops */
static struct rt6_info *__ip6_dst_alloc(struct net *net,
struct net_device *dev,
int flags)
{
struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
0, DST_OBSOLETE_FORCE_CHK, flags);
if (rt)
rt6_info_init(rt);
return rt;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin KaFai Lau | 52 | 92.86% | 1 | 33.33% |
David S. Miller | 2 | 3.57% | 1 | 33.33% |
Kazunori Miyazawa | 2 | 3.57% | 1 | 33.33% |
Total | 56 | 100.00% | 3 | 100.00% |
struct rt6_info *ip6_dst_alloc(struct net *net,
struct net_device *dev,
int flags)
{
struct rt6_info *rt = __ip6_dst_alloc(net, dev, flags);
if (rt) {
rt->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, GFP_ATOMIC);
if (rt->rt6i_pcpu) {
int cpu;
for_each_possible_cpu(cpu) {
struct rt6_info **p;
p = per_cpu_ptr(rt->rt6i_pcpu, cpu);
/* no one shares rt */
*p = NULL;
}
} else {
dst_destroy((struct dst_entry *)rt);
return NULL;
}
}
return rt;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin KaFai Lau | 112 | 100.00% | 1 | 100.00% |
Total | 112 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL(ip6_dst_alloc);
static void ip6_dst_destroy(struct dst_entry *dst)
{
struct rt6_info *rt = (struct rt6_info *)dst;
struct dst_entry *from = dst->from;
struct inet6_dev *idev;
dst_destroy_metrics_generic(dst);
free_percpu(rt->rt6i_pcpu);
rt6_uncached_list_del(rt);
idev = rt->rt6i_idev;
if (idev) {
rt->rt6i_idev = NULL;
in6_dev_put(idev);
}
dst->from = NULL;
dst_release(from);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hideaki Yoshifuji / 吉藤英明 | 49 | 55.68% | 3 | 37.50% |
Martin KaFai Lau | 23 | 26.14% | 2 | 25.00% |
Gao Feng | 8 | 9.09% | 1 | 12.50% |
Zheng Yan | 7 | 7.95% | 1 | 12.50% |
David S. Miller | 1 | 1.14% | 1 | 12.50% |
Total | 88 | 100.00% | 8 | 100.00% |
static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
int how)
{
struct rt6_info *rt = (struct rt6_info *)dst;
struct inet6_dev *idev = rt->rt6i_idev;
struct net_device *loopback_dev =
dev_net(dev)->loopback_dev;
if (dev != loopback_dev) {
if (idev && idev->dev == dev) {
struct inet6_dev *loopback_idev =
in6_dev_get(loopback_dev);
if (loopback_idev) {
rt->rt6i_idev = loopback_idev;
in6_dev_put(idev);
}
}
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hideaki Yoshifuji / 吉藤英明 | 75 | 75.76% | 4 | 57.14% |
Herbert Xu | 10 | 10.10% | 1 | 14.29% |
Denis V. Lunev | 9 | 9.09% | 1 | 14.29% |
David S. Miller | 5 | 5.05% | 1 | 14.29% |
Total | 99 | 100.00% | 7 | 100.00% |
static bool __rt6_check_expired(const struct rt6_info *rt)
{
if (rt->rt6i_flags & RTF_EXPIRES)
return time_after(jiffies, rt->dst.expires);
else
return false;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Martin KaFai Lau | 36 | 100.00% | 1 | 100.00% |
Total | 36 | 100.00% | 1 | 100.00% |
static bool rt6_check_expired(const struct rt6_info *rt)
{
if (rt->rt6i_flags & RTF_EXPIRES) {
if (time_after(jiffies, rt->dst.expires))
return true;
} else if (rt->dst.from) {
return rt6_check_expired((struct rt6_info *) rt->dst.from);
}
return false;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Gao Feng | 44 | 65.67% | 1 | 25.00% |
Hideaki Yoshifuji / 吉藤英明 | 17 | 25.37% | 1 | 25.00% |
Li RongQing | 3 | 4.48% | 1 | 25.00% |
Eric Dumazet | 3 | 4.48% | 1 | 25.00% |
Total | 67 | 100.00% | 4 | 100.00% |
/* Multipath route selection:
* Hash based function using packet header and flowlabel.
* Adapted from fib_info_hashfn()
*/
static int rt6_info_hash_nhsfn(unsigned int candidate_count,
const struct flowi6 *fl6)
{
return get_hash_from_flowi6(fl6) % candidate_count;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Nicolas Dichtel | 20 | 83.33% | 1 | 33.33% |
Hideaki Yoshifuji / 吉藤英明 | 2 | 8.33% | 1 | 33.33% |
Tom Herbert | 2 | 8.33% | 1 | 33.33% |
Total | 24 | 100.00% | 3 | 100.00% |
static struct rt6_info *rt6_multipath_select(struct rt6_info *match,
struct flowi6 *fl6, int oif,
int strict)
{
struct rt6_info *sibling, *next_sibling;
int route_choosen;
route_choosen = rt6_info_hash_nhsfn(match->rt6i_nsiblings + 1, fl6);
/* Don't change the route, if route_choosen == 0
* (siblings does not include ourself)
*/
if (route_choosen)
list_for_each_entry_safe(sibling, next_sibling,
&match->rt6i_siblings, rt6i_siblings) {
route_choosen--;
if (route_choosen == 0) {
if (rt6_score_route(sibling, oif, strict) < 0)
break;
match = sibling;
break;
}
}
return match;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Nicolas Dichtel | 98 | 100.00% | 2 | 100.00% |
Total | 98 | 100.00% | 2 | 100.00% |
/*
* Route lookup. Any table->tb6_lock is implied.
*/
static inline struct rt6_info *rt6_device_match(struct net *net,
struct rt6_info *rt,
const struct in6_addr *saddr,
int oif,
int flags)
{
struct rt6_info *local = NULL;
struct rt6_info *sprt;
if (!oif && ipv6_addr_any(saddr))
goto out;
for (sprt = rt; sprt; sprt = sprt->dst.rt6_next) {
struct net_device *dev = sprt->dst.dev;
if (oif) {
if (dev->ifindex == oif)
return sprt;
if (dev->flags & IFF_LOOPBACK) {
if (!sprt->rt6i_idev ||
sprt->rt6i_idev->dev->ifindex != oif) {
if (flags & RT6_LOOKUP_F_IFACE)
continue;
if (local &&
local->rt6i_idev->dev->ifindex == oif)
continue;
}
local = sprt;
}
} else {
if (ipv6_chk_addr(net, saddr, dev,
flags & RT6_LOOKUP_F_IFACE))
return sprt;
}
}
if (oif) {
if (local)
return local;
if (flags & RT6_LOOKUP_F_IFACE)
return net->ipv6.ip6_null_entry;
}
out:
return rt;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hideaki Yoshifuji / 吉藤英明 | 93 | 44.50% | 4 | 33.33% |
Linus Torvalds (pre-git) | 71 | 33.97% | 3 | 25.00% |
Daniel Lezcano | 37 | 17.70% | 1 | 8.33% |
Eric Dumazet | 4 | 1.91% | 2 | 16.67% |
David S. Miller | 4 | 1.91% | 2 | 16.67% |
Total | 209 | 100.00% | 12 | 100.00% |
#ifdef CONFIG_IPV6_ROUTER_PREF
struct __rt6_probe_work {
struct work_struct work;
struct in6_addr target;
struct net_device *dev;
};
static void rt6_probe_deferred(struct work_struct *w)
{
struct in6_addr mcaddr;
struct __rt6_probe_work *work =
container_of(w, struct __rt6_probe_work, work);
addrconf_addr_solict_mult(&work->target, &mcaddr);
ndisc_send_ns(work->dev, &work->target, &mcaddr, NULL, 0);
dev_put(work->dev);
kfree(work);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hannes Frederic Sowa | 69 | 95.83% | 1 | 33.33% |
Erik Nordmark | 2 | 2.78% | 1 | 33.33% |
Michael Büsch | 1 | 1.39% | 1 | 33.33% |
Total | 72 | 100.00% | 3 | 100.00% |
static void rt6_probe(struct rt6_info *rt)
{
struct __rt6_probe_work *work;
struct neighbour *neigh;
/*
* Okay, this does not seem to be appropriate
* for now, however, we need to check if it
* is really so; aka Router Reachability Probing.
*
* Router Reachability Probe MUST be rate-limited
* to no more than one per minute.
*/
if (!rt || !(rt->rt6i_flags & RTF_GATEWAY))
return;
rcu_read_lock_bh();
neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
if (neigh) {
if (neigh->nud_state & NUD_VALID)
goto out;
work = NULL;
write_lock(&neigh->lock);
if (!(neigh->nud_state & NUD_VALID) &&
time_after(jiffies,
neigh->updated +
rt->rt6i_idev->cnf.rtr_probe_interval)) {
work = kmalloc(sizeof(*work), GFP_ATOMIC);
if (work)
__neigh_set_probe_once(neigh);
}
write_unlock(&neigh->lock);
} else {
work = kmalloc(sizeof(*work), GFP_ATOMIC);
}
if (work) {
INIT_WORK(&work->work, rt6_probe_deferred);
work->target = rt->rt6i_gateway;
dev_hold(rt->dst.dev);
work->dev = rt->dst.dev;
schedule_work(&work->work);
}
out:
rcu_read_unlock_bh();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hideaki Yoshifuji / 吉藤英明 | 113 | 52.07% | 5 | 41.67% |
Hannes Frederic Sowa | 47 | 21.66% | 1 | 8.33% |
Martin KaFai Lau | 44 | 20.28% | 2 | 16.67% |
Eric Dumazet | 6 | 2.76% | 1 | 8.33% |
Jiri Benc | 3 | 1.38% | 1 | 8.33% |
David S. Miller | 3 | 1.38% | 1 | 8.33% |
Daniel Lezcano | 1 | 0.46% | 1 | 8.33% |
Total | 217 | 100.00% | 12 | 100.00% |
#else
static inline void rt6_probe(struct rt6_info *rt)
{
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hideaki Yoshifuji / 吉藤英明 | 10 | 90.91% | 1 | 50.00% |
Joe Perches | 1 | 9.09% | 1 | 50.00% |
Total | 11 | 100.00% | 2 | 100.00% |
#endif
/*
* Default Router Selection (RFC 2461 6.3.6)
*/
static inline int rt6_check_dev(struct rt6_info *rt, int oif)
{
struct net_device *dev = rt->dst.dev;
if (!oif || dev->ifindex == oif)
return 2;
if ((dev->flags & IFF_LOOPBACK) &&
rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif)
return 1;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hideaki Yoshifuji / 吉藤英明 | 55 | 78.57% | 4 | 57.14% |
David S. Miller | 14 | 20.00% | 2 | 28.57% |
Dave Jones | 1 | 1.43% | 1 | 14.29% |
Total | 70 | 100.00% | 7 | 100.00% |
static inline enum rt6_nud_state rt6_check_neigh(struct rt6_info *rt)