aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/ip_fib.h36
-rw-r--r--include/net/netns/ipv4.h8
-rw-r--r--net/ipv4/fib_frontend.c27
-rw-r--r--net/ipv4/fib_rules.c12
-rw-r--r--net/ipv4/fib_semantics.c6
5 files changed, 73 insertions, 16 deletions
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index 3dc7c96bbeab..539c6721f810 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -220,11 +220,33 @@ extern void __net_exit fib4_rules_exit(struct net *net);
220extern u32 fib_rules_tclass(const struct fib_result *res); 220extern u32 fib_rules_tclass(const struct fib_result *res);
221#endif 221#endif
222 222
223extern int fib_lookup(struct net *n, struct flowi4 *flp, struct fib_result *res);
224
225extern struct fib_table *fib_new_table(struct net *net, u32 id); 223extern struct fib_table *fib_new_table(struct net *net, u32 id);
226extern struct fib_table *fib_get_table(struct net *net, u32 id); 224extern struct fib_table *fib_get_table(struct net *net, u32 id);
227 225
226extern int __fib_lookup(struct net *net, struct flowi4 *flp,
227 struct fib_result *res);
228
229static inline int fib_lookup(struct net *net, struct flowi4 *flp,
230 struct fib_result *res)
231{
232 if (!net->ipv4.fib_has_custom_rules) {
233 if (net->ipv4.fib_local &&
234 !fib_table_lookup(net->ipv4.fib_local, flp, res,
235 FIB_LOOKUP_NOREF))
236 return 0;
237 if (net->ipv4.fib_main &&
238 !fib_table_lookup(net->ipv4.fib_main, flp, res,
239 FIB_LOOKUP_NOREF))
240 return 0;
241 if (net->ipv4.fib_default &&
242 !fib_table_lookup(net->ipv4.fib_default, flp, res,
243 FIB_LOOKUP_NOREF))
244 return 0;
245 return -ENETUNREACH;
246 }
247 return __fib_lookup(net, flp, res);
248}
249
228#endif /* CONFIG_IP_MULTIPLE_TABLES */ 250#endif /* CONFIG_IP_MULTIPLE_TABLES */
229 251
230/* Exported by fib_frontend.c */ 252/* Exported by fib_frontend.c */
@@ -236,9 +258,15 @@ extern int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
236 struct in_device *idev, u32 *itag); 258 struct in_device *idev, u32 *itag);
237extern void fib_select_default(struct fib_result *res); 259extern void fib_select_default(struct fib_result *res);
238#ifdef CONFIG_IP_ROUTE_CLASSID 260#ifdef CONFIG_IP_ROUTE_CLASSID
239extern int fib_num_tclassid_users; 261static inline int fib_num_tclassid_users(struct net *net)
262{
263 return net->ipv4.fib_num_tclassid_users;
264}
240#else 265#else
241#define fib_num_tclassid_users 0 266static inline int fib_num_tclassid_users(struct net *net)
267{
268 return 0;
269}
242#endif 270#endif
243 271
244/* Exported by fib_semantics.c */ 272/* Exported by fib_semantics.c */
diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h
index 227f0cd9d3f6..599e48fa97cb 100644
--- a/include/net/netns/ipv4.h
+++ b/include/net/netns/ipv4.h
@@ -11,6 +11,7 @@ struct ctl_table_header;
11struct ipv4_devconf; 11struct ipv4_devconf;
12struct fib_rules_ops; 12struct fib_rules_ops;
13struct hlist_head; 13struct hlist_head;
14struct fib_table;
14struct sock; 15struct sock;
15 16
16struct netns_ipv4 { 17struct netns_ipv4 {
@@ -24,6 +25,13 @@ struct netns_ipv4 {
24 struct ipv4_devconf *devconf_dflt; 25 struct ipv4_devconf *devconf_dflt;
25#ifdef CONFIG_IP_MULTIPLE_TABLES 26#ifdef CONFIG_IP_MULTIPLE_TABLES
26 struct fib_rules_ops *rules_ops; 27 struct fib_rules_ops *rules_ops;
28 bool fib_has_custom_rules;
29 struct fib_table *fib_local;
30 struct fib_table *fib_main;
31 struct fib_table *fib_default;
32#endif
33#ifdef CONFIG_IP_ROUTE_CLASSID
34 int fib_num_tclassid_users;
27#endif 35#endif
28 struct hlist_head *fib_table_hash; 36 struct hlist_head *fib_table_hash;
29 struct sock *fibnl; 37 struct sock *fibnl;
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 3e11ea225dad..81f85716a894 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -86,6 +86,24 @@ struct fib_table *fib_new_table(struct net *net, u32 id)
86 tb = fib_trie_table(id); 86 tb = fib_trie_table(id);
87 if (!tb) 87 if (!tb)
88 return NULL; 88 return NULL;
89
90 switch (id) {
91 case RT_TABLE_LOCAL:
92 net->ipv4.fib_local = tb;
93 break;
94
95 case RT_TABLE_MAIN:
96 net->ipv4.fib_main = tb;
97 break;
98
99 case RT_TABLE_DEFAULT:
100 net->ipv4.fib_default = tb;
101 break;
102
103 default:
104 break;
105 }
106
89 h = id & (FIB_TABLE_HASHSZ - 1); 107 h = id & (FIB_TABLE_HASHSZ - 1);
90 hlist_add_head_rcu(&tb->tb_hlist, &net->ipv4.fib_table_hash[h]); 108 hlist_add_head_rcu(&tb->tb_hlist, &net->ipv4.fib_table_hash[h]);
91 return tb; 109 return tb;
@@ -218,10 +236,6 @@ __be32 fib_compute_spec_dst(struct sk_buff *skb)
218 return inet_select_addr(dev, ip_hdr(skb)->saddr, scope); 236 return inet_select_addr(dev, ip_hdr(skb)->saddr, scope);
219} 237}
220 238
221#ifdef CONFIG_IP_ROUTE_CLASSID
222int fib_num_tclassid_users __read_mostly;
223#endif
224
225/* Given (packet source, input interface) and optional (dst, oif, tos): 239/* Given (packet source, input interface) and optional (dst, oif, tos):
226 * - (main) check, that source is valid i.e. not broadcast or our local 240 * - (main) check, that source is valid i.e. not broadcast or our local
227 * address. 241 * address.
@@ -312,7 +326,7 @@ int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
312{ 326{
313 int r = secpath_exists(skb) ? 0 : IN_DEV_RPFILTER(idev); 327 int r = secpath_exists(skb) ? 0 : IN_DEV_RPFILTER(idev);
314 328
315 if (!r && !fib_num_tclassid_users) { 329 if (!r && !fib_num_tclassid_users(dev_net(dev))) {
316 *itag = 0; 330 *itag = 0;
317 return 0; 331 return 0;
318 } 332 }
@@ -1134,6 +1148,9 @@ static int __net_init fib_net_init(struct net *net)
1134{ 1148{
1135 int error; 1149 int error;
1136 1150
1151#ifdef CONFIG_IP_ROUTE_CLASSID
1152 net->ipv4.fib_num_tclassid_users = 0;
1153#endif
1137 error = ip_fib_net_init(net); 1154 error = ip_fib_net_init(net);
1138 if (error < 0) 1155 if (error < 0)
1139 goto out; 1156 goto out;
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
index b23fd952c84f..c06da93b0b70 100644
--- a/net/ipv4/fib_rules.c
+++ b/net/ipv4/fib_rules.c
@@ -54,7 +54,7 @@ u32 fib_rules_tclass(const struct fib_result *res)
54} 54}
55#endif 55#endif
56 56
57int fib_lookup(struct net *net, struct flowi4 *flp, struct fib_result *res) 57int __fib_lookup(struct net *net, struct flowi4 *flp, struct fib_result *res)
58{ 58{
59 struct fib_lookup_arg arg = { 59 struct fib_lookup_arg arg = {
60 .result = res, 60 .result = res,
@@ -67,7 +67,7 @@ int fib_lookup(struct net *net, struct flowi4 *flp, struct fib_result *res)
67 67
68 return err; 68 return err;
69} 69}
70EXPORT_SYMBOL_GPL(fib_lookup); 70EXPORT_SYMBOL_GPL(__fib_lookup);
71 71
72static int fib4_rule_action(struct fib_rule *rule, struct flowi *flp, 72static int fib4_rule_action(struct fib_rule *rule, struct flowi *flp,
73 int flags, struct fib_lookup_arg *arg) 73 int flags, struct fib_lookup_arg *arg)
@@ -172,7 +172,7 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
172 if (tb[FRA_FLOW]) { 172 if (tb[FRA_FLOW]) {
173 rule4->tclassid = nla_get_u32(tb[FRA_FLOW]); 173 rule4->tclassid = nla_get_u32(tb[FRA_FLOW]);
174 if (rule4->tclassid) 174 if (rule4->tclassid)
175 fib_num_tclassid_users++; 175 net->ipv4.fib_num_tclassid_users++;
176 } 176 }
177#endif 177#endif
178 178
@@ -182,6 +182,7 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
182 rule4->dstmask = inet_make_mask(rule4->dst_len); 182 rule4->dstmask = inet_make_mask(rule4->dst_len);
183 rule4->tos = frh->tos; 183 rule4->tos = frh->tos;
184 184
185 net->ipv4.fib_has_custom_rules = true;
185 err = 0; 186 err = 0;
186errout: 187errout:
187 return err; 188 return err;
@@ -189,12 +190,14 @@ errout:
189 190
190static void fib4_rule_delete(struct fib_rule *rule) 191static void fib4_rule_delete(struct fib_rule *rule)
191{ 192{
193 struct net *net = rule->fr_net;
192#ifdef CONFIG_IP_ROUTE_CLASSID 194#ifdef CONFIG_IP_ROUTE_CLASSID
193 struct fib4_rule *rule4 = (struct fib4_rule *) rule; 195 struct fib4_rule *rule4 = (struct fib4_rule *) rule;
194 196
195 if (rule4->tclassid) 197 if (rule4->tclassid)
196 fib_num_tclassid_users--; 198 net->ipv4.fib_num_tclassid_users--;
197#endif 199#endif
200 net->ipv4.fib_has_custom_rules = true;
198} 201}
199 202
200static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, 203static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
@@ -309,6 +312,7 @@ int __net_init fib4_rules_init(struct net *net)
309 if (err < 0) 312 if (err < 0)
310 goto fail; 313 goto fail;
311 net->ipv4.rules_ops = ops; 314 net->ipv4.rules_ops = ops;
315 net->ipv4.fib_has_custom_rules = false;
312 return 0; 316 return 0;
313 317
314fail: 318fail:
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index c46c20b6b0b6..ae301c897a19 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -166,7 +166,7 @@ void free_fib_info(struct fib_info *fi)
166#ifdef CONFIG_IP_ROUTE_CLASSID 166#ifdef CONFIG_IP_ROUTE_CLASSID
167 change_nexthops(fi) { 167 change_nexthops(fi) {
168 if (nexthop_nh->nh_tclassid) 168 if (nexthop_nh->nh_tclassid)
169 fib_num_tclassid_users--; 169 fi->fib_net->ipv4.fib_num_tclassid_users--;
170 } endfor_nexthops(fi); 170 } endfor_nexthops(fi);
171#endif 171#endif
172 call_rcu(&fi->rcu, free_fib_info_rcu); 172 call_rcu(&fi->rcu, free_fib_info_rcu);
@@ -428,7 +428,7 @@ static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh,
428 nla = nla_find(attrs, attrlen, RTA_FLOW); 428 nla = nla_find(attrs, attrlen, RTA_FLOW);
429 nexthop_nh->nh_tclassid = nla ? nla_get_u32(nla) : 0; 429 nexthop_nh->nh_tclassid = nla ? nla_get_u32(nla) : 0;
430 if (nexthop_nh->nh_tclassid) 430 if (nexthop_nh->nh_tclassid)
431 fib_num_tclassid_users++; 431 fi->fib_net->ipv4.fib_num_tclassid_users++;
432#endif 432#endif
433 } 433 }
434 434
@@ -824,7 +824,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
824#ifdef CONFIG_IP_ROUTE_CLASSID 824#ifdef CONFIG_IP_ROUTE_CLASSID
825 nh->nh_tclassid = cfg->fc_flow; 825 nh->nh_tclassid = cfg->fc_flow;
826 if (nh->nh_tclassid) 826 if (nh->nh_tclassid)
827 fib_num_tclassid_users++; 827 fi->fib_net->ipv4.fib_num_tclassid_users++;
828#endif 828#endif
829#ifdef CONFIG_IP_ROUTE_MULTIPATH 829#ifdef CONFIG_IP_ROUTE_MULTIPATH
830 nh->nh_weight = 1; 830 nh->nh_weight = 1;