Blame view

net/ipv4/fib_rules.c 6.57 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: policy rules.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
   * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
9
   * 		Thomas Graf <tgraf@suug.ch>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
12
13
14
15
16
17
18
19
   *
   *		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.
   *
   * Fixes:
   * 		Rani Assaf	:	local_rule cannot be deleted
   *		Marc Boucher	:	routing by fwmark
   */
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
  #include <linux/netdevice.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
  #include <linux/netlink.h>
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
24
  #include <linux/inetdevice.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
  #include <linux/init.h>
7b204afd4   Robert Olsson   [IPV4]: Use RCU l...
26
27
  #include <linux/list.h>
  #include <linux/rcupdate.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
  #include <net/ip.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
  #include <net/route.h>
  #include <net/tcp.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
  #include <net/ip_fib.h>
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
32
  #include <net/fib_rules.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33

e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
34
  struct fib4_rule
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
  {
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
36
37
38
39
  	struct fib_rule		common;
  	u8			dst_len;
  	u8			src_len;
  	u8			tos;
81f7bf6cb   Al Viro   [IPV4]: net/ipv4/...
40
41
42
43
  	__be32			src;
  	__be32			srcmask;
  	__be32			dst;
  	__be32			dstmask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
  #ifdef CONFIG_NET_CLS_ROUTE
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
45
  	u32			tclassid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
  };
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
48
49
50
51
52
53
  #ifdef CONFIG_NET_CLS_ROUTE
  u32 fib_rules_tclass(struct fib_result *res)
  {
  	return res->r ? ((struct fib4_rule *) res->r)->tclassid : 0;
  }
  #endif
7b204afd4   Robert Olsson   [IPV4]: Use RCU l...
54

da0e28cb6   Denis V. Lunev   [NETNS]: Add netn...
55
  int fib_lookup(struct net *net, struct flowi *flp, struct fib_result *res)
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
56
57
58
59
60
  {
  	struct fib_lookup_arg arg = {
  		.result = res,
  	};
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61

da0e28cb6   Denis V. Lunev   [NETNS]: Add netn...
62
  	err = fib_rules_lookup(net->ipv4.rules_ops, flp, 0, &arg);
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
63
  	res->r = arg.rule;
a5cdc0300   Patrick McHardy   [IPV4]: Add fib r...
64

e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
65
66
  	return err;
  }
