Skip to content

Commit 76fa363

Browse files
committed
Merge branch 'ovs-drop-reasons'
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/[email protected]/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 <[email protected]>
2 parents afb0c19 + 4242029 commit 76fa363

File tree

9 files changed

+226
-18
lines changed

9 files changed

+226
-18
lines changed

include/net/dropreason.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ enum skb_drop_reason_subsys {
2323
*/
2424
SKB_DROP_REASON_SUBSYS_MAC80211_MONITOR,
2525

26+
/**
27+
* @SKB_DROP_REASON_SUBSYS_OPENVSWITCH: openvswitch drop reasons,
28+
* see net/openvswitch/drop.h
29+
*/
30+
SKB_DROP_REASON_SUBSYS_OPENVSWITCH,
31+
2632
/** @SKB_DROP_REASON_SUBSYS_NUM: number of subsystems defined */
2733
SKB_DROP_REASON_SUBSYS_NUM
2834
};

include/uapi/linux/openvswitch.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -965,6 +965,7 @@ struct check_pkt_len_arg {
965965
* start of the packet or at the start of the l3 header depending on the value
966966
* of l3 tunnel flag in the tun_flags field of OVS_ACTION_ATTR_ADD_MPLS
967967
* argument.
968+
* @OVS_ACTION_ATTR_DROP: Explicit drop action.
968969
*
969970
* Only a single header can be set with a single %OVS_ACTION_ATTR_SET. Not all
970971
* fields within a header are modifiable, e.g. the IPv4 protocol and fragment
@@ -1002,6 +1003,7 @@ enum ovs_action_attr {
10021003
OVS_ACTION_ATTR_CHECK_PKT_LEN, /* Nested OVS_CHECK_PKT_LEN_ATTR_*. */
10031004
OVS_ACTION_ATTR_ADD_MPLS, /* struct ovs_action_add_mpls. */
10041005
OVS_ACTION_ATTR_DEC_TTL, /* Nested OVS_DEC_TTL_ATTR_*. */
1006+
OVS_ACTION_ATTR_DROP, /* u32 error code. */
10051007

10061008
__OVS_ACTION_ATTR_MAX, /* Nothing past this will be accepted
10071009
* from userspace. */

net/openvswitch/actions.c

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <net/sctp/checksum.h>
2828

2929
#include "datapath.h"
30+
#include "drop.h"
3031
#include "flow.h"
3132
#include "conntrack.h"
3233
#include "vport.h"
@@ -781,7 +782,7 @@ static int ovs_vport_output(struct net *net, struct sock *sk,
781782
struct vport *vport = data->vport;
782783

783784
if (skb_cow_head(skb, data->l2_len) < 0) {
784-
kfree_skb(skb);
785+
kfree_skb_reason(skb, SKB_DROP_REASON_NOMEM);
785786
return -ENOMEM;
786787
}
787788

@@ -852,6 +853,7 @@ static void ovs_fragment(struct net *net, struct vport *vport,
852853
struct sk_buff *skb, u16 mru,
853854
struct sw_flow_key *key)
854855
{
856+
enum ovs_drop_reason reason;
855857
u16 orig_network_offset = 0;
856858

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

862864
if (skb_network_offset(skb) > MAX_L2_LEN) {
863865
OVS_NLERR(1, "L2 header too long to fragment");
866+
reason = OVS_DROP_FRAG_L2_TOO_LONG;
864867
goto err;
865868
}
866869

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

907911
return;
908912
err:
909-
kfree_skb(skb);
913+
ovs_kfree_skb_reason(skb, reason);
910914
}
911915

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

934938
ovs_fragment(net, vport, skb, mru, key);
935939
} else {
936-
kfree_skb(skb);
940+
kfree_skb_reason(skb, SKB_DROP_REASON_PKT_TOO_BIG);
937941
}
938942
} else {
939-
kfree_skb(skb);
943+
kfree_skb_reason(skb, SKB_DROP_REASON_DEV_READY);
940944
}
941945
}
942946

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

1013-
consume_skb(skb);
1017+
ovs_kfree_skb_reason(skb, OVS_DROP_IP_TTL);
10141018
return 0;
10151019
}
10161020

