Commit 47c1a9a4 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'ipv6-kfree_skb_reason'



Menglong Dong says:

====================
net: use kfree_skb_reason() for ip/udp packet receive

In this series patches, kfree_skb() is replaced with kfree_skb_reason()
during ipv4 and udp4 packet receiving path, and following drop reasons
are introduced:

SKB_DROP_REASON_SOCKET_FILTER
SKB_DROP_REASON_NETFILTER_DROP
SKB_DROP_REASON_OTHERHOST
SKB_DROP_REASON_IP_CSUM
SKB_DROP_REASON_IP_INHDR
SKB_DROP_REASON_IP_RPFILTER
SKB_DROP_REASON_UNICAST_IN_L2_MULTICAST
SKB_DROP_REASON_XFRM_POLICY
SKB_DROP_REASON_IP_NOPROTO
SKB_DROP_REASON_SOCKET_RCVBUFF
SKB_DROP_REASON_PROTO_MEM

TCP is more complex, so I left it in the next series.

I just figure out how __print_symbolic() works. It doesn't base on the
array index, but searching for symbols by loop. So I'm a little afraid
it's performance.

Changes since v3:
- fix some small problems in the third patch (net: ipv4: use
  kfree_skb_reason() in ip_rcv_core()), as David Ahern said

Changes since v2:
- use SKB_DROP_REASON_PKT_TOO_SMALL for a path in ip_rcv_core()

Changes since v1:
- add document for all drop reasons, as David advised
- remove unreleated cleanup
- remove EARLY_DEMUX and IP_ROUTE_INPUT drop reason
- replace {UDP, TCP}_FILTER with SOCKET_FILTER
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents c2d1e3df 08d4c037
Loading
Loading
Loading
Loading
+32 −6
Original line number Diff line number Diff line
@@ -314,12 +314,38 @@ struct sk_buff;
 * used to translate the reason to string.
 */
enum skb_drop_reason {
	SKB_DROP_REASON_NOT_SPECIFIED,
	SKB_DROP_REASON_NO_SOCKET,
	SKB_DROP_REASON_PKT_TOO_SMALL,
	SKB_DROP_REASON_TCP_CSUM,
	SKB_DROP_REASON_SOCKET_FILTER,
	SKB_DROP_REASON_UDP_CSUM,
	SKB_DROP_REASON_NOT_SPECIFIED,	/* drop reason is not specified */
	SKB_DROP_REASON_NO_SOCKET,	/* socket not found */
	SKB_DROP_REASON_PKT_TOO_SMALL,	/* packet size is too small */
	SKB_DROP_REASON_TCP_CSUM,	/* TCP checksum error */
	SKB_DROP_REASON_SOCKET_FILTER,	/* dropped by socket filter */
	SKB_DROP_REASON_UDP_CSUM,	/* UDP checksum error */
	SKB_DROP_REASON_NETFILTER_DROP,	/* dropped by netfilter */
	SKB_DROP_REASON_OTHERHOST,	/* packet don't belong to current
					 * host (interface is in promisc
					 * mode)
					 */
	SKB_DROP_REASON_IP_CSUM,	/* IP checksum error */
	SKB_DROP_REASON_IP_INHDR,	/* there is something wrong with
					 * IP header (see
					 * IPSTATS_MIB_INHDRERRORS)
					 */
	SKB_DROP_REASON_IP_RPFILTER,	/* IP rpfilter validate failed.
					 * see the document for rp_filter
					 * in ip-sysctl.rst for more
					 * information
					 */
	SKB_DROP_REASON_UNICAST_IN_L2_MULTICAST, /* destination address of L2
						  * is multicast, but L3 is
						  * unicast.
						  */
	SKB_DROP_REASON_XFRM_POLICY,	/* xfrm policy check failed */
	SKB_DROP_REASON_IP_NOPROTO,	/* no support for IP protocol */
	SKB_DROP_REASON_SOCKET_RCVBUFF,	/* socket receive buff is full */
	SKB_DROP_REASON_PROTO_MEM,	/* proto memory limition, such as
					 * udp packet drop out of
					 * udp_memory_allocated.
					 */
	SKB_DROP_REASON_MAX,
};

