Skip to content

Commit

Permalink
Add a new OVS action check_pkt_larger
Browse files Browse the repository at this point in the history
This patch adds a new action 'check_pkt_larger' which checks if the
packet is larger than the given size and stores the result in the
destination register.

Usage: check_pkt_larger(len)->REGISTER
Eg. match=...,actions=check_pkt_larger(1442)->NXM_NX_REG0[0],next;

This patch makes use of the new datapath action - 'check_pkt_len'
which was recently added in the commit [1].
At the start of ovs-vswitchd, datapath is probed for this action.
If the datapath action is present, then 'check_pkt_larger'
makes use of this datapath action.

Datapath action 'check_pkt_len' takes these nlattrs
      * OVS_CHECK_PKT_LEN_ATTR_PKT_LEN - 'pkt_len' to check for
      * OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER (optional) - Nested actions
        to apply if the packet length is greater than the specified 'pkt_len'
      * OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL (optional) - Nested
        actions to apply if the packet length is lesser or equal to the
        specified 'pkt_len'.

Let's say we have these flows added to an OVS bridge br-int

table=0, priority=100 in_port=1,ip,actions=check_pkt_larger:100->NXM_NX_REG0[0],resubmit(,1)
table=1, priority=200,in_port=1,ip,reg0=0x1/0x1 actions=output:3
table=1, priority=100,in_port=1,ip,actions=output:4

Then the action 'check_pkt_larger' will be translated as
  - check_pkt_len(size=100,gt(3),le(4))

datapath will check the packet length and if the packet length is greater than 100,
it will output to port 3, else it will output to port 4.

In case, datapath doesn't support 'check_pkt_len' action, the OVS action
'check_pkt_larger' sets SLOW_ACTION so that datapath flow is not added.

This OVS action is intended to be used by OVN to check the packet length
and generate an ICMP packet with type 3, code 4 and next hop mtu
in the logical router pipeline if the MTU of the physical interface
is lesser than the packet length. More information can be found here [2]

[1] - https://kernel.googlesource.com/pub/scm/linux/kernel/git/davem/net-next/+/4d5ec89fc8d14dcdab7214a0c13a1c7321dc6ea9
[2] - https://mail.openvswitch.org/pipermail/ovs-discuss/2018-July/047039.html

Reported-at:
https://mail.openvswitch.org/pipermail/ovs-discuss/2018-July/047039.html
Suggested-by: Ben Pfaff <blp@ovn.org>
Signed-off-by: Numan Siddique <nusiddiq@redhat.com>
CC: Ben Pfaff <blp@ovn.org>
CC: Gregory Rose <gvrose8192@gmail.com>
Acked-by: Mark Michelson <mmichels@redhat.com>
Signed-off-by: 0-day Robot <robot@bytheb.org>
  • Loading branch information
