aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2011-03-01 16:19:07 -0500
committerDavid S. Miller <davem@davemloft.net>2011-03-01 16:19:07 -0500
commit68d0c6d34d586a893292d4fb633a3bf8c547b222 (patch)
treeb6d812307621873cf16000171563c1f68b5bc255 /net/ipv6
parent903ab86d195cca295379699299c5fc10beba31c7 (diff)
ipv6: Consolidate route lookup sequences.
Route lookups follow a general pattern in the ipv6 code wherein we first find the non-IPSEC route, potentially override the flow destination address due to ipv6 options settings, and then finally make an IPSEC search using either xfrm_lookup() or __xfrm_lookup(). __xfrm_lookup() is used when we want to generate a blackhole route if the key manager needs to resolve the IPSEC rules (in this case -EREMOTE is returned and the original 'dst' is left unchanged). Otherwise plain xfrm_lookup() is used and when asynchronous IPSEC resolution is necessary, we simply fail the lookup completely. All of these cases are encapsulated into two routines, ip6_dst_lookup_flow and ip6_sk_dst_lookup_flow. The latter of which handles unconnected UDP datagram sockets. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/af_inet6.c17
-rw-r--r--net/ipv6/datagram.c15
-rw-r--r--net/ipv6/inet6_connection_sock.c25
-rw-r--r--net/ipv6/ip6_output.c80
-rw-r--r--net/ipv6/raw.c15
-rw-r--r--net/ipv6/syncookies.c7
-rw-r--r--net/ipv6/tcp_ipv6.c57
-rw-r--r--net/ipv6/udp.c15
8 files changed, 114 insertions, 117 deletions
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 3194aa909872..a88b2e9d25f1 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -644,9 +644,8 @@ EXPORT_SYMBOL(inet6_unregister_protosw);
644 644
645int inet6_sk_rebuild_header(struct sock *sk) 645int inet6_sk_rebuild_header(struct sock *sk)
646{ 646{
647 int err;
648 struct dst_entry *dst;
649 struct ipv6_pinfo *np = inet6_sk(sk); 647 struct ipv6_pinfo *np = inet6_sk(sk);
648 struct dst_entry *dst;
650 649
651 dst = __sk_dst_check(sk, np->dst_cookie); 650 dst = __sk_dst_check(sk, np->dst_cookie);
652 651
@@ -668,17 +667,11 @@ int inet6_sk_rebuild_header(struct sock *sk)
668 667
669 final_p = fl6_update_dst(&fl, np->opt, &final); 668 final_p = fl6_update_dst(&fl, np->opt, &final);
670 669
671 err = ip6_dst_lookup(sk, &dst, &fl); 670 dst = ip6_dst_lookup_flow(sk, &fl, final_p, false);
672 if (err) { 671 if (IS_ERR(dst)) {
673 sk->sk_route_caps = 0; 672 sk->sk_route_caps = 0;
674 return err; 673 sk->sk_err_soft = -PTR_ERR(dst);
675 } 674 return PTR_ERR(dst);
676 if (final_p)
677 ipv6_addr_copy(&fl.fl6_dst, final_p);
678
679 if ((err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0) {
680 sk->sk_err_soft = -err;
681 return err;
682 } 675 }
683 676
684 __ip6_dst_store(sk, dst, NULL, NULL); 677 __ip6_dst_store(sk, dst, NULL, NULL);
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index 320bdb877eed..be3a781c0085 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -162,18 +162,11 @@ ipv4_connected:
162 opt = flowlabel ? flowlabel->opt : np->opt; 162 opt = flowlabel ? flowlabel->opt : np->opt;
163 final_p = fl6_update_dst(&fl, opt, &final); 163 final_p = fl6_update_dst(&fl, opt, &final);
164 164
165 err = ip6_dst_lookup(sk, &dst, &fl); 165 dst = ip6_dst_lookup_flow(sk, &fl, final_p, true);
166 if (err) 166 err = 0;
167 if (IS_ERR(dst)) {
168 err = PTR_ERR(dst);
167 goto out; 169 goto out;
168 if (final_p)
169 ipv6_addr_copy(&fl.fl6_dst, final_p);
170
171 err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT);
172 if (err < 0) {
173 if (err == -EREMOTE)
174 err = ip6_dst_blackhole(sk, &dst, &fl);
175 if (err < 0)
176 goto out;
177 } 170 }
178 171
179 /* source address lookup done in ip6_dst_lookup */ 172 /* source address lookup done in ip6_dst_lookup */
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index d144e629d2b4..d687e1397333 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -74,13 +74,8 @@ struct dst_entry *inet6_csk_route_req(struct sock *sk,
74 fl.fl_ip_sport = inet_rsk(req)->loc_port; 74 fl.fl_ip_sport = inet_rsk(req)->loc_port;
75 security_req_classify_flow(req, &fl); 75 security_req_classify_flow(req, &fl);
76 76
77 if (ip6_dst_lookup(sk, &dst, &fl)) 77 dst = ip6_dst_lookup_flow(sk, &fl, final_p, false);
78 return NULL; 78 if (IS_ERR(dst))
79
80 if (final_p)
81 ipv6_addr_copy(&fl.fl6_dst, final_p);
82
83 if ((xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0)
84 return NULL; 79 return NULL;
85 80
86 return dst; 81 return dst;
@@ -234,21 +229,13 @@ int inet6_csk_xmit(struct sk_buff *skb)
234 dst = __inet6_csk_dst_check(sk, np->dst_cookie); 229 dst = __inet6_csk_dst_check(sk, np->dst_cookie);
235 230
236 if (dst == NULL) { 231 if (dst == NULL) {
237 int err = ip6_dst_lookup(sk, &dst, &fl); 232 dst = ip6_dst_lookup_flow(sk, &fl, final_p, false);
238
239 if (err) {
240 sk->sk_err_soft = -err;
241 kfree_skb(skb);
242 return err;
243 }
244
245 if (final_p)
246 ipv6_addr_copy(&fl.fl6_dst, final_p);
247 233
248 if ((err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0) { 234 if (IS_ERR(dst)) {
235 sk->sk_err_soft = -PTR_ERR(dst);
249 sk->sk_route_caps = 0; 236 sk->sk_route_caps = 0;
250 kfree_skb(skb); 237 kfree_skb(skb);
251 return err; 238 return PTR_ERR(dst);
252 } 239 }
253 240
254 __inet6_csk_dst_store(sk, dst, NULL, NULL); 241 __inet6_csk_dst_store(sk, dst, NULL, NULL);
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 5c618f20523e..28209b2d254d 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1002,29 +1002,87 @@ int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl)
1002EXPORT_SYMBOL_GPL(ip6_dst_lookup); 1002EXPORT_SYMBOL_GPL(ip6_dst_lookup);
1003 1003
1004/** 1004/**
1005 * ip6_sk_dst_lookup - perform socket cached route lookup on flow 1005 * ip6_dst_lookup_flow - perform route lookup on flow with ipsec
1006 * @sk: socket which provides route info
1007 * @fl: flow to lookup
1008 * @final_dst: final destination address for ipsec lookup
1009 * @want_blackhole: IPSEC blackhole handling desired
1010 *
1011 * This function performs a route lookup on the given flow.
1012 *
1013 * It returns a valid dst pointer on success, or a pointer encoded
1014 * error code.
1015 */
1016struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi *fl,
1017 const struct in6_addr *final_dst,
1018 bool want_blackhole)
1019{
1020 struct dst_entry *dst = NULL;
1021 int err;
1022
1023 err = ip6_dst_lookup_tail(sk, &dst, fl);
1024 if (err)
1025 return ERR_PTR(err);
1026 if (final_dst)
1027 ipv6_addr_copy(&fl->fl6_dst, final_dst);
1028 if (want_blackhole) {
1029 err = __xfrm_lookup(sock_net(sk), &dst, fl, sk, XFRM_LOOKUP_WAIT);
1030 if (err == -EREMOTE)
1031 err = ip6_dst_blackhole(sk, &dst, fl);
1032 if (err)
1033 return ERR_PTR(err);
1034 } else {
1035 err = xfrm_lookup(sock_net(sk), &dst, fl, sk, 0);
1036 if (err)
1037 return ERR_PTR(err);
1038 }
1039 return dst;
1040}
1041EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow);
1042
1043/**
1044 * ip6_sk_dst_lookup_flow - perform socket cached route lookup on flow
1006 * @sk: socket which provides the dst cache and route info 1045 * @sk: socket which provides the dst cache and route info
1007 * @dst: pointer to dst_entry * for result
1008 * @fl: flow to lookup 1046 * @fl: flow to lookup
1047 * @final_dst: final destination address for ipsec lookup
1048 * @want_blackhole: IPSEC blackhole handling desired
1009 * 1049 *
1010 * This function performs a route lookup on the given flow with the 1050 * This function performs a route lookup on the given flow with the
1011 * possibility of using the cached route in the socket if it is valid. 1051 * possibility of using the cached route in the socket if it is valid.
1012 * It will take the socket dst lock when operating on the dst cache. 1052 * It will take the socket dst lock when operating on the dst cache.
1013 * As a result, this function can only be used in process context. 1053 * As a result, this function can only be used in process context.
1014 * 1054 *
1015 * It returns zero on success, or a standard errno code on error. 1055 * It returns a valid dst pointer on success, or a pointer encoded
1056 * error code.
1016 */ 1057 */
1017int ip6_sk_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl) 1058struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi *fl,
1059 const struct in6_addr *final_dst,
1060 bool want_blackhole)
1018{ 1061{
1019 *dst = NULL; 1062 struct dst_entry *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie);
1020 if (sk) { 1063 int err;
1021 *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie);
1022 *dst = ip6_sk_dst_check(sk, *dst, fl);
1023 }
1024 1064
1025 return ip6_dst_lookup_tail(sk, dst, fl); 1065 dst = ip6_sk_dst_check(sk, dst, fl);
1066
1067 err = ip6_dst_lookup_tail(sk, &dst, fl);
1068 if (err)
1069 return ERR_PTR(err);
1070 if (final_dst)
1071 ipv6_addr_copy(&fl->fl6_dst, final_dst);
1072 if (want_blackhole) {
1073 err = __xfrm_lookup(sock_net(sk), &dst, fl, sk, XFRM_LOOKUP_WAIT);
1074 if (err == -EREMOTE)
1075 err = ip6_dst_blackhole(sk, &dst, fl);
1076 if (err)
1077 return ERR_PTR(err);
1078 } else {
1079 err = xfrm_lookup(sock_net(sk), &dst, fl, sk, 0);
1080 if (err)
1081 return ERR_PTR(err);
1082 }
1083 return dst;
1026} 1084}
1027EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup); 1085EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow);
1028 1086
1029static inline int ip6_ufo_append_data(struct sock *sk, 1087static inline int ip6_ufo_append_data(struct sock *sk,
1030 int getfrag(void *from, char *to, int offset, int len, 1088 int getfrag(void *from, char *to, int offset, int len,
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 364e86683388..dc29b07caf42 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -856,20 +856,11 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
856 fl.oif = np->mcast_oif; 856 fl.oif = np->mcast_oif;
857 security_sk_classify_flow(sk, &fl); 857 security_sk_classify_flow(sk, &fl);
858 858
859 err = ip6_dst_lookup(sk, &dst, &fl); 859 dst = ip6_dst_lookup_flow(sk, &fl, final_p, true);
860 if (err) 860 if (IS_ERR(dst)) {
861 err = PTR_ERR(dst);
861 goto out; 862 goto out;
862 if (final_p)
863 ipv6_addr_copy(&fl.fl6_dst, final_p);
864
865 err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT);
866 if (err < 0) {
867 if (err == -EREMOTE)
868 err = ip6_dst_blackhole(sk, &dst, &fl);
869 if (err < 0)
870 goto out;
871 } 863 }
872
873 if (hlimit < 0) { 864 if (hlimit < 0) {
874 if (ipv6_addr_is_multicast(&fl.fl6_dst)) 865 if (ipv6_addr_is_multicast(&fl.fl6_dst))
875 hlimit = np->mcast_hops; 866 hlimit = np->mcast_hops;
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 09fd34f0dbf2..0b4cf350631b 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -243,12 +243,9 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
243 fl.fl_ip_dport = inet_rsk(req)->rmt_port; 243 fl.fl_ip_dport = inet_rsk(req)->rmt_port;
244 fl.fl_ip_sport = inet_sk(sk)->inet_sport; 244 fl.fl_ip_sport = inet_sk(sk)->inet_sport;
245 security_req_classify_flow(req, &fl); 245 security_req_classify_flow(req, &fl);
246 if (ip6_dst_lookup(sk, &dst, &fl))
247 goto out_free;
248 246
249 if (final_p) 247 dst = ip6_dst_lookup_flow(sk, &fl, final_p, false);
250 ipv6_addr_copy(&fl.fl6_dst, final_p); 248 if (IS_ERR(dst))
251 if ((xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0)
252 goto out_free; 249 goto out_free;
253 } 250 }
254 251
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 1d0ab5570904..e59a31c48baf 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -255,18 +255,10 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
255 255
256 security_sk_classify_flow(sk, &fl); 256 security_sk_classify_flow(sk, &fl);
257 257
258 err = ip6_dst_lookup(sk, &dst, &fl); 258 dst = ip6_dst_lookup_flow(sk, &fl, final_p, true);
259 if (err) 259 if (IS_ERR(dst)) {
260 err = PTR_ERR(dst);
260 goto failure; 261 goto failure;
261 if (final_p)
262 ipv6_addr_copy(&fl.fl6_dst, final_p);
263
264 err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT);
265 if (err < 0) {
266 if (err == -EREMOTE)
267 err = ip6_dst_blackhole(sk, &dst, &fl);
268 if (err < 0)
269 goto failure;
270 } 262 }
271 263
272 if (saddr == NULL) { 264 if (saddr == NULL) {
@@ -385,7 +377,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
385 np = inet6_sk(sk); 377 np = inet6_sk(sk);
386 378
387 if (type == ICMPV6_PKT_TOOBIG) { 379 if (type == ICMPV6_PKT_TOOBIG) {
388 struct dst_entry *dst = NULL; 380 struct dst_entry *dst;
389 381
390 if (sock_owned_by_user(sk)) 382 if (sock_owned_by_user(sk))
391 goto out; 383 goto out;
@@ -413,13 +405,9 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
413 fl.fl_ip_sport = inet->inet_sport; 405 fl.fl_ip_sport = inet->inet_sport;
414 security_skb_classify_flow(skb, &fl); 406 security_skb_classify_flow(skb, &fl);
415 407
416 if ((err = ip6_dst_lookup(sk, &dst, &fl))) { 408 dst = ip6_dst_lookup_flow(sk, &fl, NULL, false);
417 sk->sk_err_soft = -err; 409 if (IS_ERR(dst)) {
418 goto out; 410 sk->sk_err_soft = -PTR_ERR(dst);
419 }
420
421 if ((err = xfrm_lookup(net, &dst, &fl, sk, 0)) < 0) {
422 sk->sk_err_soft = -err;
423 goto out; 411 goto out;
424 } 412 }
425 413
@@ -496,7 +484,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
496 struct in6_addr * final_p, final; 484 struct in6_addr * final_p, final;
497 struct flowi fl; 485 struct flowi fl;
498 struct dst_entry *dst; 486 struct dst_entry *dst;
499 int err = -1; 487 int err;
500 488
501 memset(&fl, 0, sizeof(fl)); 489 memset(&fl, 0, sizeof(fl));
502 fl.proto = IPPROTO_TCP; 490 fl.proto = IPPROTO_TCP;
@@ -512,15 +500,13 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
512 opt = np->opt; 500 opt = np->opt;
513 final_p = fl6_update_dst(&fl, opt, &final); 501 final_p = fl6_update_dst(&fl, opt, &final);
514 502
515 err = ip6_dst_lookup(sk, &dst, &fl); 503 dst = ip6_dst_lookup_flow(sk, &fl, final_p, false);
516 if (err) 504 if (IS_ERR(dst)) {
505 err = PTR_ERR(dst);
517 goto done; 506 goto done;
518 if (final_p) 507 }
519 ipv6_addr_copy(&fl.fl6_dst, final_p);
520 if ((err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0)
521 goto done;
522
523 skb = tcp_make_synack(sk, dst, req, rvp); 508 skb = tcp_make_synack(sk, dst, req, rvp);
509 err = -ENOMEM;
524 if (skb) { 510 if (skb) {
525 __tcp_v6_send_check(skb, &treq->loc_addr, &treq->rmt_addr); 511 __tcp_v6_send_check(skb, &treq->loc_addr, &treq->rmt_addr);
526 512
@@ -1079,15 +1065,14 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
1079 * Underlying function will use this to retrieve the network 1065 * Underlying function will use this to retrieve the network
1080 * namespace 1066 * namespace
1081 */ 1067 */
1082 if (!ip6_dst_lookup(ctl_sk, &dst, &fl)) { 1068 dst = ip6_dst_lookup_flow(ctl_sk, &fl, NULL, false);
1083 if (xfrm_lookup(net, &dst, &fl, NULL, 0) >= 0) { 1069 if (!IS_ERR(dst)) {
1084 skb_dst_set(buff, dst); 1070 skb_dst_set(buff, dst);
1085 ip6_xmit(ctl_sk, buff, &fl, NULL); 1071 ip6_xmit(ctl_sk, buff, &fl, NULL);
1086 TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); 1072 TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
1087 if (rst) 1073 if (rst)
1088 TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS); 1074 TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS);
1089 return; 1075 return;
1090 }
1091 } 1076 }
1092 1077
1093 kfree_skb(buff); 1078 kfree_skb(buff);
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index a419a787eb69..d86d7f67a597 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1125,18 +1125,11 @@ do_udp_sendmsg:
1125 1125
1126 security_sk_classify_flow(sk, &fl); 1126 security_sk_classify_flow(sk, &fl);
1127 1127
1128 err = ip6_sk_dst_lookup(sk, &dst, &fl); 1128 dst = ip6_sk_dst_lookup_flow(sk, &fl, final_p, true);
1129 if (err) 1129 if (IS_ERR(dst)) {
1130 err = PTR_ERR(dst);
1131 dst = NULL;
1130 goto out; 1132 goto out;
1131 if (final_p)
1132 ipv6_addr_copy(&fl.fl6_dst, final_p);
1133
1134 err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT);
1135 if (err < 0) {
1136 if (err == -EREMOTE)
1137 err = ip6_dst_blackhole(sk, &dst, &fl);
1138 if (err < 0)
1139 goto out;
1140 } 1133 }
1141 1134
1142 if (hlimit < 0) { 1135 if (hlimit < 0) {