8ce11e6a9   Adrian Bunk   [NET]: Make code ...
67
68
  static int fib4_rule_action(struct fib_rule *rule, struct flowi *flp,
  			    int flags, struct fib_lookup_arg *arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
  {
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
  	int err = -EAGAIN;
  	struct fib_table *tbl;
  
  	switch (rule->action) {
  	case FR_ACT_TO_TBL:
  		break;
  
  	case FR_ACT_UNREACHABLE:
  		err = -ENETUNREACH;
  		goto errout;
  
  	case FR_ACT_PROHIBIT:
  		err = -EACCES;
  		goto errout;
  
  	case FR_ACT_BLACKHOLE:
  	default:
  		err = -EINVAL;
  		goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
  	}
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
90

51314a17b   Denis V. Lunev   [NETNS]: Process ...
91
  	if ((tbl = fib_get_table(rule->fr_net, rule->table)) == NULL)
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
92
  		goto errout;
16c6cf8bb   Stephen Hemminger   ipv4: fib table a...
93
  	err = fib_table_lookup(tbl, flp, (struct fib_result *) arg->result);
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
94
95
96
  	if (err > 0)
  		err = -EAGAIN;
  errout:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
98
  	return err;
  }
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
99

e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
100
101
102
  static int fib4_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
  {
  	struct fib4_rule *r = (struct fib4_rule *) rule;
81f7bf6cb   Al Viro   [IPV4]: net/ipv4/...
103
104
  	__be32 daddr = fl->fl4_dst;
  	__be32 saddr = fl->fl4_src;
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
105
106
107
108
109
110
111
  
  	if (((saddr ^ r->src) & r->srcmask) ||
  	    ((daddr ^ r->dst) & r->dstmask))
  		return 0;
  
  	if (r->tos && (r->tos != fl->fl4_tos))
  		return 0;
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
112
113
  	return 1;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114

8ad4942cd   Denis V. Lunev   [NETNS]: Add netn...
115
  static struct fib_table *fib_empty_table(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
  {
2dfe55b47   Patrick McHardy   [NET]: Use u32 fo...
117
  	u32 id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
119
  
  	for (id = 1; id <= RT_TABLE_MAX; id++)
8ad4942cd   Denis V. Lunev   [NETNS]: Add netn...
120
121
  		if (fib_get_table(net, id) == NULL)
  			return fib_new_table(net, id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
123
  	return NULL;
  }
ef7c79ed6   Patrick McHardy   [NETLINK]: Mark n...
124
  static const struct nla_policy fib4_rule_policy[FRA_MAX+1] = {
1f6c9557e   Thomas Graf   [NET] rules: Shar...
125
  	FRA_GENERIC_POLICY,
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
126
127
  	[FRA_FLOW]	= { .type = NLA_U32 },
  };
7b204afd4   Robert Olsson   [IPV4]: Use RCU l...
128

e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
129
  static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
8b3521eeb   Rami Rosen   ipv4: remove an u...
130
  			       struct fib_rule_hdr *frh,
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
131
  			       struct nlattr **tb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
133
  	struct net *net = sock_net(skb->sk);
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
134
135
  	int err = -EINVAL;
  	struct fib4_rule *rule4 = (struct fib4_rule *) rule;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136

e1701c68c   Thomas Graf   [NET]: Fix fib_ru...
137
  	if (frh->tos & ~IPTOS_TOS_MASK)
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
138
  		goto errout;
7b204afd4   Robert Olsson   [IPV4]: Use RCU l...
139

e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
140
141
142
  	if (rule->table == RT_TABLE_UNSPEC) {
  		if (rule->action == FR_ACT_TO_TBL) {
  			struct fib_table *table;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143

e4e4971c5   Denis V. Lunev   [NETNS]: Namespac...
144
  			table = fib_empty_table(net);
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
145
146
147
148
  			if (table == NULL) {
  				err = -ENOBUFS;
  				goto errout;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149

e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
150
  			rule->table = table->tb_id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
  		}
  	}
e1701c68c   Thomas Graf   [NET]: Fix fib_ru...
153
  	if (frh->src_len)
45d60b9e2   Al Viro   [IPV4]: FRA_{DST,...
154
  		rule4->src = nla_get_be32(tb[FRA_SRC]);
7b204afd4   Robert Olsson   [IPV4]: Use RCU l...
155

e1701c68c   Thomas Graf   [NET]: Fix fib_ru...
156
  	if (frh->dst_len)
45d60b9e2   Al Viro   [IPV4]: FRA_{DST,...
157
  		rule4->dst = nla_get_be32(tb[FRA_DST]);
7b204afd4   Robert Olsson   [IPV4]: Use RCU l...
158

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
  #ifdef CONFIG_NET_CLS_ROUTE
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
160
161
  	if (tb[FRA_FLOW])
  		rule4->tclassid = nla_get_u32(tb[FRA_FLOW]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
  #endif
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
163
164
165
166
167
  	rule4->src_len = frh->src_len;
  	rule4->srcmask = inet_make_mask(rule4->src_len);
  	rule4->dst_len = frh->dst_len;
  	rule4->dstmask = inet_make_mask(rule4->dst_len);
  	rule4->tos = frh->tos;
7b204afd4   Robert Olsson   [IPV4]: Use RCU l...
168

e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
169
170
171
  	err = 0;
  errout:
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
  }
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
173
174
  static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
  			     struct nlattr **tb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
  {
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
176
  	struct fib4_rule *rule4 = (struct fib4_rule *) rule;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177

e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
178
179
  	if (frh->src_len && (rule4->src_len != frh->src_len))
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180

e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
181
182
  	if (frh->dst_len && (rule4->dst_len != frh->dst_len))
  		return 0;
7b204afd4   Robert Olsson   [IPV4]: Use RCU l...
183

e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
184
185
  	if (frh->tos && (rule4->tos != frh->tos))
  		return 0;
7b204afd4   Robert Olsson   [IPV4]: Use RCU l...
186

e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
187
188
189
190
  #ifdef CONFIG_NET_CLS_ROUTE
  	if (tb[FRA_FLOW] && (rule4->tclassid != nla_get_u32(tb[FRA_FLOW])))
  		return 0;
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191

e1701c68c   Thomas Graf   [NET]: Fix fib_ru...
192
  	if (frh->src_len && (rule4->src != nla_get_be32(tb[FRA_SRC])))
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
193
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194

e1701c68c   Thomas Graf   [NET]: Fix fib_ru...
195
  	if (frh->dst_len && (rule4->dst != nla_get_be32(tb[FRA_DST])))
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
196
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197

e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
198
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
  }
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
200
  static int fib4_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
04af8cf6f   Rami Rosen   net: Remove unuse...
201
  			  struct fib_rule_hdr *frh)
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
202
203
  {
  	struct fib4_rule *rule4 = (struct fib4_rule *) rule;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204

e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
205
206
207
  	frh->dst_len = rule4->dst_len;
  	frh->src_len = rule4->src_len;
  	frh->tos = rule4->tos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208

e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
209
  	if (rule4->dst_len)
45d60b9e2   Al Viro   [IPV4]: FRA_{DST,...
210
  		NLA_PUT_BE32(skb, FRA_DST, rule4->dst);
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
211
212
  
  	if (rule4->src_len)
45d60b9e2   Al Viro   [IPV4]: FRA_{DST,...
213
  		NLA_PUT_BE32(skb, FRA_SRC, rule4->src);
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
214

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
  #ifdef CONFIG_NET_CLS_ROUTE
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
216
217
  	if (rule4->tclassid)
  		NLA_PUT_U32(skb, FRA_FLOW, rule4->tclassid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
  #endif
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
219
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220

e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
221
222
  nla_put_failure:
  	return -ENOBUFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
  }
339bf98ff   Thomas Graf   [NETLINK]: Do pre...
224
225
226
227
228
229
  static size_t fib4_rule_nlmsg_payload(struct fib_rule *rule)
  {
  	return nla_total_size(4) /* dst */
  	       + nla_total_size(4) /* src */
  	       + nla_total_size(4); /* flow */
  }
ae299fc05   Denis V. Lunev   net: add fib_rule...
230
  static void fib4_rule_flush_cache(struct fib_rules_ops *ops)
73417f617   Thomas Graf   [NET] fib_rules: ...
231
  {
ae299fc05   Denis V. Lunev   net: add fib_rule...
232
  	rt_cache_flush(ops->fro_net, -1);
73417f617   Thomas Graf   [NET] fib_rules: ...
233
  }
3d0c9c4eb   Patrick McHardy   net: fib_rules: m...
234
  static const struct fib_rules_ops __net_initdata fib4_rules_ops_template = {
25239cee7   Patrick McHardy   net: rtnetlink: d...
235
  	.family		= AF_INET,
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
236
  	.rule_size	= sizeof(struct fib4_rule),
e1701c68c   Thomas Graf   [NET]: Fix fib_ru...
237
  	.addr_size	= sizeof(u32),
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
238
239
240
241
242
  	.action		= fib4_rule_action,
  	.match		= fib4_rule_match,
  	.configure	= fib4_rule_configure,
  	.compare	= fib4_rule_compare,
  	.fill		= fib4_rule_fill,
d8a566bea   Patrick McHardy   net: fib_rules: c...
243
  	.default_pref	= fib_default_rule_pref,
339bf98ff   Thomas Graf   [NETLINK]: Do pre...
244
  	.nlmsg_payload	= fib4_rule_nlmsg_payload,
73417f617   Thomas Graf   [NET] fib_rules: ...
245
  	.flush_cache	= fib4_rule_flush_cache,
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
246
247
  	.nlgroup	= RTNLGRP_IPV4_RULE,
  	.policy		= fib4_rule_policy,
e1ef4bf23   Thomas Graf   [IPV4]: Use Proto...
248
249
  	.owner		= THIS_MODULE,
  };
e4e4971c5   Denis V. Lunev   [NETNS]: Namespac...
250
  static int fib_default_rules_init(struct fib_rules_ops *ops)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
  {
2994c6386   Denis V. Lunev   [INET]: Small pos...
252
  	int err;
5adef1809   Patrick McHardy   net 04/05: fib_ru...
253
  	err = fib_default_rule_add(ops, 0, RT_TABLE_LOCAL, 0);
2994c6386   Denis V. Lunev   [INET]: Small pos...
254
255
  	if (err < 0)
  		return err;
e4e4971c5   Denis V. Lunev   [NETNS]: Namespac...
256
  	err = fib_default_rule_add(ops, 0x7FFE, RT_TABLE_MAIN, 0);
2994c6386   Denis V. Lunev   [INET]: Small pos...
257
258
  	if (err < 0)
  		return err;
e4e4971c5   Denis V. Lunev   [NETNS]: Namespac...
259
  	err = fib_default_rule_add(ops, 0x7FFF, RT_TABLE_DEFAULT, 0);
2994c6386   Denis V. Lunev   [INET]: Small pos...
260
261
262
263
  	if (err < 0)
  		return err;
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264

7b1a74fdb   Denis V. Lunev   [NETNS]: Refactor...
265
  int __net_init fib4_rules_init(struct net *net)
2994c6386   Denis V. Lunev   [INET]: Small pos...
266
  {
dbb50165b   Denis V. Lunev   [IPV4]: Check fib...
267
  	int err;
e4e4971c5   Denis V. Lunev   [NETNS]: Namespac...
268
  	struct fib_rules_ops *ops;
e9c5158ac   Eric W. Biederman   net: Allow fib_ru...
269
270
271
  	ops = fib_rules_register(&fib4_rules_ops_template, net);
  	if (IS_ERR(ops))
  		return PTR_ERR(ops);
dbb50165b   Denis V. Lunev   [IPV4]: Check fib...
272

e4e4971c5   Denis V. Lunev   [NETNS]: Namespac...
273
  	err = fib_default_rules_init(ops);
dbb50165b   Denis V. Lunev   [IPV4]: Check fib...
274
275
  	if (err < 0)
  		goto fail;
e4e4971c5   Denis V. Lunev   [NETNS]: Namespac...
276
  	net->ipv4.rules_ops = ops;
dbb50165b   Denis V. Lunev   [IPV4]: Check fib...
277
278
279
280
  	return 0;
  
  fail:
  	/* also cleans all rules already added */
9e3a54878   Denis V. Lunev   [NETNS]: FIB rule...
281
  	fib_rules_unregister(ops);
dbb50165b   Denis V. Lunev   [IPV4]: Check fib...
282
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
  }
7b1a74fdb   Denis V. Lunev   [NETNS]: Refactor...
284
285
286
  
  void __net_exit fib4_rules_exit(struct net *net)
  {
9e3a54878   Denis V. Lunev   [NETNS]: FIB rule...
287
  	fib_rules_unregister(net->ipv4.rules_ops);
7b1a74fdb   Denis V. Lunev   [NETNS]: Refactor...
288
  }