From patchwork Mon Nov 21 16:12:15 2022
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: =?utf-8?q?Adri=C3=A1n_Moreno?=
X-Patchwork-Id: 1707467
X-Patchwork-Delegate: dceara@redhat.com
Return-Path:
X-Original-To: incoming@patchwork.ozlabs.org
Delivered-To: patchwork-incoming@legolas.ozlabs.org
Authentication-Results: legolas.ozlabs.org;
spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org
(client-ip=2605:bc80:3010::138; helo=smtp1.osuosl.org;
envelope-from=ovs-dev-bounces@openvswitch.org; receiver=)
Authentication-Results: legolas.ozlabs.org;
dkim=fail reason="signature verification failed" (1024-bit key;
unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256
header.s=mimecast20190719 header.b=F4qnSo45;
dkim-atps=neutral
Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384)
(No client certificate requested)
by legolas.ozlabs.org (Postfix) with ESMTPS id 4NGC8s433zz23nX
for ; Tue, 22 Nov 2022 03:12:45 +1100 (AEDT)
Received: from localhost (localhost [127.0.0.1])
by smtp1.osuosl.org (Postfix) with ESMTP id F246A81E40;
Mon, 21 Nov 2022 16:12:42 +0000 (UTC)
DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org F246A81E40
Authentication-Results: smtp1.osuosl.org;
dkim=fail reason="signature verification failed" (1024-bit key)
header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256
header.s=mimecast20190719 header.b=F4qnSo45
X-Virus-Scanned: amavisd-new at osuosl.org
Received: from smtp1.osuosl.org ([127.0.0.1])
by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)
with ESMTP id V869iD8sEwzF; Mon, 21 Nov 2022 16:12:41 +0000 (UTC)
Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56])
by smtp1.osuosl.org (Postfix) with ESMTPS id A57A981ADE;
Mon, 21 Nov 2022 16:12:40 +0000 (UTC)
DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org A57A981ADE
Received: from lf-lists.osuosl.org (localhost [127.0.0.1])
by lists.linuxfoundation.org (Postfix) with ESMTP id 6DFC6C0070;
Mon, 21 Nov 2022 16:12:40 +0000 (UTC)
X-Original-To: dev@openvswitch.org
Delivered-To: ovs-dev@lists.linuxfoundation.org
Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136])
by lists.linuxfoundation.org (Postfix) with ESMTP id B8CE1C0033
for ; Mon, 21 Nov 2022 16:12:38 +0000 (UTC)
Received: from localhost (localhost [127.0.0.1])
by smtp3.osuosl.org (Postfix) with ESMTP id A14E460F41
for ; Mon, 21 Nov 2022 16:12:38 +0000 (UTC)
DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org A14E460F41
Authentication-Results: smtp3.osuosl.org;
dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com
header.a=rsa-sha256 header.s=mimecast20190719 header.b=F4qnSo45
X-Virus-Scanned: amavisd-new at osuosl.org
Received: from smtp3.osuosl.org ([127.0.0.1])
by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)
with ESMTP id Ct2NcIvDayaU for ;
Mon, 21 Nov 2022 16:12:37 +0000 (UTC)
X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0
DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 614B460F37
Received: from us-smtp-delivery-124.mimecast.com
(us-smtp-delivery-124.mimecast.com [170.10.129.124])
by smtp3.osuosl.org (Postfix) with ESMTPS id 614B460F37
for ; Mon, 21 Nov 2022 16:12:37 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;
s=mimecast20190719; t=1669047156;
h=from:from:reply-to:subject:subject:date:date:message-id:message-id:
to:to:cc:cc:mime-version:mime-version:content-type:content-type:
content-transfer-encoding:content-transfer-encoding:
in-reply-to:in-reply-to:references:references;
bh=+IXoHxcE2/f10MuO5u5vSMmQqWG+TNmmK8ZEDNDQrE4=;
b=F4qnSo458ldB4fgf0ocHJCQX/pW4SQmFrMo7+POmoeJBUe3ne6SZllRiMQxccEbQJ5/3to
r7gqHERJjC5JHXrZzLpd0cVgEDnKwxttN8ltvf4JvJqD33T+i05t/I4K3hf0WSwWSn76qu
4gqthTLvclDGNrUZQDotwWGHZDfMcDk=
Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com
[66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS
(version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id
us-mta-433-sU44oBdFP7a6cpDvKRE7AA-1; Mon, 21 Nov 2022 11:12:33 -0500
X-MC-Unique: sU44oBdFP7a6cpDvKRE7AA-1
Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com
[10.11.54.4])
(using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))
(No client certificate requested)
by mimecast-mx02.redhat.com (Postfix) with ESMTPS id B40AC3C025D2;
Mon, 21 Nov 2022 16:12:32 +0000 (UTC)
Received: from antares.redhat.com (unknown [10.39.193.41])
by smtp.corp.redhat.com (Postfix) with ESMTP id A0B082024CB7;
Mon, 21 Nov 2022 16:12:30 +0000 (UTC)
From: Adrian Moreno
To: dev@openvswitch.org
Date: Mon, 21 Nov 2022 17:12:15 +0100
Message-Id: <20221121161217.304094-2-amorenoz@redhat.com>
In-Reply-To: <20221121161217.304094-1-amorenoz@redhat.com>
References: <20221121161217.304094-1-amorenoz@redhat.com>
MIME-Version: 1.0
X-Scanned-By: MIMEDefang 3.1 on 10.11.54.4
X-Mimecast-Spam-Score: 0
X-Mimecast-Originator: redhat.com
Cc: dceara@redhat.com
Subject: [ovs-dev] [PATCH ovn v6 1/3] actions: add sample action
X-BeenThere: ovs-dev@openvswitch.org
X-Mailman-Version: 2.1.15
Precedence: list
List-Id:
List-Unsubscribe: ,
List-Archive:
List-Post:
List-Help:
List-Subscribe: ,
Errors-To: ovs-dev-bounces@openvswitch.org
Sender: "dev"
sample ovn action encodes into the OFPACT_SAMPLE ovs action.
OVN action allows the following parameters:
- obs_domain_id: 8-bit integer that identifies the sampling application.
This value will be combined with the datapath's tunnel_id to form the
final observation_domain_id that will be used in the OVS action as:
ObservationDomainID = obs_domain_id << 24 | (dp_key & 0xFFFFFF)
- obs_point_id: a 32-bit integer or the $cookie macro that will be
expanded into the first 32 bits of the lflow's UUID.
- probability: a 16-bit integer that specifies the sampling probability.
Specifying 0 has no effect and 65535 means sampling all packets.
- collector_set: the 32-bit id that has to be configured in OVS's
Flow_Sample_Collector_Set table in order to configure IPFIX sampling.
Signed-off-by: Adrian Moreno
Acked-by: Numan Siddique
---
controller/lflow.c | 1 +
include/ovn/actions.h | 16 ++++++
lib/actions.c | 120 ++++++++++++++++++++++++++++++++++++++++++
ovn-sb.xml | 52 ++++++++++++++++++
tests/ovn.at | 28 ++++++++++
tests/test-ovn.c | 3 ++
utilities/ovn-trace.c | 3 ++
7 files changed, 223 insertions(+)
diff --git a/controller/lflow.c b/controller/lflow.c
index cc0f31db0..ad316c17f 100644
--- a/controller/lflow.c
+++ b/controller/lflow.c
@@ -1007,6 +1007,7 @@ add_matches_to_flow_table(const struct sbrec_logical_flow *lflow,
.group_table = l_ctx_out->group_table,
.meter_table = l_ctx_out->meter_table,
.lflow_uuid = lflow->header_.uuid,
+ .dp_key = ldp->datapath->tunnel_key,
.pipeline = ingress ? OVNACT_P_INGRESS : OVNACT_P_EGRESS,
.ingress_ptable = OFTABLE_LOG_INGRESS_PIPELINE,
diff --git a/include/ovn/actions.h b/include/ovn/actions.h
index d7ee84dac..009487cfc 100644
--- a/include/ovn/actions.h
+++ b/include/ovn/actions.h
@@ -121,6 +121,7 @@ struct ovn_extend_table;
OVNACT(COMMIT_ECMP_NH, ovnact_commit_ecmp_nh) \
OVNACT(CHK_ECMP_NH_MAC, ovnact_result) \
OVNACT(CHK_ECMP_NH, ovnact_result) \
+ OVNACT(SAMPLE, ovnact_sample) \
/* enum ovnact_type, with a member OVNACT_ for each action. */
enum OVS_PACKED_ENUM ovnact_type {
@@ -456,6 +457,18 @@ 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. */
+ uint8_t obs_domain_id; /* most significant byte of the
+ observation domain id. The other 24 bits
+ will come from the datapath's tunnel key. */
+ uint32_t collector_set_id; /* colector_set_id. */
+ uint32_t obs_point_id; /* observation point id. */
+ bool use_cookie; /* use cookie as obs_point_id */
+};
+
/* OVNACT_COMMIT_ECMP_NH. */
struct ovnact_commit_ecmp_nh {
struct ovnact ovnact;
@@ -785,6 +798,9 @@ struct ovnact_encode_params {
/* The logical flow uuid that drove this action. */
struct uuid lflow_uuid;
+ /* The datapath key. */
+ uint32_t dp_key;
+
/* OVN maps each logical flow table (ltable), one-to-one, onto a physical
* OpenFlow flow table (ptable). A number of parameters describe this
* mapping and data related to flow tables:
diff --git a/lib/actions.c b/lib/actions.c
index adbb42db4..65205aaba 100644
--- a/lib/actions.c
+++ b/lib/actions.c
@@ -4279,6 +4279,124 @@ encode_CHECK_OUT_PORT_SEC(const struct ovnact_result *dl,
MLF_CHECK_PORT_SEC_BIT, ofpacts);
}
+static void
+format_SAMPLE(const struct ovnact_sample *sample, struct ds *s)
+{
+ ds_put_format(s, "sample(probability=%"PRIu16, sample->probability);
+
+ ds_put_format(s, ",collector_set=%"PRIu32, sample->collector_set_id);
+ ds_put_format(s, ",obs_domain=%"PRIu8, sample->obs_domain_id);
+ if (sample->use_cookie) {
+ ds_put_cstr(s, ",obs_point=$cookie");
+ } else {
+ ds_put_format(s, ",obs_point=%"PRIu32, 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 << 24) | (ep->dp_key & 0xFFFFFF);
+
+ 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) {
+ uint32_t obs_domain = ntohll(ctx->lexer->token.value.integer);
+ if (obs_domain > UINT8_MAX) {
+ lexer_syntax_error(ctx->lexer,
+ "obs_domain must be 8-bit long");
+ return;
+ }
+ sample->obs_domain_id = obs_domain;
+ }
+ 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, "unknown argument");
+ }
+}
+
+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)
+{
+}
+
static void
parse_commit_ecmp_nh(struct action_context *ctx,
struct ovnact_commit_ecmp_nh *ecmp_nh)
@@ -4790,6 +4908,8 @@ parse_action(struct action_context *ctx)
parse_put_fdb(ctx, ovnact_put_PUT_FDB(ctx->ovnacts));
} else if (lexer_match_id(ctx->lexer, "commit_ecmp_nh")) {
parse_commit_ecmp_nh(ctx, ovnact_put_COMMIT_ECMP_NH(ctx->ovnacts));
+ } else if (lexer_match_id(ctx->lexer, "sample")) {
+ parse_sample(ctx);
} else {
lexer_syntax_error(ctx->lexer, "expecting action");
}
diff --git a/ovn-sb.xml b/ovn-sb.xml
index 42e6fa3ee..75ead78fa 100644
--- a/ovn-sb.xml
+++ b/ovn-sb.xml
@@ -2626,6 +2626,58 @@ tcp.flags = RST;
register R is set to 1.
+
+ sample(probability=packets, ...)
+
+
+ This action causes the matched traffic to be sampled using
+ IPFIX protocol. More information about how per-flow IPFIX sampling
+ works in OVS can be found in ovs-actions
(7) and
+ ovs-vswitchd.conf.db
(5).
+
+
+
+ In order to reliably identify each sampled packet when it is
+ received by the IPFIX collector, this action sets the content of
+ the ObservationDomainID
and
+ ObservationPointID
IPFIX fields (see argument
+ description below).
+
+
+
+ The following key-value arguments are supported:
+
+
+
+ probability=
packets
+ -
+ The number of sampled packets out of 65535. It must be greater or
+ equal to 1.
+
+ collector_set=
id
+ -
+ The unsigned 32-bit integer identifier of the sample collector to
+ send sampled packets to. It must match the value configured in
+ the
Flow_Sample_Collector_Set
Table in OVS.
+ Defaults to 0.
+
+ obs_domain=
id
+ -
+ An unsigned 8-bit integer that identifies the sampling
+ application. It will be placed in the 8 most significant bits of
+ the
ObservationDomainID
field of IPFIX samples.
+ The 24 less significant bits will be automatically filled in with
+ the datapath key. Defaults to 0.
+
+ obs_point=
id
+ -
+ An unsigned 32-bit integer to be used as
+
ObsservationPointID
or the string
+ @cookie
to indicate that the first 32 bits of the
+ Logical_Flow
's UUID shall be used instead.
+
+
+
diff --git a/tests/ovn.at b/tests/ovn.at
index 6552681bd..08d91e2e8 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -2136,6 +2136,34 @@ pop(eth.type);
push(abc);
Syntax error at `abc' expecting field name.
+# sample
+sample(probability=100,collector_set=200,obs_domain=0,obs_point=1000);
+ encodes as sample(probability=100,collector_set_id=200,obs_domain_id=11259375,obs_point_id=1000)
+
+# sample with obs_domain = 10. Final obs_domain is 0xA << 24 | 0xABCDEF.
+sample(probability=100,collector_set=200,obs_domain=10,obs_point=$cookie);
+ encodes as sample(probability=100,collector_set_id=200,obs_domain_id=179031535,obs_point_id=2863311530)
+
+sample(probability=10);
+ formats as sample(probability=10,collector_set=0,obs_domain=0,obs_point=0);
+ encodes as sample(probability=10,collector_set_id=0,obs_domain_id=11259375,obs_point_id=0)
+
+sample(probability=10);
+ formats as sample(probability=10,collector_set=0,obs_domain=0,obs_point=0);
+ encodes as sample(probability=10,collector_set_id=0,obs_domain_id=11259375,obs_point_id=0)
+
+sample(probability=0,collector_set=200,obs_domain=0,obs_point=1000);
+ probability must be greater than zero
+
+sample(probability=0,collector_set=200,obs_domain=0,obs_point=foo);
+ Syntax error at `foo' malformed sample observation_point_id.
+
+sample(probability=0,collector_set=200,obs_domain=300,obs_point=foo);
+ Syntax error at `300' obs_domain must be 8-bit long.
+
+sample(probability=10,foo=bar,obs_domain=0,obs_point=1000);
+ Syntax error at `foo' unknown argument.
+
# Miscellaneous negative tests.
;
Syntax error at `;'.
diff --git a/tests/test-ovn.c b/tests/test-ovn.c
index a241f150d..fd580b5df 100644
--- a/tests/test-ovn.c
+++ b/tests/test-ovn.c
@@ -1355,6 +1355,9 @@ test_parse_actions(struct ovs_cmdl_context *ctx OVS_UNUSED)
.common_nat_ct_zone = MFF_LOG_DNAT_ZONE,
.in_port_sec_ptable = OFTABLE_CHK_IN_PORT_SEC,
.out_port_sec_ptable = OFTABLE_CHK_OUT_PORT_SEC,
+ .lflow_uuid.parts =
+ { 0xaaaaaaaa, 0xbbbbbbbb, 0xcccccccc, 0xdddddddd},
+ .dp_key = 0xabcdef,
};
struct ofpbuf ofpacts;
ofpbuf_init(&ofpacts, 0);
diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c
index 6fa5137d9..854385bc1 100644
--- a/utilities/ovn-trace.c
+++ b/utilities/ovn-trace.c
@@ -1466,6 +1466,7 @@ execute_load(const struct ovnact_load *load,
const struct ovnact_encode_params ep = {
.lookup_port = ovntrace_lookup_port,
.aux = dp,
+ .dp_key = dp->tunnel_key,
};
uint64_t stub[512 / 8];
struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(stub);
@@ -3290,6 +3291,8 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len,
break;
case OVNACT_CHK_ECMP_NH:
break;
+ case OVNACT_SAMPLE:
+ break;
}
}
ofpbuf_uninit(&stack);