2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-31 22:35:15 +00:00

Add a new OVS action check_pkt_larger

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] - 4d5ec89fc8
[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: Ben Pfaff <blp@ovn.org>
This commit is contained in:
Numan Siddique
2019-04-23 00:53:38 +05:30
committed by Ben Pfaff
parent 718be50dae
commit 5b34f8fc3b
18 changed files with 713 additions and 2 deletions

View File

@@ -355,6 +355,9 @@ enum ofp_raw_action_type {
/* NX1.3+(48): void. */
NXAST_RAW_DEC_NSH_TTL,
/* NX1.0+(49): struct nx_action_check_pkt_larger, ... VLMFF */
NXAST_RAW_CHECK_PKT_LARGER,
/* ## ------------------ ## */
/* ## Debugging actions. ## */
/* ## ------------------ ## */
@@ -492,6 +495,7 @@ ofpact_next_flattened(const struct ofpact *ofpact)
case OFPACT_ENCAP:
case OFPACT_DECAP:
case OFPACT_DEC_NSH_TTL:
case OFPACT_CHECK_PKT_LARGER:
return ofpact_next(ofpact);
case OFPACT_CLONE:
@@ -7429,6 +7433,124 @@ check_WRITE_METADATA(const struct ofpact_metadata *a OVS_UNUSED,
return 0;
}
/* Check packet length action. */
struct nx_action_check_pkt_larger {
ovs_be16 type; /* OFPAT_VENDOR. */
ovs_be16 len; /* 24. */
ovs_be32 vendor; /* NX_VENDOR_ID. */
ovs_be16 subtype; /* NXAST_OUTPUT_REG. */
ovs_be16 pkt_len; /* Length of the packet to check. */
ovs_be16 offset; /* Result bit offset in destination. */
/* Followed by:
* - 'dst', as an OXM/NXM header (either 4 or 8 bytes).
* - Enough 0-bytes to pad the action out to 24 bytes. */
uint8_t pad[10];
};
OFP_ASSERT(sizeof(struct nx_action_check_pkt_larger) == 24);
static enum ofperr
decode_NXAST_RAW_CHECK_PKT_LARGER(
const struct nx_action_check_pkt_larger *ncpl,
enum ofp_version ofp_version OVS_UNUSED,
const struct vl_mff_map *vl_mff_map, uint64_t *tlv_bitmap,
struct ofpbuf *out)
{
struct ofpact_check_pkt_larger *check_pkt_larger;
enum ofperr error;
check_pkt_larger = ofpact_put_CHECK_PKT_LARGER(out);
check_pkt_larger->pkt_len = ntohs(ncpl->pkt_len);
check_pkt_larger->dst.ofs = ntohs(ncpl->offset);
check_pkt_larger->dst.n_bits = 1;
struct ofpbuf b = ofpbuf_const_initializer(ncpl, ntohs(ncpl->len));
ofpbuf_pull(&b, OBJECT_OFFSETOF(ncpl, pad));
error = mf_vl_mff_nx_pull_header(&b, vl_mff_map,
&check_pkt_larger->dst.field,
NULL, tlv_bitmap);
if (error) {
return error;
}
if (!is_all_zeros(b.data, b.size)) {
return OFPERR_NXBRC_MUST_BE_ZERO;
}
return mf_check_dst(&check_pkt_larger->dst, NULL);
}
static void
encode_CHECK_PKT_LARGER(const struct ofpact_check_pkt_larger *check_pkt_larger,
enum ofp_version ofp_version OVS_UNUSED,
struct ofpbuf *out)
{
struct nx_action_check_pkt_larger *ncpl = put_NXAST_CHECK_PKT_LARGER(out);
ncpl->pkt_len = htons(check_pkt_larger->pkt_len);
ncpl->offset = htons(check_pkt_larger->dst.ofs);
if (check_pkt_larger->dst.field) {
size_t size = out->size;
out->size = size - sizeof ncpl->pad;
nx_put_mff_header(out, check_pkt_larger->dst.field, 0, false);
out->size = size;
}
}
static char * OVS_WARN_UNUSED_RESULT
parse_CHECK_PKT_LARGER(char *arg, const struct ofpact_parse_params *pp)
{
char *value;
char *delim;
char *key;
char *error = set_field_split_str(arg, &key, &value, &delim);
if (error) {
return error;
}
delim[0] = '\0';
if (value[strlen(value) - 1] == ')') {
value[strlen(value) - 1] = '\0';
}
struct mf_subfield dst;
error = mf_parse_subfield(&dst, key);
if (error) {
return error;
}
if (dst.n_bits != 1) {
return xstrdup("Only 1-bit destination field is allowed");
}
struct ofpact_check_pkt_larger *check_pkt_larger =
ofpact_put_CHECK_PKT_LARGER(pp->ofpacts);
error = str_to_u16(value, NULL, &check_pkt_larger->pkt_len);
if (error) {
return error;
}
check_pkt_larger->dst = dst;
return NULL;
}
static void
format_CHECK_PKT_LARGER(const struct ofpact_check_pkt_larger *a,
const struct ofpact_format_params *fp)
{
ds_put_format(fp->s, "%scheck_pkt_larger(%s%"PRIu32")->",
colors.param, colors.end, a->pkt_len);
mf_format_subfield(&a->dst, fp->s);
}
static enum ofperr
check_CHECK_PKT_LARGER(const struct ofpact_check_pkt_larger *a OVS_UNUSED,
const struct ofpact_check_params *cp OVS_UNUSED)
{
return 0;
}
/* Goto-Table instruction. */
static void
@@ -7715,6 +7837,7 @@ action_set_classify(const struct ofpact *a)
case OFPACT_WRITE_METADATA:
case OFPACT_DEBUG_RECIRC:
case OFPACT_DEBUG_SLOW:
case OFPACT_CHECK_PKT_LARGER:
return ACTION_SLOT_INVALID;
default:
@@ -7914,6 +8037,7 @@ ovs_instruction_type_from_ofpact_type(enum ofpact_type type)
case OFPACT_ENCAP:
case OFPACT_DECAP:
case OFPACT_DEC_NSH_TTL:
case OFPACT_CHECK_PKT_LARGER:
default:
return OVSINST_OFPIT11_APPLY_ACTIONS;
}
@@ -8783,6 +8907,7 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port)
case OFPACT_ENCAP:
case OFPACT_DECAP:
case OFPACT_DEC_NSH_TTL:
case OFPACT_CHECK_PKT_LARGER:
default:
return false;
}
@@ -9019,7 +9144,6 @@ ofpacts_parse__(char *str, const struct ofpact_parse_params *pp,
enum ofpact_type type;
char *error = NULL;
ofp_port_t port;
if (ofpact_type_from_name(key, &type)) {
error = ofpact_parse(type, value, pp);
inst = ovs_instruction_type_from_ofpact_type(type);