diff options
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r-- | net/ipv6/ip6_output.c | 66 |
1 files changed, 41 insertions, 25 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index e6f931997996..ef02b26ccf81 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -321,6 +321,27 @@ static inline int ip6_forward_finish(struct sk_buff *skb) | |||
321 | return dst_output(skb); | 321 | return dst_output(skb); |
322 | } | 322 | } |
323 | 323 | ||
324 | static unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst) | ||
325 | { | ||
326 | unsigned int mtu; | ||
327 | struct inet6_dev *idev; | ||
328 | |||
329 | if (dst_metric_locked(dst, RTAX_MTU)) { | ||
330 | mtu = dst_metric_raw(dst, RTAX_MTU); | ||
331 | if (mtu) | ||
332 | return mtu; | ||
333 | } | ||
334 | |||
335 | mtu = IPV6_MIN_MTU; | ||
336 | rcu_read_lock(); | ||
337 | idev = __in6_dev_get(dst->dev); | ||
338 | if (idev) | ||
339 | mtu = idev->cnf.mtu6; | ||
340 | rcu_read_unlock(); | ||
341 | |||
342 | return mtu; | ||
343 | } | ||
344 | |||
324 | int ip6_forward(struct sk_buff *skb) | 345 | int ip6_forward(struct sk_buff *skb) |
325 | { | 346 | { |
326 | struct dst_entry *dst = skb_dst(skb); | 347 | struct dst_entry *dst = skb_dst(skb); |
@@ -336,7 +357,8 @@ int ip6_forward(struct sk_buff *skb) | |||
336 | goto drop; | 357 | goto drop; |
337 | 358 | ||
338 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) { | 359 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) { |
339 | IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS); | 360 | IP6_INC_STATS_BH(net, ip6_dst_idev(dst), |
361 | IPSTATS_MIB_INDISCARDS); | ||
340 | goto drop; | 362 | goto drop; |
341 | } | 363 | } |
342 | 364 | ||
@@ -370,8 +392,8 @@ int ip6_forward(struct sk_buff *skb) | |||
370 | /* Force OUTPUT device used as source address */ | 392 | /* Force OUTPUT device used as source address */ |
371 | skb->dev = dst->dev; | 393 | skb->dev = dst->dev; |
372 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, 0); | 394 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, 0); |
373 | IP6_INC_STATS_BH(net, | 395 | IP6_INC_STATS_BH(net, ip6_dst_idev(dst), |
374 | ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS); | 396 | IPSTATS_MIB_INHDRERRORS); |
375 | 397 | ||
376 | kfree_skb(skb); | 398 | kfree_skb(skb); |
377 | return -ETIMEDOUT; | 399 | return -ETIMEDOUT; |
@@ -384,14 +406,15 @@ int ip6_forward(struct sk_buff *skb) | |||
384 | if (proxied > 0) | 406 | if (proxied > 0) |
385 | return ip6_input(skb); | 407 | return ip6_input(skb); |
386 | else if (proxied < 0) { | 408 | else if (proxied < 0) { |
387 | IP6_INC_STATS(net, ip6_dst_idev(dst), | 409 | IP6_INC_STATS_BH(net, ip6_dst_idev(dst), |
388 | IPSTATS_MIB_INDISCARDS); | 410 | IPSTATS_MIB_INDISCARDS); |
389 | goto drop; | 411 | goto drop; |
390 | } | 412 | } |
391 | } | 413 | } |
392 | 414 | ||
393 | if (!xfrm6_route_forward(skb)) { | 415 | if (!xfrm6_route_forward(skb)) { |
394 | IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS); | 416 | IP6_INC_STATS_BH(net, ip6_dst_idev(dst), |
417 | IPSTATS_MIB_INDISCARDS); | ||
395 | goto drop; | 418 | goto drop; |
396 | } | 419 | } |
397 | dst = skb_dst(skb); | 420 | dst = skb_dst(skb); |
@@ -439,7 +462,7 @@ int ip6_forward(struct sk_buff *skb) | |||
439 | } | 462 | } |
440 | } | 463 | } |
441 | 464 | ||
442 | mtu = dst_mtu(dst); | 465 | mtu = ip6_dst_mtu_forward(dst); |
443 | if (mtu < IPV6_MIN_MTU) | 466 | if (mtu < IPV6_MIN_MTU) |
444 | mtu = IPV6_MIN_MTU; | 467 | mtu = IPV6_MIN_MTU; |
445 | 468 | ||
@@ -448,16 +471,17 @@ int ip6_forward(struct sk_buff *skb) | |||
448 | /* Again, force OUTPUT device used as source address */ | 471 | /* Again, force OUTPUT device used as source address */ |
449 | skb->dev = dst->dev; | 472 | skb->dev = dst->dev; |
450 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); | 473 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
451 | IP6_INC_STATS_BH(net, | 474 | IP6_INC_STATS_BH(net, ip6_dst_idev(dst), |
452 | ip6_dst_idev(dst), IPSTATS_MIB_INTOOBIGERRORS); | 475 | IPSTATS_MIB_INTOOBIGERRORS); |
453 | IP6_INC_STATS_BH(net, | 476 | IP6_INC_STATS_BH(net, ip6_dst_idev(dst), |
454 | ip6_dst_idev(dst), IPSTATS_MIB_FRAGFAILS); | 477 | IPSTATS_MIB_FRAGFAILS); |
455 | kfree_skb(skb); | 478 | kfree_skb(skb); |
456 | return -EMSGSIZE; | 479 | return -EMSGSIZE; |
457 | } | 480 | } |
458 | 481 | ||
459 | if (skb_cow(skb, dst->dev->hard_header_len)) { | 482 | if (skb_cow(skb, dst->dev->hard_header_len)) { |
460 | IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTDISCARDS); | 483 | IP6_INC_STATS_BH(net, ip6_dst_idev(dst), |
484 | IPSTATS_MIB_OUTDISCARDS); | ||
461 | goto drop; | 485 | goto drop; |
462 | } | 486 | } |
463 | 487 | ||
@@ -938,7 +962,6 @@ EXPORT_SYMBOL_GPL(ip6_dst_lookup); | |||
938 | * @sk: socket which provides route info | 962 | * @sk: socket which provides route info |
939 | * @fl6: flow to lookup | 963 | * @fl6: flow to lookup |
940 | * @final_dst: final destination address for ipsec lookup | 964 | * @final_dst: final destination address for ipsec lookup |
941 | * @can_sleep: we are in a sleepable context | ||
942 | * | 965 | * |
943 | * This function performs a route lookup on the given flow. | 966 | * This function performs a route lookup on the given flow. |
944 | * | 967 | * |
@@ -946,8 +969,7 @@ EXPORT_SYMBOL_GPL(ip6_dst_lookup); | |||
946 | * error code. | 969 | * error code. |
947 | */ | 970 | */ |
948 | struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, | 971 | struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, |
949 | const struct in6_addr *final_dst, | 972 | const struct in6_addr *final_dst) |
950 | bool can_sleep) | ||
951 | { | 973 | { |
952 | struct dst_entry *dst = NULL; | 974 | struct dst_entry *dst = NULL; |
953 | int err; | 975 | int err; |
@@ -957,8 +979,6 @@ struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, | |||
957 | return ERR_PTR(err); | 979 | return ERR_PTR(err); |
958 | if (final_dst) | 980 | if (final_dst) |
959 | fl6->daddr = *final_dst; | 981 | fl6->daddr = *final_dst; |
960 | if (can_sleep) | ||
961 | fl6->flowi6_flags |= FLOWI_FLAG_CAN_SLEEP; | ||
962 | 982 | ||
963 | return xfrm_lookup(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0); | 983 | return xfrm_lookup(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0); |
964 | } | 984 | } |
@@ -969,7 +989,6 @@ EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow); | |||
969 | * @sk: socket which provides the dst cache and route info | 989 | * @sk: socket which provides the dst cache and route info |
970 | * @fl6: flow to lookup | 990 | * @fl6: flow to lookup |
971 | * @final_dst: final destination address for ipsec lookup | 991 | * @final_dst: final destination address for ipsec lookup |
972 | * @can_sleep: we are in a sleepable context | ||
973 | * | 992 | * |
974 | * This function performs a route lookup on the given flow with the | 993 | * This function performs a route lookup on the given flow with the |
975 | * possibility of using the cached route in the socket if it is valid. | 994 | * possibility of using the cached route in the socket if it is valid. |
@@ -980,8 +999,7 @@ EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow); | |||
980 | * error code. | 999 | * error code. |
981 | */ | 1000 | */ |
982 | struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, | 1001 | struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, |
983 | const struct in6_addr *final_dst, | 1002 | const struct in6_addr *final_dst) |
984 | bool can_sleep) | ||
985 | { | 1003 | { |
986 | struct dst_entry *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie); | 1004 | struct dst_entry *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie); |
987 | int err; | 1005 | int err; |
@@ -993,8 +1011,6 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, | |||
993 | return ERR_PTR(err); | 1011 | return ERR_PTR(err); |
994 | if (final_dst) | 1012 | if (final_dst) |
995 | fl6->daddr = *final_dst; | 1013 | fl6->daddr = *final_dst; |
996 | if (can_sleep) | ||
997 | fl6->flowi6_flags |= FLOWI_FLAG_CAN_SLEEP; | ||
998 | 1014 | ||
999 | return xfrm_lookup(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0); | 1015 | return xfrm_lookup(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0); |
1000 | } | 1016 | } |
@@ -1162,10 +1178,10 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
1162 | np->cork.hop_limit = hlimit; | 1178 | np->cork.hop_limit = hlimit; |
1163 | np->cork.tclass = tclass; | 1179 | np->cork.tclass = tclass; |
1164 | if (rt->dst.flags & DST_XFRM_TUNNEL) | 1180 | if (rt->dst.flags & DST_XFRM_TUNNEL) |
1165 | mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ? | 1181 | mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ? |
1166 | rt->dst.dev->mtu : dst_mtu(&rt->dst); | 1182 | rt->dst.dev->mtu : dst_mtu(&rt->dst); |
1167 | else | 1183 | else |
1168 | mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ? | 1184 | mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ? |
1169 | rt->dst.dev->mtu : dst_mtu(rt->dst.path); | 1185 | rt->dst.dev->mtu : dst_mtu(rt->dst.path); |
1170 | if (np->frag_size < mtu) { | 1186 | if (np->frag_size < mtu) { |
1171 | if (np->frag_size) | 1187 | if (np->frag_size) |
@@ -1285,7 +1301,7 @@ alloc_new_skb: | |||
1285 | if (skb == NULL || skb_prev == NULL) | 1301 | if (skb == NULL || skb_prev == NULL) |
1286 | ip6_append_data_mtu(&mtu, &maxfraglen, | 1302 | ip6_append_data_mtu(&mtu, &maxfraglen, |
1287 | fragheaderlen, skb, rt, | 1303 | fragheaderlen, skb, rt, |
1288 | np->pmtudisc == | 1304 | np->pmtudisc >= |
1289 | IPV6_PMTUDISC_PROBE); | 1305 | IPV6_PMTUDISC_PROBE); |
1290 | 1306 | ||
1291 | skb_prev = skb; | 1307 | skb_prev = skb; |