Blame view

net/ipv4/fib_frontend.c 27.3 KB
1da177e4c   Linus Torvalds   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   Linus Torvalds   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   Linus Torvalds   Linux-2.6.12-rc2
15
16
  #include <linux/module.h>
  #include <asm/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
  #include <linux/bitops.h>
4fc268d24   Randy Dunlap   [PATCH] capable/c...
18
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
  #include <linux/types.h>
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
23
24
25
26
27
  #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   Arnaldo Carvalho de Melo   [INET_SOCK]: Move...
28
  #include <linux/inetdevice.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
  #include <linux/netdevice.h>
1823730fb   Thomas Graf   [IPv4]: Move inte...
30
  #include <linux/if_addr.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
  #include <linux/if_arp.h>
  #include <linux/skbuff.h>
7a9bc9b81   David S. Miller   ipv4: Elide fib_v...
33
  #include <linux/cache.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
  #include <linux/init.h>
1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
35
  #include <linux/list.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
36
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   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   Linus Torvalds   Linux-2.6.12-rc2
43
44
  #include <net/arp.h>
  #include <net/ip_fib.h>
63f3444fb   Thomas Graf   [IPv4]: Use rtnl ...
45
  #include <net/rtnetlink.h>
990078afb   Michael Smith   Disable rp_filter...
46
  #include <net/xfrm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
  #ifndef CONFIG_IP_MULTIPLE_TABLES
7b1a74fdb   Denis V. Lunev   [NETNS]: Refactor...
49
  static int __net_init fib4_rules_init(struct net *net)
c3e9a353d   Pavel Emelyanov   [IPV4]: Compact s...
50
  {
93456b6d7   Denis V. Lunev   [IPV4]: Unify acc...
51
  	struct fib_table *local_table, *main_table;
5348ba85a   David S. Miller   ipv4: Update some...
52
  	local_table = fib_trie_table(RT_TABLE_LOCAL);
93456b6d7   Denis V. Lunev   [IPV4]: Unify acc...
53
  	if (local_table == NULL)
dbb50165b   Denis V. Lunev   [IPV4]: Check fib...
54
  		return -ENOMEM;
5348ba85a   David S. Miller   ipv4: Update some...
55
  	main_table  = fib_trie_table(RT_TABLE_MAIN);
93456b6d7   Denis V. Lunev   [IPV4]: Unify acc...
56
  	if (main_table == NULL)
dbb50165b   Denis V. Lunev   [IPV4]: Check fib...
57
  		goto fail;
93456b6d7   Denis V. Lunev   [IPV4]: Unify acc...
58
  	hlist_add_head_rcu(&local_table->tb_hlist,
e4aef8aea   Denis V. Lunev   [NETNS]: Place fi...
59
  				&net->ipv4.fib_table_hash[TABLE_LOCAL_INDEX]);
93456b6d7   Denis V. Lunev   [IPV4]: Unify acc...
60
  	hlist_add_head_rcu(&main_table->tb_hlist,
e4aef8aea   Denis V. Lunev   [NETNS]: Place fi...
61
  				&net->ipv4.fib_table_hash[TABLE_MAIN_INDEX]);
dbb50165b   Denis V. Lunev   [IPV4]: Check fib...
62
63
64
  	return 0;
  
  fail:
93456b6d7   Denis V. Lunev   [IPV4]: Unify acc...
65
  	kfree(local_table);
dbb50165b   Denis V. Lunev   [IPV4]: Check fib...
66
  	return -ENOMEM;
c3e9a353d   Pavel Emelyanov   [IPV4]: Compact s...
67
  }
1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
68
  #else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69

