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