@@ -1036,7 +1040,7 @@ static int sample(struct datapath *dp, struct sk_buff *skb,
10361040
if ((arg->probability != U32_MAX) &&
10371041
(!arg->probability || get_random_u32() > arg->probability)) {
10381042
if (last)
1039-
consume_skb(skb);
1043+
ovs_kfree_skb_reason(skb, OVS_DROP_LAST_ACTION);
10401044
return 0;
10411045
}
10421046

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

1304+
/* Actions that rightfully have to consume the skb should do it
1305+
* and return directly.
1306+
*/
13001307
switch (nla_type(a)) {
13011308
case OVS_ACTION_ATTR_OUTPUT: {
13021309
int port = nla_get_u32(a);
@@ -1332,6 +1339,10 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
13321339
output_userspace(dp, skb, key, a, attr,
13331340
len, OVS_CB(skb)->cutlen);
13341341
OVS_CB(skb)->cutlen = 0;
1342+
if (nla_is_last(a, rem)) {
1343+
consume_skb(skb);
1344+
return 0;
1345+
}
13351346
break;
13361347

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

14471458
case OVS_ACTION_ATTR_METER:
14481459
if (ovs_meter_execute(dp, skb, key, nla_get_u32(a))) {
1449-
consume_skb(skb);
1460+
ovs_kfree_skb_reason(skb, OVS_DROP_METER);
14501461
return 0;
14511462
}
14521463
break;
@@ -1477,15 +1488,24 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
14771488
return dec_ttl_exception_handler(dp, skb,
14781489
key, a);
14791490
break;
1491+
1492+
case OVS_ACTION_ATTR_DROP: {
1493+
enum ovs_drop_reason reason = nla_get_u32(a)
1494+
? OVS_DROP_EXPLICIT_WITH_ERROR
1495+
: OVS_DROP_EXPLICIT;
1496+
1497+
ovs_kfree_skb_reason(skb, reason);
1498+
return 0;
1499+
}
14801500
}
14811501

14821502
if (unlikely(err)) {
1483-
kfree_skb(skb);
1503+
ovs_kfree_skb_reason(skb, OVS_DROP_ACTION_ERROR);
14841504
return err;
14851505
}
14861506
}
14871507

1488-
consume_skb(skb);
1508+
ovs_kfree_skb_reason(skb, OVS_DROP_LAST_ACTION);
14891509
return 0;
14901510
}
14911511

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