+11 −0
Original line number Diff line number Diff line
@@ -16,6 +16,17 @@
	EM(SKB_DROP_REASON_TCP_CSUM, TCP_CSUM)			\
	EM(SKB_DROP_REASON_SOCKET_FILTER, SOCKET_FILTER)	\
	EM(SKB_DROP_REASON_UDP_CSUM, UDP_CSUM)			\
	EM(SKB_DROP_REASON_NETFILTER_DROP, NETFILTER_DROP)	\
	EM(SKB_DROP_REASON_OTHERHOST, OTHERHOST)		\
	EM(SKB_DROP_REASON_IP_CSUM, IP_CSUM)			\
	EM(SKB_DROP_REASON_IP_INHDR, IP_INHDR)			\
	EM(SKB_DROP_REASON_IP_RPFILTER, IP_RPFILTER)		\
	EM(SKB_DROP_REASON_UNICAST_IN_L2_MULTICAST,		\
	   UNICAST_IN_L2_MULTICAST)				\
	EM(SKB_DROP_REASON_XFRM_POLICY, XFRM_POLICY)		\
	EM(SKB_DROP_REASON_IP_NOPROTO, IP_NOPROTO)		\
	EM(SKB_DROP_REASON_SOCKET_RCVBUFF, SOCKET_RCVBUFF)	\
	EM(SKB_DROP_REASON_PROTO_MEM, PROTO_MEM)		\
	EMe(SKB_DROP_REASON_MAX, MAX)

