提交 e3e32170 编写于 作者: R Rick Jones 提交者: David S. Miller

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: NRick Jones <rick.jones2@hp.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 54aeba7f
...@@ -82,7 +82,7 @@ int ping_common_sendmsg(int family, struct msghdr *msg, size_t len, ...@@ -82,7 +82,7 @@ int ping_common_sendmsg(int family, struct msghdr *msg, size_t len,
int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
size_t len); size_t len);
int ping_queue_rcv_skb(struct sock *sk, struct sk_buff *skb); int ping_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
void ping_rcv(struct sk_buff *skb); bool ping_rcv(struct sk_buff *skb);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
struct ping_seq_afinfo { struct ping_seq_afinfo {
......
...@@ -190,7 +190,7 @@ EXPORT_SYMBOL(icmp_err_convert); ...@@ -190,7 +190,7 @@ EXPORT_SYMBOL(icmp_err_convert);
*/ */
struct icmp_control { struct icmp_control {
void (*handler)(struct sk_buff *skb); bool (*handler)(struct sk_buff *skb);
short error; /* This ICMP is classed as an error message */ short error; /* This ICMP is classed as an error message */
}; };
...@@ -746,7 +746,7 @@ static bool icmp_tag_validation(int proto) ...@@ -746,7 +746,7 @@ static bool icmp_tag_validation(int proto)
* ICMP_PARAMETERPROB. * ICMP_PARAMETERPROB.
*/ */
static void icmp_unreach(struct sk_buff *skb) static bool icmp_unreach(struct sk_buff *skb)
{ {
const struct iphdr *iph; const struct iphdr *iph;
struct icmphdr *icmph; struct icmphdr *icmph;
...@@ -839,10 +839,10 @@ static void icmp_unreach(struct sk_buff *skb) ...@@ -839,10 +839,10 @@ static void icmp_unreach(struct sk_buff *skb)
icmp_socket_deliver(skb, info); icmp_socket_deliver(skb, info);
out: out:
return; return true;
out_err: out_err:
ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS); ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS);
goto out; return false;
} }
...@@ -850,17 +850,20 @@ static void icmp_unreach(struct sk_buff *skb) ...@@ -850,17 +850,20 @@ static void icmp_unreach(struct sk_buff *skb)
* Handle ICMP_REDIRECT. * Handle ICMP_REDIRECT.
*/ */
static void icmp_redirect(struct sk_buff *skb) static bool icmp_redirect(struct sk_buff *skb)
{ {
if (skb->len < sizeof(struct iphdr)) { if (skb->len < sizeof(struct iphdr)) {
ICMP_INC_STATS_BH(dev_net(skb->dev), ICMP_MIB_INERRORS); ICMP_INC_STATS_BH(dev_net(skb->dev), ICMP_MIB_INERRORS);
return; return false;
} }
if (!pskb_may_pull(skb, sizeof(struct iphdr))) if (!pskb_may_pull(skb, sizeof(struct iphdr))) {
return; /* there aught to be a stat */
return false;
}
icmp_socket_deliver(skb, icmp_hdr(skb)->un.gateway); icmp_socket_deliver(skb, icmp_hdr(skb)->un.gateway);
return true;
} }
/* /*
...@@ -875,7 +878,7 @@ static void icmp_redirect(struct sk_buff *skb) ...@@ -875,7 +878,7 @@ static void icmp_redirect(struct sk_buff *skb)
* See also WRT handling of options once they are done and working. * See also WRT handling of options once they are done and working.
*/ */
static void icmp_echo(struct sk_buff *skb) static bool icmp_echo(struct sk_buff *skb)
{ {
struct net *net; struct net *net;
...@@ -891,6 +894,8 @@ static void icmp_echo(struct sk_buff *skb) ...@@ -891,6 +894,8 @@ static void icmp_echo(struct sk_buff *skb)
icmp_param.head_len = sizeof(struct icmphdr); icmp_param.head_len = sizeof(struct icmphdr);
icmp_reply(&icmp_param, skb); icmp_reply(&icmp_param, skb);
} }
/* should there be an ICMP stat for ignored echos? */
return true;
} }
/* /*
...@@ -900,7 +905,7 @@ static void icmp_echo(struct sk_buff *skb) ...@@ -900,7 +905,7 @@ static void icmp_echo(struct sk_buff *skb)
* MUST be accurate to a few minutes. * MUST be accurate to a few minutes.
* MUST be updated at least at 15Hz. * MUST be updated at least at 15Hz.
*/ */
static void icmp_timestamp(struct sk_buff *skb) static bool icmp_timestamp(struct sk_buff *skb)
{ {
struct timespec tv; struct timespec tv;
struct icmp_bxm icmp_param; struct icmp_bxm icmp_param;
...@@ -927,15 +932,17 @@ static void icmp_timestamp(struct sk_buff *skb) ...@@ -927,15 +932,17 @@ static void icmp_timestamp(struct sk_buff *skb)
icmp_param.data_len = 0; icmp_param.data_len = 0;
icmp_param.head_len = sizeof(struct icmphdr) + 12; icmp_param.head_len = sizeof(struct icmphdr) + 12;
icmp_reply(&icmp_param, skb); icmp_reply(&icmp_param, skb);
out: return true;
return;
out_err: out_err:
ICMP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), ICMP_MIB_INERRORS); ICMP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), ICMP_MIB_INERRORS);
goto out; return false;
} }
static void icmp_discard(struct sk_buff *skb) static bool icmp_discard(struct sk_buff *skb)
{ {
/* pretend it was a success */
return true;
} }
/* /*
...@@ -946,6 +953,7 @@ int icmp_rcv(struct sk_buff *skb) ...@@ -946,6 +953,7 @@ int icmp_rcv(struct sk_buff *skb)
struct icmphdr *icmph; struct icmphdr *icmph;
struct rtable *rt = skb_rtable(skb); struct rtable *rt = skb_rtable(skb);
struct net *net = dev_net(rt->dst.dev); struct net *net = dev_net(rt->dst.dev);
bool success;
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
struct sec_path *sp = skb_sec_path(skb); struct sec_path *sp = skb_sec_path(skb);
...@@ -1012,7 +1020,12 @@ int icmp_rcv(struct sk_buff *skb) ...@@ -1012,7 +1020,12 @@ int icmp_rcv(struct sk_buff *skb)
} }
} }
icmp_pointers[icmph->type].handler(skb); success = icmp_pointers[icmph->type].handler(skb);
if (success) {
consume_skb(skb);
return 0;
}
drop: drop:
kfree_skb(skb); kfree_skb(skb);
......
...@@ -955,7 +955,7 @@ EXPORT_SYMBOL_GPL(ping_queue_rcv_skb); ...@@ -955,7 +955,7 @@ EXPORT_SYMBOL_GPL(ping_queue_rcv_skb);
* All we need to do is get the socket. * All we need to do is get the socket.
*/ */
void ping_rcv(struct sk_buff *skb) bool ping_rcv(struct sk_buff *skb)
{ {
struct sock *sk; struct sock *sk;
struct net *net = dev_net(skb->dev); struct net *net = dev_net(skb->dev);
...@@ -974,11 +974,11 @@ void ping_rcv(struct sk_buff *skb) ...@@ -974,11 +974,11 @@ void ping_rcv(struct sk_buff *skb)
pr_debug("rcv on socket %p\n", sk); pr_debug("rcv on socket %p\n", sk);
ping_queue_rcv_skb(sk, skb_get(skb)); ping_queue_rcv_skb(sk, skb_get(skb));
sock_put(sk); sock_put(sk);
return; return true;
} }
pr_debug("no socket, dropping\n"); pr_debug("no socket, dropping\n");
/* We're called from icmp_rcv(). kfree_skb() is done there. */ return false;
} }
EXPORT_SYMBOL_GPL(ping_rcv); EXPORT_SYMBOL_GPL(ping_rcv);
......
...@@ -679,6 +679,7 @@ static int icmpv6_rcv(struct sk_buff *skb) ...@@ -679,6 +679,7 @@ static int icmpv6_rcv(struct sk_buff *skb)
const struct in6_addr *saddr, *daddr; const struct in6_addr *saddr, *daddr;
struct icmp6hdr *hdr; struct icmp6hdr *hdr;
u8 type; u8 type;
bool success = false;
if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
struct sec_path *sp = skb_sec_path(skb); struct sec_path *sp = skb_sec_path(skb);
...@@ -726,7 +727,7 @@ static int icmpv6_rcv(struct sk_buff *skb) ...@@ -726,7 +727,7 @@ static int icmpv6_rcv(struct sk_buff *skb)
break; break;
case ICMPV6_ECHO_REPLY: case ICMPV6_ECHO_REPLY:
ping_rcv(skb); success = ping_rcv(skb);
break; break;
case ICMPV6_PKT_TOOBIG: case ICMPV6_PKT_TOOBIG:
...@@ -790,7 +791,14 @@ static int icmpv6_rcv(struct sk_buff *skb) ...@@ -790,7 +791,14 @@ static int icmpv6_rcv(struct sk_buff *skb)
icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu); icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
} }
kfree_skb(skb); /* until the v6 path can be better sorted assume failure and
* preserve the status quo behaviour for the rest of the paths to here
*/
if (success)
consume_skb(skb);
else
kfree_skb(skb);
return 0; return 0;
csum_error: csum_error:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册