Skip to content

Commit

Permalink
Merge branch 'ovs-drop-reasons'
Browse files Browse the repository at this point in the history
Adrian Moreno says:

====================
openvswitch: add drop reasons

There is currently a gap in drop visibility in the openvswitch module.
This series tries to improve this by adding a new drop reason subsystem
for OVS.

Apart from adding a new drop reasson subsystem and some common drop
reasons, this series takes Eric's preliminary work [1] on adding an
explicit drop action and integrates it into the same subsystem.

A limitation of this series is that it does not report upcall errors.
The reason is that there could be many sources of upcall drops and the
most common one, which is the netlink buffer overflow, cannot be
reported via kfree_skb() because the skb is freed in the netlink layer
(see [2]). Therefore, using a reason for the rare events and not the
common one would be even more misleading. I'd propose we add (in a
follow up patch) a tracepoint to better report upcall errors.

[1] https://lore.kernel.org/netdev/202306300609.tdRdZscy-lkp@intel.com/T/
[2] commit 1100248 ("openvswitch: Fix double reporting of drops in dropwatch")

---
v4 -> v5:
- Rebased
- Added a helper function to explicitly convert drop reason enum types

v3 -> v4:
- Changed names of errors following Ilya's suggestions
- Moved the ovs-dpctl.py changes from patch 7/7 to 3/7
- Added a test to ensure actions following a drop are rejected

rfc2 -> v3:
- Rebased on top of latest net-next

