2
0
mirror of https://github.com/openvswitch/ovs synced 2025-09-05 08:45:23 +00:00

ofp-actions: Add truncate action.

The patch adds a new action to support packet truncation.  The new action
is formatted as 'output(port=n,max_len=m)', as output to port n, with
packet size being MIN(original_size, m).

One use case is to enable port mirroring to send smaller packets to the
destination port so that only useful packet information is mirrored/copied,
saving some performance overhead of copying entire packet payload.  Example
use case is below as well as shown in the testcases:

    - Output to port 1 with max_len 100 bytes.
    - The output packet size on port 1 will be MIN(original_packet_size, 100).
    # ovs-ofctl add-flow br0 'actions=output(port=1,max_len=100)'

    - The scope of max_len is limited to output action itself.  The following
      packet size of output:1 and output:2 will be intact.
    # ovs-ofctl add-flow br0 \
            'actions=output(port=1,max_len=100),output:1,output:2'
    - The Datapath actions shows:
    # Datapath actions: trunc(100),1,1,2

Tested-at: https://travis-ci.org/williamtu/ovs-travis/builds/140037134
Signed-off-by: William Tu <u9012063@gmail.com>
Acked-by: Pravin B Shelar <pshelar@ovn.org>
This commit is contained in:
William Tu
2016-06-24 07:42:30 -07:00
committed by Pravin B Shelar
parent 4c7804f14b
commit aaca4fe0ce
27 changed files with 848 additions and 4 deletions

View File

