aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2011-01-31 19:16:50 -0500
committerDavid S. Miller <davem@davemloft.net>2011-01-31 19:16:50 -0500
commit0c838ff1ade71162775afffd9e5c6478a60bdca6 (patch)
tree81910cc5582f4862770307784c40c66aa3a44948
parent5b4704419cbd0b7597a91c19f9e8e8b17c1af071 (diff)
ipv4: Consolidate all default route selection implementations.
Both fib_trie and fib_hash have a local implementation of fib_table_select_default(). This is completely unnecessary code duplication. Since we now remember the fib_table and the head of the fib alias list of the default route, we can implement one single generic version of this routine. Looking at the fib_hash implementation you may get the impression that it's possible for there to be multiple top-level routes in the table for the default route. The truth is, it isn't, the insert code will only allow one entry to exist in the zero prefix hash table, because all keys evaluate to zero and all keys in a hash table must be unique. Signed-off-by: David S. Miller <davem@davemloft.net>
-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);