8ad4942cd   Denis V. Lunev   [NETNS]: Add netn...
70
  struct fib_table *fib_new_table(struct net *net, u32 id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
  {
  	struct fib_table *tb;
1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
73
  	unsigned int h;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74

1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
75
76
  	if (id == 0)
  		id = RT_TABLE_MAIN;
8ad4942cd   Denis V. Lunev   [NETNS]: Add netn...
77
  	tb = fib_get_table(net, id);
1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
78
79
  	if (tb)
  		return tb;
7f9b80529   Stephen Hemminger   [IPV4]: fib hash|...
80

5348ba85a   David S. Miller   ipv4: Update some...
81
  	tb = fib_trie_table(id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
83
  	if (!tb)
  		return NULL;
f4530fa57   David S. Miller   ipv4: Avoid overh...
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  
  	switch (id) {
  	case RT_TABLE_LOCAL:
  		net->ipv4.fib_local = tb;
  		break;
  
  	case RT_TABLE_MAIN:
  		net->ipv4.fib_main = tb;
  		break;
  
  	case RT_TABLE_DEFAULT:
  		net->ipv4.fib_default = tb;
  		break;
  
  	default:
  		break;
  	}
1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
101
  	h = id & (FIB_TABLE_HASHSZ - 1);
e4aef8aea   Denis V. Lunev   [NETNS]: Place fi...
102
  	hlist_add_head_rcu(&tb->tb_hlist, &net->ipv4.fib_table_hash[h]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
104
  	return tb;
  }
8ad4942cd   Denis V. Lunev   [NETNS]: Add netn...
105
  struct fib_table *fib_get_table(struct net *net, u32 id)
1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
106
107
  {
  	struct fib_table *tb;
e4aef8aea   Denis V. Lunev   [NETNS]: Place fi...
108
  	struct hlist_head *head;
1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
109
  	unsigned int h;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110

1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
111
112
113
  	if (id == 0)
  		id = RT_TABLE_MAIN;
  	h = id & (FIB_TABLE_HASHSZ - 1);
e4aef8aea   Denis V. Lunev   [NETNS]: Place fi...
114

1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
115
  	rcu_read_lock();
e4aef8aea   Denis V. Lunev   [NETNS]: Place fi...
116
  	head = &net->ipv4.fib_table_hash[h];
b67bfe0d4   Sasha Levin   hlist: drop the n...
117
  	hlist_for_each_entry_rcu(tb, head, tb_hlist) {
1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
118
119
120
121
122
123
124
125
  		if (tb->tb_id == id) {
  			rcu_read_unlock();
  			return tb;
  		}
  	}
  	rcu_read_unlock();
  	return NULL;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
  #endif /* CONFIG_IP_MULTIPLE_TABLES */
e4aef8aea   Denis V. Lunev   [NETNS]: Place fi...
127
  static void fib_flush(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
129
  {
  	int flushed = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
  	struct fib_table *tb;
e4aef8aea   Denis V. Lunev   [NETNS]: Place fi...
131
  	struct hlist_head *head;
1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
132
  	unsigned int h;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133

1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
134
  	for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
e4aef8aea   Denis V. Lunev   [NETNS]: Place fi...
135
  		head = &net->ipv4.fib_table_hash[h];
b67bfe0d4   Sasha Levin   hlist: drop the n...
136
  		hlist_for_each_entry(tb, head, tb_hlist)
16c6cf8bb   Stephen Hemminger   ipv4: fib table a...
137
  			flushed += fib_table_flush(tb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
140
  
  	if (flushed)
4ccfe6d41   Nicolas Dichtel   ipv4/route: arg d...
141
  		rt_cache_flush(net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
  }
055381161   Laszlo Attila Toth   [IPV4]: Add inet_...
143
144
145
146
  /*
   * Find address type as if only "dev" was present in the system. If
   * on_dev is NULL then all interfaces are taken into consideration.
   */
95c961747   Eric Dumazet   net: cleanup unsi...
147
148
149
  static inline unsigned int __inet_dev_addr_type(struct net *net,
  						const struct net_device *dev,
  						__be32 addr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
  {
9ade22861   David S. Miller   ipv4: Use flowi4 ...
151
  	struct flowi4		fl4 = { .daddr = addr };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
  	struct fib_result	res;
95c961747   Eric Dumazet   net: cleanup unsi...
153
  	unsigned int ret = RTN_BROADCAST;
03cf786c4   Pavel Emelyanov   [IPV4]: Explicitl...
154
  	struct fib_table *local_table;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155

1e637c74b   Jan Engelhardt   [IPV4]: Enable us...
156
  	if (ipv4_is_zeronet(addr) || ipv4_is_lbcast(addr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
  		return RTN_BROADCAST;
f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
158
  	if (ipv4_is_multicast(addr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
  		return RTN_MULTICAST;
6b175b26c   Eric W. Biederman   [NETNS]: Add netn...
160
  	local_table = fib_get_table(net, RT_TABLE_LOCAL);
03cf786c4   Pavel Emelyanov   [IPV4]: Explicitl...
161
  	if (local_table) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
  		ret = RTN_UNICAST;
ebc0ffae5   Eric Dumazet   fib: RCU conversi...
163
  		rcu_read_lock();
9ade22861   David S. Miller   ipv4: Use flowi4 ...
164
  		if (!fib_table_lookup(local_table, &fl4, &res, FIB_LOOKUP_NOREF)) {
055381161   Laszlo Attila Toth   [IPV4]: Add inet_...
165
166
  			if (!dev || dev == res.fi->fib_dev)
  				ret = res.type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
  		}
ebc0ffae5   Eric Dumazet   fib: RCU conversi...
168
  		rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
171
  	}
  	return ret;
  }
6b175b26c   Eric W. Biederman   [NETNS]: Add netn...
172
  unsigned int inet_addr_type(struct net *net, __be32 addr)
055381161   Laszlo Attila Toth   [IPV4]: Add inet_...
173
  {
6b175b26c   Eric W. Biederman   [NETNS]: Add netn...
174
  	return __inet_dev_addr_type(net, NULL, addr);
055381161   Laszlo Attila Toth   [IPV4]: Add inet_...
175
  }
4bc2f18ba   Eric Dumazet   net/ipv4: EXPORT_...
176
  EXPORT_SYMBOL(inet_addr_type);
055381161   Laszlo Attila Toth   [IPV4]: Add inet_...
177

6b175b26c   Eric W. Biederman   [NETNS]: Add netn...
178
179
  unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev,
  				__be32 addr)
055381161   Laszlo Attila Toth   [IPV4]: Add inet_...
180
  {
6a31d2a97   Eric Dumazet   fib: cleanups
181
  	return __inet_dev_addr_type(net, dev, addr);
055381161   Laszlo Attila Toth   [IPV4]: Add inet_...
182
  }
4bc2f18ba   Eric Dumazet   net/ipv4: EXPORT_...
183
  EXPORT_SYMBOL(inet_dev_addr_type);
055381161   Laszlo Attila Toth   [IPV4]: Add inet_...
184

35ebf65e8   David S. Miller   ipv4: Create and ...
185
186
187
188
189
  __be32 fib_compute_spec_dst(struct sk_buff *skb)
  {
  	struct net_device *dev = skb->dev;
  	struct in_device *in_dev;
  	struct fib_result res;
a207a4b2e   David S. Miller   ipv4: Fix bugs in...
190
  	struct rtable *rt;
35ebf65e8   David S. Miller   ipv4: Create and ...
191
192
  	struct flowi4 fl4;
  	struct net *net;
a207a4b2e   David S. Miller   ipv4: Fix bugs in...
193
  	int scope;
35ebf65e8   David S. Miller   ipv4: Create and ...
194

a207a4b2e   David S. Miller   ipv4: Fix bugs in...
195
  	rt = skb_rtable(skb);
0cc535a29   Julian Anastasov   ipv4: fix address...
196
197
  	if ((rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST | RTCF_LOCAL)) ==
  	    RTCF_LOCAL)
35ebf65e8   David S. Miller   ipv4: Create and ...
198
199
200
201
  		return ip_hdr(skb)->daddr;
  
  	in_dev = __in_dev_get_rcu(dev);
  	BUG_ON(!in_dev);
35ebf65e8   David S. Miller   ipv4: Create and ...
202
203
  
  	net = dev_net(dev);
a207a4b2e   David S. Miller   ipv4: Fix bugs in...
204
205
206
207
  
  	scope = RT_SCOPE_UNIVERSE;
  	if (!ipv4_is_zeronet(ip_hdr(skb)->saddr)) {
  		fl4.flowi4_oif = 0;
1fb9489bf   Pavel Emelyanov   net: Loopback ifi...
208
  		fl4.flowi4_iif = LOOPBACK_IFINDEX;
a207a4b2e   David S. Miller   ipv4: Fix bugs in...
209
210
211
212
213
214
215
216
217
218
219
220
  		fl4.daddr = ip_hdr(skb)->saddr;
  		fl4.saddr = 0;
  		fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos);
  		fl4.flowi4_scope = scope;
  		fl4.flowi4_mark = IN_DEV_SRC_VMARK(in_dev) ? skb->mark : 0;
  		if (!fib_lookup(net, &fl4, &res))
  			return FIB_RES_PREFSRC(net, res);
  	} else {
  		scope = RT_SCOPE_LINK;
  	}
  
  	return inet_select_addr(dev, ip_hdr(skb)->saddr, scope);
35ebf65e8   David S. Miller   ipv4: Create and ...
221
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
  /* Given (packet source, input interface) and optional (dst, oif, tos):
6a31d2a97   Eric Dumazet   fib: cleanups
223
224
225
226
227
   * - (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   Eric Dumazet   fib: RCU conversi...
228
   * called with rcu_read_lock()
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
   */
7a9bc9b81   David S. Miller   ipv4: Elide fib_v...
230
231
232
  static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
  				 u8 tos, int oif, struct net_device *dev,
  				 int rpf, struct in_device *idev, u32 *itag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
  {
1dced6a85   Sébastien Barré   ipv4: Restore acc...
234
  	int ret, no_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
  	struct fib_result res;
9e56e3800   David S. Miller   ipv4: Adjust in_d...
236
  	struct flowi4 fl4;
5b707aaae   Denis V. Lunev   [NETNS]: Pass cor...
237
  	struct net *net;
9e56e3800   David S. Miller   ipv4: Adjust in_d...
238
  	bool dev_match;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239

9ade22861   David S. Miller   ipv4: Use flowi4 ...
240
  	fl4.flowi4_oif = 0;
6a662719c   Cong Wang   ipv4, fib: pass L...
241
  	fl4.flowi4_iif = oif ? : LOOPBACK_IFINDEX;
9ade22861   David S. Miller   ipv4: Use flowi4 ...
242
243
244
245
  	fl4.daddr = src;
  	fl4.saddr = dst;
  	fl4.flowi4_tos = tos;
  	fl4.flowi4_scope = RT_SCOPE_UNIVERSE;
cc7e17ea0   David S. Miller   ipv4: Optimize fl...
246

9e56e3800   David S. Miller   ipv4: Adjust in_d...
247
  	no_addr = idev->ifa_list == NULL;
990078afb   Michael Smith   Disable rp_filter...
248

9e56e3800   David S. Miller   ipv4: Adjust in_d...
249
  	fl4.flowi4_mark = IN_DEV_SRC_VMARK(idev) ? skb->mark : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250

c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
251
  	net = dev_net(dev);
9ade22861   David S. Miller   ipv4: Use flowi4 ...
252
  	if (fib_lookup(net, &fl4, &res))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
  		goto last_resort;
1dced6a85   Sébastien Barré   ipv4: Restore acc...
254
255
256
257
258
259
  	if (res.type != RTN_UNICAST &&
  	    (res.type != RTN_LOCAL || !IN_DEV_ACCEPT_LOCAL(idev)))
  		goto e_inval;
  	if (!rpf && !fib_num_tclassid_users(dev_net(dev)) &&
  	    (dev->ifindex != oif || !IN_DEV_TX_REDIRECTS(idev)))
  		goto last_resort;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
  	fib_combine_itag(itag, &res);
6f86b3251   David S. Miller   ipv4: Fix reverse...
261
  	dev_match = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
  #ifdef CONFIG_IP_ROUTE_MULTIPATH
6f86b3251   David S. Miller   ipv4: Fix reverse...
263
264
265
266
267
268
269
270
  	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   Linus Torvalds   Linux-2.6.12-rc2
271
272
  #else
  	if (FIB_RES_DEV(res) == dev)
6f86b3251   David S. Miller   ipv4: Fix reverse...
273
  		dev_match = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
  #endif
6f86b3251   David S. Miller   ipv4: Fix reverse...
275
  	if (dev_match) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
  		ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
278
  		return ret;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
280
  	if (no_addr)
  		goto last_resort;
c1cf8422f   Stephen Hemminger   ip: add loose rev...
281
  	if (rpf == 1)
b5f7e7554   Eric Dumazet   ipv4: add LINUX_M...
282
  		goto e_rpf;
9ade22861   David S. Miller   ipv4: Use flowi4 ...
283
  	fl4.flowi4_oif = dev->ifindex;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
285
  
  	ret = 0;
9ade22861   David S. Miller   ipv4: Use flowi4 ...
286
  	if (fib_lookup(net, &fl4, &res) == 0) {
41347dcdd   David S. Miller   ipv4: Kill rt->rt...
287
  		if (res.type == RTN_UNICAST)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
  			ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
290
291
292
293
  	}
  	return ret;
  
  last_resort:
  	if (rpf)
b5f7e7554   Eric Dumazet   ipv4: add LINUX_M...
294
  		goto e_rpf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
296
  	*itag = 0;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
298
  e_inval:
  	return -EINVAL;
b5f7e7554   Eric Dumazet   ipv4: add LINUX_M...
299
300
  e_rpf:
  	return -EXDEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
  }
7a9bc9b81   David S. Miller   ipv4: Elide fib_v...
302
303
304
305
306
307
  /* Ignore rp_filter for packets protected by IPsec. */
  int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
  			u8 tos, int oif, struct net_device *dev,
  			struct in_device *idev, u32 *itag)
  {
  	int r = secpath_exists(skb) ? 0 : IN_DEV_RPFILTER(idev);
e81da0e11   Julian Anastasov   ipv4: fix sending...
308
  	if (!r && !fib_num_tclassid_users(dev_net(dev)) &&
1dced6a85   Sébastien Barré   ipv4: Restore acc...
309
  	    IN_DEV_ACCEPT_LOCAL(idev) &&
e81da0e11   Julian Anastasov   ipv4: fix sending...
310
  	    (dev->ifindex != oif || !IN_DEV_TX_REDIRECTS(idev))) {
7a9bc9b81   David S. Miller   ipv4: Elide fib_v...
311
312
313
314
315
  		*itag = 0;
  		return 0;
  	}
  	return __fib_validate_source(skb, src, dst, tos, oif, dev, r, idev, itag);
  }
81f7bf6cb   Al Viro   [IPV4]: net/ipv4/...
316
  static inline __be32 sk_extract_addr(struct sockaddr *addr)
4e902c574   Thomas Graf   [IPv4]: FIB confi...
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
  {
  	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   Denis V. Lunev   [NETNS]: Correctl...
332
  static int rtentry_to_fib_config(struct net *net, int cmd, struct rtentry *rt,
4e902c574   Thomas Graf   [IPv4]: FIB confi...
333
334
  				 struct fib_config *cfg)
  {
6d85c10ab   Al Viro   [IPV4]: struct fi...
335
  	__be32 addr;
4e902c574   Thomas Graf   [IPv4]: FIB confi...
336
337
338
  	int plen;
  
  	memset(cfg, 0, sizeof(*cfg));
4b5d47d4d   Denis V. Lunev   [NETNS]: Correctl...
339
  	cfg->fc_nlinfo.nl_net = net;
4e902c574   Thomas Graf   [IPv4]: FIB confi...
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
  
  	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   Al Viro   [IPV4]: net/ipv4/...
355
  		__be32 mask = sk_extract_addr(&rt->rt_genmask);
4e902c574   Thomas Graf   [IPv4]: FIB confi...
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
  
  		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   Denis V. Lunev   [NETNS]: Correctl...
400
  		dev = __dev_get_by_name(net, devname);
4e902c574   Thomas Graf   [IPv4]: FIB confi...
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
  		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   Denis V. Lunev   [NETNS]: Correctl...
423
  		    inet_addr_type(net, addr) == RTN_UNICAST)
4e902c574   Thomas Graf   [IPv4]: FIB confi...
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
  			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   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
441
  		if (mx == NULL)
4e902c574   Thomas Graf   [IPv4]: FIB confi...
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
  			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   Linus Torvalds   Linux-2.6.12-rc2
459
  /*
6a31d2a97   Eric Dumazet   fib: cleanups
460
461
   * Handle IP routing ioctl calls.
   * These are used to manipulate the routing tables
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
   */
1bad118a3   Denis V. Lunev   [NETNS]: Pass nam...
463
  int ip_rt_ioctl(struct net *net, unsigned int cmd, void __user *arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464
  {
4e902c574   Thomas Graf   [IPv4]: FIB confi...
465
466
  	struct fib_config cfg;
  	struct rtentry rt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
469
470
471
  
  	switch (cmd) {
  	case SIOCADDRT:		/* Add a route */
  	case SIOCDELRT:		/* Delete a route */
52e804c6d   Eric W. Biederman   net: Allow userns...
472
  		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
473
  			return -EPERM;
4e902c574   Thomas Graf   [IPv4]: FIB confi...
474
475
  
  		if (copy_from_user(&rt, arg, sizeof(rt)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
  			return -EFAULT;
4e902c574   Thomas Graf   [IPv4]: FIB confi...
477

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
478
  		rtnl_lock();
1bad118a3   Denis V. Lunev   [NETNS]: Pass nam...
479
  		err = rtentry_to_fib_config(net, cmd, &rt, &cfg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
480
  		if (err == 0) {
4e902c574   Thomas Graf   [IPv4]: FIB confi...
481
  			struct fib_table *tb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
  			if (cmd == SIOCDELRT) {
1bad118a3   Denis V. Lunev   [NETNS]: Pass nam...
483
  				tb = fib_get_table(net, cfg.fc_table);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484
  				if (tb)
16c6cf8bb   Stephen Hemminger   ipv4: fib table a...
485
  					err = fib_table_delete(tb, &cfg);
4e902c574   Thomas Graf   [IPv4]: FIB confi...
486
487
  				else
  					err = -ESRCH;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
488
  			} else {
1bad118a3   Denis V. Lunev   [NETNS]: Pass nam...
489
  				tb = fib_new_table(net, cfg.fc_table);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
  				if (tb)
16c6cf8bb   Stephen Hemminger   ipv4: fib table a...
491
  					err = fib_table_insert(tb, &cfg);
4e902c574   Thomas Graf   [IPv4]: FIB confi...
492
493
  				else
  					err = -ENOBUFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
  			}
4e902c574   Thomas Graf   [IPv4]: FIB confi...
495
496
497
  
  			/* allocated by rtentry_to_fib_config() */
  			kfree(cfg.fc_mx);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
498
499
500
501
502
503
  		}
  		rtnl_unlock();
  		return err;
  	}
  	return -EINVAL;
  }
6a31d2a97   Eric Dumazet   fib: cleanups
504
  const struct nla_policy rtm_ipv4_policy[RTA_MAX + 1] = {
4e902c574   Thomas Graf   [IPv4]: FIB confi...
505
506
507
508
509
510
511
512
  	[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   Thomas Graf   [NETLINK]: Make u...
513
  	[RTA_MULTIPATH]		= { .len = sizeof(struct rtnexthop) },
4e902c574   Thomas Graf   [IPv4]: FIB confi...
514
  	[RTA_FLOW]		= { .type = NLA_U32 },
4e902c574   Thomas Graf   [IPv4]: FIB confi...
515
  };
4b5d47d4d   Denis V. Lunev   [NETNS]: Correctl...
516
  static int rtm_to_fib_config(struct net *net, struct sk_buff *skb,
6a31d2a97   Eric Dumazet   fib: cleanups
517
  			     struct nlmsghdr *nlh, struct fib_config *cfg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518
  {
4e902c574   Thomas Graf   [IPv4]: FIB confi...
519
520
521
522
523
524
525
526
527
528
529
  	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   Thomas Graf   [IPv4]: FIB confi...
530
  	cfg->fc_dst_len = rtm->rtm_dst_len;
4e902c574   Thomas Graf   [IPv4]: FIB confi...
531
532
533
534
535
536
537
  	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;
15e473046   Eric W. Biederman   netlink: Rename p...
538
  	cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid;
4e902c574   Thomas Graf   [IPv4]: FIB confi...
539
  	cfg->fc_nlinfo.nlh = nlh;
4b5d47d4d   Denis V. Lunev   [NETNS]: Correctl...
540
  	cfg->fc_nlinfo.nl_net = net;
4e902c574   Thomas Graf   [IPv4]: FIB confi...
541

a0ee18b9b   Thomas Graf   [IPv4] fib: Fix o...
542
543
544
545
  	if (cfg->fc_type > RTN_MAX) {
  		err = -EINVAL;
  		goto errout;
  	}
4e902c574   Thomas Graf   [IPv4]: FIB confi...
546
  	nlmsg_for_each_attr(attr, nlh, sizeof(struct rtmsg), remaining) {
8f4c1f9b0   Thomas Graf   [NETLINK]: Introd...
547
  		switch (nla_type(attr)) {
4e902c574   Thomas Graf   [IPv4]: FIB confi...
548
  		case RTA_DST:
17fb2c643   Al Viro   [IPV4]: RTA_{DST,...
549
  			cfg->fc_dst = nla_get_be32(attr);
4e902c574   Thomas Graf   [IPv4]: FIB confi...
550
  			break;
4e902c574   Thomas Graf   [IPv4]: FIB confi...
551
552
553
554
  		case RTA_OIF:
  			cfg->fc_oif = nla_get_u32(attr);
  			break;
  		case RTA_GATEWAY:
17fb2c643   Al Viro   [IPV4]: RTA_{DST,...
555
  			cfg->fc_gw = nla_get_be32(attr);
4e902c574   Thomas Graf   [IPv4]: FIB confi...
556
557
558
559
560
  			break;
  		case RTA_PRIORITY:
  			cfg->fc_priority = nla_get_u32(attr);
  			break;
  		case RTA_PREFSRC:
17fb2c643   Al Viro   [IPV4]: RTA_{DST,...
561
  			cfg->fc_prefsrc = nla_get_be32(attr);
4e902c574   Thomas Graf   [IPv4]: FIB confi...
562
563
564
565
566
567
568
569
570
571
572
573
  			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   Thomas Graf   [IPv4]: FIB confi...
574
575
576
  		case RTA_TABLE:
  			cfg->fc_table = nla_get_u32(attr);
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577
578
  		}
  	}
4e902c574   Thomas Graf   [IPv4]: FIB confi...
579

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
  	return 0;
4e902c574   Thomas Graf   [IPv4]: FIB confi...
581
582
  errout:
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
583
  }
661d2967b   Thomas Graf   rtnetlink: Remove...
584
  static int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
586
  	struct net *net = sock_net(skb->sk);
4e902c574   Thomas Graf   [IPv4]: FIB confi...
587
588
589
  	struct fib_config cfg;
  	struct fib_table *tb;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
590

4b5d47d4d   Denis V. Lunev   [NETNS]: Correctl...
591
  	err = rtm_to_fib_config(net, skb, nlh, &cfg);
4e902c574   Thomas Graf   [IPv4]: FIB confi...
592
593
  	if (err < 0)
  		goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594

8ad4942cd   Denis V. Lunev   [NETNS]: Add netn...
595
  	tb = fib_get_table(net, cfg.fc_table);
4e902c574   Thomas Graf   [IPv4]: FIB confi...
596
597
598
599
  	if (tb == NULL) {
  		err = -ESRCH;
  		goto errout;
  	}
16c6cf8bb   Stephen Hemminger   ipv4: fib table a...
600
  	err = fib_table_delete(tb, &cfg);
4e902c574   Thomas Graf   [IPv4]: FIB confi...
601
602
  errout:
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603
  }
661d2967b   Thomas Graf   rtnetlink: Remove...
604
  static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
605
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
606
  	struct net *net = sock_net(skb->sk);
4e902c574   Thomas Graf   [IPv4]: FIB confi...
607
608
609
  	struct fib_config cfg;
  	struct fib_table *tb;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
610

4b5d47d4d   Denis V. Lunev   [NETNS]: Correctl...
611
  	err = rtm_to_fib_config(net, skb, nlh, &cfg);
4e902c574   Thomas Graf   [IPv4]: FIB confi...
612
613
  	if (err < 0)
  		goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
614

226b0b4a5   Denis V. Lunev   [NETNS]: Replace ...
615
  	tb = fib_new_table(net, cfg.fc_table);
4e902c574   Thomas Graf   [IPv4]: FIB confi...
616
617
618
619
  	if (tb == NULL) {
  		err = -ENOBUFS;
  		goto errout;
  	}
16c6cf8bb   Stephen Hemminger   ipv4: fib table a...
620
  	err = fib_table_insert(tb, &cfg);
4e902c574   Thomas Graf   [IPv4]: FIB confi...
621
622
  errout:
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
623
  }
63f3444fb   Thomas Graf   [IPv4]: Use rtnl ...
624
  static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
626
  	struct net *net = sock_net(skb->sk);
1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
627
628
  	unsigned int h, s_h;
  	unsigned int e = 0, s_e;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
629
  	struct fib_table *tb;
e4aef8aea   Denis V. Lunev   [NETNS]: Place fi...
630
  	struct hlist_head *head;
1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
631
  	int dumped = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
632

be403ea18   Thomas Graf   [IPv4]: Convert F...
633
634
  	if (nlmsg_len(cb->nlh) >= sizeof(struct rtmsg) &&
  	    ((struct rtmsg *) nlmsg_data(cb->nlh))->rtm_flags & RTM_F_CLONED)
0b8c7f6f2   Li RongQing   ipv4: remove ip_r...
635
  		return skb->len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636

1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
637
638
639
640
641
  	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   Denis V. Lunev   [NETNS]: Place fi...
642
  		head = &net->ipv4.fib_table_hash[h];
b67bfe0d4   Sasha Levin   hlist: drop the n...
643
  		hlist_for_each_entry(tb, head, tb_hlist) {
1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
644
645
646
647
  			if (e < s_e)
  				goto next;
  			if (dumped)
  				memset(&cb->args[2], 0, sizeof(cb->args) -
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
648
  						 2 * sizeof(cb->args[0]));
16c6cf8bb   Stephen Hemminger   ipv4: fib table a...
649
  			if (fib_table_dump(tb, skb, cb) < 0)
1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
650
651
652
653
654
  				goto out;
  			dumped = 1;
  next:
  			e++;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
655
  	}
1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
656
657
658
  out:
  	cb->args[1] = e;
  	cb->args[0] = h;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
660
661
662
663
  
  	return skb->len;
  }
  
  /* Prepare and feed intra-kernel routing request.
6a31d2a97   Eric Dumazet   fib: cleanups
664
665
666
667
   * 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   Linus Torvalds   Linux-2.6.12-rc2
668
   */
81f7bf6cb   Al Viro   [IPV4]: net/ipv4/...
669
  static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifaddr *ifa)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670
  {
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
671
  	struct net *net = dev_net(ifa->ifa_dev->dev);
4e902c574   Thomas Graf   [IPv4]: FIB confi...
672
673
674
675
676
677
678
679
680
  	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   Denis V. Lunev   [NETNS]: Add netn...
681
  		.fc_nlinfo = {
4b5d47d4d   Denis V. Lunev   [NETNS]: Correctl...
682
  			.nl_net = net,
4d1169c1e   Denis V. Lunev   [NETNS]: Add netn...
683
  		},
4e902c574   Thomas Graf   [IPv4]: FIB confi...
684
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
686
  
  	if (type == RTN_UNICAST)
4b5d47d4d   Denis V. Lunev   [NETNS]: Correctl...
687
  		tb = fib_new_table(net, RT_TABLE_MAIN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
688
  	else
4b5d47d4d   Denis V. Lunev   [NETNS]: Correctl...
689
  		tb = fib_new_table(net, RT_TABLE_LOCAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
690
691
692
  
  	if (tb == NULL)
  		return;
4e902c574   Thomas Graf   [IPv4]: FIB confi...
693
  	cfg.fc_table = tb->tb_id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
694

4e902c574   Thomas Graf   [IPv4]: FIB confi...
695
696
697
698
  	if (type != RTN_LOCAL)
  		cfg.fc_scope = RT_SCOPE_LINK;
  	else
  		cfg.fc_scope = RT_SCOPE_HOST;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
699
700
  
  	if (cmd == RTM_NEWROUTE)
16c6cf8bb   Stephen Hemminger   ipv4: fib table a...
701
  		fib_table_insert(tb, &cfg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
  	else
16c6cf8bb   Stephen Hemminger   ipv4: fib table a...
703
  		fib_table_delete(tb, &cfg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704
  }
0ff60a456   Jamal Hadi Salim   [IPV4]: Fix secon...
705
  void fib_add_ifaddr(struct in_ifaddr *ifa)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706
707
708
709
  {
  	struct in_device *in_dev = ifa->ifa_dev;
  	struct net_device *dev = in_dev->dev;
  	struct in_ifaddr *prim = ifa;
a144ea4b7   Al Viro   [IPV4]: annotate ...
710
711
  	__be32 mask = ifa->ifa_mask;
  	__be32 addr = ifa->ifa_local;
6a31d2a97   Eric Dumazet   fib: cleanups
712
  	__be32 prefix = ifa->ifa_address & mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713

6a31d2a97   Eric Dumazet   fib: cleanups
714
  	if (ifa->ifa_flags & IFA_F_SECONDARY) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
715
716
  		prim = inet_ifa_byprefix(in_dev, prefix, mask);
  		if (prim == NULL) {
058bd4d2a   Joe Perches   net: Convert prin...
717
718
  			pr_warn("%s: bug: prim == NULL
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
719
720
721
722
723
  			return;
  		}
  	}
  
  	fib_magic(RTM_NEWROUTE, RTN_LOCAL, addr, 32, prim);
6a31d2a97   Eric Dumazet   fib: cleanups
724
  	if (!(dev->flags & IFF_UP))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725
726
727
  		return;
  
  	/* Add broadcast address, if it is explicitly assigned. */
a144ea4b7   Al Viro   [IPV4]: annotate ...
728
  	if (ifa->ifa_broadcast && ifa->ifa_broadcast != htonl(0xFFFFFFFF))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
729
  		fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
6a31d2a97   Eric Dumazet   fib: cleanups
730
  	if (!ipv4_is_zeronet(prefix) && !(ifa->ifa_flags & IFA_F_SECONDARY) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
731
  	    (prefix != addr || ifa->ifa_prefixlen < 32)) {
6a31d2a97   Eric Dumazet   fib: cleanups
732
733
734
  		fib_magic(RTM_NEWROUTE,
  			  dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST,
  			  prefix, ifa->ifa_prefixlen, prim);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
735
736
737
738
  
  		/* Add network specific broadcasts, when it takes a sense */
  		if (ifa->ifa_prefixlen < 31) {
  			fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix, 32, prim);
6a31d2a97   Eric Dumazet   fib: cleanups
739
740
  			fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix | ~mask,
  				  32, prim);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
741
742
743
  		}
  	}
  }
e6abbaa27   Julian Anastasov   ipv4: fix route d...
744
745
746
747
748
749
  /* 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   Linus Torvalds   Linux-2.6.12-rc2
750
751
752
753
  {
  	struct in_device *in_dev = ifa->ifa_dev;
  	struct net_device *dev = in_dev->dev;
  	struct in_ifaddr *ifa1;
e6abbaa27   Julian Anastasov   ipv4: fix route d...
754
  	struct in_ifaddr *prim = ifa, *prim1 = NULL;
6a31d2a97   Eric Dumazet   fib: cleanups
755
756
  	__be32 brd = ifa->ifa_address | ~ifa->ifa_mask;
  	__be32 any = ifa->ifa_address & ifa->ifa_mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
758
759
760
  #define LOCAL_OK	1
  #define BRD_OK		2
  #define BRD0_OK		4
  #define BRD1_OK		8
95c961747   Eric Dumazet   net: cleanup unsi...
761
  	unsigned int ok = 0;
e6abbaa27   Julian Anastasov   ipv4: fix route d...
762
763
764
  	int subnet = 0;		/* Primary network */
  	int gone = 1;		/* Address is missing */
  	int same_prefsrc = 0;	/* Another primary with same IP */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765

e6abbaa27   Julian Anastasov   ipv4: fix route d...
766
  	if (ifa->ifa_flags & IFA_F_SECONDARY) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
768
  		prim = inet_ifa_byprefix(in_dev, any, ifa->ifa_mask);
  		if (prim == NULL) {
058bd4d2a   Joe Perches   net: Convert prin...
769
770
  			pr_warn("%s: bug: prim == NULL
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771
772
  			return;
  		}
e6abbaa27   Julian Anastasov   ipv4: fix route d...
773
  		if (iprim && iprim != prim) {
058bd4d2a   Joe Perches   net: Convert prin...
774
775
  			pr_warn("%s: bug: iprim != prim
  ", __func__);
e6abbaa27   Julian Anastasov   ipv4: fix route d...
776
777
778
779
780
781
782
783
  			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   Linus Torvalds   Linux-2.6.12-rc2
784
785
786
  	}
  
  	/* Deletion is more complicated than add.
6a31d2a97   Eric Dumazet   fib: cleanups
787
788
789
  	 * We should take care of not to delete too much :-)
  	 *
  	 * Scan address list to be sure that addresses are really gone.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
790
791
792
  	 */
  
  	for (ifa1 = in_dev->ifa_list; ifa1; ifa1 = ifa1->ifa_next) {
e6abbaa27   Julian Anastasov   ipv4: fix route d...
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
  		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   Linus Torvalds   Linux-2.6.12-rc2
836
837
838
839
840
841
842
843
  		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   Julian Anastasov   ipv4: fix route d...
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
  		/* 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   Linus Torvalds   Linux-2.6.12-rc2
859
  	}
6a31d2a97   Eric Dumazet   fib: cleanups
860
  	if (!(ok & BRD_OK))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
861
  		fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
e6abbaa27   Julian Anastasov   ipv4: fix route d...
862
863
864
865
866
867
  	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   Eric Dumazet   fib: cleanups
868
  	if (!(ok & LOCAL_OK)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
869
870
871
  		fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim);
  
  		/* Check, that this local address finally disappeared. */
e6abbaa27   Julian Anastasov   ipv4: fix route d...
872
873
  		if (gone &&
  		    inet_addr_type(dev_net(dev), ifa->ifa_local) != RTN_LOCAL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
874
  			/* And the last, but not the least thing.
6a31d2a97   Eric Dumazet   fib: cleanups
875
876
877
878
879
  			 * We must flush stray FIB entries.
  			 *
  			 * First of all, we scan fib_info list searching
  			 * for stray nexthop entries, then ignite fib_flush.
  			 */
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
880
881
  			if (fib_sync_down_addr(dev_net(dev), ifa->ifa_local))
  				fib_flush(dev_net(dev));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
882
883
884
885
886
887
888
  		}
  	}
  #undef LOCAL_OK
  #undef BRD_OK
  #undef BRD0_OK
  #undef BRD1_OK
  }
6a31d2a97   Eric Dumazet   fib: cleanups
889
  static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb)
246955fe4   Robert Olsson   [NETLINK]: fib_lo...
890
  {
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
891

246955fe4   Robert Olsson   [NETLINK]: fib_lo...
892
  	struct fib_result       res;
9ade22861   David S. Miller   ipv4: Use flowi4 ...
893
894
895
896
897
  	struct flowi4           fl4 = {
  		.flowi4_mark = frn->fl_mark,
  		.daddr = frn->fl_addr,
  		.flowi4_tos = frn->fl_tos,
  		.flowi4_scope = frn->fl_scope,
6a31d2a97   Eric Dumazet   fib: cleanups
898
  	};
1194ed0a3   Alexey Kuznetsov   [NETLINK]: Infini...
899
900
  
  	frn->err = -ENOENT;
246955fe4   Robert Olsson   [NETLINK]: fib_lo...
901
902
903
904
  	if (tb) {
  		local_bh_disable();
  
  		frn->tb_id = tb->tb_id;
9ade22861   David S. Miller   ipv4: Use flowi4 ...
905
  		frn->err = fib_table_lookup(tb, &fl4, &res, FIB_LOOKUP_NOREF);
246955fe4   Robert Olsson   [NETLINK]: fib_lo...
906
907
908
909
910
911
912
913
914
915
  
  		if (!frn->err) {
  			frn->prefixlen = res.prefixlen;
  			frn->nh_sel = res.nh_sel;
  			frn->type = res.type;
  			frn->scope = res.scope;
  		}
  		local_bh_enable();
  	}
  }
28f7b0360   David S. Miller   [NETLINK]: fib_fr...
916
  static void nl_fib_input(struct sk_buff *skb)
246955fe4   Robert Olsson   [NETLINK]: fib_lo...
917
  {
6bd48fcf7   Denis V. Lunev   [NETNS]: Provide ...
918
  	struct net *net;
246955fe4   Robert Olsson   [NETLINK]: fib_lo...
919
  	struct fib_result_nl *frn;
28f7b0360   David S. Miller   [NETLINK]: fib_fr...
920
  	struct nlmsghdr *nlh;
246955fe4   Robert Olsson   [NETLINK]: fib_lo...
921
  	struct fib_table *tb;
15e473046   Eric W. Biederman   netlink: Rename p...
922
  	u32 portid;
1194ed0a3   Alexey Kuznetsov   [NETLINK]: Infini...
923

3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
924
  	net = sock_net(skb->sk);
b529ccf27   Arnaldo Carvalho de Melo   [NETLINK]: Introd...
925
  	nlh = nlmsg_hdr(skb);
573ce260b   Hong zhi guo   net-next: replace...
926
927
  	if (skb->len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len ||
  	    nlmsg_len(nlh) < sizeof(*frn))
ea86575ea   Thomas Graf   [NETLINK]: Fix pr...
928
  		return;
d883a0367   Denis V. Lunev   [IPV4]: OOPS with...
929

3a36515f7   Pablo Neira   netlink: fix spla...
930
  	skb = netlink_skb_clone(skb, GFP_KERNEL);
d883a0367   Denis V. Lunev   [IPV4]: OOPS with...
931
932
933
  	if (skb == NULL)
  		return;
  	nlh = nlmsg_hdr(skb);
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
934

573ce260b   Hong zhi guo   net-next: replace...
935
  	frn = (struct fib_result_nl *) nlmsg_data(nlh);
6bd48fcf7   Denis V. Lunev   [NETNS]: Provide ...
936
  	tb = fib_get_table(net, frn->tb_id_in);
246955fe4   Robert Olsson   [NETLINK]: fib_lo...
937
938
  
  	nl_fib_lookup(frn, tb);
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
939

28a28283f   Rami Rosen   ipv4: fib: fix a ...
940
  	portid = NETLINK_CB(skb).portid;      /* netlink portid */
15e473046   Eric W. Biederman   netlink: Rename p...
941
  	NETLINK_CB(skb).portid = 0;        /* from kernel */
ac6d439d2   Patrick McHardy   [NETLINK]: Conver...
942
  	NETLINK_CB(skb).dst_group = 0;  /* unicast */
15e473046   Eric W. Biederman   netlink: Rename p...
943
  	netlink_unicast(net->ipv4.fibnl, skb, portid, MSG_DONTWAIT);
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
944
  }
246955fe4   Robert Olsson   [NETLINK]: fib_lo...
945

2c8c1e729   Alexey Dobriyan   net: spread __net...
946
  static int __net_init nl_fib_lookup_init(struct net *net)
246955fe4   Robert Olsson   [NETLINK]: fib_lo...
947
  {
6bd48fcf7   Denis V. Lunev   [NETNS]: Provide ...
948
  	struct sock *sk;
a31f2d17b   Pablo Neira Ayuso   netlink: add netl...
949
950
951
  	struct netlink_kernel_cfg cfg = {
  		.input	= nl_fib_input,
  	};
9f00d9776   Pablo Neira Ayuso   netlink: hide str...
952
  	sk = netlink_kernel_create(net, NETLINK_FIB_LOOKUP, &cfg);
6bd48fcf7   Denis V. Lunev   [NETNS]: Provide ...
953
  	if (sk == NULL)
7b1a74fdb   Denis V. Lunev   [NETNS]: Refactor...
954
  		return -EAFNOSUPPORT;
6bd48fcf7   Denis V. Lunev   [NETNS]: Provide ...
955
  	net->ipv4.fibnl = sk;
7b1a74fdb   Denis V. Lunev   [NETNS]: Refactor...
956
957
958
959
960
  	return 0;
  }
  
  static void nl_fib_lookup_exit(struct net *net)
  {
b7c6ba6eb   Denis V. Lunev   [NETNS]: Consolid...
961
  	netlink_kernel_release(net->ipv4.fibnl);
775516bfa   Denis V. Lunev   [NETNS]: Namespac...
962
  	net->ipv4.fibnl = NULL;
246955fe4   Robert Olsson   [NETLINK]: fib_lo...
963
  }
4ccfe6d41   Nicolas Dichtel   ipv4/route: arg d...
964
  static void fib_disable_ip(struct net_device *dev, int force)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
965
  {
85326fa54   Denis V. Lunev   [IPV4]: fib_sync_...
966
  	if (fib_sync_down_dev(dev, force))
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
967
  		fib_flush(dev_net(dev));
4ccfe6d41   Nicolas Dichtel   ipv4/route: arg d...
968
  	rt_cache_flush(dev_net(dev));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
969
970
971
972
973
  	arp_ifdown(dev);
  }
  
  static int fib_inetaddr_event(struct notifier_block *this, unsigned long event, void *ptr)
  {
6ed2533e5   Jianjun Kong   net: clean up net...
974
  	struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
76e6ebfb4   Denis V. Lunev   netns: add namesp...
975
  	struct net_device *dev = ifa->ifa_dev->dev;
436c3b66e   David S. Miller   ipv4: Invalidate ...
976
  	struct net *net = dev_net(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
977
978
979
980
981
  
  	switch (event) {
  	case NETDEV_UP:
  		fib_add_ifaddr(ifa);
  #ifdef CONFIG_IP_ROUTE_MULTIPATH
76e6ebfb4   Denis V. Lunev   netns: add namesp...
982
  		fib_sync_up(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
983
  #endif
436c3b66e   David S. Miller   ipv4: Invalidate ...
984
  		atomic_inc(&net->ipv4.dev_addr_genid);
4ccfe6d41   Nicolas Dichtel   ipv4/route: arg d...
985
  		rt_cache_flush(dev_net(dev));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
986
987
  		break;
  	case NETDEV_DOWN:
e6abbaa27   Julian Anastasov   ipv4: fix route d...
988
  		fib_del_ifaddr(ifa, NULL);
436c3b66e   David S. Miller   ipv4: Invalidate ...
989
  		atomic_inc(&net->ipv4.dev_addr_genid);
9fcc2e8a7   Jayachandran C   [IPV4]: Fix issue...
990
  		if (ifa->ifa_dev->ifa_list == NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
991
  			/* Last address was deleted from this interface.
6a31d2a97   Eric Dumazet   fib: cleanups
992
  			 * Disable IP.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
993
  			 */
4ccfe6d41   Nicolas Dichtel   ipv4/route: arg d...
994
  			fib_disable_ip(dev, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
995
  		} else {
4ccfe6d41   Nicolas Dichtel   ipv4/route: arg d...
996
  			rt_cache_flush(dev_net(dev));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
997
998
999
1000
1001
1002
1003
1004
  		}
  		break;
  	}
  	return NOTIFY_DONE;
  }
  
  static int fib_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
  {
351638e7d   Jiri Pirko   net: pass info st...
1005
  	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
0115e8e30   Eric Dumazet   net: remove delay...
1006
  	struct in_device *in_dev;
436c3b66e   David S. Miller   ipv4: Invalidate ...
1007
  	struct net *net = dev_net(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1008
1009
  
  	if (event == NETDEV_UNREGISTER) {
4ccfe6d41   Nicolas Dichtel   ipv4/route: arg d...
1010
  		fib_disable_ip(dev, 2);
caacf05e5   David S. Miller   ipv4: Properly pu...
1011
  		rt_flush_dev(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1012
1013
  		return NOTIFY_DONE;
  	}
0115e8e30   Eric Dumazet   net: remove delay...
1014
  	in_dev = __in_dev_get_rtnl(dev);
a0065f266   Oliver Hartkopp   fib_frontend: fix...
1015
1016
  	if (!in_dev)
  		return NOTIFY_DONE;
0115e8e30   Eric Dumazet   net: remove delay...
1017

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1018
1019
1020
1021
1022
1023
1024
1025
  	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   David S. Miller   ipv4: Invalidate ...
1026
  		atomic_inc(&net->ipv4.dev_addr_genid);
4ccfe6d41   Nicolas Dichtel   ipv4/route: arg d...
1027
  		rt_cache_flush(net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1028
1029
  		break;
  	case NETDEV_DOWN:
4ccfe6d41   Nicolas Dichtel   ipv4/route: arg d...
1030
  		fib_disable_ip(dev, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1031
1032
1033
  		break;
  	case NETDEV_CHANGEMTU:
  	case NETDEV_CHANGE:
4ccfe6d41   Nicolas Dichtel   ipv4/route: arg d...
1034
  		rt_cache_flush(net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1035
1036
1037
1038
1039
1040
  		break;
  	}
  	return NOTIFY_DONE;
  }
  
  static struct notifier_block fib_inetaddr_notifier = {
6ed2533e5   Jianjun Kong   net: clean up net...
1041
  	.notifier_call = fib_inetaddr_event,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1042
1043
1044
  };
  
  static struct notifier_block fib_netdev_notifier = {
6ed2533e5   Jianjun Kong   net: clean up net...
1045
  	.notifier_call = fib_netdev_event,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1046
  };
7b1a74fdb   Denis V. Lunev   [NETNS]: Refactor...
1047
  static int __net_init ip_fib_net_init(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1048
  {
dce5cbeec   Denis V. Lunev   [IPV4]: Fix memor...
1049
  	int err;
10da66f75   Eric Dumazet   fib: avoid false ...
1050
1051
1052
1053
  	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   Patrick McHardy   [IPV4]: Increase ...
1054

10da66f75   Eric Dumazet   fib: avoid false ...
1055
  	net->ipv4.fib_table_hash = kzalloc(size, GFP_KERNEL);
e4aef8aea   Denis V. Lunev   [NETNS]: Place fi...
1056
1057
  	if (net->ipv4.fib_table_hash == NULL)
  		return -ENOMEM;
dce5cbeec   Denis V. Lunev   [IPV4]: Fix memor...
1058
1059
1060
1061
1062
1063
1064
1065
  	err = fib4_rules_init(net);
  	if (err < 0)
  		goto fail;
  	return 0;
  
  fail:
  	kfree(net->ipv4.fib_table_hash);
  	return err;
7b1a74fdb   Denis V. Lunev   [NETNS]: Refactor...
1066
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1067

2c8c1e729   Alexey Dobriyan   net: spread __net...
1068
  static void ip_fib_net_exit(struct net *net)
7b1a74fdb   Denis V. Lunev   [NETNS]: Refactor...
1069
1070
1071
1072
1073
1074
  {
  	unsigned int i;
  
  #ifdef CONFIG_IP_MULTIPLE_TABLES
  	fib4_rules_exit(net);
  #endif
e2666f849   Eric Dumazet   fib: add rtnl loc...
1075
  	rtnl_lock();
7b1a74fdb   Denis V. Lunev   [NETNS]: Refactor...
1076
1077
1078
  	for (i = 0; i < FIB_TABLE_HASHSZ; i++) {
  		struct fib_table *tb;
  		struct hlist_head *head;
b67bfe0d4   Sasha Levin   hlist: drop the n...
1079
  		struct hlist_node *tmp;
63f3444fb   Thomas Graf   [IPv4]: Use rtnl ...
1080

e4aef8aea   Denis V. Lunev   [NETNS]: Place fi...
1081
  		head = &net->ipv4.fib_table_hash[i];
b67bfe0d4   Sasha Levin   hlist: drop the n...
1082
1083
  		hlist_for_each_entry_safe(tb, tmp, head, tb_hlist) {
  			hlist_del(&tb->tb_hlist);
16c6cf8bb   Stephen Hemminger   ipv4: fib table a...
1084
  			fib_table_flush(tb);
4aa2c466a   Pavel Emelyanov   fib: Fix fib zone...
1085
  			fib_free_table(tb);
7b1a74fdb   Denis V. Lunev   [NETNS]: Refactor...
1086
1087
  		}
  	}
e2666f849   Eric Dumazet   fib: add rtnl loc...
1088
  	rtnl_unlock();
e4aef8aea   Denis V. Lunev   [NETNS]: Place fi...
1089
  	kfree(net->ipv4.fib_table_hash);
7b1a74fdb   Denis V. Lunev   [NETNS]: Refactor...
1090
1091
1092
1093
1094
  }
  
  static int __net_init fib_net_init(struct net *net)
  {
  	int error;
f4530fa57   David S. Miller   ipv4: Avoid overh...
1095
1096
1097
  #ifdef CONFIG_IP_ROUTE_CLASSID
  	net->ipv4.fib_num_tclassid_users = 0;
  #endif
7b1a74fdb   Denis V. Lunev   [NETNS]: Refactor...
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
  	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   Greg Rose   rtnetlink: Comput...
1131
1132
1133
  	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   Denis V. Lunev   [NETNS]: Refactor...
1134
1135
1136
1137
  
  	register_pernet_subsys(&fib_net_ops);
  	register_netdevice_notifier(&fib_netdev_notifier);
  	register_inetaddr_notifier(&fib_inetaddr_notifier);
7f9b80529   Stephen Hemminger   [IPV4]: fib hash|...
1138

5348ba85a   David S. Miller   ipv4: Update some...
1139
  	fib_trie_init();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1140
  }