@@ -301,6 +301,9 @@ enum ofp_raw_action_type {
/* NX1.0+(36): struct nx_action_nat, ... */
NXAST_RAW_NAT,
/* NX1.0+(39): struct nx_action_output_trunc. */
NXAST_RAW_OUTPUT_TRUNC,
/* ## ------------------ ## */
/* ## Debugging actions. ## */
/* ## ------------------ ## */
@@ -381,6 +384,7 @@ ofpact_next_flattened(const struct ofpact *ofpact)
case OFPACT_CONTROLLER:
case OFPACT_ENQUEUE:
case OFPACT_OUTPUT_REG:
case OFPACT_OUTPUT_TRUNC:
case OFPACT_BUNDLE:
case OFPACT_SET_FIELD:
case OFPACT_SET_VLAN_VID:
@@ -537,6 +541,40 @@ encode_OUTPUT(const struct ofpact_output *output,
}
}
static char * OVS_WARN_UNUSED_RESULT
parse_truncate_subfield(struct ofpact_output_trunc *output_trunc,
const char *arg_)
{
char *key, *value;
char *arg = CONST_CAST(char *, arg_);
while (ofputil_parse_key_value(&arg, &key, &value)) {
if (!strcmp(key, "port")) {
if (!ofputil_port_from_string(value, &output_trunc->port)) {
return xasprintf("output to unknown truncate port: %s",
value);
}
if (ofp_to_u16(output_trunc->port) > ofp_to_u16(OFPP_MAX)) {
if (output_trunc->port != OFPP_LOCAL &&
output_trunc->port != OFPP_IN_PORT)
return xasprintf("output to unsupported truncate port: %s",
value);
}
} else if (!strcmp(key, "max_len")) {
char *err;
err = str_to_u32(value, &output_trunc->max_len);
if (err) {
return err;
}
} else {
return xasprintf("invalid key '%s' in output_trunc argument",
key);
}
}
return NULL;
}
static char * OVS_WARN_UNUSED_RESULT
parse_OUTPUT(const char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
@@ -547,6 +585,11 @@ parse_OUTPUT(const char *arg, struct ofpbuf *ofpacts,
output_reg = ofpact_put_OUTPUT_REG(ofpacts);
output_reg->max_len = UINT16_MAX;
return mf_parse_subfield(&output_reg->src, arg);
} else if (strstr(arg, "port") && strstr(arg, "max_len")) {
struct ofpact_output_trunc *output_trunc;
output_trunc = ofpact_put_OUTPUT_TRUNC(ofpacts);
return parse_truncate_subfield(output_trunc, arg);
} else {
struct ofpact_output *output;
@@ -5603,6 +5646,61 @@ parse_NAT(char *arg, struct ofpbuf *ofpacts,
return NULL;
}
/* Truncate output action. */
struct nx_action_output_trunc {
ovs_be16 type; /* OFPAT_VENDOR. */
ovs_be16 len; /* At least 16. */
ovs_be32 vendor; /* NX_VENDOR_ID. */
ovs_be16 subtype; /* NXAST_OUTPUT_TRUNC. */
ovs_be16 port; /* Output port */
ovs_be32 max_len; /* Truncate packet to size bytes */
};
OFP_ASSERT(sizeof(struct nx_action_output_trunc) == 16);
static enum ofperr
decode_NXAST_RAW_OUTPUT_TRUNC(const struct nx_action_output_trunc *natrc,
enum ofp_version ofp_version OVS_UNUSED,
struct ofpbuf *out)
{
struct ofpact_output_trunc *output_trunc;
output_trunc = ofpact_put_OUTPUT_TRUNC(out);
output_trunc->max_len = ntohl(natrc->max_len);
output_trunc->port = u16_to_ofp(ntohs(natrc->port));
if (output_trunc->max_len < ETH_HEADER_LEN) {
return OFPERR_OFPBAC_BAD_ARGUMENT;
}
return 0;
}
static void
encode_OUTPUT_TRUNC(const struct ofpact_output_trunc *output_trunc,
enum ofp_version ofp_version OVS_UNUSED,
struct ofpbuf *out)
{
struct nx_action_output_trunc *natrc = put_NXAST_OUTPUT_TRUNC(out);
natrc->max_len = htonl(output_trunc->max_len);
natrc->port = htons(ofp_to_u16(output_trunc->port));
}
static char * OVS_WARN_UNUSED_RESULT
parse_OUTPUT_TRUNC(const char *arg, struct ofpbuf *ofpacts OVS_UNUSED,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
/* Disable output_trunc parsing. Expose as output(port=N,max_len=M) and
* reuse parse_OUTPUT to parse output_trunc action. */
return xasprintf("unknown action %s", arg);
}
static void
format_OUTPUT_TRUNC(const struct ofpact_output_trunc *a, struct ds *s)
{
ds_put_format(s, "%soutput%s(port=%"PRIu16",max_len=%"PRIu32")",
colors.special, colors.end, a->port, a->max_len);
}
/* Meter instruction. */
@@ -5997,6 +6095,7 @@ ofpact_is_set_or_move_action(const struct ofpact *a)
case OFPACT_NOTE:
case OFPACT_OUTPUT:
case OFPACT_OUTPUT_REG:
case OFPACT_OUTPUT_TRUNC:
case OFPACT_POP_MPLS:
case OFPACT_POP_QUEUE:
case OFPACT_PUSH_MPLS:
@@ -6025,6 +6124,7 @@ ofpact_is_allowed_in_actions_set(const struct ofpact *a)
case OFPACT_DEC_TTL:
case OFPACT_GROUP:
case OFPACT_OUTPUT:
case OFPACT_OUTPUT_TRUNC:
case OFPACT_POP_MPLS:
case OFPACT_PUSH_MPLS:
case OFPACT_PUSH_VLAN:
@@ -6249,6 +6349,7 @@ ovs_instruction_type_from_ofpact_type(enum ofpact_type type)
case OFPACT_CONTROLLER:
case OFPACT_ENQUEUE:
case OFPACT_OUTPUT_REG:
case OFPACT_OUTPUT_TRUNC:
case OFPACT_BUNDLE:
case OFPACT_SET_VLAN_VID:
case OFPACT_SET_VLAN_PCP:
@@ -6677,6 +6778,10 @@ ofpact_check__(enum ofputil_protocol *usable_protocols, struct ofpact *a,
case OFPACT_OUTPUT_REG:
return mf_check_src(&ofpact_get_OUTPUT_REG(a)->src, flow);
case OFPACT_OUTPUT_TRUNC:
return ofpact_check_output_port(ofpact_get_OUTPUT_TRUNC(a)->port,
max_ports);
case OFPACT_BUNDLE:
return bundle_check(ofpact_get_BUNDLE(a), max_ports, flow);
@@ -7354,6 +7459,7 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port)
return port == OFPP_CONTROLLER;
case OFPACT_OUTPUT_REG:
case OFPACT_OUTPUT_TRUNC:
case OFPACT_BUNDLE:
case OFPACT_SET_VLAN_VID:
case OFPACT_SET_VLAN_PCP: