Blame view
net/ipv4/fib_rules.c
6.57 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 |
/* * INET An implementation of the TCP/IP protocol suite for the LINUX * operating system. INET is implemented using the BSD Socket * interface as the means of communication with the user level. * * IPv4 Forwarding Information Base: policy rules. * |
1da177e4c Linux-2.6.12-rc2 |
8 |
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> |
e1ef4bf23 [IPV4]: Use Proto... |
9 |
* Thomas Graf <tgraf@suug.ch> |
1da177e4c 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 Linux-2.6.12-rc2 |
20 21 |
#include <linux/types.h> #include <linux/kernel.h> |
1da177e4c Linux-2.6.12-rc2 |
22 |
#include <linux/netdevice.h> |
1da177e4c Linux-2.6.12-rc2 |
23 |
#include <linux/netlink.h> |
e1ef4bf23 [IPV4]: Use Proto... |
24 |
#include <linux/inetdevice.h> |
1da177e4c Linux-2.6.12-rc2 |
25 |
#include <linux/init.h> |
7b204afd4 [IPV4]: Use RCU l... |
26 27 |
#include <linux/list.h> #include <linux/rcupdate.h> |
1da177e4c Linux-2.6.12-rc2 |
28 |
#include <net/ip.h> |
1da177e4c Linux-2.6.12-rc2 |
29 30 |
#include <net/route.h> #include <net/tcp.h> |
1da177e4c Linux-2.6.12-rc2 |
31 |
#include <net/ip_fib.h> |
e1ef4bf23 [IPV4]: Use Proto... |
32 |
#include <net/fib_rules.h> |
1da177e4c Linux-2.6.12-rc2 |
33 |
|
e1ef4bf23 [IPV4]: Use Proto... |
34 |
struct fib4_rule |
1da177e4c Linux-2.6.12-rc2 |
35 |
{ |
e1ef4bf23 [IPV4]: Use Proto... |
36 37 38 39 |
struct fib_rule common; u8 dst_len; u8 src_len; u8 tos; |
81f7bf6cb [IPV4]: net/ipv4/... |
40 41 42 43 |
__be32 src; __be32 srcmask; __be32 dst; __be32 dstmask; |
1da177e4c Linux-2.6.12-rc2 |
44 |
#ifdef CONFIG_NET_CLS_ROUTE |
e1ef4bf23 [IPV4]: Use Proto... |
45 |
u32 tclassid; |
1da177e4c Linux-2.6.12-rc2 |
46 |
#endif |
1da177e4c Linux-2.6.12-rc2 |
47 |
}; |
e1ef4bf23 [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 [IPV4]: Use RCU l... |
54 |
|
da0e28cb6 [NETNS]: Add netn... |
55 |
int fib_lookup(struct net *net, struct flowi *flp, struct fib_result *res) |
e1ef4bf23 [IPV4]: Use Proto... |
56 57 58 59 60 |
{ struct fib_lookup_arg arg = { .result = res, }; int err; |
1da177e4c Linux-2.6.12-rc2 |
61 |
|
da0e28cb6 [NETNS]: Add netn... |
62 |
err = fib_rules_lookup(net->ipv4.rules_ops, flp, 0, &arg); |
e1ef4bf23 [IPV4]: Use Proto... |
63 |
res->r = arg.rule; |
a5cdc0300 [IPV4]: Add fib r... |
64 |
|
e1ef4bf23 [IPV4]: Use Proto... |
65 66 |
return err; } |
8ce11e6a9 [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 Linux-2.6.12-rc2 |
69 |
{ |
e1ef4bf23 [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 Linux-2.6.12-rc2 |
89 |
} |
e1ef4bf23 [IPV4]: Use Proto... |
90 |
|
51314a17b [NETNS]: Process ... |
91 |
if ((tbl = fib_get_table(rule->fr_net, rule->table)) == NULL) |
e1ef4bf23 [IPV4]: Use Proto... |
92 |
goto errout; |
16c6cf8bb ipv4: fib table a... |
93 |
err = fib_table_lookup(tbl, flp, (struct fib_result *) arg->result); |
e1ef4bf23 [IPV4]: Use Proto... |
94 95 96 |
if (err > 0) err = -EAGAIN; errout: |
1da177e4c Linux-2.6.12-rc2 |
97 98 |
return err; } |
e1ef4bf23 [IPV4]: Use Proto... |
99 |
|
e1ef4bf23 [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 [IPV4]: net/ipv4/... |
103 104 |
__be32 daddr = fl->fl4_dst; __be32 saddr = fl->fl4_src; |
e1ef4bf23 [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 [IPV4]: Use Proto... |
112 113 |
return 1; } |
1da177e4c Linux-2.6.12-rc2 |
114 |
|
8ad4942cd [NETNS]: Add netn... |
115 |
static struct fib_table *fib_empty_table(struct net *net) |
1da177e4c Linux-2.6.12-rc2 |
116 |
{ |
2dfe55b47 [NET]: Use u32 fo... |
117 |
u32 id; |
1da177e4c Linux-2.6.12-rc2 |
118 119 |
for (id = 1; id <= RT_TABLE_MAX; id++) |
8ad4942cd [NETNS]: Add netn... |
120 121 |
if (fib_get_table(net, id) == NULL) return fib_new_table(net, id); |
1da177e4c Linux-2.6.12-rc2 |
122 123 |
return NULL; } |
ef7c79ed6 [NETLINK]: Mark n... |
124 |
static const struct nla_policy fib4_rule_policy[FRA_MAX+1] = { |
1f6c9557e [NET] rules: Shar... |
125 |
FRA_GENERIC_POLICY, |
e1ef4bf23 [IPV4]: Use Proto... |
126 127 |
[FRA_FLOW] = { .type = NLA_U32 }, }; |
7b204afd4 [IPV4]: Use RCU l... |
128 |
|
e1ef4bf23 [IPV4]: Use Proto... |
129 |
static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb, |
8b3521eeb ipv4: remove an u... |
130 |
struct fib_rule_hdr *frh, |
e1ef4bf23 [IPV4]: Use Proto... |
131 |
struct nlattr **tb) |
1da177e4c Linux-2.6.12-rc2 |
132 |
{ |
3b1e0a655 [NET] NETNS: Omit... |
133 |
struct net *net = sock_net(skb->sk); |
e1ef4bf23 [IPV4]: Use Proto... |
134 135 |
int err = -EINVAL; struct fib4_rule *rule4 = (struct fib4_rule *) rule; |
1da177e4c Linux-2.6.12-rc2 |
136 |
|
e1701c68c [NET]: Fix fib_ru... |
137 |
if (frh->tos & ~IPTOS_TOS_MASK) |
e1ef4bf23 [IPV4]: Use Proto... |
138 |
goto errout; |
7b204afd4 [IPV4]: Use RCU l... |
139 |
|
e1ef4bf23 [IPV4]: Use Proto... |
140 141 142 |
if (rule->table == RT_TABLE_UNSPEC) { if (rule->action == FR_ACT_TO_TBL) { struct fib_table *table; |
1da177e4c Linux-2.6.12-rc2 |
143 |
|
e4e4971c5 [NETNS]: Namespac... |
144 |
table = fib_empty_table(net); |
e1ef4bf23 [IPV4]: Use Proto... |
145 146 147 148 |
if (table == NULL) { err = -ENOBUFS; goto errout; } |
1da177e4c Linux-2.6.12-rc2 |
149 |
|
e1ef4bf23 [IPV4]: Use Proto... |
150 |
rule->table = table->tb_id; |
1da177e4c Linux-2.6.12-rc2 |
151 152 |
} } |
e1701c68c [NET]: Fix fib_ru... |
153 |
if (frh->src_len) |
45d60b9e2 [IPV4]: FRA_{DST,... |
154 |
rule4->src = nla_get_be32(tb[FRA_SRC]); |
7b204afd4 [IPV4]: Use RCU l... |
155 |
|
e1701c68c [NET]: Fix fib_ru... |
156 |
if (frh->dst_len) |
45d60b9e2 [IPV4]: FRA_{DST,... |
157 |
rule4->dst = nla_get_be32(tb[FRA_DST]); |
7b204afd4 [IPV4]: Use RCU l... |
158 |
|
1da177e4c Linux-2.6.12-rc2 |
159 |
#ifdef CONFIG_NET_CLS_ROUTE |
e1ef4bf23 [IPV4]: Use Proto... |
160 161 |
if (tb[FRA_FLOW]) rule4->tclassid = nla_get_u32(tb[FRA_FLOW]); |
1da177e4c Linux-2.6.12-rc2 |
162 |
#endif |
e1ef4bf23 [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 [IPV4]: Use RCU l... |
168 |
|
e1ef4bf23 [IPV4]: Use Proto... |
169 170 171 |
err = 0; errout: return err; |
1da177e4c Linux-2.6.12-rc2 |
172 |
} |
e1ef4bf23 [IPV4]: Use Proto... |
173 174 |
static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, struct nlattr **tb) |
1da177e4c Linux-2.6.12-rc2 |
175 |
{ |
e1ef4bf23 [IPV4]: Use Proto... |
176 |
struct fib4_rule *rule4 = (struct fib4_rule *) rule; |
1da177e4c Linux-2.6.12-rc2 |
177 |
|
e1ef4bf23 [IPV4]: Use Proto... |
178 179 |
if (frh->src_len && (rule4->src_len != frh->src_len)) return 0; |
1da177e4c Linux-2.6.12-rc2 |
180 |
|
e1ef4bf23 [IPV4]: Use Proto... |
181 182 |
if (frh->dst_len && (rule4->dst_len != frh->dst_len)) return 0; |
7b204afd4 [IPV4]: Use RCU l... |
183 |
|
e1ef4bf23 [IPV4]: Use Proto... |
184 185 |
if (frh->tos && (rule4->tos != frh->tos)) return 0; |
7b204afd4 [IPV4]: Use RCU l... |
186 |
|
e1ef4bf23 [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 Linux-2.6.12-rc2 |
191 |
|
e1701c68c [NET]: Fix fib_ru... |
192 |
if (frh->src_len && (rule4->src != nla_get_be32(tb[FRA_SRC]))) |
e1ef4bf23 [IPV4]: Use Proto... |
193 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
194 |
|
e1701c68c [NET]: Fix fib_ru... |
195 |
if (frh->dst_len && (rule4->dst != nla_get_be32(tb[FRA_DST]))) |
e1ef4bf23 [IPV4]: Use Proto... |
196 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
197 |
|
e1ef4bf23 [IPV4]: Use Proto... |
198 |
return 1; |
1da177e4c Linux-2.6.12-rc2 |
199 |
} |
e1ef4bf23 [IPV4]: Use Proto... |
200 |
static int fib4_rule_fill(struct fib_rule *rule, struct sk_buff *skb, |
04af8cf6f net: Remove unuse... |
201 |
struct fib_rule_hdr *frh) |
e1ef4bf23 [IPV4]: Use Proto... |
202 203 |
{ struct fib4_rule *rule4 = (struct fib4_rule *) rule; |
1da177e4c Linux-2.6.12-rc2 |
204 |
|
e1ef4bf23 [IPV4]: Use Proto... |
205 206 207 |
frh->dst_len = rule4->dst_len; frh->src_len = rule4->src_len; frh->tos = rule4->tos; |
1da177e4c Linux-2.6.12-rc2 |
208 |
|
e1ef4bf23 [IPV4]: Use Proto... |
209 |
if (rule4->dst_len) |
45d60b9e2 [IPV4]: FRA_{DST,... |
210 |
NLA_PUT_BE32(skb, FRA_DST, rule4->dst); |
e1ef4bf23 [IPV4]: Use Proto... |
211 212 |
if (rule4->src_len) |
45d60b9e2 [IPV4]: FRA_{DST,... |
213 |
NLA_PUT_BE32(skb, FRA_SRC, rule4->src); |
e1ef4bf23 [IPV4]: Use Proto... |
214 |
|
1da177e4c Linux-2.6.12-rc2 |
215 |
#ifdef CONFIG_NET_CLS_ROUTE |
e1ef4bf23 [IPV4]: Use Proto... |
216 217 |
if (rule4->tclassid) NLA_PUT_U32(skb, FRA_FLOW, rule4->tclassid); |
1da177e4c Linux-2.6.12-rc2 |
218 |
#endif |
e1ef4bf23 [IPV4]: Use Proto... |
219 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
220 |
|
e1ef4bf23 [IPV4]: Use Proto... |
221 222 |
nla_put_failure: return -ENOBUFS; |
1da177e4c Linux-2.6.12-rc2 |
223 |
} |
339bf98ff [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 net: add fib_rule... |
230 |
static void fib4_rule_flush_cache(struct fib_rules_ops *ops) |
73417f617 [NET] fib_rules: ... |
231 |
{ |
ae299fc05 net: add fib_rule... |
232 |
rt_cache_flush(ops->fro_net, -1); |
73417f617 [NET] fib_rules: ... |
233 |
} |
3d0c9c4eb net: fib_rules: m... |
234 |
static const struct fib_rules_ops __net_initdata fib4_rules_ops_template = { |
25239cee7 net: rtnetlink: d... |
235 |
.family = AF_INET, |
e1ef4bf23 [IPV4]: Use Proto... |
236 |
.rule_size = sizeof(struct fib4_rule), |
e1701c68c [NET]: Fix fib_ru... |
237 |
.addr_size = sizeof(u32), |
e1ef4bf23 [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 net: fib_rules: c... |
243 |
.default_pref = fib_default_rule_pref, |
339bf98ff [NETLINK]: Do pre... |
244 |
.nlmsg_payload = fib4_rule_nlmsg_payload, |
73417f617 [NET] fib_rules: ... |
245 |
.flush_cache = fib4_rule_flush_cache, |
e1ef4bf23 [IPV4]: Use Proto... |
246 247 |
.nlgroup = RTNLGRP_IPV4_RULE, .policy = fib4_rule_policy, |
e1ef4bf23 [IPV4]: Use Proto... |
248 249 |
.owner = THIS_MODULE, }; |
e4e4971c5 [NETNS]: Namespac... |
250 |
static int fib_default_rules_init(struct fib_rules_ops *ops) |
1da177e4c Linux-2.6.12-rc2 |
251 |
{ |
2994c6386 [INET]: Small pos... |
252 |
int err; |
5adef1809 net 04/05: fib_ru... |
253 |
err = fib_default_rule_add(ops, 0, RT_TABLE_LOCAL, 0); |
2994c6386 [INET]: Small pos... |
254 255 |
if (err < 0) return err; |
e4e4971c5 [NETNS]: Namespac... |
256 |
err = fib_default_rule_add(ops, 0x7FFE, RT_TABLE_MAIN, 0); |
2994c6386 [INET]: Small pos... |
257 258 |
if (err < 0) return err; |
e4e4971c5 [NETNS]: Namespac... |
259 |
err = fib_default_rule_add(ops, 0x7FFF, RT_TABLE_DEFAULT, 0); |
2994c6386 [INET]: Small pos... |
260 261 262 263 |
if (err < 0) return err; return 0; } |
1da177e4c Linux-2.6.12-rc2 |
264 |
|
7b1a74fdb [NETNS]: Refactor... |
265 |
int __net_init fib4_rules_init(struct net *net) |
2994c6386 [INET]: Small pos... |
266 |
{ |
dbb50165b [IPV4]: Check fib... |
267 |
int err; |
e4e4971c5 [NETNS]: Namespac... |
268 |
struct fib_rules_ops *ops; |
e9c5158ac 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 [IPV4]: Check fib... |
272 |
|
e4e4971c5 [NETNS]: Namespac... |
273 |
err = fib_default_rules_init(ops); |
dbb50165b [IPV4]: Check fib... |
274 275 |
if (err < 0) goto fail; |
e4e4971c5 [NETNS]: Namespac... |
276 |
net->ipv4.rules_ops = ops; |
dbb50165b [IPV4]: Check fib... |
277 278 279 280 |
return 0; fail: /* also cleans all rules already added */ |
9e3a54878 [NETNS]: FIB rule... |
281 |
fib_rules_unregister(ops); |
dbb50165b [IPV4]: Check fib... |
282 |
return err; |
1da177e4c Linux-2.6.12-rc2 |
283 |
} |
7b1a74fdb [NETNS]: Refactor... |
284 285 286 |
void __net_exit fib4_rules_exit(struct net *net) { |
9e3a54878 [NETNS]: FIB rule... |
287 |
fib_rules_unregister(net->ipv4.rules_ops); |
7b1a74fdb [NETNS]: Refactor... |
288 |
} |