Commit e7bc7db9 authored by Eric Garver's avatar Eric Garver Committed by David S. Miller

net: openvswitch: add explicit drop action

From: Eric Garver <eric@garver.life>

This adds an explicit drop action. This is used by OVS to drop packets
for which it cannot determine what to do. An explicit action in the
kernel allows passing the reason _why_ the packet is being dropped or
zero to indicate no particular error happened (i.e: OVS intentionally
dropped the packet).

Since the error codes coming from userspace mean nothing for the kernel,
we squash all of them into only two drop reasons:
- OVS_DROP_EXPLICIT_WITH_ERROR to indicate a non-zero value was passed
- OVS_DROP_EXPLICIT to indicate a zero value was passed (no error)

e.g. trace all OVS dropped skbs

 # perf trace -e skb:kfree_skb --filter="reason >= 0x30000"
 [..]
 106.023 ping/2465 skb:kfree_skb(skbaddr: 0xffffa0e8765f2000, \
  location:0xffffffffc0d9b462, protocol: 2048, reason: 196611)

reason: 196611 --> 0x30003 (OVS_DROP_EXPLICIT)

Also, this patch allows ovs-dpctl.py to add explicit drop actions as:
  "drop"     -> implicit empty-action drop
  "drop(0)"  -> explicit non-error action drop
  "drop(42)" -> explicit error action drop
