Define NXAST_SAMPLE_IPFIX OpenFlow vendor action and the corresponding OFPACT_SAMPLE_IPFIX OVS action.
Signed-off-by: Romain Lenglet <rleng...@vmware.com> --- NEWS | 1 + include/openflow/nicira-ext.h | 22 +++++++++++++++++++++ lib/ofp-actions.c | 45 +++++++++++++++++++++++++++++++++++++++++++ lib/ofp-actions.h | 10 ++++++++++ lib/ofp-parse.c | 21 ++++++++++++++++++++ lib/ofp-util.def | 1 + ofproto/ofproto-dpif.c | 4 ++++ tests/ofp-actions.at | 6 ++++++ tests/ovs-ofctl.at | 10 ++++++++++ utilities/ovs-ofctl.8.in | 21 ++++++++++++++++++++ 10 files changed, 141 insertions(+) diff --git a/NEWS b/NEWS index 3f06a7a..6cb81e6 100644 --- a/NEWS +++ b/NEWS @@ -17,6 +17,7 @@ post-v1.9.0 syntax. OpenFlow 1.1 adds a port named ANY, which introduces a conflict. ANY was rarely used in flow syntax, so we chose to retire that meaning of ANY in favor of the OpenFlow 1.1 meaning. + - New "sample_ipfix" action. v1.9.0 - xx xxx xxxx diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h index 91c96b3..84d536f 100644 --- a/include/openflow/nicira-ext.h +++ b/include/openflow/nicira-ext.h @@ -304,6 +304,7 @@ enum nx_action_subtype { NXAST_CONTROLLER, /* struct nx_action_controller */ NXAST_DEC_TTL_CNT_IDS, /* struct nx_action_cnt_ids */ NXAST_WRITE_METADATA, /* struct nx_action_write_metadata */ + NXAST_SAMPLE_IPFIX, /* struct nx_action_sample_ipfix */ }; /* Header for Nicira-defined actions. */ @@ -2212,4 +2213,25 @@ struct nx_action_write_metadata { }; OFP_ASSERT(sizeof(struct nx_action_write_metadata) == 32); +/* Action structure for NXAST_SAMPLE_IPFIX. + * + * Samples matching packets with the given probability and sends them + * using the IPFIX protocol. The probability is expressed as a number + * of packets to be sampled out of USHRT_MAX packets. Every sampled + * packet is associated with the given observation point ID. + * + * The IPFIX packets contain the sampled packets' headers when + * executing this rule. If a sampled packet's headers are modified by + * previous actions in the flow, those modified headers are sent in + * the IPFIX packet. */ +struct nx_action_sample_ipfix { + ovs_be16 type; /* OFPAT_VENDOR. */ + ovs_be16 len; /* Length is 16. */ + ovs_be32 vendor; /* NX_VENDOR_ID. */ + ovs_be16 subtype; /* NXAST_SAMPLE_IPFIX. */ + ovs_be16 probability; /* Fraction of packets to sample. */ + ovs_be32 obs_point_id; /* ID of sampling observation point. */ +}; +OFP_ASSERT(sizeof(struct nx_action_sample_ipfix) == 16); + #endif /* openflow/nicira-ext.h */ diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c index 1bc8a9c..6408611 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -217,6 +217,17 @@ dec_ttl_cnt_ids_from_openflow(const struct nx_action_cnt_ids *nac_ids, return 0; } +static void +sample_ipfix_from_openflow(const struct nx_action_sample_ipfix *nasi, + struct ofpbuf *out) +{ + struct ofpact_sample_ipfix *sample_ipfix; + + sample_ipfix = ofpact_put_SAMPLE_IPFIX(out); + sample_ipfix->probability = ntohs(nasi->probability); + sample_ipfix->obs_point_id = ntohl(nasi->obs_point_id); +} + static enum ofperr decode_nxast_action(const union ofp_action *a, enum ofputil_action_code *code) { @@ -401,6 +412,11 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code, case OFPUTIL_NXAST_CONTROLLER: controller_from_openflow((const struct nx_action_controller *) a, out); break; + + case OFPUTIL_NXAST_SAMPLE_IPFIX: + sample_ipfix_from_openflow((const struct nx_action_sample_ipfix *) a, + out); + break; } return error; @@ -1118,6 +1134,9 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports) case OFPACT_EXIT: return 0; + case OFPACT_SAMPLE_IPFIX: + return 0; + case OFPACT_CLEAR_ACTIONS: case OFPACT_WRITE_METADATA: case OFPACT_GOTO_TABLE: @@ -1312,6 +1331,17 @@ ofpact_fin_timeout_to_nxast(const struct ofpact_fin_timeout *fin_timeout, } static void +ofpact_sample_ipfix_to_nxast(const struct ofpact_sample_ipfix *os, + struct ofpbuf *out) +{ + struct nx_action_sample_ipfix *nasi; + + nasi = ofputil_put_NXAST_SAMPLE_IPFIX(out); + nasi->probability = htons(os->probability); + nasi->obs_point_id = htonl(os->obs_point_id); +} + +static void ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out) { switch (a->type) { @@ -1384,6 +1414,10 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out) ofputil_put_NXAST_EXIT(out); break; + case OFPACT_SAMPLE_IPFIX: + ofpact_sample_ipfix_to_nxast(ofpact_get_SAMPLE_IPFIX(a), out); + break; + case OFPACT_OUTPUT: case OFPACT_ENQUEUE: case OFPACT_SET_VLAN_VID: @@ -1511,6 +1545,7 @@ ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out) case OFPACT_AUTOPATH: case OFPACT_NOTE: case OFPACT_EXIT: + case OFPACT_SAMPLE_IPFIX: ofpact_to_nxast(a, out); break; } @@ -1653,6 +1688,7 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out) case OFPACT_AUTOPATH: case OFPACT_NOTE: case OFPACT_EXIT: + case OFPACT_SAMPLE_IPFIX: ofpact_to_nxast(a, out); break; } @@ -1776,6 +1812,7 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, uint16_t port) case OFPACT_AUTOPATH: case OFPACT_NOTE: case OFPACT_EXIT: + case OFPACT_SAMPLE_IPFIX: case OFPACT_CLEAR_ACTIONS: case OFPACT_GOTO_TABLE: default: @@ -1868,6 +1905,7 @@ ofpact_format(const struct ofpact *a, struct ds *s) const struct ofpact_controller *controller; const struct ofpact_metadata *metadata; const struct ofpact_tunnel *tunnel; + const struct ofpact_sample_ipfix *sample_ipfix; uint16_t port; switch (a->type) { @@ -2051,6 +2089,13 @@ ofpact_format(const struct ofpact *a, struct ds *s) ds_put_cstr(s, "exit"); break; + case OFPACT_SAMPLE_IPFIX: + sample_ipfix = ofpact_get_SAMPLE_IPFIX(a); + ds_put_format( + s, "sample_ipfix(probability=%"PRIu16",obs_point_id=%"PRIu32")", + sample_ipfix->probability, sample_ipfix->obs_point_id); + break; + case OFPACT_CLEAR_ACTIONS: ds_put_format(s, "%s", ofpact_instruction_name_from_type( diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h index 3989040..11a6770 100644 --- a/lib/ofp-actions.h +++ b/lib/ofp-actions.h @@ -89,6 +89,7 @@ /* Other. */ \ DEFINE_OFPACT(NOTE, ofpact_note, data) \ DEFINE_OFPACT(EXIT, ofpact_null, ofpact) \ + DEFINE_OFPACT(SAMPLE_IPFIX, ofpact_sample_ipfix, ofpact) \ \ /* Instructions */ \ /* XXX Write-Actions */ \ @@ -421,6 +422,15 @@ struct ofpact_note { uint8_t data[]; }; +/* OFPACT_SAMPLE_IPFIX. + * + * Used for NXAST_SAMPLE_IPFIX. */ +struct ofpact_sample_ipfix { + struct ofpact ofpact; + uint16_t probability; + uint32_t obs_point_id; +}; + /* OFPACT_DEC_TTL. * * Used for OFPAT11_DEC_NW_TTL, NXAST_DEC_TTL and NXAST_DEC_TTL_CNT_IDS. */ diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index 1d0ab85..0aeb612 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -379,6 +379,23 @@ parse_metadata(struct ofpbuf *b, char *arg) } static void +parse_sample_ipfix(struct ofpbuf *b, char *arg) +{ + struct ofpact_sample_ipfix *osi = ofpact_put_SAMPLE_IPFIX(b); + char *key, *value; + + while (ofputil_parse_key_value(&arg, &key, &value)) { + if (!strcmp(key, "probability")) { + osi->probability = str_to_u16(value, "probability"); + } else if (!strcmp(key, "obs_point_id")) { + osi->obs_point_id = str_to_u32(value); + } else { + ovs_fatal(0, "invalid key '%s' in 'sample_ipfix' argument", key); + } + } +} + +static void parse_named_action(enum ofputil_action_code code, const struct flow *flow, char *arg, struct ofpbuf *ofpacts) { @@ -562,6 +579,10 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow, case OFPUTIL_NXAST_CONTROLLER: parse_controller(ofpacts, arg); break; + + case OFPUTIL_NXAST_SAMPLE_IPFIX: + parse_sample_ipfix(ofpacts, arg); + break; } } diff --git a/lib/ofp-util.def b/lib/ofp-util.def index 6d08d8a..be91732 100644 --- a/lib/ofp-util.def +++ b/lib/ofp-util.def @@ -62,6 +62,7 @@ NXAST_ACTION(NXAST_CONTROLLER, nx_action_controller, 0, "controller") NXAST_ACTION(NXAST_DEC_TTL_CNT_IDS, nx_action_cnt_ids, 1, NULL) NXAST_ACTION(NXAST_WRITE_METADATA, nx_action_write_metadata, 0, "write_metadata") +NXAST_ACTION(NXAST_SAMPLE_IPFIX, nx_action_sample_ipfix, 0, "sample_ipfix") #undef OFPAT10_ACTION #undef OFPAT11_ACTION diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index bc54122..57470e0 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -6073,6 +6073,10 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, xlate_table_action(ctx, ctx->flow.in_port, ogt->table_id, true); break; } + + case OFPACT_SAMPLE_IPFIX: + /* TODO: Actually implement the translation here. */ + break; } } diff --git a/tests/ofp-actions.at b/tests/ofp-actions.at index aa51e08..bb35eb9 100644 --- a/tests/ofp-actions.at +++ b/tests/ofp-actions.at @@ -118,6 +118,9 @@ ffff 0010 00002320 0014 04d2 162e 02 00 # actions=dec_ttl(32768,12345,90,765,1024) ffff 0020 00002320 0015 000500000000 80003039005A02fd 0400000000000000 +# actions=sample_ipfix(probability=12345,obs_point_id=23456) +ffff 0010 00002320 0017 3039 00005BA0 + ]) sed '/^[[#&]]/d' < test-data > input.txt sed -n 's/^# //p; /^$/p' < test-data > expout @@ -297,6 +300,9 @@ ffff 0010 00002320 0014 04d2 162e 02 00 # actions=dec_ttl(32768,12345,90,765,1024) ffff 0020 00002320 0015 000500000000 80003039005A02fd 0400000000000000 +# actions=sample_ipfix(probability=12345,obs_point_id=23456) +ffff 0010 00002320 0017 3039 00005BA0 + ]) sed '/^[[#&]]/d' < test-data > input.txt sed -n 's/^# //p; /^$/p' < test-data > expout diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at index ca68226..9d30933 100644 --- a/tests/ovs-ofctl.at +++ b/tests/ovs-ofctl.at @@ -12,6 +12,7 @@ cookie=0x123456789abcdef hard_timeout=10 priority=60000 actions=controller actions=note:41.42.43,note:00.01.02.03.04.05.06.07,note actions=set_field:fe80:0123:4567:890a:a6ba:dbff:fefe:59fa->ipv6_src in_port=0 actions=resubmit:0 +actions=sample_ipfix(probability=12345,obs_point_id=23456) ]]) AT_CHECK([ovs-ofctl parse-flows flows.txt @@ -28,6 +29,7 @@ OFPT_FLOW_MOD: ADD priority=60000 cookie:0x123456789abcdef hard:10 actions=CONTR OFPT_FLOW_MOD: ADD actions=note:41.42.43.00.00.00,note:00.01.02.03.04.05.06.07.00.00.00.00.00.00,note:00.00.00.00.00.00 OFPT_FLOW_MOD: ADD actions=load:0xa6badbfffefe59fa->NXM_NX_IPV6_SRC[0..63],load:0xfe8001234567890a->NXM_NX_IPV6_SRC[64..127] OFPT_FLOW_MOD: ADD in_port=0 actions=resubmit:0 +OFPT_FLOW_MOD: ADD actions=sample_ipfix(probability=12345,obs_point_id=23456) ]]) AT_CLEANUP @@ -43,6 +45,7 @@ cookie=0x123456789abcdef hard_timeout=10 priority=60000 actions=controller actions=note:41.42.43,note:00.01.02.03.04.05.06.07,note actions=set_field:fe80:0123:4567:890a:a6ba:dbff:fefe:59fa->ipv6_src in_port=0 actions=resubmit:0 +actions=sample_ipfix(probability=12345,obs_point_id=23456) ]]) AT_CHECK([ovs-ofctl --protocols OpenFlow12 parse-flows flows.txt @@ -59,6 +62,7 @@ OFPT_FLOW_MOD (OF1.2): ADD table:255 priority=60000 cookie:0x123456789abcdef har OFPT_FLOW_MOD (OF1.2): ADD table:255 actions=note:41.42.43.00.00.00,note:00.01.02.03.04.05.06.07.00.00.00.00.00.00,note:00.00.00.00.00.00 OFPT_FLOW_MOD (OF1.2): ADD table:255 actions=set_field:fe80:123:4567:890a:a6ba:dbff:fefe:59fa->ipv6_src OFPT_FLOW_MOD (OF1.2): ADD table:255 in_port=0 actions=resubmit:0 +OFPT_FLOW_MOD (OF1.2): ADD table:255 actions=sample_ipfix(probability=12345,obs_point_id=23456) ]]) AT_CLEANUP @@ -116,6 +120,7 @@ send_flow_rem,actions=output:1,output:NXM_NX_REG0[],output:2,output:NXM_NX_REG1[ check_overlap,actions=output:1,exit,output:2 actions=fin_timeout(idle_timeout=5,hard_timeout=15) actions=controller(max_len=123,reason=invalid_ttl,id=555) +actions=sample_ipfix(probability=12345,obs_point_id=23456) ]]) AT_CHECK([ovs-ofctl parse-flows flows.txt @@ -150,6 +155,7 @@ NXT_FLOW_MOD: ADD table:255 send_flow_rem actions=output:1,output:NXM_NX_REG0[], NXT_FLOW_MOD: ADD table:255 check_overlap actions=output:1,exit,output:2 NXT_FLOW_MOD: ADD table:255 actions=fin_timeout(idle_timeout=5,hard_timeout=15) NXT_FLOW_MOD: ADD table:255 actions=controller(reason=invalid_ttl,max_len=123,id=555) +NXT_FLOW_MOD: ADD table:255 actions=sample_ipfix(probability=12345,obs_point_id=23456) ]]) AT_CLEANUP @@ -183,6 +189,7 @@ dl_dst=01:00:00:00:00:00/01:00:00:00:00:00,actions=drop dl_dst=00:00:00:00:00:00/01:00:00:00:00:00,actions=drop dl_dst=aa:bb:cc:dd:ee:ff/fe:ff:ff:ff:ff:ff,actions=drop dl_dst=aa:bb:cc:dd:ee:ff/00:00:00:00:00:00,actions=drop +actions=sample_ipfix(probability=12345,obs_point_id=23456) ]) AT_CHECK([ovs-ofctl -F nxm parse-flows flows.txt], [0], [stdout]) AT_CHECK([[sed 's/ (xid=0x[0-9a-fA-F]*)//' stdout]], [0], [dnl @@ -215,6 +222,7 @@ NXT_FLOW_MOD: ADD dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=drop NXT_FLOW_MOD: ADD dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 actions=drop NXT_FLOW_MOD: ADD dl_dst=aa:bb:cc:dd:ee:ff/fe:ff:ff:ff:ff:ff actions=drop NXT_FLOW_MOD: ADD actions=drop +NXT_FLOW_MOD: ADD actions=sample_ipfix(probability=12345,obs_point_id=23456) ]) AT_CLEANUP @@ -245,6 +253,7 @@ reg0=123,actions=move:NXM_NX_REG0[0..5]->NXM_NX_REG1[26..31],load:55->NXM_NX_REG actions=move:OXM_OF_ETH_DST[]->OXM_OF_ETH_SRC[] actions=autopath(5,NXM_NX_REG0[]) vlan_tci=0x1123/0x1fff,actions=drop +actions=sample_ipfix(probability=12345,obs_point_id=23456) ]]) AT_CHECK([ovs-ofctl -F nxm -mmm parse-flows flows.txt], [0], [stdout], [stderr]) AT_CHECK([[sed 's/ (xid=0x[0-9a-fA-F]*)//' stdout]], [0], @@ -274,6 +283,7 @@ NXT_FLOW_MOD: ADD NXM_NX_REG0(0000007b) actions=move:NXM_NX_REG0[0..5]->NXM_NX_R NXT_FLOW_MOD: ADD <any> actions=move:NXM_OF_ETH_DST[]->NXM_OF_ETH_SRC[] NXT_FLOW_MOD: ADD <any> actions=autopath(5,NXM_NX_REG0[]) NXT_FLOW_MOD: ADD NXM_OF_VLAN_TCI_W(1123/1fff) actions=drop +NXT_FLOW_MOD: ADD <any> actions=sample_ipfix(probability=12345,obs_point_id=23456) ]]) AT_CHECK([[sed 's/^[^|]*|[^|]*|//' stderr]], [0], [dnl autopath|WARN|The autopath action is deprecated and may be removed in February 2013. Please email dev@openvswitch.org with concerns. diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in index c48645a..7322b74 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -1198,6 +1198,26 @@ flow's creation, not since the receipt of the FIN or RST.) .RE .IP This action was added in Open vSwitch 1.5.90. +. +.IP "\fBsample_ipfix(\fIargument\fR[\fB,\fIargument\fR]...\fB)\fR" +Samples packets and sends one IPFIX data record for every sampled +packet. +.IP +\fIargument\fR takes the following forms: +.RS +.IP "\fBprobability=\fIpackets\fR" +The number of sampled packets out of 65535. Defaults to 0. If 0, +this action does nothing. +.IP "\fBobs_point_id=\fIid\fR" +The unsigned 32-bit integer identifier of the IPFIX Observation Point +ID associated with every sampled packet. Defaults to 0. +.RE +.IP +Refer to \fBovs\-vswitchd.conf.db\fR(8) for more details on +configuring IPFIX. +.IP +This action was added in Open vSwitch 1.9.1. +. .IP "\fBexit\fR" This action causes Open vSwitch to immediately halt execution of further actions. Those actions which have already been executed are unaffected. Any @@ -1512,3 +1532,4 @@ Prints the flow entries in the switch. .BR ovs\-appctl (8), .BR ovs\-controller (8), .BR ovs\-vswitchd (8) +.BR ovs\-vswitchd.conf.db (8) -- 1.8.1 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev