aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/ip_fib.h6
-rw-r--r--net/ipv4/fib_frontend.c15
-rw-r--r--net/ipv4/fib_hash.c72
-rw-r--r--net/ipv4/fib_semantics.c56
-rw-r--r--net/ipv4/fib_trie.c74
-rw-r--r--net/ipv4/route.c2
6 files changed, 58 insertions, 167 deletions
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index f5199b08ba53..819d61ca25cb 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -158,9 +158,6 @@ extern int fib_table_delete(struct fib_table *, struct fib_config *);
158extern int fib_table_dump(struct fib_table *table, struct sk_buff *skb, 158extern int fib_table_dump(struct fib_table *table, struct sk_buff *skb,
159 struct netlink_callback *cb); 159 struct netlink_callback *cb);
160extern int fib_table_flush(struct fib_table *table); 160extern int fib_table_flush(struct fib_table *table);
161extern void fib_table_select_default(struct fib_table *table,
162 const struct flowi *flp,
163 struct fib_result *res);
164extern void fib_free_table(struct fib_table *tb); 161extern void fib_free_table(struct fib_table *tb);
165 162
166 163
@@ -221,8 +218,7 @@ extern void ip_fib_init(void);
221extern int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, 218extern int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
222 struct net_device *dev, __be32 *spec_dst, 219 struct net_device *dev, __be32 *spec_dst,
223 u32 *itag, u32 mark); 220 u32 *itag, u32 mark);
224extern void fib_select_default(struct net *net, const struct flowi *flp, 221extern void fib_select_default(struct fib_result *res);
225 struct fib_result *res);
226 222
227/* Exported by fib_semantics.c */ 223/* Exported by fib_semantics.c */
228extern int ip_fib_check_default(__be32 gw, struct net_device *dev); 224extern int ip_fib_check_default(__be32 gw, struct net_device *dev);
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
117void 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
132static void fib_flush(struct net *net) 117static 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
305void 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;
373out:
374 rcu_read_unlock();
375}
376
377/* Insert node F to FZ. */ 305/* Insert node F to FZ. */
378static inline void fib_insert_node(struct fn_zone *fz, struct fib_node *f) 306static 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. */
1140void 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;
1191out:
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
1805void 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;
1875out:
1876 rcu_read_unlock();
1877}
1878
1879static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah, 1805static 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);