numansiddique authored and ovsrobot committed Apr 16, 2019
1 parent 50aa6e6 commit 6d4079d
Show file tree
Hide file tree
Showing 18 changed files with 718 additions and 2 deletions.
2 changes: 2 additions & 0 deletions NEWS
Expand Up @@ -5,6 +5,7 @@ Post-v2.11.0
hugepage memory that can be used by DPDK.
- OpenFlow:
* Removed support for OpenFlow 1.6 (draft), which ONF abandoned.
* New action "check_pkt_larger".
- Userspace datapath:
* ICMPv6 ND enhancements: support for match and set ND options type
and reserved fields.
Expand All @@ -17,6 +18,7 @@ Post-v2.11.0
conntrack fragmentation support.
* New "ovs-appctl dpctl/ipf-get-status" command for userspace datapath
conntrack fragmentation support.
* New action "check_pkt_len".
- OVSDB:
* OVSDB clients can now resynchronize with clustered servers much more
quickly after a brief disconnection, saving bandwidth and CPU time.
Expand Down
22 changes: 22 additions & 0 deletions datapath/linux/compat/include/linux/openvswitch.h
Expand Up @@ -863,6 +863,24 @@ enum ovs_nat_attr {

#define OVS_NAT_ATTR_MAX (__OVS_NAT_ATTR_MAX - 1)

/*
* enum ovs_check_pkt_len_attr - Attributes for %OVS_ACTION_ATTR_CHECK_PKT_LEN.
*
* @OVS_CHECK_PKT_LEN_ATTR_PKT_LEN: u16 Packet length to check for.
* @OVS_CHECK_PKT_LEN_ATTR_USERSPACE_COND: u8 comparison condition to send
* the packet to userspace. One of OVS_CHECK_PKT_LEN_COND_*.
* @OVS_CHECK_PKT_LEN_ATTR_USERPACE - Nested OVS_USERSPACE_ATTR_* actions.
*/
enum ovs_check_pkt_len_attr {
OVS_CHECK_PKT_LEN_ATTR_UNSPEC,
OVS_CHECK_PKT_LEN_ATTR_PKT_LEN,
OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER,
OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL,
__OVS_CHECK_PKT_LEN_ATTR_MAX,
};

#define OVS_CHECK_PKT_LEN_ATTR_MAX (__OVS_CHECK_PKT_LEN_ATTR_MAX - 1)

/**
* enum ovs_action_attr - Action types.
*
Expand Down Expand Up @@ -919,6 +937,9 @@ enum ovs_nat_attr {
* packet, or modify the packet (e.g., change the DSCP field).
* @OVS_ACTION_ATTR_CLONE: make a copy of the packet and execute a list of
* actions without affecting the original packet and key.
* @OVS_ACTION_ATTR_CHECK_PKT_LEN: Check the packet length and execute a set
* of actions if greater than the specified packet length, else execute
* another set of actions.
*/

enum ovs_action_attr {
Expand Down Expand Up @@ -946,6 +967,7 @@ enum ovs_action_attr {
OVS_ACTION_ATTR_POP_NSH, /* No argument. */
OVS_ACTION_ATTR_METER, /* u32 meter number. */
OVS_ACTION_ATTR_CLONE, /* Nested OVS_CLONE_ATTR_*. */
OVS_ACTION_ATTR_CHECK_PKT_LEN, /* Nested OVS_CHECK_PKT_LEN_ATTR_*. */

#ifndef __KERNEL__
OVS_ACTION_ATTR_TUNNEL_PUSH, /* struct ovs_action_push_tnl*/
Expand Down
19 changes: 19 additions & 0 deletions include/openvswitch/ofp-actions.h
Expand Up @@ -123,6 +123,8 @@ struct vl_mff_map;
OFPACT(NAT, ofpact_nat, ofpact, "nat") \
OFPACT(OUTPUT_TRUNC, ofpact_output_trunc,ofpact, "output_trunc") \
OFPACT(CLONE, ofpact_nest, actions, "clone") \
OFPACT(CHECK_PKT_LARGER, ofpact_check_pkt_larger, ofpact, \
"check_pkt_larger") \
\
/* Debugging actions. \
* \
Expand Down Expand Up @@ -225,6 +227,13 @@ ofpact_last(const struct ofpact *a, const struct ofpact *ofpacts,
return ofpact_next(a) == ofpact_end(ofpacts, ofpact_len);
}

static inline size_t
ofpact_remaining_len(const struct ofpact *a, const struct ofpact *ofpacts,
size_t ofpact_len)
{
return ofpact_len - ((uint8_t *)a - (uint8_t *)ofpacts);
}

static inline const struct ofpact *
ofpact_find_type_flattened(const struct ofpact *a, enum ofpact_type type,
const struct ofpact * const end)
Expand Down Expand Up @@ -620,6 +629,16 @@ struct ofpact_meter {
);
};

/* OFPACT_CHECK_PKT_LARGER.
*
* Used for NXAST_CHECK_PKT_LARGER. */
struct ofpact_check_pkt_larger {
OFPACT_PADDED_MEMBERS(
struct ofpact ofpact;
struct mf_subfield dst;
uint16_t pkt_len;
);
};
/* OFPACT_WRITE_ACTIONS, OFPACT_CLONE.
*
* Used for OFPIT11_WRITE_ACTIONS, NXAST_CLONE. */
Expand Down
1 change: 1 addition & 0 deletions lib/dpif-netdev.c
Expand Up @@ -7249,6 +7249,7 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
case OVS_ACTION_ATTR_PUSH_NSH:
case OVS_ACTION_ATTR_POP_NSH:
case OVS_ACTION_ATTR_CT_CLEAR:
case OVS_ACTION_ATTR_CHECK_PKT_LEN:
case __OVS_ACTION_ATTR_MAX:
OVS_NOT_REACHED();
}
Expand Down
1 change: 1 addition & 0 deletions lib/dpif.c
Expand Up @@ -1266,6 +1266,7 @@ dpif_execute_helper_cb(void *aux_, struct dp_packet_batch *packets_,
case OVS_ACTION_ATTR_POP_NSH:
case OVS_ACTION_ATTR_CT_CLEAR:
case OVS_ACTION_ATTR_UNSPEC:
case OVS_ACTION_ATTR_CHECK_PKT_LEN:
case __OVS_ACTION_ATTR_MAX:
OVS_NOT_REACHED();
}
Expand Down
72 changes: 72 additions & 0 deletions lib/odp-execute.c
Expand Up @@ -674,6 +674,64 @@ odp_execute_clone(void *dp, struct dp_packet_batch *batch, bool steal,
}
}

static void
odp_execute_check_pkt_len(void *dp, struct dp_packet *packet, bool steal,
const struct nlattr *action,
odp_execute_cb dp_execute_action)
{
const struct nlattr *a;
const struct nlattr *attrs[OVS_CHECK_PKT_LEN_ATTR_MAX + 1];
const struct nlattr *subactions = NULL;
size_t subactions_size = 0;
struct dp_packet_batch pb;
size_t left;

bool is_greater = false;
memset(attrs, 0, sizeof(attrs));
NL_NESTED_FOR_EACH_UNSAFE (a, left, action) {
int type = nl_attr_type(a);

if (!type || type > OVS_CHECK_PKT_LEN_ATTR_MAX || attrs[type]) {
OVS_NOT_REACHED();
}
attrs[type] = a;
}

if (left) {
OVS_NOT_REACHED();
}
a = attrs[OVS_CHECK_PKT_LEN_ATTR_PKT_LEN];
if (!a) {
OVS_NOT_REACHED();
}

is_greater = dp_packet_size(packet) > nl_attr_get_u16(a);
if (is_greater) {
a = attrs[OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER];
} else {
a = attrs[OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL];
}

if (a) {
subactions = nl_attr_get(a);
subactions_size = nl_attr_get_size(a);
}

if (!steal) {
/* The 'subactions' may modify the packet, but the modification
* should not propagate beyond this action. Make a copy
* the packet in case we don't own the packet, so that the
* 'subactions' are only applid to check_pkt_len. 'odp_execute_actions'
* will free the clone. */
packet = dp_packet_clone(packet);
}
/* If subactions is NULL, the packet will be freed by
* odp_execute_actions. */
dp_packet_batch_init_packet(&pb, packet);
odp_execute_actions(dp, &pb, true, subactions, subactions_size,
dp_execute_action);
}

static bool
requires_datapath_assistance(const struct nlattr *a)
{
Expand Down Expand Up @@ -705,6 +763,7 @@ requires_datapath_assistance(const struct nlattr *a)
case OVS_ACTION_ATTR_PUSH_NSH:
case OVS_ACTION_ATTR_POP_NSH:
case OVS_ACTION_ATTR_CT_CLEAR:
case OVS_ACTION_ATTR_CHECK_PKT_LEN:
return false;

case OVS_ACTION_ATTR_UNSPEC:
Expand Down Expand Up @@ -932,6 +991,19 @@ odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal,
}
break;

case OVS_ACTION_ATTR_CHECK_PKT_LEN:
DP_PACKET_BATCH_FOR_EACH (i, packet, batch) {
odp_execute_check_pkt_len(dp, packet, steal && last_action, a,
dp_execute_action);
}

if (last_action) {
/* We do not need to free the packets.
* odp_execute_check_pkt_len() has stolen them. */
return;
}
break;

case OVS_ACTION_ATTR_OUTPUT:
case OVS_ACTION_ATTR_TUNNEL_PUSH:
case OVS_ACTION_ATTR_TUNNEL_POP:
Expand Down
86 changes: 86 additions & 0 deletions lib/odp-util.c
Expand Up @@ -132,6 +132,7 @@ odp_action_len(uint16_t type)
case OVS_ACTION_ATTR_CLONE: return ATTR_LEN_VARIABLE;
case OVS_ACTION_ATTR_PUSH_NSH: return ATTR_LEN_VARIABLE;
case OVS_ACTION_ATTR_POP_NSH: return 0;
case OVS_ACTION_ATTR_CHECK_PKT_LEN: return ATTR_LEN_VARIABLE;

case OVS_ACTION_ATTR_UNSPEC:
case __OVS_ACTION_ATTR_MAX:
Expand Down Expand Up @@ -1044,6 +1045,42 @@ format_odp_set_nsh(struct ds *ds, const struct nlattr *attr)
ds_put_cstr(ds, "))");
}

