diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /net/ipv4/xfrm4_policy.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'net/ipv4/xfrm4_policy.c')
-rw-r--r-- | net/ipv4/xfrm4_policy.c | 142 |
1 files changed, 74 insertions, 68 deletions
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index a580349f0b8a..981e43eaf704 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c | |||
@@ -11,57 +11,60 @@ | |||
11 | #include <linux/err.h> | 11 | #include <linux/err.h> |
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/inetdevice.h> | 13 | #include <linux/inetdevice.h> |
14 | #include <linux/if_tunnel.h> | ||
14 | #include <net/dst.h> | 15 | #include <net/dst.h> |
15 | #include <net/xfrm.h> | 16 | #include <net/xfrm.h> |
16 | #include <net/ip.h> | 17 | #include <net/ip.h> |
17 | 18 | ||
18 | static struct xfrm_policy_afinfo xfrm4_policy_afinfo; | 19 | static struct xfrm_policy_afinfo xfrm4_policy_afinfo; |
19 | 20 | ||
20 | static struct dst_entry *xfrm4_dst_lookup(struct net *net, int tos, | 21 | static struct dst_entry *__xfrm4_dst_lookup(struct net *net, struct flowi4 *fl4, |
21 | xfrm_address_t *saddr, | 22 | int tos, |
22 | xfrm_address_t *daddr) | 23 | const xfrm_address_t *saddr, |
24 | const xfrm_address_t *daddr) | ||
23 | { | 25 | { |
24 | struct flowi fl = { | ||
25 | .nl_u = { | ||
26 | .ip4_u = { | ||
27 | .tos = tos, | ||
28 | .daddr = daddr->a4, | ||
29 | }, | ||
30 | }, | ||
31 | }; | ||
32 | struct dst_entry *dst; | ||
33 | struct rtable *rt; | 26 | struct rtable *rt; |
34 | int err; | ||
35 | 27 | ||
28 | memset(fl4, 0, sizeof(*fl4)); | ||
29 | fl4->daddr = daddr->a4; | ||
30 | fl4->flowi4_tos = tos; | ||
36 | if (saddr) | 31 | if (saddr) |
37 | fl.fl4_src = saddr->a4; | 32 | fl4->saddr = saddr->a4; |
33 | |||
34 | rt = __ip_route_output_key(net, fl4); | ||
35 | if (!IS_ERR(rt)) | ||
36 | return &rt->dst; | ||
38 | 37 | ||
39 | err = __ip_route_output_key(net, &rt, &fl); | 38 | return ERR_CAST(rt); |
40 | dst = &rt->dst; | 39 | } |
41 | if (err) | 40 | |
42 | dst = ERR_PTR(err); | 41 | static struct dst_entry *xfrm4_dst_lookup(struct net *net, int tos, |
43 | return dst; | 42 | const xfrm_address_t *saddr, |
43 | const xfrm_address_t *daddr) | ||
44 | { | ||
45 | struct flowi4 fl4; | ||
46 | |||
47 | return __xfrm4_dst_lookup(net, &fl4, tos, saddr, daddr); | ||
44 | } | 48 | } |
45 | 49 | ||
46 | static int xfrm4_get_saddr(struct net *net, | 50 | static int xfrm4_get_saddr(struct net *net, |
47 | xfrm_address_t *saddr, xfrm_address_t *daddr) | 51 | xfrm_address_t *saddr, xfrm_address_t *daddr) |
48 | { | 52 | { |
49 | struct dst_entry *dst; | 53 | struct dst_entry *dst; |
50 | struct rtable *rt; | 54 | struct flowi4 fl4; |
51 | 55 | ||
52 | dst = xfrm4_dst_lookup(net, 0, NULL, daddr); | 56 | dst = __xfrm4_dst_lookup(net, &fl4, 0, NULL, daddr); |
53 | if (IS_ERR(dst)) | 57 | if (IS_ERR(dst)) |
54 | return -EHOSTUNREACH; | 58 | return -EHOSTUNREACH; |
55 | 59 | ||
56 | rt = (struct rtable *)dst; | 60 | saddr->a4 = fl4.saddr; |
57 | saddr->a4 = rt->rt_src; | ||
58 | dst_release(dst); | 61 | dst_release(dst); |
59 | return 0; | 62 | return 0; |
60 | } | 63 | } |
61 | 64 | ||
62 | static int xfrm4_get_tos(struct flowi *fl) | 65 | static int xfrm4_get_tos(const struct flowi *fl) |
63 | { | 66 | { |
64 | return IPTOS_RT_MASK & fl->fl4_tos; /* Strip ECN bits */ | 67 | return IPTOS_RT_MASK & fl->u.ip4.flowi4_tos; /* Strip ECN bits */ |
65 | } | 68 | } |
66 | 69 | ||
67 | static int xfrm4_init_path(struct xfrm_dst *path, struct dst_entry *dst, | 70 | static int xfrm4_init_path(struct xfrm_dst *path, struct dst_entry *dst, |
@@ -71,19 +74,22 @@ static int xfrm4_init_path(struct xfrm_dst *path, struct dst_entry *dst, | |||
71 | } | 74 | } |
72 | 75 | ||
73 | static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, | 76 | static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, |
74 | struct flowi *fl) | 77 | const struct flowi *fl) |
75 | { | 78 | { |
76 | struct rtable *rt = (struct rtable *)xdst->route; | 79 | struct rtable *rt = (struct rtable *)xdst->route; |
80 | const struct flowi4 *fl4 = &fl->u.ip4; | ||
77 | 81 | ||
78 | xdst->u.rt.fl = *fl; | 82 | rt->rt_key_dst = fl4->daddr; |
83 | rt->rt_key_src = fl4->saddr; | ||
84 | rt->rt_key_tos = fl4->flowi4_tos; | ||
85 | rt->rt_route_iif = fl4->flowi4_iif; | ||
86 | rt->rt_iif = fl4->flowi4_iif; | ||
87 | rt->rt_oif = fl4->flowi4_oif; | ||
88 | rt->rt_mark = fl4->flowi4_mark; | ||
79 | 89 | ||
80 | xdst->u.dst.dev = dev; | 90 | xdst->u.dst.dev = dev; |
81 | dev_hold(dev); | 91 | dev_hold(dev); |
82 | 92 | ||
83 | xdst->u.rt.idev = in_dev_get(dev); | ||
84 | if (!xdst->u.rt.idev) | ||
85 | return -ENODEV; | ||
86 | |||
87 | xdst->u.rt.peer = rt->peer; | 93 | xdst->u.rt.peer = rt->peer; |
88 | if (rt->peer) | 94 | if (rt->peer) |
89 | atomic_inc(&rt->peer->refcnt); | 95 | atomic_inc(&rt->peer->refcnt); |
@@ -104,11 +110,12 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, | |||
104 | static void | 110 | static void |
105 | _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse) | 111 | _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse) |
106 | { | 112 | { |
107 | struct iphdr *iph = ip_hdr(skb); | 113 | const struct iphdr *iph = ip_hdr(skb); |
108 | u8 *xprth = skb_network_header(skb) + iph->ihl * 4; | 114 | u8 *xprth = skb_network_header(skb) + iph->ihl * 4; |
115 | struct flowi4 *fl4 = &fl->u.ip4; | ||
109 | 116 | ||
110 | memset(fl, 0, sizeof(struct flowi)); | 117 | memset(fl4, 0, sizeof(struct flowi4)); |
111 | fl->mark = skb->mark; | 118 | fl4->flowi4_mark = skb->mark; |
112 | 119 | ||
113 | if (!(iph->frag_off & htons(IP_MF | IP_OFFSET))) { | 120 | if (!(iph->frag_off & htons(IP_MF | IP_OFFSET))) { |
114 | switch (iph->protocol) { | 121 | switch (iph->protocol) { |
@@ -121,8 +128,8 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse) | |||
121 | pskb_may_pull(skb, xprth + 4 - skb->data)) { | 128 | pskb_may_pull(skb, xprth + 4 - skb->data)) { |
122 | __be16 *ports = (__be16 *)xprth; | 129 | __be16 *ports = (__be16 *)xprth; |
123 | 130 | ||
124 | fl->fl_ip_sport = ports[!!reverse]; | 131 | fl4->fl4_sport = ports[!!reverse]; |
125 | fl->fl_ip_dport = ports[!reverse]; | 132 | fl4->fl4_dport = ports[!reverse]; |
126 | } | 133 | } |
127 | break; | 134 | break; |
128 | 135 | ||
@@ -130,8 +137,8 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse) | |||
130 | if (pskb_may_pull(skb, xprth + 2 - skb->data)) { | 137 | if (pskb_may_pull(skb, xprth + 2 - skb->data)) { |
131 | u8 *icmp = xprth; | 138 | u8 *icmp = xprth; |
132 | 139 | ||
133 | fl->fl_icmp_type = icmp[0]; | 140 | fl4->fl4_icmp_type = icmp[0]; |
134 | fl->fl_icmp_code = icmp[1]; | 141 | fl4->fl4_icmp_code = icmp[1]; |
135 | } | 142 | } |
136 | break; | 143 | break; |
137 | 144 | ||
@@ -139,7 +146,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse) | |||
139 | if (pskb_may_pull(skb, xprth + 4 - skb->data)) { | 146 | if (pskb_may_pull(skb, xprth + 4 - skb->data)) { |
140 | __be32 *ehdr = (__be32 *)xprth; | 147 | __be32 *ehdr = (__be32 *)xprth; |
141 | 148 | ||
142 | fl->fl_ipsec_spi = ehdr[0]; | 149 | fl4->fl4_ipsec_spi = ehdr[0]; |
143 | } | 150 | } |
144 | break; | 151 | break; |
145 | 152 | ||
@@ -147,7 +154,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse) | |||
147 | if (pskb_may_pull(skb, xprth + 8 - skb->data)) { | 154 | if (pskb_may_pull(skb, xprth + 8 - skb->data)) { |
148 | __be32 *ah_hdr = (__be32*)xprth; | 155 | __be32 *ah_hdr = (__be32*)xprth; |
149 | 156 | ||
150 | fl->fl_ipsec_spi = ah_hdr[1]; | 157 | fl4->fl4_ipsec_spi = ah_hdr[1]; |
151 | } | 158 | } |
152 | break; | 159 | break; |
153 | 160 | ||
@@ -155,18 +162,32 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse) | |||
155 | if (pskb_may_pull(skb, xprth + 4 - skb->data)) { | 162 | if (pskb_may_pull(skb, xprth + 4 - skb->data)) { |
156 | __be16 *ipcomp_hdr = (__be16 *)xprth; | 163 | __be16 *ipcomp_hdr = (__be16 *)xprth; |
157 | 164 | ||
158 | fl->fl_ipsec_spi = htonl(ntohs(ipcomp_hdr[1])); | 165 | fl4->fl4_ipsec_spi = htonl(ntohs(ipcomp_hdr[1])); |
166 | } | ||
167 | break; | ||
168 | |||
169 | case IPPROTO_GRE: | ||
170 | if (pskb_may_pull(skb, xprth + 12 - skb->data)) { | ||
171 | __be16 *greflags = (__be16 *)xprth; | ||
172 | __be32 *gre_hdr = (__be32 *)xprth; | ||
173 | |||
174 | if (greflags[0] & GRE_KEY) { | ||
175 | if (greflags[0] & GRE_CSUM) | ||
176 | gre_hdr++; | ||
177 | fl4->fl4_gre_key = gre_hdr[1]; | ||
178 | } | ||
159 | } | 179 | } |
160 | break; | 180 | break; |
181 | |||
161 | default: | 182 | default: |
162 | fl->fl_ipsec_spi = 0; | 183 | fl4->fl4_ipsec_spi = 0; |
163 | break; | 184 | break; |
164 | } | 185 | } |
165 | } | 186 | } |
166 | fl->proto = iph->protocol; | 187 | fl4->flowi4_proto = iph->protocol; |
167 | fl->fl4_dst = reverse ? iph->saddr : iph->daddr; | 188 | fl4->daddr = reverse ? iph->saddr : iph->daddr; |
168 | fl->fl4_src = reverse ? iph->daddr : iph->saddr; | 189 | fl4->saddr = reverse ? iph->daddr : iph->saddr; |
169 | fl->fl4_tos = iph->tos; | 190 | fl4->flowi4_tos = iph->tos; |
170 | } | 191 | } |
171 | 192 | ||
172 | static inline int xfrm4_garbage_collect(struct dst_ops *ops) | 193 | static inline int xfrm4_garbage_collect(struct dst_ops *ops) |
@@ -174,7 +195,7 @@ static inline int xfrm4_garbage_collect(struct dst_ops *ops) | |||
174 | struct net *net = container_of(ops, struct net, xfrm.xfrm4_dst_ops); | 195 | struct net *net = container_of(ops, struct net, xfrm.xfrm4_dst_ops); |
175 | 196 | ||
176 | xfrm4_policy_afinfo.garbage_collect(net); | 197 | xfrm4_policy_afinfo.garbage_collect(net); |
177 | return (atomic_read(&ops->entries) > ops->gc_thresh * 2); | 198 | return (dst_entries_get_slow(ops) > ops->gc_thresh * 2); |
178 | } | 199 | } |
179 | 200 | ||
180 | static void xfrm4_update_pmtu(struct dst_entry *dst, u32 mtu) | 201 | static void xfrm4_update_pmtu(struct dst_entry *dst, u32 mtu) |
@@ -189,37 +210,20 @@ static void xfrm4_dst_destroy(struct dst_entry *dst) | |||
189 | { | 210 | { |
190 | struct xfrm_dst *xdst = (struct xfrm_dst *)dst; | 211 | struct xfrm_dst *xdst = (struct xfrm_dst *)dst; |
191 | 212 | ||
192 | if (likely(xdst->u.rt.idev)) | 213 | dst_destroy_metrics_generic(dst); |
193 | in_dev_put(xdst->u.rt.idev); | 214 | |
194 | if (likely(xdst->u.rt.peer)) | 215 | if (likely(xdst->u.rt.peer)) |
195 | inet_putpeer(xdst->u.rt.peer); | 216 | inet_putpeer(xdst->u.rt.peer); |
217 | |||
196 | xfrm_dst_destroy(xdst); | 218 | xfrm_dst_destroy(xdst); |
197 | } | 219 | } |
198 | 220 | ||
199 | static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, | 221 | static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, |
200 | int unregister) | 222 | int unregister) |
201 | { | 223 | { |
202 | struct xfrm_dst *xdst; | ||
203 | |||
204 | if (!unregister) | 224 | if (!unregister) |
205 | return; | 225 | return; |
206 | 226 | ||
207 | xdst = (struct xfrm_dst *)dst; | ||
208 | if (xdst->u.rt.idev->dev == dev) { | ||
209 | struct in_device *loopback_idev = | ||
210 | in_dev_get(dev_net(dev)->loopback_dev); | ||
211 | BUG_ON(!loopback_idev); | ||
212 | |||
213 | do { | ||
214 | in_dev_put(xdst->u.rt.idev); | ||
215 | xdst->u.rt.idev = loopback_idev; | ||
216 | in_dev_hold(loopback_idev); | ||
217 | xdst = (struct xfrm_dst *)xdst->u.dst.child; | ||
218 | } while (xdst->u.dst.xfrm); | ||
219 | |||
220 | __in_dev_put(loopback_idev); | ||
221 | } | ||
222 | |||
223 | xfrm_dst_ifdown(dst, dev); | 227 | xfrm_dst_ifdown(dst, dev); |
224 | } | 228 | } |
225 | 229 | ||
@@ -228,11 +232,11 @@ static struct dst_ops xfrm4_dst_ops = { | |||
228 | .protocol = cpu_to_be16(ETH_P_IP), | 232 | .protocol = cpu_to_be16(ETH_P_IP), |
229 | .gc = xfrm4_garbage_collect, | 233 | .gc = xfrm4_garbage_collect, |
230 | .update_pmtu = xfrm4_update_pmtu, | 234 | .update_pmtu = xfrm4_update_pmtu, |
235 | .cow_metrics = dst_cow_metrics_generic, | ||
231 | .destroy = xfrm4_dst_destroy, | 236 | .destroy = xfrm4_dst_destroy, |
232 | .ifdown = xfrm4_dst_ifdown, | 237 | .ifdown = xfrm4_dst_ifdown, |
233 | .local_out = __ip_local_out, | 238 | .local_out = __ip_local_out, |
234 | .gc_thresh = 1024, | 239 | .gc_thresh = 1024, |
235 | .entries = ATOMIC_INIT(0), | ||
236 | }; | 240 | }; |
237 | 241 | ||
238 | static struct xfrm_policy_afinfo xfrm4_policy_afinfo = { | 242 | static struct xfrm_policy_afinfo xfrm4_policy_afinfo = { |
@@ -244,6 +248,7 @@ static struct xfrm_policy_afinfo xfrm4_policy_afinfo = { | |||
244 | .get_tos = xfrm4_get_tos, | 248 | .get_tos = xfrm4_get_tos, |
245 | .init_path = xfrm4_init_path, | 249 | .init_path = xfrm4_init_path, |
246 | .fill_dst = xfrm4_fill_dst, | 250 | .fill_dst = xfrm4_fill_dst, |
251 | .blackhole_route = ipv4_blackhole_route, | ||
247 | }; | 252 | }; |
248 | 253 | ||
249 | #ifdef CONFIG_SYSCTL | 254 | #ifdef CONFIG_SYSCTL |
@@ -288,6 +293,7 @@ void __init xfrm4_init(int rt_max_size) | |||
288 | * and start cleaning when were 1/2 full | 293 | * and start cleaning when were 1/2 full |
289 | */ | 294 | */ |
290 | xfrm4_dst_ops.gc_thresh = rt_max_size/2; | 295 | xfrm4_dst_ops.gc_thresh = rt_max_size/2; |
296 | dst_entries_init(&xfrm4_dst_ops); | ||
291 | 297 | ||
292 | xfrm4_state_init(); | 298 | xfrm4_state_init(); |
293 | xfrm4_policy_init(); | 299 | xfrm4_policy_init(); |