On Fri, Apr 18, 2025 at 8:52 AM Alexandra Rukomoinikova
<arukomoinikova@k2.cloud> wrote:
>
> Changes introduced in the NB/SB db schema:
>
> 1) new field for mirroring rules has been added to the Mirror table,
>    allowing the definition of traffic reflection rules.
>
> 2) new table, Mirror Rule, has been created to filter remote
>    overlay traffic.
>
> 3) new mirroring type, lport, has been introduced to encapsulate
>    mirrored traffic to another OVN port.
>
> 4) ovn-nbctl commands for to create lport mirror and rules.
>
> Signed-off-by: Alexandra Rukomoinikova <arukomoinikova@k2.cloud>
> Signed-off-by: Vladislav Odintsov <vlodintsov@k2.cloud>
> Co-authored-by: Vladislav Odintsov <vlodintsov@k2.cloud>
> Tested-by: Ivan Burnin <iburnin@k2.cloud>
> ---
> v9 -> v10: fixed Numan's nit comment.

Thanks v10.

Acked-by: Numan Siddique <num...@ovn.org>

Numan


> ---
>  ovn-nb.ovsschema      |  25 ++++-
>  ovn-nb.xml            |  45 ++++++++-
>  ovn-sb.ovsschema      |   7 +-
>  ovn-sb.xml            |   2 +-
>  tests/ovn-nbctl.at    |  99 +++++++++++++++++++-
>  utilities/ovn-nbctl.c | 213 +++++++++++++++++++++++++++++++++++++++---
>  6 files changed, 369 insertions(+), 22 deletions(-)
>
> diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema
> index ea71d09bd..f55930a2e 100644
> --- a/ovn-nb.ovsschema
> +++ b/ovn-nb.ovsschema
> @@ -1,7 +1,7 @@
>  {
>      "name": "OVN_Northbound",
> -    "version": "7.11.0",
> -    "cksum": "2520708261 39034",
> +    "version": "7.12.0",
> +    "cksum": "2749576410 39903",
>      "tables": {
>          "NB_Global": {
>              "columns": {
> @@ -364,13 +364,32 @@
>                  "type": {"type": {"key": {"type": "string",
>                                            "enum": ["set", ["gre",
>                                                             "erspan",
> -                                                           "local"]]}}},
> +                                                           "local",
> +                                                           "lport"]]}}},
>                  "index": {"type": "integer"},
> +                "mirror_rules": {
> +                    "type": {
> +                        "key": {
> +                            "type": "uuid",
> +                            "refTable": "Mirror_Rule",
> +                            "refType": "strong"},
> +                        "min": 0,
> +                        "max": "unlimited"}},
>                  "external_ids": {
>                      "type": {"key": "string", "value": "string",
>                               "min": 0, "max": "unlimited"}}},
>              "indexes": [["name"]],
>              "isRoot": true},
> +        "Mirror_Rule": {
> +            "columns": {
> +                "match": {"type": "string"},
> +                "action": {"type": {
> +                    "key": {"type": "string",
> +                            "enum": ["set", ["mirror", "skip"]]}}},
> +                "priority": {"type": {"key": {"type": "integer",
> +                                              "minInteger": 0,
> +                                              "maxInteger": 32767}}}},
> +            "isRoot": false},
>          "Meter": {
>              "columns": {
>                  "name": {"type": "string"},
> diff --git a/ovn-nb.xml b/ovn-nb.xml
> index bf1f1628b..e416a1fba 100644
> --- a/ovn-nb.xml
> +++ b/ovn-nb.xml
> @@ -3325,7 +3325,7 @@ or
>      <column name="type">
>        <p>
>          The value of this field specifies the mirror type - <code>gre</code>,
> -        <code>erspan</code> or <code>local</code>.
> +        <code>erspan</code>, <code>local</code> or <code>lport</code>.
>        </p>
>      </column>
>
> @@ -3339,11 +3339,54 @@ or
>        </p>
>      </column>
>
> +    <column name="mirror_rules">
> +      <p>
> +        The value of this field represents the mirror rule for filtering
> +        mirror traffic.
> +      </p>
> +    </column>
> +
>      <column name="external_ids">
>        See <em>External IDs</em> at the beginning of this document.
>      </column>
>    </table>
>
> +  <table name="Mirror_Rule" title="Mirror rule entry">
> +    <p>
> +      Each row in this table represents a mirror rule that can be used
> +      for filtering of <code>lport</code> mirrored traffic.
> +    </p>
> +
> +    <column name="match">
> +      <p>
> +        The match expression, describing which packets should be executed
> +        against Mirror Rule action. The Logical_Flow expression language is
> +        used.
> +      </p>
> +    </column>
> +
> +    <column name="action">
> +      <p>The action to take when the Mirror Rule matches:</p>
> +      <ul>
> +        <li>
> +          <code>mirror</code>: Mirror the matched packet.
> +        </li>
> +
> +        <li>
> +          <code>skip</code>: Do not mirror matched packet.
> +        </li>
> +      </ul>
> +    </column>
> +
> +    <column name="priority">
> +      <p>
> +        The Mirror Rule priority. Rule with higher priority takes precedence
> +        over those with lower. A rule is uniquely identified by the priority
> +        and match string.
> +      </p>
> +    </column>
> +  </table>
> +
>    <table name="Meter" title="Meter entry">
>      <p>
>        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 d7cfeaa8f..7eda3a5d9 100644
> --- a/ovn-sb.ovsschema
> +++ b/ovn-sb.ovsschema
> @@ -1,7 +1,7 @@
>  {
>      "name": "OVN_Southbound",
> -    "version": "21.0.0",
> -    "cksum": "4028932437 34711",
> +    "version": "21.1.0",
> +    "cksum": "880279393 34779",
>      "tables": {
>          "SB_Global": {
>              "columns": {
> @@ -156,7 +156,8 @@
>                  "type": {"type": {"key": {"type": "string",
>                                            "enum": ["set", ["gre",
>                                                             "erspan",
> -                                                           "local"]]}}},
> +                                                           "local",
> +                                                           "lport"]]}}},
>                  "index": {"type": "integer"},
>                  "external_ids": {
>                      "type": {"key": "string", "value": "string",
> diff --git a/ovn-sb.xml b/ovn-sb.xml
> index 9777cc64a..d1d0085af 100644
> --- a/ovn-sb.xml
> +++ b/ovn-sb.xml
> @@ -3081,7 +3081,7 @@ tcp.flags = RST;
>      <column name="type">
>        <p>
>          The value of this field specifies the mirror type - <code>gre</code>,
> -        <code>erspan</code> or <code>local</code>.
> +        <code>erspan</code>, <code>local</code> or <code>lport</code>.
>        </p>
>      </column>
>
> diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at
> index fc74e5c62..7129ba004 100644
> --- a/tests/ovn-nbctl.at
> +++ b/tests/ovn-nbctl.at
> @@ -457,13 +457,15 @@ check ovn-nbctl ls-add sw0
>  check ovn-nbctl lsp-add sw0 sw0-port1
>  check ovn-nbctl lsp-add sw0 sw0-port2
>  check ovn-nbctl lsp-add sw0 sw0-port3
> +check ovn-nbctl lsp-add sw0 sw0-port4
> +check ovn-nbctl mirror-add mirror-lport lport to-lport sw0-port1
>
>  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([ovn-nbctl lsp-attach-mirror sw0-port5 mirror3], [1], [], [stderr])
>  AT_CHECK([grep 'port name not found' stderr], [0], [ignore])
>
>  dnl Attach source port to invalid mirror
> @@ -479,6 +481,11 @@ dnl Attach one more source port to mirror
>  check ovn-nbctl lsp-attach-mirror sw0-port3 mirror3
>  check_column "$mirror3uuid" nb:Logical_Switch_Port mirror_rules 
> name=sw0-port3
>
> +mirror_lportuuid=$(fetch_column nb:Mirror _uuid name=mirror-lport)
> +dnl Attach source port to lport mirror
> +check ovn-nbctl lsp-attach-mirror sw0-port4 mirror-lport
> +check_column "$mirror_lportuuid" nb:Logical_Switch_Port mirror_rules 
> name=sw0-port4
> +
>  dnl Verify if multiple ports are attached to the same mirror properly
>  AT_CHECK([ovn-nbctl mirror-list], [0], [dnl
>  mirror-local:
> @@ -486,6 +493,11 @@ mirror-local:
>    Sink     :  10.10.10.3
>    Filter   :  both
>
> +mirror-lport:
> +  Type     :  lport
> +  Sink     :  sw0-port1
> +  Filter   :  to-lport
> +
>  mirror1:
>    Type     :  gre
>    Sink     :  10.10.10.1
> @@ -523,6 +535,11 @@ check_column "" nb:Logical_Switch_Port mirror_rules 
> name=sw0-port1
>
>  dnl Check if the mirror deleted properly
>  AT_CHECK([ovn-nbctl mirror-list], [0], [dnl
> +mirror-lport:
> +  Type     :  lport
> +  Sink     :  sw0-port1
> +  Filter   :  to-lport
> +
>  mirror1:
>    Type     :  gre
>    Sink     :  10.10.10.1
> @@ -537,9 +554,12 @@ mirror2:
>
>  ])
>
> -dnl Delete another mirror
> +dnl Delete mirrors one more mirror
>  check ovn-nbctl mirror-del mirror2
>
> +dnl Delete one more mirror
> +check ovn-nbctl mirror-del mirror-lport
> +
>  dnl Update the Sink address
>  check ovn-nbctl set mirror . sink=192.168.1.13
>
> @@ -559,6 +579,81 @@ AT_CHECK([ovn-nbctl mirror-list], [0], [dnl
>
>  dnl ---------------------------------------------------------------------
>
> +OVN_NBCTL_TEST([ovn_nbctl_mirrors_rules], [mirror_rules], [
> +check ovn-nbctl ls-add sw0
> +check ovn-nbctl lsp-add sw0 sw0-p1
> +check ovn-nbctl mirror-add mirror1 lport from-lport sw0-p1
> +check ovn-nbctl mirror-add mirror2 lport to-lport sw0-p1
> +
> +check ovn-nbctl mirror-rule-add mirror1 100 '1' mirror
> +check ovn-nbctl mirror-rule-add mirror2 150 'ip' mirror
> +
> +dnl Add mirror rule for non-exist mirror name
> +AT_CHECK([ovn-nbctl mirror-rule-add mirror5 150 'ip' allow], [1], [], 
> [stderr])
> +AT_CHECK([grep 'not found' stderr], [0], [ignore])
> +
> +dnl Add same mirror rule for mirror
> +AT_CHECK([ovn-nbctl mirror-rule-add mirror2 150 'ip' mirror], [1], [], 
> [stderr])
> +AT_CHECK([grep 'exists' stderr], [0], [ignore])
> +
> +AT_CHECK([ovn-nbctl mirror-list], [0], [dnl
> +mirror1:
> +  Type     :  lport
> +  Sink     :  sw0-p1
> +  Filter   :  from-lport
> +  Rules    :
> +         100                              1          mirror
> +
> +mirror2:
> +  Type     :  lport
> +  Sink     :  sw0-p1
> +  Filter   :  to-lport
> +  Rules    :
> +         150                             ip          mirror
> +
> +])
> +
> +dnl Add one more mirror rule to mirror
> +check ovn-nbctl mirror-rule-add mirror2 200 'icmp' mirror
> +
> +check ovn-nbctl mirror-rule-add mirror2 250 'icmp' skip
> +
> +dnl Mirror rule attach mirror
> +mirrorrule1uuid=$(fetch_column nb:Mirror_rule _uuid name=mirror1)
> +check_column "$mirrorrule1uuid" nb:Mirror mirror_rule 
> mirror_rule="$mirrorrule1uuid"
> +
> +dnl Remove the mirror rule by name
> +check ovn-nbctl mirror-rule-del mirror1
> +
> +dnl Mirror rule dettach mirror
> +mirrorr1uuid=$(fetch_column nb:Mirror _uuid name=mirror1)
> +check_column "" nb:Mirror mirror_rule mirror_rule="mirrorr1uuid"
> +
> +dnl Delete mirror rule by priority
> +check ovn-nbctl mirror-rule-del mirror2 200
> +
> +dnl Remove the mirror rule by priority and match
> +check ovn-nbctl mirror-rule-del mirror2 250 'icmp'
> +
> +AT_CHECK([ovn-nbctl mirror-list], [0], [dnl
> +mirror1:
> +  Type     :  lport
> +  Sink     :  sw0-p1
> +  Filter   :  from-lport
> +
> +mirror2:
> +  Type     :  lport
> +  Sink     :  sw0-p1
> +  Filter   :  to-lport
> +  Rules    :
> +         150                             ip          mirror
> +
> +])
> +
> +])
> +
> +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 e94658371..aa970a4fb 100644
> --- a/utilities/ovn-nbctl.c
> +++ b/utilities/ovn-nbctl.c
> @@ -298,9 +298,10 @@ QoS commands:\n\
>    qos-list SWITCH           print QoS rules for SWITCH\n\
>  \n\
>  Mirror commands:\n\
> -  mirror-add NAME TYPE [INDEX] FILTER {IP | MIRROR-ID} \n\
> +  mirror-add NAME TYPE [INDEX] FILTER {IP | MIRROR-ID| TARGET-PORT} \n\
>                              add a mirror with given name\n\
> -                            specify TYPE 'gre', 'erspan', or 'local'\n\
> +                            specify TYPE 'gre', 'erspan', 'local'\n\
> +                                or 'lport'.\n\
>                              specify the tunnel INDEX value\n\
>                                  (indicates key if GRE\n\
>                                   erpsan_idx if ERSPAN)\n\
> @@ -309,8 +310,16 @@ Mirror commands:\n\
>                              specify Sink / Destination i.e. Remote IP, or 
> a\n\
>                                  local interface with 
> external-ids:mirror-id\n\
>                                  matching MIRROR-ID\n\
> +                                In case of lport type specify logical 
> switch\n\
> +                                port, which is a mirror target.\n\
>    mirror-del [NAME]         remove mirrors\n\
>    mirror-list               print mirrors\n\
> +  mirror-rule-add MIRROR-NAME PRIORITY MATCH ACTION \n\
> +                            add a mirror rule selection to given lport\n\
> +                            mirror.\n\
> +                            specify MATCH for selecting mirrored traffic.\n\
> +                            specify ACTION 'mirror' or 'skip'.\n\
> +  mirror-rule-del MIRROR-NAME [PRIORITY | MATCH] remove mirrors\n\
>  \n\
>  Meter commands:\n\
>    [--fair]\n\
> @@ -1821,11 +1830,11 @@ nbctl_lsp_attach_mirror(struct ctl_context *ctx)
>          return;
>      }
>
> +    bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
>      /* Check if same mirror rule already exists for the lsp */
>      for (size_t i = 0; i < lsp->n_mirror_rules; i++) {
>          if (uuid_equals(&lsp->mirror_rules[i]->header_.uuid,
>                          &mirror->header_.uuid)) {
> -            bool may_exist = shash_find(&ctx->options, "--may-exist") != 
> NULL;
>              if (!may_exist) {
>                  ctl_error(ctx, "mirror %s is already attached to the "
>                            "logical port %s.",
> @@ -7772,16 +7781,18 @@ static char * OVS_WARN_UNUSED_RESULT
>  parse_mirror_type(const char *arg, const char **type_p)
>  {
>      /* Validate type.  Only require the first letter. */
> -    if (arg[0] == 'g') {
> +    if (!strcmp(arg, "gre")) {
>          *type_p = "gre";
> -    } else if (arg[0] == 'e') {
> +    } else if (!strcmp(arg, "erspan")) {
>          *type_p = "erspan";
> -    } else if (arg[0] == 'l') {
> +    } else if (!strcmp(arg, "local")) {
>          *type_p = "local";
> +    } else if (!strcmp(arg, "lport")) {
> +        *type_p = "lport";
>      } else {
>          *type_p = NULL;
>          return xasprintf("%s: type must be \"gre\", "
> -                         "\"erspan\", or \"local\"", arg);
> +                         "\"erspan\", or \"local\" or \"lport\"", arg);
>      }
>      return NULL;
>  }
> @@ -7794,6 +7805,7 @@ nbctl_pre_mirror_add(struct ctl_context *ctx)
>      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_logical_switch_port_col_name);
>  }
>
>  static void
> @@ -7818,14 +7830,17 @@ nbctl_mirror_add(struct ctl_context *ctx)
>          }
>      }
>
> -    /* Type - gre/erspan/local */
> +    /* Type - gre/erspan/local/lport */
>      error = parse_mirror_type(ctx->argv[pos++], &type);
>      if (error) {
>          ctx->error = error;
>          return;
>      }
>
> -    if (strcmp(type, "local")) {
> +    int is_local = !strcmp(type, "local");
> +    int is_lport = !strcmp(type, "lport");
> +
> +    if (!is_local && !is_lport) {
>          /* tunnel index / GRE key / ERSPAN idx */
>          if (!str_to_long(ctx->argv[pos++], 10, (long int *) &index)) {
>              ctl_error(ctx, "Invalid Index");
> @@ -7844,7 +7859,7 @@ nbctl_mirror_add(struct ctl_context *ctx)
>      sink = ctx->argv[pos++];
>
>      /* check if it is a valid ip unless it is type 'local' */
> -    if (strcmp(type, "local")) {
> +    if (!is_local && !is_lport) {
>          char *new_sink_ip = normalize_ipv4_addr_str(sink);
>          if (!new_sink_ip) {
>              new_sink_ip = normalize_ipv6_addr_str(sink);
> @@ -7857,6 +7872,21 @@ nbctl_mirror_add(struct ctl_context *ctx)
>          free(new_sink_ip);
>      }
>
> +    /* Check if it is an existing port for lport mirror type. */
> +    if (is_lport) {
> +        const struct nbrec_logical_switch_port *lsp;
> +        error = lsp_by_name_or_uuid(ctx, sink, false, &lsp);
> +        if (error) {
> +            ctx->error = error;
> +            return;
> +        }
> +
> +        if (!lsp) {
> +            VLOG_WARN("Attaching target to non existing port with name %s.",
> +                      sink);
> +        }
> +    }
> +
>      /* Create the mirror. */
>      struct nbrec_mirror *mirror = nbrec_mirror_insert(ctx->txn);
>      nbrec_mirror_set_name(mirror, name);
> @@ -7896,6 +7926,143 @@ nbctl_mirror_del(struct ctl_context *ctx)
>      }
>  }
>
> +static int
> +rule_cmp(const void *mirror1_, const void *mirror2_)
> +{
> +    const struct nbrec_mirror_rule *const *mirror_1 = mirror1_;
> +    const struct nbrec_mirror_rule *const *mirror_2 = mirror2_;
> +
> +    const struct nbrec_mirror_rule *mirror1 = *mirror_1;
> +    const struct nbrec_mirror_rule *mirror2 = *mirror_2;
> +
> +    int result =  mirror1->priority - mirror2->priority;
> +    if (result) {
> +        return result;
> +    }
> +
> +    result = strcmp(mirror1->match, mirror2->match);
> +    if (result) {
> +        return result;
> +    }
> +
> +    return strcmp(mirror1->action, mirror2->action);
> +}
> +
> +static void
> +nbctl_pre_mirror_rule_add(struct ctl_context *ctx)
> +{
> +    ovsdb_idl_add_column(ctx->idl, &nbrec_mirror_col_name);
> +    ovsdb_idl_add_column(ctx->idl, &nbrec_mirror_col_mirror_rules);
> +    ovsdb_idl_add_column(ctx->idl, &nbrec_mirror_rule_col_match);
> +    ovsdb_idl_add_column(ctx->idl, &nbrec_mirror_rule_col_action);
> +    ovsdb_idl_add_column(ctx->idl, &nbrec_mirror_rule_col_priority);
> +}
> +
> +static void
> +nbctl_mirror_rule_add(struct ctl_context *ctx)
> +{
> +    const struct nbrec_mirror_rule *mirror_rule;
> +    const struct nbrec_mirror *mirror;
> +    int64_t priority = 0;
> +    char *error;
> +
> +    error = mirror_by_name_or_uuid(ctx, ctx->argv[1], true, &mirror);
> +    if (error) {
> +        ctx->error = error;
> +        return;
> +    }
> +
> +    error = parse_priority(ctx->argv[2], &priority);
> +    if (error) {
> +        ctx->error = error;
> +        return;
> +    }
> +
> +    const char *action = ctx->argv[4];
> +    if (strcmp(action, "mirror") && strcmp(action, "skip")) {
> +        ctl_error(ctx, "%s: action must be one of \"mirror\", \"skip\"",
> +                  action);
> +    }
> +
> +    mirror_rule = nbrec_mirror_rule_insert(ctx->txn);
> +    nbrec_mirror_rule_set_match(mirror_rule, ctx->argv[3]);
> +    nbrec_mirror_rule_set_action(mirror_rule, action);
> +    nbrec_mirror_rule_set_priority(mirror_rule, priority);
> +
> +    bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
> +    /* Check if same mirror rule exists for this mirror. */
> +    for (size_t i = 0; i < mirror->n_mirror_rules; i++) {
> +        if (!rule_cmp(&mirror_rule, &mirror->mirror_rules[i])) {
> +            if (!may_exist) {
> +                ctl_error(ctx, "Same mirror-rule already exists on the "
> +                          "mirror %s.", ctx->argv[1]);
> +            } else {
> +                nbrec_mirror_rule_delete(mirror_rule);
> +            }
> +            return;
> +        }
> +    }
> +
> +    /* Insert mirror rule to mirror. */
> +    nbrec_mirror_update_mirror_rules_addvalue(mirror, mirror_rule);
> +}
> +
> +static void
> +nbctl_pre_mirror_rule_del(struct ctl_context *ctx)
> +{
> +    ovsdb_idl_add_column(ctx->idl, &nbrec_mirror_col_name);
> +    ovsdb_idl_add_column(ctx->idl, &nbrec_mirror_col_mirror_rules);
> +    ovsdb_idl_add_column(ctx->idl, &nbrec_mirror_rule_col_action);
> +    ovsdb_idl_add_column(ctx->idl, &nbrec_mirror_rule_col_priority);
> +    ovsdb_idl_add_column(ctx->idl, &nbrec_mirror_rule_col_match);
> +}
> +
> +static void
> +nbctl_mirror_rule_del(struct ctl_context *ctx)
> +{
> +    const struct nbrec_mirror *mirror = NULL;
> +    int64_t priority = 0;
> +    char *error = NULL;
> +
> +    error = mirror_by_name_or_uuid(ctx, ctx->argv[1], true, &mirror);
> +    if (error) {
> +        ctx->error = error;
> +        return;
> +    }
> +
> +    if (ctx->argc == 2) {
> +        for (size_t i = 0; i < mirror->n_mirror_rules; i++) {
> +            nbrec_mirror_update_mirror_rules_delvalue(mirror,
> +                                    mirror->mirror_rules[i]);
> +        }
> +        return;
> +    }
> +
> +    error = parse_priority(ctx->argv[2], &priority);
> +    if (error) {
> +        ctx->error = error;
> +        return;
> +    }
> +
> +    if (ctx->argc == 3) {
> +        for (size_t i = 0; i < mirror->n_mirror_rules; i++) {
> +            struct nbrec_mirror_rule *rule = mirror->mirror_rules[i];
> +            if (priority == rule->priority) {
> +                nbrec_mirror_update_mirror_rules_delvalue(mirror, rule);
> +                return;
> +            }
> +        }
> +    }
> +
> +    for (size_t i = 0; i < mirror->n_mirror_rules; i++) {
> +        struct nbrec_mirror_rule *rule = mirror->mirror_rules[i];
> +        if (priority == rule->priority && !strcmp(ctx->argv[3],
> +            rule->match)) {
> +            nbrec_mirror_update_mirror_rules_delvalue(mirror, rule);
> +        }
> +    }
> +}
> +
>  static void
>  nbctl_pre_mirror_list(struct ctl_context *ctx)
>  {
> @@ -7905,6 +8072,10 @@ nbctl_pre_mirror_list(struct ctl_context *ctx)
>      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_mirror_rules);
> +    ovsdb_idl_add_column(ctx->idl, &nbrec_mirror_rule_col_action);
> +    ovsdb_idl_add_column(ctx->idl, &nbrec_mirror_rule_col_match);
> +    ovsdb_idl_add_column(ctx->idl, &nbrec_mirror_rule_col_priority);
>  }
>
>  static void
> @@ -7931,15 +8102,27 @@ nbctl_mirror_list(struct ctl_context *ctx)
>
>      for (size_t i = 0; i < n_mirrors; i++) {
>          mirror = mirrors[i];
> +        bool is_lport = !strcmp(mirror->type, "lport");
> +        bool is_local = !strcmp(mirror->type, "local");
> +
>          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);
> -        if (strcmp(mirror->type, "local")) {
> +        if (!is_local && !is_lport) {
>              ds_put_format(&ctx->output, "  Index/Key:  %"PRId64"\n",
>                            mirror->index);
>          }
> +        if (mirror->n_mirror_rules) {
> +            ds_put_cstr(&ctx->output, "  Rules    :\n");
> +            for (size_t j = 0; j < mirror->n_mirror_rules; j++) {
> +                ds_put_format(&ctx->output, "       %5"PRId64" %30s %15s\n",
> +                              mirror->mirror_rules[j]->priority,
> +                              mirror->mirror_rules[j]->match,
> +                              mirror->mirror_rules[j]->action);
> +            }
> +        }
>          ds_put_cstr(&ctx->output, "\n");
>      }
>
> @@ -8044,13 +8227,19 @@ static const struct ctl_command_syntax 
> nbctl_commands[] = {
>
>      /* mirror commands. */
>      { "mirror-add", 4, 5,
> -      "NAME TYPE INDEX FILTER IP",
> +      "NAME TYPE INDEX FILTER SINK",
>        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 },
>
> +    /* Mirror rule commands. */
> +    { "mirror-rule-add", 4, 4, "MIRROR-NAME PRIORITY MATCH ACTION",
> +      nbctl_pre_mirror_rule_add, nbctl_mirror_rule_add, NULL, "", RW},
> +    { "mirror-rule-del", 1, 3, "MIRROR-NAME [PRIORITY MATCH]",
> +      nbctl_pre_mirror_rule_del, nbctl_mirror_rule_del, NULL, "", RW },
> +
>      /* meter commands. */
>      { "meter-add", 4, 5, "NAME ACTION RATE UNIT [BURST]", 
> nbctl_pre_meter_add,
>        nbctl_meter_add, NULL, "--fair,--may-exist", RW },
> --
> 2.48.1
>
> _______________________________________________
> dev mailing list
> d...@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to