diff mbox series

[net-next,06/10] net: vxlan: add skb drop reasons to vxlan_rcv()

Message ID 20240815124302.982711-7-dongml2@chinatelecom.cn (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series net: vxlan: add skb drop reasons support | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net-next
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 72 this patch: 72
netdev/build_tools success Errors and warnings before: 0 this patch: 0
netdev/cc_maintainers success CCed 8 of 8 maintainers
netdev/build_clang success Errors and warnings before: 131 this patch: 131
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 4976 this patch: 4976
netdev/checkpatch warning WARNING: From:/Signed-off-by: email address mismatch: 'From: Menglong Dong <menglong8.dong@gmail.com>' != 'Signed-off-by: Menglong Dong <dongml2@chinatelecom.cn>'
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
netdev/contest success net-next-2024-08-16--21-00 (tests: 710)

Commit Message

Menglong Dong Aug. 15, 2024, 12:42 p.m. UTC
Introduce skb drop reasons to the function vxlan_rcv(). Following new
vxlan drop reasons are added:

  VXLAN_DROP_FLAGS
  VXLAN_DROP_VNI
  VXLAN_DROP_MAC

And Following core skb drop reason is added:

  SKB_DROP_REASON_IP_TUNNEL_ECN

As ip tunnel is a public module, I'm not sure how to deal with it. So I
simply add it to the core drop reasons.

Signed-off-by: Menglong Dong <dongml2@chinatelecom.cn>
---
 drivers/net/vxlan/drop.h       |  3 +++
 drivers/net/vxlan/vxlan_core.c | 35 +++++++++++++++++++++++++---------
 include/net/dropreason-core.h  |  6 ++++++
 3 files changed, 35 insertions(+), 9 deletions(-)

Comments

Jakub Kicinski Aug. 17, 2024, 2:22 a.m. UTC | #1
On Thu, 15 Aug 2024 20:42:58 +0800 Menglong Dong wrote:
>  #define VXLAN_DROP_REASONS(R)			\
> +	R(VXLAN_DROP_FLAGS)			\
> +	R(VXLAN_DROP_VNI)			\
> +	R(VXLAN_DROP_MAC)			\

Drop reasons should be documented.
I don't think name of a header field is a great fit for a reason.

>  	/* deliberate comment for trailing \ */
>  
>  enum vxlan_drop_reason {
> diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
> index e971c4785962..9a61f04bb95d 100644
> --- a/drivers/net/vxlan/vxlan_core.c
> +++ b/drivers/net/vxlan/vxlan_core.c
> @@ -1668,6 +1668,7 @@ static bool vxlan_ecn_decapsulate(struct vxlan_sock *vs, void *oiph,
>  /* Callback from net/ipv4/udp.c to receive packets */
>  static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
>  {
> +	enum skb_drop_reason reason = pskb_may_pull_reason(skb, VXLAN_HLEN);

Do not call complex functions inline as variable init..

>  	struct vxlan_vni_node *vninode = NULL;
>  	struct vxlan_dev *vxlan;
>  	struct vxlan_sock *vs;
> @@ -1681,7 +1682,7 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
>  	int nh;
>  
>  	/* Need UDP and VXLAN header to be present */
> -	if (!pskb_may_pull(skb, VXLAN_HLEN))
> +	if (reason != SKB_NOT_DROPPED_YET)

please don't compare against "not dropped yet", just:

	if (reason)

> @@ -1815,8 +1831,9 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
>  	return 0;
>  
>  drop:
> +	SKB_DR_RESET(reason);

the name of this macro is very confusing, I don't think it should exist
in the first place. nothing should goto drop without initialing reason

>  	/* Consume bad packet */
> -	kfree_skb(skb);
> +	kfree_skb_reason(skb, reason);
>  	return 0;
>  }
Menglong Dong Aug. 17, 2024, 11:33 a.m. UTC | #2
On Sat, Aug 17, 2024 at 10:22 AM Jakub Kicinski <kuba@kernel.org> wrote:
>
> On Thu, 15 Aug 2024 20:42:58 +0800 Menglong Dong wrote:
> >  #define VXLAN_DROP_REASONS(R)                        \
> > +     R(VXLAN_DROP_FLAGS)                     \
> > +     R(VXLAN_DROP_VNI)                       \
> > +     R(VXLAN_DROP_MAC)                       \
>
> Drop reasons should be documented.

Yeah, I wrote the code here just like what we did in
net/openvswitch/drop.h, which makes the definition of
enum ovs_drop_reason a call of VXLAN_DROP_REASONS().

I think that we can define the enum ovs_drop_reason just like
what we do in include/net/dropreason-core.h, which can make
it easier to document the reasons.

> I don't think name of a header field is a great fit for a reason.
>

Enn...Do you mean the "VXLAN_DROP_" prefix?

> >       /* deliberate comment for trailing \ */
> >
> >  enum vxlan_drop_reason {
> > diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
> > index e971c4785962..9a61f04bb95d 100644
> > --- a/drivers/net/vxlan/vxlan_core.c
> > +++ b/drivers/net/vxlan/vxlan_core.c
> > @@ -1668,6 +1668,7 @@ static bool vxlan_ecn_decapsulate(struct vxlan_sock *vs, void *oiph,
> >  /* Callback from net/ipv4/udp.c to receive packets */
> >  static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
> >  {
> > +     enum skb_drop_reason reason = pskb_may_pull_reason(skb, VXLAN_HLEN);
>
> Do not call complex functions inline as variable init..

Okay!

>
> >       struct vxlan_vni_node *vninode = NULL;
> >       struct vxlan_dev *vxlan;
> >       struct vxlan_sock *vs;
> > @@ -1681,7 +1682,7 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
> >       int nh;
> >
> >       /* Need UDP and VXLAN header to be present */
> > -     if (!pskb_may_pull(skb, VXLAN_HLEN))
> > +     if (reason != SKB_NOT_DROPPED_YET)
>
> please don't compare against "not dropped yet", just:
>

Okay!

>         if (reason)
>
> > @@ -1815,8 +1831,9 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
> >       return 0;
> >
> >  drop:
> > +     SKB_DR_RESET(reason);
>
> the name of this macro is very confusing, I don't think it should exist
> in the first place. nothing should goto drop without initialing reason
>

It's for the case that we call a function which returns drop reasons.
For example, the reason now is assigned from:

  reason = pskb_may_pull_reason(skb, VXLAN_HLEN);
  if (reason) goto drop;

  xxxxxx
  if (xx) goto drop;

The reason now is SKB_NOT_DROPPED_YET when we "goto drop",
as we don't set a drop reason here, which is unnecessary in some cases.
And, we can't set the drop reason for every "drop" code path, can we?
So, we need to check if the drop reason is SKB_NOT_DROPPED_YET
when we call kfree_skb_reason().

We use "SKB_DR_OR(drop_reason, NOT_SPECIFIED);" in tcp_v4_rcv()
for this purpose. And we can remove SKB_DR_RESET and replace it
with "SKB_DR_OR(drop_reason, NOT_SPECIFIED);" here if you think
it's ok.

Thanks!
Menglong Dong
> >       /* Consume bad packet */
> > -     kfree_skb(skb);
> > +     kfree_skb_reason(skb, reason);
> >       return 0;
> >  }
Jakub Kicinski Aug. 19, 2024, 10:59 p.m. UTC | #3
On Sat, 17 Aug 2024 19:33:23 +0800 Menglong Dong wrote:
> On Sat, Aug 17, 2024 at 10:22 AM Jakub Kicinski <kuba@kernel.org> wrote:
> >
> > On Thu, 15 Aug 2024 20:42:58 +0800 Menglong Dong wrote:  
> > >  #define VXLAN_DROP_REASONS(R)                        \
> > > +     R(VXLAN_DROP_FLAGS)                     \
> > > +     R(VXLAN_DROP_VNI)                       \
> > > +     R(VXLAN_DROP_MAC)                       \  
> >
> > Drop reasons should be documented.  
> 
> Yeah, I wrote the code here just like what we did in
> net/openvswitch/drop.h, which makes the definition of
> enum ovs_drop_reason a call of VXLAN_DROP_REASONS().
> 
> I think that we can define the enum ovs_drop_reason just like
> what we do in include/net/dropreason-core.h, which can make
> it easier to document the reasons.
> 
> > I don't think name of a header field is a great fit for a reason.
> >  
> 
> Enn...Do you mean the "VXLAN_DROP_" prefix?

No, I mean the thing after VXLAN_DROP_, it's FLAGS, VNI, MAC,
those are names of header fields.

> > > @@ -1815,8 +1831,9 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
> > >       return 0;
> > >
> > >  drop:
> > > +     SKB_DR_RESET(reason);  
> >
> > the name of this macro is very confusing, I don't think it should exist
> > in the first place. nothing should goto drop without initialing reason
> >  
> 
> It's for the case that we call a function which returns drop reasons.
> For example, the reason now is assigned from:
> 
>   reason = pskb_may_pull_reason(skb, VXLAN_HLEN);
>   if (reason) goto drop;
> 
>   xxxxxx
>   if (xx) goto drop;
> 
> The reason now is SKB_NOT_DROPPED_YET when we "goto drop",
> as we don't set a drop reason here, which is unnecessary in some cases.
> And, we can't set the drop reason for every "drop" code path, can we?

Why? It's like saying "we can't set return code before jumping to
an error label". In my mind drop reasons and function return codes
are very similar. So IDK why we need all the SK_DR_ macros when
we are just fine without them for function return codes.
Ido Schimmel Aug. 20, 2024, 12:26 p.m. UTC | #4
On Thu, Aug 15, 2024 at 08:42:58PM +0800, Menglong Dong wrote:
> diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
> index e971c4785962..9a61f04bb95d 100644
> --- a/drivers/net/vxlan/vxlan_core.c
> +++ b/drivers/net/vxlan/vxlan_core.c
> @@ -1668,6 +1668,7 @@ static bool vxlan_ecn_decapsulate(struct vxlan_sock *vs, void *oiph,
>  /* Callback from net/ipv4/udp.c to receive packets */
>  static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
>  {
> +	enum skb_drop_reason reason = pskb_may_pull_reason(skb, VXLAN_HLEN);
>  	struct vxlan_vni_node *vninode = NULL;
>  	struct vxlan_dev *vxlan;
>  	struct vxlan_sock *vs;
> @@ -1681,7 +1682,7 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
>  	int nh;
>  
>  	/* Need UDP and VXLAN header to be present */
> -	if (!pskb_may_pull(skb, VXLAN_HLEN))
> +	if (reason != SKB_NOT_DROPPED_YET)
>  		goto drop;
>  
>  	unparsed = *vxlan_hdr(skb);
> @@ -1690,6 +1691,7 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
>  		netdev_dbg(skb->dev, "invalid vxlan flags=%#x vni=%#x\n",
>  			   ntohl(vxlan_hdr(skb)->vx_flags),
>  			   ntohl(vxlan_hdr(skb)->vx_vni));
> +		reason = (u32)VXLAN_DROP_FLAGS;

I don't find "FLAGS" very descriptive. AFAICT the reason is used in
these two cases:

1. "I flag" is not set
2. The reserved fields are not zero

Maybe call it VXLAN_DROP_INVALID_HDR ?

And I agree with the comment about documenting these drop reasons like
in include/net/dropreason-core.h

>  		/* Return non vxlan pkt */
>  		goto drop;
>  	}
> @@ -1703,8 +1705,10 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
>  	vni = vxlan_vni(vxlan_hdr(skb)->vx_vni);
>  
>  	vxlan = vxlan_vs_find_vni(vs, skb->dev->ifindex, vni, &vninode);
> -	if (!vxlan)
> +	if (!vxlan) {
> +		reason = (u32)VXLAN_DROP_VNI;

Same comment here. Maybe VXLAN_DROP_VNI_NOT_FOUND ?

>  		goto drop;
> +	}
>  
>  	/* For backwards compatibility, only allow reserved fields to be
>  	 * used by VXLAN extensions if explicitly requested.
> @@ -1717,12 +1721,16 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
>  	}
>  
>  	if (__iptunnel_pull_header(skb, VXLAN_HLEN, protocol, raw_proto,
> -				   !net_eq(vxlan->net, dev_net(vxlan->dev))))
> +				   !net_eq(vxlan->net, dev_net(vxlan->dev)))) {
> +		reason = SKB_DROP_REASON_NOMEM;
>  		goto drop;
> +	}
>  
> -	if (vs->flags & VXLAN_F_REMCSUM_RX)
> -		if (unlikely(!vxlan_remcsum(&unparsed, skb, vs->flags)))
> +	if (vs->flags & VXLAN_F_REMCSUM_RX) {
> +		reason = vxlan_remcsum(&unparsed, skb, vs->flags);
> +		if (unlikely(reason != SKB_NOT_DROPPED_YET))
>  			goto drop;
> +	}
>  
>  	if (vxlan_collect_metadata(vs)) {
>  		IP_TUNNEL_DECLARE_FLAGS(flags) = { };
> @@ -1732,8 +1740,10 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
>  		tun_dst = udp_tun_rx_dst(skb, vxlan_get_sk_family(vs), flags,
>  					 key32_to_tunnel_id(vni), sizeof(*md));
>  
> -		if (!tun_dst)
> +		if (!tun_dst) {
> +			reason = SKB_DROP_REASON_NOMEM;
>  			goto drop;
> +		}
>  
>  		md = ip_tunnel_info_opts(&tun_dst->u.tun_info);
>  
> @@ -1757,12 +1767,15 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
>  		 * is more robust and provides a little more security in
>  		 * adding extensions to VXLAN.
>  		 */
> +		reason = (u32)VXLAN_DROP_FLAGS;
>  		goto drop;
>  	}
>  
>  	if (!raw_proto) {
> -		if (!vxlan_set_mac(vxlan, vs, skb, vni))
> +		if (!vxlan_set_mac(vxlan, vs, skb, vni)) {
> +			reason = (u32)VXLAN_DROP_MAC;

The function drops the packet for various reasons:

1. Source MAC is equal to the VXLAN device's MAC
2. Source MAC is invalid (all zeroes or multicast)
3. Trying to migrate a static entry or one pointing to a nexthop

They are all quite obscure so it might be fine to fold them under the
same reason, but I can't find a descriptive name.

If you split 1-2 to one reason and 3 to another, then they can become
VXLAN_DROP_INVALID_SMAC and VXLAN_DROP_ENTRY_EXISTS

>  			goto drop;
> +		}
Menglong Dong Aug. 21, 2024, 12:51 p.m. UTC | #5
On Tue, Aug 20, 2024 at 6:59 AM Jakub Kicinski <kuba@kernel.org> wrote:
>
> On Sat, 17 Aug 2024 19:33:23 +0800 Menglong Dong wrote:
> > On Sat, Aug 17, 2024 at 10:22 AM Jakub Kicinski <kuba@kernel.org> wrote:
> > >
> > > On Thu, 15 Aug 2024 20:42:58 +0800 Menglong Dong wrote:
> > > >  #define VXLAN_DROP_REASONS(R)                        \
> > > > +     R(VXLAN_DROP_FLAGS)                     \
> > > > +     R(VXLAN_DROP_VNI)                       \
> > > > +     R(VXLAN_DROP_MAC)                       \
> > >
> > > Drop reasons should be documented.
> >
> > Yeah, I wrote the code here just like what we did in
> > net/openvswitch/drop.h, which makes the definition of
> > enum ovs_drop_reason a call of VXLAN_DROP_REASONS().
> >
> > I think that we can define the enum ovs_drop_reason just like
> > what we do in include/net/dropreason-core.h, which can make
> > it easier to document the reasons.
> >
> > > I don't think name of a header field is a great fit for a reason.
> > >
> >
> > Enn...Do you mean the "VXLAN_DROP_" prefix?
>
> No, I mean the thing after VXLAN_DROP_, it's FLAGS, VNI, MAC,
> those are names of header fields.
>

Yeah, the reason here seems too simple. I use VXLAN_DROP_FLAGS
for any dropping out of vxlan flags. Just like what Ido advised, we can use
more descriptive reasons here, such as VXLAN_DROP_INVALID_HDR
for FLAGS, VXLAN_DROP_NO_VNI for vni not found, etc.

> > > > @@ -1815,8 +1831,9 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
> > > >       return 0;
> > > >
> > > >  drop:
> > > > +     SKB_DR_RESET(reason);
> > >
> > > the name of this macro is very confusing, I don't think it should exist
> > > in the first place. nothing should goto drop without initialing reason
> > >
> >
> > It's for the case that we call a function which returns drop reasons.
> > For example, the reason now is assigned from:
> >
> >   reason = pskb_may_pull_reason(skb, VXLAN_HLEN);
> >   if (reason) goto drop;
> >
> >   xxxxxx
> >   if (xx) goto drop;
> >
> > The reason now is SKB_NOT_DROPPED_YET when we "goto drop",
> > as we don't set a drop reason here, which is unnecessary in some cases.
> > And, we can't set the drop reason for every "drop" code path, can we?
>
> Why? It's like saying "we can't set return code before jumping to
> an error label". In my mind drop reasons and function return codes
> are very similar. So IDK why we need all the SK_DR_ macros when
> we are just fine without them for function return codes.

Of course we can. In my example above, we need to set
reason to SKB_DROP_REASON_NOT_SPECIFIED before we
jump to an error label:

reason = pskb_may_pull_reason(skb, VXLAN_HLEN);
if (reason) goto drop;

xxxxxx
// we need to set reason here, or a WARN will be printed in
// kfree_skb_reason(), as reason now is SKB_NOT_DROPPED_YET.
reason = SKB_DROP_REASON_NOT_SPECIFIED;
if (xx) goto drop;

Should it be better to do it this way?

Thanks!
Menglong Dong
Menglong Dong Aug. 21, 2024, 12:54 p.m. UTC | #6
On Tue, Aug 20, 2024 at 8:27 PM Ido Schimmel <idosch@nvidia.com> wrote:
>
> On Thu, Aug 15, 2024 at 08:42:58PM +0800, Menglong Dong wrote:
> > diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
> > index e971c4785962..9a61f04bb95d 100644
> > --- a/drivers/net/vxlan/vxlan_core.c
> > +++ b/drivers/net/vxlan/vxlan_core.c
> > @@ -1668,6 +1668,7 @@ static bool vxlan_ecn_decapsulate(struct vxlan_sock *vs, void *oiph,
> >  /* Callback from net/ipv4/udp.c to receive packets */
> >  static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
> >  {
> > +     enum skb_drop_reason reason = pskb_may_pull_reason(skb, VXLAN_HLEN);
> >       struct vxlan_vni_node *vninode = NULL;
> >       struct vxlan_dev *vxlan;
> >       struct vxlan_sock *vs;
> > @@ -1681,7 +1682,7 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
> >       int nh;
> >
> >       /* Need UDP and VXLAN header to be present */
> > -     if (!pskb_may_pull(skb, VXLAN_HLEN))
> > +     if (reason != SKB_NOT_DROPPED_YET)
> >               goto drop;
> >
> >       unparsed = *vxlan_hdr(skb);
> > @@ -1690,6 +1691,7 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
> >               netdev_dbg(skb->dev, "invalid vxlan flags=%#x vni=%#x\n",
> >                          ntohl(vxlan_hdr(skb)->vx_flags),
> >                          ntohl(vxlan_hdr(skb)->vx_vni));
> > +             reason = (u32)VXLAN_DROP_FLAGS;
>
> I don't find "FLAGS" very descriptive. AFAICT the reason is used in
> these two cases:
>
> 1. "I flag" is not set
> 2. The reserved fields are not zero
>
> Maybe call it VXLAN_DROP_INVALID_HDR ?
>

Yeah, that makes sense.

> And I agree with the comment about documenting these drop reasons like
> in include/net/dropreason-core.h
>

Okay, I'm planning to do it this way.

> >               /* Return non vxlan pkt */
> >               goto drop;
> >       }
> > @@ -1703,8 +1705,10 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
> >       vni = vxlan_vni(vxlan_hdr(skb)->vx_vni);
> >
> >       vxlan = vxlan_vs_find_vni(vs, skb->dev->ifindex, vni, &vninode);
> > -     if (!vxlan)
> > +     if (!vxlan) {
> > +             reason = (u32)VXLAN_DROP_VNI;
>
> Same comment here. Maybe VXLAN_DROP_VNI_NOT_FOUND ?
>

Yeah, sounds nice.

> >               goto drop;
> > +     }
> >
> >       /* For backwards compatibility, only allow reserved fields to be
> >        * used by VXLAN extensions if explicitly requested.
> > @@ -1717,12 +1721,16 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
> >       }
> >
> >       if (__iptunnel_pull_header(skb, VXLAN_HLEN, protocol, raw_proto,
> > -                                !net_eq(vxlan->net, dev_net(vxlan->dev))))
> > +                                !net_eq(vxlan->net, dev_net(vxlan->dev)))) {
> > +             reason = SKB_DROP_REASON_NOMEM;
> >               goto drop;
> > +     }
> >
> > -     if (vs->flags & VXLAN_F_REMCSUM_RX)
> > -             if (unlikely(!vxlan_remcsum(&unparsed, skb, vs->flags)))
> > +     if (vs->flags & VXLAN_F_REMCSUM_RX) {
> > +             reason = vxlan_remcsum(&unparsed, skb, vs->flags);
> > +             if (unlikely(reason != SKB_NOT_DROPPED_YET))
> >                       goto drop;
> > +     }
> >
> >       if (vxlan_collect_metadata(vs)) {
> >               IP_TUNNEL_DECLARE_FLAGS(flags) = { };
> > @@ -1732,8 +1740,10 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
> >               tun_dst = udp_tun_rx_dst(skb, vxlan_get_sk_family(vs), flags,
> >                                        key32_to_tunnel_id(vni), sizeof(*md));
> >
> > -             if (!tun_dst)
> > +             if (!tun_dst) {
> > +                     reason = SKB_DROP_REASON_NOMEM;
> >                       goto drop;
> > +             }
> >
> >               md = ip_tunnel_info_opts(&tun_dst->u.tun_info);
> >
> > @@ -1757,12 +1767,15 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
> >                * is more robust and provides a little more security in
> >                * adding extensions to VXLAN.
> >                */
> > +             reason = (u32)VXLAN_DROP_FLAGS;
> >               goto drop;
> >       }
> >
> >       if (!raw_proto) {
> > -             if (!vxlan_set_mac(vxlan, vs, skb, vni))
> > +             if (!vxlan_set_mac(vxlan, vs, skb, vni)) {
> > +                     reason = (u32)VXLAN_DROP_MAC;
>
> The function drops the packet for various reasons:
>
> 1. Source MAC is equal to the VXLAN device's MAC
> 2. Source MAC is invalid (all zeroes or multicast)
> 3. Trying to migrate a static entry or one pointing to a nexthop
>
> They are all quite obscure so it might be fine to fold them under the
> same reason, but I can't find a descriptive name.
>
> If you split 1-2 to one reason and 3 to another, then they can become
> VXLAN_DROP_INVALID_SMAC and VXLAN_DROP_ENTRY_EXISTS
>

Sounds great! Thanks for creating these names for me,
I'm really not good at naming :/

> >                       goto drop;
> > +             }
diff mbox series

Patch

diff --git a/drivers/net/vxlan/drop.h b/drivers/net/vxlan/drop.h
index 83e10550dd6a..cae1e0ea8c56 100644
--- a/drivers/net/vxlan/drop.h
+++ b/drivers/net/vxlan/drop.h
@@ -9,6 +9,9 @@ 
 #include <net/dropreason.h>
 
 #define VXLAN_DROP_REASONS(R)			\
+	R(VXLAN_DROP_FLAGS)			\
+	R(VXLAN_DROP_VNI)			\
+	R(VXLAN_DROP_MAC)			\
 	/* deliberate comment for trailing \ */
 
 enum vxlan_drop_reason {
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index e971c4785962..9a61f04bb95d 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -1668,6 +1668,7 @@  static bool vxlan_ecn_decapsulate(struct vxlan_sock *vs, void *oiph,
 /* Callback from net/ipv4/udp.c to receive packets */
 static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
 {
+	enum skb_drop_reason reason = pskb_may_pull_reason(skb, VXLAN_HLEN);
 	struct vxlan_vni_node *vninode = NULL;
 	struct vxlan_dev *vxlan;
 	struct vxlan_sock *vs;
@@ -1681,7 +1682,7 @@  static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
 	int nh;
 
 	/* Need UDP and VXLAN header to be present */
-	if (!pskb_may_pull(skb, VXLAN_HLEN))
+	if (reason != SKB_NOT_DROPPED_YET)
 		goto drop;
 
 	unparsed = *vxlan_hdr(skb);
@@ -1690,6 +1691,7 @@  static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
 		netdev_dbg(skb->dev, "invalid vxlan flags=%#x vni=%#x\n",
 			   ntohl(vxlan_hdr(skb)->vx_flags),
 			   ntohl(vxlan_hdr(skb)->vx_vni));
+		reason = (u32)VXLAN_DROP_FLAGS;
 		/* Return non vxlan pkt */
 		goto drop;
 	}
@@ -1703,8 +1705,10 @@  static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
 	vni = vxlan_vni(vxlan_hdr(skb)->vx_vni);
 
 	vxlan = vxlan_vs_find_vni(vs, skb->dev->ifindex, vni, &vninode);
-	if (!vxlan)
+	if (!vxlan) {
+		reason = (u32)VXLAN_DROP_VNI;
 		goto drop;
+	}
 
 	/* For backwards compatibility, only allow reserved fields to be
 	 * used by VXLAN extensions if explicitly requested.
@@ -1717,12 +1721,16 @@  static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
 	}
 
 	if (__iptunnel_pull_header(skb, VXLAN_HLEN, protocol, raw_proto,
-				   !net_eq(vxlan->net, dev_net(vxlan->dev))))
+				   !net_eq(vxlan->net, dev_net(vxlan->dev)))) {
+		reason = SKB_DROP_REASON_NOMEM;
 		goto drop;
+	}
 
-	if (vs->flags & VXLAN_F_REMCSUM_RX)
-		if (unlikely(!vxlan_remcsum(&unparsed, skb, vs->flags)))
+	if (vs->flags & VXLAN_F_REMCSUM_RX) {
+		reason = vxlan_remcsum(&unparsed, skb, vs->flags);
+		if (unlikely(reason != SKB_NOT_DROPPED_YET))
 			goto drop;
+	}
 
 	if (vxlan_collect_metadata(vs)) {
 		IP_TUNNEL_DECLARE_FLAGS(flags) = { };
@@ -1732,8 +1740,10 @@  static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
 		tun_dst = udp_tun_rx_dst(skb, vxlan_get_sk_family(vs), flags,
 					 key32_to_tunnel_id(vni), sizeof(*md));
 
-		if (!tun_dst)
+		if (!tun_dst) {
+			reason = SKB_DROP_REASON_NOMEM;
 			goto drop;
+		}
 
 		md = ip_tunnel_info_opts(&tun_dst->u.tun_info);
 
@@ -1757,12 +1767,15 @@  static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
 		 * is more robust and provides a little more security in
 		 * adding extensions to VXLAN.
 		 */
+		reason = (u32)VXLAN_DROP_FLAGS;
 		goto drop;
 	}
 
 	if (!raw_proto) {
-		if (!vxlan_set_mac(vxlan, vs, skb, vni))
+		if (!vxlan_set_mac(vxlan, vs, skb, vni)) {
+			reason = (u32)VXLAN_DROP_MAC;
 			goto drop;
+		}
 	} else {
 		skb_reset_mac_header(skb);
 		skb->dev = vxlan->dev;
@@ -1777,7 +1790,8 @@  static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
 
 	skb_reset_network_header(skb);
 
-	if (!pskb_inet_may_pull(skb)) {
+	reason = pskb_inet_may_pull_reason(skb);
+	if (reason != SKB_NOT_DROPPED_YET) {
 		DEV_STATS_INC(vxlan->dev, rx_length_errors);
 		DEV_STATS_INC(vxlan->dev, rx_errors);
 		vxlan_vnifilter_count(vxlan, vni, vninode,
@@ -1789,6 +1803,7 @@  static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
 	oiph = skb->head + nh;
 
 	if (!vxlan_ecn_decapsulate(vs, oiph, skb)) {
+		reason = SKB_DROP_REASON_IP_TUNNEL_ECN;
 		DEV_STATS_INC(vxlan->dev, rx_frame_errors);
 		DEV_STATS_INC(vxlan->dev, rx_errors);
 		vxlan_vnifilter_count(vxlan, vni, vninode,
@@ -1803,6 +1818,7 @@  static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
 		dev_core_stats_rx_dropped_inc(vxlan->dev);
 		vxlan_vnifilter_count(vxlan, vni, vninode,
 				      VXLAN_VNI_STATS_RX_DROPS, 0);
+		reason = SKB_DROP_REASON_DEV_READY;
 		goto drop;
 	}
 
@@ -1815,8 +1831,9 @@  static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
 	return 0;
 
 drop:
+	SKB_DR_RESET(reason);
 	/* Consume bad packet */
-	kfree_skb(skb);
+	kfree_skb_reason(skb, reason);
 	return 0;
 }
 
diff --git a/include/net/dropreason-core.h b/include/net/dropreason-core.h
index 8da0129d1ed6..8388c0ae893d 100644
--- a/include/net/dropreason-core.h
+++ b/include/net/dropreason-core.h
@@ -92,6 +92,7 @@ 
 	FN(PACKET_SOCK_ERROR)		\
 	FN(TC_CHAIN_NOTFOUND)		\
 	FN(TC_RECLASSIFY_LOOP)		\
+	FN(IP_TUNNEL_ECN)		\
 	FNe(MAX)
 
 /**
@@ -418,6 +419,11 @@  enum skb_drop_reason {
 	 * iterations.
 	 */
 	SKB_DROP_REASON_TC_RECLASSIFY_LOOP,
+	/**
+	 * @SKB_DROP_REASON_IP_TUNNEL_ECN: skb is dropped according to
+	 * RFC 6040 4.2, see __INET_ECN_decapsulate() for detail.
+	 */
+	SKB_DROP_REASON_IP_TUNNEL_ECN,
 	/**
 	 * @SKB_DROP_REASON_MAX: the maximum of core drop reasons, which
 	 * shouldn't be used as a real 'reason' - only for tracing code gen