- 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;
- }
- }
+out:
+ return match;
+}
+
+static struct rt6_info *find_rr_leaf(struct fib6_node *fn,
+ struct rt6_info *rr_head,
+ u32 metric, int oif, int strict)
+{
+ struct rt6_info *rt, *match;
+ int mpri = -1;
+
+ match = NULL;
+ for (rt = rr_head; rt && rt->rt6i_metric == metric;
+ rt = rt->u.next)
+ match = find_match(rt, oif, strict, &mpri, match);
+ for (rt = fn->leaf; rt && rt != rr_head && rt->rt6i_metric == metric;
+ rt = rt->u.next)
+ match = find_match(rt, oif, strict, &mpri, match);
+
+ return match;
+}
+
+static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
+{
+ struct rt6_info *match, *rt0;
+
+ RT6_TRACE("%s(fn->leaf=%p, oif=%d)\n",
+ __FUNCTION__, fn->leaf, oif);
+
+ rt0 = fn->rr_ptr;
+ if (!rt0)
+ fn->rr_ptr = rt0 = fn->leaf;
+
+ match = find_rr_leaf(fn, rt0, rt0->rt6i_metric, oif, strict);
+
+ if (!match &&
+ (strict & RT6_LOOKUP_F_REACHABLE)) {
+ struct rt6_info *next = rt0->u.next;
+
+ /* no entries matched; do round-robin */
+ if (!next || next->rt6i_metric != rt0->rt6i_metric)
+ next = fn->leaf;
+
+ if (next != rt0)
+ fn->rr_ptr = next;