diff options
author | David S. Miller <davem@davemloft.net> | 2011-03-01 16:19:07 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-03-01 16:19:07 -0500 |
commit | 68d0c6d34d586a893292d4fb633a3bf8c547b222 (patch) | |
tree | b6d812307621873cf16000171563c1f68b5bc255 /net/ipv6 | |
parent | 903ab86d195cca295379699299c5fc10beba31c7 (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.c | 17 | ||||
-rw-r--r-- | net/ipv6/datagram.c | 15 | ||||
-rw-r--r-- | net/ipv6/inet6_connection_sock.c | 25 | ||||
-rw-r--r-- | net/ipv6/ip6_output.c | 80 | ||||
-rw-r--r-- | net/ipv6/raw.c | 15 | ||||
-rw-r--r-- | net/ipv6/syncookies.c | 7 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 57 | ||||
-rw-r--r-- | net/ipv6/udp.c | 15 |
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 | ||
645 | int inet6_sk_rebuild_header(struct sock *sk) | 645 | int 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) | |||
1002 | EXPORT_SYMBOL_GPL(ip6_dst_lookup); | 1002 | EXPORT_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 | */ | ||
1016 | struct 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 | } | ||
1041 | EXPORT_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 | */ |
1017 | int ip6_sk_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl) | 1058 | struct 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 | } |
1027 | EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup); | 1085 | EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow); |
1028 | 1086 | ||
1029 | static inline int ip6_ufo_append_data(struct sock *sk, | 1087 | static 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) { |