Loading include/net/ip6_route.h +0 −2 Original line number Original line Diff line number Diff line Loading @@ -91,8 +91,6 @@ extern struct rt6_info * rt6_add_dflt_router(struct in6_addr *gwaddr, extern void rt6_purge_dflt_routers(void); extern void rt6_purge_dflt_routers(void); extern void rt6_reset_dflt_pointer(struct rt6_info *rt); extern void rt6_redirect(struct in6_addr *dest, extern void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr, struct in6_addr *saddr, struct neighbour *neigh, struct neighbour *neigh, Loading net/ipv6/ip6_fib.c +0 −1 Original line number Original line Diff line number Diff line Loading @@ -1105,7 +1105,6 @@ static int fib6_age(struct rt6_info *rt, void *arg) if (rt->rt6i_flags&RTF_EXPIRES && rt->rt6i_expires) { if (rt->rt6i_flags&RTF_EXPIRES && rt->rt6i_expires) { if (time_after(now, rt->rt6i_expires)) { if (time_after(now, rt->rt6i_expires)) { RT6_TRACE("expiring %p\n", rt); RT6_TRACE("expiring %p\n", rt); rt6_reset_dflt_pointer(rt); return -1; return -1; } } gc_args.more++; gc_args.more++; Loading net/ipv6/route.c +69 −128 Original line number Original line Diff line number Diff line Loading @@ -74,6 +74,9 @@ #define CLONE_OFFLINK_ROUTE 0 #define CLONE_OFFLINK_ROUTE 0 #define RT6_SELECT_F_IFACE 0x1 #define RT6_SELECT_F_REACHABLE 0x2 static int ip6_rt_max_size = 4096; static int ip6_rt_max_size = 4096; static int ip6_rt_gc_min_interval = HZ / 2; static int ip6_rt_gc_min_interval = HZ / 2; static int ip6_rt_gc_timeout = 60*HZ; static int ip6_rt_gc_timeout = 60*HZ; Loading Loading @@ -216,148 +219,89 @@ static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt, } } /* /* * pointer to the last default router chosen. BH is disabled locally. * Default Router Selection (RFC 2461 6.3.6) */ */ static struct rt6_info *rt6_dflt_pointer; static int inline rt6_check_dev(struct rt6_info *rt, int oif) static DEFINE_SPINLOCK(rt6_dflt_lock); void rt6_reset_dflt_pointer(struct rt6_info *rt) { { spin_lock_bh(&rt6_dflt_lock); struct net_device *dev = rt->rt6i_dev; if (rt == NULL || rt == rt6_dflt_pointer) { if (!oif || dev->ifindex == oif) RT6_TRACE("reset default router: %p->NULL\n", rt6_dflt_pointer); return 2; rt6_dflt_pointer = NULL; if ((dev->flags & IFF_LOOPBACK) && } rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif) spin_unlock_bh(&rt6_dflt_lock); return 1; return 0; } } /* Default Router Selection (RFC 2461 6.3.6) */ static int inline rt6_check_neigh(struct rt6_info *rt) static struct rt6_info *rt6_best_dflt(struct rt6_info *rt, int oif) { { struct rt6_info *match = NULL; struct neighbour *neigh = rt->rt6i_nexthop; struct rt6_info *sprt; int mpri = 0; for (sprt = rt; sprt; sprt = sprt->u.next) { struct neighbour *neigh; int m = 0; int m = 0; if (neigh) { read_lock_bh(&neigh->lock); if (neigh->nud_state & NUD_VALID) m = 1; read_unlock_bh(&neigh->lock); } return m; } if (!oif || static int rt6_score_route(struct rt6_info *rt, int oif, (sprt->rt6i_dev && int strict) sprt->rt6i_dev->ifindex == oif)) { m += 8; int m = rt6_check_dev(rt, oif); if (!m && (strict & RT6_SELECT_F_IFACE)) return -1; if (rt6_check_neigh(rt)) m |= 4; else if (strict & RT6_SELECT_F_REACHABLE) return -1; return m; } if (rt6_check_expired(sprt)) static struct rt6_info *rt6_select(struct rt6_info **head, int oif, continue; int strict) { struct rt6_info *match = NULL, *last = NULL; struct rt6_info *rt, *rt0 = *head; u32 metric; int mpri = -1; if (sprt == rt6_dflt_pointer) RT6_TRACE("%s(head=%p(*head=%p), oif=%d)\n", m += 4; __FUNCTION__, head, head ? *head : NULL, oif); if ((neigh = sprt->rt6i_nexthop) != NULL) { for (rt = rt0, metric = rt0->rt6i_metric; read_lock_bh(&neigh->lock); rt && rt->rt6i_metric == metric; switch (neigh->nud_state) { rt = rt->u.next) { case NUD_REACHABLE: int m; m += 3; break; case NUD_STALE: if (rt6_check_expired(rt)) case NUD_DELAY: continue; case NUD_PROBE: m += 2; break; case NUD_NOARP: last = rt; case NUD_PERMANENT: m += 1; break; case NUD_INCOMPLETE: m = rt6_score_route(rt, oif, strict); default: if (m < 0) read_unlock_bh(&neigh->lock); continue; } read_unlock_bh(&neigh->lock); } else { continue; continue; } if (m > mpri || m >= 12) { if (m > mpri) { match = sprt; match = rt; mpri = m; mpri = m; if (m >= 12) { /* we choose the last default router if it * is in (probably) reachable state. * If route changed, we should do pmtu * discovery. --yoshfuji */ break; } } } spin_lock(&rt6_dflt_lock); if (!match) { /* * No default routers are known to be reachable. * SHOULD round robin */ if (rt6_dflt_pointer) { for (sprt = rt6_dflt_pointer->u.next; sprt; sprt = sprt->u.next) { if (sprt->u.dst.obsolete <= 0 && sprt->u.dst.error == 0 && !rt6_check_expired(sprt)) { match = sprt; break; } } for (sprt = rt; !match && sprt; sprt = sprt->u.next) { if (sprt->u.dst.obsolete <= 0 && sprt->u.dst.error == 0 && !rt6_check_expired(sprt)) { match = sprt; break; } if (sprt == rt6_dflt_pointer) break; } } } } } if (match) { if (!match && if (rt6_dflt_pointer != match) (strict & RT6_SELECT_F_REACHABLE) && RT6_TRACE("changed default router: %p->%p\n", last && last != rt0) { rt6_dflt_pointer, match); /* no entries matched; do round-robin */ rt6_dflt_pointer = match; *head = rt0->u.next; rt0->u.next = last->u.next; last->u.next = rt0; } } spin_unlock(&rt6_dflt_lock); if (!match) { RT6_TRACE("%s() => %p, score=%d\n", /* __FUNCTION__, match, mpri); * Last Resort: if no default routers found, * use addrconf default route. * We don't record this route. */ for (sprt = ip6_routing_table.leaf; sprt; sprt = sprt->u.next) { if (!rt6_check_expired(sprt) && (sprt->rt6i_flags & RTF_DEFAULT) && (!oif || (sprt->rt6i_dev && sprt->rt6i_dev->ifindex == oif))) { match = sprt; break; } } if (!match) { /* no default route. give up. */ match = &ip6_null_entry; } } return match; return (match ? match : &ip6_null_entry); } } struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr, struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr, Loading Loading @@ -542,7 +486,7 @@ struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) int attempts = 3; int attempts = 3; int err; int err; strict = ipv6_addr_type(&fl->fl6_dst) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL); strict = ipv6_addr_type(&fl->fl6_dst) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL) ? RT6_SELECT_F_IFACE : 0; relookup: relookup: read_lock_bh(&rt6_lock); read_lock_bh(&rt6_lock); Loading @@ -558,8 +502,9 @@ struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) goto out; goto out; } } if (rt->rt6i_flags & RTF_DEFAULT) { if (rt->rt6i_flags & RTF_DEFAULT) { if (rt->rt6i_metric >= IP6_RT_PRIO_ADDRCONF) rt = rt6_select(&fn->leaf, fl->oif, strict | RT6_SELECT_F_REACHABLE); rt = rt6_best_dflt(rt, fl->oif); if (rt == &ip6_null_entry) rt = rt6_select(&fn->leaf, fl->oif, strict); } else { } else { rt = rt6_device_match(rt, fl->oif, strict); rt = rt6_device_match(rt, fl->oif, strict); BACKTRACK(); BACKTRACK(); Loading Loading @@ -1025,8 +970,6 @@ int ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct write_lock_bh(&rt6_lock); write_lock_bh(&rt6_lock); rt6_reset_dflt_pointer(NULL); err = fib6_del(rt, nlh, _rtattr, req); err = fib6_del(rt, nlh, _rtattr, req); dst_release(&rt->u.dst); dst_release(&rt->u.dst); Loading Loading @@ -1341,8 +1284,6 @@ void rt6_purge_dflt_routers(void) if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) { if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) { dst_hold(&rt->u.dst); dst_hold(&rt->u.dst); rt6_reset_dflt_pointer(NULL); read_unlock_bh(&rt6_lock); read_unlock_bh(&rt6_lock); ip6_del_rt(rt, NULL, NULL, NULL); ip6_del_rt(rt, NULL, NULL, NULL); Loading Loading
include/net/ip6_route.h +0 −2 Original line number Original line Diff line number Diff line Loading @@ -91,8 +91,6 @@ extern struct rt6_info * rt6_add_dflt_router(struct in6_addr *gwaddr, extern void rt6_purge_dflt_routers(void); extern void rt6_purge_dflt_routers(void); extern void rt6_reset_dflt_pointer(struct rt6_info *rt); extern void rt6_redirect(struct in6_addr *dest, extern void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr, struct in6_addr *saddr, struct neighbour *neigh, struct neighbour *neigh, Loading
net/ipv6/ip6_fib.c +0 −1 Original line number Original line Diff line number Diff line Loading @@ -1105,7 +1105,6 @@ static int fib6_age(struct rt6_info *rt, void *arg) if (rt->rt6i_flags&RTF_EXPIRES && rt->rt6i_expires) { if (rt->rt6i_flags&RTF_EXPIRES && rt->rt6i_expires) { if (time_after(now, rt->rt6i_expires)) { if (time_after(now, rt->rt6i_expires)) { RT6_TRACE("expiring %p\n", rt); RT6_TRACE("expiring %p\n", rt); rt6_reset_dflt_pointer(rt); return -1; return -1; } } gc_args.more++; gc_args.more++; Loading
net/ipv6/route.c +69 −128 Original line number Original line Diff line number Diff line Loading @@ -74,6 +74,9 @@ #define CLONE_OFFLINK_ROUTE 0 #define CLONE_OFFLINK_ROUTE 0 #define RT6_SELECT_F_IFACE 0x1 #define RT6_SELECT_F_REACHABLE 0x2 static int ip6_rt_max_size = 4096; static int ip6_rt_max_size = 4096; static int ip6_rt_gc_min_interval = HZ / 2; static int ip6_rt_gc_min_interval = HZ / 2; static int ip6_rt_gc_timeout = 60*HZ; static int ip6_rt_gc_timeout = 60*HZ; Loading Loading @@ -216,148 +219,89 @@ static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt, } } /* /* * pointer to the last default router chosen. BH is disabled locally. * Default Router Selection (RFC 2461 6.3.6) */ */ static struct rt6_info *rt6_dflt_pointer; static int inline rt6_check_dev(struct rt6_info *rt, int oif) static DEFINE_SPINLOCK(rt6_dflt_lock); void rt6_reset_dflt_pointer(struct rt6_info *rt) { { spin_lock_bh(&rt6_dflt_lock); struct net_device *dev = rt->rt6i_dev; if (rt == NULL || rt == rt6_dflt_pointer) { if (!oif || dev->ifindex == oif) RT6_TRACE("reset default router: %p->NULL\n", rt6_dflt_pointer); return 2; rt6_dflt_pointer = NULL; if ((dev->flags & IFF_LOOPBACK) && } rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif) spin_unlock_bh(&rt6_dflt_lock); return 1; return 0; } } /* Default Router Selection (RFC 2461 6.3.6) */ static int inline rt6_check_neigh(struct rt6_info *rt) static struct rt6_info *rt6_best_dflt(struct rt6_info *rt, int oif) { { struct rt6_info *match = NULL; struct neighbour *neigh = rt->rt6i_nexthop; struct rt6_info *sprt; int mpri = 0; for (sprt = rt; sprt; sprt = sprt->u.next) { struct neighbour *neigh; int m = 0; int m = 0; if (neigh) { read_lock_bh(&neigh->lock); if (neigh->nud_state & NUD_VALID) m = 1; read_unlock_bh(&neigh->lock); } return m; } if (!oif || static int rt6_score_route(struct rt6_info *rt, int oif, (sprt->rt6i_dev && int strict) sprt->rt6i_dev->ifindex == oif)) { m += 8; int m = rt6_check_dev(rt, oif); if (!m && (strict & RT6_SELECT_F_IFACE)) return -1; if (rt6_check_neigh(rt)) m |= 4; else if (strict & RT6_SELECT_F_REACHABLE) return -1; return m; } if (rt6_check_expired(sprt)) static struct rt6_info *rt6_select(struct rt6_info **head, int oif, continue; int strict) { struct rt6_info *match = NULL, *last = NULL; struct rt6_info *rt, *rt0 = *head; u32 metric; int mpri = -1; if (sprt == rt6_dflt_pointer) RT6_TRACE("%s(head=%p(*head=%p), oif=%d)\n", m += 4; __FUNCTION__, head, head ? *head : NULL, oif); if ((neigh = sprt->rt6i_nexthop) != NULL) { for (rt = rt0, metric = rt0->rt6i_metric; read_lock_bh(&neigh->lock); rt && rt->rt6i_metric == metric; switch (neigh->nud_state) { rt = rt->u.next) { case NUD_REACHABLE: int m; m += 3; break; case NUD_STALE: if (rt6_check_expired(rt)) case NUD_DELAY: continue; case NUD_PROBE: m += 2; break; case NUD_NOARP: last = rt; case NUD_PERMANENT: m += 1; break; case NUD_INCOMPLETE: m = rt6_score_route(rt, oif, strict); default: if (m < 0) read_unlock_bh(&neigh->lock); continue; } read_unlock_bh(&neigh->lock); } else { continue; continue; } if (m > mpri || m >= 12) { if (m > mpri) { match = sprt; match = rt; mpri = m; mpri = m; if (m >= 12) { /* we choose the last default router if it * is in (probably) reachable state. * If route changed, we should do pmtu * discovery. --yoshfuji */ break; } } } spin_lock(&rt6_dflt_lock); if (!match) { /* * No default routers are known to be reachable. * SHOULD round robin */ if (rt6_dflt_pointer) { for (sprt = rt6_dflt_pointer->u.next; sprt; sprt = sprt->u.next) { if (sprt->u.dst.obsolete <= 0 && sprt->u.dst.error == 0 && !rt6_check_expired(sprt)) { match = sprt; break; } } for (sprt = rt; !match && sprt; sprt = sprt->u.next) { if (sprt->u.dst.obsolete <= 0 && sprt->u.dst.error == 0 && !rt6_check_expired(sprt)) { match = sprt; break; } if (sprt == rt6_dflt_pointer) break; } } } } } if (match) { if (!match && if (rt6_dflt_pointer != match) (strict & RT6_SELECT_F_REACHABLE) && RT6_TRACE("changed default router: %p->%p\n", last && last != rt0) { rt6_dflt_pointer, match); /* no entries matched; do round-robin */ rt6_dflt_pointer = match; *head = rt0->u.next; rt0->u.next = last->u.next; last->u.next = rt0; } } spin_unlock(&rt6_dflt_lock); if (!match) { RT6_TRACE("%s() => %p, score=%d\n", /* __FUNCTION__, match, mpri); * Last Resort: if no default routers found, * use addrconf default route. * We don't record this route. */ for (sprt = ip6_routing_table.leaf; sprt; sprt = sprt->u.next) { if (!rt6_check_expired(sprt) && (sprt->rt6i_flags & RTF_DEFAULT) && (!oif || (sprt->rt6i_dev && sprt->rt6i_dev->ifindex == oif))) { match = sprt; break; } } if (!match) { /* no default route. give up. */ match = &ip6_null_entry; } } return match; return (match ? match : &ip6_null_entry); } } struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr, struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr, Loading Loading @@ -542,7 +486,7 @@ struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) int attempts = 3; int attempts = 3; int err; int err; strict = ipv6_addr_type(&fl->fl6_dst) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL); strict = ipv6_addr_type(&fl->fl6_dst) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL) ? RT6_SELECT_F_IFACE : 0; relookup: relookup: read_lock_bh(&rt6_lock); read_lock_bh(&rt6_lock); Loading @@ -558,8 +502,9 @@ struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) goto out; goto out; } } if (rt->rt6i_flags & RTF_DEFAULT) { if (rt->rt6i_flags & RTF_DEFAULT) { if (rt->rt6i_metric >= IP6_RT_PRIO_ADDRCONF) rt = rt6_select(&fn->leaf, fl->oif, strict | RT6_SELECT_F_REACHABLE); rt = rt6_best_dflt(rt, fl->oif); if (rt == &ip6_null_entry) rt = rt6_select(&fn->leaf, fl->oif, strict); } else { } else { rt = rt6_device_match(rt, fl->oif, strict); rt = rt6_device_match(rt, fl->oif, strict); BACKTRACK(); BACKTRACK(); Loading Loading @@ -1025,8 +970,6 @@ int ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct write_lock_bh(&rt6_lock); write_lock_bh(&rt6_lock); rt6_reset_dflt_pointer(NULL); err = fib6_del(rt, nlh, _rtattr, req); err = fib6_del(rt, nlh, _rtattr, req); dst_release(&rt->u.dst); dst_release(&rt->u.dst); Loading Loading @@ -1341,8 +1284,6 @@ void rt6_purge_dflt_routers(void) if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) { if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) { dst_hold(&rt->u.dst); dst_hold(&rt->u.dst); rt6_reset_dflt_pointer(NULL); read_unlock_bh(&rt6_lock); read_unlock_bh(&rt6_lock); ip6_del_rt(rt, NULL, NULL, NULL); ip6_del_rt(rt, NULL, NULL, NULL); Loading