#undef EM
+23 −8
Original line number Diff line number Diff line
@@ -196,7 +196,8 @@ void ip_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int protocol)
	if (ipprot) {
		if (!ipprot->no_policy) {
			if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
				kfree_skb(skb);
				kfree_skb_reason(skb,
						 SKB_DROP_REASON_XFRM_POLICY);
				return;
			}
			nf_reset_ct(skb);
@@ -215,7 +216,7 @@ void ip_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int protocol)
				icmp_send(skb, ICMP_DEST_UNREACH,
					  ICMP_PROT_UNREACH, 0);
			}
			kfree_skb(skb);
			kfree_skb_reason(skb, SKB_DROP_REASON_IP_NOPROTO);
		} else {
			__IP_INC_STATS(net, IPSTATS_MIB_INDELIVERS);
			consume_skb(skb);
@@ -318,8 +319,10 @@ static int ip_rcv_finish_core(struct net *net, struct sock *sk,
{
	const struct iphdr *iph = ip_hdr(skb);
	int (*edemux)(struct sk_buff *skb);
	int err, drop_reason;
	struct rtable *rt;
	int err;

	drop_reason = SKB_DROP_REASON_NOT_SPECIFIED;

	if (ip_can_use_hint(skb, iph, hint)) {
		err = ip_route_use_hint(skb, iph->daddr, iph->saddr, iph->tos,
@@ -396,19 +399,23 @@ static int ip_rcv_finish_core(struct net *net, struct sock *sk,
		 * so-called "hole-196" attack) so do it for both.
		 */
		if (in_dev &&
		    IN_DEV_ORCONF(in_dev, DROP_UNICAST_IN_L2_MULTICAST))
		    IN_DEV_ORCONF(in_dev, DROP_UNICAST_IN_L2_MULTICAST)) {
			drop_reason = SKB_DROP_REASON_UNICAST_IN_L2_MULTICAST;
			goto drop;
		}
	}

	return NET_RX_SUCCESS;

drop:
	kfree_skb(skb);
	kfree_skb_reason(skb, drop_reason);
	return NET_RX_DROP;

drop_error:
	if (err == -EXDEV)
	if (err == -EXDEV) {
		drop_reason = SKB_DROP_REASON_IP_RPFILTER;
		__NET_INC_STATS(net, LINUX_MIB_IPRPFILTER);
	}
	goto drop;
}

@@ -436,13 +443,16 @@ static int ip_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
static struct sk_buff *ip_rcv_core(struct sk_buff *skb, struct net *net)
{
	const struct iphdr *iph;
	int drop_reason;
	u32 len;

	/* When the interface is in promisc. mode, drop all the crap
	 * that it receives, do not try to analyse it.
	 */
	if (skb->pkt_type == PACKET_OTHERHOST)
	if (skb->pkt_type == PACKET_OTHERHOST) {
		drop_reason = SKB_DROP_REASON_OTHERHOST;
		goto drop;
	}

	__IP_UPD_PO_STATS(net, IPSTATS_MIB_IN, skb->len);

@@ -452,6 +462,7 @@ static struct sk_buff *ip_rcv_core(struct sk_buff *skb, struct net *net)
		goto out;
	}

	drop_reason = SKB_DROP_REASON_NOT_SPECIFIED;
	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
		goto inhdr_error;

@@ -488,6 +499,7 @@ static struct sk_buff *ip_rcv_core(struct sk_buff *skb, struct net *net)

	len = ntohs(iph->tot_len);
	if (skb->len < len) {
		drop_reason = SKB_DROP_REASON_PKT_TOO_SMALL;
		__IP_INC_STATS(net, IPSTATS_MIB_INTRUNCATEDPKTS);
		goto drop;
	} else if (len < (iph->ihl*4))
@@ -516,11 +528,14 @@ static struct sk_buff *ip_rcv_core(struct sk_buff *skb, struct net *net)
	return skb;

csum_error:
	drop_reason = SKB_DROP_REASON_IP_CSUM;
	__IP_INC_STATS(net, IPSTATS_MIB_CSUMERRORS);
inhdr_error:
	if (drop_reason == SKB_DROP_REASON_NOT_SPECIFIED)
		drop_reason = SKB_DROP_REASON_IP_INHDR;
	__IP_INC_STATS(net, IPSTATS_MIB_INHDRERRORS);
drop:
	kfree_skb(skb);
	kfree_skb_reason(skb, drop_reason);
out:
	return NULL;
}
+16 −6
Original line number Diff line number Diff line
@@ -2093,16 +2093,20 @@ static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
	rc = __udp_enqueue_schedule_skb(sk, skb);
	if (rc < 0) {
		int is_udplite = IS_UDPLITE(sk);
		int drop_reason;

		/* Note that an ENOMEM error is charged twice */
		if (rc == -ENOMEM)
		if (rc == -ENOMEM) {
			UDP_INC_STATS(sock_net(sk), UDP_MIB_RCVBUFERRORS,
					is_udplite);
		else
			drop_reason = SKB_DROP_REASON_SOCKET_RCVBUFF;
		} else {
			UDP_INC_STATS(sock_net(sk), UDP_MIB_MEMERRORS,
				      is_udplite);
			drop_reason = SKB_DROP_REASON_PROTO_MEM;
		}
		UDP_INC_STATS(sock_net(sk), UDP_MIB_INERRORS, is_udplite);
		kfree_skb(skb);
		kfree_skb_reason(skb, drop_reason);
		trace_udp_fail_queue_rcv_skb(rc, sk);
		return -1;
	}
@@ -2120,14 +2124,17 @@ static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 */
static int udp_queue_rcv_one_skb(struct sock *sk, struct sk_buff *skb)
{
	int drop_reason = SKB_DROP_REASON_NOT_SPECIFIED;
	struct udp_sock *up = udp_sk(sk);
	int is_udplite = IS_UDPLITE(sk);

	/*
	 *	Charge it to the socket, dropping if the queue is full.
	 */
	if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb))
	if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) {
		drop_reason = SKB_DROP_REASON_XFRM_POLICY;
		goto drop;
	}
	nf_reset_ct(skb);

	if (static_branch_unlikely(&udp_encap_needed_key) && up->encap_type) {
@@ -2204,8 +2211,10 @@ static int udp_queue_rcv_one_skb(struct sock *sk, struct sk_buff *skb)
	    udp_lib_checksum_complete(skb))
			goto csum_error;

	if (sk_filter_trim_cap(sk, skb, sizeof(struct udphdr)))
	if (sk_filter_trim_cap(sk, skb, sizeof(struct udphdr))) {
		drop_reason = SKB_DROP_REASON_SOCKET_FILTER;
		goto drop;
	}

	udp_csum_pull_header(skb);

@@ -2213,11 +2222,12 @@ static int udp_queue_rcv_one_skb(struct sock *sk, struct sk_buff *skb)
	return __udp_queue_rcv_skb(sk, skb);

csum_error:
	drop_reason = SKB_DROP_REASON_UDP_CSUM;
	__UDP_INC_STATS(sock_net(sk), UDP_MIB_CSUMERRORS, is_udplite);
drop:
	__UDP_INC_STATS(sock_net(sk), UDP_MIB_INERRORS, is_udplite);
	atomic_inc(&sk->sk_drops);
	kfree_skb(skb);
	kfree_skb_reason(skb, drop_reason);
	return -1;
}

+2 −1
Original line number Diff line number Diff line
@@ -621,7 +621,8 @@ int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state,
		case NF_ACCEPT:
			break;
		case NF_DROP:
			kfree_skb(skb);
			kfree_skb_reason(skb,
					 SKB_DROP_REASON_NETFILTER_DROP);
			ret = NF_DROP_GETERR(verdict);
			if (ret == 0)
				ret = -EPERM;