diff options
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/fib_frontend.c | 15 | ||||
-rw-r--r-- | net/ipv4/fib_hash.c | 72 | ||||
-rw-r--r-- | net/ipv4/fib_semantics.c | 56 | ||||
-rw-r--r-- | net/ipv4/fib_trie.c | 74 | ||||
-rw-r--r-- | net/ipv4/route.c | 2 |
5 files changed, 57 insertions, 162 deletions
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 1d2cdd43a878..930768ba49af 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c | |||
@@ -114,21 +114,6 @@ struct fib_table *fib_get_table(struct net *net, u32 id) | |||
114 | } | 114 | } |
115 | #endif /* CONFIG_IP_MULTIPLE_TABLES */ | 115 | #endif /* CONFIG_IP_MULTIPLE_TABLES */ |
116 | 116 | ||
117 | void fib_select_default(struct net *net, | ||
118 | const struct flowi *flp, struct fib_result *res) | ||
119 | { | ||
120 | struct fib_table *tb; | ||
121 | int table = RT_TABLE_MAIN; | ||
122 | #ifdef CONFIG_IP_MULTIPLE_TABLES | ||
123 | if (res->r == NULL || res->r->action != FR_ACT_TO_TBL) | ||
124 | return; | ||
125 | table = res->r->table; | ||
126 | #endif | ||
127 | tb = fib_get_table(net, table); | ||
128 | if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) | ||
129 | fib_table_select_default(tb, flp, res); | ||
130 | } | ||
131 | |||
132 | static void fib_flush(struct net *net) | 117 | static void fib_flush(struct net *net) |
133 | { | 118 | { |
134 | int flushed = 0; | 119 | int flushed = 0; |
diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index 0a88866ad1e5..fadb6024de27 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c | |||
@@ -302,78 +302,6 @@ out: | |||
302 | return err; | 302 | return err; |
303 | } | 303 | } |
304 | 304 | ||
305 | void fib_table_select_default(struct fib_table *tb, | ||
306 | const struct flowi *flp, struct fib_result *res) | ||
307 | { | ||
308 | int order, last_idx; | ||
309 | struct hlist_node *node; | ||
310 | struct fib_node *f; | ||
311 | struct fib_info *fi = NULL; | ||
312 | struct fib_info *last_resort; | ||
313 | struct fn_hash *t = (struct fn_hash *)tb->tb_data; | ||
314 | struct fn_zone *fz = t->fn_zones[0]; | ||
315 | struct hlist_head *head; | ||
316 | |||
317 | if (fz == NULL) | ||
318 | return; | ||
319 | |||
320 | last_idx = -1; | ||
321 | last_resort = NULL; | ||
322 | order = -1; | ||
323 | |||
324 | rcu_read_lock(); | ||
325 | head = rcu_dereference(fz->fz_hash); | ||
326 | hlist_for_each_entry_rcu(f, node, head, fn_hash) { | ||
327 | struct fib_alias *fa; | ||
328 | |||
329 | list_for_each_entry_rcu(fa, &f->fn_alias, fa_list) { | ||
330 | struct fib_info *next_fi = fa->fa_info; | ||
331 | |||
332 | if (fa->fa_scope != res->scope || | ||
333 | fa->fa_type != RTN_UNICAST) | ||
334 | continue; | ||
335 | |||
336 | if (next_fi->fib_priority > res->fi->fib_priority) | ||
337 | break; | ||
338 | if (!next_fi->fib_nh[0].nh_gw || | ||
339 | next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK) | ||
340 | continue; | ||
341 | |||
342 | fib_alias_accessed(fa); | ||
343 | |||
344 | if (fi == NULL) { | ||
345 | if (next_fi != res->fi) | ||
346 | break; | ||
347 | } else if (!fib_detect_death(fi, order, &last_resort, | ||
348 | &last_idx, tb->tb_default)) { | ||
349 | fib_result_assign(res, fi); | ||
350 | tb->tb_default = order; | ||
351 | goto out; | ||
352 | } | ||
353 | fi = next_fi; | ||
354 | order++; | ||
355 | } | ||
356 | } | ||
357 | |||
358 | if (order <= 0 || fi == NULL) { | ||
359 | tb->tb_default = -1; | ||
360 | goto out; | ||
361 | } | ||
362 | |||
363 | if (!fib_detect_death(fi, order, &last_resort, &last_idx, | ||
364 | tb->tb_default)) { | ||
365 | fib_result_assign(res, fi); | ||
366 | tb->tb_default = order; | ||
367 | goto out; | ||
368 | } | ||
369 | |||
370 | if (last_idx >= 0) | ||
371 | fib_result_assign(res, last_resort); | ||
372 | tb->tb_default = last_idx; | ||
373 | out: | ||
374 | rcu_read_unlock(); | ||
375 | } | ||
376 | |||
377 | /* Insert node F to FZ. */ | 305 | /* Insert node F to FZ. */ |
378 | static inline void fib_insert_node(struct fn_zone *fz, struct fib_node *f) | 306 | static inline void fib_insert_node(struct fn_zone *fz, struct fib_node *f) |
379 | { | 307 | { |
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 1bf6fb906cfc..b15857d2b77e 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c | |||
@@ -1136,6 +1136,62 @@ int fib_sync_down_dev(struct net_device *dev, int force) | |||
1136 | return ret; | 1136 | return ret; |
1137 | } | 1137 | } |
1138 | 1138 | ||
1139 | /* Must be invoked inside of an RCU protected region. */ | ||
1140 | void fib_select_default(struct fib_result *res) | ||
1141 | { | ||
1142 | struct fib_info *fi = NULL, *last_resort = NULL; | ||
1143 | struct list_head *fa_head = res->fa_head; | ||
1144 | struct fib_table *tb = res->table; | ||
1145 | int order = -1, last_idx = -1; | ||
1146 | struct fib_alias *fa; | ||
1147 | |||
1148 | list_for_each_entry_rcu(fa, fa_head, fa_list) { | ||
1149 | struct fib_info *next_fi = fa->fa_info; | ||
1150 | |||
1151 | if (fa->fa_scope != res->scope || | ||
1152 | fa->fa_type != RTN_UNICAST) | ||
1153 | continue; | ||
1154 | |||
1155 | if (next_fi->fib_priority > res->fi->fib_priority) | ||
1156 | break; | ||
1157 | if (!next_fi->fib_nh[0].nh_gw || | ||
1158 | next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK) | ||
1159 | continue; | ||
1160 | |||
1161 | fib_alias_accessed(fa); | ||
1162 | |||
1163 | if (fi == NULL) { | ||
1164 | if (next_fi != res->fi) | ||
1165 | break; | ||
1166 | } else if (!fib_detect_death(fi, order, &last_resort, | ||
1167 | &last_idx, tb->tb_default)) { | ||
1168 | fib_result_assign(res, fi); | ||
1169 | tb->tb_default = order; | ||
1170 | goto out; | ||
1171 | } | ||
1172 | fi = next_fi; | ||
1173 | order++; | ||
1174 | } | ||
1175 | |||
1176 | if (order <= 0 || fi == NULL) { | ||
1177 | tb->tb_default = -1; | ||
1178 | goto out; | ||
1179 | } | ||
1180 | |||
1181 | if (!fib_detect_death(fi, order, &last_resort, &last_idx, | ||
1182 | tb->tb_default)) { | ||
1183 | fib_result_assign(res, fi); | ||
1184 | tb->tb_default = order; | ||
1185 | goto out; | ||
1186 | } | ||
1187 | |||
1188 | if (last_idx >= 0) | ||
1189 | fib_result_assign(res, last_resort); | ||
1190 | tb->tb_default = last_idx; | ||
1191 | out: | ||
1192 | rcu_read_unlock(); | ||
1193 | } | ||
1194 | |||
1139 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | 1195 | #ifdef CONFIG_IP_ROUTE_MULTIPATH |
1140 | 1196 | ||
1141 | /* | 1197 | /* |
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 8cee5c8848ed..16d589c70a92 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c | |||
@@ -1802,80 +1802,6 @@ void fib_free_table(struct fib_table *tb) | |||
1802 | kfree(tb); | 1802 | kfree(tb); |
1803 | } | 1803 | } |
1804 | 1804 | ||
1805 | void fib_table_select_default(struct fib_table *tb, | ||
1806 | const struct flowi *flp, | ||
1807 | struct fib_result *res) | ||
1808 | { | ||
1809 | struct trie *t = (struct trie *) tb->tb_data; | ||
1810 | int order, last_idx; | ||
1811 | struct fib_info *fi = NULL; | ||
1812 | struct fib_info *last_resort; | ||
1813 | struct fib_alias *fa = NULL; | ||
1814 | struct list_head *fa_head; | ||
1815 | struct leaf *l; | ||
1816 | |||
1817 | last_idx = -1; | ||
1818 | last_resort = NULL; | ||
1819 | order = -1; | ||
1820 | |||
1821 | rcu_read_lock(); | ||
1822 | |||
1823 | l = fib_find_node(t, 0); | ||
1824 | if (!l) | ||
1825 | goto out; | ||
1826 | |||
1827 | fa_head = get_fa_head(l, 0); | ||
1828 | if (!fa_head) | ||
1829 | goto out; | ||
1830 | |||
1831 | if (list_empty(fa_head)) | ||
1832 | goto out; | ||
1833 | |||
1834 | list_for_each_entry_rcu(fa, fa_head, fa_list) { | ||
1835 | struct fib_info *next_fi = fa->fa_info; | ||
1836 | |||
1837 | if (fa->fa_scope != res->scope || | ||
1838 | fa->fa_type != RTN_UNICAST) | ||
1839 | continue; | ||
1840 | |||
1841 | if (next_fi->fib_priority > res->fi->fib_priority) | ||
1842 | break; | ||
1843 | if (!next_fi->fib_nh[0].nh_gw || | ||
1844 | next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK) | ||
1845 | continue; | ||
1846 | |||
1847 | fib_alias_accessed(fa); | ||
1848 | |||
1849 | if (fi == NULL) { | ||
1850 | if (next_fi != res->fi) | ||
1851 | break; | ||
1852 | } else if (!fib_detect_death(fi, order, &last_resort, | ||
1853 | &last_idx, tb->tb_default)) { | ||
1854 | fib_result_assign(res, fi); | ||
1855 | tb->tb_default = order; | ||
1856 | goto out; | ||
1857 | } | ||
1858 | fi = next_fi; | ||
1859 | order++; | ||
1860 | } | ||
1861 | if (order <= 0 || fi == NULL) { | ||
1862 | tb->tb_default = -1; | ||
1863 | goto out; | ||
1864 | } | ||
1865 | |||
1866 | if (!fib_detect_death(fi, order, &last_resort, &last_idx, | ||
1867 | tb->tb_default)) { | ||
1868 | fib_result_assign(res, fi); | ||
1869 | tb->tb_default = order; | ||
1870 | goto out; | ||
1871 | } | ||
1872 | if (last_idx >= 0) | ||
1873 | fib_result_assign(res, last_resort); | ||
1874 | tb->tb_default = last_idx; | ||
1875 | out: | ||
1876 | rcu_read_unlock(); | ||
1877 | } | ||
1878 | |||
1879 | static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah, | 1805 | static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah, |
1880 | struct fib_table *tb, | 1806 | struct fib_table *tb, |
1881 | struct sk_buff *skb, struct netlink_callback *cb) | 1807 | struct sk_buff *skb, struct netlink_callback *cb) |
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index b1e5d3ac3460..242a3de83fbb 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -2711,7 +2711,7 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp, | |||
2711 | else | 2711 | else |
2712 | #endif | 2712 | #endif |
2713 | if (!res.prefixlen && res.type == RTN_UNICAST && !fl.oif) | 2713 | if (!res.prefixlen && res.type == RTN_UNICAST && !fl.oif) |
2714 | fib_select_default(net, &fl, &res); | 2714 | fib_select_default(&res); |
2715 | 2715 | ||
2716 | if (!fl.fl4_src) | 2716 | if (!fl.fl4_src) |
2717 | fl.fl4_src = FIB_RES_PREFSRC(res); | 2717 | fl.fl4_src = FIB_RES_PREFSRC(res); |