static void
format_odp_check_pkt_len_action(struct ds *ds, const struct nlattr *attr,
const struct hmap *portno_names OVS_UNUSED)
{
static const struct nl_policy ovs_cpl_policy[] = {
[OVS_CHECK_PKT_LEN_ATTR_PKT_LEN] = { .type = NL_A_U16 },
[OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER] = { .type = NL_A_NESTED },
[OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL]
= { .type = NL_A_NESTED },
};
struct nlattr *a[ARRAY_SIZE(ovs_cpl_policy)];
ds_put_cstr(ds, "check_pkt_len");
if (!nl_parse_nested(attr, ovs_cpl_policy, a, ARRAY_SIZE(a))) {
ds_put_cstr(ds, "(error)");
return;
}

if (!a[OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER] ||
!a[OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL]) {
ds_put_cstr(ds, "(error)");
return;
}

uint16_t pkt_len = nl_attr_get_u16(a[OVS_CHECK_PKT_LEN_ATTR_PKT_LEN]);
ds_put_format(ds, "(size=%u,gt(", pkt_len);
const struct nlattr *acts;
acts = a[OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER];
format_odp_actions(ds, nl_attr_get(acts), nl_attr_get_size(acts),
portno_names);

ds_put_cstr(ds, "),le(");
acts = a[OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL];
format_odp_actions(ds, nl_attr_get(acts), nl_attr_get_size(acts),
portno_names);
ds_put_cstr(ds, "))");
}

