aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/fib_frontend.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/fib_frontend.c')
-rw-r--r--net/ipv4/fib_frontend.c117
1 files changed, 89 insertions, 28 deletions
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 3854411fa37..81f85716a89 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -31,6 +31,7 @@
31#include <linux/if_addr.h> 31#include <linux/if_addr.h>
32#include <linux/if_arp.h> 32#include <linux/if_arp.h>
33#include <linux/skbuff.h> 33#include <linux/skbuff.h>
34#include <linux/cache.h>
34#include <linux/init.h> 35#include <linux/init.h>
35#include <linux/list.h> 36#include <linux/list.h>
36#include <linux/slab.h> 37#include <linux/slab.h>
@@ -85,6 +86,24 @@ struct fib_table *fib_new_table(struct net *net, u32 id)
85 tb = fib_trie_table(id); 86 tb = fib_trie_table(id);
86 if (!tb) 87 if (!tb)
87 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
88 h = id & (FIB_TABLE_HASHSZ - 1); 107 h = id & (FIB_TABLE_HASHSZ - 1);
89 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]);
90 return tb; 109 return tb;
@@ -180,6 +199,43 @@ unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev,
180} 199}
181EXPORT_SYMBOL(inet_dev_addr_type); 200EXPORT_SYMBOL(inet_dev_addr_type);
182 201
202__be32 fib_compute_spec_dst(struct sk_buff *skb)
203{
204 struct net_device *dev = skb->dev;
205 struct in_device *in_dev;
206 struct fib_result res;
207 struct rtable *rt;
208 struct flowi4 fl4;
209 struct net *net;
210 int scope;
211
212 rt = skb_rtable(skb);
213 if (!(rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)))
214 return ip_hdr(skb)->daddr;
215
216 in_dev = __in_dev_get_rcu(dev);
217 BUG_ON(!in_dev);
218
219 net = dev_net(dev);
220
221 scope = RT_SCOPE_UNIVERSE;
222 if (!ipv4_is_zeronet(ip_hdr(skb)->saddr)) {
223 fl4.flowi4_oif = 0;
224 fl4.flowi4_iif = net->loopback_dev->ifindex;
225 fl4.daddr = ip_hdr(skb)->saddr;
226 fl4.saddr = 0;
227 fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos);
228 fl4.flowi4_scope = scope;
229 fl4.flowi4_mark = IN_DEV_SRC_VMARK(in_dev) ? skb->mark : 0;
230 if (!fib_lookup(net, &fl4, &res))
231 return FIB_RES_PREFSRC(net, res);
232 } else {
233 scope = RT_SCOPE_LINK;
234 }
235
236 return inet_select_addr(dev, ip_hdr(skb)->saddr, scope);
237}
238
183/* Given (packet source, input interface) and optional (dst, oif, tos): 239/* Given (packet source, input interface) and optional (dst, oif, tos):
184 * - (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
185 * address. 241 * address.
@@ -188,17 +244,15 @@ EXPORT_SYMBOL(inet_dev_addr_type);
188 * - check, that packet arrived from expected physical interface. 244 * - check, that packet arrived from expected physical interface.
189 * called with rcu_read_lock() 245 * called with rcu_read_lock()
190 */ 246 */
191int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, u8 tos, 247static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
192 int oif, struct net_device *dev, __be32 *spec_dst, 248 u8 tos, int oif, struct net_device *dev,
193 u32 *itag) 249 int rpf, struct in_device *idev, u32 *itag)
194{ 250{
195 struct in_device *in_dev; 251 int ret, no_addr, accept_local;
196 struct flowi4 fl4;
197 struct fib_result res; 252 struct fib_result res;
198 int no_addr, rpf, accept_local; 253 struct flowi4 fl4;
199 bool dev_match;
200 int ret;
201 struct net *net; 254 struct net *net;
255 bool dev_match;
202 256
203 fl4.flowi4_oif = 0; 257 fl4.flowi4_oif = 0;
204 fl4.flowi4_iif = oif; 258 fl4.flowi4_iif = oif;
@@ -207,20 +261,11 @@ int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, u8 tos,
207 fl4.flowi4_tos = tos; 261 fl4.flowi4_tos = tos;
208 fl4.flowi4_scope = RT_SCOPE_UNIVERSE; 262 fl4.flowi4_scope = RT_SCOPE_UNIVERSE;
209 263
210 no_addr = rpf = accept_local = 0; 264 no_addr = accept_local = 0;
211 in_dev = __in_dev_get_rcu(dev); 265 no_addr = idev->ifa_list == NULL;
212 if (in_dev) {
213 no_addr = in_dev->ifa_list == NULL;
214
215 /* Ignore rp_filter for packets protected by IPsec. */
216 rpf = secpath_exists(skb) ? 0 : IN_DEV_RPFILTER(in_dev);
217 266
218 accept_local = IN_DEV_ACCEPT_LOCAL(in_dev); 267 accept_local = IN_DEV_ACCEPT_LOCAL(idev);
219 fl4.flowi4_mark = IN_DEV_SRC_VMARK(in_dev) ? skb->mark : 0; 268 fl4.flowi4_mark = IN_DEV_SRC_VMARK(idev) ? skb->mark : 0;
220 }
221
222 if (in_dev == NULL)
223 goto e_inval;
224 269
225 net = dev_net(dev); 270 net = dev_net(dev);
226 if (fib_lookup(net, &fl4, &res)) 271 if (fib_lookup(net, &fl4, &res))
@@ -229,7 +274,6 @@ int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, u8 tos,
229 if (res.type != RTN_LOCAL || !accept_local) 274 if (res.type != RTN_LOCAL || !accept_local)
230 goto e_inval; 275 goto e_inval;
231 } 276 }
232 *spec_dst = FIB_RES_PREFSRC(net, res);
233 fib_combine_itag(itag, &res); 277 fib_combine_itag(itag, &res);
234 dev_match = false; 278 dev_match = false;
235 279
@@ -258,17 +302,14 @@ int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, u8 tos,
258 302
259 ret = 0; 303 ret = 0;
260 if (fib_lookup(net, &fl4, &res) == 0) { 304 if (fib_lookup(net, &fl4, &res) == 0) {
261 if (res.type == RTN_UNICAST) { 305 if (res.type == RTN_UNICAST)
262 *spec_dst = FIB_RES_PREFSRC(net, res);
263 ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; 306 ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
264 }
265 } 307 }
266 return ret; 308 return ret;
267 309
268last_resort: 310last_resort:
269 if (rpf) 311 if (rpf)
270 goto e_rpf; 312 goto e_rpf;
271 *spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE);
272 *itag = 0; 313 *itag = 0;
273 return 0; 314 return 0;
274 315
@@ -278,6 +319,20 @@ e_rpf:
278 return -EXDEV; 319 return -EXDEV;
279} 320}
280 321
322/* Ignore rp_filter for packets protected by IPsec. */
323int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
324 u8 tos, int oif, struct net_device *dev,
325 struct in_device *idev, u32 *itag)
326{
327 int r = secpath_exists(skb) ? 0 : IN_DEV_RPFILTER(idev);
328
329 if (!r && !fib_num_tclassid_users(dev_net(dev))) {
330 *itag = 0;
331 return 0;
332 }
333 return __fib_validate_source(skb, src, dst, tos, oif, dev, r, idev, itag);
334}
335
281static inline __be32 sk_extract_addr(struct sockaddr *addr) 336static inline __be32 sk_extract_addr(struct sockaddr *addr)
282{ 337{
283 return ((struct sockaddr_in *) addr)->sin_addr.s_addr; 338 return ((struct sockaddr_in *) addr)->sin_addr.s_addr;
@@ -935,8 +990,11 @@ static void nl_fib_input(struct sk_buff *skb)
935static int __net_init nl_fib_lookup_init(struct net *net) 990static int __net_init nl_fib_lookup_init(struct net *net)
936{ 991{
937 struct sock *sk; 992 struct sock *sk;
938 sk = netlink_kernel_create(net, NETLINK_FIB_LOOKUP, 0, 993 struct netlink_kernel_cfg cfg = {
939 nl_fib_input, NULL, THIS_MODULE); 994 .input = nl_fib_input,
995 };
996
997 sk = netlink_kernel_create(net, NETLINK_FIB_LOOKUP, THIS_MODULE, &cfg);
940 if (sk == NULL) 998 if (sk == NULL)
941 return -EAFNOSUPPORT; 999 return -EAFNOSUPPORT;
942 net->ipv4.fibnl = sk; 1000 net->ipv4.fibnl = sk;
@@ -1090,6 +1148,9 @@ static int __net_init fib_net_init(struct net *net)
1090{ 1148{
1091 int error; 1149 int error;
1092 1150
1151#ifdef CONFIG_IP_ROUTE_CLASSID
1152 net->ipv4.fib_num_tclassid_users = 0;
1153#endif
1093 error = ip_fib_net_init(net); 1154 error = ip_fib_net_init(net);
1094 if (error < 0) 1155 if (error < 0)
1095 goto out; 1156 goto out;