From patchwork Sun Nov 27 20:14:05 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Abhiram RN X-Patchwork-Id: 1709440 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::136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20210112 header.b=oOy9Sgyp; dkim-atps=neutral Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) (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 4NL0FF3Zcjz23mg for ; Mon, 28 Nov 2022 07:14:40 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 35B7D60C1A; Sun, 27 Nov 2022 20:14:34 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 35B7D60C1A Authentication-Results: smtp3.osuosl.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20210112 header.b=oOy9Sgyp 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 o2ilfZd9eCJI; Sun, 27 Nov 2022 20:14:32 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp3.osuosl.org (Postfix) with ESMTPS id 8996760E50; Sun, 27 Nov 2022 20:14:31 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 8996760E50 Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 46650C0032; Sun, 27 Nov 2022 20:14:31 +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 BF662C002D for ; Sun, 27 Nov 2022 20:14:29 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id A195060E50 for ; Sun, 27 Nov 2022 20:14:29 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org A195060E50 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 l9eYpHIEaCPc for ; Sun, 27 Nov 2022 20:14:27 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.8.0 DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 6FAA960C1A Received: from mail-pf1-x434.google.com (mail-pf1-x434.google.com [IPv6:2607:f8b0:4864:20::434]) by smtp3.osuosl.org (Postfix) with ESMTPS id 6FAA960C1A for ; Sun, 27 Nov 2022 20:14:27 +0000 (UTC) Received: by mail-pf1-x434.google.com with SMTP id q12so4537605pfn.10 for ; Sun, 27 Nov 2022 12:14:27 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=jyTEoGMaMTusgHpvCV13MU2ekCP3hzN9R7ymozIDEWo=; b=oOy9Sgypa+g3/bOg4k2iRtLJ5qktF7TErgbKECyI9HXntv587A+09mjL3l8bn8kGwP 4lsRFiihcuQP66Urys02wkZkXag7XM2Ro2Il4df4ZH8Ipp7R0HSIdc/25oqvGafbT1qF q1jfdX9bw4zQts00hwt1Vhx4qKcUfS22VcVXy4QVrPeb8vkMdQeLSI7yvfb7La4LB338 QOmFCiUzb9blX6mKMqkavGyg2g9WrbCnJTLIgf5Wdn4cWKBViQGUhHZNmCHu8cKFG/uR kZNDasfmOavAXETwBzburp2xQco1nERA/zF5yP9jN+imEqAuJm3af3H21s8RmXwMXaSB n9pQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=jyTEoGMaMTusgHpvCV13MU2ekCP3hzN9R7ymozIDEWo=; b=Qizs5109/cdi092LXf1+Ldcs7oLbbaZlOxzI2cb8NnXq4wk9qJsXTxNNwZDVlKjsNX I/IZySJt+InZ5vo2c6jAmxfGHGjsyXyZosDCnJx0Imo/75iGbxTfPPFeY29vPFl7KgHM cwxQPYlg3MlChYAcBOFFrKtQOfrrY6HiXNcoj5lj9KMtrQMH996sQIWQE4/RML4qe0bO TAN6yO+H18XZbXaywwOXKaDX7N5Rymk9VuYKdww4Amdk4u3J6817VNk1ClnCdHo4amTS KiXVXxa8KwA2/i0nhC3HIeupwyRcHbPNmJarXUt6fD4G9c+r3mz9AXyLJhJBOU3ElUUb +f/g== X-Gm-Message-State: ANoB5pnG6QPHP6RiSCBy8WmQRJd3lCmlBVrpEfLKdMMEu0FANJbl7ons WarIab0reJi3yZP+JSllcWX50iVK/ZZQ6w== X-Google-Smtp-Source: AA0mqf6BGg1iCOXMPj9MgDl4U6uB6Dl/TcVgt8dueODFo7QfRhaMYhpN+8znybgBbvFzuTl73a2yKA== X-Received: by 2002:a63:1c55:0:b0:477:d9fe:c3b0 with SMTP id c21-20020a631c55000000b00477d9fec3b0mr13100608pgm.445.1669580066238; Sun, 27 Nov 2022 12:14:26 -0800 (PST) Received: from arn.com ([49.205.133.150]) by smtp.googlemail.com with ESMTPSA id z14-20020a170903018e00b00186a2dd3ffdsm7255658plg.15.2022.11.27.12.14.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 27 Nov 2022 12:14:25 -0800 (PST) From: Abhiram R N To: dev@openvswitch.org Date: Mon, 28 Nov 2022 01:44:05 +0530 Message-Id: <20221127201407.1579603-1-abhiramrn@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20221125200219.1312140-3-abhiramrn@gmail.com> References: <20221125200219.1312140-3-abhiramrn@gmail.com> MIME-Version: 1.0 Cc: vbarrenk@redhat.com, vedabarrenkala@gmail.com, arn@redhat.com Subject: [ovs-dev] [OVN v17 1/3] OVN Remote Port Mirroring: Add new Schemas in NB and SB 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" In order to support Remote Port Mirroring added the required schemas in NB and SB. Also, nbctl.c and sbctl.c changes are added. Futher added test case to test nbctl commands. Co-authored-by: Veda Barrenkala Signed-off-by: Veda Barrenkala Signed-off-by: Abhiram R N --- v16-->v17: No changes ovn-nb.ovsschema | 31 +++- ovn-nb.xml | 63 ++++++++ ovn-sb.ovsschema | 26 ++- ovn-sb.xml | 50 ++++++ tests/ovn-nbctl.at | 120 ++++++++++++++ utilities/ovn-nbctl.c | 357 ++++++++++++++++++++++++++++++++++++++++++ utilities/ovn-sbctl.c | 4 + 7 files changed, 647 insertions(+), 4 deletions(-) diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema index 174364c8b..01de55222 100644 --- a/ovn-nb.ovsschema +++ b/ovn-nb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Northbound", - "version": "6.3.0", - "cksum": "4042813038 31869", + "version": "6.4.0", + "cksum": "589874483 33352", "tables": { "NB_Global": { "columns": { @@ -132,6 +132,11 @@ "refType": "weak"}, "min": 0, "max": 1}}, + "mirror_rules": {"type": {"key": {"type": "uuid", + "refTable": "Mirror", + "refType": "weak"}, + "min": 0, + "max": "unlimited"}}, "ha_chassis_group": { "type": {"key": {"type": "uuid", "refTable": "HA_Chassis_Group", @@ -301,6 +306,28 @@ "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}}, "isRoot": false}, + "Mirror": { + "columns": { + "name": {"type": "string"}, + "filter": {"type": {"key": {"type": "string", + "enum": ["set", ["from-lport", + "to-lport", + "both"]]}}}, + "sink":{"type": "string"}, + "type": {"type": {"key": {"type": "string", + "enum": ["set", ["gre", + "erspan"]]}}}, + "index": {"type": "integer"}, + "src": {"type": {"key": {"type": "uuid", + "refTable": "Logical_Switch_Port", + "refType": "weak"}, + "min": 0, + "max": "unlimited"}}, + "external_ids": { + "type": {"key": "string", "value": "string", + "min": 0, "max": "unlimited"}}}, + "indexes": [["name"]], + "isRoot": true}, "Meter": { "columns": { "name": {"type": "string"}, diff --git a/ovn-nb.xml b/ovn-nb.xml index 7f207a413..671692b49 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -1582,6 +1582,11 @@ + + Mirror rules that apply to logical switch port which is the source. + Please see the table. + + References a row in the OVN Northbound database's table. @@ -2527,6 +2532,64 @@ + +

+ Each row in this table represents one Mirror that can be used for + port mirroring. These Mirrors are referenced by the + column in + the table. +

+ + +

+ Represents the name of the mirror. +

+
+ + +

+ The value of this field represents selection criteria of the mirror. + Supported values for filter to-lport / from-lport / both + to-lport - to mirror packets coming into logical port + from-lport - to mirror packets going out of logical port + both - to mirror packets coming into and going out of logical port. +

+
+ + +

+ The value of this field represents the destination/sink of the mirror. + The value it takes is an IP address of the sink port. +

+
+ + +

+ The value of this field represents the type of the tunnel used for + sending the mirrored packets. Supported Tunnel types gre and erspan +

+
+ + +

+ The value of this field represents the tunnel ID. Depending on the + tunnel type configured, GRE key value if type GRE and erspan_idx value + if ERSPAN +

+
+ + +

+ The value of this field represents a list of source ports for the + mirror. Please see the table. +

+
+ + + See External IDs at the beginning of this document. + +
+

Each row in this table represents a meter that can be used for QoS or diff --git a/ovn-sb.ovsschema b/ovn-sb.ovsschema index 576ebbdeb..b83134416 100644 --- a/ovn-sb.ovsschema +++ b/ovn-sb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Southbound", - "version": "20.25.0", - "cksum": "53184112 28845", + "version": "20.26.0", + "cksum": "2344151793 30004", "tables": { "SB_Global": { "columns": { @@ -142,6 +142,23 @@ "indexes": [["datapath", "tunnel_key"], ["datapath", "name"]], "isRoot": true}, + "Mirror": { + "columns": { + "name": {"type": "string"}, + "filter": {"type": {"key": {"type": "string", + "enum": ["set", + ["from-lport", + "to-lport","both"]]}}}, + "sink":{"type": "string"}, + "type": {"type": {"key": {"type": "string", + "enum": ["set", + ["gre", "erspan"]]}}}, + "index": {"type": "integer"}, + "external_ids": { + "type": {"key": "string", "value": "string", + "min": 0, "max": "unlimited"}}}, + "indexes": [["name"]], + "isRoot": true}, "Meter": { "columns": { "name": {"type": "string"}, @@ -230,6 +247,11 @@ "refTable": "Encap", "refType": "weak"}, "min": 0, "max": "unlimited"}}, + "mirror_rules": {"type": {"key": {"type": "uuid", + "refTable": "Mirror", + "refType": "weak"}, + "min": 0, + "max": "unlimited"}}, "mac": {"type": {"key": "string", "min": 0, "max": "unlimited"}}, diff --git a/ovn-sb.xml b/ovn-sb.xml index 16f57b374..2dd2e304f 100644 --- a/ovn-sb.xml +++ b/ovn-sb.xml @@ -2869,6 +2869,51 @@ tcp.flags = RST;

+ +

+ Each row in this table represents one Mirror that can be used for + port mirroring. These Mirrors are referenced by the + column in + the table. +

+ + +

+ Represents the name of the mirror. +

+
+ + +

+ The value of this field represents selection criteria of the mirror. +

+
+ + +

+ The value of this field represents the destination/sink of the mirror. +

+
+ + +

+ The value of this field represents the type of the tunnel used for + sending the mirrored packets +

+
+ + +

+ The value of this field represents the key/idx depending on the + tunnel type configured +

+
+ + + See External IDs at the beginning of this document. + +
+

Each row in this table represents a meter that can be used for QoS or @@ -3371,6 +3416,11 @@ tcp.flags = RST; + + Mirror rules that apply to the port binding. + Please see the table. + +

These options apply to logical ports with of diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at index 4d480e357..d79f9d929 100644 --- a/tests/ovn-nbctl.at +++ b/tests/ovn-nbctl.at @@ -435,6 +435,126 @@ AT_CHECK([ovn-nbctl meter-list], [0], [dnl dnl --------------------------------------------------------------------- +OVN_NBCTL_TEST([ovn_nbctl_mirrors], [mirrors], [ +AT_CHECK([ovn-nbctl mirror-add mirror1 gre 0 from-lport 10.10.10.1]) +AT_CHECK([ovn-nbctl mirror-add mirror2 erspan 1 both 10.10.10.2]) +AT_CHECK([ovn-nbctl mirror-add mirror3 gre 2 to-lport 10.10.10.3]) +AT_CHECK([ovn-nbctl ls-add sw0]) +AT_CHECK([ovn-nbctl lsp-add sw0 sw0-port1]) +AT_CHECK([ovn-nbctl lsp-add sw0 sw0-port2]) +AT_CHECK([ovn-nbctl lsp-add sw0 sw0-port3]) + +dnl Add duplicate mirror name +AT_CHECK([ovn-nbctl mirror-add mirror1 gre 0 from-lport 10.10.10.5], [1], [], [stderr]) +AT_CHECK([grep 'already exists' stderr], [0], [ignore]) + +dnl Attach invalid source port to mirror +AT_CHECK([ovn-nbctl lsp-attach-mirror sw0-port4 mirror3], [1], [], [stderr]) +AT_CHECK([grep 'port name not found' stderr], [0], [ignore]) + +dnl Attach source port to invalid mirror +AT_CHECK([ovn-nbctl lsp-attach-mirror sw0-port3 mirror4], [1], [], [stderr]) +AT_CHECK([grep 'mirror name not found' stderr], [0], [ignore]) + +dnl Attach source port to mirror +AT_CHECK([ovn-nbctl lsp-attach-mirror sw0-port1 mirror3]) + +dnl Attach one more source port to mirror +AT_CHECK([ovn-nbctl lsp-attach-mirror sw0-port3 mirror3]) + +dnl Verify if multiple ports are attached to the same mirror properly +AT_CHECK([ovn-nbctl mirror-list], [0], [dnl +mirror1: + Type : gre + Sink : 10.10.10.1 + Filter : from-lport + Index/Key: 0 + Sources : None attached +mirror2: + Type : erspan + Sink : 10.10.10.2 + Filter : both + Index/Key: 1 + Sources : None attached +mirror3: + Type : gre + Sink : 10.10.10.3 + Filter : to-lport + Index/Key: 2 + Sources : sw0-port1 sw0-port3 +]) + +dnl Detach one source port from mirror +AT_CHECK([ovn-nbctl lsp-detach-mirror sw0-port3 mirror3]) + +dnl Verify if detach source port from mirror happens properly +AT_CHECK([ovn-nbctl mirror-list], [0], [dnl +mirror1: + Type : gre + Sink : 10.10.10.1 + Filter : from-lport + Index/Key: 0 + Sources : None attached +mirror2: + Type : erspan + Sink : 10.10.10.2 + Filter : both + Index/Key: 1 + Sources : None attached +mirror3: + Type : gre + Sink : 10.10.10.3 + Filter : to-lport + Index/Key: 2 + Sources : sw0-port1 +]) + +dnl Delete a single mirror which has source attached. +AT_CHECK([ovn-nbctl mirror-del mirror3]) + +dnl Check if the detach happened from source properly +AT_CHECK([ovn-nbctl get Logical_Switch_Port sw0-port1 mirror_rules | cut -b 3], [0], [dnl + +]) + +dnl Check if the mirror deleted properly +AT_CHECK([ovn-nbctl mirror-list], [0], [dnl +mirror1: + Type : gre + Sink : 10.10.10.1 + Filter : from-lport + Index/Key: 0 + Sources : None attached +mirror2: + Type : erspan + Sink : 10.10.10.2 + Filter : both + Index/Key: 1 + Sources : None attached +]) + +dnl Delete another mirror +AT_CHECK([ovn-nbctl mirror-del mirror2]) + +dnl Update the Sink address +AT_CHECK([ovn-nbctl set mirror . sink=192.168.1.13]) + +AT_CHECK([ovn-nbctl mirror-list], [0], [dnl +mirror1: + Type : gre + Sink : 192.168.1.13 + Filter : from-lport + Index/Key: 0 + Sources : None attached +]) + +dnl Delete all mirrors +AT_CHECK([ovn-nbctl mirror-del]) +AT_CHECK([ovn-nbctl mirror-list], [0], [dnl +])]) + +dnl --------------------------------------------------------------------- + OVN_NBCTL_TEST([ovn_nbctl_nats], [NATs], [ AT_CHECK([ovn-nbctl lr-add lr0]) AT_CHECK([ovn-nbctl lr-nat-add lr0 snatt 30.0.0.2 192.168.1.2], [1], [], diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c index 811468dc6..af2e61435 100644 --- a/utilities/ovn-nbctl.c +++ b/utilities/ovn-nbctl.c @@ -271,6 +271,19 @@ QoS commands:\n\ remove QoS rules from SWITCH\n\ qos-list SWITCH print QoS rules for SWITCH\n\ \n\ +Mirror commands:\n\ + mirror-add NAME TYPE INDEX FILTER IP\n\ + add a mirror with given name\n\ + specify TYPE 'gre' or 'erspan'\n\ + specify the tunnel INDEX value\n\ + (indicates key if GRE\n\ + erpsan_idx if ERSPAN)\n\ + specify FILTER for mirroring selection\n\ + 'to-lport' / 'from-lport' / 'both'\n\ + specify Sink / Destination i.e. Remote IP\n\ + mirror-del [NAME] remove mirrors\n\ + mirror-list print mirrors\n\ +\n\ Meter commands:\n\ [--fair]\n\ meter-add NAME ACTION RATE UNIT [BURST]\n\ @@ -311,6 +324,8 @@ Logical switch port commands:\n\ set dhcpv6 options for PORT\n\ lsp-get-dhcpv6-options PORT get the dhcpv6 options for PORT\n\ lsp-get-ls PORT get the logical switch which the port belongs to\n\ + lsp-attach-mirror PORT MIRROR attach source PORT to MIRROR\n\ + lsp-detach-mirror PORT MIRROR detach source PORT from MIRROR\n\ \n\ Forwarding group commands:\n\ [--liveness]\n\ @@ -1685,6 +1700,130 @@ nbctl_pre_lsp_type(struct ctl_context *ctx) ovsdb_idl_add_column(ctx->idl, &nbrec_logical_switch_port_col_type); } +static void +nbctl_pre_lsp_mirror(struct ctl_context *ctx) +{ + ovsdb_idl_add_column(ctx->idl, &nbrec_logical_switch_port_col_name); + ovsdb_idl_add_column(ctx->idl, + &nbrec_logical_switch_port_col_mirror_rules); + ovsdb_idl_add_column(ctx->idl, &nbrec_mirror_col_name); + ovsdb_idl_add_column(ctx->idl, &nbrec_mirror_col_src); +} + +static int +mirror_cmp(const void *mirror1_, const void *mirror2_) +{ + const struct nbrec_mirror *const *mirror_1 = mirror1_; + const struct nbrec_mirror *const *mirror_2 = mirror2_; + + const struct nbrec_mirror *mirror1 = *mirror_1; + const struct nbrec_mirror *mirror2 = *mirror_2; + + return strcmp(mirror1->name,mirror2->name); +} + +static char * OVS_WARN_UNUSED_RESULT +mirror_by_name_or_uuid(struct ctl_context *ctx, const char *id, + bool must_exist, + const struct nbrec_mirror **mirror_p) +{ + const struct nbrec_mirror *mirror = NULL; + *mirror_p = NULL; + + struct uuid mirror_uuid; + bool is_uuid = uuid_from_string(&mirror_uuid, id); + if (is_uuid) { + mirror = nbrec_mirror_get_for_uuid(ctx->idl, &mirror_uuid); + } + + if (!mirror) { + NBREC_MIRROR_FOR_EACH (mirror, ctx->idl) { + if (!strcmp(mirror->name, id)) { + break; + } + } + } + + if (!mirror && must_exist) { + return xasprintf("%s: mirror %s not found", + id, is_uuid ? "UUID" : "name"); + } + + *mirror_p = mirror; + return NULL; +} + +static void +nbctl_lsp_attach_mirror(struct ctl_context *ctx) +{ + const char *port = ctx->argv[1]; + const char *mirror_name = ctx->argv[2]; + const struct nbrec_logical_switch_port *lsp = NULL; + const struct nbrec_mirror *mirror; + + char *error; + + error = lsp_by_name_or_uuid(ctx, port, true, &lsp); + if (error) { + ctx->error = error; + return; + } + + + /*check if a mirror rule actually exists on that name or not*/ + error = mirror_by_name_or_uuid(ctx, mirror_name, true, &mirror); + if (error) { + ctx->error = error; + return; + } + + /* Check if same mirror rule already exists for the lsp */ + for (size_t i = 0; i < lsp->n_mirror_rules; i++) { + if (!mirror_cmp(&lsp->mirror_rules[i], &mirror)) { + bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL; + if (!may_exist) { + ctl_error(ctx, "Same mirror already existed on the lsp %s.", + ctx->argv[1]); + return; + } + return; + } + } + + nbrec_logical_switch_port_update_mirror_rules_addvalue(lsp, mirror); + nbrec_mirror_update_src_addvalue(mirror,lsp); + +} + +static void +nbctl_lsp_detach_mirror(struct ctl_context *ctx) +{ + const char *port = ctx->argv[1]; + const char *mirror_name = ctx->argv[2]; + const struct nbrec_logical_switch_port *lsp = NULL; + const struct nbrec_mirror *mirror; + + char *error; + + error = lsp_by_name_or_uuid(ctx, port, true, &lsp); + if (error) { + ctx->error = error; + return; + } + + + /*check if a mirror rule actually exists on that name or not*/ + error = mirror_by_name_or_uuid(ctx, mirror_name, true, &mirror); + if (error) { + ctx->error = error; + return; + } + + nbrec_logical_switch_port_update_mirror_rules_delvalue(lsp, mirror); + nbrec_mirror_update_src_delvalue(mirror,lsp); + +} + static void nbctl_lsp_set_type(struct ctl_context *ctx) { @@ -7241,6 +7380,211 @@ cmd_ha_ch_grp_set_chassis_prio(struct ctl_context *ctx) nbrec_ha_chassis_set_priority(ha_chassis, priority); } +static char * OVS_WARN_UNUSED_RESULT +parse_filter(const char *arg, const char **selection_p) +{ + /* Validate selection. Only require the first letter. */ + if (arg[0] == 't') { + *selection_p = "to-lport"; + } else if (arg[0] == 'f') { + *selection_p = "from-lport"; + } else if (arg[0] == 'b') { + *selection_p = "both"; + } else { + *selection_p = NULL; + return xasprintf("%s: selection must be \"to-lport\" or " + "\"from-lport\" or \"both\" ", arg); + } + return NULL; +} + +static char * OVS_WARN_UNUSED_RESULT +parse_type(const char *arg, const char **type_p) +{ + /* Validate type. Only require the first letter. */ + if (arg[0] == 'g') { + *type_p = "gre"; + } else if (arg[0] == 'e') { + *type_p = "erspan"; + } else { + *type_p = NULL; + return xasprintf("%s: type must be \"gre\" or " + "\"erspan\"", arg); + } + return NULL; +} + +static void +nbctl_pre_mirror_add(struct ctl_context *ctx) +{ + ovsdb_idl_add_column(ctx->idl, &nbrec_mirror_col_name); + ovsdb_idl_add_column(ctx->idl, &nbrec_mirror_col_filter); + ovsdb_idl_add_column(ctx->idl, &nbrec_mirror_col_index); + ovsdb_idl_add_column(ctx->idl, &nbrec_mirror_col_sink); + ovsdb_idl_add_column(ctx->idl, &nbrec_mirror_col_type); +} + +static void +nbctl_mirror_add(struct ctl_context *ctx) +{ + const char *filter = NULL; + const char *sink_ip = NULL; + const char *type = NULL; + const char *name = NULL; + char *new_sink_ip = NULL; + int64_t index; + char *error = NULL; + const struct nbrec_mirror *mirror_check = NULL; + + /* Mirror Name */ + name = ctx->argv[1]; + NBREC_MIRROR_FOR_EACH (mirror_check, ctx->idl) { + if (!strcmp(mirror_check->name, name)) { + ctl_error(ctx, "Mirror with %s name already exists.", + name); + return; + } + } + + /* Tunnel Type - GRE/ERSPAN */ + error = parse_type(ctx->argv[2], &type); + if (error) { + ctx->error = error; + return; + } + + /* tunnel index / GRE key / ERSPAN idx */ + index = atoi(ctx->argv[3]); + + /* Filter for mirroring */ + error = parse_filter(ctx->argv[4], &filter); + if (error) { + ctx->error = error; + return; + } + + /* Destination / Sink details */ + sink_ip = ctx->argv[5]; + + /* check if it is a valid ip */ + new_sink_ip = normalize_ipv4_addr_str(sink_ip); + if (!new_sink_ip) { + new_sink_ip = normalize_ipv6_addr_str(sink_ip); + } + + if (new_sink_ip) { + free(new_sink_ip); + } else { + ctl_error(ctx, "Invalid sink ip: %s", sink_ip); + return; + } + + /* Create the mirror. */ + struct nbrec_mirror *mirror = nbrec_mirror_insert(ctx->txn); + nbrec_mirror_set_name(mirror, name); + nbrec_mirror_set_index(mirror, index); + nbrec_mirror_set_filter(mirror, filter); + nbrec_mirror_set_type(mirror, type); + nbrec_mirror_set_sink(mirror, sink_ip); + +} + +static void +nbctl_pre_mirror_del(struct ctl_context *ctx) +{ + ovsdb_idl_add_column(ctx->idl, &nbrec_mirror_col_name); + ovsdb_idl_add_column(ctx->idl, &nbrec_mirror_col_src); +} + +static void +nbctl_mirror_del(struct ctl_context *ctx) +{ + const struct nbrec_mirror *mirror, *next; + + /* If a name is not specified, delete all mirrors. */ + if (ctx->argc == 1) { + NBREC_MIRROR_FOR_EACH_SAFE (mirror, next, ctx->idl) { + nbrec_mirror_delete(mirror); + } + return; + } + + /* Remove the matching mirror. */ + NBREC_MIRROR_FOR_EACH (mirror, ctx->idl) { + if (strcmp(ctx->argv[1], mirror->name)) { + continue; + } + nbrec_mirror_delete(mirror); + return; + } +} + +static void +nbctl_pre_mirror_list(struct ctl_context *ctx) +{ + ovsdb_idl_add_column(ctx->idl, &nbrec_logical_switch_port_col_name); + ovsdb_idl_add_column(ctx->idl, &nbrec_mirror_col_name); + ovsdb_idl_add_column(ctx->idl, &nbrec_mirror_col_filter); + ovsdb_idl_add_column(ctx->idl, &nbrec_mirror_col_index); + ovsdb_idl_add_column(ctx->idl, &nbrec_mirror_col_sink); + ovsdb_idl_add_column(ctx->idl, &nbrec_mirror_col_type); + ovsdb_idl_add_column(ctx->idl, &nbrec_mirror_col_src); +} + +static void +nbctl_mirror_list(struct ctl_context *ctx) +{ + + const struct nbrec_mirror **mirrors = NULL; + const struct nbrec_mirror *mirror; + size_t n_capacity = 0; + size_t n_mirrors = 0; + + NBREC_MIRROR_FOR_EACH (mirror, ctx->idl) { + if (n_mirrors == n_capacity) { + mirrors = x2nrealloc(mirrors, &n_capacity, sizeof *mirrors); + } + + mirrors[n_mirrors] = mirror; + n_mirrors++; + } + + if (n_mirrors) { + qsort(mirrors, n_mirrors, sizeof *mirrors, mirror_cmp); + } + + for (size_t i = 0; i < n_mirrors; i++) { + mirror = mirrors[i]; + ds_put_format(&ctx->output, "%s:\n", mirror->name); + /* print all the values */ + ds_put_format(&ctx->output, " Type : %s\n", mirror->type); + ds_put_format(&ctx->output, " Sink : %s\n", mirror->sink); + ds_put_format(&ctx->output, " Filter : %s\n", mirror->filter); + ds_put_format(&ctx->output, " Index/Key: %ld\n", + (long int) mirror->index); + ds_put_cstr(&ctx->output, " Sources :"); + if (mirror->n_src > 0) { + struct svec srcs; + const char *src; + size_t j; + svec_init(&srcs); + for (j = 0; j < mirror->n_src; j++) { + svec_add(&srcs, mirror->src[j]->name); + } + svec_sort(&srcs); + SVEC_FOR_EACH (j, src, &srcs) { + ds_put_format(&ctx->output, " %s", src); + } + svec_destroy(&srcs); + } else { + ds_put_cstr(&ctx->output, " None attached"); + } + ds_put_cstr(&ctx->output, "\n"); + } + + free(mirrors); +} + static const struct ctl_table_class tables[NBREC_N_TABLES] = { [NBREC_TABLE_DHCP_OPTIONS].row_ids = {{&nbrec_logical_switch_port_col_name, NULL, @@ -7334,6 +7678,15 @@ static const struct ctl_command_syntax nbctl_commands[] = { { "qos-list", 1, 1, "SWITCH", nbctl_pre_qos_list, nbctl_qos_list, NULL, "", RO }, + /* mirror commands. */ + { "mirror-add", 5, 5, + "NAME TYPE INDEX FILTER IP", + nbctl_pre_mirror_add, nbctl_mirror_add, NULL, "--may-exist", RW }, + { "mirror-del", 0, 1, "[NAME]", + nbctl_pre_mirror_del, nbctl_mirror_del, NULL, "", RW }, + { "mirror-list", 0, 0, "", nbctl_pre_mirror_list, nbctl_mirror_list, + NULL, "", RO }, + /* meter commands. */ { "meter-add", 4, 5, "NAME ACTION RATE UNIT [BURST]", nbctl_pre_meter_add, nbctl_meter_add, NULL, "--fair,--may-exist", RW }, @@ -7388,6 +7741,10 @@ static const struct ctl_command_syntax nbctl_commands[] = { nbctl_lsp_get_dhcpv6_options, NULL, "", RO }, { "lsp-get-ls", 1, 1, "PORT", nbctl_pre_lsp_get_ls, nbctl_lsp_get_ls, NULL, "", RO }, + { "lsp-attach-mirror", 2, 2, "PORT MIRROR", nbctl_pre_lsp_mirror, + nbctl_lsp_attach_mirror, NULL, "", RW }, + { "lsp-detach-mirror", 2, 2, "PORT MIRROR", nbctl_pre_lsp_mirror, + nbctl_lsp_detach_mirror, NULL, "", RW }, /* forwarding group commands. */ { "fwd-group-add", 4, INT_MAX, "SWITCH GROUP VIP VMAC PORT...", diff --git a/utilities/ovn-sbctl.c b/utilities/ovn-sbctl.c index f60dde1b6..3d73e9e25 100644 --- a/utilities/ovn-sbctl.c +++ b/utilities/ovn-sbctl.c @@ -307,6 +307,7 @@ pre_get_info(struct ctl_context *ctx) ovsdb_idl_add_column(ctx->idl, &sbrec_port_binding_col_chassis); ovsdb_idl_add_column(ctx->idl, &sbrec_port_binding_col_datapath); ovsdb_idl_add_column(ctx->idl, &sbrec_port_binding_col_up); + ovsdb_idl_add_column(ctx->idl, &sbrec_port_binding_col_mirror_rules); ovsdb_idl_add_column(ctx->idl, &sbrec_logical_flow_col_logical_datapath); ovsdb_idl_add_column(ctx->idl, &sbrec_logical_flow_col_logical_dp_group); @@ -1431,6 +1432,9 @@ static const struct ctl_table_class tables[SBREC_N_TABLES] = { [SBREC_TABLE_HA_CHASSIS_GROUP].row_ids[0] = {&sbrec_ha_chassis_group_col_name, NULL, NULL}, + [SBREC_TABLE_MIRROR].row_ids[0] + = {&sbrec_mirror_col_name, NULL, NULL}, + [SBREC_TABLE_METER].row_ids[0] = {&sbrec_meter_col_name, NULL, NULL},