static void
format_odp_action(struct ds *ds, const struct nlattr *a,
Expand Down Expand Up @@ -1183,6 +1220,9 @@ format_odp_action(struct ds *ds, const struct nlattr *a,
case OVS_ACTION_ATTR_POP_NSH:
ds_put_cstr(ds, "pop_nsh()");
break;
case OVS_ACTION_ATTR_CHECK_PKT_LEN:
format_odp_check_pkt_len_action(ds, a, portno_names);
break;
case OVS_ACTION_ATTR_UNSPEC:
case __OVS_ACTION_ATTR_MAX:
default:
Expand Down Expand Up @@ -2399,6 +2439,52 @@ parse_odp_action(const char *s, const struct simap *port_names,
}
}

{
uint16_t pkt_len;
int n = -1;
if (ovs_scan(s, "check_pkt_len(size=%"SCNi16",gt(%n", &pkt_len, &n)) {
size_t cpl_ofs, actions_ofs;
cpl_ofs = nl_msg_start_nested(actions,
OVS_ACTION_ATTR_CHECK_PKT_LEN);
nl_msg_put_u16(actions, OVS_CHECK_PKT_LEN_ATTR_PKT_LEN, pkt_len);
actions_ofs = nl_msg_start_nested(
actions, OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER);

int retval;
if (!strncasecmp(s + n, "drop", 4)) {
n += 4;
} else {
retval = parse_action_list(s + n, port_names, actions);
if (retval < 0) {
return retval;
}

n += retval;
}
nl_msg_end_nested(actions, actions_ofs);
retval = -1;
if (!ovs_scan(s + n, "),le(%n", &retval)) {
return -EINVAL;
}
n += retval;

actions_ofs = nl_msg_start_nested(
actions, OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL);
if (!strncasecmp(s + n, "drop", 4)) {
n += 4;
} else {
retval = parse_action_list(s + n, port_names, actions);
if (retval < 0) {
return retval;
}
n += retval;
}
nl_msg_end_nested(actions, actions_ofs);
nl_msg_end_nested(actions, cpl_ofs);
return s[n + 1] == ')' ? n + 2 : -EINVAL;
}
}

{
int retval;

Expand Down

0 comments on commit 6d4079d

Please sign in to comment.