Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e3e32170 authored by Rick Jones's avatar Rick Jones Committed by David S. Miller
Browse files

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: default avatarRick Jones <rick.jones2@hp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 54aeba7f
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -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 {
+28 −15
Original line number Original line Diff line number Diff line
@@ -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);
+3 −3
Original line number Original line Diff line number Diff line
@@ -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);


+10 −2
Original line number Original line Diff line number Diff line
@@ -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);
	}
	}


	/* 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);
		kfree_skb(skb);

	return 0;
	return 0;


csum_error:
csum_error: