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:
committed by
Pravin B Shelar
parent
4c7804f14b
commit
aaca4fe0ce
@@ -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:
|
||||
|
Reference in New Issue
Block a user