aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/xfrm4_policy.c
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
commitc71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch)
treeecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /net/ipv4/xfrm4_policy.c
parentea53c912f8a86a8567697115b6a0d8152beee5c8 (diff)
parent6a00f206debf8a5c8899055726ad127dbeeed098 (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.c142
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
18static struct xfrm_policy_afinfo xfrm4_policy_afinfo; 19static struct xfrm_policy_afinfo xfrm4_policy_afinfo;
19 20
20static struct dst_entry *xfrm4_dst_lookup(struct net *net, int tos, 21static 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); 41static 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
46static int xfrm4_get_saddr(struct net *net, 50static 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
62static int xfrm4_get_tos(struct flowi *fl) 65static 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
67static int xfrm4_init_path(struct xfrm_dst *path, struct dst_entry *dst, 70static 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
73static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, 76static 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,
104static void 110static 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
172static inline int xfrm4_garbage_collect(struct dst_ops *ops) 193static 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
180static void xfrm4_update_pmtu(struct dst_entry *dst, u32 mtu) 201static 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
199static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, 221static 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
238static struct xfrm_policy_afinfo xfrm4_policy_afinfo = { 242static 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();