15521572
if (net_ratelimit()) {
15531573
if (actions) { /* Sample action */
@@ -1599,7 +1619,7 @@ int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb,
15991619
if (unlikely(level > OVS_RECURSION_LIMIT)) {
16001620
net_crit_ratelimited("ovs: recursion limit reached on datapath %s, probable configuration error\n",
16011621
ovs_dp_name(dp));
1602-
kfree_skb(skb);
1622+
ovs_kfree_skb_reason(skb, OVS_DROP_RECURSION_LIMIT);
16031623
err = -ENETDOWN;
16041624
goto out;
16051625
}

net/openvswitch/conntrack.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <net/netfilter/nf_conntrack_act_ct.h>
3030

3131
#include "datapath.h"
32+
#include "drop.h"
3233
#include "conntrack.h"
3334
#include "flow.h"
3435
#include "flow_netlink.h"
@@ -1035,7 +1036,7 @@ int ovs_ct_execute(struct net *net, struct sk_buff *skb,
10351036

10361037
skb_push_rcsum(skb, nh_ofs);
10371038
if (err)
1038-
kfree_skb(skb);
1039+
ovs_kfree_skb_reason(skb, OVS_DROP_CONNTRACK);
10391040
return err;
10401041
}
10411042

net/openvswitch/datapath.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include <net/pkt_cls.h>
4242

4343
#include "datapath.h"
44+
#include "drop.h"
4445
#include "flow.h"
4546
#include "flow_table.h"
4647
#include "flow_netlink.h"
@@ -2702,6 +2703,17 @@ static struct pernet_operations ovs_net_ops = {
27022703
.size = sizeof(struct ovs_net),
27032704
};
27042705

2706+
static const char * const ovs_drop_reasons[] = {
2707+
#define S(x) (#x),
2708+
OVS_DROP_REASONS(S)
2709+
#undef S
2710+
};
2711+
2712+
static struct drop_reason_list drop_reason_list_ovs = {
2713+
.reasons = ovs_drop_reasons,
2714+
.n_reasons = ARRAY_SIZE(ovs_drop_reasons),
2715+
};
2716+
27052717
static int __init dp_init(void)
27062718
{
27072719
int err;
@@ -2743,6 +2755,9 @@ static int __init dp_init(void)
27432755
if (err < 0)
27442756
goto error_unreg_netdev;
27452757

2758+
drop_reasons_register_subsys(SKB_DROP_REASON_SUBSYS_OPENVSWITCH,
2759+
&drop_reason_list_ovs);
2760+
27462761
return 0;
27472762

27482763
error_unreg_netdev:
@@ -2769,6 +2784,7 @@ static void dp_cleanup(void)
27692784
ovs_netdev_exit();
27702785
unregister_netdevice_notifier(&ovs_dp_device_notifier);
27712786
unregister_pernet_device(&ovs_net_ops);
2787+
drop_reasons_unregister_subsys(SKB_DROP_REASON_SUBSYS_OPENVSWITCH);
27722788
rcu_barrier();
27732789
ovs_vport_exit();
27742790
ovs_flow_exit();

net/openvswitch/drop.h

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/*
3+
* OpenvSwitch drop reason list.
4+
*/
5+
6+
#ifndef OPENVSWITCH_DROP_H
7+
#define OPENVSWITCH_DROP_H
8+
#include <linux/skbuff.h>
9+
#include <net/dropreason.h>
10+
11+
#define OVS_DROP_REASONS(R) \
12+
R(OVS_DROP_LAST_ACTION) \
13+
R(OVS_DROP_ACTION_ERROR) \
14+
R(OVS_DROP_EXPLICIT) \
15+
R(OVS_DROP_EXPLICIT_WITH_ERROR) \
16+
R(OVS_DROP_METER) \
17+
R(OVS_DROP_RECURSION_LIMIT) \
18+
R(OVS_DROP_DEFERRED_LIMIT) \
19+
R(OVS_DROP_FRAG_L2_TOO_LONG) \
20+
R(OVS_DROP_FRAG_INVALID_PROTO) \
21+
R(OVS_DROP_CONNTRACK) \
22+
R(OVS_DROP_IP_TTL) \
23+
/* deliberate comment for trailing \ */
24+
25+
enum ovs_drop_reason {
26+
__OVS_DROP_REASON = SKB_DROP_REASON_SUBSYS_OPENVSWITCH <<
27+
SKB_DROP_REASON_SUBSYS_SHIFT,
28+
#define ENUM(x) x,
29+
OVS_DROP_REASONS(ENUM)
30+
#undef ENUM
31+
32+
OVS_DROP_MAX,
33+
};
34+
35+
static inline void
36+
ovs_kfree_skb_reason(struct sk_buff *skb, enum ovs_drop_reason reason)
37+
{
38+
kfree_skb_reason(skb, (u32)reason);
39+
}
40+
41+
#endif /* OPENVSWITCH_DROP_H */

net/openvswitch/flow_netlink.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include <net/tun_proto.h>
3939
#include <net/erspan.h>
4040

41+
#include "drop.h"
4142
#include "flow_netlink.h"
4243

4344
struct ovs_len_tbl {
@@ -61,6 +62,7 @@ static bool actions_may_change_flow(const struct nlattr *actions)
6162
case OVS_ACTION_ATTR_RECIRC:
6263
case OVS_ACTION_ATTR_TRUNC:
6364
case OVS_ACTION_ATTR_USERSPACE:
65+
case OVS_ACTION_ATTR_DROP:
6466
break;
6567

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

23992401
if (!actions)
24002402
return;
@@ -3182,6 +3184,7 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
31823184
[OVS_ACTION_ATTR_CHECK_PKT_LEN] = (u32)-1,
31833185
[OVS_ACTION_ATTR_ADD_MPLS] = sizeof(struct ovs_action_add_mpls),
31843186
[OVS_ACTION_ATTR_DEC_TTL] = (u32)-1,
3187+
[OVS_ACTION_ATTR_DROP] = sizeof(u32),
31853188
};
31863189
const struct ovs_action_push_vlan *vlan;
31873190
int type = nla_type(a);
@@ -3453,6 +3456,11 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
34533456
skip_copy = true;
34543457
break;
34553458

3459+
case OVS_ACTION_ATTR_DROP:
3460+
if (!nla_is_last(a, rem))
3461+
return -EINVAL;
3462+
break;
3463+
34563464
default:
34573465
OVS_NLERR(log, "Unknown Action type %d", type);
34583466
return -EINVAL;

0 commit comments

Comments
 (0)