|
@@ -1181,72 +1181,6 @@ err:
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
-/* should be called with rcu_read_lock */
|
|
|
|
-static int check_leaf(struct fib_table *tb, struct trie *t, struct tnode *l,
|
|
|
|
- t_key key, const struct flowi4 *flp,
|
|
|
|
- struct fib_result *res, int fib_flags)
|
|
|
|
-{
|
|
|
|
- struct leaf_info *li;
|
|
|
|
- struct hlist_head *hhead = &l->list;
|
|
|
|
-
|
|
|
|
- hlist_for_each_entry_rcu(li, hhead, hlist) {
|
|
|
|
- struct fib_alias *fa;
|
|
|
|
-
|
|
|
|
- if (l->key != (key & li->mask_plen))
|
|
|
|
- continue;
|
|
|
|
-
|
|
|
|
- list_for_each_entry_rcu(fa, &li->falh, fa_list) {
|
|
|
|
- struct fib_info *fi = fa->fa_info;
|
|
|
|
- int nhsel, err;
|
|
|
|
-
|
|
|
|
- if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos)
|
|
|
|
- continue;
|
|
|
|
- if (fi->fib_dead)
|
|
|
|
- continue;
|
|
|
|
- if (fa->fa_info->fib_scope < flp->flowi4_scope)
|
|
|
|
- continue;
|
|
|
|
- fib_alias_accessed(fa);
|
|
|
|
- err = fib_props[fa->fa_type].error;
|
|
|
|
- if (unlikely(err < 0)) {
|
|
|
|
-#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
|
|
- this_cpu_inc(t->stats->semantic_match_passed);
|
|
|
|
-#endif
|
|
|
|
- return err;
|
|
|
|
- }
|
|
|
|
- if (fi->fib_flags & RTNH_F_DEAD)
|
|
|
|
- continue;
|
|
|
|
- for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) {
|
|
|
|
- const struct fib_nh *nh = &fi->fib_nh[nhsel];
|
|
|
|
-
|
|
|
|
- if (nh->nh_flags & RTNH_F_DEAD)
|
|
|
|
- continue;
|
|
|
|
- if (flp->flowi4_oif && flp->flowi4_oif != nh->nh_oif)
|
|
|
|
- continue;
|
|
|
|
-
|
|
|
|
-#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
|
|
- this_cpu_inc(t->stats->semantic_match_passed);
|
|
|
|
-#endif
|
|
|
|
- res->prefixlen = li->plen;
|
|
|
|
- res->nh_sel = nhsel;
|
|
|
|
- res->type = fa->fa_type;
|
|
|
|
- res->scope = fi->fib_scope;
|
|
|
|
- res->fi = fi;
|
|
|
|
- res->table = tb;
|
|
|
|
- res->fa_head = &li->falh;
|
|
|
|
- if (!(fib_flags & FIB_LOOKUP_NOREF))
|
|
|
|
- atomic_inc(&fi->fib_clntref);
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
|
|
- this_cpu_inc(t->stats->semantic_match_miss);
|
|
|
|
-#endif
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return 1;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static inline t_key prefix_mismatch(t_key key, struct tnode *n)
|
|
static inline t_key prefix_mismatch(t_key key, struct tnode *n)
|
|
{
|
|
{
|
|
t_key prefix = n->key;
|
|
t_key prefix = n->key;
|
|
@@ -1254,6 +1188,7 @@ static inline t_key prefix_mismatch(t_key key, struct tnode *n)
|
|
return (key ^ prefix) & (prefix | -prefix);
|
|
return (key ^ prefix) & (prefix | -prefix);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/* should be called with rcu_read_lock */
|
|
int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
|
|
int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
|
|
struct fib_result *res, int fib_flags)
|
|
struct fib_result *res, int fib_flags)
|
|
{
|
|
{
|
|
@@ -1263,14 +1198,12 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
|
|
#endif
|
|
#endif
|
|
const t_key key = ntohl(flp->daddr);
|
|
const t_key key = ntohl(flp->daddr);
|
|
struct tnode *n, *pn;
|
|
struct tnode *n, *pn;
|
|
|
|
+ struct leaf_info *li;
|
|
t_key cindex;
|
|
t_key cindex;
|
|
- int ret = 1;
|
|
|
|
-
|
|
|
|
- rcu_read_lock();
|
|
|
|
|
|
|
|
n = rcu_dereference(t->trie);
|
|
n = rcu_dereference(t->trie);
|
|
if (!n)
|
|
if (!n)
|
|
- goto failed;
|
|
|
|
|
|
+ return -EAGAIN;
|
|
|
|
|
|
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
this_cpu_inc(stats->gets);
|
|
this_cpu_inc(stats->gets);
|
|
@@ -1350,7 +1283,7 @@ backtrace:
|
|
|
|
|
|
pn = node_parent_rcu(pn);
|
|
pn = node_parent_rcu(pn);
|
|
if (unlikely(!pn))
|
|
if (unlikely(!pn))
|
|
- goto failed;
|
|
|
|
|
|
+ return -EAGAIN;
|
|
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
this_cpu_inc(stats->backtrack);
|
|
this_cpu_inc(stats->backtrack);
|
|
#endif
|
|
#endif
|
|
@@ -1368,12 +1301,62 @@ backtrace:
|
|
|
|
|
|
found:
|
|
found:
|
|
/* Step 3: Process the leaf, if that fails fall back to backtracing */
|
|
/* Step 3: Process the leaf, if that fails fall back to backtracing */
|
|
- ret = check_leaf(tb, t, n, key, flp, res, fib_flags);
|
|
|
|
- if (unlikely(ret > 0))
|
|
|
|
- goto backtrace;
|
|
|
|
-failed:
|
|
|
|
- rcu_read_unlock();
|
|
|
|
- return ret;
|
|
|
|
|
|
+ hlist_for_each_entry_rcu(li, &n->list, hlist) {
|
|
|
|
+ struct fib_alias *fa;
|
|
|
|
+
|
|
|
|
+ if ((key ^ n->key) & li->mask_plen)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ list_for_each_entry_rcu(fa, &li->falh, fa_list) {
|
|
|
|
+ struct fib_info *fi = fa->fa_info;
|
|
|
|
+ int nhsel, err;
|
|
|
|
+
|
|
|
|
+ if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos)
|
|
|
|
+ continue;
|
|
|
|
+ if (fi->fib_dead)
|
|
|
|
+ continue;
|
|
|
|
+ if (fa->fa_info->fib_scope < flp->flowi4_scope)
|
|
|
|
+ continue;
|
|
|
|
+ fib_alias_accessed(fa);
|
|
|
|
+ err = fib_props[fa->fa_type].error;
|
|
|
|
+ if (unlikely(err < 0)) {
|
|
|
|
+#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
|
|
+ this_cpu_inc(stats->semantic_match_passed);
|
|
|
|
+#endif
|
|
|
|
+ return err;
|
|
|
|
+ }
|
|
|
|
+ if (fi->fib_flags & RTNH_F_DEAD)
|
|
|
|
+ continue;
|
|
|
|
+ for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) {
|
|
|
|
+ const struct fib_nh *nh = &fi->fib_nh[nhsel];
|
|
|
|
+
|
|
|
|
+ if (nh->nh_flags & RTNH_F_DEAD)
|
|
|
|
+ continue;
|
|
|
|
+ if (flp->flowi4_oif && flp->flowi4_oif != nh->nh_oif)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ if (!(fib_flags & FIB_LOOKUP_NOREF))
|
|
|
|
+ atomic_inc(&fi->fib_clntref);
|
|
|
|
+
|
|
|
|
+ res->prefixlen = li->plen;
|
|
|
|
+ res->nh_sel = nhsel;
|
|
|
|
+ res->type = fa->fa_type;
|
|
|
|
+ res->scope = fi->fib_scope;
|
|
|
|
+ res->fi = fi;
|
|
|
|
+ res->table = tb;
|
|
|
|
+ res->fa_head = &li->falh;
|
|
|
|
+#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
|
|
+ this_cpu_inc(stats->semantic_match_passed);
|
|
|
|
+#endif
|
|
|
|
+ return err;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
|
|
+ this_cpu_inc(stats->semantic_match_miss);
|
|
|
|
+#endif
|
|
|
|
+ }
|
|
|
|
+ goto backtrace;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(fib_table_lookup);
|
|
EXPORT_SYMBOL_GPL(fib_table_lookup);
|
|
|
|
|