static int fib4_rule_action(struct fib_rule *rule, struct flowi *flp, int flags, struct fib_lookup_arg *arg) { int err = -EAGAIN; struct fib_table *tbl; switch (rule->action) { case FR_ACT_TO_TBL: break; case FR_ACT_UNREACHABLE: err = -ENETUNREACH; goto errout; case FR_ACT_PROHIBIT: err = -EACCES; goto errout; case FR_ACT_BLACKHOLE: default: err = -EINVAL; goto errout; } tbl = fib_get_table(rule->fr_net, rule->table); if (!tbl) goto errout; err = fib_table_lookup(tbl, &flp->u.ip4, (struct fib_result *) arg->result, arg->flags); if (err > 0) err = -EAGAIN; errout: return err; }
static inline unsigned __inet_dev_addr_type(struct net *net, const struct net_device *dev, __be32 addr) { struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } }; struct fib_result res; unsigned ret = RTN_BROADCAST; struct fib_table *local_table; if (ipv4_is_zeronet(addr) || ipv4_is_lbcast(addr)) return RTN_BROADCAST; if (ipv4_is_multicast(addr)) return RTN_MULTICAST; #ifdef CONFIG_IP_MULTIPLE_TABLES res.r = NULL; #endif local_table = fib_get_table(net, RT_TABLE_LOCAL); if (local_table) { ret = RTN_UNICAST; if (!local_table->tb_lookup(local_table, &fl, &res)) { if (!dev || dev == res.fi->fib_dev) ret = res.type; fib_res_put(&res); } } return ret; }
struct fib_table *fib_new_table(struct net *net, u32 id) { struct fib_table *tb, *alias = NULL; unsigned int h; if (id == 0) id = RT_TABLE_MAIN; tb = fib_get_table(net, id); if (tb) return tb; if (id == RT_TABLE_LOCAL) alias = fib_new_table(net, RT_TABLE_MAIN); tb = fib_trie_table(id, alias); if (!tb) return NULL; switch (id) { case RT_TABLE_MAIN: rcu_assign_pointer(net->ipv4.fib_main, tb); break; case RT_TABLE_DEFAULT: rcu_assign_pointer(net->ipv4.fib_default, tb); break; default: break; } h = id & (FIB_TABLE_HASHSZ - 1); hlist_add_head_rcu(&tb->tb_hlist, &net->ipv4.fib_table_hash[h]); return tb; }
static struct fib_table *fib_empty_table(struct net *net) { u32 id; for (id = 1; id <= RT_TABLE_MAX; id++) if (fib_get_table(net, id) == NULL) return fib_new_table(net, id); return NULL; }
static struct fib_table *fib_empty_table(struct net *net) { u32 id; #ifdef FIB_RULE_DEBUG printk(KERN_DEBUG "[NET][IPV4][RULE] %s \n", __func__); #endif for (id = 1; id <= RT_TABLE_MAX; id++) if (fib_get_table(net, id) == NULL) return fib_new_table(net, id); return NULL; }
void fib_select_default(struct net *net, const struct flowi *flp, struct fib_result *res) { struct fib_table *tb; int table = RT_TABLE_MAIN; #ifdef CONFIG_IP_MULTIPLE_TABLES if (res->r == NULL || res->r->action != FR_ACT_TO_TBL) return; table = res->r->table; #endif tb = fib_get_table(net, table); if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) tb->tb_select_default(tb, flp, res); }
struct fib_table *fib_new_table(struct net *net, u32 id) { struct fib_table *tb; unsigned int h; if (id == 0) id = RT_TABLE_MAIN; tb = fib_get_table(net, id); if (tb) return tb; tb = fib_hash_table(id); if (!tb) return NULL; h = id & (FIB_TABLE_HASHSZ - 1); hlist_add_head_rcu(&tb->tb_hlist, &net->ipv4.fib_table_hash[h]); return tb; }
void fib_flush(void) { int flushed = 0; #ifdef CONFIG_IP_MULTIPLE_TABLES struct fib_table *tb; int id; for (id = RT_TABLE_MAX; id>0; id--) { if ((tb = fib_get_table(id))==NULL) continue; flushed += tb->tb_flush(tb); } #else /* CONFIG_IP_MULTIPLE_TABLES */ flushed += main_table->tb_flush(main_table); flushed += local_table->tb_flush(local_table); #endif /* CONFIG_IP_MULTIPLE_TABLES */ if (flushed) rt_cache_flush(-1); }
struct net_device * ip_dev_find(struct net *net, __be32 addr) { struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } }; struct fib_result res; struct net_device *dev = NULL; struct fib_table *local_table; #ifdef CONFIG_IP_MULTIPLE_TABLES res.r = NULL; #endif local_table = fib_get_table(net, RT_TABLE_LOCAL); if (!local_table || local_table->tb_lookup(local_table, &fl, &res)) return NULL; if (res.type != RTN_LOCAL) goto out; dev = FIB_RES_DEV(res); if (dev) dev_hold(dev); out: fib_res_put(&res); return dev; }