@@ -116,6 +116,7 @@ struct ovn_extend_table;
OVNACT(PUT_FDB, ovnact_put_fdb) \
OVNACT(GET_FDB, ovnact_get_fdb) \
OVNACT(LOOKUP_FDB, ovnact_lookup_fdb) \
+ OVNACT(SAMPLE, ovnact_sample) \
/* enum ovnact_type, with a member OVNACT_<ENUM> for each action. */
enum OVS_PACKED_ENUM ovnact_type {
@@ -451,6 +452,16 @@ struct ovnact_lookup_fdb {
struct expr_field dst; /* 1-bit destination field. */
};
+/* OVNACT_SAMPLE */
+struct ovnact_sample {
+ struct ovnact ovnact;
+ uint16_t probability; /* probability over UINT16_MAX. */
+ uint32_t collector_set_id; /* colector_set_id. */
+ uint32_t obs_domain_id; /* observation domain id. */
+ uint32_t obs_point_id; /* observation point id. */
+ bool use_cookie; /* use cookie as obs_point_id */
+};
+
/* Internal use by the helpers below. */
void ovnact_init(struct ovnact *, enum ovnact_type, size_t len);
void *ovnact_put(struct ofpbuf *, enum ovnact_type, size_t len);
@@ -4216,6 +4216,115 @@ ovnact_lookup_fdb_free(struct ovnact_lookup_fdb *get_fdb OVS_UNUSED)
{
}
+static void
+format_SAMPLE(const struct ovnact_sample *sample, struct ds *s)
+{
+ ds_put_format(s, "sample(probability=%"PRId16, sample->probability);
+
+ ds_put_format(s, ",collector_set=%"PRId32, sample->collector_set_id);
+ ds_put_format(s, ",obs_domain=%"PRId32, sample->obs_domain_id);
+ if (sample->use_cookie) {
+ ds_put_cstr(s, ",obs_point=$cookie");
+ } else {
+ ds_put_format(s, ",obs_point=%"PRId32, sample->obs_point_id);
+ }
+ ds_put_format(s, ");");
+}
+
+static void
+encode_SAMPLE(const struct ovnact_sample *sample,
+ const struct ovnact_encode_params *ep,
+ struct ofpbuf *ofpacts)
+{
+ struct ofpact_sample *os = ofpact_put_SAMPLE(ofpacts);
+ os->probability = sample->probability;
+ os->collector_set_id = sample->collector_set_id;
+ os->obs_domain_id= sample->obs_domain_id;
+ if (sample->use_cookie) {
+ os->obs_point_id = ep->lflow_uuid.parts[0];
+ } else {
+ os->obs_point_id = sample->obs_point_id;
+ }
+ os->sampling_port = OFPP_NONE;
+}
+
+static void
+parse_sample_arg(struct action_context *ctx, struct ovnact_sample *sample)
+{
+ if (lexer_match_id(ctx->lexer, "probability")) {
+ if (!lexer_force_match(ctx->lexer, LEX_T_EQUALS)) {
+ return;
+ }
+ if (ctx->lexer->token.type == LEX_T_INTEGER
+ && ctx->lexer->token.format == LEX_F_DECIMAL) {
+ if (!action_parse_uint16(ctx, &sample->probability,
+ "probability")) {
+ return;
+ }
+ }
+ } else if (lexer_match_id(ctx->lexer, "obs_point")) {
+ if (!lexer_force_match(ctx->lexer, LEX_T_EQUALS)) {
+ return;
+ }
+ if (ctx->lexer->token.type == LEX_T_MACRO &&
+ !strcmp(ctx->lexer->token.s, "cookie")) {
+ sample->use_cookie = true;
+ lexer_get(ctx->lexer);
+ } else if (ctx->lexer->token.type == LEX_T_INTEGER
+ && ctx->lexer->token.format == LEX_F_DECIMAL) {
+ sample->obs_point_id = ntohll(ctx->lexer->token.value.integer);
+ lexer_get(ctx->lexer);
+ } else {
+ lexer_syntax_error(ctx->lexer,
+ "Malformed sample observation_point_id");
+ }
+ } else if (lexer_match_id(ctx->lexer, "obs_domain")) {
+ if (!lexer_force_match(ctx->lexer, LEX_T_EQUALS)) {
+ return;
+ }
+ if (ctx->lexer->token.type == LEX_T_INTEGER
+ && ctx->lexer->token.format == LEX_F_DECIMAL) {
+ sample->obs_domain_id = ntohll(ctx->lexer->token.value.integer);
+ }
+ lexer_get(ctx->lexer);
+ } else if (lexer_match_id(ctx->lexer, "collector_set")) {
+ if (!lexer_force_match(ctx->lexer, LEX_T_EQUALS)) {
+ return;
+ }
+ if (ctx->lexer->token.type == LEX_T_INTEGER
+ && ctx->lexer->token.format == LEX_F_DECIMAL) {
+ sample->collector_set_id = ntohll(ctx->lexer->token.value.integer);
+ }
+ lexer_get(ctx->lexer);
+ } else {
+ lexer_syntax_error(ctx->lexer, "Malformed sample action");
+ }
+}
+static void
+parse_sample(struct action_context *ctx)
+{
+ struct ovnact_sample * sample = ovnact_put_SAMPLE(ctx->ovnacts);
+
+ if (lexer_match(ctx->lexer, LEX_T_LPAREN)) {
+ while (!lexer_match(ctx->lexer, LEX_T_RPAREN)) {
+ parse_sample_arg(ctx, sample);
+ if (ctx->lexer->error) {
+ return;
+ }
+ lexer_match(ctx->lexer, LEX_T_COMMA);
+ }
+ }
+ if (!sample->probability) {
+ lexer_error(ctx->lexer, "probability must be greater than zero");
+ return;
+ }
+}
+
+static void
+ovnact_sample_free(struct ovnact_sample *sample OVS_UNUSED)
+{
+}
+
/* Parses an assignment or exchange or put_dhcp_opts action. */
static void
parse_set_action(struct action_context *ctx)
@@ -4388,6 +4497,8 @@ parse_action(struct action_context *ctx)
ovnact_put_CT_SNAT_TO_VIP(ctx->ovnacts);
} else if (lexer_match_id(ctx->lexer, "put_fdb")) {
parse_put_fdb(ctx, ovnact_put_PUT_FDB(ctx->ovnacts));
+ } else if (lexer_match_id(ctx->lexer, "sample")) {
+ parse_sample(ctx);
} else {
lexer_syntax_error(ctx->lexer, "expecting action");
}
@@ -2006,6 +2006,14 @@ pop(eth.type);
push(abc);
Syntax error at `abc' expecting field name.
+# sample
+sample(probability=100,collector_set=200,obs_domain=10,obs_point=1000);
+ encodes as sample(probability=100,collector_set_id=200,obs_domain_id=10,obs_point_id=1000)
+
+sample(probability=100,collector_set=200,obs_domain=10,obs_point=$cookie);
+ encodes as sample(probability=100,collector_set_id=200,obs_domain_id=10,obs_point_id=2863311530)
+
+
# Miscellaneous negative tests.
;
Syntax error at `;'.
@@ -1351,6 +1351,8 @@ test_parse_actions(struct ovs_cmdl_context *ctx OVS_UNUSED)
.ct_snat_vip_ptable = OFTABLE_CT_SNAT_HAIRPIN,
.fdb_ptable = OFTABLE_GET_FDB,
.fdb_lookup_ptable = OFTABLE_LOOKUP_FDB,
+ .lflow_uuid.parts =
+ { 0xaaaaaaaa, 0xbbbbbbbb, 0xcccccccc, 0xdddddddd},
};
struct ofpbuf ofpacts;
ofpbuf_init(&ofpacts, 0);
@@ -2890,6 +2890,9 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len,
case OVNACT_LOOKUP_FDB:
execute_lookup_fdb(ovnact_get_LOOKUP_FDB(a), dp, uflow, super);
break;
+
+ case OVNACT_SAMPLE:
+ break;
}
}
ofpbuf_uninit(&stack);
sample ovn action encodes into the OFPACT_SAMPLE ovs action. The only extra bit of logic is the ability to specify the macro $cookie as observation_point_id that makes the encoding logic use the lflow's first 32bits as observation_point_id. Signed-off-by: Adrian Moreno <amorenoz@redhat.com> --- include/ovn/actions.h | 11 +++++ lib/actions.c | 111 ++++++++++++++++++++++++++++++++++++++++++ tests/ovn.at | 8 +++ tests/test-ovn.c | 2 + utilities/ovn-trace.c | 3 ++ 5 files changed, 135 insertions(+)