diff mbox series

[ovs-dev,RFC,1/3] actions: add sample action

Message ID 20220425111724.2981776-2-amorenoz@redhat.com
State RFC
Headers show
Series Add ovn drop debugging | expand

Commit Message

Adrian Moreno April 25, 2022, 11:17 a.m. UTC
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(+)
diff mbox series

Patch

diff --git a/include/ovn/actions.h b/include/ovn/actions.h
index f55d77d47..9e078b403 100644
--- a/include/ovn/actions.h
+++ b/include/ovn/actions.h
@@ -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);
diff --git a/lib/actions.c b/lib/actions.c
index 7fe80f458..53869ce9f 100644
--- a/lib/actions.c
+++ b/lib/actions.c
@@ -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");
     }
diff --git a/tests/ovn.at b/tests/ovn.at
index f9551b843..d1b062fb3 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -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 `;'.
diff --git a/tests/test-ovn.c b/tests/test-ovn.c
index d79c6a5bc..f9a70c8a3 100644
--- a/tests/test-ovn.c
+++ b/tests/test-ovn.c
@@ -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);
diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c
index 4b652828d..390ddc763 100644
--- a/utilities/ovn-trace.c
+++ b/utilities/ovn-trace.c
@@ -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);