On Tue, Nov 29, 2022 at 7:50 AM Abhiram R N <[email protected]> wrote:
>
> Hi Mark,
>
> Thanks for your review.
> Please see replies inline below
>
> On Tue, Nov 29, 2022 at 3:24 AM Mark Michelson <[email protected]> wrote:
>
> > Hi, since this patch series doesn't have a cover letter, I figure I
> > would make some top-level comments on the series here on patch 1. First
> > off, I suggest running all of the patches through
> > utilities/checkpatch.py in OVN. There are quite a few nitpicky coding
> > guidelines violations I noticed that it will point out to you.
> >
> I had indeed run all the patches using the utilities. For the patches 2 and
> 3
> it said "no obvious problems found"
> But only for the patch 1/3 it showed me 5 warnings
> But those are bit wired ones.
> For example...
> WARNING: Line lacks whitespace around operator
>
> #1496 FILE: utilities/ovn-nbctl.c:275:
>
>   mirror-add NAME TYPE INDEX FILTER IP\n\
> Here ... it expects a space between the hyphen.. but its similar to other
> commands.
>
> All the 5 warnings I got were similar ones. Other than those I didn't get
> any warnings, so I have
> ignored those.
> Is there any way to tell the checkpatch to ignore these? Because I don't
> see these warnings
> for other commands.( like meter-add, meter-list etc)
>
>
> >
> > Overall, I'm not all that familiar with the ins and outs of port
> > mirroring (i.e. what the requirements are), so I'm focusing mostly on
> > the mechanics in this review. With all that said, I have comments down
> > below.
> >
> > On 11/27/22 15:14, Abhiram R N wrote:
> > > 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 <[email protected]>
> > > Signed-off-by: Veda Barrenkala <[email protected]>
> > > Signed-off-by: Abhiram R N <[email protected]>
> > > ---
> > > 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"}},
> >
> > IMO, there is no reason for both the "mirror_rules" column to exist in
> > the logical switch port and for the "src" column to exist in the Mirror
> > table. This results in a circular reference that doesn't really seem
> > necessary based on my reading of the changes in northd.c . The
> > southbound DB doesn't have this problem since there is no "src" column
> > in the Port_Binding table.
> >
> This cross dependency we kept only in NB DB. And it is not there in SB DB.
> Numan had asked this point in an earlier version itself.
> This is needed for mirror-list. Since lsp can be attached to multiple
> mirrors
> and also multiple lsps can be attached to 1 mirror this helps while
> executing
> 'mirror-list'. Else to list mirrors with its attachments(srcs) we have to
> go through
> for each mirror through the list of lsps which is expensive we felt.
>

I agree with Mark and I had the same concerns.  I don't think we
should have circular
dependency just for the sake of displaying in ovn-nbctl.c

I'd suggest removing the "src" column from the Mirror table.
If you think the admin/CMS wants to know the attached ports to a
mirror, then I'd suggest implement it by
looping through all the ports and figuring out the mirrors to which a
port is associated.

I've some comments and suggestions in v18.  Please take a look there.

Numan


