diff options
Diffstat (limited to 'net/ipv4/fib_trie.c')
-rw-r--r-- | net/ipv4/fib_trie.c | 137 |
1 files changed, 60 insertions, 77 deletions
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 28a3065470bc..987b06d1effe 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c | |||
@@ -1181,72 +1181,6 @@ err: | |||
1181 | return err; | 1181 | return err; |
1182 | } | 1182 | } |
1183 | 1183 | ||
1184 | /* should be called with rcu_read_lock */ | ||
1185 | static int check_leaf(struct fib_table *tb, struct trie *t, struct tnode *l, | ||
1186 | t_key key, const struct flowi4 *flp, | ||
1187 | struct fib_result *res, int fib_flags) | ||
1188 | { | ||
1189 | struct leaf_info *li; | ||
1190 | struct hlist_head *hhead = &l->list; | ||
1191 | |||
1192 | hlist_for_each_entry_rcu(li, hhead, hlist) { | ||
1193 | struct fib_alias *fa; | ||
1194 | |||
1195 | if (l->key != (key & li->mask_plen)) | ||
1196 | continue; | ||
1197 | |||
1198 | list_for_each_entry_rcu(fa, &li->falh, fa_list) { | ||
1199 | struct fib_info *fi = fa->fa_info; | ||
1200 | int nhsel, err; | ||
1201 | |||
1202 | if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos) | ||
1203 | continue; | ||
1204 | if (fi->fib_dead) | ||
1205 | continue; | ||
1206 | if (fa->fa_info->fib_scope < flp->flowi4_scope) | ||
1207 | continue; | ||
1208 | fib_alias_accessed(fa); | ||
1209 | err = fib_props[fa->fa_type].error; | ||
1210 | if (unlikely(err < 0)) { | ||
1211 | #ifdef CONFIG_IP_FIB_TRIE_STATS | ||
1212 | this_cpu_inc(t->stats->semantic_match_passed); | ||
1213 | #endif | ||
1214 | return err; | ||
1215 | } | ||
1216 | if (fi->fib_flags & RTNH_F_DEAD) | ||
1217 | continue; | ||
1218 | for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) { | ||
1219 | const struct fib_nh *nh = &fi->fib_nh[nhsel]; | ||
1220 | |||
1221 | if (nh->nh_flags & RTNH_F_DEAD) | ||
1222 | continue; | ||
1223 | if (flp->flowi4_oif && flp->flowi4_oif != nh->nh_oif) | ||
1224 | continue; | ||
1225 | |||
1226 | #ifdef CONFIG_IP_FIB_TRIE_STATS | ||
1227 | this_cpu_inc(t->stats->semantic_match_passed); | ||
1228 | #endif | ||
1229 | res->prefixlen = li->plen; | ||
1230 | res->nh_sel = nhsel; | ||
1231 | res->type = fa->fa_type; | ||
1232 | res->scope = fi->fib_scope; | ||
1233 | res->fi = fi; | ||
1234 | res->table = tb; | ||
1235 | res->fa_head = &li->falh; | ||
1236 | if (!(fib_flags & FIB_LOOKUP_NOREF)) | ||
1237 | atomic_inc(&fi->fib_clntref); | ||
1238 | return 0; | ||
1239 | } | ||
1240 | } | ||
1241 | |||
1242 | #ifdef CONFIG_IP_FIB_TRIE_STATS | ||
1243 | this_cpu_inc(t->stats->semantic_match_miss); | ||
1244 | #endif | ||
1245 | } | ||
1246 | |||
1247 | return 1; | ||
1248 | } | ||
1249 | |||
1250 | static inline t_key prefix_mismatch(t_key key, struct tnode *n) | 1184 | static inline t_key prefix_mismatch(t_key key, struct tnode *n) |
1251 | { | 1185 | { |
1252 | t_key prefix = n->key; | 1186 | t_key prefix = n->key; |
@@ -1254,6 +1188,7 @@ static inline t_key prefix_mismatch(t_key key, struct tnode *n) | |||
1254 | return (key ^ prefix) & (prefix | -prefix); | 1188 | return (key ^ prefix) & (prefix | -prefix); |
1255 | } | 1189 | } |
1256 | 1190 | ||
1191 | /* should be called with rcu_read_lock */ | ||
1257 | int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp, | 1192 | int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp, |
1258 | struct fib_result *res, int fib_flags) | 1193 | struct fib_result *res, int fib_flags) |
1259 | { | 1194 | { |
@@ -1263,14 +1198,12 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp, | |||
1263 | #endif | 1198 | #endif |
1264 | const t_key key = ntohl(flp->daddr); | 1199 | const t_key key = ntohl(flp->daddr); |
1265 | struct tnode *n, *pn; | 1200 | struct tnode *n, *pn; |
1201 | struct leaf_info *li; | ||
1266 | t_key cindex; | 1202 | t_key cindex; |
1267 | int ret = 1; | ||
1268 | |||
1269 | rcu_read_lock(); | ||
1270 | 1203 | ||
1271 | n = rcu_dereference(t->trie); | 1204 | n = rcu_dereference(t->trie); |
1272 | if (!n) | 1205 | if (!n) |
1273 | goto failed; | 1206 | return -EAGAIN; |
1274 | 1207 | ||
1275 | #ifdef CONFIG_IP_FIB_TRIE_STATS | 1208 | #ifdef CONFIG_IP_FIB_TRIE_STATS |
1276 | this_cpu_inc(stats->gets); | 1209 | this_cpu_inc(stats->gets); |
@@ -1350,7 +1283,7 @@ backtrace: | |||
1350 | 1283 | ||
1351 | pn = node_parent_rcu(pn); | 1284 | pn = node_parent_rcu(pn); |
1352 | if (unlikely(!pn)) | 1285 | if (unlikely(!pn)) |
1353 | goto failed; | 1286 | return -EAGAIN; |
1354 | #ifdef CONFIG_IP_FIB_TRIE_STATS | 1287 | #ifdef CONFIG_IP_FIB_TRIE_STATS |
1355 | this_cpu_inc(stats->backtrack); | 1288 | this_cpu_inc(stats->backtrack); |
1356 | #endif | 1289 | #endif |
@@ -1368,12 +1301,62 @@ backtrace: | |||
1368 | 1301 | ||
1369 | found: | 1302 | found: |
1370 | /* Step 3: Process the leaf, if that fails fall back to backtracing */ | 1303 | /* Step 3: Process the leaf, if that fails fall back to backtracing */ |
1371 | ret = check_leaf(tb, t, n, key, flp, res, fib_flags); | 1304 | hlist_for_each_entry_rcu(li, &n->list, hlist) { |
1372 | if (unlikely(ret > 0)) | 1305 | struct fib_alias *fa; |
1373 | goto backtrace; | 1306 | |
1374 | failed: | 1307 | if ((key ^ n->key) & li->mask_plen) |
1375 | rcu_read_unlock(); | 1308 | continue; |
1376 | return ret; | 1309 | |
1310 | list_for_each_entry_rcu(fa, &li->falh, fa_list) { | ||
1311 | struct fib_info *fi = fa->fa_info; | ||
1312 | int nhsel, err; | ||
1313 | |||
1314 | if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos) | ||
1315 | continue; | ||
1316 | if (fi->fib_dead) | ||
1317 | continue; | ||
1318 | if (fa->fa_info->fib_scope < flp->flowi4_scope) | ||
1319 | continue; | ||
1320 | fib_alias_accessed(fa); | ||
1321 | err = fib_props[fa->fa_type].error; | ||
1322 | if (unlikely(err < 0)) { | ||
1323 | #ifdef CONFIG_IP_FIB_TRIE_STATS | ||
1324 | this_cpu_inc(stats->semantic_match_passed); | ||
1325 | #endif | ||
1326 | return err; | ||
1327 | } | ||
1328 | if (fi->fib_flags & RTNH_F_DEAD) | ||
1329 | continue; | ||
1330 | for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) { | ||
1331 | const struct fib_nh *nh = &fi->fib_nh[nhsel]; | ||
1332 | |||
1333 | if (nh->nh_flags & RTNH_F_DEAD) | ||
1334 | continue; | ||
1335 | if (flp->flowi4_oif && flp->flowi4_oif != nh->nh_oif) | ||
1336 | continue; | ||
1337 | |||
1338 | if (!(fib_flags & FIB_LOOKUP_NOREF)) | ||
1339 | atomic_inc(&fi->fib_clntref); | ||
1340 | |||
1341 | res->prefixlen = li->plen; | ||
1342 | res->nh_sel = nhsel; | ||
1343 | res->type = fa->fa_type; | ||
1344 | res->scope = fi->fib_scope; | ||
1345 | res->fi = fi; | ||
1346 | res->table = tb; | ||
1347 | res->fa_head = &li->falh; | ||
1348 | #ifdef CONFIG_IP_FIB_TRIE_STATS | ||
1349 | this_cpu_inc(stats->semantic_match_passed); | ||
1350 | #endif | ||
1351 | return err; | ||
1352 | } | ||
1353 | } | ||
1354 | |||
1355 | #ifdef CONFIG_IP_FIB_TRIE_STATS | ||
1356 | this_cpu_inc(stats->semantic_match_miss); | ||
1357 | #endif | ||
1358 | } | ||
1359 | goto backtrace; | ||
1377 | } | 1360 | } |
1378 | EXPORT_SYMBOL_GPL(fib_table_lookup); | 1361 | EXPORT_SYMBOL_GPL(fib_table_lookup); |
1379 | 1362 | ||