diff options
author | Rick Jones <rick.jones2@hp.com> | 2014-11-17 17:04:29 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-11-18 15:28:28 -0500 |
commit | e3e3217029a35c579bf100998b43976d0b1cb8d7 (patch) | |
tree | dc2e5073002588cea3bb600e9df7d8de00359d86 | |
parent | 54aeba7f06323e04d59a6053ee3c6023079667b2 (diff) |
icmp: Remove some spurious dropped packet profile hits from the ICMP path
If icmp_rcv() has successfully processed the incoming ICMP datagram, we
should use consume_skb() rather than kfree_skb() because a hit on the likes
of perf -e skb:kfree_skb is not called-for.
Signed-off-by: Rick Jones <rick.jones2@hp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/ping.h | 2 | ||||
-rw-r--r-- | net/ipv4/icmp.c | 43 | ||||
-rw-r--r-- | net/ipv4/ping.c | 6 | ||||
-rw-r--r-- | net/ipv6/icmp.c | 12 |
4 files changed, 42 insertions, 21 deletions
diff --git a/include/net/ping.h b/include/net/ping.h index 026479b61a2d..f074060bc5de 100644 --- a/include/net/ping.h +++ b/include/net/ping.h | |||
@@ -82,7 +82,7 @@ int ping_common_sendmsg(int family, struct msghdr *msg, size_t len, | |||
82 | int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | 82 | int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, |
83 | size_t len); | 83 | size_t len); |
84 | int ping_queue_rcv_skb(struct sock *sk, struct sk_buff *skb); | 84 | int ping_queue_rcv_skb(struct sock *sk, struct sk_buff *skb); |
85 | void ping_rcv(struct sk_buff *skb); | 85 | bool ping_rcv(struct sk_buff *skb); |
86 | 86 | ||
87 | #ifdef CONFIG_PROC_FS | 87 | #ifdef CONFIG_PROC_FS |
88 | struct ping_seq_afinfo { | 88 | struct ping_seq_afinfo { |
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 36b7bfa609d6..36f5584d93c5 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c | |||
@@ -190,7 +190,7 @@ EXPORT_SYMBOL(icmp_err_convert); | |||
190 | */ | 190 | */ |
191 | 191 | ||
192 | struct icmp_control { | 192 | struct icmp_control { |
193 | void (*handler)(struct sk_buff *skb); | 193 | bool (*handler)(struct sk_buff *skb); |
194 | short error; /* This ICMP is classed as an error message */ | 194 | short error; /* This ICMP is classed as an error message */ |
195 | }; | 195 | }; |
196 | 196 | ||
@@ -746,7 +746,7 @@ static bool icmp_tag_validation(int proto) | |||
746 | * ICMP_PARAMETERPROB. | 746 | * ICMP_PARAMETERPROB. |
747 | */ | 747 | */ |
748 | 748 | ||
749 | static void icmp_unreach(struct sk_buff *skb) | 749 | static bool icmp_unreach(struct sk_buff *skb) |
750 | { | 750 | { |
751 | const struct iphdr *iph; | 751 | const struct iphdr *iph; |
752 | struct icmphdr *icmph; | 752 | struct icmphdr *icmph; |
@@ -839,10 +839,10 @@ static void icmp_unreach(struct sk_buff *skb) | |||
839 | icmp_socket_deliver(skb, info); | 839 | icmp_socket_deliver(skb, info); |
840 | 840 | ||
841 | out: | 841 | out: |
842 | return; | 842 | return true; |
843 | out_err: | 843 | out_err: |
844 | ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS); | 844 | ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS); |
845 | goto out; | 845 | return false; |
846 | } | 846 | } |
847 | 847 | ||
848 | 848 | ||
@@ -850,17 +850,20 @@ out_err: | |||
850 | * Handle ICMP_REDIRECT. | 850 | * Handle ICMP_REDIRECT. |
851 | */ | 851 | */ |
852 | 852 | ||
853 | static void icmp_redirect(struct sk_buff *skb) | 853 | static bool icmp_redirect(struct sk_buff *skb) |
854 | { | 854 | { |
855 | if (skb->len < sizeof(struct iphdr)) { | 855 | if (skb->len < sizeof(struct iphdr)) { |
856 | ICMP_INC_STATS_BH(dev_net(skb->dev), ICMP_MIB_INERRORS); | 856 | ICMP_INC_STATS_BH(dev_net(skb->dev), ICMP_MIB_INERRORS); |
857 | return; | 857 | return false; |
858 | } | 858 | } |
859 | 859 | ||
860 | if (!pskb_may_pull(skb, sizeof(struct iphdr))) | 860 | if (!pskb_may_pull(skb, sizeof(struct iphdr))) { |
861 | return; | 861 | /* there aught to be a stat */ |
862 | return false; | ||
863 | } | ||
862 | 864 | ||
863 | icmp_socket_deliver(skb, icmp_hdr(skb)->un.gateway); | 865 | icmp_socket_deliver(skb, icmp_hdr(skb)->un.gateway); |
866 | return true; | ||
864 | } | 867 | } |
865 | 868 | ||
866 | /* | 869 | /* |
@@ -875,7 +878,7 @@ static void icmp_redirect(struct sk_buff *skb) | |||
875 | * See also WRT handling of options once they are done and working. | 878 | * See also WRT handling of options once they are done and working. |
876 | */ | 879 | */ |
877 | 880 | ||
878 | static void icmp_echo(struct sk_buff *skb) | 881 | static bool icmp_echo(struct sk_buff *skb) |
879 | { | 882 | { |
880 | struct net *net; | 883 | struct net *net; |
881 | 884 | ||
@@ -891,6 +894,8 @@ static void icmp_echo(struct sk_buff *skb) | |||
891 | icmp_param.head_len = sizeof(struct icmphdr); | 894 | icmp_param.head_len = sizeof(struct icmphdr); |
892 | icmp_reply(&icmp_param, skb); | 895 | icmp_reply(&icmp_param, skb); |
893 | } | 896 | } |
897 | /* should there be an ICMP stat for ignored echos? */ | ||
898 | return true; | ||
894 | } | 899 | } |
895 | 900 | ||
896 | /* | 901 | /* |
@@ -900,7 +905,7 @@ static void icmp_echo(struct sk_buff *skb) | |||
900 | * MUST be accurate to a few minutes. | 905 | * MUST be accurate to a few minutes. |
901 | * MUST be updated at least at 15Hz. | 906 | * MUST be updated at least at 15Hz. |
902 | */ | 907 | */ |
903 | static void icmp_timestamp(struct sk_buff *skb) | 908 | static bool icmp_timestamp(struct sk_buff *skb) |
904 | { | 909 | { |
905 | struct timespec tv; | 910 | struct timespec tv; |
906 | struct icmp_bxm icmp_param; | 911 | struct icmp_bxm icmp_param; |
@@ -927,15 +932,17 @@ static void icmp_timestamp(struct sk_buff *skb) | |||
927 | icmp_param.data_len = 0; | 932 | icmp_param.data_len = 0; |
928 | icmp_param.head_len = sizeof(struct icmphdr) + 12; | 933 | icmp_param.head_len = sizeof(struct icmphdr) + 12; |
929 | icmp_reply(&icmp_param, skb); | 934 | icmp_reply(&icmp_param, skb); |
930 | out: | 935 | return true; |
931 | return; | 936 | |
932 | out_err: | 937 | out_err: |
933 | ICMP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), ICMP_MIB_INERRORS); | 938 | ICMP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), ICMP_MIB_INERRORS); |
934 | goto out; | 939 | return false; |
935 | } | 940 | } |
936 | 941 | ||
937 | static void icmp_discard(struct sk_buff *skb) | 942 | static bool icmp_discard(struct sk_buff *skb) |
938 | { | 943 | { |
944 | /* pretend it was a success */ | ||
945 | return true; | ||
939 | } | 946 | } |
940 | 947 | ||
941 | /* | 948 | /* |
@@ -946,6 +953,7 @@ int icmp_rcv(struct sk_buff *skb) | |||
946 | struct icmphdr *icmph; | 953 | struct icmphdr *icmph; |
947 | struct rtable *rt = skb_rtable(skb); | 954 | struct rtable *rt = skb_rtable(skb); |
948 | struct net *net = dev_net(rt->dst.dev); | 955 | struct net *net = dev_net(rt->dst.dev); |
956 | bool success; | ||
949 | 957 | ||
950 | if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { | 958 | if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { |
951 | struct sec_path *sp = skb_sec_path(skb); | 959 | struct sec_path *sp = skb_sec_path(skb); |
@@ -1012,7 +1020,12 @@ int icmp_rcv(struct sk_buff *skb) | |||
1012 | } | 1020 | } |
1013 | } | 1021 | } |
1014 | 1022 | ||
1015 | icmp_pointers[icmph->type].handler(skb); | 1023 | success = icmp_pointers[icmph->type].handler(skb); |
1024 | |||
1025 | if (success) { | ||
1026 | consume_skb(skb); | ||
1027 | return 0; | ||
1028 | } | ||
1016 | 1029 | ||
1017 | drop: | 1030 | drop: |
1018 | kfree_skb(skb); | 1031 | kfree_skb(skb); |
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 736236c3e554..ce2920f5bef3 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c | |||
@@ -955,7 +955,7 @@ EXPORT_SYMBOL_GPL(ping_queue_rcv_skb); | |||
955 | * All we need to do is get the socket. | 955 | * All we need to do is get the socket. |
956 | */ | 956 | */ |
957 | 957 | ||
958 | void ping_rcv(struct sk_buff *skb) | 958 | bool ping_rcv(struct sk_buff *skb) |
959 | { | 959 | { |
960 | struct sock *sk; | 960 | struct sock *sk; |
961 | struct net *net = dev_net(skb->dev); | 961 | struct net *net = dev_net(skb->dev); |
@@ -974,11 +974,11 @@ void ping_rcv(struct sk_buff *skb) | |||
974 | pr_debug("rcv on socket %p\n", sk); | 974 | pr_debug("rcv on socket %p\n", sk); |
975 | ping_queue_rcv_skb(sk, skb_get(skb)); | 975 | ping_queue_rcv_skb(sk, skb_get(skb)); |
976 | sock_put(sk); | 976 | sock_put(sk); |
977 | return; | 977 | return true; |
978 | } | 978 | } |
979 | pr_debug("no socket, dropping\n"); | 979 | pr_debug("no socket, dropping\n"); |
980 | 980 | ||
981 | /* We're called from icmp_rcv(). kfree_skb() is done there. */ | 981 | return false; |
982 | } | 982 | } |
983 | EXPORT_SYMBOL_GPL(ping_rcv); | 983 | EXPORT_SYMBOL_GPL(ping_rcv); |
984 | 984 | ||
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 092934032077..39b3ff97a504 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c | |||
@@ -679,6 +679,7 @@ static int icmpv6_rcv(struct sk_buff *skb) | |||
679 | const struct in6_addr *saddr, *daddr; | 679 | const struct in6_addr *saddr, *daddr; |
680 | struct icmp6hdr *hdr; | 680 | struct icmp6hdr *hdr; |
681 | u8 type; | 681 | u8 type; |
682 | bool success = false; | ||
682 | 683 | ||
683 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { | 684 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { |
684 | struct sec_path *sp = skb_sec_path(skb); | 685 | struct sec_path *sp = skb_sec_path(skb); |
@@ -726,7 +727,7 @@ static int icmpv6_rcv(struct sk_buff *skb) | |||
726 | break; | 727 | break; |
727 | 728 | ||
728 | case ICMPV6_ECHO_REPLY: | 729 | case ICMPV6_ECHO_REPLY: |
729 | ping_rcv(skb); | 730 | success = ping_rcv(skb); |
730 | break; | 731 | break; |
731 | 732 | ||
732 | case ICMPV6_PKT_TOOBIG: | 733 | case ICMPV6_PKT_TOOBIG: |
@@ -790,7 +791,14 @@ static int icmpv6_rcv(struct sk_buff *skb) | |||
790 | icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu); | 791 | icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu); |
791 | } | 792 | } |
792 | 793 | ||
793 | kfree_skb(skb); | 794 | /* until the v6 path can be better sorted assume failure and |
795 | * preserve the status quo behaviour for the rest of the paths to here | ||
796 | */ | ||
797 | if (success) | ||
798 | consume_skb(skb); | ||
799 | else | ||
800 | kfree_skb(skb); | ||
801 | |||
794 | return 0; | 802 | return 0; |
795 | 803 | ||
796 | csum_error: | 804 | csum_error: |