>
> > Also, this is a bit nitpicky of me, but why is the column called
> > "mirror_rules"? Should it just be called "mirrors"?
> >
> Nothing specific. I guess we had referred to qos_rules as reference.
>
>
> >
> > >                   "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 @@
> > >         </column>
> > >       </group>
> > >
> > > +    <column name="mirror_rules">
> > > +        Mirror rules that apply to logical switch port which is the
> > source.
> > > +        Please see the <ref table="Mirror"/> table.
> > > +    </column>
> > > +
> > >       <column name="ha_chassis_group">
> > >         References a row in the OVN Northbound database's
> > >         <ref table="HA_Chassis_Group" db="OVN_Northbound"/> table.
> > > @@ -2527,6 +2532,64 @@
> > >       </column>
> > >     </table>
> > >
> > > +  <table name="Mirror" title="Mirror Entry">
> > > +    <p>
> > > +      Each row in this table represents one Mirror that can be used for
> > > +      port mirroring. These Mirrors are referenced by the
> > > +      <ref column="mirror_rules" table="Logical_Switch_Port"/> column in
> > > +      the <ref table="Logical_Switch_Port"/> table.
> > > +    </p>
> > > +
> > > +    <column name="name">
> > > +      <p>
> > > +        Represents the name of the mirror.
> > > +      </p>
> > > +    </column>
> > > +
> > > +    <column name="filter">
> > > +      <p>
> > > +        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.
> > > +      </p>
> > > +    </column>
> > > +
> > > +    <column name="sink">
> > > +      <p>
> > > +        The value of this field represents the destination/sink of the
> > mirror.
> > > +        The value it takes is an IP address of the sink port.
> > > +      </p>
> > > +    </column>
> > > +
> > > +    <column name="type">
> > > +      <p>
> > > +        The value of this field represents the type of the tunnel used
> > for
> > > +        sending the mirrored packets. Supported Tunnel types gre and
> > erspan
> > > +      </p>
> > > +    </column>
> > > +
> > > +    <column name="index">
> > > +      <p>
> > > +        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
> > > +      </p>
> > > +    </column>
> > > +
> > > +    <column name="src">
> > > +      <p>
> > > +        The value of this field represents a list of source ports for
> > the
> > > +        mirror. Please see the <ref table="Logical_Switch_Port"/> table.
> > > +      </p>
> > > +    </column>
> > > +
> > > +    <column name="external_ids">
> > > +      See <em>External IDs</em> at the beginning of this document.
> > > +    </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 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;
> > >       </column>
> > >     </table>
> > >
> > > +  <table name="Mirror" title="Mirror Entry">
> > > +    <p>
> > > +      Each row in this table represents one Mirror that can be used for
> > > +      port mirroring. These Mirrors are referenced by the
> > > +      <ref column="mirror_rules" table="Port_Binding"/> column in
> > > +      the <ref table="Port_Binding"/> table.
> > > +    </p>
> > > +
> > > +    <column name="name">
> > > +      <p>
> > > +        Represents the name of the mirror.
> > > +      </p>
> > > +    </column>
> > > +
> > > +    <column name="filter">
> > > +      <p>
> > > +        The value of this field represents selection criteria of the
> > mirror.
> > > +      </p>
> > > +    </column>
> > > +
> > > +    <column name="sink">
> > > +      <p>
> > > +        The value of this field represents the destination/sink of the
> > mirror.
> > > +      </p>
> > > +    </column>
> > > +
> > > +    <column name="type">
> > > +      <p>
> > > +        The value of this field represents the type of the tunnel used
> > for
> > > +        sending the mirrored packets
> > > +      </p>
> > > +    </column>
> > > +
> > > +    <column name="index">
> > > +      <p>
> > > +        The value of this field represents the key/idx depending on the
> > > +        tunnel type configured
> > > +      </p>
> > > +    </column>
> > > +
> > > +    <column name="external_ids">
> > > +      See <em>External IDs</em> at the beginning of this document.
> > > +    </column>
> > > +  </table>
> > > +
> > >     <table name="Meter" title="Meter entry">
> > >       <p>
> > >         Each row in this table represents a meter that can be used for
> > QoS or
> > > @@ -3371,6 +3416,11 @@ tcp.flags = RST;
> > >         </column>
> > >       </group>
> > >
> > > +    <column name="mirror_rules">
> > > +        Mirror rules that apply to the port binding.
> > > +        Please see the <ref table="Mirror"/> table.
> > > +    </column>
> > > +
> > >       <group title="Patch Options">
> > >         <p>
> > >           These options apply to logical ports with <ref column="type"/>
> > 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])
> >
> > Suggestion: Replace uses of AT_CHECK above with "check". It's a bit less
> > cluttered and it has the benefit of automatically echoing the command to
> > stdout. That can really help when debugging.
> >
> Ok. Will replace it.
>
> >
> > You can use "check" any time that a command should execute with a
> > 0-return value and is expected to output nothing to stdout or stderr.
> >
> Sure.
>
> >
> > > +
> > > +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
> > > +
> > > +])
> >
> > There are some handy functions in ovn-macros.at that can simplify this
> > sort of query. In this case, you can use the "check_column" function
> > like so:
> >
> > check_column "" nb:Logical_Switch_Port mirror_rules name=sw0-port1
> >
> Sure. Will try to use them.
>
> >
> > > +
> > > +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
> > ---------------------------------------------------------------------
> >
> > Overall this is a decent test but it should also ensure that the
> > mirror_rules columns in the affected logical switch ports have the
> > expected data in them.
> >
> Sure.
>
> >
> > > +
> > >   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]);
> >
> > It's preferable to use the OVS function str_to_int() here instead of
> > atoi(). The reason is that atoi() returns 0 for both an invalid input
> > and for the literal "0". str_to_int() returns a bool to indicate whether
> > the input was valid or not.
> >
> Ok. Will use str_to_int.
>
> >
> > > +
> > > +    /* 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},
> > >
> >
> > Thanks & Regards,
> Abhiram R N
> _______________________________________________
> dev mailing list
> [email protected]
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


Reply via email to