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>
This commit is contained in:
parent
54aeba7f06
commit
e3e3217029
|
@ -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);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
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)
|
||||||
* 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)
|
||||||
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 @@ out_err:
|
||||||
* 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)
|
||||||
* 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)
|
||||||
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)
|
||||||
* 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)
|
||||||
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
* 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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user