Signed-off-by: default avatarEric Garver <eric@garver.life>
Co-developed-by: default avatarAdrian Moreno <amorenoz@redhat.com>
Signed-off-by: default avatarAdrian Moreno <amorenoz@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ec7bfb5e
...@@ -965,6 +965,7 @@ struct check_pkt_len_arg { ...@@ -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 * 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 * of l3 tunnel flag in the tun_flags field of OVS_ACTION_ATTR_ADD_MPLS
* argument. * argument.
* @OVS_ACTION_ATTR_DROP: Explicit drop action.
* *
* Only a single header can be set with a single %OVS_ACTION_ATTR_SET. Not all * 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 * fields within a header are modifiable, e.g. the IPv4 protocol and fragment
...@@ -1002,6 +1003,7 @@ enum ovs_action_attr { ...@@ -1002,6 +1003,7 @@ enum ovs_action_attr {
OVS_ACTION_ATTR_CHECK_PKT_LEN, /* Nested OVS_CHECK_PKT_LEN_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_ADD_MPLS, /* struct ovs_action_add_mpls. */
OVS_ACTION_ATTR_DEC_TTL, /* Nested OVS_DEC_TTL_ATTR_*. */ 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 __OVS_ACTION_ATTR_MAX, /* Nothing past this will be accepted
* from userspace. */ * from userspace. */
......
...@@ -1485,6 +1485,15 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, ...@@ -1485,6 +1485,15 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
return dec_ttl_exception_handler(dp, skb, return dec_ttl_exception_handler(dp, skb,
key, a); key, a);
break; 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)) { if (unlikely(err)) {
......
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
#define OVS_DROP_REASONS(R) \ #define OVS_DROP_REASONS(R) \
R(OVS_DROP_LAST_ACTION) \ R(OVS_DROP_LAST_ACTION) \
R(OVS_DROP_ACTION_ERROR) \ R(OVS_DROP_ACTION_ERROR) \
R(OVS_DROP_EXPLICIT) \
R(OVS_DROP_EXPLICIT_WITH_ERROR) \
/* deliberate comment for trailing \ */ /* deliberate comment for trailing \ */
enum ovs_drop_reason { enum ovs_drop_reason {
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include <net/tun_proto.h> #include <net/tun_proto.h>
#include <net/erspan.h> #include <net/erspan.h>
#include "drop.h"
#include "flow_netlink.h" #include "flow_netlink.h"
struct ovs_len_tbl { struct ovs_len_tbl {
...@@ -61,6 +62,7 @@ static bool actions_may_change_flow(const struct nlattr *actions) ...@@ -61,6 +62,7 @@ static bool actions_may_change_flow(const struct nlattr *actions)
case OVS_ACTION_ATTR_RECIRC: case OVS_ACTION_ATTR_RECIRC:
case OVS_ACTION_ATTR_TRUNC: case OVS_ACTION_ATTR_TRUNC:
case OVS_ACTION_ATTR_USERSPACE: case OVS_ACTION_ATTR_USERSPACE:
case OVS_ACTION_ATTR_DROP:
break; break;
case OVS_ACTION_ATTR_CT: case OVS_ACTION_ATTR_CT:
...@@ -2394,7 +2396,7 @@ static void ovs_nla_free_nested_actions(const struct nlattr *actions, int len) ...@@ -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 /* Whenever new actions are added, the need to update this
* function should be considered. * function should be considered.
*/ */
BUILD_BUG_ON(OVS_ACTION_ATTR_MAX != 23); BUILD_BUG_ON(OVS_ACTION_ATTR_MAX != 24);
if (!actions) if (!actions)
return; return;
...@@ -3182,6 +3184,7 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, ...@@ -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_CHECK_PKT_LEN] = (u32)-1,
[OVS_ACTION_ATTR_ADD_MPLS] = sizeof(struct ovs_action_add_mpls), [OVS_ACTION_ATTR_ADD_MPLS] = sizeof(struct ovs_action_add_mpls),
[OVS_ACTION_ATTR_DEC_TTL] = (u32)-1, [OVS_ACTION_ATTR_DEC_TTL] = (u32)-1,
[OVS_ACTION_ATTR_DROP] = sizeof(u32),
}; };
const struct ovs_action_push_vlan *vlan; const struct ovs_action_push_vlan *vlan;
int type = nla_type(a); int type = nla_type(a);
...@@ -3453,6 +3456,11 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, ...@@ -3453,6 +3456,11 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
skip_copy = true; skip_copy = true;
break; break;
case OVS_ACTION_ATTR_DROP:
if (!nla_is_last(a, rem))
return -EINVAL;
break;
default: default:
OVS_NLERR(log, "Unknown Action type %d", type); OVS_NLERR(log, "Unknown Action type %d", type);
return -EINVAL; return -EINVAL;
......
...@@ -301,6 +301,7 @@ class ovsactions(nla): ...@@ -301,6 +301,7 @@ class ovsactions(nla):
("OVS_ACTION_ATTR_CHECK_PKT_LEN", "none"), ("OVS_ACTION_ATTR_CHECK_PKT_LEN", "none"),
("OVS_ACTION_ATTR_ADD_MPLS", "none"), ("OVS_ACTION_ATTR_ADD_MPLS", "none"),
("OVS_ACTION_ATTR_DEC_TTL", "none"), ("OVS_ACTION_ATTR_DEC_TTL", "none"),
("OVS_ACTION_ATTR_DROP", "uint32"),
) )
class ctact(nla): class ctact(nla):
...@@ -447,6 +448,8 @@ class ovsactions(nla): ...@@ -447,6 +448,8 @@ class ovsactions(nla):
print_str += "recirc(0x%x)" % int(self.get_attr(field[0])) print_str += "recirc(0x%x)" % int(self.get_attr(field[0]))
elif field[0] == "OVS_ACTION_ATTR_TRUNC": elif field[0] == "OVS_ACTION_ATTR_TRUNC":
print_str += "trunc(%d)" % int(self.get_attr(field[0])) print_str += "trunc(%d)" % int(self.get_attr(field[0]))
elif field[0] == "OVS_ACTION_ATTR_DROP":
print_str += "drop(%d)" % int(self.get_attr(field[0]))
elif field[1] == "flag": elif field[1] == "flag":
if field[0] == "OVS_ACTION_ATTR_CT_CLEAR": if field[0] == "OVS_ACTION_ATTR_CT_CLEAR":
print_str += "ct_clear" print_str += "ct_clear"
...@@ -468,10 +471,21 @@ class ovsactions(nla): ...@@ -468,10 +471,21 @@ class ovsactions(nla):
while len(actstr) != 0: while len(actstr) != 0:
parsed = False parsed = False
if actstr.startswith("drop"): if actstr.startswith("drop"):
# for now, drops have no explicit action, so we # If no reason is provided, the implicit drop is used (i.e no
# don't need to set any attributes. The final # action). If some reason is given, an explicit action is used.
# act of the processing chain will just drop the packet actstr, reason = parse_extract_field(
return actstr,
"drop(",
"([0-9]+)",
lambda x: int(x, 0),
False,
None,
)
if reason is not None:
self["attrs"].append(["OVS_ACTION_ATTR_DROP", reason])
parsed = True
else:
return
elif parse_starts_block(actstr, "^(\d+)", False, True): elif parse_starts_block(actstr, "^(\d+)", False, True):
actstr, output = parse_extract_field( actstr, output = parse_extract_field(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment