2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-22 01:51:26 +00:00

ofp-actions: Add delete field action

This patch adds a new OpenFlow action, delete field, to delete a
field in packets.  Currently, only the tun_metadata fields are
supported.

One use case to add this action is to support multiple versions
of geneve tunnel metadatas to be exchanged among different versions
of networks.  For example, we may introduce tun_metadata2 to
replace old tun_metadata1, but still want to provide backward
compatibility to the older release.  In this case, in the new
OpenFlow pipeline, we would like to support the case to receive a
packet with tun_metadata1, do some processing.  And if the packet
is going to a switch in the newer release, we would like to delete
the value in tun_metadata1 and set a value into tun_metadata2.

Currently, ovs does not provide an action to remove a value in
tun_metadata if the value is present.  This patch fulfills the gap
by adding the delete_field action.  For example, the OpenFlow
syntax to delete tun_metadata1 is:

    actions=delete_field:tun_metadata1

Signed-off-by: Yi-Hung Wei <yihung.wei@gmail.com>
Signed-off-by: William Tu <u9012063@gmail.com>
Acked-by: William Tu <u9012063@gmail.com>
This commit is contained in:
Yi-Hung Wei 2020-04-14 13:33:28 -07:00 committed by William Tu
parent 5e76d41d52
commit 81f71381ff
11 changed files with 221 additions and 5 deletions

1
NEWS
View File

@ -5,6 +5,7 @@ Post-v2.13.0
* The OpenFlow ofp_desc/serial_num may now be configured by setting the
value of other-config:dp-sn in the Bridge table.
* Added support to watch CONTROLLER port status in fast failover group.
* New action "delete_field".
- DPDK:
* Deprecated DPDK pdump packet capture support removed.
* Deprecated DPDK ring ports (dpdkr) are no longer supported.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017, 2019 Nicira, Inc.
* Copyright (c) 2012-2017, 2019-2020 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -94,6 +94,7 @@ struct vl_mff_map;
OFPACT(PUSH_MPLS, ofpact_push_mpls, ofpact, "push_mpls") \
OFPACT(POP_MPLS, ofpact_pop_mpls, ofpact, "pop_mpls") \
OFPACT(DEC_NSH_TTL, ofpact_null, ofpact, "dec_nsh_ttl") \
OFPACT(DELETE_FIELD, ofpact_delete_field, ofpact, "delete_field") \
\
/* Generic encap & decap */ \
OFPACT(ENCAP, ofpact_encap, props, "encap") \
@ -576,6 +577,16 @@ struct ofpact_pop_mpls {
);
};
/* OFPACT_DELETE_FIELD.
*
* Used for NXAST_DELETE_FIELD. */
struct ofpact_delete_field {
OFPACT_PADDED_MEMBERS(
struct ofpact ofpact;
const struct mf_field *field;
);
};
/* OFPACT_SET_TUNNEL.
*
* Used for NXAST_SET_TUNNEL, NXAST_SET_TUNNEL64. */

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Nicira, Inc.
* Copyright (c) 2010-2017, 2020 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -1994,6 +1994,24 @@ nxm_execute_stack_pop(const struct ofpact_stack *pop,
}
}
/* Parses a field from '*s' into '*field'. If successful, stores the
* reference to the field in '*field', and returns NULL. On failure,
* returns a malloc()'ed error message.
*/
char * OVS_WARN_UNUSED_RESULT
mf_parse_field(const struct mf_field **field, const char *s)
{
const struct nxm_field *f;
int s_len = strlen(s);
f = nxm_field_by_name(s, s_len);
(*field) = f ? mf_from_id(f->id) : mf_from_name_len(s, s_len);
if (!*field) {
return xasprintf("unknown field `%s'", s);
}
return NULL;
}
/* Formats 'sf' into 's' in a format normally acceptable to
* mf_parse_subfield(). (It won't be acceptable if sf->field is NULL or if
* sf->field has no NXM name.) */

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2017 Nicira, Inc.
* Copyright (c) 2010-2017, 2020 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -42,6 +42,8 @@ struct vl_mff_map;
* See include/openflow/nicira-ext.h for NXM specification.
*/
char * mf_parse_field(const struct mf_field **field, const char *s)
OVS_WARN_UNUSED_RESULT;
void mf_format_subfield(const struct mf_subfield *, struct ds *);
char *mf_parse_subfield__(struct mf_subfield *sf, const char **s)
OVS_WARN_UNUSED_RESULT;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008-2017, 2019 Nicira, Inc.
* Copyright (c) 2008-2017, 2019-2020 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -361,6 +361,9 @@ enum ofp_raw_action_type {
/* NX1.0+(49): struct nx_action_check_pkt_larger, ... VLMFF */
NXAST_RAW_CHECK_PKT_LARGER,
/* NX1.0+(50): struct nx_action_delete_field. VLMFF */
NXAST_RAW_DELETE_FIELD,
/* ## ------------------ ## */
/* ## Debugging actions. ## */
/* ## ------------------ ## */
@ -500,6 +503,7 @@ ofpact_next_flattened(const struct ofpact *ofpact)
case OFPACT_DECAP:
case OFPACT_DEC_NSH_TTL:
case OFPACT_CHECK_PKT_LARGER:
case OFPACT_DELETE_FIELD:
return ofpact_next(ofpact);
case OFPACT_CLONE:
@ -4140,6 +4144,87 @@ check_SET_TUNNEL(const struct ofpact_tunnel *a OVS_UNUSED,
return 0;
}
/* Delete field action. */
/* Action structure for DELETE_FIELD */
struct nx_action_delete_field {
ovs_be16 type; /* OFPAT_VENDOR */
ovs_be16 len; /* Length is 24. */
ovs_be32 vendor; /* NX_VENDOR_ID. */
ovs_be16 subtype; /* NXAST_DELETE_FIELD. */
/* Followed by:
* - OXM/NXM header for field to delete (4 or 8 bytes).
* - Enough 0-bytes to pad out the action to 24 bytes. */
uint8_t pad[14];
};
OFP_ASSERT(sizeof(struct nx_action_delete_field ) == 24);
static enum ofperr
decode_NXAST_RAW_DELETE_FIELD(const struct nx_action_delete_field *nadf,
enum ofp_version ofp_version OVS_UNUSED,
const struct vl_mff_map *vl_mff_map,
uint64_t *tlv_bitmap, struct ofpbuf *out)
{
struct ofpact_delete_field *delete_field;
enum ofperr err;
delete_field = ofpact_put_DELETE_FIELD(out);
delete_field->ofpact.raw = NXAST_RAW_DELETE_FIELD;
struct ofpbuf b = ofpbuf_const_initializer(nadf, ntohs(nadf->len));
ofpbuf_pull(&b, OBJECT_OFFSETOF(nadf, pad));
err = mf_vl_mff_nx_pull_header(&b, vl_mff_map, &delete_field->field,
NULL, tlv_bitmap);
if (err) {
return err;
}
return 0;
}
static void
encode_DELETE_FIELD(const struct ofpact_delete_field *delete_field,
enum ofp_version ofp_version OVS_UNUSED,
struct ofpbuf *out)
{
struct nx_action_delete_field *nadf = put_NXAST_DELETE_FIELD(out);
size_t size = out->size;
out->size = size - sizeof nadf->pad;
nx_put_mff_header(out, delete_field->field, 0, false);
out->size = size;
}
static char * OVS_WARN_UNUSED_RESULT
parse_DELETE_FIELD(char *arg, const struct ofpact_parse_params *pp)
{
struct ofpact_delete_field *delete_field;
delete_field = ofpact_put_DELETE_FIELD(pp->ofpacts);
return mf_parse_field(&delete_field->field, arg);
}
static void
format_DELETE_FIELD(const struct ofpact_delete_field *odf,
const struct ofpact_format_params *fp)
{
ds_put_format(fp->s, "%sdelete_field:%s", colors.param,
colors.end);
ds_put_format(fp->s, "%s", odf->field->name);
}
static enum ofperr
check_DELETE_FIELD(const struct ofpact_delete_field *odf,
struct ofpact_check_params *cp OVS_UNUSED)
{
if (odf->field->id < MFF_TUN_METADATA0 ||
odf->field->id > MFF_TUN_METADATA63) {
return OFPERR_OFPBAC_BAD_ARGUMENT;
}
return 0;
}
/* Set queue action. */
static enum ofperr
@ -7870,6 +7955,7 @@ action_set_classify(const struct ofpact *a)
case OFPACT_DEBUG_RECIRC:
case OFPACT_DEBUG_SLOW:
case OFPACT_CHECK_PKT_LARGER:
case OFPACT_DELETE_FIELD:
return ACTION_SLOT_INVALID;
default:
@ -8073,6 +8159,7 @@ ovs_instruction_type_from_ofpact_type(enum ofpact_type type,
case OFPACT_DECAP:
case OFPACT_DEC_NSH_TTL:
case OFPACT_CHECK_PKT_LARGER:
case OFPACT_DELETE_FIELD:
default:
return OVSINST_OFPIT11_APPLY_ACTIONS;
}
@ -8984,6 +9071,7 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port)
case OFPACT_DECAP:
case OFPACT_DEC_NSH_TTL:
case OFPACT_CHECK_PKT_LARGER:
case OFPACT_DELETE_FIELD:
default:
return false;
}

View File

@ -1552,6 +1552,22 @@ for <var>i</var> in [1,<var>n_slaves</var>]:
This action was added in Open vSwitch 2.11.90.
</p>
</action>
<action name="DELETE_FIELD">
<h2>The <code>delete_field</code> action</h2>
<syntax><code>delete_field:</code><var>field</var></syntax>
<p>
The <code>delete_field</code> action deletes a field in the syntax
described under ``Field Specifications'' above. Currently, only
the tun_metadta fields are supported.
</p>
<p>
This action was added in Open vSwitch 2.13.90.
</p>
</action>
</group>
<group title="Metadata Actions">

View File

@ -261,6 +261,23 @@ tun_metadata_write(struct flow_tnl *tnl,
value->tun_metadata + mf->n_bytes - loc->len, loc, idx);
}
/* Deletes field 'mf' in 'tnl' (in non-UDPIF format).
* 'mf' must be an MFF_TUN_METADATA* field.
*/
void
tun_metadata_delete(struct flow_tnl *tnl, const struct mf_field *mf)
{
unsigned int idx;
if (tnl->flags & FLOW_TNL_F_UDPIF) {
return;
}
idx = mf->id - MFF_TUN_METADATA0;
ovs_assert(idx < TUN_METADATA_NUM_OPTS);
ULLONG_SET0(tnl->metadata.present.map, idx);
}
static const struct tun_metadata_loc *
metadata_loc_from_match(const struct tun_table *map, struct match *match,
const char *name, unsigned int idx,

View File

@ -47,6 +47,7 @@ void tun_metadata_read(const struct flow_tnl *,
const struct mf_field *, union mf_value *);
void tun_metadata_write(struct flow_tnl *,
const struct mf_field *, const union mf_value *);
void tun_metadata_delete(struct flow_tnl *, const struct mf_field *);
void tun_metadata_set_match(const struct mf_field *,
const union mf_value *value,
const union mf_value *mask, struct match *,

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019 Nicira, Inc.
/* Copyright (c) 2009-2017, 2019-2020 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -5159,6 +5159,21 @@ compose_dec_mpls_ttl_action(struct xlate_ctx *ctx)
return true;
}
static void
xlate_delete_field(struct xlate_ctx *ctx,
struct flow *flow,
const struct ofpact_delete_field *odf)
{
struct ds s = DS_EMPTY_INITIALIZER;
/* Currently, only tun_metadata is allowed for delete_field action. */
tun_metadata_delete(&flow->tunnel, odf->field);
ds_put_format(&s, "delete %s", odf->field->name);
xlate_report(ctx, OFT_DETAIL, "%s", ds_cstr(&s));
ds_destroy(&s);
}
/* Emits an action that outputs to 'port', within 'ctx'.
*
* 'controller_len' affects only packets sent to an OpenFlow controller. It
@ -5684,6 +5699,7 @@ reversible_actions(const struct ofpact *ofpacts, size_t ofpacts_len)
case OFPACT_WRITE_ACTIONS:
case OFPACT_WRITE_METADATA:
case OFPACT_CHECK_PKT_LARGER:
case OFPACT_DELETE_FIELD:
break;
case OFPACT_CT:
@ -5993,6 +6009,7 @@ freeze_unroll_actions(const struct ofpact *a, const struct ofpact *end,
case OFPACT_CT_CLEAR:
case OFPACT_NAT:
case OFPACT_CHECK_PKT_LARGER:
case OFPACT_DELETE_FIELD:
/* These may not generate PACKET INs. */
break;
@ -6653,6 +6670,7 @@ recirc_for_mpls(const struct ofpact *a, struct xlate_ctx *ctx)
case OFPACT_WRITE_METADATA:
case OFPACT_GOTO_TABLE:
case OFPACT_CHECK_PKT_LARGER:
case OFPACT_DELETE_FIELD:
default:
break;
}
@ -7030,6 +7048,10 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
xlate_fin_timeout(ctx, ofpact_get_FIN_TIMEOUT(a));
break;
case OFPACT_DELETE_FIELD:
xlate_delete_field(ctx, flow, ofpact_get_DELETE_FIELD(a));
break;
case OFPACT_CLEAR_ACTIONS:
xlate_report_action_set(ctx, "was");
ofpbuf_clear(&ctx->action_set);

View File

@ -316,6 +316,9 @@ ffff 0018 00002320 0031 05dc 000000010004000000000000
# actions=check_pkt_larger(1000)->NXM_NX_XXREG1[4]
ffff 0018 00002320 0031 03e8 00040001e010000000000000
# actions=delete_field:tun_metadata10
ffff 0018 00002320 0032 00 01 64 7c 00 00 00 00 000000000000
])
sed '/^[[#&]]/d' < test-data > input.txt
sed -n 's/^# //p; /^$/p' < test-data > expout

View File

@ -890,6 +890,43 @@ Datapath actions: set(tunnel(dst=1.1.1.1,ttl=64,tp_dst=6081,geneve({class=0xffff
OVS_VSWITCHD_STOP
AT_CLEANUP
AT_SETUP([tunnel - Delete Geneve option])
OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=geneve \
options:remote_ip=1.1.1.1 ofport_request=1 \
-- add-port br0 p2 -- set Interface p2 type=dummy \
ofport_request=2 ofport_request=2])
OVS_VSWITCHD_DISABLE_TUNNEL_PUSH_POP
AT_CHECK([ovs-ofctl add-tlv-map br0 "{class=0xffff,type=0,len=4}->tun_metadata0,{class=0xffff,type=1,len=4}->tun_metadata1,{class=0xffff,type=2,len=4}->tun_metadata3"])
AT_DATA([flows.txt], [dnl
table=0,tun_metadata0=0x11112222,actions=set_field:0x55556666->tun_metadata1,resubmit(,1)
table=0,tun_metadata0=0x33334444,actions=delete_field:tun_metadata0,set_field:0x77778888->tun_metadata1,resubmit(,1)
table=0,tun_metadata0=0x88889999,actions=delete_field:tun_metadata3,resubmit(,1)
table=1,actions=IN_PORT
])
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'recirc_id(0),tunnel(tun_id=0x0,src=1.1.1.1,dst=1.1.1.2,ttl=64,geneve({class=0xffff,type=0,len=4,0x11112222}),flags(df|key)),in_port(6081),skb_mark(0),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(frag=no)'], [0], [stdout])
AT_CHECK([tail -2 stdout], [0],
[Megaflow: recirc_id=0,eth,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=1.1.1.2,tun_tos=0,tun_flags=+df-csum+key,tun_metadata0=0x11112222,tun_metadata1=NP,in_port=1,nw_ecn=0,nw_frag=no
Datapath actions: set(tunnel(dst=1.1.1.1,ttl=64,tp_dst=6081,geneve({class=0xffff,type=0,len=4,0x11112222}{class=0xffff,type=0x1,len=4,0x55556666}),flags(df))),6081
])
AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'recirc_id(0),tunnel(tun_id=0x0,src=1.1.1.1,dst=1.1.1.2,ttl=64,geneve({class=0xffff,type=0,len=4,0x33334444}),flags(df|key)),in_port(6081),skb_mark(0),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(frag=no)'], [0], [stdout])
AT_CHECK([tail -2 stdout], [0],
[Megaflow: recirc_id=0,eth,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=1.1.1.2,tun_tos=0,tun_flags=+df-csum+key,tun_metadata0=0x33334444,tun_metadata1=NP,in_port=1,nw_ecn=0,nw_frag=no
Datapath actions: set(tunnel(dst=1.1.1.1,ttl=64,tp_dst=6081,geneve({class=0xffff,type=0x1,len=4,0x77778888}),flags(df))),6081
])
AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'recirc_id(0),tunnel(tun_id=0x0,src=1.1.1.1,dst=1.1.1.2,ttl=64,geneve({class=0xffff,type=0,len=4,0x88889999}),flags(df|key)),in_port(6081),skb_mark(0),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(frag=no)'], [0], [stdout])
AT_CHECK([tail -2 stdout], [0],
[Megaflow: recirc_id=0,eth,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=1.1.1.2,tun_tos=0,tun_flags=+df-csum+key,tun_metadata0=0x88889999,in_port=1,nw_ecn=0,nw_frag=no
Datapath actions: set(tunnel(dst=1.1.1.1,ttl=64,tp_dst=6081,geneve({class=0xffff,type=0,len=4,0x88889999}),flags(df))),6081
])
OVS_VSWITCHD_STOP
AT_CLEANUP
AT_SETUP([tunnel - concomitant IPv6 and IPv4 tunnels])
OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=vxlan \
options:remote_ip=1.1.1.1 ofport_request=1 \