Blame view
net/ipv4/fib_frontend.c
26.4 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 |
/* * INET An implementation of the TCP/IP protocol suite for the LINUX * operating system. INET is implemented using the BSD Socket * interface as the means of communication with the user level. * * IPv4 Forwarding Information Base: FIB frontend. * |
1da177e4c Linux-2.6.12-rc2 |
8 9 10 11 12 13 14 |
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ |
1da177e4c Linux-2.6.12-rc2 |
15 16 17 18 |
#include <linux/module.h> #include <asm/uaccess.h> #include <asm/system.h> #include <linux/bitops.h> |
4fc268d24 [PATCH] capable/c... |
19 |
#include <linux/capability.h> |
1da177e4c Linux-2.6.12-rc2 |
20 21 |
#include <linux/types.h> #include <linux/kernel.h> |
1da177e4c Linux-2.6.12-rc2 |
22 23 24 25 26 27 28 |
#include <linux/mm.h> #include <linux/string.h> #include <linux/socket.h> #include <linux/sockios.h> #include <linux/errno.h> #include <linux/in.h> #include <linux/inet.h> |
14c850212 [INET_SOCK]: Move... |
29 |
#include <linux/inetdevice.h> |
1da177e4c Linux-2.6.12-rc2 |
30 |
#include <linux/netdevice.h> |
1823730fb [IPv4]: Move inte... |
31 |
#include <linux/if_addr.h> |
1da177e4c Linux-2.6.12-rc2 |
32 33 |
#include <linux/if_arp.h> #include <linux/skbuff.h> |
1da177e4c Linux-2.6.12-rc2 |
34 |
#include <linux/init.h> |
1af5a8c4a [IPV4]: Increase ... |
35 |
#include <linux/list.h> |
5a0e3ad6a include cleanup: ... |
36 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
37 38 39 40 41 42 |
#include <net/ip.h> #include <net/protocol.h> #include <net/route.h> #include <net/tcp.h> #include <net/sock.h> |
1da177e4c Linux-2.6.12-rc2 |
43 44 |
#include <net/arp.h> #include <net/ip_fib.h> |
63f3444fb [IPv4]: Use rtnl ... |
45 |
#include <net/rtnetlink.h> |
990078afb Disable rp_filter... |
46 |
#include <net/xfrm.h> |
1da177e4c Linux-2.6.12-rc2 |
47 |
|
1da177e4c Linux-2.6.12-rc2 |
48 |
#ifndef CONFIG_IP_MULTIPLE_TABLES |
7b1a74fdb [NETNS]: Refactor... |
49 |
static int __net_init fib4_rules_init(struct net *net) |
c3e9a353d [IPV4]: Compact s... |
50 |
{ |
93456b6d7 [IPV4]: Unify acc... |
51 |
struct fib_table *local_table, *main_table; |
5348ba85a ipv4: Update some... |
52 |
local_table = fib_trie_table(RT_TABLE_LOCAL); |
93456b6d7 [IPV4]: Unify acc... |
53 |
if (local_table == NULL) |
dbb50165b [IPV4]: Check fib... |
54 |
return -ENOMEM; |
5348ba85a ipv4: Update some... |
55 |
main_table = fib_trie_table(RT_TABLE_MAIN); |
93456b6d7 [IPV4]: Unify acc... |
56 |
if (main_table == NULL) |
dbb50165b [IPV4]: Check fib... |
57 |
goto fail; |
93456b6d7 [IPV4]: Unify acc... |
58 |
hlist_add_head_rcu(&local_table->tb_hlist, |
e4aef8aea [NETNS]: Place fi... |
59 |
&net->ipv4.fib_table_hash[TABLE_LOCAL_INDEX]); |
93456b6d7 [IPV4]: Unify acc... |
60 |
hlist_add_head_rcu(&main_table->tb_hlist, |
e4aef8aea [NETNS]: Place fi... |
61 |
&net->ipv4.fib_table_hash[TABLE_MAIN_INDEX]); |
dbb50165b [IPV4]: Check fib... |
62 63 64 |
return 0; fail: |
93456b6d7 [IPV4]: Unify acc... |
65 |
kfree(local_table); |
dbb50165b [IPV4]: Check fib... |
66 |
return -ENOMEM; |
c3e9a353d [IPV4]: Compact s... |
67 |
} |
1af5a8c4a [IPV4]: Increase ... |
68 |
#else |
1da177e4c Linux-2.6.12-rc2 |
69 |
|
8ad4942cd [NETNS]: Add netn... |
70 |
struct fib_table *fib_new_table(struct net *net, u32 id) |
1da177e4c Linux-2.6.12-rc2 |
71 72 |
{ struct fib_table *tb; |
1af5a8c4a [IPV4]: Increase ... |
73 |
unsigned int h; |
1da177e4c Linux-2.6.12-rc2 |
74 |
|
1af5a8c4a [IPV4]: Increase ... |
75 76 |
if (id == 0) id = RT_TABLE_MAIN; |
8ad4942cd [NETNS]: Add netn... |
77 |
tb = fib_get_table(net, id); |
1af5a8c4a [IPV4]: Increase ... |
78 79 |
if (tb) return tb; |
7f9b80529 [IPV4]: fib hash|... |
80 |
|
5348ba85a ipv4: Update some... |
81 |
tb = fib_trie_table(id); |
1da177e4c Linux-2.6.12-rc2 |
82 83 |
if (!tb) return NULL; |
1af5a8c4a [IPV4]: Increase ... |
84 |
h = id & (FIB_TABLE_HASHSZ - 1); |
e4aef8aea [NETNS]: Place fi... |
85 |
hlist_add_head_rcu(&tb->tb_hlist, &net->ipv4.fib_table_hash[h]); |
1da177e4c Linux-2.6.12-rc2 |
86 87 |
return tb; } |
8ad4942cd [NETNS]: Add netn... |
88 |
struct fib_table *fib_get_table(struct net *net, u32 id) |
1af5a8c4a [IPV4]: Increase ... |
89 90 91 |
{ struct fib_table *tb; struct hlist_node *node; |
e4aef8aea [NETNS]: Place fi... |
92 |
struct hlist_head *head; |
1af5a8c4a [IPV4]: Increase ... |
93 |
unsigned int h; |
1da177e4c Linux-2.6.12-rc2 |
94 |
|
1af5a8c4a [IPV4]: Increase ... |
95 96 97 |
if (id == 0) id = RT_TABLE_MAIN; h = id & (FIB_TABLE_HASHSZ - 1); |
e4aef8aea [NETNS]: Place fi... |
98 |
|
1af5a8c4a [IPV4]: Increase ... |
99 |
rcu_read_lock(); |
e4aef8aea [NETNS]: Place fi... |
100 101 |
head = &net->ipv4.fib_table_hash[h]; hlist_for_each_entry_rcu(tb, node, head, tb_hlist) { |
1af5a8c4a [IPV4]: Increase ... |
102 103 104 105 106 107 108 109 |
if (tb->tb_id == id) { rcu_read_unlock(); return tb; } } rcu_read_unlock(); return NULL; } |
1da177e4c Linux-2.6.12-rc2 |
110 |
#endif /* CONFIG_IP_MULTIPLE_TABLES */ |
e4aef8aea [NETNS]: Place fi... |
111 |
static void fib_flush(struct net *net) |
1da177e4c Linux-2.6.12-rc2 |
112 113 |
{ int flushed = 0; |
1da177e4c Linux-2.6.12-rc2 |
114 |
struct fib_table *tb; |
1af5a8c4a [IPV4]: Increase ... |
115 |
struct hlist_node *node; |
e4aef8aea [NETNS]: Place fi... |
116 |
struct hlist_head *head; |
1af5a8c4a [IPV4]: Increase ... |
117 |
unsigned int h; |
1da177e4c Linux-2.6.12-rc2 |
118 |
|
1af5a8c4a [IPV4]: Increase ... |
119 |
for (h = 0; h < FIB_TABLE_HASHSZ; h++) { |
e4aef8aea [NETNS]: Place fi... |
120 121 |
head = &net->ipv4.fib_table_hash[h]; hlist_for_each_entry(tb, node, head, tb_hlist) |
16c6cf8bb ipv4: fib table a... |
122 |
flushed += fib_table_flush(tb); |
1da177e4c Linux-2.6.12-rc2 |
123 |
} |
1da177e4c Linux-2.6.12-rc2 |
124 125 |
if (flushed) |
76e6ebfb4 netns: add namesp... |
126 |
rt_cache_flush(net, -1); |
1da177e4c Linux-2.6.12-rc2 |
127 |
} |
055381161 [IPV4]: Add inet_... |
128 129 130 131 |
/* * Find address type as if only "dev" was present in the system. If * on_dev is NULL then all interfaces are taken into consideration. */ |
6b175b26c [NETNS]: Add netn... |
132 133 |
static inline unsigned __inet_dev_addr_type(struct net *net, const struct net_device *dev, |
055381161 [IPV4]: Add inet_... |
134 |
__be32 addr) |
1da177e4c Linux-2.6.12-rc2 |
135 |
{ |
9ade22861 ipv4: Use flowi4 ... |
136 |
struct flowi4 fl4 = { .daddr = addr }; |
1da177e4c Linux-2.6.12-rc2 |
137 138 |
struct fib_result res; unsigned ret = RTN_BROADCAST; |
03cf786c4 [IPV4]: Explicitl... |
139 |
struct fib_table *local_table; |
1da177e4c Linux-2.6.12-rc2 |
140 |
|
1e637c74b [IPV4]: Enable us... |
141 |
if (ipv4_is_zeronet(addr) || ipv4_is_lbcast(addr)) |
1da177e4c Linux-2.6.12-rc2 |
142 |
return RTN_BROADCAST; |
f97c1e0c6 [IPV4] net/ipv4: ... |
143 |
if (ipv4_is_multicast(addr)) |
1da177e4c Linux-2.6.12-rc2 |
144 145 146 147 148 |
return RTN_MULTICAST; #ifdef CONFIG_IP_MULTIPLE_TABLES res.r = NULL; #endif |
e905a9eda [NET] IPV4: Fix w... |
149 |
|
6b175b26c [NETNS]: Add netn... |
150 |
local_table = fib_get_table(net, RT_TABLE_LOCAL); |
03cf786c4 [IPV4]: Explicitl... |
151 |
if (local_table) { |
1da177e4c Linux-2.6.12-rc2 |
152 |
ret = RTN_UNICAST; |
ebc0ffae5 fib: RCU conversi... |
153 |
rcu_read_lock(); |
9ade22861 ipv4: Use flowi4 ... |
154 |
if (!fib_table_lookup(local_table, &fl4, &res, FIB_LOOKUP_NOREF)) { |
055381161 [IPV4]: Add inet_... |
155 156 |
if (!dev || dev == res.fi->fib_dev) ret = res.type; |
1da177e4c Linux-2.6.12-rc2 |
157 |
} |
ebc0ffae5 fib: RCU conversi... |
158 |
rcu_read_unlock(); |
1da177e4c Linux-2.6.12-rc2 |
159 160 161 |
} return ret; } |
6b175b26c [NETNS]: Add netn... |
162 |
unsigned int inet_addr_type(struct net *net, __be32 addr) |
055381161 [IPV4]: Add inet_... |
163 |
{ |
6b175b26c [NETNS]: Add netn... |
164 |
return __inet_dev_addr_type(net, NULL, addr); |
055381161 [IPV4]: Add inet_... |
165 |
} |
4bc2f18ba net/ipv4: EXPORT_... |
166 |
EXPORT_SYMBOL(inet_addr_type); |
055381161 [IPV4]: Add inet_... |
167 |
|
6b175b26c [NETNS]: Add netn... |
168 169 |
unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev, __be32 addr) |
055381161 [IPV4]: Add inet_... |
170 |
{ |
6a31d2a97 fib: cleanups |
171 |
return __inet_dev_addr_type(net, dev, addr); |
055381161 [IPV4]: Add inet_... |
172 |
} |
4bc2f18ba net/ipv4: EXPORT_... |
173 |
EXPORT_SYMBOL(inet_dev_addr_type); |
055381161 [IPV4]: Add inet_... |
174 |
|
1da177e4c Linux-2.6.12-rc2 |
175 |
/* Given (packet source, input interface) and optional (dst, oif, tos): |
6a31d2a97 fib: cleanups |
176 177 178 179 180 |
* - (main) check, that source is valid i.e. not broadcast or our local * address. * - figure out what "logical" interface this packet arrived * and calculate "specific destination" address. * - check, that packet arrived from expected physical interface. |
ebc0ffae5 fib: RCU conversi... |
181 |
* called with rcu_read_lock() |
1da177e4c Linux-2.6.12-rc2 |
182 |
*/ |
5c04c819a fib_validate_sour... |
183 184 185 |
int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, u8 tos, int oif, struct net_device *dev, __be32 *spec_dst, u32 *itag) |
1da177e4c Linux-2.6.12-rc2 |
186 187 |
{ struct in_device *in_dev; |
9ade22861 ipv4: Use flowi4 ... |
188 |
struct flowi4 fl4; |
1da177e4c Linux-2.6.12-rc2 |
189 |
struct fib_result res; |
8153a10c0 ipv4 05/05: add s... |
190 |
int no_addr, rpf, accept_local; |
6f86b3251 ipv4: Fix reverse... |
191 |
bool dev_match; |
1da177e4c Linux-2.6.12-rc2 |
192 |
int ret; |
5b707aaae [NETNS]: Pass cor... |
193 |
struct net *net; |
1da177e4c Linux-2.6.12-rc2 |
194 |
|
9ade22861 ipv4: Use flowi4 ... |
195 196 |
fl4.flowi4_oif = 0; fl4.flowi4_iif = oif; |
9ade22861 ipv4: Use flowi4 ... |
197 198 199 200 |
fl4.daddr = src; fl4.saddr = dst; fl4.flowi4_tos = tos; fl4.flowi4_scope = RT_SCOPE_UNIVERSE; |
cc7e17ea0 ipv4: Optimize fl... |
201 |
|
8153a10c0 ipv4 05/05: add s... |
202 |
no_addr = rpf = accept_local = 0; |
e5ed63991 [IPV4]: Replace _... |
203 |
in_dev = __in_dev_get_rcu(dev); |
1da177e4c Linux-2.6.12-rc2 |
204 205 |
if (in_dev) { no_addr = in_dev->ifa_list == NULL; |
990078afb Disable rp_filter... |
206 207 208 |
/* Ignore rp_filter for packets protected by IPsec. */ rpf = secpath_exists(skb) ? 0 : IN_DEV_RPFILTER(in_dev); |
8153a10c0 ipv4 05/05: add s... |
209 |
accept_local = IN_DEV_ACCEPT_LOCAL(in_dev); |
5c04c819a fib_validate_sour... |
210 |
fl4.flowi4_mark = IN_DEV_SRC_VMARK(in_dev) ? skb->mark : 0; |
1da177e4c Linux-2.6.12-rc2 |
211 |
} |
1da177e4c Linux-2.6.12-rc2 |
212 213 214 |
if (in_dev == NULL) goto e_inval; |
c346dca10 [NET] NETNS: Omit... |
215 |
net = dev_net(dev); |
9ade22861 ipv4: Use flowi4 ... |
216 |
if (fib_lookup(net, &fl4, &res)) |
1da177e4c Linux-2.6.12-rc2 |
217 |
goto last_resort; |
8153a10c0 ipv4 05/05: add s... |
218 219 |
if (res.type != RTN_UNICAST) { if (res.type != RTN_LOCAL || !accept_local) |
ebc0ffae5 fib: RCU conversi... |
220 |
goto e_inval; |
8153a10c0 ipv4 05/05: add s... |
221 |
} |
436c3b66e ipv4: Invalidate ... |
222 |
*spec_dst = FIB_RES_PREFSRC(net, res); |
1da177e4c Linux-2.6.12-rc2 |
223 |
fib_combine_itag(itag, &res); |
6f86b3251 ipv4: Fix reverse... |
224 |
dev_match = false; |
1da177e4c Linux-2.6.12-rc2 |
225 |
#ifdef CONFIG_IP_ROUTE_MULTIPATH |
6f86b3251 ipv4: Fix reverse... |
226 227 228 229 230 231 232 233 |
for (ret = 0; ret < res.fi->fib_nhs; ret++) { struct fib_nh *nh = &res.fi->fib_nh[ret]; if (nh->nh_dev == dev) { dev_match = true; break; } } |
1da177e4c Linux-2.6.12-rc2 |
234 235 |
#else if (FIB_RES_DEV(res) == dev) |
6f86b3251 ipv4: Fix reverse... |
236 |
dev_match = true; |
1da177e4c Linux-2.6.12-rc2 |
237 |
#endif |
6f86b3251 ipv4: Fix reverse... |
238 |
if (dev_match) { |
1da177e4c Linux-2.6.12-rc2 |
239 |
ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; |
1da177e4c Linux-2.6.12-rc2 |
240 241 |
return ret; } |
1da177e4c Linux-2.6.12-rc2 |
242 243 |
if (no_addr) goto last_resort; |
c1cf8422f ip: add loose rev... |
244 |
if (rpf == 1) |
b5f7e7554 ipv4: add LINUX_M... |
245 |
goto e_rpf; |
9ade22861 ipv4: Use flowi4 ... |
246 |
fl4.flowi4_oif = dev->ifindex; |
1da177e4c Linux-2.6.12-rc2 |
247 248 |
ret = 0; |
9ade22861 ipv4: Use flowi4 ... |
249 |
if (fib_lookup(net, &fl4, &res) == 0) { |
1da177e4c Linux-2.6.12-rc2 |
250 |
if (res.type == RTN_UNICAST) { |
436c3b66e ipv4: Invalidate ... |
251 |
*spec_dst = FIB_RES_PREFSRC(net, res); |
1da177e4c Linux-2.6.12-rc2 |
252 253 |
ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; } |
1da177e4c Linux-2.6.12-rc2 |
254 255 256 257 258 |
} return ret; last_resort: if (rpf) |
b5f7e7554 ipv4: add LINUX_M... |
259 |
goto e_rpf; |
1da177e4c Linux-2.6.12-rc2 |
260 261 262 |
*spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE); *itag = 0; return 0; |
1da177e4c Linux-2.6.12-rc2 |
263 264 |
e_inval: return -EINVAL; |
b5f7e7554 ipv4: add LINUX_M... |
265 266 |
e_rpf: return -EXDEV; |
1da177e4c Linux-2.6.12-rc2 |
267 |
} |
81f7bf6cb [IPV4]: net/ipv4/... |
268 |
static inline __be32 sk_extract_addr(struct sockaddr *addr) |
4e902c574 [IPv4]: FIB confi... |
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 |
{ return ((struct sockaddr_in *) addr)->sin_addr.s_addr; } static int put_rtax(struct nlattr *mx, int len, int type, u32 value) { struct nlattr *nla; nla = (struct nlattr *) ((char *) mx + len); nla->nla_type = type; nla->nla_len = nla_attr_size(4); *(u32 *) nla_data(nla) = value; return len + nla_total_size(4); } |
4b5d47d4d [NETNS]: Correctl... |
284 |
static int rtentry_to_fib_config(struct net *net, int cmd, struct rtentry *rt, |
4e902c574 [IPv4]: FIB confi... |
285 286 |
struct fib_config *cfg) { |
6d85c10ab [IPV4]: struct fi... |
287 |
__be32 addr; |
4e902c574 [IPv4]: FIB confi... |
288 289 290 |
int plen; memset(cfg, 0, sizeof(*cfg)); |
4b5d47d4d [NETNS]: Correctl... |
291 |
cfg->fc_nlinfo.nl_net = net; |
4e902c574 [IPv4]: FIB confi... |
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
if (rt->rt_dst.sa_family != AF_INET) return -EAFNOSUPPORT; /* * Check mask for validity: * a) it must be contiguous. * b) destination must have all host bits clear. * c) if application forgot to set correct family (AF_INET), * reject request unless it is absolutely clear i.e. * both family and mask are zero. */ plen = 32; addr = sk_extract_addr(&rt->rt_dst); if (!(rt->rt_flags & RTF_HOST)) { |
81f7bf6cb [IPV4]: net/ipv4/... |
307 |
__be32 mask = sk_extract_addr(&rt->rt_genmask); |
4e902c574 [IPv4]: FIB confi... |
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 |
if (rt->rt_genmask.sa_family != AF_INET) { if (mask || rt->rt_genmask.sa_family) return -EAFNOSUPPORT; } if (bad_mask(mask, addr)) return -EINVAL; plen = inet_mask_len(mask); } cfg->fc_dst_len = plen; cfg->fc_dst = addr; if (cmd != SIOCDELRT) { cfg->fc_nlflags = NLM_F_CREATE; cfg->fc_protocol = RTPROT_BOOT; } if (rt->rt_metric) cfg->fc_priority = rt->rt_metric - 1; if (rt->rt_flags & RTF_REJECT) { cfg->fc_scope = RT_SCOPE_HOST; cfg->fc_type = RTN_UNREACHABLE; return 0; } cfg->fc_scope = RT_SCOPE_NOWHERE; cfg->fc_type = RTN_UNICAST; if (rt->rt_dev) { char *colon; struct net_device *dev; char devname[IFNAMSIZ]; if (copy_from_user(devname, rt->rt_dev, IFNAMSIZ-1)) return -EFAULT; devname[IFNAMSIZ-1] = 0; colon = strchr(devname, ':'); if (colon) *colon = 0; |
4b5d47d4d [NETNS]: Correctl... |
352 |
dev = __dev_get_by_name(net, devname); |
4e902c574 [IPv4]: FIB confi... |
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 |
if (!dev) return -ENODEV; cfg->fc_oif = dev->ifindex; if (colon) { struct in_ifaddr *ifa; struct in_device *in_dev = __in_dev_get_rtnl(dev); if (!in_dev) return -ENODEV; *colon = ':'; for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) if (strcmp(ifa->ifa_label, devname) == 0) break; if (ifa == NULL) return -ENODEV; cfg->fc_prefsrc = ifa->ifa_local; } } addr = sk_extract_addr(&rt->rt_gateway); if (rt->rt_gateway.sa_family == AF_INET && addr) { cfg->fc_gw = addr; if (rt->rt_flags & RTF_GATEWAY && |
4b5d47d4d [NETNS]: Correctl... |
375 |
inet_addr_type(net, addr) == RTN_UNICAST) |
4e902c574 [IPv4]: FIB confi... |
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 |
cfg->fc_scope = RT_SCOPE_UNIVERSE; } if (cmd == SIOCDELRT) return 0; if (rt->rt_flags & RTF_GATEWAY && !cfg->fc_gw) return -EINVAL; if (cfg->fc_scope == RT_SCOPE_NOWHERE) cfg->fc_scope = RT_SCOPE_LINK; if (rt->rt_flags & (RTF_MTU | RTF_WINDOW | RTF_IRTT)) { struct nlattr *mx; int len = 0; mx = kzalloc(3 * nla_total_size(4), GFP_KERNEL); |
e905a9eda [NET] IPV4: Fix w... |
393 |
if (mx == NULL) |
4e902c574 [IPv4]: FIB confi... |
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 |
return -ENOMEM; if (rt->rt_flags & RTF_MTU) len = put_rtax(mx, len, RTAX_ADVMSS, rt->rt_mtu - 40); if (rt->rt_flags & RTF_WINDOW) len = put_rtax(mx, len, RTAX_WINDOW, rt->rt_window); if (rt->rt_flags & RTF_IRTT) len = put_rtax(mx, len, RTAX_RTT, rt->rt_irtt << 3); cfg->fc_mx = mx; cfg->fc_mx_len = len; } return 0; } |
1da177e4c Linux-2.6.12-rc2 |
411 |
/* |
6a31d2a97 fib: cleanups |
412 413 |
* Handle IP routing ioctl calls. * These are used to manipulate the routing tables |
1da177e4c Linux-2.6.12-rc2 |
414 |
*/ |
1bad118a3 [NETNS]: Pass nam... |
415 |
int ip_rt_ioctl(struct net *net, unsigned int cmd, void __user *arg) |
1da177e4c Linux-2.6.12-rc2 |
416 |
{ |
4e902c574 [IPv4]: FIB confi... |
417 418 |
struct fib_config cfg; struct rtentry rt; |
1da177e4c Linux-2.6.12-rc2 |
419 |
int err; |
1da177e4c Linux-2.6.12-rc2 |
420 421 422 423 424 425 |
switch (cmd) { case SIOCADDRT: /* Add a route */ case SIOCDELRT: /* Delete a route */ if (!capable(CAP_NET_ADMIN)) return -EPERM; |
4e902c574 [IPv4]: FIB confi... |
426 427 |
if (copy_from_user(&rt, arg, sizeof(rt))) |
1da177e4c Linux-2.6.12-rc2 |
428 |
return -EFAULT; |
4e902c574 [IPv4]: FIB confi... |
429 |
|
1da177e4c Linux-2.6.12-rc2 |
430 |
rtnl_lock(); |
1bad118a3 [NETNS]: Pass nam... |
431 |
err = rtentry_to_fib_config(net, cmd, &rt, &cfg); |
1da177e4c Linux-2.6.12-rc2 |
432 |
if (err == 0) { |
4e902c574 [IPv4]: FIB confi... |
433 |
struct fib_table *tb; |
1da177e4c Linux-2.6.12-rc2 |
434 |
if (cmd == SIOCDELRT) { |
1bad118a3 [NETNS]: Pass nam... |
435 |
tb = fib_get_table(net, cfg.fc_table); |
1da177e4c Linux-2.6.12-rc2 |
436 |
if (tb) |
16c6cf8bb ipv4: fib table a... |
437 |
err = fib_table_delete(tb, &cfg); |
4e902c574 [IPv4]: FIB confi... |
438 439 |
else err = -ESRCH; |
1da177e4c Linux-2.6.12-rc2 |
440 |
} else { |
1bad118a3 [NETNS]: Pass nam... |
441 |
tb = fib_new_table(net, cfg.fc_table); |
1da177e4c Linux-2.6.12-rc2 |
442 |
if (tb) |
16c6cf8bb ipv4: fib table a... |
443 |
err = fib_table_insert(tb, &cfg); |
4e902c574 [IPv4]: FIB confi... |
444 445 |
else err = -ENOBUFS; |
1da177e4c Linux-2.6.12-rc2 |
446 |
} |
4e902c574 [IPv4]: FIB confi... |
447 448 449 |
/* allocated by rtentry_to_fib_config() */ kfree(cfg.fc_mx); |
1da177e4c Linux-2.6.12-rc2 |
450 451 452 453 454 455 |
} rtnl_unlock(); return err; } return -EINVAL; } |
6a31d2a97 fib: cleanups |
456 |
const struct nla_policy rtm_ipv4_policy[RTA_MAX + 1] = { |
4e902c574 [IPv4]: FIB confi... |
457 458 459 460 461 462 463 464 |
[RTA_DST] = { .type = NLA_U32 }, [RTA_SRC] = { .type = NLA_U32 }, [RTA_IIF] = { .type = NLA_U32 }, [RTA_OIF] = { .type = NLA_U32 }, [RTA_GATEWAY] = { .type = NLA_U32 }, [RTA_PRIORITY] = { .type = NLA_U32 }, [RTA_PREFSRC] = { .type = NLA_U32 }, [RTA_METRICS] = { .type = NLA_NESTED }, |
5176f91ea [NETLINK]: Make u... |
465 |
[RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) }, |
4e902c574 [IPv4]: FIB confi... |
466 |
[RTA_FLOW] = { .type = NLA_U32 }, |
4e902c574 [IPv4]: FIB confi... |
467 |
}; |
4b5d47d4d [NETNS]: Correctl... |
468 |
static int rtm_to_fib_config(struct net *net, struct sk_buff *skb, |
6a31d2a97 fib: cleanups |
469 |
struct nlmsghdr *nlh, struct fib_config *cfg) |
1da177e4c Linux-2.6.12-rc2 |
470 |
{ |
4e902c574 [IPv4]: FIB confi... |
471 472 473 474 475 476 477 478 479 480 481 |
struct nlattr *attr; int err, remaining; struct rtmsg *rtm; err = nlmsg_validate(nlh, sizeof(*rtm), RTA_MAX, rtm_ipv4_policy); if (err < 0) goto errout; memset(cfg, 0, sizeof(*cfg)); rtm = nlmsg_data(nlh); |
4e902c574 [IPv4]: FIB confi... |
482 |
cfg->fc_dst_len = rtm->rtm_dst_len; |
4e902c574 [IPv4]: FIB confi... |
483 484 485 486 487 488 489 490 491 492 |
cfg->fc_tos = rtm->rtm_tos; cfg->fc_table = rtm->rtm_table; cfg->fc_protocol = rtm->rtm_protocol; cfg->fc_scope = rtm->rtm_scope; cfg->fc_type = rtm->rtm_type; cfg->fc_flags = rtm->rtm_flags; cfg->fc_nlflags = nlh->nlmsg_flags; cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid; cfg->fc_nlinfo.nlh = nlh; |
4b5d47d4d [NETNS]: Correctl... |
493 |
cfg->fc_nlinfo.nl_net = net; |
4e902c574 [IPv4]: FIB confi... |
494 |
|
a0ee18b9b [IPv4] fib: Fix o... |
495 496 497 498 |
if (cfg->fc_type > RTN_MAX) { err = -EINVAL; goto errout; } |
4e902c574 [IPv4]: FIB confi... |
499 |
nlmsg_for_each_attr(attr, nlh, sizeof(struct rtmsg), remaining) { |
8f4c1f9b0 [NETLINK]: Introd... |
500 |
switch (nla_type(attr)) { |
4e902c574 [IPv4]: FIB confi... |
501 |
case RTA_DST: |
17fb2c643 [IPV4]: RTA_{DST,... |
502 |
cfg->fc_dst = nla_get_be32(attr); |
4e902c574 [IPv4]: FIB confi... |
503 |
break; |
4e902c574 [IPv4]: FIB confi... |
504 505 506 507 |
case RTA_OIF: cfg->fc_oif = nla_get_u32(attr); break; case RTA_GATEWAY: |
17fb2c643 [IPV4]: RTA_{DST,... |
508 |
cfg->fc_gw = nla_get_be32(attr); |
4e902c574 [IPv4]: FIB confi... |
509 510 511 512 513 |
break; case RTA_PRIORITY: cfg->fc_priority = nla_get_u32(attr); break; case RTA_PREFSRC: |
17fb2c643 [IPV4]: RTA_{DST,... |
514 |
cfg->fc_prefsrc = nla_get_be32(attr); |
4e902c574 [IPv4]: FIB confi... |
515 516 517 518 519 520 521 522 523 524 525 526 |
break; case RTA_METRICS: cfg->fc_mx = nla_data(attr); cfg->fc_mx_len = nla_len(attr); break; case RTA_MULTIPATH: cfg->fc_mp = nla_data(attr); cfg->fc_mp_len = nla_len(attr); break; case RTA_FLOW: cfg->fc_flow = nla_get_u32(attr); break; |
4e902c574 [IPv4]: FIB confi... |
527 528 529 |
case RTA_TABLE: cfg->fc_table = nla_get_u32(attr); break; |
1da177e4c Linux-2.6.12-rc2 |
530 531 |
} } |
4e902c574 [IPv4]: FIB confi... |
532 |
|
1da177e4c Linux-2.6.12-rc2 |
533 |
return 0; |
4e902c574 [IPv4]: FIB confi... |
534 535 |
errout: return err; |
1da177e4c Linux-2.6.12-rc2 |
536 |
} |
6ed2533e5 net: clean up net... |
537 |
static int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
1da177e4c Linux-2.6.12-rc2 |
538 |
{ |
3b1e0a655 [NET] NETNS: Omit... |
539 |
struct net *net = sock_net(skb->sk); |
4e902c574 [IPv4]: FIB confi... |
540 541 542 |
struct fib_config cfg; struct fib_table *tb; int err; |
1da177e4c Linux-2.6.12-rc2 |
543 |
|
4b5d47d4d [NETNS]: Correctl... |
544 |
err = rtm_to_fib_config(net, skb, nlh, &cfg); |
4e902c574 [IPv4]: FIB confi... |
545 546 |
if (err < 0) goto errout; |
1da177e4c Linux-2.6.12-rc2 |
547 |
|
8ad4942cd [NETNS]: Add netn... |
548 |
tb = fib_get_table(net, cfg.fc_table); |
4e902c574 [IPv4]: FIB confi... |
549 550 551 552 |
if (tb == NULL) { err = -ESRCH; goto errout; } |
16c6cf8bb ipv4: fib table a... |
553 |
err = fib_table_delete(tb, &cfg); |
4e902c574 [IPv4]: FIB confi... |
554 555 |
errout: return err; |
1da177e4c Linux-2.6.12-rc2 |
556 |
} |
6ed2533e5 net: clean up net... |
557 |
static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
1da177e4c Linux-2.6.12-rc2 |
558 |
{ |
3b1e0a655 [NET] NETNS: Omit... |
559 |
struct net *net = sock_net(skb->sk); |
4e902c574 [IPv4]: FIB confi... |
560 561 562 |
struct fib_config cfg; struct fib_table *tb; int err; |
1da177e4c Linux-2.6.12-rc2 |
563 |
|
4b5d47d4d [NETNS]: Correctl... |
564 |
err = rtm_to_fib_config(net, skb, nlh, &cfg); |
4e902c574 [IPv4]: FIB confi... |
565 566 |
if (err < 0) goto errout; |
1da177e4c Linux-2.6.12-rc2 |
567 |
|
226b0b4a5 [NETNS]: Replace ... |
568 |
tb = fib_new_table(net, cfg.fc_table); |
4e902c574 [IPv4]: FIB confi... |
569 570 571 572 |
if (tb == NULL) { err = -ENOBUFS; goto errout; } |
16c6cf8bb ipv4: fib table a... |
573 |
err = fib_table_insert(tb, &cfg); |
4e902c574 [IPv4]: FIB confi... |
574 575 |
errout: return err; |
1da177e4c Linux-2.6.12-rc2 |
576 |
} |
63f3444fb [IPv4]: Use rtnl ... |
577 |
static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) |
1da177e4c Linux-2.6.12-rc2 |
578 |
{ |
3b1e0a655 [NET] NETNS: Omit... |
579 |
struct net *net = sock_net(skb->sk); |
1af5a8c4a [IPV4]: Increase ... |
580 581 |
unsigned int h, s_h; unsigned int e = 0, s_e; |
1da177e4c Linux-2.6.12-rc2 |
582 |
struct fib_table *tb; |
1af5a8c4a [IPV4]: Increase ... |
583 |
struct hlist_node *node; |
e4aef8aea [NETNS]: Place fi... |
584 |
struct hlist_head *head; |
1af5a8c4a [IPV4]: Increase ... |
585 |
int dumped = 0; |
1da177e4c Linux-2.6.12-rc2 |
586 |
|
be403ea18 [IPv4]: Convert F... |
587 588 |
if (nlmsg_len(cb->nlh) >= sizeof(struct rtmsg) && ((struct rtmsg *) nlmsg_data(cb->nlh))->rtm_flags & RTM_F_CLONED) |
1da177e4c Linux-2.6.12-rc2 |
589 |
return ip_rt_dump(skb, cb); |
1af5a8c4a [IPV4]: Increase ... |
590 591 592 593 594 |
s_h = cb->args[0]; s_e = cb->args[1]; for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) { e = 0; |
e4aef8aea [NETNS]: Place fi... |
595 596 |
head = &net->ipv4.fib_table_hash[h]; hlist_for_each_entry(tb, node, head, tb_hlist) { |
1af5a8c4a [IPV4]: Increase ... |
597 598 599 600 |
if (e < s_e) goto next; if (dumped) memset(&cb->args[2], 0, sizeof(cb->args) - |
e905a9eda [NET] IPV4: Fix w... |
601 |
2 * sizeof(cb->args[0])); |
16c6cf8bb ipv4: fib table a... |
602 |
if (fib_table_dump(tb, skb, cb) < 0) |
1af5a8c4a [IPV4]: Increase ... |
603 604 605 606 607 |
goto out; dumped = 1; next: e++; } |
1da177e4c Linux-2.6.12-rc2 |
608 |
} |
1af5a8c4a [IPV4]: Increase ... |
609 610 611 |
out: cb->args[1] = e; cb->args[0] = h; |
1da177e4c Linux-2.6.12-rc2 |
612 613 614 615 616 |
return skb->len; } /* Prepare and feed intra-kernel routing request. |
6a31d2a97 fib: cleanups |
617 618 619 620 |
* Really, it should be netlink message, but :-( netlink * can be not configured, so that we feed it directly * to fib engine. It is legal, because all events occur * only when netlink is already locked. |
1da177e4c Linux-2.6.12-rc2 |
621 |
*/ |
81f7bf6cb [IPV4]: net/ipv4/... |
622 |
static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifaddr *ifa) |
1da177e4c Linux-2.6.12-rc2 |
623 |
{ |
c346dca10 [NET] NETNS: Omit... |
624 |
struct net *net = dev_net(ifa->ifa_dev->dev); |
4e902c574 [IPv4]: FIB confi... |
625 626 627 628 629 630 631 632 633 |
struct fib_table *tb; struct fib_config cfg = { .fc_protocol = RTPROT_KERNEL, .fc_type = type, .fc_dst = dst, .fc_dst_len = dst_len, .fc_prefsrc = ifa->ifa_local, .fc_oif = ifa->ifa_dev->dev->ifindex, .fc_nlflags = NLM_F_CREATE | NLM_F_APPEND, |
4d1169c1e [NETNS]: Add netn... |
634 |
.fc_nlinfo = { |
4b5d47d4d [NETNS]: Correctl... |
635 |
.nl_net = net, |
4d1169c1e [NETNS]: Add netn... |
636 |
}, |
4e902c574 [IPv4]: FIB confi... |
637 |
}; |
1da177e4c Linux-2.6.12-rc2 |
638 639 |
if (type == RTN_UNICAST) |
4b5d47d4d [NETNS]: Correctl... |
640 |
tb = fib_new_table(net, RT_TABLE_MAIN); |
1da177e4c Linux-2.6.12-rc2 |
641 |
else |
4b5d47d4d [NETNS]: Correctl... |
642 |
tb = fib_new_table(net, RT_TABLE_LOCAL); |
1da177e4c Linux-2.6.12-rc2 |
643 644 645 |
if (tb == NULL) return; |
4e902c574 [IPv4]: FIB confi... |
646 |
cfg.fc_table = tb->tb_id; |
1da177e4c Linux-2.6.12-rc2 |
647 |
|
4e902c574 [IPv4]: FIB confi... |
648 649 650 651 |
if (type != RTN_LOCAL) cfg.fc_scope = RT_SCOPE_LINK; else cfg.fc_scope = RT_SCOPE_HOST; |
1da177e4c Linux-2.6.12-rc2 |
652 653 |
if (cmd == RTM_NEWROUTE) |
16c6cf8bb ipv4: fib table a... |
654 |
fib_table_insert(tb, &cfg); |
1da177e4c Linux-2.6.12-rc2 |
655 |
else |
16c6cf8bb ipv4: fib table a... |
656 |
fib_table_delete(tb, &cfg); |
1da177e4c Linux-2.6.12-rc2 |
657 |
} |
0ff60a456 [IPV4]: Fix secon... |
658 |
void fib_add_ifaddr(struct in_ifaddr *ifa) |
1da177e4c Linux-2.6.12-rc2 |
659 660 661 662 |
{ struct in_device *in_dev = ifa->ifa_dev; struct net_device *dev = in_dev->dev; struct in_ifaddr *prim = ifa; |
a144ea4b7 [IPV4]: annotate ... |
663 664 |
__be32 mask = ifa->ifa_mask; __be32 addr = ifa->ifa_local; |
6a31d2a97 fib: cleanups |
665 |
__be32 prefix = ifa->ifa_address & mask; |
1da177e4c Linux-2.6.12-rc2 |
666 |
|
6a31d2a97 fib: cleanups |
667 |
if (ifa->ifa_flags & IFA_F_SECONDARY) { |
1da177e4c Linux-2.6.12-rc2 |
668 669 |
prim = inet_ifa_byprefix(in_dev, prefix, mask); if (prim == NULL) { |
a6db90109 [IPV4] FIB: print... |
670 671 |
printk(KERN_WARNING "fib_add_ifaddr: bug: prim == NULL "); |
1da177e4c Linux-2.6.12-rc2 |
672 673 674 675 676 |
return; } } fib_magic(RTM_NEWROUTE, RTN_LOCAL, addr, 32, prim); |
6a31d2a97 fib: cleanups |
677 |
if (!(dev->flags & IFF_UP)) |
1da177e4c Linux-2.6.12-rc2 |
678 679 680 |
return; /* Add broadcast address, if it is explicitly assigned. */ |
a144ea4b7 [IPV4]: annotate ... |
681 |
if (ifa->ifa_broadcast && ifa->ifa_broadcast != htonl(0xFFFFFFFF)) |
1da177e4c Linux-2.6.12-rc2 |
682 |
fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim); |
6a31d2a97 fib: cleanups |
683 |
if (!ipv4_is_zeronet(prefix) && !(ifa->ifa_flags & IFA_F_SECONDARY) && |
1da177e4c Linux-2.6.12-rc2 |
684 |
(prefix != addr || ifa->ifa_prefixlen < 32)) { |
6a31d2a97 fib: cleanups |
685 686 687 |
fib_magic(RTM_NEWROUTE, dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST, prefix, ifa->ifa_prefixlen, prim); |
1da177e4c Linux-2.6.12-rc2 |
688 689 690 691 |
/* Add network specific broadcasts, when it takes a sense */ if (ifa->ifa_prefixlen < 31) { fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix, 32, prim); |
6a31d2a97 fib: cleanups |
692 693 |
fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix | ~mask, 32, prim); |
1da177e4c Linux-2.6.12-rc2 |
694 695 696 |
} } } |
e6abbaa27 ipv4: fix route d... |
697 698 699 700 701 702 |
/* Delete primary or secondary address. * Optionally, on secondary address promotion consider the addresses * from subnet iprim as deleted, even if they are in device list. * In this case the secondary ifa can be in device list. */ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim) |
1da177e4c Linux-2.6.12-rc2 |
703 704 705 706 |
{ struct in_device *in_dev = ifa->ifa_dev; struct net_device *dev = in_dev->dev; struct in_ifaddr *ifa1; |
e6abbaa27 ipv4: fix route d... |
707 |
struct in_ifaddr *prim = ifa, *prim1 = NULL; |
6a31d2a97 fib: cleanups |
708 709 |
__be32 brd = ifa->ifa_address | ~ifa->ifa_mask; __be32 any = ifa->ifa_address & ifa->ifa_mask; |
1da177e4c Linux-2.6.12-rc2 |
710 711 712 713 714 |
#define LOCAL_OK 1 #define BRD_OK 2 #define BRD0_OK 4 #define BRD1_OK 8 unsigned ok = 0; |
e6abbaa27 ipv4: fix route d... |
715 716 717 |
int subnet = 0; /* Primary network */ int gone = 1; /* Address is missing */ int same_prefsrc = 0; /* Another primary with same IP */ |
1da177e4c Linux-2.6.12-rc2 |
718 |
|
e6abbaa27 ipv4: fix route d... |
719 |
if (ifa->ifa_flags & IFA_F_SECONDARY) { |
1da177e4c Linux-2.6.12-rc2 |
720 721 |
prim = inet_ifa_byprefix(in_dev, any, ifa->ifa_mask); if (prim == NULL) { |
a6db90109 [IPV4] FIB: print... |
722 723 |
printk(KERN_WARNING "fib_del_ifaddr: bug: prim == NULL "); |
1da177e4c Linux-2.6.12-rc2 |
724 725 |
return; } |
e6abbaa27 ipv4: fix route d... |
726 727 728 729 730 731 732 733 734 735 736 |
if (iprim && iprim != prim) { printk(KERN_WARNING "fib_del_ifaddr: bug: iprim != prim "); return; } } else if (!ipv4_is_zeronet(any) && (any != ifa->ifa_local || ifa->ifa_prefixlen < 32)) { fib_magic(RTM_DELROUTE, dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST, any, ifa->ifa_prefixlen, prim); subnet = 1; |
1da177e4c Linux-2.6.12-rc2 |
737 738 739 |
} /* Deletion is more complicated than add. |
6a31d2a97 fib: cleanups |
740 741 742 |
* We should take care of not to delete too much :-) * * Scan address list to be sure that addresses are really gone. |
1da177e4c Linux-2.6.12-rc2 |
743 744 745 |
*/ for (ifa1 = in_dev->ifa_list; ifa1; ifa1 = ifa1->ifa_next) { |
e6abbaa27 ipv4: fix route d... |
746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 |
if (ifa1 == ifa) { /* promotion, keep the IP */ gone = 0; continue; } /* Ignore IFAs from our subnet */ if (iprim && ifa1->ifa_mask == iprim->ifa_mask && inet_ifa_match(ifa1->ifa_address, iprim)) continue; /* Ignore ifa1 if it uses different primary IP (prefsrc) */ if (ifa1->ifa_flags & IFA_F_SECONDARY) { /* Another address from our subnet? */ if (ifa1->ifa_mask == prim->ifa_mask && inet_ifa_match(ifa1->ifa_address, prim)) prim1 = prim; else { /* We reached the secondaries, so * same_prefsrc should be determined. */ if (!same_prefsrc) continue; /* Search new prim1 if ifa1 is not * using the current prim1 */ if (!prim1 || ifa1->ifa_mask != prim1->ifa_mask || !inet_ifa_match(ifa1->ifa_address, prim1)) prim1 = inet_ifa_byprefix(in_dev, ifa1->ifa_address, ifa1->ifa_mask); if (!prim1) continue; if (prim1->ifa_local != prim->ifa_local) continue; } } else { if (prim->ifa_local != ifa1->ifa_local) continue; prim1 = ifa1; if (prim != prim1) same_prefsrc = 1; } |
1da177e4c Linux-2.6.12-rc2 |
789 790 791 792 793 794 795 796 |
if (ifa->ifa_local == ifa1->ifa_local) ok |= LOCAL_OK; if (ifa->ifa_broadcast == ifa1->ifa_broadcast) ok |= BRD_OK; if (brd == ifa1->ifa_broadcast) ok |= BRD1_OK; if (any == ifa1->ifa_broadcast) ok |= BRD0_OK; |
e6abbaa27 ipv4: fix route d... |
797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 |
/* primary has network specific broadcasts */ if (prim1 == ifa1 && ifa1->ifa_prefixlen < 31) { __be32 brd1 = ifa1->ifa_address | ~ifa1->ifa_mask; __be32 any1 = ifa1->ifa_address & ifa1->ifa_mask; if (!ipv4_is_zeronet(any1)) { if (ifa->ifa_broadcast == brd1 || ifa->ifa_broadcast == any1) ok |= BRD_OK; if (brd == brd1 || brd == any1) ok |= BRD1_OK; if (any == brd1 || any == any1) ok |= BRD0_OK; } } |
1da177e4c Linux-2.6.12-rc2 |
812 |
} |
6a31d2a97 fib: cleanups |
813 |
if (!(ok & BRD_OK)) |
1da177e4c Linux-2.6.12-rc2 |
814 |
fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim); |
e6abbaa27 ipv4: fix route d... |
815 816 817 818 819 820 |
if (subnet && ifa->ifa_prefixlen < 31) { if (!(ok & BRD1_OK)) fib_magic(RTM_DELROUTE, RTN_BROADCAST, brd, 32, prim); if (!(ok & BRD0_OK)) fib_magic(RTM_DELROUTE, RTN_BROADCAST, any, 32, prim); } |
6a31d2a97 fib: cleanups |
821 |
if (!(ok & LOCAL_OK)) { |
1da177e4c Linux-2.6.12-rc2 |
822 823 824 |
fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim); /* Check, that this local address finally disappeared. */ |
e6abbaa27 ipv4: fix route d... |
825 826 |
if (gone && inet_addr_type(dev_net(dev), ifa->ifa_local) != RTN_LOCAL) { |
1da177e4c Linux-2.6.12-rc2 |
827 |
/* And the last, but not the least thing. |
6a31d2a97 fib: cleanups |
828 829 830 831 832 |
* We must flush stray FIB entries. * * First of all, we scan fib_info list searching * for stray nexthop entries, then ignite fib_flush. */ |
c346dca10 [NET] NETNS: Omit... |
833 834 |
if (fib_sync_down_addr(dev_net(dev), ifa->ifa_local)) fib_flush(dev_net(dev)); |
1da177e4c Linux-2.6.12-rc2 |
835 836 837 838 839 840 841 |
} } #undef LOCAL_OK #undef BRD_OK #undef BRD0_OK #undef BRD1_OK } |
6a31d2a97 fib: cleanups |
842 |
static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb) |
246955fe4 [NETLINK]: fib_lo... |
843 |
{ |
e905a9eda [NET] IPV4: Fix w... |
844 |
|
246955fe4 [NETLINK]: fib_lo... |
845 |
struct fib_result res; |
9ade22861 ipv4: Use flowi4 ... |
846 847 848 849 850 |
struct flowi4 fl4 = { .flowi4_mark = frn->fl_mark, .daddr = frn->fl_addr, .flowi4_tos = frn->fl_tos, .flowi4_scope = frn->fl_scope, |
6a31d2a97 fib: cleanups |
851 |
}; |
1194ed0a3 [NETLINK]: Infini... |
852 |
|
912a41a4a [IPV4] nl_fib_loo... |
853 854 855 |
#ifdef CONFIG_IP_MULTIPLE_TABLES res.r = NULL; #endif |
1194ed0a3 [NETLINK]: Infini... |
856 |
frn->err = -ENOENT; |
246955fe4 [NETLINK]: fib_lo... |
857 858 859 860 |
if (tb) { local_bh_disable(); frn->tb_id = tb->tb_id; |
ebc0ffae5 fib: RCU conversi... |
861 |
rcu_read_lock(); |
9ade22861 ipv4: Use flowi4 ... |
862 |
frn->err = fib_table_lookup(tb, &fl4, &res, FIB_LOOKUP_NOREF); |
246955fe4 [NETLINK]: fib_lo... |
863 864 865 866 867 868 869 |
if (!frn->err) { frn->prefixlen = res.prefixlen; frn->nh_sel = res.nh_sel; frn->type = res.type; frn->scope = res.scope; } |
ebc0ffae5 fib: RCU conversi... |
870 |
rcu_read_unlock(); |
246955fe4 [NETLINK]: fib_lo... |
871 872 873 |
local_bh_enable(); } } |
28f7b0360 [NETLINK]: fib_fr... |
874 |
static void nl_fib_input(struct sk_buff *skb) |
246955fe4 [NETLINK]: fib_lo... |
875 |
{ |
6bd48fcf7 [NETNS]: Provide ... |
876 |
struct net *net; |
246955fe4 [NETLINK]: fib_lo... |
877 |
struct fib_result_nl *frn; |
28f7b0360 [NETLINK]: fib_fr... |
878 |
struct nlmsghdr *nlh; |
246955fe4 [NETLINK]: fib_lo... |
879 |
struct fib_table *tb; |
28f7b0360 [NETLINK]: fib_fr... |
880 |
u32 pid; |
1194ed0a3 [NETLINK]: Infini... |
881 |
|
3b1e0a655 [NET] NETNS: Omit... |
882 |
net = sock_net(skb->sk); |
b529ccf27 [NETLINK]: Introd... |
883 |
nlh = nlmsg_hdr(skb); |
ea86575ea [NETLINK]: Fix pr... |
884 |
if (skb->len < NLMSG_SPACE(0) || skb->len < nlh->nlmsg_len || |
d883a0367 [IPV4]: OOPS with... |
885 |
nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*frn))) |
ea86575ea [NETLINK]: Fix pr... |
886 |
return; |
d883a0367 [IPV4]: OOPS with... |
887 888 889 890 891 |
skb = skb_clone(skb, GFP_KERNEL); if (skb == NULL) return; nlh = nlmsg_hdr(skb); |
e905a9eda [NET] IPV4: Fix w... |
892 |
|
246955fe4 [NETLINK]: fib_lo... |
893 |
frn = (struct fib_result_nl *) NLMSG_DATA(nlh); |
6bd48fcf7 [NETNS]: Provide ... |
894 |
tb = fib_get_table(net, frn->tb_id_in); |
246955fe4 [NETLINK]: fib_lo... |
895 896 |
nl_fib_lookup(frn, tb); |
e905a9eda [NET] IPV4: Fix w... |
897 |
|
6a31d2a97 fib: cleanups |
898 899 |
pid = NETLINK_CB(skb).pid; /* pid of sending process */ NETLINK_CB(skb).pid = 0; /* from kernel */ |
ac6d439d2 [NETLINK]: Conver... |
900 |
NETLINK_CB(skb).dst_group = 0; /* unicast */ |
6bd48fcf7 [NETNS]: Provide ... |
901 |
netlink_unicast(net->ipv4.fibnl, skb, pid, MSG_DONTWAIT); |
e905a9eda [NET] IPV4: Fix w... |
902 |
} |
246955fe4 [NETLINK]: fib_lo... |
903 |
|
2c8c1e729 net: spread __net... |
904 |
static int __net_init nl_fib_lookup_init(struct net *net) |
246955fe4 [NETLINK]: fib_lo... |
905 |
{ |
6bd48fcf7 [NETNS]: Provide ... |
906 907 908 909 |
struct sock *sk; sk = netlink_kernel_create(net, NETLINK_FIB_LOOKUP, 0, nl_fib_input, NULL, THIS_MODULE); if (sk == NULL) |
7b1a74fdb [NETNS]: Refactor... |
910 |
return -EAFNOSUPPORT; |
6bd48fcf7 [NETNS]: Provide ... |
911 |
net->ipv4.fibnl = sk; |
7b1a74fdb [NETNS]: Refactor... |
912 913 914 915 916 |
return 0; } static void nl_fib_lookup_exit(struct net *net) { |
b7c6ba6eb [NETNS]: Consolid... |
917 |
netlink_kernel_release(net->ipv4.fibnl); |
775516bfa [NETNS]: Namespac... |
918 |
net->ipv4.fibnl = NULL; |
246955fe4 [NETLINK]: fib_lo... |
919 |
} |
e2ce14684 ipv4: factorize c... |
920 |
static void fib_disable_ip(struct net_device *dev, int force, int delay) |
1da177e4c Linux-2.6.12-rc2 |
921 |
{ |
85326fa54 [IPV4]: fib_sync_... |
922 |
if (fib_sync_down_dev(dev, force)) |
c346dca10 [NET] NETNS: Omit... |
923 |
fib_flush(dev_net(dev)); |
e2ce14684 ipv4: factorize c... |
924 |
rt_cache_flush(dev_net(dev), delay); |
1da177e4c Linux-2.6.12-rc2 |
925 926 927 928 929 |
arp_ifdown(dev); } static int fib_inetaddr_event(struct notifier_block *this, unsigned long event, void *ptr) { |
6ed2533e5 net: clean up net... |
930 |
struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; |
76e6ebfb4 netns: add namesp... |
931 |
struct net_device *dev = ifa->ifa_dev->dev; |
436c3b66e ipv4: Invalidate ... |
932 |
struct net *net = dev_net(dev); |
1da177e4c Linux-2.6.12-rc2 |
933 934 935 936 937 |
switch (event) { case NETDEV_UP: fib_add_ifaddr(ifa); #ifdef CONFIG_IP_ROUTE_MULTIPATH |
76e6ebfb4 netns: add namesp... |
938 |
fib_sync_up(dev); |
1da177e4c Linux-2.6.12-rc2 |
939 |
#endif |
436c3b66e ipv4: Invalidate ... |
940 |
atomic_inc(&net->ipv4.dev_addr_genid); |
76e6ebfb4 netns: add namesp... |
941 |
rt_cache_flush(dev_net(dev), -1); |
1da177e4c Linux-2.6.12-rc2 |
942 943 |
break; case NETDEV_DOWN: |
e6abbaa27 ipv4: fix route d... |
944 |
fib_del_ifaddr(ifa, NULL); |
436c3b66e ipv4: Invalidate ... |
945 |
atomic_inc(&net->ipv4.dev_addr_genid); |
9fcc2e8a7 [IPV4]: Fix issue... |
946 |
if (ifa->ifa_dev->ifa_list == NULL) { |
1da177e4c Linux-2.6.12-rc2 |
947 |
/* Last address was deleted from this interface. |
6a31d2a97 fib: cleanups |
948 |
* Disable IP. |
1da177e4c Linux-2.6.12-rc2 |
949 |
*/ |
e2ce14684 ipv4: factorize c... |
950 |
fib_disable_ip(dev, 1, 0); |
1da177e4c Linux-2.6.12-rc2 |
951 |
} else { |
76e6ebfb4 netns: add namesp... |
952 |
rt_cache_flush(dev_net(dev), -1); |
1da177e4c Linux-2.6.12-rc2 |
953 954 955 956 957 958 959 960 961 |
} break; } return NOTIFY_DONE; } static int fib_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) { struct net_device *dev = ptr; |
e5ed63991 [IPV4]: Replace _... |
962 |
struct in_device *in_dev = __in_dev_get_rtnl(dev); |
436c3b66e ipv4: Invalidate ... |
963 |
struct net *net = dev_net(dev); |
1da177e4c Linux-2.6.12-rc2 |
964 965 |
if (event == NETDEV_UNREGISTER) { |
e2ce14684 ipv4: factorize c... |
966 |
fib_disable_ip(dev, 2, -1); |
1da177e4c Linux-2.6.12-rc2 |
967 968 969 970 971 972 973 974 975 976 977 978 979 980 |
return NOTIFY_DONE; } if (!in_dev) return NOTIFY_DONE; switch (event) { case NETDEV_UP: for_ifa(in_dev) { fib_add_ifaddr(ifa); } endfor_ifa(in_dev); #ifdef CONFIG_IP_ROUTE_MULTIPATH fib_sync_up(dev); #endif |
436c3b66e ipv4: Invalidate ... |
981 |
atomic_inc(&net->ipv4.dev_addr_genid); |
76e6ebfb4 netns: add namesp... |
982 |
rt_cache_flush(dev_net(dev), -1); |
1da177e4c Linux-2.6.12-rc2 |
983 984 |
break; case NETDEV_DOWN: |
e2ce14684 ipv4: factorize c... |
985 |
fib_disable_ip(dev, 0, 0); |
1da177e4c Linux-2.6.12-rc2 |
986 987 988 |
break; case NETDEV_CHANGEMTU: case NETDEV_CHANGE: |
76e6ebfb4 netns: add namesp... |
989 |
rt_cache_flush(dev_net(dev), 0); |
1da177e4c Linux-2.6.12-rc2 |
990 |
break; |
a5ee15513 net: NETDEV_UNREG... |
991 |
case NETDEV_UNREGISTER_BATCH: |
6561a3b12 ipv4: Flush per-n... |
992 993 994 995 996 |
/* The batch unregister is only called on the first * device in the list of devices being unregistered. * Therefore we should not pass dev_net(dev) in here. */ rt_cache_flush_batch(NULL); |
a5ee15513 net: NETDEV_UNREG... |
997 |
break; |
1da177e4c Linux-2.6.12-rc2 |
998 999 1000 1001 1002 |
} return NOTIFY_DONE; } static struct notifier_block fib_inetaddr_notifier = { |
6ed2533e5 net: clean up net... |
1003 |
.notifier_call = fib_inetaddr_event, |
1da177e4c Linux-2.6.12-rc2 |
1004 1005 1006 |
}; static struct notifier_block fib_netdev_notifier = { |
6ed2533e5 net: clean up net... |
1007 |
.notifier_call = fib_netdev_event, |
1da177e4c Linux-2.6.12-rc2 |
1008 |
}; |
7b1a74fdb [NETNS]: Refactor... |
1009 |
static int __net_init ip_fib_net_init(struct net *net) |
1da177e4c Linux-2.6.12-rc2 |
1010 |
{ |
dce5cbeec [IPV4]: Fix memor... |
1011 |
int err; |
10da66f75 fib: avoid false ... |
1012 1013 1014 1015 |
size_t size = sizeof(struct hlist_head) * FIB_TABLE_HASHSZ; /* Avoid false sharing : Use at least a full cache line */ size = max_t(size_t, size, L1_CACHE_BYTES); |
1af5a8c4a [IPV4]: Increase ... |
1016 |
|
10da66f75 fib: avoid false ... |
1017 |
net->ipv4.fib_table_hash = kzalloc(size, GFP_KERNEL); |
e4aef8aea [NETNS]: Place fi... |
1018 1019 |
if (net->ipv4.fib_table_hash == NULL) return -ENOMEM; |
dce5cbeec [IPV4]: Fix memor... |
1020 1021 1022 1023 1024 1025 1026 1027 |
err = fib4_rules_init(net); if (err < 0) goto fail; return 0; fail: kfree(net->ipv4.fib_table_hash); return err; |
7b1a74fdb [NETNS]: Refactor... |
1028 |
} |
1da177e4c Linux-2.6.12-rc2 |
1029 |
|
2c8c1e729 net: spread __net... |
1030 |
static void ip_fib_net_exit(struct net *net) |
7b1a74fdb [NETNS]: Refactor... |
1031 1032 1033 1034 1035 1036 |
{ unsigned int i; #ifdef CONFIG_IP_MULTIPLE_TABLES fib4_rules_exit(net); #endif |
e2666f849 fib: add rtnl loc... |
1037 |
rtnl_lock(); |
7b1a74fdb [NETNS]: Refactor... |
1038 1039 1040 1041 |
for (i = 0; i < FIB_TABLE_HASHSZ; i++) { struct fib_table *tb; struct hlist_head *head; struct hlist_node *node, *tmp; |
63f3444fb [IPv4]: Use rtnl ... |
1042 |
|
e4aef8aea [NETNS]: Place fi... |
1043 |
head = &net->ipv4.fib_table_hash[i]; |
7b1a74fdb [NETNS]: Refactor... |
1044 1045 |
hlist_for_each_entry_safe(tb, node, tmp, head, tb_hlist) { hlist_del(node); |
16c6cf8bb ipv4: fib table a... |
1046 |
fib_table_flush(tb); |
4aa2c466a fib: Fix fib zone... |
1047 |
fib_free_table(tb); |
7b1a74fdb [NETNS]: Refactor... |
1048 1049 |
} } |
e2666f849 fib: add rtnl loc... |
1050 |
rtnl_unlock(); |
e4aef8aea [NETNS]: Place fi... |
1051 |
kfree(net->ipv4.fib_table_hash); |
7b1a74fdb [NETNS]: Refactor... |
1052 1053 1054 1055 1056 |
} static int __net_init fib_net_init(struct net *net) { int error; |
7b1a74fdb [NETNS]: Refactor... |
1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 |
error = ip_fib_net_init(net); if (error < 0) goto out; error = nl_fib_lookup_init(net); if (error < 0) goto out_nlfl; error = fib_proc_init(net); if (error < 0) goto out_proc; out: return error; out_proc: nl_fib_lookup_exit(net); out_nlfl: ip_fib_net_exit(net); goto out; } static void __net_exit fib_net_exit(struct net *net) { fib_proc_exit(net); nl_fib_lookup_exit(net); ip_fib_net_exit(net); } static struct pernet_operations fib_net_ops = { .init = fib_net_init, .exit = fib_net_exit, }; void __init ip_fib_init(void) { |
c7ac8679b rtnetlink: Comput... |
1090 1091 1092 |
rtnl_register(PF_INET, RTM_NEWROUTE, inet_rtm_newroute, NULL, NULL); rtnl_register(PF_INET, RTM_DELROUTE, inet_rtm_delroute, NULL, NULL); rtnl_register(PF_INET, RTM_GETROUTE, NULL, inet_dump_fib, NULL); |
7b1a74fdb [NETNS]: Refactor... |
1093 1094 1095 1096 |
register_pernet_subsys(&fib_net_ops); register_netdevice_notifier(&fib_netdev_notifier); register_inetaddr_notifier(&fib_inetaddr_notifier); |
7f9b80529 [IPV4]: fib hash|... |
1097 |
|
5348ba85a ipv4: Update some... |
1098 |
fib_trie_init(); |
1da177e4c Linux-2.6.12-rc2 |
1099 |
} |