Blame view

net/ipv4/fib_frontend.c 26.4 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
17
18
  #include <linux/module.h>
  #include <asm/uaccess.h>
  #include <asm/system.h>
  #include <linux/bitops.h>
4fc268d24   Randy Dunlap   [PATCH] capable/c...
19
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
  #include <linux/types.h>
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   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   Arnaldo Carvalho de Melo   [INET_SOCK]: Move...
29
  #include <linux/inetdevice.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
  #include <linux/netdevice.h>
1823730fb   Thomas Graf   [IPv4]: Move inte...
31
  #include <linux/if_addr.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
  #include <linux/if_arp.h>
  #include <linux/skbuff.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;
1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
84
  	h = id & (FIB_TABLE_HASHSZ - 1);
e4aef8aea   Denis V. Lunev   [NETNS]: Place fi...
85
  	hlist_add_head_rcu(&tb->tb_hlist, &net->ipv4.fib_table_hash[h]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
  	return tb;
  }
8ad4942cd   Denis V. Lunev   [NETNS]: Add netn...
88
  struct fib_table *fib_get_table(struct net *net, u32 id)
1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
89
90
91
  {
  	struct fib_table *tb;
  	struct hlist_node *node;
e4aef8aea   Denis V. Lunev   [NETNS]: Place fi...
92
  	struct hlist_head *head;
1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
93
  	unsigned int h;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94

1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
95
96
97
  	if (id == 0)
  		id = RT_TABLE_MAIN;
  	h = id & (FIB_TABLE_HASHSZ - 1);
e4aef8aea   Denis V. Lunev   [NETNS]: Place fi...
98

1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
99
  	rcu_read_lock();
e4aef8aea   Denis V. Lunev   [NETNS]: Place fi...
100
101
  	head = &net->ipv4.fib_table_hash[h];
  	hlist_for_each_entry_rcu(tb, node, head, tb_hlist) {
1af5a8c4a   Patrick McHardy   [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   Linus Torvalds   Linux-2.6.12-rc2
110
  #endif /* CONFIG_IP_MULTIPLE_TABLES */
e4aef8aea   Denis V. Lunev   [NETNS]: Place fi...
111
  static void fib_flush(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
113
  {
  	int flushed = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
  	struct fib_table *tb;
1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
115
  	struct hlist_node *node;
e4aef8aea   Denis V. Lunev   [NETNS]: Place fi...
116
  	struct hlist_head *head;
1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
117
  	unsigned int h;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118

1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
119
  	for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
e4aef8aea   Denis V. Lunev   [NETNS]: Place fi...
120
121
  		head = &net->ipv4.fib_table_hash[h];
  		hlist_for_each_entry(tb, node, head, tb_hlist)
16c6cf8bb   Stephen Hemminger   ipv4: fib table a...
122
  			flushed += fib_table_flush(tb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
125
  
  	if (flushed)
76e6ebfb4   Denis V. Lunev   netns: add namesp...
126
  		rt_cache_flush(net, -1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
  }
055381161   Laszlo Attila Toth   [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   Eric W. Biederman   [NETNS]: Add netn...
132
133
  static inline unsigned __inet_dev_addr_type(struct net *net,
  					    const struct net_device *dev,
055381161   Laszlo Attila Toth   [IPV4]: Add inet_...
134
  					    __be32 addr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
  {
9ade22861   David S. Miller   ipv4: Use flowi4 ...
136
  	struct flowi4		fl4 = { .daddr = addr };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
138
  	struct fib_result	res;
  	unsigned ret = RTN_BROADCAST;
03cf786c4   Pavel Emelyanov   [IPV4]: Explicitl...
139
  	struct fib_table *local_table;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140

1e637c74b   Jan Engelhardt   [IPV4]: Enable us...
141
  	if (ipv4_is_zeronet(addr) || ipv4_is_lbcast(addr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
  		return RTN_BROADCAST;
f97c1e0c6   Joe Perches   [IPV4] net/ipv4: ...
143
  	if (ipv4_is_multicast(addr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
146
147
148
  		return RTN_MULTICAST;
  
  #ifdef CONFIG_IP_MULTIPLE_TABLES
  	res.r = NULL;
  #endif
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
149

6b175b26c   Eric W. Biederman   [NETNS]: Add netn...
150
  	local_table = fib_get_table(net, RT_TABLE_LOCAL);
03cf786c4   Pavel Emelyanov   [IPV4]: Explicitl...
151
  	if (local_table) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
  		ret = RTN_UNICAST;
ebc0ffae5   Eric Dumazet   fib: RCU conversi...
153
  		rcu_read_lock();
9ade22861   David S. Miller   ipv4: Use flowi4 ...
154
  		if (!fib_table_lookup(local_table, &fl4, &res, FIB_LOOKUP_NOREF)) {
055381161   Laszlo Attila Toth   [IPV4]: Add inet_...
155
156
  			if (!dev || dev == res.fi->fib_dev)
  				ret = res.type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
  		}
ebc0ffae5   Eric Dumazet   fib: RCU conversi...
158
  		rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
160
161
  	}
  	return ret;
  }
6b175b26c   Eric W. Biederman   [NETNS]: Add netn...
162
  unsigned int inet_addr_type(struct net *net, __be32 addr)
055381161   Laszlo Attila Toth   [IPV4]: Add inet_...
163
  {
6b175b26c   Eric W. Biederman   [NETNS]: Add netn...
164
  	return __inet_dev_addr_type(net, NULL, addr);
055381161   Laszlo Attila Toth   [IPV4]: Add inet_...
165
  }
4bc2f18ba   Eric Dumazet   net/ipv4: EXPORT_...
166
  EXPORT_SYMBOL(inet_addr_type);
055381161   Laszlo Attila Toth   [IPV4]: Add inet_...
167

6b175b26c   Eric W. Biederman   [NETNS]: Add netn...
168
169
  unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev,
  				__be32 addr)
055381161   Laszlo Attila Toth   [IPV4]: Add inet_...
170
  {
6a31d2a97   Eric Dumazet   fib: cleanups
171
  	return __inet_dev_addr_type(net, dev, addr);
055381161   Laszlo Attila Toth   [IPV4]: Add inet_...
172
  }
4bc2f18ba   Eric Dumazet   net/ipv4: EXPORT_...
173
  EXPORT_SYMBOL(inet_dev_addr_type);
055381161   Laszlo Attila Toth   [IPV4]: Add inet_...
174

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
  /* Given (packet source, input interface) and optional (dst, oif, tos):
6a31d2a97   Eric Dumazet   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   Eric Dumazet   fib: RCU conversi...
181
   * called with rcu_read_lock()
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
   */
5c04c819a   Michael Smith   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   Linus Torvalds   Linux-2.6.12-rc2
186
187
  {
  	struct in_device *in_dev;
9ade22861   David S. Miller   ipv4: Use flowi4 ...
188
  	struct flowi4 fl4;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
  	struct fib_result res;
8153a10c0   Patrick McHardy   ipv4 05/05: add s...
190
  	int no_addr, rpf, accept_local;
6f86b3251   David S. Miller   ipv4: Fix reverse...
191
  	bool dev_match;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
  	int ret;
5b707aaae   Denis V. Lunev   [NETNS]: Pass cor...
193
  	struct net *net;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194

9ade22861   David S. Miller   ipv4: Use flowi4 ...
195
196
  	fl4.flowi4_oif = 0;
  	fl4.flowi4_iif = oif;
9ade22861   David S. Miller   ipv4: Use flowi4 ...
197
198
199
200
  	fl4.daddr = src;
  	fl4.saddr = dst;
  	fl4.flowi4_tos = tos;
  	fl4.flowi4_scope = RT_SCOPE_UNIVERSE;
cc7e17ea0   David S. Miller   ipv4: Optimize fl...
201

8153a10c0   Patrick McHardy   ipv4 05/05: add s...
202
  	no_addr = rpf = accept_local = 0;
e5ed63991   Herbert Xu   [IPV4]: Replace _...
203
  	in_dev = __in_dev_get_rcu(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
205
  	if (in_dev) {
  		no_addr = in_dev->ifa_list == NULL;
990078afb   Michael Smith   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   Patrick McHardy   ipv4 05/05: add s...
209
  		accept_local = IN_DEV_ACCEPT_LOCAL(in_dev);
5c04c819a   Michael Smith   fib_validate_sour...
210
  		fl4.flowi4_mark = IN_DEV_SRC_VMARK(in_dev) ? skb->mark : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
213
214
  
  	if (in_dev == NULL)
  		goto e_inval;
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
215
  	net = dev_net(dev);
9ade22861   David S. Miller   ipv4: Use flowi4 ...
216
  	if (fib_lookup(net, &fl4, &res))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
  		goto last_resort;
8153a10c0   Patrick McHardy   ipv4 05/05: add s...
218
219
  	if (res.type != RTN_UNICAST) {
  		if (res.type != RTN_LOCAL || !accept_local)
ebc0ffae5   Eric Dumazet   fib: RCU conversi...
220
  			goto e_inval;
8153a10c0   Patrick McHardy   ipv4 05/05: add s...
221
  	}
436c3b66e   David S. Miller   ipv4: Invalidate ...
222
  	*spec_dst = FIB_RES_PREFSRC(net, res);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
  	fib_combine_itag(itag, &res);
6f86b3251   David S. Miller   ipv4: Fix reverse...
224
  	dev_match = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
  #ifdef CONFIG_IP_ROUTE_MULTIPATH
6f86b3251   David S. Miller   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   Linus Torvalds   Linux-2.6.12-rc2
234
235
  #else
  	if (FIB_RES_DEV(res) == dev)
6f86b3251   David S. Miller   ipv4: Fix reverse...
236
  		dev_match = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
  #endif
6f86b3251   David S. Miller   ipv4: Fix reverse...
238
  	if (dev_match) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
  		ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
241
  		return ret;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
243
  	if (no_addr)
  		goto last_resort;
c1cf8422f   Stephen Hemminger   ip: add loose rev...
244
  	if (rpf == 1)
b5f7e7554   Eric Dumazet   ipv4: add LINUX_M...
245
  		goto e_rpf;
9ade22861   David S. Miller   ipv4: Use flowi4 ...
246
  	fl4.flowi4_oif = dev->ifindex;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
248
  
  	ret = 0;
9ade22861   David S. Miller   ipv4: Use flowi4 ...
249
  	if (fib_lookup(net, &fl4, &res) == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
  		if (res.type == RTN_UNICAST) {
436c3b66e   David S. Miller   ipv4: Invalidate ...
251
  			*spec_dst = FIB_RES_PREFSRC(net, res);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
253
  			ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
255
256
257
258
  	}
  	return ret;
  
  last_resort:
  	if (rpf)
b5f7e7554   Eric Dumazet   ipv4: add LINUX_M...
259
  		goto e_rpf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
261
262
  	*spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE);
  	*itag = 0;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
264
  e_inval:
  	return -EINVAL;
b5f7e7554   Eric Dumazet   ipv4: add LINUX_M...
265
266
  e_rpf:
  	return -EXDEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267
  }
81f7bf6cb   Al Viro   [IPV4]: net/ipv4/...
268
  static inline __be32 sk_extract_addr(struct sockaddr *addr)
4e902c574   Thomas Graf   [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   Denis V. Lunev   [NETNS]: Correctl...
284
  static int rtentry_to_fib_config(struct net *net, int cmd, struct rtentry *rt,
4e902c574   Thomas Graf   [IPv4]: FIB confi...
285
286
  				 struct fib_config *cfg)
  {
6d85c10ab   Al Viro   [IPV4]: struct fi...
287
  	__be32 addr;
4e902c574   Thomas Graf   [IPv4]: FIB confi...
288
289
290
  	int plen;
  
  	memset(cfg, 0, sizeof(*cfg));
4b5d47d4d   Denis V. Lunev   [NETNS]: Correctl...
291
  	cfg->fc_nlinfo.nl_net = net;
4e902c574   Thomas Graf   [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   Al Viro   [IPV4]: net/ipv4/...
307
  		__be32 mask = sk_extract_addr(&rt->rt_genmask);
4e902c574   Thomas Graf   [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   Denis V. Lunev   [NETNS]: Correctl...
352
  		dev = __dev_get_by_name(net, devname);
4e902c574   Thomas Graf   [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   Denis V. Lunev   [NETNS]: Correctl...
375
  		    inet_addr_type(net, addr) == RTN_UNICAST)
4e902c574   Thomas Graf   [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   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
393
  		if (mx == NULL)
4e902c574   Thomas Graf   [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   Linus Torvalds   Linux-2.6.12-rc2
411
  /*
6a31d2a97   Eric Dumazet   fib: cleanups
412
413
   * Handle IP routing ioctl calls.
   * These are used to manipulate the routing tables
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
   */
1bad118a3   Denis V. Lunev   [NETNS]: Pass nam...
415
  int ip_rt_ioctl(struct net *net, unsigned int cmd, void __user *arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416
  {
4e902c574   Thomas Graf   [IPv4]: FIB confi...
417
418
  	struct fib_config cfg;
  	struct rtentry rt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419
  	int err;
1da177e4c   Linus Torvalds   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   Thomas Graf   [IPv4]: FIB confi...
426
427
  
  		if (copy_from_user(&rt, arg, sizeof(rt)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
  			return -EFAULT;
4e902c574   Thomas Graf   [IPv4]: FIB confi...
429

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
  		rtnl_lock();
1bad118a3   Denis V. Lunev   [NETNS]: Pass nam...
431
  		err = rtentry_to_fib_config(net, cmd, &rt, &cfg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
432
  		if (err == 0) {
4e902c574   Thomas Graf   [IPv4]: FIB confi...
433
  			struct fib_table *tb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
434
  			if (cmd == SIOCDELRT) {
1bad118a3   Denis V. Lunev   [NETNS]: Pass nam...
435
  				tb = fib_get_table(net, cfg.fc_table);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
436
  				if (tb)
16c6cf8bb   Stephen Hemminger   ipv4: fib table a...
437
  					err = fib_table_delete(tb, &cfg);
4e902c574   Thomas Graf   [IPv4]: FIB confi...
438
439
  				else
  					err = -ESRCH;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440
  			} else {
1bad118a3   Denis V. Lunev   [NETNS]: Pass nam...
441
  				tb = fib_new_table(net, cfg.fc_table);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
  				if (tb)
16c6cf8bb   Stephen Hemminger   ipv4: fib table a...
443
  					err = fib_table_insert(tb, &cfg);
4e902c574   Thomas Graf   [IPv4]: FIB confi...
444
445
  				else
  					err = -ENOBUFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
  			}
4e902c574   Thomas Graf   [IPv4]: FIB confi...
447
448
449
  
  			/* allocated by rtentry_to_fib_config() */
  			kfree(cfg.fc_mx);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
450
451
452
453
454
455
  		}
  		rtnl_unlock();
  		return err;
  	}
  	return -EINVAL;
  }
6a31d2a97   Eric Dumazet   fib: cleanups
456
  const struct nla_policy rtm_ipv4_policy[RTA_MAX + 1] = {
4e902c574   Thomas Graf   [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   Thomas Graf   [NETLINK]: Make u...
465
  	[RTA_MULTIPATH]		= { .len = sizeof(struct rtnexthop) },
4e902c574   Thomas Graf   [IPv4]: FIB confi...
466
  	[RTA_FLOW]		= { .type = NLA_U32 },
4e902c574   Thomas Graf   [IPv4]: FIB confi...
467
  };
4b5d47d4d   Denis V. Lunev   [NETNS]: Correctl...
468
  static int rtm_to_fib_config(struct net *net, struct sk_buff *skb,
6a31d2a97   Eric Dumazet   fib: cleanups
469
  			     struct nlmsghdr *nlh, struct fib_config *cfg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
  {
4e902c574   Thomas Graf   [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   Thomas Graf   [IPv4]: FIB confi...
482
  	cfg->fc_dst_len = rtm->rtm_dst_len;
4e902c574   Thomas Graf   [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   Denis V. Lunev   [NETNS]: Correctl...
493
  	cfg->fc_nlinfo.nl_net = net;
4e902c574   Thomas Graf   [IPv4]: FIB confi...
494

a0ee18b9b   Thomas Graf   [IPv4] fib: Fix o...
495
496
497
498
  	if (cfg->fc_type > RTN_MAX) {
  		err = -EINVAL;
  		goto errout;
  	}
4e902c574   Thomas Graf   [IPv4]: FIB confi...
499
  	nlmsg_for_each_attr(attr, nlh, sizeof(struct rtmsg), remaining) {
8f4c1f9b0   Thomas Graf   [NETLINK]: Introd...
500
  		switch (nla_type(attr)) {
4e902c574   Thomas Graf   [IPv4]: FIB confi...
501
  		case RTA_DST:
17fb2c643   Al Viro   [IPV4]: RTA_{DST,...
502
  			cfg->fc_dst = nla_get_be32(attr);
4e902c574   Thomas Graf   [IPv4]: FIB confi...
503
  			break;
4e902c574   Thomas Graf   [IPv4]: FIB confi...
504
505
506
507
  		case RTA_OIF:
  			cfg->fc_oif = nla_get_u32(attr);
  			break;
  		case RTA_GATEWAY:
17fb2c643   Al Viro   [IPV4]: RTA_{DST,...
508
  			cfg->fc_gw = nla_get_be32(attr);
4e902c574   Thomas Graf   [IPv4]: FIB confi...
509
510
511
512
513
  			break;
  		case RTA_PRIORITY:
  			cfg->fc_priority = nla_get_u32(attr);
  			break;
  		case RTA_PREFSRC:
17fb2c643   Al Viro   [IPV4]: RTA_{DST,...
514
  			cfg->fc_prefsrc = nla_get_be32(attr);
4e902c574   Thomas Graf   [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   Thomas Graf   [IPv4]: FIB confi...
527
528
529
  		case RTA_TABLE:
  			cfg->fc_table = nla_get_u32(attr);
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
531
  		}
  	}
4e902c574   Thomas Graf   [IPv4]: FIB confi...
532

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
  	return 0;
4e902c574   Thomas Graf   [IPv4]: FIB confi...
534
535
  errout:
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536
  }
6ed2533e5   Jianjun Kong   net: clean up net...
537
  static int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
538
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
539
  	struct net *net = sock_net(skb->sk);
4e902c574   Thomas Graf   [IPv4]: FIB confi...
540
541
542
  	struct fib_config cfg;
  	struct fib_table *tb;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
543

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

8ad4942cd   Denis V. Lunev   [NETNS]: Add netn...
548
  	tb = fib_get_table(net, cfg.fc_table);
4e902c574   Thomas Graf   [IPv4]: FIB confi...
549
550
551
552
  	if (tb == NULL) {
  		err = -ESRCH;
  		goto errout;
  	}
16c6cf8bb   Stephen Hemminger   ipv4: fib table a...
553
  	err = fib_table_delete(tb, &cfg);
4e902c574   Thomas Graf   [IPv4]: FIB confi...
554
555
  errout:
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556
  }
6ed2533e5   Jianjun Kong   net: clean up net...
557
  static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
559
  	struct net *net = sock_net(skb->sk);
4e902c574   Thomas Graf   [IPv4]: FIB confi...
560
561
562
  	struct fib_config cfg;
  	struct fib_table *tb;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563

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

226b0b4a5   Denis V. Lunev   [NETNS]: Replace ...
568
  	tb = fib_new_table(net, cfg.fc_table);
4e902c574   Thomas Graf   [IPv4]: FIB confi...
569
570
571
572
  	if (tb == NULL) {
  		err = -ENOBUFS;
  		goto errout;
  	}
16c6cf8bb   Stephen Hemminger   ipv4: fib table a...
573
  	err = fib_table_insert(tb, &cfg);
4e902c574   Thomas Graf   [IPv4]: FIB confi...
574
575
  errout:
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576
  }
63f3444fb   Thomas Graf   [IPv4]: Use rtnl ...
577
  static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
579
  	struct net *net = sock_net(skb->sk);
1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
580
581
  	unsigned int h, s_h;
  	unsigned int e = 0, s_e;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
  	struct fib_table *tb;
1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
583
  	struct hlist_node *node;
e4aef8aea   Denis V. Lunev   [NETNS]: Place fi...
584
  	struct hlist_head *head;
1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
585
  	int dumped = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586

be403ea18   Thomas Graf   [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   Linus Torvalds   Linux-2.6.12-rc2
589
  		return ip_rt_dump(skb, cb);
1af5a8c4a   Patrick McHardy   [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   Denis V. Lunev   [NETNS]: Place fi...
595
596
  		head = &net->ipv4.fib_table_hash[h];
  		hlist_for_each_entry(tb, node, head, tb_hlist) {
1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
597
598
599
600
  			if (e < s_e)
  				goto next;
  			if (dumped)
  				memset(&cb->args[2], 0, sizeof(cb->args) -
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
601
  						 2 * sizeof(cb->args[0]));
16c6cf8bb   Stephen Hemminger   ipv4: fib table a...
602
  			if (fib_table_dump(tb, skb, cb) < 0)
1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
603
604
605
606
607
  				goto out;
  			dumped = 1;
  next:
  			e++;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
608
  	}
1af5a8c4a   Patrick McHardy   [IPV4]: Increase ...
609
610
611
  out:
  	cb->args[1] = e;
  	cb->args[0] = h;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
612
613
614
615
616
  
  	return skb->len;
  }
  
  /* Prepare and feed intra-kernel routing request.
6a31d2a97   Eric Dumazet   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   Linus Torvalds   Linux-2.6.12-rc2
621
   */
81f7bf6cb   Al Viro   [IPV4]: net/ipv4/...
622
  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
623
  {
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
624
  	struct net *net = dev_net(ifa->ifa_dev->dev);
4e902c574   Thomas Graf   [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   Denis V. Lunev   [NETNS]: Add netn...
634
  		.fc_nlinfo = {
4b5d47d4d   Denis V. Lunev   [NETNS]: Correctl...
635
  			.nl_net = net,
4d1169c1e   Denis V. Lunev   [NETNS]: Add netn...
636
  		},
4e902c574   Thomas Graf   [IPv4]: FIB confi...
637
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
638
639
  
  	if (type == RTN_UNICAST)
4b5d47d4d   Denis V. Lunev   [NETNS]: Correctl...
640
  		tb = fib_new_table(net, RT_TABLE_MAIN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641
  	else
4b5d47d4d   Denis V. Lunev   [NETNS]: Correctl...
642
  		tb = fib_new_table(net, RT_TABLE_LOCAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
643
644
645
  
  	if (tb == NULL)
  		return;
4e902c574   Thomas Graf   [IPv4]: FIB confi...
646
  	cfg.fc_table = tb->tb_id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647

4e902c574   Thomas Graf   [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   Linus Torvalds   Linux-2.6.12-rc2
652
653
  
  	if (cmd == RTM_NEWROUTE)
16c6cf8bb   Stephen Hemminger   ipv4: fib table a...
654
  		fib_table_insert(tb, &cfg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
655
  	else
16c6cf8bb   Stephen Hemminger   ipv4: fib table a...
656
  		fib_table_delete(tb, &cfg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
657
  }
0ff60a456   Jamal Hadi Salim   [IPV4]: Fix secon...
658
  void fib_add_ifaddr(struct in_ifaddr *ifa)
1da177e4c   Linus Torvalds   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   Al Viro   [IPV4]: annotate ...
663
664
  	__be32 mask = ifa->ifa_mask;
  	__be32 addr = ifa->ifa_local;
6a31d2a97   Eric Dumazet   fib: cleanups
665
  	__be32 prefix = ifa->ifa_address & mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
666

6a31d2a97   Eric Dumazet   fib: cleanups
667
  	if (ifa->ifa_flags & IFA_F_SECONDARY) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
669
  		prim = inet_ifa_byprefix(in_dev, prefix, mask);
  		if (prim == NULL) {
a6db90109   Stephen Hemminger   [IPV4] FIB: print...
670
671
  			printk(KERN_WARNING "fib_add_ifaddr: bug: prim == NULL
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
672
673
674
675
676
  			return;
  		}
  	}
  
  	fib_magic(RTM_NEWROUTE, RTN_LOCAL, addr, 32, prim);
6a31d2a97   Eric Dumazet   fib: cleanups
677
  	if (!(dev->flags & IFF_UP))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
678
679
680
  		return;
  
  	/* Add broadcast address, if it is explicitly assigned. */
a144ea4b7   Al Viro   [IPV4]: annotate ...
681
  	if (ifa->ifa_broadcast && ifa->ifa_broadcast != htonl(0xFFFFFFFF))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
682
  		fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
6a31d2a97   Eric Dumazet   fib: cleanups
683
  	if (!ipv4_is_zeronet(prefix) && !(ifa->ifa_flags & IFA_F_SECONDARY) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
684
  	    (prefix != addr || ifa->ifa_prefixlen < 32)) {
6a31d2a97   Eric Dumazet   fib: cleanups
685
686
687
  		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
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   Eric Dumazet   fib: cleanups
692
693
  			fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix | ~mask,
  				  32, prim);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
694
695
696
  		}
  	}
  }
e6abbaa27   Julian Anastasov   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   Linus Torvalds   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   Julian Anastasov   ipv4: fix route d...
707
  	struct in_ifaddr *prim = ifa, *prim1 = NULL;
6a31d2a97   Eric Dumazet   fib: cleanups
708
709
  	__be32 brd = ifa->ifa_address | ~ifa->ifa_mask;
  	__be32 any = ifa->ifa_address & ifa->ifa_mask;
1da177e4c   Linus Torvalds   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   Julian Anastasov   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   Linus Torvalds   Linux-2.6.12-rc2
718

e6abbaa27   Julian Anastasov   ipv4: fix route d...
719
  	if (ifa->ifa_flags & IFA_F_SECONDARY) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
720
721
  		prim = inet_ifa_byprefix(in_dev, any, ifa->ifa_mask);
  		if (prim == NULL) {
a6db90109   Stephen Hemminger   [IPV4] FIB: print...
722
723
  			printk(KERN_WARNING "fib_del_ifaddr: bug: prim == NULL
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
724
725
  			return;
  		}
e6abbaa27   Julian Anastasov   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   Linus Torvalds   Linux-2.6.12-rc2
737
738
739
  	}
  
  	/* Deletion is more complicated than add.
6a31d2a97   Eric Dumazet   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   Linus Torvalds   Linux-2.6.12-rc2
743
744
745
  	 */
  
  	for (ifa1 = in_dev->ifa_list; ifa1; ifa1 = ifa1->ifa_next) {
e6abbaa27   Julian Anastasov   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   Linus Torvalds   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   Julian Anastasov   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   Linus Torvalds   Linux-2.6.12-rc2
812
  	}
6a31d2a97   Eric Dumazet   fib: cleanups
813
  	if (!(ok & BRD_OK))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814
  		fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
e6abbaa27   Julian Anastasov   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   Eric Dumazet   fib: cleanups
821
  	if (!(ok & LOCAL_OK)) {
1da177e4c   Linus Torvalds   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   Julian Anastasov   ipv4: fix route d...
825
826
  		if (gone &&
  		    inet_addr_type(dev_net(dev), ifa->ifa_local) != RTN_LOCAL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
  			/* And the last, but not the least thing.
6a31d2a97   Eric Dumazet   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   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
833
834
  			if (fib_sync_down_addr(dev_net(dev), ifa->ifa_local))
  				fib_flush(dev_net(dev));
1da177e4c   Linus Torvalds   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   Eric Dumazet   fib: cleanups
842
  static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb)
246955fe4   Robert Olsson   [NETLINK]: fib_lo...
843
  {
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
844

246955fe4   Robert Olsson   [NETLINK]: fib_lo...
845
  	struct fib_result       res;
9ade22861   David S. Miller   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   Eric Dumazet   fib: cleanups
851
  	};
1194ed0a3   Alexey Kuznetsov   [NETLINK]: Infini...
852

912a41a4a   Sergey Vlasov   [IPV4] nl_fib_loo...
853
854
855
  #ifdef CONFIG_IP_MULTIPLE_TABLES
  	res.r = NULL;
  #endif
1194ed0a3   Alexey Kuznetsov   [NETLINK]: Infini...
856
  	frn->err = -ENOENT;
246955fe4   Robert Olsson   [NETLINK]: fib_lo...
857
858
859
860
  	if (tb) {
  		local_bh_disable();
  
  		frn->tb_id = tb->tb_id;
ebc0ffae5   Eric Dumazet   fib: RCU conversi...
861
  		rcu_read_lock();
9ade22861   David S. Miller   ipv4: Use flowi4 ...
862
  		frn->err = fib_table_lookup(tb, &fl4, &res, FIB_LOOKUP_NOREF);
246955fe4   Robert Olsson   [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   Eric Dumazet   fib: RCU conversi...
870
  		rcu_read_unlock();
246955fe4   Robert Olsson   [NETLINK]: fib_lo...
871
872
873
  		local_bh_enable();
  	}
  }
28f7b0360   David S. Miller   [NETLINK]: fib_fr...
874
  static void nl_fib_input(struct sk_buff *skb)
246955fe4   Robert Olsson   [NETLINK]: fib_lo...
875
  {
6bd48fcf7   Denis V. Lunev   [NETNS]: Provide ...
876
  	struct net *net;
246955fe4   Robert Olsson   [NETLINK]: fib_lo...
877
  	struct fib_result_nl *frn;
28f7b0360   David S. Miller   [NETLINK]: fib_fr...
878
  	struct nlmsghdr *nlh;
246955fe4   Robert Olsson   [NETLINK]: fib_lo...
879
  	struct fib_table *tb;
28f7b0360   David S. Miller   [NETLINK]: fib_fr...
880
  	u32 pid;
1194ed0a3   Alexey Kuznetsov   [NETLINK]: Infini...
881

3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
882
  	net = sock_net(skb->sk);
b529ccf27   Arnaldo Carvalho de Melo   [NETLINK]: Introd...
883
  	nlh = nlmsg_hdr(skb);
ea86575ea   Thomas Graf   [NETLINK]: Fix pr...
884
  	if (skb->len < NLMSG_SPACE(0) || skb->len < nlh->nlmsg_len ||
d883a0367   Denis V. Lunev   [IPV4]: OOPS with...
885
  	    nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*frn)))
ea86575ea   Thomas Graf   [NETLINK]: Fix pr...
886
  		return;
d883a0367   Denis V. Lunev   [IPV4]: OOPS with...
887
888
889
890
891
  
  	skb = skb_clone(skb, GFP_KERNEL);
  	if (skb == NULL)
  		return;
  	nlh = nlmsg_hdr(skb);
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
892

246955fe4   Robert Olsson   [NETLINK]: fib_lo...
893
  	frn = (struct fib_result_nl *) NLMSG_DATA(nlh);
6bd48fcf7   Denis V. Lunev   [NETNS]: Provide ...
894
  	tb = fib_get_table(net, frn->tb_id_in);
246955fe4   Robert Olsson   [NETLINK]: fib_lo...
895
896
  
  	nl_fib_lookup(frn, tb);
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
897

6a31d2a97   Eric Dumazet   fib: cleanups
898
899
  	pid = NETLINK_CB(skb).pid;      /* pid of sending process */
  	NETLINK_CB(skb).pid = 0;        /* from kernel */
ac6d439d2   Patrick McHardy   [NETLINK]: Conver...
900
  	NETLINK_CB(skb).dst_group = 0;  /* unicast */
6bd48fcf7   Denis V. Lunev   [NETNS]: Provide ...
901
  	netlink_unicast(net->ipv4.fibnl, skb, pid, MSG_DONTWAIT);
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
902
  }
246955fe4   Robert Olsson   [NETLINK]: fib_lo...
903

2c8c1e729   Alexey Dobriyan   net: spread __net...
904
  static int __net_init nl_fib_lookup_init(struct net *net)
246955fe4   Robert Olsson   [NETLINK]: fib_lo...
905
  {
6bd48fcf7   Denis V. Lunev   [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   Denis V. Lunev   [NETNS]: Refactor...
910
  		return -EAFNOSUPPORT;
6bd48fcf7   Denis V. Lunev   [NETNS]: Provide ...
911
  	net->ipv4.fibnl = sk;
7b1a74fdb   Denis V. Lunev   [NETNS]: Refactor...
912
913
914
915
916
  	return 0;
  }
  
  static void nl_fib_lookup_exit(struct net *net)
  {
b7c6ba6eb   Denis V. Lunev   [NETNS]: Consolid...
917
  	netlink_kernel_release(net->ipv4.fibnl);
775516bfa   Denis V. Lunev   [NETNS]: Namespac...
918
  	net->ipv4.fibnl = NULL;
246955fe4   Robert Olsson   [NETLINK]: fib_lo...
919
  }
e2ce14684   Octavian Purdila   ipv4: factorize c...
920
  static void fib_disable_ip(struct net_device *dev, int force, int delay)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
921
  {
85326fa54   Denis V. Lunev   [IPV4]: fib_sync_...
922
  	if (fib_sync_down_dev(dev, force))
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
923
  		fib_flush(dev_net(dev));
e2ce14684   Octavian Purdila   ipv4: factorize c...
924
  	rt_cache_flush(dev_net(dev), delay);
1da177e4c   Linus Torvalds   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   Jianjun Kong   net: clean up net...
930
  	struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
76e6ebfb4   Denis V. Lunev   netns: add namesp...
931
  	struct net_device *dev = ifa->ifa_dev->dev;
436c3b66e   David S. Miller   ipv4: Invalidate ...
932
  	struct net *net = dev_net(dev);
1da177e4c   Linus Torvalds   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   Denis V. Lunev   netns: add namesp...
938
  		fib_sync_up(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939
  #endif
436c3b66e   David S. Miller   ipv4: Invalidate ...
940
  		atomic_inc(&net->ipv4.dev_addr_genid);
76e6ebfb4   Denis V. Lunev   netns: add namesp...
941
  		rt_cache_flush(dev_net(dev), -1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
942
943
  		break;
  	case NETDEV_DOWN:
e6abbaa27   Julian Anastasov   ipv4: fix route d...
944
  		fib_del_ifaddr(ifa, NULL);
436c3b66e   David S. Miller   ipv4: Invalidate ...
945
  		atomic_inc(&net->ipv4.dev_addr_genid);
9fcc2e8a7   Jayachandran C   [IPV4]: Fix issue...
946
  		if (ifa->ifa_dev->ifa_list == NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
947
  			/* Last address was deleted from this interface.
6a31d2a97   Eric Dumazet   fib: cleanups
948
  			 * Disable IP.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
949
  			 */
e2ce14684   Octavian Purdila   ipv4: factorize c...
950
  			fib_disable_ip(dev, 1, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
951
  		} else {
76e6ebfb4   Denis V. Lunev   netns: add namesp...
952
  			rt_cache_flush(dev_net(dev), -1);
1da177e4c   Linus Torvalds   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   Herbert Xu   [IPV4]: Replace _...
962
  	struct in_device *in_dev = __in_dev_get_rtnl(dev);
436c3b66e   David S. Miller   ipv4: Invalidate ...
963
  	struct net *net = dev_net(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
964
965
  
  	if (event == NETDEV_UNREGISTER) {
e2ce14684   Octavian Purdila   ipv4: factorize c...
966
  		fib_disable_ip(dev, 2, -1);
1da177e4c   Linus Torvalds   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   David S. Miller   ipv4: Invalidate ...
981
  		atomic_inc(&net->ipv4.dev_addr_genid);
76e6ebfb4   Denis V. Lunev   netns: add namesp...
982
  		rt_cache_flush(dev_net(dev), -1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
983
984
  		break;
  	case NETDEV_DOWN:
e2ce14684   Octavian Purdila   ipv4: factorize c...
985
  		fib_disable_ip(dev, 0, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
986
987
988
  		break;
  	case NETDEV_CHANGEMTU:
  	case NETDEV_CHANGE:
76e6ebfb4   Denis V. Lunev   netns: add namesp...
989
  		rt_cache_flush(dev_net(dev), 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
990
  		break;
a5ee15513   Eric W. Biederman   net: NETDEV_UNREG...
991
  	case NETDEV_UNREGISTER_BATCH:
6561a3b12   David S. Miller   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   Eric W. Biederman   net: NETDEV_UNREG...
997
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
998
999
1000
1001
1002
  	}
  	return NOTIFY_DONE;
  }
  
  static struct notifier_block fib_inetaddr_notifier = {
6ed2533e5   Jianjun Kong   net: clean up net...
1003
  	.notifier_call = fib_inetaddr_event,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1004
1005
1006
  };
  
  static struct notifier_block fib_netdev_notifier = {
6ed2533e5   Jianjun Kong   net: clean up net...
1007
  	.notifier_call = fib_netdev_event,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1008
  };
7b1a74fdb   Denis V. Lunev   [NETNS]: Refactor...
1009
  static int __net_init ip_fib_net_init(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1010
  {
dce5cbeec   Denis V. Lunev   [IPV4]: Fix memor...
1011
  	int err;
10da66f75   Eric Dumazet   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   Patrick McHardy   [IPV4]: Increase ...
1016

10da66f75   Eric Dumazet   fib: avoid false ...
1017
  	net->ipv4.fib_table_hash = kzalloc(size, GFP_KERNEL);
e4aef8aea   Denis V. Lunev   [NETNS]: Place fi...
1018
1019
  	if (net->ipv4.fib_table_hash == NULL)
  		return -ENOMEM;
dce5cbeec   Denis V. Lunev   [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   Denis V. Lunev   [NETNS]: Refactor...
1028
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1029

2c8c1e729   Alexey Dobriyan   net: spread __net...
1030
  static void ip_fib_net_exit(struct net *net)
7b1a74fdb   Denis V. Lunev   [NETNS]: Refactor...
1031
1032
1033
1034
1035
1036
  {
  	unsigned int i;
  
  #ifdef CONFIG_IP_MULTIPLE_TABLES
  	fib4_rules_exit(net);
  #endif
e2666f849   Eric Dumazet   fib: add rtnl loc...
1037
  	rtnl_lock();
7b1a74fdb   Denis V. Lunev   [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   Thomas Graf   [IPv4]: Use rtnl ...
1042

e4aef8aea   Denis V. Lunev   [NETNS]: Place fi...
1043
  		head = &net->ipv4.fib_table_hash[i];
7b1a74fdb   Denis V. Lunev   [NETNS]: Refactor...
1044
1045
  		hlist_for_each_entry_safe(tb, node, tmp, head, tb_hlist) {
  			hlist_del(node);
16c6cf8bb   Stephen Hemminger   ipv4: fib table a...
1046
  			fib_table_flush(tb);
4aa2c466a   Pavel Emelyanov   fib: Fix fib zone...
1047
  			fib_free_table(tb);
7b1a74fdb   Denis V. Lunev   [NETNS]: Refactor...
1048
1049
  		}
  	}
e2666f849   Eric Dumazet   fib: add rtnl loc...
1050
  	rtnl_unlock();
e4aef8aea   Denis V. Lunev   [NETNS]: Place fi...
1051
  	kfree(net->ipv4.fib_table_hash);
7b1a74fdb   Denis V. Lunev   [NETNS]: Refactor...
1052
1053
1054
1055
1056
  }
  
  static int __net_init fib_net_init(struct net *net)
  {
  	int error;
7b1a74fdb   Denis V. Lunev   [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   Greg Rose   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   Denis V. Lunev   [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   Stephen Hemminger   [IPV4]: fib hash|...
1097

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