rfc1 -> rfc2:
- Fail when an explicit drop is not the last
- Added a drop reason for action errors
- Added braces around macros
- Dropped patch that added support for masks in ovs-dpctl.py as it's now
  included in Aaron's series [2].
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Aug 14, 2023
2 parents afb0c19 + 4242029 commit 76fa363
Show file tree
Hide file tree
Showing 9 changed files with 226 additions and 18 deletions.
6 changes: 6 additions & 0 deletions include/net/dropreason.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ enum skb_drop_reason_subsys {
*/
SKB_DROP_REASON_SUBSYS_MAC80211_MONITOR,

/**
* @SKB_DROP_REASON_SUBSYS_OPENVSWITCH: openvswitch drop reasons,
* see net/openvswitch/drop.h
*/
SKB_DROP_REASON_SUBSYS_OPENVSWITCH,

/** @SKB_DROP_REASON_SUBSYS_NUM: number of subsystems defined */
SKB_DROP_REASON_SUBSYS_NUM
};
Expand Down
2 changes: 2 additions & 0 deletions include/uapi/linux/openvswitch.h
Original file line number Diff line number Diff line change
Expand Up @@ -965,6 +965,7 @@ struct check_pkt_len_arg {
* start of the packet or at the start of the l3 header depending on the value
* of l3 tunnel flag in the tun_flags field of OVS_ACTION_ATTR_ADD_MPLS
* argument.
* @OVS_ACTION_ATTR_DROP: Explicit drop action.
*
* Only a single header can be set with a single %OVS_ACTION_ATTR_SET. Not all
* fields within a header are modifiable, e.g. the IPv4 protocol and fragment
Expand Down Expand Up @@ -1002,6 +1003,7 @@ enum ovs_action_attr {
OVS_ACTION_ATTR_CHECK_PKT_LEN, /* Nested OVS_CHECK_PKT_LEN_ATTR_*. */
OVS_ACTION_ATTR_ADD_MPLS, /* struct ovs_action_add_mpls. */
OVS_ACTION_ATTR_DEC_TTL, /* Nested OVS_DEC_TTL_ATTR_*. */
OVS_ACTION_ATTR_DROP, /* u32 error code. */

__OVS_ACTION_ATTR_MAX, /* Nothing past this will be accepted
* from userspace. */
Expand Down
42 changes: 31 additions & 11 deletions net/openvswitch/actions.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <net/sctp/checksum.h>

#include "datapath.h"
#include "drop.h"
#include "flow.h"
#include "conntrack.h"
#include "vport.h"
Expand Down Expand Up @@ -781,7 +782,7 @@ static int ovs_vport_output(struct net *net, struct sock *sk,
struct vport *vport = data->vport;

if (skb_cow_head(skb, data->l2_len) < 0) {
kfree_skb(skb);
kfree_skb_reason(skb, SKB_DROP_REASON_NOMEM);
return -ENOMEM;
}

Expand Down Expand Up @@ -852,6 +853,7 @@ static void ovs_fragment(struct net *net, struct vport *vport,
struct sk_buff *skb, u16 mru,
struct sw_flow_key *key)
{
enum ovs_drop_reason reason;
u16 orig_network_offset = 0;

if (eth_p_mpls(skb->protocol)) {
Expand All @@ -861,6 +863,7 @@ static void ovs_fragment(struct net *net, struct vport *vport,

if (skb_network_offset(skb) > MAX_L2_LEN) {
OVS_NLERR(1, "L2 header too long to fragment");
reason = OVS_DROP_FRAG_L2_TOO_LONG;
goto err;
}

Expand Down Expand Up @@ -901,12 +904,13 @@ static void ovs_fragment(struct net *net, struct vport *vport,
WARN_ONCE(1, "Failed fragment ->%s: eth=%04x, MRU=%d, MTU=%d.",
ovs_vport_name(vport), ntohs(key->eth.type), mru,
vport->dev->mtu);
reason = OVS_DROP_FRAG_INVALID_PROTO;
goto err;
}

return;
err:
kfree_skb(skb);
ovs_kfree_skb_reason(skb, reason);
}

static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port,
Expand All @@ -933,10 +937,10 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port,

ovs_fragment(net, vport, skb, mru, key);
} else {
kfree_skb(skb);
kfree_skb_reason(skb, SKB_DROP_REASON_PKT_TOO_BIG);
}
} else {
kfree_skb(skb);
kfree_skb_reason(skb, SKB_DROP_REASON_DEV_READY);
}
}

Expand Down Expand Up @@ -1010,7 +1014,7 @@ static int dec_ttl_exception_handler(struct datapath *dp, struct sk_buff *skb,
return clone_execute(dp, skb, key, 0, nla_data(actions),
nla_len(actions), true, false);

consume_skb(skb);
ovs_kfree_skb_reason(skb, OVS_DROP_IP_TTL);
return 0;
}

Expand All @@ -1036,7 +1040,7 @@ static int sample(struct datapath *dp, struct sk_buff *skb,
if ((arg->probability != U32_MAX) &&
(!arg->probability || get_random_u32() > arg->probability)) {
if (last)
consume_skb(skb);
ovs_kfree_skb_reason(skb, OVS_DROP_LAST_ACTION);
return 0;
}

Expand Down Expand Up @@ -1297,6 +1301,9 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
if (trace_ovs_do_execute_action_enabled())
trace_ovs_do_execute_action(dp, skb, key, a, rem);

/* Actions that rightfully have to consume the skb should do it
* and return directly.
*/
switch (nla_type(a)) {
case OVS_ACTION_ATTR_OUTPUT: {
int port = nla_get_u32(a);
Expand Down Expand Up @@ -1332,6 +1339,10 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
output_userspace(dp, skb, key, a, attr,
len, OVS_CB(skb)->cutlen);
OVS_CB(skb)->cutlen = 0;
if (nla_is_last(a, rem)) {
consume_skb(skb);
return 0;
}
break;

case OVS_ACTION_ATTR_HASH:
Expand Down Expand Up @@ -1446,7 +1457,7 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,

case OVS_ACTION_ATTR_METER:
if (ovs_meter_execute(dp, skb, key, nla_get_u32(a))) {
consume_skb(skb);
ovs_kfree_skb_reason(skb, OVS_DROP_METER);
return 0;
}
break;
Expand Down Expand Up @@ -1477,15 +1488,24 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
return dec_ttl_exception_handler(dp, skb,
key, a);
break;

case OVS_ACTION_ATTR_DROP: {
enum ovs_drop_reason reason = nla_get_u32(a)
? OVS_DROP_EXPLICIT_WITH_ERROR
: OVS_DROP_EXPLICIT;

ovs_kfree_skb_reason(skb, reason);
return 0;
}
}

if (unlikely(err)) {
kfree_skb(skb);
ovs_kfree_skb_reason(skb, OVS_DROP_ACTION_ERROR);
return err;
}
}

consume_skb(skb);
ovs_kfree_skb_reason(skb, OVS_DROP_LAST_ACTION);
return 0;
}

Expand Down Expand Up @@ -1547,7 +1567,7 @@ static int clone_execute(struct datapath *dp, struct sk_buff *skb,
/* Out of per CPU action FIFO space. Drop the 'skb' and
* log an error.
*/
kfree_skb(skb);
ovs_kfree_skb_reason(skb, OVS_DROP_DEFERRED_LIMIT);

if (net_ratelimit()) {
if (actions) { /* Sample action */
Expand Down Expand Up @@ -1599,7 +1619,7 @@ int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb,
if (unlikely(level > OVS_RECURSION_LIMIT)) {
net_crit_ratelimited("ovs: recursion limit reached on datapath %s, probable configuration error\n",
ovs_dp_name(dp));
kfree_skb(skb);
ovs_kfree_skb_reason(skb, OVS_DROP_RECURSION_LIMIT);
err = -ENETDOWN;
goto out;
}
Expand Down
3 changes: 2 additions & 1 deletion net/openvswitch/conntrack.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <net/netfilter/nf_conntrack_act_ct.h>

#include "datapath.h"
#include "drop.h"
#include "conntrack.h"
#include "flow.h"
#include "flow_netlink.h"
Expand Down Expand Up @@ -1035,7 +1036,7 @@ int ovs_ct_execute(struct net *net, struct sk_buff *skb,

skb_push_rcsum(skb, nh_ofs);
if (err)
kfree_skb(skb);
ovs_kfree_skb_reason(skb, OVS_DROP_CONNTRACK);
return err;
}

Expand Down
16 changes: 16 additions & 0 deletions net/openvswitch/datapath.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include <net/pkt_cls.h>

#include "datapath.h"
#include "drop.h"
#include "flow.h"
#include "flow_table.h"
#include "flow_netlink.h"
Expand Down Expand Up @@ -2702,6 +2703,17 @@ static struct pernet_operations ovs_net_ops = {
.size = sizeof(struct ovs_net),
};

static const char * const ovs_drop_reasons[] = {
#define S(x) (#x),
OVS_DROP_REASONS(S)
#undef S
};

static struct drop_reason_list drop_reason_list_ovs = {
.reasons = ovs_drop_reasons,
.n_reasons = ARRAY_SIZE(ovs_drop_reasons),
};

static int __init dp_init(void)
{
int err;
Expand Down Expand Up @@ -2743,6 +2755,9 @@ static int __init dp_init(void)
if (err < 0)
goto error_unreg_netdev;

drop_reasons_register_subsys(SKB_DROP_REASON_SUBSYS_OPENVSWITCH,
&drop_reason_list_ovs);

return 0;

error_unreg_netdev:
Expand All @@ -2769,6 +2784,7 @@ static void dp_cleanup(void)
ovs_netdev_exit();
unregister_netdevice_notifier(&ovs_dp_device_notifier);
unregister_pernet_device(&ovs_net_ops);
drop_reasons_unregister_subsys(SKB_DROP_REASON_SUBSYS_OPENVSWITCH);
rcu_barrier();
ovs_vport_exit();
ovs_flow_exit();
Expand Down
41 changes: 41 additions & 0 deletions net/openvswitch/drop.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* OpenvSwitch drop reason list.
*/

#ifndef OPENVSWITCH_DROP_H
#define OPENVSWITCH_DROP_H
#include <linux/skbuff.h>
#include <net/dropreason.h>

#define OVS_DROP_REASONS(R) \
R(OVS_DROP_LAST_ACTION) \
R(OVS_DROP_ACTION_ERROR) \
R(OVS_DROP_EXPLICIT) \
R(OVS_DROP_EXPLICIT_WITH_ERROR) \
R(OVS_DROP_METER) \
R(OVS_DROP_RECURSION_LIMIT) \
R(OVS_DROP_DEFERRED_LIMIT) \
R(OVS_DROP_FRAG_L2_TOO_LONG) \
R(OVS_DROP_FRAG_INVALID_PROTO) \
R(OVS_DROP_CONNTRACK) \
R(OVS_DROP_IP_TTL) \
/* deliberate comment for trailing \ */

enum ovs_drop_reason {
__OVS_DROP_REASON = SKB_DROP_REASON_SUBSYS_OPENVSWITCH <<
SKB_DROP_REASON_SUBSYS_SHIFT,
#define ENUM(x) x,
OVS_DROP_REASONS(ENUM)
#undef ENUM

OVS_DROP_MAX,
};

static inline void
ovs_kfree_skb_reason(struct sk_buff *skb, enum ovs_drop_reason reason)
{
kfree_skb_reason(skb, (u32)reason);
}

#endif /* OPENVSWITCH_DROP_H */
10 changes: 9 additions & 1 deletion net/openvswitch/flow_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include <net/tun_proto.h>
#include <net/erspan.h>

#include "drop.h"
#include "flow_netlink.h"

struct ovs_len_tbl {
Expand All @@ -61,6 +62,7 @@ static bool actions_may_change_flow(const struct nlattr *actions)
case OVS_ACTION_ATTR_RECIRC:
case OVS_ACTION_ATTR_TRUNC:
case OVS_ACTION_ATTR_USERSPACE:
case OVS_ACTION_ATTR_DROP:
break;

case OVS_ACTION_ATTR_CT:
Expand Down Expand Up @@ -2394,7 +2396,7 @@ static void ovs_nla_free_nested_actions(const struct nlattr *actions, int len)
/* Whenever new actions are added, the need to update this
* function should be considered.
*/
BUILD_BUG_ON(OVS_ACTION_ATTR_MAX != 23);
BUILD_BUG_ON(OVS_ACTION_ATTR_MAX != 24);

if (!actions)
return;
Expand Down Expand Up @@ -3182,6 +3184,7 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
[OVS_ACTION_ATTR_CHECK_PKT_LEN] = (u32)-1,
[OVS_ACTION_ATTR_ADD_MPLS] = sizeof(struct ovs_action_add_mpls),
[OVS_ACTION_ATTR_DEC_TTL] = (u32)-1,
[OVS_ACTION_ATTR_DROP] = sizeof(u32),
};
const struct ovs_action_push_vlan *vlan;
int type = nla_type(a);
Expand Down Expand Up @@ -3453,6 +3456,11 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
skip_copy = true;
break;

case OVS_ACTION_ATTR_DROP:
if (!nla_is_last(a, rem))
return -EINVAL;
break;

default:
OVS_NLERR(log, "Unknown Action type %d", type);
return -EINVAL;
Expand Down
Loading

0 comments on commit 76fa363

Please sign in to comment.