void fib6_run_gc(unsigned long dummy) { if (dummy != ~0UL) gc_args.timeout = (int)dummy; else gc_args.timeout = ip6_rt_gc_interval; gc_args.more = 0; fib6_clean_tree(&ip6_routing_table, fib6_age, 0, NULL); del_timer(&ip6_fib_timer); ip6_fib_timer.expires = 0; if (gc_args.more) { ip6_fib_timer.expires = jiffies + ip6_rt_gc_interval; add_timer(&ip6_fib_timer); } }
static struct rt6_info *rt6_flow_lookup(struct rt6_info *rt, struct in6_addr *daddr, struct in6_addr *saddr, struct fl_acc_args *args) { struct flow_rule *frule; struct rt6_info *nrt = NULL; struct pol_chain *pol; for (pol = rt6_pol_list; pol; pol = pol->next) { struct fib6_node *fn; struct rt6_info *sprt; fn = fib6_lookup(pol->rules, daddr, saddr); do { for (sprt = fn->leaf; sprt; sprt=sprt->u.next) { int res; frule = sprt->rt6i_flowr; #if RT6_DEBUG >= 2 if (frule == NULL) { printk(KERN_DEBUG "NULL flowr\n"); goto error; } #endif res = frule->ops->accept(rt, sprt, args, &nrt); switch (res) { case FLOWR_SELECT: goto found; case FLOWR_CLEAR: goto next_policy; case FLOWR_NODECISION: break; default: goto error; }; } fn = fn->parent; } while ((fn->fn_flags & RTN_TL_ROOT) == 0); next_policy: } error: dst_hold(&ip6_null_entry.u.dst); return &ip6_null_entry; found: if (nrt == NULL) goto error; nrt->rt6i_flags |= RTF_CACHE; dst_hold(&nrt->u.dst); err = rt6_ins(nrt, NULL); if (err) nrt->u.dst.error = err; return nrt; } #endif static int fib6_ifdown(struct rt6_info *rt, void *arg) { if (((void*)rt->rt6i_dev == arg || arg == NULL) && rt != &ip6_null_entry) { RT6_TRACE("deleted by ifdown %p\n", rt); return -1; } return 0; } void rt6_ifdown(struct net_device *dev) { write_lock_bh(&rt6_lock); fib6_clean_tree(&ip6_routing_table, fib6_ifdown, 0, dev); write_unlock_bh(&rt6_lock); }
static void fib6_prune_clones(struct fib6_node *fn, struct rt6_info *rt) { fib6_clean_tree(fn, fib6_prune_clone, 1, rt); }