[ovs-dev] 回复: [External] Re: [PATCH ovn] northd: Fix issues for Forwarding_Group

2024-07-10 Thread Qiang Qiang45 Zhang via dev
Test cases have been added.


发件人: Ales Musil 
发送时间: 2024年7月10日 15:02
收件人: Qiang Qiang45 Zhang 
抄送: d...@openvswitch.org
主题: [External] Re: [ovs-dev] [PATCH ovn] northd: Fix issues for Forwarding_Group



On Mon, Jul 8, 2024 at 5:01 PM Qiang Qiang45 Zhang via dev 
mailto:ovs-dev@openvswitch.org>> wrote:
When a logical switch has 2 FWGs and each FWG has 3 ports,
Logical-Flow only has one fwg_group() action.
Submitted-at: northd: Fix issues for Forwarding_Group by ZhangQiang3 * Pull 
Request #250 * ovn-org/ovn 
(github.com)

From 02186da234426bc361615eb6b5142c76f296202f Mon Sep 17 00:00:00 2001
From: zhangqiang45 
zhangqian...@lenovo.com>
Date: Mon, 8 Jul 2024 14:25:04 +0800
Subject: [PATCH ovn] northd: Fix issues for Forwarding_Group The use of
variables from the outer loop in the inner loop causes the outer loop to
terminate prematurely. eg. LVS are three fwgs,
fwg1(p1,p2,p3,p4),fwg2(p11,p22),fwg3(p31,p32),only fwg1 in logical_flows

---

Hello,

thank you for the fix. The commit message seems to be broken as it
includes the email header for some reason. Also could you please add
test to ovn-northd.at that ensures this won't happen in 
future?

northd/northd.c | 7 +--
1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/northd/northd.c b/northd/northd.c
index 6898daa00..21ab0bb91 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -7929,6 +7929,9 @@ build_fwd_group_lflows(struct ovn_datapath *od, struct 
lflow_table *lflows,
 continue;
 }

+ds_clear();
+ds_clear();
+
 /* ARP responder for the forwarding group's virtual IP */
 ds_put_format(, "arp.tpa == %s && arp.op == 1",
   fwd_group->vip);
@@ -7959,9 +7962,9 @@ build_fwd_group_lflows(struct ovn_datapath *od, struct 
lflow_table *lflows,
 ds_put_cstr(_ports, "liveness=\"true\",");
 }
 ds_put_cstr(_ports, "childports=");
-for (i = 0; i < (fwd_group->n_child_port - 1); ++i) {
+for (int j = 0; j < (fwd_group->n_child_port - 1); ++j) {

nit: Please use size_t as the "j" type.
 ds_put_format(_ports, "\"%s\",",
- fwd_group->child_port[i]);
+ fwd_group->child_port[j]);
 }
 ds_put_format(_ports, "\"%s\"",
   fwd_group->child_port[fwd_group->n_child_port - 1]);
--
2.39.3

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Thanks,
Ales

--

Ales Musil

Senior Software Engineer - OVN Core

Red Hat EMEA

amu...@redhat.com
[https://static.redhat.com/libs/redhat/brand-assets/latest/corp/logo.png]

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


Re: [ovs-dev] [PATCH v1 13/13] ofp-actions: Load data from fields in sample action.

2024-07-10 Thread Ilya Maximets
On 7/10/24 23:38, Adrián Moreno wrote:
> On Wed, Jul 10, 2024 at 11:00:43PM GMT, Ilya Maximets wrote:
>> On 7/7/24 22:09, Adrian Moreno wrote:
>>> When sample action gets used as a way of sampling traffic with
>>> controller-generated metadata (i.e: obs_domain_id and obs_point_id),
>>> the controller will have to increase the number of flows to ensure each
>>> part of the pipeline contains the right metadata.
>>>
>>> As an example, if the controller decides to sample stateful traffic, it
>>> could store the computed metadata for each connection in the conntrack
>>> label. However, for established connections, a flow must be created for
>>> each different ct_label value with a sample action that contains a
>>> different hardcoded obs_domain and obs_point id.
>>>
>>> This patch adds a new version of the NXAST_RAW_SAMPLE* action (number 4)
>>> that supports specifying the observation point and domain using an
>>> OpenFlow field reference, so now the controller can express:
>>>
>>>  sample(...
>>> obs_domain_id=NXM_NX_CT_LABEL[0..31],
>>> obs_point_id=NXM_NX_CT_LABEL[32..63]
>>> ...
>>>)
>>>
>>> Signed-off-by: Adrian Moreno 
>>> ---
>>>  include/openvswitch/ofp-actions.h |   8 +-
>>>  lib/ofp-actions.c | 249 +++---
>>>  ofproto/ofproto-dpif-xlate.c  |  55 ++-
>>>  python/ovs/flow/ofp.py|   8 +-
>>>  python/ovs/flow/ofp_act.py|   4 +-
>>>  tests/ofp-actions.at  |   5 +
>>>  tests/ofproto-dpif.at |  41 +
>>>  tests/system-traffic.at   |  74 +
>>>  8 files changed, 405 insertions(+), 39 deletions(-)
>>
>> Not a full review, it's a complicated change.  See a few comments below.
>>
>>>
>>> diff --git a/include/openvswitch/ofp-actions.h 
>>> b/include/openvswitch/ofp-actions.h
>>> index 7b57e49ad..56dc2c147 100644
>>> --- a/include/openvswitch/ofp-actions.h
>>> +++ b/include/openvswitch/ofp-actions.h
>>> @@ -1015,14 +1015,16 @@ enum nx_action_sample_direction {
>>>
>>>  /* OFPACT_SAMPLE.
>>>   *
>>> - * Used for NXAST_SAMPLE, NXAST_SAMPLE2, and NXAST_SAMPLE3. */
>>> + * Used for NXAST_SAMPLE, NXAST_SAMPLE2, NXAST_SAMPLE3 and NXAST_SAMPLE4. 
>>> */
>>>  struct ofpact_sample {
>>>  OFPACT_PADDED_MEMBERS(
>>>  struct ofpact ofpact;
>>>  uint16_t probability;   /* Always positive. */
>>>  uint32_t collector_set_id;
>>> -uint32_t obs_domain_id;
>>> -uint32_t obs_point_id;
>>> +uint32_t obs_domain_imm;
>>> +struct mf_subfield obs_domain_src;
>>> +uint32_t obs_point_imm;
>>> +struct mf_subfield obs_point_src;
>>>  ofp_port_t sampling_port;
>>>  enum nx_action_sample_direction direction;
>>>  );
>>> diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
>>> index da7b1dd31..e329a7e3f 100644
>>> --- a/lib/ofp-actions.c
>>> +++ b/lib/ofp-actions.c
>>> @@ -330,6 +330,8 @@ enum ofp_raw_action_type {
>>>  NXAST_RAW_SAMPLE2,
>>>  /* NX1.0+(41): struct nx_action_sample2. */
>>>  NXAST_RAW_SAMPLE3,
>>> +/* NX1.0+(51): struct nx_action_sample4, ... VLMFF */
>>
>> Why the dots are here?  The structure doesn't seem to have
>> extra fields at the end.
> 
> I missread the description then. I thought it was just about alignment.
> 
>>
>>> +NXAST_RAW_SAMPLE4,
>>>
>>>  /* NX1.0+(34): struct nx_action_conjunction. */
>>>  NXAST_RAW_CONJUNCTION,
>>> @@ -6188,6 +6190,34 @@ struct nx_action_sample2 {
>>>   };
>>>   OFP_ASSERT(sizeof(struct nx_action_sample2) == 32);
>>>
>>> +/* Action structure for NXAST_SAMPLE4
>>> + *
>>> + * NXAST_SAMPLE4 was added in Open vSwitch 3.4.0.  Compared to 
>>> NXAST_SAMPLE3,
>>> + * it adds support for using field specifiers for observation_domain_id and
>>> + * observation_point_id. */
>>> +struct nx_action_sample4 {
>>> +ovs_be16 type;  /* OFPAT_VENDOR. */
>>> +ovs_be16 len;   /* Length is 32. */
>>
>> Is the length 32?  40, I suppose.
> 
> Yep
> 
>>
>>> +ovs_be32 vendor;/* NX_VENDOR_ID. */
>>> +ovs_be16 subtype;   /* NXAST_SAMPLE. */
>>
>> NXAST_SAMPLE4 ?
> 
> Ack.
> 
>>
>>> +ovs_be16 probability;   /* Fraction of packets to sample. */
>>> +ovs_be32 collector_set_id;  /* ID of collector set in OVSDB. */
>>> +ovs_be32 obs_domain_src;/* Source of the 
>>> observation_domain_id. */
>>> +union {
>>> +ovs_be16 obs_domain_ofs_nbits;  /* Range to use from source field. 
>>> */
>>> +ovs_be32 obs_domain_imm;/* Immediate value for domain id. 
>>> */
>>> +};
>>> +ovs_be32 obs_point_src; /* Source of the observation_point_id 
>>> */
>>> +union {
>>> +ovs_be16 obs_point_ofs_nbits;  /* Range to use from source field. 
>>> */
>>> +ovs_be32 obs_point_imm;/* Immediate value for point id. */
>>> +};
>>> +ovs_be16 sampling_port; /* Sampling port. */
>>> +uint8_t  

Re: [ovs-dev] [PATCH v1 11/13] ofproto: xlate: Make flow-sampled drops explicit.

2024-07-10 Thread Adrián Moreno
On Wed, Jul 10, 2024 at 11:31:42PM GMT, Ilya Maximets wrote:
> On 7/7/24 22:09, Adrian Moreno wrote:
> > When an action set ends in a an OFP_SAMPLE action, it means the packet
> > will be dropped and sampled. Make the drop explicit in this case so that
> > drop statistics remain accurate.
> >
> > This could be done outside of the sample action, i.e: "sample(...),drop"
> > but datapaths optimize sample actions that are found in the last
> > position. So, taking into account that datapaths already report when the
> > last sample probability fails, it is safe to put the drop inside the
> > sample, i.e: "sample(...,drop)".
> >
> > Signed-off-by: Adrian Moreno 
> > ---
> >  ofproto/ofproto-dpif-xlate.c | 16 +++--
> >  tests/drop-stats.at  | 65 
> >  tests/ofproto-dpif.at| 44 
> >  3 files changed, 123 insertions(+), 2 deletions(-)
>
> Hi, Adrian.  As we discussed before on the kernel list, I'm not sure
> this is a right change to make for a fwe reasons:
>
> 1. We do not know the user's intentions.  We do not know if they
>wanted to drop these packets or their goal was to sample them
>and it just happened to be the last action in the list, because
>they put it after the output action and not before.
>

If there are datapath actions after output action you will probably get
drops reported in both datapaths.

> 2. This patch doesn't cover cases where sampling is not actually
>the last action, but further actions do not yield any datapath
>actions.  E.g. if you have a register resoration afterwards,
>which happens in automatically built pipelines like in OVN.
>Or if the last action after sampling is learn().  And things are
>getting more complicated if we take into account resubmits and
>processing in different bridges via patch ports.

I agree this could be problematic. Maybe we should make sure the sample
is the last dp action and "fix it". A trick such as the one done for
sflow.

>
> 3. If someone is sampling the drops specifically, they know where
>to find the packets, because they configured the collector.
>

I think drop stats and samples are two different things. There are
typically extacted by different tools and systems.

Besides, what about per-bridge sampling (next patch)?
The user enables sampling on a bridge without explicitly doing it
for drops and suddenly the drop statistics dissapear.

> 4. Packets are not actually dropped, they are delivered to userspace
>or psample.  It might make sense though to drop with a reson in
>case the upcall fails or psample fails to deliver to any entity
>and it is the last action in the datapath, but that's a kernel
>change to make.
>

I don't want to get into another semantic discussion between consume,
free and drop or the dark corners of the OpenFlow protocol. For me it's
pretty clear that if the last action is to sample, the packet is
"dropped" in the sense that, from a switch' perspective, if it's not
forwarded/sent somewhere, it's dropped.

I know you don't think the same :-).

Would you then agree that the concept of dropping packets is very
unclear and OpenFlow does not make it easy (or even possible?) to
express a sampled drops and we should add an extension action to
explicitly drop packets?

> 5. Drop reporting in either datapath implementation is not 100%
>accurate anyway and requires users to know the kernel internals.
>

Shouldn't we try to make them more accurate, not less?

> Some of that also applies to the next patch in the set.
>

I can take some of the critics for this patch but for me, the next one
is bluntly fixing a bug: Per-bridge sflow/IPFIX should not break drop
statistics.

> For the patch itself, you should also check that the action set is
> actually empty (not the action list) after the sample action translation.

Aye, what about doing the sflow trick and look at the datapath flow
alone?

> There is a chance that the clone action is disabled and sample is
> used in place of a clone, I'm not sure this case is covered.

That case does not go through compose_sample_action but encodes the
datapath action directly.

> And the formatting in tests seems very inconsistent.
>

I agree, I tried to follow the drop-stats.at "style" and the result is
pretty bad.

> Best regards, Ilya Maximets.
>

Thanks.

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


Re: [ovs-dev] [PATCH v1 13/13] ofp-actions: Load data from fields in sample action.

2024-07-10 Thread Adrián Moreno
On Wed, Jul 10, 2024 at 11:00:43PM GMT, Ilya Maximets wrote:
> On 7/7/24 22:09, Adrian Moreno wrote:
> > When sample action gets used as a way of sampling traffic with
> > controller-generated metadata (i.e: obs_domain_id and obs_point_id),
> > the controller will have to increase the number of flows to ensure each
> > part of the pipeline contains the right metadata.
> >
> > As an example, if the controller decides to sample stateful traffic, it
> > could store the computed metadata for each connection in the conntrack
> > label. However, for established connections, a flow must be created for
> > each different ct_label value with a sample action that contains a
> > different hardcoded obs_domain and obs_point id.
> >
> > This patch adds a new version of the NXAST_RAW_SAMPLE* action (number 4)
> > that supports specifying the observation point and domain using an
> > OpenFlow field reference, so now the controller can express:
> >
> >  sample(...
> > obs_domain_id=NXM_NX_CT_LABEL[0..31],
> > obs_point_id=NXM_NX_CT_LABEL[32..63]
> > ...
> >)
> >
> > Signed-off-by: Adrian Moreno 
> > ---
> >  include/openvswitch/ofp-actions.h |   8 +-
> >  lib/ofp-actions.c | 249 +++---
> >  ofproto/ofproto-dpif-xlate.c  |  55 ++-
> >  python/ovs/flow/ofp.py|   8 +-
> >  python/ovs/flow/ofp_act.py|   4 +-
> >  tests/ofp-actions.at  |   5 +
> >  tests/ofproto-dpif.at |  41 +
> >  tests/system-traffic.at   |  74 +
> >  8 files changed, 405 insertions(+), 39 deletions(-)
>
> Not a full review, it's a complicated change.  See a few comments below.
>
> >
> > diff --git a/include/openvswitch/ofp-actions.h 
> > b/include/openvswitch/ofp-actions.h
> > index 7b57e49ad..56dc2c147 100644
> > --- a/include/openvswitch/ofp-actions.h
> > +++ b/include/openvswitch/ofp-actions.h
> > @@ -1015,14 +1015,16 @@ enum nx_action_sample_direction {
> >
> >  /* OFPACT_SAMPLE.
> >   *
> > - * Used for NXAST_SAMPLE, NXAST_SAMPLE2, and NXAST_SAMPLE3. */
> > + * Used for NXAST_SAMPLE, NXAST_SAMPLE2, NXAST_SAMPLE3 and NXAST_SAMPLE4. 
> > */
> >  struct ofpact_sample {
> >  OFPACT_PADDED_MEMBERS(
> >  struct ofpact ofpact;
> >  uint16_t probability;   /* Always positive. */
> >  uint32_t collector_set_id;
> > -uint32_t obs_domain_id;
> > -uint32_t obs_point_id;
> > +uint32_t obs_domain_imm;
> > +struct mf_subfield obs_domain_src;
> > +uint32_t obs_point_imm;
> > +struct mf_subfield obs_point_src;
> >  ofp_port_t sampling_port;
> >  enum nx_action_sample_direction direction;
> >  );
> > diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
> > index da7b1dd31..e329a7e3f 100644
> > --- a/lib/ofp-actions.c
> > +++ b/lib/ofp-actions.c
> > @@ -330,6 +330,8 @@ enum ofp_raw_action_type {
> >  NXAST_RAW_SAMPLE2,
> >  /* NX1.0+(41): struct nx_action_sample2. */
> >  NXAST_RAW_SAMPLE3,
> > +/* NX1.0+(51): struct nx_action_sample4, ... VLMFF */
>
> Why the dots are here?  The structure doesn't seem to have
> extra fields at the end.

I missread the description then. I thought it was just about alignment.

>
> > +NXAST_RAW_SAMPLE4,
> >
> >  /* NX1.0+(34): struct nx_action_conjunction. */
> >  NXAST_RAW_CONJUNCTION,
> > @@ -6188,6 +6190,34 @@ struct nx_action_sample2 {
> >   };
> >   OFP_ASSERT(sizeof(struct nx_action_sample2) == 32);
> >
> > +/* Action structure for NXAST_SAMPLE4
> > + *
> > + * NXAST_SAMPLE4 was added in Open vSwitch 3.4.0.  Compared to 
> > NXAST_SAMPLE3,
> > + * it adds support for using field specifiers for observation_domain_id and
> > + * observation_point_id. */
> > +struct nx_action_sample4 {
> > +ovs_be16 type;  /* OFPAT_VENDOR. */
> > +ovs_be16 len;   /* Length is 32. */
>
> Is the length 32?  40, I suppose.

Yep

>
> > +ovs_be32 vendor;/* NX_VENDOR_ID. */
> > +ovs_be16 subtype;   /* NXAST_SAMPLE. */
>
> NXAST_SAMPLE4 ?

Ack.

>
> > +ovs_be16 probability;   /* Fraction of packets to sample. */
> > +ovs_be32 collector_set_id;  /* ID of collector set in OVSDB. */
> > +ovs_be32 obs_domain_src;/* Source of the 
> > observation_domain_id. */
> > +union {
> > +ovs_be16 obs_domain_ofs_nbits;  /* Range to use from source field. 
> > */
> > +ovs_be32 obs_domain_imm;/* Immediate value for domain id. 
> > */
> > +};
> > +ovs_be32 obs_point_src; /* Source of the observation_point_id 
> > */
> > +union {
> > +ovs_be16 obs_point_ofs_nbits;  /* Range to use from source field. 
> > */
> > +ovs_be32 obs_point_imm;/* Immediate value for point id. */
> > +};
> > +ovs_be16 sampling_port; /* Sampling port. */
> > +uint8_t  direction; /* Sampling direction. */
> > +uint8_t  zeros[5];  

Re: [ovs-dev] [PATCH v1 11/13] ofproto: xlate: Make flow-sampled drops explicit.

2024-07-10 Thread Ilya Maximets
On 7/7/24 22:09, Adrian Moreno wrote:
> When an action set ends in a an OFP_SAMPLE action, it means the packet
> will be dropped and sampled. Make the drop explicit in this case so that
> drop statistics remain accurate.
> 
> This could be done outside of the sample action, i.e: "sample(...),drop"
> but datapaths optimize sample actions that are found in the last
> position. So, taking into account that datapaths already report when the
> last sample probability fails, it is safe to put the drop inside the
> sample, i.e: "sample(...,drop)".
> 
> Signed-off-by: Adrian Moreno 
> ---
>  ofproto/ofproto-dpif-xlate.c | 16 +++--
>  tests/drop-stats.at  | 65 
>  tests/ofproto-dpif.at| 44 
>  3 files changed, 123 insertions(+), 2 deletions(-)

Hi, Adrian.  As we discussed before on the kernel list, I'm not sure
this is a right change to make for a fwe reasons:

1. We do not know the user's intentions.  We do not know if they
   wanted to drop these packets or their goal was to sample them
   and it just happened to be the last action in the list, because
   they put it after the output action and not before.

2. This patch doesn't cover cases where sampling is not actually
   the last action, but further actions do not yield any datapath
   actions.  E.g. if you have a register resoration afterwards,
   which happens in automatically built pipelines like in OVN.
   Or if the last action after sampling is learn().  And things are
   getting more complicated if we take into account resubmits and
   processing in different bridges via patch ports.

3. If someone is sampling the drops specifically, they know where
   to find the packets, because they configured the collector.

4. Packets are not actually dropped, they are delivered to userspace
   or psample.  It might make sense though to drop with a reson in
   case the upcall fails or psample fails to deliver to any entity
   and it is the last action in the datapath, but that's a kernel
   change to make.

5. Drop reporting in either datapath implementation is not 100%
   accurate anyway and requires users to know the kernel internals.

Some of that also applies to the next patch in the set.

For the patch itself, you should also check that the action set is
actually empty (not the action list) after the sample action translation.
There is a chance that the clone action is disabled and sample is
used in place of a clone, I'm not sure this case is covered.
And the formatting in tests seems very inconsistent.

Best regards, Ilya Maximets.
___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


Re: [ovs-dev] [PATCH v1 13/13] ofp-actions: Load data from fields in sample action.

2024-07-10 Thread Ilya Maximets
On 7/7/24 22:09, Adrian Moreno wrote:
> When sample action gets used as a way of sampling traffic with
> controller-generated metadata (i.e: obs_domain_id and obs_point_id),
> the controller will have to increase the number of flows to ensure each
> part of the pipeline contains the right metadata.
> 
> As an example, if the controller decides to sample stateful traffic, it
> could store the computed metadata for each connection in the conntrack
> label. However, for established connections, a flow must be created for
> each different ct_label value with a sample action that contains a
> different hardcoded obs_domain and obs_point id.
> 
> This patch adds a new version of the NXAST_RAW_SAMPLE* action (number 4)
> that supports specifying the observation point and domain using an
> OpenFlow field reference, so now the controller can express:
> 
>  sample(...
> obs_domain_id=NXM_NX_CT_LABEL[0..31],
> obs_point_id=NXM_NX_CT_LABEL[32..63]
> ...
>)
> 
> Signed-off-by: Adrian Moreno 
> ---
>  include/openvswitch/ofp-actions.h |   8 +-
>  lib/ofp-actions.c | 249 +++---
>  ofproto/ofproto-dpif-xlate.c  |  55 ++-
>  python/ovs/flow/ofp.py|   8 +-
>  python/ovs/flow/ofp_act.py|   4 +-
>  tests/ofp-actions.at  |   5 +
>  tests/ofproto-dpif.at |  41 +
>  tests/system-traffic.at   |  74 +
>  8 files changed, 405 insertions(+), 39 deletions(-)

Not a full review, it's a complicated change.  See a few comments below.

> 
> diff --git a/include/openvswitch/ofp-actions.h 
> b/include/openvswitch/ofp-actions.h
> index 7b57e49ad..56dc2c147 100644
> --- a/include/openvswitch/ofp-actions.h
> +++ b/include/openvswitch/ofp-actions.h
> @@ -1015,14 +1015,16 @@ enum nx_action_sample_direction {
>  
>  /* OFPACT_SAMPLE.
>   *
> - * Used for NXAST_SAMPLE, NXAST_SAMPLE2, and NXAST_SAMPLE3. */
> + * Used for NXAST_SAMPLE, NXAST_SAMPLE2, NXAST_SAMPLE3 and NXAST_SAMPLE4. */
>  struct ofpact_sample {
>  OFPACT_PADDED_MEMBERS(
>  struct ofpact ofpact;
>  uint16_t probability;   /* Always positive. */
>  uint32_t collector_set_id;
> -uint32_t obs_domain_id;
> -uint32_t obs_point_id;
> +uint32_t obs_domain_imm;
> +struct mf_subfield obs_domain_src;
> +uint32_t obs_point_imm;
> +struct mf_subfield obs_point_src;
>  ofp_port_t sampling_port;
>  enum nx_action_sample_direction direction;
>  );
> diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
> index da7b1dd31..e329a7e3f 100644
> --- a/lib/ofp-actions.c
> +++ b/lib/ofp-actions.c
> @@ -330,6 +330,8 @@ enum ofp_raw_action_type {
>  NXAST_RAW_SAMPLE2,
>  /* NX1.0+(41): struct nx_action_sample2. */
>  NXAST_RAW_SAMPLE3,
> +/* NX1.0+(51): struct nx_action_sample4, ... VLMFF */

Why the dots are here?  The structure doesn't seem to have
extra fields at the end.

> +NXAST_RAW_SAMPLE4,
>  
>  /* NX1.0+(34): struct nx_action_conjunction. */
>  NXAST_RAW_CONJUNCTION,
> @@ -6188,6 +6190,34 @@ struct nx_action_sample2 {
>   };
>   OFP_ASSERT(sizeof(struct nx_action_sample2) == 32);
>  
> +/* Action structure for NXAST_SAMPLE4
> + *
> + * NXAST_SAMPLE4 was added in Open vSwitch 3.4.0.  Compared to NXAST_SAMPLE3,
> + * it adds support for using field specifiers for observation_domain_id and
> + * observation_point_id. */
> +struct nx_action_sample4 {
> +ovs_be16 type;  /* OFPAT_VENDOR. */
> +ovs_be16 len;   /* Length is 32. */

Is the length 32?  40, I suppose.

> +ovs_be32 vendor;/* NX_VENDOR_ID. */
> +ovs_be16 subtype;   /* NXAST_SAMPLE. */

NXAST_SAMPLE4 ?

> +ovs_be16 probability;   /* Fraction of packets to sample. */
> +ovs_be32 collector_set_id;  /* ID of collector set in OVSDB. */
> +ovs_be32 obs_domain_src;/* Source of the observation_domain_id. 
> */
> +union {
> +ovs_be16 obs_domain_ofs_nbits;  /* Range to use from source field. */
> +ovs_be32 obs_domain_imm;/* Immediate value for domain id. */
> +};
> +ovs_be32 obs_point_src; /* Source of the observation_point_id */
> +union {
> +ovs_be16 obs_point_ofs_nbits;  /* Range to use from source field. */
> +ovs_be32 obs_point_imm;/* Immediate value for point id. */
> +};
> +ovs_be16 sampling_port; /* Sampling port. */
> +uint8_t  direction; /* Sampling direction. */
> +uint8_t  zeros[5];  /* Pad to a multiple of 8 bytes */

Double spaces are a little strage.

> + };
> + OFP_ASSERT(sizeof(struct nx_action_sample4) == 40);
> +
>  static enum ofperr
>  decode_NXAST_RAW_SAMPLE(const struct nx_action_sample *nas,
>  enum ofp_version ofp_version OVS_UNUSED,
> @@ -6199,11 +6229,14 @@ decode_NXAST_RAW_SAMPLE(const struct nx_action_sample 
> *nas,

Re: [ovs-dev] [PATCH v1 13/13] ofp-actions: Load data from fields in sample action.

2024-07-10 Thread Adrián Moreno
On Wed, Jul 10, 2024 at 10:26:23PM GMT, Ilya Maximets wrote:
> On 7/9/24 16:25, Eelco Chaudron wrote:
> >
> >
> > On 9 Jul 2024, at 16:17, Adrián Moreno wrote:
> >
> >> On Tue, Jul 09, 2024 at 11:46:12AM GMT, Eelco Chaudron wrote:
> >>> On 7 Jul 2024, at 22:09, Adrian Moreno wrote:
> >>>
>  When sample action gets used as a way of sampling traffic with
>  controller-generated metadata (i.e: obs_domain_id and obs_point_id),
>  the controller will have to increase the number of flows to ensure each
>  part of the pipeline contains the right metadata.
> 
>  As an example, if the controller decides to sample stateful traffic, it
>  could store the computed metadata for each connection in the conntrack
>  label. However, for established connections, a flow must be created for
>  each different ct_label value with a sample action that contains a
>  different hardcoded obs_domain and obs_point id.
> 
>  This patch adds a new version of the NXAST_RAW_SAMPLE* action (number 4)
>  that supports specifying the observation point and domain using an
>  OpenFlow field reference, so now the controller can express:
> 
>   sample(...
>  obs_domain_id=NXM_NX_CT_LABEL[0..31],
>  obs_point_id=NXM_NX_CT_LABEL[32..63]
>  ...
> )
> 
>  Signed-off-by: Adrian Moreno 
> >>>
> >>> See some comments inline. I’m missing the documentation update.
> >>>
> >>
> >> Yes. I noticed I missed both the NEWS and documentation update.
> >>
>
> You're also missing unit tests in ovs-ofctl.at.
>

Ack.

>  index 323a58cbf..2aff48f5e 100644
>  --- a/ofproto/ofproto-dpif-xlate.c
>  +++ b/ofproto/ofproto-dpif-xlate.c
>  @@ -5909,6 +5909,44 @@ xlate_fin_timeout(struct xlate_ctx *ctx,
>   }
>   }
> 
>  +static uint32_t
>  +ofpact_sample_get_domain(struct xlate_ctx *ctx,
>  + const struct ofpact_sample *os)
>  +{
>  +if (os->obs_domain_src.field) {
>  +union mf_subvalue *value = xmalloc(sizeof *value);
> >>>
> >>> Would it be better to just put these 128 bytes on the stack to avoid
> >>> memory fragmentation? Same for the next function.
> >>>
> >>> Or maybe something better, we could do something like we did for
> >>> exact_match_mask?
> >>>
> >>>   const union mf_value exact_match_mask = MF_VALUE_EXACT_INITIALIZER;
> >>>   extern const union mf_value exact_match_mask;
> >>>
> >>
> >> A quick look seemed to indicate dynamic memory was preferred in this
> >> module so I assumed there was a reason for it (I do remember stack size
> >> being a problem at some point, not sure if it was here).
> >>
> >> I'll look at the exact_match_mask case.
> >
> > I guess this function is not called recursively, so we should be ok with 
> > the stack usage. But a const variable might be better (and we can fix the 
> > other place(s) where you copied this code from ;).
>
> While the function itself is not called recursively, the problem is
> that it can be inlined into the main do_xlate_actions and cause
> a significant stack usage increase even if the sampling is not used.
> So, extra investigation on what is getting inlined with different
> compilers and compiler flags is needed if we want to allocate it
> on stack.
>
> Best regards, Ilya Maximets.
>

For the next version, I have implemented Eelco's suggestion: an extern
constant all-one enum mf_subfield. That should avoid both stack increase
and memory fragmentation

Cheers,
Adrián

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


Re: [ovs-dev] [PATCH v1 13/13] ofp-actions: Load data from fields in sample action.

2024-07-10 Thread Ilya Maximets
On 7/9/24 16:25, Eelco Chaudron wrote:
> 
> 
> On 9 Jul 2024, at 16:17, Adrián Moreno wrote:
> 
>> On Tue, Jul 09, 2024 at 11:46:12AM GMT, Eelco Chaudron wrote:
>>> On 7 Jul 2024, at 22:09, Adrian Moreno wrote:
>>>
 When sample action gets used as a way of sampling traffic with
 controller-generated metadata (i.e: obs_domain_id and obs_point_id),
 the controller will have to increase the number of flows to ensure each
 part of the pipeline contains the right metadata.

 As an example, if the controller decides to sample stateful traffic, it
 could store the computed metadata for each connection in the conntrack
 label. However, for established connections, a flow must be created for
 each different ct_label value with a sample action that contains a
 different hardcoded obs_domain and obs_point id.

 This patch adds a new version of the NXAST_RAW_SAMPLE* action (number 4)
 that supports specifying the observation point and domain using an
 OpenFlow field reference, so now the controller can express:

  sample(...
 obs_domain_id=NXM_NX_CT_LABEL[0..31],
 obs_point_id=NXM_NX_CT_LABEL[32..63]
 ...
)

 Signed-off-by: Adrian Moreno 
>>>
>>> See some comments inline. I’m missing the documentation update.
>>>
>>
>> Yes. I noticed I missed both the NEWS and documentation update.
>>

You're also missing unit tests in ovs-ofctl.at.

 index 323a58cbf..2aff48f5e 100644
 --- a/ofproto/ofproto-dpif-xlate.c
 +++ b/ofproto/ofproto-dpif-xlate.c
 @@ -5909,6 +5909,44 @@ xlate_fin_timeout(struct xlate_ctx *ctx,
  }
  }

 +static uint32_t
 +ofpact_sample_get_domain(struct xlate_ctx *ctx,
 + const struct ofpact_sample *os)
 +{
 +if (os->obs_domain_src.field) {
 +union mf_subvalue *value = xmalloc(sizeof *value);
>>>
>>> Would it be better to just put these 128 bytes on the stack to avoid
>>> memory fragmentation? Same for the next function.
>>>
>>> Or maybe something better, we could do something like we did for
>>> exact_match_mask?
>>>
>>>   const union mf_value exact_match_mask = MF_VALUE_EXACT_INITIALIZER;
>>>   extern const union mf_value exact_match_mask;
>>>
>>
>> A quick look seemed to indicate dynamic memory was preferred in this
>> module so I assumed there was a reason for it (I do remember stack size
>> being a problem at some point, not sure if it was here).
>>
>> I'll look at the exact_match_mask case.
> 
> I guess this function is not called recursively, so we should be ok with the 
> stack usage. But a const variable might be better (and we can fix the other 
> place(s) where you copied this code from ;).

While the function itself is not called recursively, the problem is
that it can be inlined into the main do_xlate_actions and cause
a significant stack usage increase even if the sampling is not used.
So, extra investigation on what is getting inlined with different
compilers and compiler flags is needed if we want to allocate it
on stack.

Best regards, Ilya Maximets.

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


Re: [ovs-dev] [PATCH v1 06/13] ofproto-dpif-xlate: Use psample for local sample.

2024-07-10 Thread Ilya Maximets
On 7/10/24 19:17, Adrián Moreno wrote:
> On Wed, Jul 10, 2024 at 06:52:30PM GMT, Ilya Maximets wrote:
>> On 7/10/24 15:25, Adrián Moreno wrote:
>>> On Wed, Jul 10, 2024 at 02:56:44PM GMT, Ilya Maximets wrote:
 On 7/7/24 22:08, Adrian Moreno wrote:
> Use the newly added psample action to implement OpenFlow sample() actions
> with local sampling configuration if possible.
>
> A bit of refactoring in compose_sample_actions arguments helps make it a
> bit more readable.
>
> Signed-off-by: Adrian Moreno 
> ---
>  ofproto/ofproto-dpif-lsample.c |  16 +++
>  ofproto/ofproto-dpif-lsample.h |   5 +
>  ofproto/ofproto-dpif-xlate.c   | 251 +++--
>  ofproto/ofproto-dpif-xlate.h   |   5 +-
>  ofproto/ofproto-dpif.c |   2 +-
>  tests/ofproto-dpif.at  | 146 +++
>  6 files changed, 345 insertions(+), 80 deletions(-)
>
> diff --git a/ofproto/ofproto-dpif-lsample.c 
> b/ofproto/ofproto-dpif-lsample.c
> index d675a116f..534ad96f0 100644
> --- a/ofproto/ofproto-dpif-lsample.c
> +++ b/ofproto/ofproto-dpif-lsample.c
> @@ -140,6 +140,22 @@ dpif_lsample_set_options(struct dpif_lsample 
> *lsample,
>  return changed;
>  }
>
> +/* Returns the group_id for a given collector_set_id, if it exists. */
> +bool
> +dpif_lsample_get_group_id(struct dpif_lsample *ps, uint32_t 
> collector_set_id,
> +  uint32_t *group_id)
> +{
> +struct lsample_exporter_node *node;
> +bool found = false;
> +
> +node = dpif_lsample_find_exporter_node(ps, collector_set_id);
> +if (node) {
> +found = true;
> +*group_id = node->exporter.options.group_id;
> +}
> +return found;
> +}
> +
>  struct dpif_lsample *
>  dpif_lsample_create(void)
>  {
> diff --git a/ofproto/ofproto-dpif-lsample.h 
> b/ofproto/ofproto-dpif-lsample.h
> index bee36c9c5..9c1026551 100644
> --- a/ofproto/ofproto-dpif-lsample.h
> +++ b/ofproto/ofproto-dpif-lsample.h
> @@ -18,6 +18,7 @@
>  #define OFPROTO_DPIF_LSAMPLE_H 1
>
>  #include 
> +#include 
>  #include 
>
>  struct dpif_lsample;
> @@ -33,4 +34,8 @@ bool dpif_lsample_set_options(struct dpif_lsample *,
>const struct ofproto_lsample_options *,
>size_t n_opts);
>
> +bool dpif_lsample_get_group_id(struct dpif_lsample *,
> +   uint32_t collector_set_id,
> +   uint32_t *group_id);
> +
>  #endif /* OFPROTO_DPIF_LSAMPLE_H */
> diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
> index 7c4950895..5e8113d5e 100644
> --- a/ofproto/ofproto-dpif-xlate.c
> +++ b/ofproto/ofproto-dpif-xlate.c
> @@ -47,6 +47,7 @@
>  #include "ofproto/ofproto-dpif-ipfix.h"
>  #include "ofproto/ofproto-dpif-mirror.h"
>  #include "ofproto/ofproto-dpif-monitor.h"
> +#include "ofproto/ofproto-dpif-lsample.h"
>  #include "ofproto/ofproto-dpif-sflow.h"
>  #include "ofproto/ofproto-dpif-trace.h"
>  #include "ofproto/ofproto-dpif-xlate-cache.h"
> @@ -117,6 +118,7 @@ struct xbridge {
>  struct dpif_sflow *sflow; /* SFlow handle, or null. */
>  struct dpif_ipfix *ipfix; /* Ipfix handle, or null. */
>  struct netflow *netflow;  /* Netflow handle, or null. */
> +struct dpif_lsample *lsample; /* Local sample handle, or null. */
>  struct stp *stp;  /* STP or null if disabled. */
>  struct rstp *rstp;/* RSTP or null if disabled. */
>
> @@ -686,6 +688,7 @@ static void xlate_xbridge_set(struct xbridge *, 
> struct dpif *,
>const struct mbridge *,
>const struct dpif_sflow *,
>const struct dpif_ipfix *,
> +  const struct dpif_lsample *,
>const struct netflow *,
>bool forward_bpdu, bool has_in_band,
>const struct dpif_backer_support *,
> @@ -1069,6 +1072,7 @@ xlate_xbridge_set(struct xbridge *xbridge,
>const struct mbridge *mbridge,
>const struct dpif_sflow *sflow,
>const struct dpif_ipfix *ipfix,
> +  const struct dpif_lsample *lsample,
>const struct netflow *netflow,
>bool forward_bpdu, bool has_in_band,
>const struct dpif_backer_support *support,
> @@ -1099,6 +1103,11 @@ xlate_xbridge_set(struct xbridge *xbridge,
>  xbridge->ipfix = dpif_ipfix_ref(ipfix);
>  }
>
> + 

[ovs-dev] [PATCH v6 ovn] northd: Add bfd, static_routes and route_policies nodes to I-P engine.

2024-07-10 Thread Lorenzo Bianconi
Introduce bfd, static_routes and route_policies nodes to northd I-P
engine to track bfd connections and northd static_route/policy_route
changes.

Acked-by: Numan Siddique 
Reported-at: https://issues.redhat.com/browse/FDP-600
Signed-off-by: Lorenzo Bianconi 
---
Changes since v5:
- remove bfd_mutex
Changes since v4:
- introduce bfd_nb_sync node and ger rid of bfd_consumer routine
Changes since v3:
- fix bfd_northd_change_handler logic
- fix route_policies_northd_change_handler logic
- fix static_routes_northd_change_handler logic
- add unit-tests
- cosmetics
Changes since v2:
- add incremental processing routines
- split bfd_consumer node in static_routes and route_policies nodes
Changes since v1:
- add incremental processing logic for bfd_consumer node to avoid a full
  recompute
---
 northd/en-lflow.c|  25 +-
 northd/en-northd.c   | 215 ++
 northd/en-northd.h   |  23 ++
 northd/inc-proc-northd.c |  37 ++-
 northd/northd.c  | 592 +++
 northd/northd.h  |  63 -
 tests/ovn-northd.at  |  56 
 7 files changed, 808 insertions(+), 203 deletions(-)

diff --git a/northd/en-lflow.c b/northd/en-lflow.c
index c4b927fb8..3dba5034b 100644
--- a/northd/en-lflow.c
+++ b/northd/en-lflow.c
@@ -41,6 +41,11 @@ lflow_get_input_data(struct engine_node *node,
  struct lflow_input *lflow_input)
 {
 struct northd_data *northd_data = engine_get_input_data("northd", node);
+struct bfd_data *bfd_data = engine_get_input_data("bfd", node);
+struct static_routes_data *static_routes_data =
+engine_get_input_data("static_routes", node);
+struct route_policies_data *route_policies_data =
+engine_get_input_data("route_policies", node);
 struct port_group_data *pg_data =
 engine_get_input_data("port_group", node);
 struct sync_meters_data *sync_meters_data =
@@ -50,10 +55,6 @@ lflow_get_input_data(struct engine_node *node,
 struct ed_type_ls_stateful *ls_stateful_data =
 engine_get_input_data("ls_stateful", node);
 
-lflow_input->nbrec_bfd_table =
-EN_OVSDB_GET(engine_get_input("NB_bfd", node));
-lflow_input->sbrec_bfd_table =
-EN_OVSDB_GET(engine_get_input("SB_bfd", node));
 lflow_input->sbrec_logical_flow_table =
 EN_OVSDB_GET(engine_get_input("SB_logical_flow", node));
 lflow_input->sbrec_multicast_group_table =
@@ -78,7 +79,10 @@ lflow_get_input_data(struct engine_node *node,
 lflow_input->meter_groups = _meters_data->meter_groups;
 lflow_input->lb_datapaths_map = _data->lb_datapaths_map;
 lflow_input->svc_monitor_map = _data->svc_monitor_map;
-lflow_input->bfd_connections = NULL;
+lflow_input->bfd_connections = _data->bfd_connections;
+lflow_input->parsed_routes = _routes_data->parsed_routes;
+lflow_input->route_tables = _routes_data->route_tables;
+lflow_input->route_policies = _policies_data->route_policies;
 
 struct ed_type_global_config *global_config =
 engine_get_input_data("global_config", node);
@@ -95,25 +99,14 @@ void en_lflow_run(struct engine_node *node, void *data)
 struct lflow_input lflow_input;
 lflow_get_input_data(node, _input);
 
-struct hmap bfd_connections = HMAP_INITIALIZER(_connections);
-lflow_input.bfd_connections = _connections;
-
 stopwatch_start(BUILD_LFLOWS_STOPWATCH_NAME, time_msec());
 
 struct lflow_data *lflow_data = data;
 lflow_table_clear(lflow_data->lflow_table);
 lflow_reset_northd_refs(_input);
 
-build_bfd_table(eng_ctx->ovnsb_idl_txn,
-lflow_input.nbrec_bfd_table,
-lflow_input.sbrec_bfd_table,
-lflow_input.lr_ports,
-_connections);
 build_lflows(eng_ctx->ovnsb_idl_txn, _input,
  lflow_data->lflow_table);
-bfd_cleanup_connections(lflow_input.nbrec_bfd_table,
-_connections);
-hmap_destroy(_connections);
 stopwatch_stop(BUILD_LFLOWS_STOPWATCH_NAME, time_msec());
 
 engine_set_node_state(node, EN_UPDATED);
diff --git a/northd/en-northd.c b/northd/en-northd.c
index 4479b4aff..7595c6f5f 100644
--- a/northd/en-northd.c
+++ b/northd/en-northd.c
@@ -236,6 +236,162 @@ northd_global_config_handler(struct engine_node *node, 
void *data OVS_UNUSED)
 return true;
 }
 
+bool
+route_policies_northd_change_handler(struct engine_node *node,
+ void *data OVS_UNUSED)
+{
+struct northd_data *northd_data = engine_get_input_data("northd", node);
+if (!northd_has_tracked_data(_data->trk_data)) {
+return false;
+}
+
+/* This node uses the below data from the en_northd engine node.
+ * See (lr_stateful_get_input_data())
+ *   1. northd_data->lr_datapaths
+ *  This data gets updated when a logical router is created or deleted.
+ *  northd engine node presently falls back to full recompute when
+ * 

Re: [ovs-dev] [PATCH v5 13/13] documentation: Document ovs-flowviz.

2024-07-10 Thread 0-day Robot
Bleep bloop.  Greetings Adrian Moreno, I am a robot and I have tried out your 
patch.
Thanks for your contribution.

I encountered some error that I wasn't expecting.  See the details below.


checkpatch:
WARNING: Line is 81 characters long (recommended limit is 79)
#550 FILE: Documentation/ref/ovs-flowviz.8.rst:468:
   [! | not ] {key}[[.subkey]...] [OPERATOR] {value})] [LOGICAL OPERATOR] 
...

WARNING: Line is 80 characters long (recommended limit is 79)
#564 FILE: Documentation/ref/ovs-flowviz.8.rst:482:
  To compare against a match or info field, use the field directly, e.g:

WARNING: Line is 80 characters long (recommended limit is 79)
#571 FILE: Documentation/ref/ovs-flowviz.8.rst:489:
  Actions values might be dictionaries, use subkeys to access individual

WARNING: Line is 110 characters long (recommended limit is 79)
#607 FILE: Documentation/ref/ovs-flowviz.8.rst:525:
$ ovs-flowviz -i flows.txt --style "light" --highlight "n_packets > 0 and 
drop" openflow html > flows.html

WARNING: Line is 141 characters long (recommended limit is 79)
#703 FILE: Documentation/topics/flow-visualization.rst:80:
  cookie=0xf76b4b20, duration=765.107s, table=0, n_packets=0, n_bytes=0, 
priority=180,vlan_tci=0x/0x1000 actions=conjunction(100,2/2)

WARNING: Line is 328 characters long (recommended limit is 79)
#704 FILE: Documentation/topics/flow-visualization.rst:81:
  cookie=0xf76b4b20, duration=765.107s, table=0, n_packets=0, n_bytes=0, 
priority=180,conj_id=100,in_port="patch-br-int-to",vlan_tci=0x/0x1000 
actions=load:0xa->NXM_NX_REG13[],load:0xc->NXM_NX_REG11[],load:0xb->NXM_NX_REG12[],load:0xb->OXM_OF_METADATA[],load:0x1->NXM_NX_REG14[],mod_dl_src:02:42:ac:12:00:03,resubmit(,8)

WARNING: Line is 286 characters long (recommended limit is 79)
#705 FILE: Documentation/topics/flow-visualization.rst:82:
  cookie=0x0, duration=765.388s, table=0, n_packets=0, n_bytes=0, 
priority=100,in_port="ovn-6bb3b3-0" 
actions=move:NXM_NX_TUN_ID[0..23]->OXM_OF_METADATA[0..23],move:NXM_NX_TUN_METADATA0[16..30]->NXM_NX_REG14[0..14],move:NXM_NX_TUN_METADATA0[0..15]->NXM_NX_REG15[0..15],resubmit(,40)

WARNING: Line is 286 characters long (recommended limit is 79)
#706 FILE: Documentation/topics/flow-visualization.rst:83:
  cookie=0x0, duration=765.388s, table=0, n_packets=0, n_bytes=0, 
priority=100,in_port="ovn-a6ff98-0" 
actions=move:NXM_NX_TUN_ID[0..23]->OXM_OF_METADATA[0..23],move:NXM_NX_TUN_METADATA0[16..30]->NXM_NX_REG14[0..14],move:NXM_NX_TUN_METADATA0[0..15]->NXM_NX_REG15[0..15],resubmit(,40)

WARNING: Line is 262 characters long (recommended limit is 79)
#707 FILE: Documentation/topics/flow-visualization.rst:84:
  cookie=0xf2ca6195, duration=765.107s, table=0, n_packets=6, n_bytes=636, 
priority=100,in_port="ovn-k8s-mp0" 
actions=load:0x1->NXM_NX_REG13[],load:0x2->NXM_NX_REG11[],load:0x7->NXM_NX_REG12[],load:0x4->OXM_OF_METADATA[],load:0x2->NXM_NX_REG14[],resubmit(,8)

WARNING: Line is 266 characters long (recommended limit is 79)
#708 FILE: Documentation/topics/flow-visualization.rst:85:
  cookie=0x236e941d, duration=408.874s, table=0, n_packets=11, n_bytes=846, 
priority=100,in_port=aceac9829941d11 
actions=load:0x11->NXM_NX_REG13[],load:0x2->NXM_NX_REG11[],load:0x7->NXM_NX_REG12[],load:0x4->OXM_OF_METADATA[],load:0x3->NXM_NX_REG14[],resubmit(,8)

WARNING: Line is 268 characters long (recommended limit is 79)
#709 FILE: Documentation/topics/flow-visualization.rst:86:
  cookie=0x3facf689, duration=405.581s, table=0, n_packets=11, n_bytes=846, 
priority=100,in_port="363ba22029cd92b" 
actions=load:0x12->NXM_NX_REG13[],load:0x2->NXM_NX_REG11[],load:0x7->NXM_NX_REG12[],load:0x4->OXM_OF_METADATA[],load:0x4->NXM_NX_REG14[],resubmit(,8)

WARNING: Line is 268 characters long (recommended limit is 79)
#710 FILE: Documentation/topics/flow-visualization.rst:87:
  cookie=0xe7c8c4bb, duration=405.570s, table=0, n_packets=11, n_bytes=846, 
priority=100,in_port="6a62cde0d50ef44" 
actions=load:0x13->NXM_NX_REG13[],load:0x2->NXM_NX_REG11[],load:0x7->NXM_NX_REG12[],load:0x4->OXM_OF_METADATA[],load:0x5->NXM_NX_REG14[],resubmit(,8)

WARNING: Line is 266 characters long (recommended limit is 79)
#711 FILE: Documentation/topics/flow-visualization.rst:88:
  cookie=0x99a0ffc1, duration=59.391s, table=0, n_packets=8, n_bytes=636, 
priority=100,in_port="5ff3bfaaa4eb622" 
actions=load:0x14->NXM_NX_REG13[],load:0x2->NXM_NX_REG11[],load:0x7->NXM_NX_REG12[],load:0x4->OXM_OF_METADATA[],load:0x6->NXM_NX_REG14[],resubmit(,8)

WARNING: Line is 266 characters long (recommended limit is 79)
#712 FILE: Documentation/topics/flow-visualization.rst:89:
  cookie=0xe1b5c263, duration=59.365s, table=0, n_packets=8, n_bytes=636, 
priority=100,in_port="8d9e0bc76347e59" 
actions=load:0x15->NXM_NX_REG13[],load:0x2->NXM_NX_REG11[],load:0x7->NXM_NX_REG12[],load:0x4->OXM_OF_METADATA[],load:0x7->NXM_NX_REG14[],resubmit(,8)

WARNING: Line is 123 characters long (recommended limit is 79)
#723 FILE: 

Re: [ovs-dev] [PATCH v1 06/13] ofproto-dpif-xlate: Use psample for local sample.

2024-07-10 Thread Adrián Moreno
On Wed, Jul 10, 2024 at 06:52:30PM GMT, Ilya Maximets wrote:
> On 7/10/24 15:25, Adrián Moreno wrote:
> > On Wed, Jul 10, 2024 at 02:56:44PM GMT, Ilya Maximets wrote:
> >> On 7/7/24 22:08, Adrian Moreno wrote:
> >>> Use the newly added psample action to implement OpenFlow sample() actions
> >>> with local sampling configuration if possible.
> >>>
> >>> A bit of refactoring in compose_sample_actions arguments helps make it a
> >>> bit more readable.
> >>>
> >>> Signed-off-by: Adrian Moreno 
> >>> ---
> >>>  ofproto/ofproto-dpif-lsample.c |  16 +++
> >>>  ofproto/ofproto-dpif-lsample.h |   5 +
> >>>  ofproto/ofproto-dpif-xlate.c   | 251 +++--
> >>>  ofproto/ofproto-dpif-xlate.h   |   5 +-
> >>>  ofproto/ofproto-dpif.c |   2 +-
> >>>  tests/ofproto-dpif.at  | 146 +++
> >>>  6 files changed, 345 insertions(+), 80 deletions(-)
> >>>
> >>> diff --git a/ofproto/ofproto-dpif-lsample.c 
> >>> b/ofproto/ofproto-dpif-lsample.c
> >>> index d675a116f..534ad96f0 100644
> >>> --- a/ofproto/ofproto-dpif-lsample.c
> >>> +++ b/ofproto/ofproto-dpif-lsample.c
> >>> @@ -140,6 +140,22 @@ dpif_lsample_set_options(struct dpif_lsample 
> >>> *lsample,
> >>>  return changed;
> >>>  }
> >>>
> >>> +/* Returns the group_id for a given collector_set_id, if it exists. */
> >>> +bool
> >>> +dpif_lsample_get_group_id(struct dpif_lsample *ps, uint32_t 
> >>> collector_set_id,
> >>> +  uint32_t *group_id)
> >>> +{
> >>> +struct lsample_exporter_node *node;
> >>> +bool found = false;
> >>> +
> >>> +node = dpif_lsample_find_exporter_node(ps, collector_set_id);
> >>> +if (node) {
> >>> +found = true;
> >>> +*group_id = node->exporter.options.group_id;
> >>> +}
> >>> +return found;
> >>> +}
> >>> +
> >>>  struct dpif_lsample *
> >>>  dpif_lsample_create(void)
> >>>  {
> >>> diff --git a/ofproto/ofproto-dpif-lsample.h 
> >>> b/ofproto/ofproto-dpif-lsample.h
> >>> index bee36c9c5..9c1026551 100644
> >>> --- a/ofproto/ofproto-dpif-lsample.h
> >>> +++ b/ofproto/ofproto-dpif-lsample.h
> >>> @@ -18,6 +18,7 @@
> >>>  #define OFPROTO_DPIF_LSAMPLE_H 1
> >>>
> >>>  #include 
> >>> +#include 
> >>>  #include 
> >>>
> >>>  struct dpif_lsample;
> >>> @@ -33,4 +34,8 @@ bool dpif_lsample_set_options(struct dpif_lsample *,
> >>>const struct ofproto_lsample_options *,
> >>>size_t n_opts);
> >>>
> >>> +bool dpif_lsample_get_group_id(struct dpif_lsample *,
> >>> +   uint32_t collector_set_id,
> >>> +   uint32_t *group_id);
> >>> +
> >>>  #endif /* OFPROTO_DPIF_LSAMPLE_H */
> >>> diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
> >>> index 7c4950895..5e8113d5e 100644
> >>> --- a/ofproto/ofproto-dpif-xlate.c
> >>> +++ b/ofproto/ofproto-dpif-xlate.c
> >>> @@ -47,6 +47,7 @@
> >>>  #include "ofproto/ofproto-dpif-ipfix.h"
> >>>  #include "ofproto/ofproto-dpif-mirror.h"
> >>>  #include "ofproto/ofproto-dpif-monitor.h"
> >>> +#include "ofproto/ofproto-dpif-lsample.h"
> >>>  #include "ofproto/ofproto-dpif-sflow.h"
> >>>  #include "ofproto/ofproto-dpif-trace.h"
> >>>  #include "ofproto/ofproto-dpif-xlate-cache.h"
> >>> @@ -117,6 +118,7 @@ struct xbridge {
> >>>  struct dpif_sflow *sflow; /* SFlow handle, or null. */
> >>>  struct dpif_ipfix *ipfix; /* Ipfix handle, or null. */
> >>>  struct netflow *netflow;  /* Netflow handle, or null. */
> >>> +struct dpif_lsample *lsample; /* Local sample handle, or null. */
> >>>  struct stp *stp;  /* STP or null if disabled. */
> >>>  struct rstp *rstp;/* RSTP or null if disabled. */
> >>>
> >>> @@ -686,6 +688,7 @@ static void xlate_xbridge_set(struct xbridge *, 
> >>> struct dpif *,
> >>>const struct mbridge *,
> >>>const struct dpif_sflow *,
> >>>const struct dpif_ipfix *,
> >>> +  const struct dpif_lsample *,
> >>>const struct netflow *,
> >>>bool forward_bpdu, bool has_in_band,
> >>>const struct dpif_backer_support *,
> >>> @@ -1069,6 +1072,7 @@ xlate_xbridge_set(struct xbridge *xbridge,
> >>>const struct mbridge *mbridge,
> >>>const struct dpif_sflow *sflow,
> >>>const struct dpif_ipfix *ipfix,
> >>> +  const struct dpif_lsample *lsample,
> >>>const struct netflow *netflow,
> >>>bool forward_bpdu, bool has_in_band,
> >>>const struct dpif_backer_support *support,
> >>> @@ -1099,6 +1103,11 @@ xlate_xbridge_set(struct xbridge *xbridge,
> >>>  xbridge->ipfix = dpif_ipfix_ref(ipfix);
> >>>  }
> >>>
> >>> +if (xbridge->lsample != lsample) {
> 

[ovs-dev] [PATCH v5 13/13] documentation: Document ovs-flowviz.

2024-07-10 Thread Adrian Moreno
Add a man page for ovs-flowviz as well as a topic page with some more
detailed examples.

Signed-off-by: Adrian Moreno 
---
 Documentation/automake.mk   |   4 +-
 Documentation/conf.py   |   2 +
 Documentation/ref/index.rst |   1 +
 Documentation/ref/ovs-flowviz.8.rst | 535 
 Documentation/topics/flow-visualization.rst | 314 
 Documentation/topics/index.rst  |   1 +
 rhel/openvswitch-fedora.spec.in |   1 +
 rhel/openvswitch.spec.in|   1 +
 8 files changed, 858 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/ref/ovs-flowviz.8.rst
 create mode 100644 Documentation/topics/flow-visualization.rst

diff --git a/Documentation/automake.mk b/Documentation/automake.mk
index 47d2e336a..539870aa2 100644
--- a/Documentation/automake.mk
+++ b/Documentation/automake.mk
@@ -45,7 +45,7 @@ DOC_SOURCE = \
Documentation/topics/fuzzing/ovs-fuzzing-infrastructure.rst \
Documentation/topics/fuzzing/ovs-fuzzers.rst \
Documentation/topics/fuzzing/security-analysis-of-ovs-fuzzers.rst \
-   Documentation/topics/testing.rst \
+   Documentation/topics/flow-visualization.rst \
Documentation/topics/integration.rst \
Documentation/topics/language-bindings.rst \
Documentation/topics/networking-namespaces.rst \
@@ -55,6 +55,7 @@ DOC_SOURCE = \
Documentation/topics/ovsdb-replication.rst \
Documentation/topics/porting.rst \
Documentation/topics/record-replay.rst \
+   Documentation/topics/testing.rst \
Documentation/topics/tracing.rst \
Documentation/topics/usdt-probes.rst \
Documentation/topics/userspace-checksum-offloading.rst \
@@ -162,6 +163,7 @@ RST_MANPAGES = \
ovs-actions.7.rst \
ovs-appctl.8.rst \
ovs-ctl.8.rst \
+   ovs-flowviz.8.rst \
ovs-l3ping.8.rst \
ovs-parse-backtrace.8.rst \
ovs-pki.8.rst \
diff --git a/Documentation/conf.py b/Documentation/conf.py
index 15785605a..3a82f23a7 100644
--- a/Documentation/conf.py
+++ b/Documentation/conf.py
@@ -120,6 +120,8 @@ _man_pages = [
  u'utility for configuring running Open vSwitch daemons'),
 ('ovs-ctl.8',
  u'OVS startup helper script'),
+('ovs-flowviz.8',
+ u'utility for visualizing OpenFlow and datapath flows'),
 ('ovs-l3ping.8',
  u'check network deployment for L3 tunneling problems'),
 ('ovs-parse-backtrace.8',
diff --git a/Documentation/ref/index.rst b/Documentation/ref/index.rst
index 03ada932f..7f2fe6177 100644
--- a/Documentation/ref/index.rst
+++ b/Documentation/ref/index.rst
@@ -42,6 +42,7 @@ time:
ovs-actions.7
ovs-appctl.8
ovs-ctl.8
+   ovs-flowviz.8
ovs-l3ping.8
ovs-pki.8
ovs-sim.1
diff --git a/Documentation/ref/ovs-flowviz.8.rst 
b/Documentation/ref/ovs-flowviz.8.rst
new file mode 100644
index 0..969fda9be
--- /dev/null
+++ b/Documentation/ref/ovs-flowviz.8.rst
@@ -0,0 +1,535 @@
+..
+  Licensed under the Apache License, Version 2.0 (the "License"); you may
+  not use this file except in compliance with the License. You may obtain
+  a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+  License for the specific language governing permissions and limitations
+  under the License.
+
+  Convention for heading levels in Open vSwitch documentation:
+
+  ===  Heading 0 (reserved for the title in a document)
+  ---  Heading 1
+  ~~~  Heading 2
+  +++  Heading 3
+  '''  Heading 4
+
+  Avoid deeper levels because they do not render well.
+
+===
+ovs-flowviz
+===
+
+Synopsis
+
+
+``ovs-flowviz``
+[``[-i | --input] <[alias,]file>``]
+[``[-c | --config] ``]
+[``[-f | --filter] ``]
+[``[-h | --highlight] ``]
+[``--style 

[ovs-dev] [PATCH v5 12/13] python: ovs: flowviz: Add datapath graph format.

2024-07-10 Thread Adrian Moreno
Graph view leverages the TreeFlow hierarchy and uses graphviz library to
build a visual graph of the datapath tree.

Conntrack zones are shown in random colors to help visualize connection
tracking interdependencies.

An html flag builds an HTML page with both the html flows and the graph
(in svg) that enables navegation.

Examples:
$ ovs-appctl dpctl/dump-flows -m | ovs-flowviz datapath graph | dot
-Tpng -o graph.png
$ ovs-appctl dpctl/dump-flows -m | ovs-flowviz datapath graph --html >
flows.html

Signed-off-by: Adrian Moreno 
---
 python/automake.mk  |   1 +
 python/ovs/flowviz/odp/cli.py   |  23 ++
 python/ovs/flowviz/odp/graph.py | 481 
 python/setup.py |   2 +-
 4 files changed, 506 insertions(+), 1 deletion(-)
 create mode 100644 python/ovs/flowviz/odp/graph.py

diff --git a/python/automake.mk b/python/automake.mk
index d534b52d9..b4521292f 100644
--- a/python/automake.mk
+++ b/python/automake.mk
@@ -71,6 +71,7 @@ ovs_flowviz = \
python/ovs/flowviz/main.py \
python/ovs/flowviz/odp/__init__.py \
python/ovs/flowviz/odp/cli.py \
+   python/ovs/flowviz/odp/graph.py \
python/ovs/flowviz/odp/html.py \
python/ovs/flowviz/odp/tree.py \
python/ovs/flowviz/ofp/__init__.py \
diff --git a/python/ovs/flowviz/odp/cli.py b/python/ovs/flowviz/odp/cli.py
index 73fadef95..294ab7636 100644
--- a/python/ovs/flowviz/odp/cli.py
+++ b/python/ovs/flowviz/odp/cli.py
@@ -15,6 +15,8 @@
 import click
 
 from ovs.flowviz.main import maincli
+
+from ovs.flowviz.odp.graph import GraphProcessor
 from ovs.flowviz.odp.html import HTMLTreeProcessor
 from ovs.flowviz.odp.tree import ConsoleTreeProcessor
 from ovs.flowviz.process import (
@@ -84,3 +86,24 @@ def html(opts):
 processor = HTMLTreeProcessor(opts)
 processor.process()
 processor.print()
+
+
+@datapath.command()
+@click.option(
+"-h",
+"--html",
+is_flag=True,
+default=False,
+show_default=True,
+help="Output an html file containing the graph",
+)
+@click.pass_obj
+def graph(opts, html):
+"""Print the flows in an graphviz (.dot) format showing the relationship
+of recirc_ids."""
+if len(opts.get("filename")) > 1:
+raise click.BadParameter("Graph format only supports one input file")
+
+processor = GraphProcessor(opts)
+processor.process()
+processor.print(html)
diff --git a/python/ovs/flowviz/odp/graph.py b/python/ovs/flowviz/odp/graph.py
new file mode 100644
index 0..c17580259
--- /dev/null
+++ b/python/ovs/flowviz/odp/graph.py
@@ -0,0 +1,481 @@
+# Copyright (c) 2023 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+""" Defines a Datapath Graph using graphviz. """
+import colorsys
+import graphviz
+import random
+
+from ovs.flowviz.odp.html import HTMLTree, HTMLFormatter
+from ovs.flowviz.odp.tree import FlowTree
+from ovs.flowviz.process import FileProcessor
+
+
+class GraphProcessor(FileProcessor):
+def __init__(self, opts):
+super().__init__(opts, "odp")
+
+def start_file(self, name, filename):
+self.tree = FlowTree()
+
+def start_thread(self, name):
+pass
+
+def stop_thread(self, name):
+pass
+
+def process_flow(self, flow, name):
+self.tree.add(flow, self.opts.get("filter"))
+
+def process(self):
+super().process(False)
+
+def print(self, html):
+self.tree.build()
+
+if len(self.tree.all_recirc_nodes) == 0:
+return
+
+dpg = DatapathGraph(self.tree, self.opts)
+if not html:
+print(dpg.source())
+return
+
+html_obj = ""
+html_obj += ""
+html_obj += HTMLTree.head()
+html_obj += ""
+
+html_obj += ""
+html_obj += HTMLTree.begin_body(self.opts)
+html_obj += " Flow Graph "
+html_obj += ""
+svg = dpg.pipe(format="svg")
+html_obj += svg.decode("utf-8")
+html_obj += ""
+html_tree = HTMLTree("graph", self.tree, self.opts)
+html_obj += html_tree.format()
+html_obj += HTMLTree.end_body()
+html_obj += ""
+html_obj += ""
+
+print(html_obj)
+
+
+class DatapathGraph:
+"""A DatapathGraph is a class that renders a set of datapath flows into
+graphviz graphs.
+
+Args:
+tree: FlowTree
+"""
+
+ct_styles = {}
+node_styles = {
+"default": {
+"style": {},
+   

[ovs-dev] [PATCH v5 08/13] python: ovs: flowviz: Add datapath tree format.

2024-07-10 Thread Adrian Moreno
Datapath flows can be arranged into a "tree"-like structure based on
recirculation ids and input ports.

A recirculation group is composed of flows sharing the same "recirc_id"
and "in_port" match. Within that group, flows are arranged in blocks of
flows that have the same action list. Finally, if an action associated
with one of this "blocks" contains a "recirc" action, the recirculation
group is shown underneath.

When filtering, instead of blindly dropping non-matching flows, drop all
the "subtrees" that don't have any matching flow.

Examples:
$ ovs-flowviz -i dpflows.txt --style dark datapath tree | less -R
$ ovs-flowviz -i dpflows.txt --filter "output.port=eth0" datapath tree

This patch adds the logic to build this structure in a format-agnostic
object called FlowTree and adds support for formatting it in the
console.

Console format supports:
- head-maps formatting of statistics
- hash-based pallete of recirculation ids: each recirculation id is
  assigned a unique color to easily follow the sequence of related
  actions.

Signed-off-by: Adrian Moreno 
---
 python/automake.mk |   1 +
 python/ovs/flow/kv.py  |   9 +
 python/ovs/flowviz/console.py  |  41 ++-
 python/ovs/flowviz/format.py   |  60 +++-
 python/ovs/flowviz/odp/cli.py  |  20 ++
 python/ovs/flowviz/odp/tree.py | 512 +
 6 files changed, 625 insertions(+), 18 deletions(-)
 create mode 100644 python/ovs/flowviz/odp/tree.py

diff --git a/python/automake.mk b/python/automake.mk
index 0487494d0..b3fef9bed 100644
--- a/python/automake.mk
+++ b/python/automake.mk
@@ -71,6 +71,7 @@ ovs_flowviz = \
python/ovs/flowviz/main.py \
python/ovs/flowviz/odp/__init__.py \
python/ovs/flowviz/odp/cli.py \
+   python/ovs/flowviz/odp/tree.py \
python/ovs/flowviz/ofp/__init__.py \
python/ovs/flowviz/ofp/cli.py \
python/ovs/flowviz/ofp/html.py \
diff --git a/python/ovs/flow/kv.py b/python/ovs/flow/kv.py
index f7d7be0cf..3afbf9fce 100644
--- a/python/ovs/flow/kv.py
+++ b/python/ovs/flow/kv.py
@@ -67,6 +67,15 @@ class KeyValue(object):
 def __repr__(self):
 return "{}('{}')".format(self.__class__.__name__, self)
 
+def __eq__(self, other):
+if isinstance(other, self.__class__):
+return self.key == other.key and self.value == other.value
+else:
+return False
+
+def __ne__(self, other):
+return not self.__eq__(other)
+
 
 class KVDecoders(object):
 """KVDecoders class is used by KVParser to select how to decode the value
diff --git a/python/ovs/flowviz/console.py b/python/ovs/flowviz/console.py
index c8a78ec11..ab91512fe 100644
--- a/python/ovs/flowviz/console.py
+++ b/python/ovs/flowviz/console.py
@@ -13,6 +13,8 @@
 # limitations under the License.
 
 import colorsys
+import itertools
+import zlib
 
 from rich.console import Console
 from rich.color import Color
@@ -79,6 +81,14 @@ class ConsoleBuffer(FlowBuffer):
 """
 return self._append(kv.meta.vstring, style)
 
+def append_value_omitted(self, kv):
+"""Append an omitted value.
+Args:
+kv (KeyValue): the KeyValue instance to append
+"""
+dots = "." * len(kv.meta.vstring)
+return self._append(dots, None)
+
 def append_extra(self, extra, style):
 """Append extra string.
 Args:
@@ -107,20 +117,21 @@ class ConsoleFormatter(FlowFormatter):
 def style_from_opts(self, opts):
 return self._style_from_opts(opts, "console", Style)
 
-def print_flow(self, flow, highlighted=None):
+def print_flow(self, flow, highlighted=None, omitted=None):
 """Prints a flow to the console.
 
 Args:
 flow (ovs_dbg.OFPFlow): the flow to print
 style (dict): Optional; style dictionary to use
 highlighted (list): Optional; list of KeyValues to highlight
+omitted (list): Optional; list of KeyValues to omit
 """
 
 buf = ConsoleBuffer(Text())
-self.format_flow(buf, flow, highlighted)
-self.console.print(buf.text)
+self.format_flow(buf, flow, highlighted, omitted)
+self.console.print(buf.text, soft_wrap=True)
 
-def format_flow(self, buf, flow, highlighted=None):
+def format_flow(self, buf, flow, highlighted=None, omitted=None):
 """Formats the flow into the provided buffer as a rich.Text.
 
 Args:
@@ -128,9 +139,10 @@ class ConsoleFormatter(FlowFormatter):
 flow (ovs_dbg.OFPFlow): the flow to format
 style (FlowStyle): Optional; style object to use
 highlighted (list): Optional; list of KeyValues to highlight
+omitted (list): Optional; list of KeyValues to omit
 """
 return super(ConsoleFormatter, self).format_flow(
-buf, flow, self.style, highlighted
+buf, flow, self.style, highlighted, omitted
 )
 
 
@@ -157,6 +169,25 @@ def 

[ovs-dev] [PATCH v5 07/13] python: ovs: flowviz: Add html formatting.

2024-07-10 Thread Adrian Moreno
Add a HTML Formatter and use it to print OpenFlow flows in an HTML list
with table links.

Examples
$ ovs-flowviz -i offlows.txt --highlight "drop" openflow html >
/tmp/flows.html
$ ovs-flowviz -i offlows.txt --filter "n_packets > 0" openflow html >
/tmp/flows.html

Both light and dark styles are supported.

Signed-off-by: Adrian Moreno 
---
 python/automake.mk  |   3 +-
 python/ovs/flowviz/html_format.py   | 138 
 python/ovs/flowviz/ofp/cli.py   |  10 ++
 python/ovs/flowviz/ofp/html.py  | 100 
 python/ovs/flowviz/ovs-flowviz.conf |  36 +++-
 5 files changed, 285 insertions(+), 2 deletions(-)
 create mode 100644 python/ovs/flowviz/html_format.py
 create mode 100644 python/ovs/flowviz/ofp/html.py

diff --git a/python/automake.mk b/python/automake.mk
index 23212e4b5..0487494d0 100644
--- a/python/automake.mk
+++ b/python/automake.mk
@@ -67,15 +67,16 @@ ovs_flowviz = \
python/ovs/flowviz/__init__.py \
python/ovs/flowviz/console.py \
python/ovs/flowviz/format.py \
+   python/ovs/flowviz/html_format.py \
python/ovs/flowviz/main.py \
python/ovs/flowviz/odp/__init__.py \
python/ovs/flowviz/odp/cli.py \
python/ovs/flowviz/ofp/__init__.py \
python/ovs/flowviz/ofp/cli.py \
+   python/ovs/flowviz/ofp/html.py \
python/ovs/flowviz/ovs-flowviz \
python/ovs/flowviz/process.py
 
-
 # These python files are used at build time but not runtime,
 # so they are not installed.
 EXTRA_DIST += \
diff --git a/python/ovs/flowviz/html_format.py 
b/python/ovs/flowviz/html_format.py
new file mode 100644
index 0..3f3550da5
--- /dev/null
+++ b/python/ovs/flowviz/html_format.py
@@ -0,0 +1,138 @@
+# Copyright (c) 2023 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from ovs.flowviz.format import FlowFormatter, FlowBuffer, FlowStyle
+
+
+class HTMLStyle:
+"""HTMLStyle defines a style for html-formatted flows.
+
+Args:
+color(str): Optional; a string representing the CSS color to use
+anchor_gen(callable): Optional; a callable to be used to generate the
+href
+"""
+
+def __init__(self, color=None, anchor_gen=None):
+self.color = color
+self.anchor_gen = anchor_gen
+
+
+class HTMLBuffer(FlowBuffer):
+"""HTMLBuffer implementes FlowBuffer to provide html-based flow formatting.
+
+Each flow gets formatted as:
+...
+"""
+
+def __init__(self):
+self._text = ""
+
+@property
+def text(self):
+return self._text
+
+def _append(self, string, color, href):
+"""Append a key a string"""
+style = ' style="color:{}"'.format(color) if color else ""
+self._text += "".format(style)
+if href:
+self._text += " ".format(
+href, 'style="color:{}"'.format(color) if color else ""
+)
+self._text += string
+if href:
+self._text += ""
+self._text += ""
+
+def append_key(self, kv, style):
+"""Append a key.
+Args:
+kv (KeyValue): the KeyValue instance to append
+style (HTMLStyle): the style to use
+"""
+href = style.anchor_gen(kv) if (style and style.anchor_gen) else ""
+return self._append(
+kv.meta.kstring, style.color if style else "", href
+)
+
+def append_delim(self, kv, style):
+"""Append a delimiter.
+Args:
+kv (KeyValue): the KeyValue instance to append
+style (HTMLStyle): the style to use
+"""
+href = style.anchor_gen(kv) if (style and style.anchor_gen) else ""
+return self._append(kv.meta.delim, style.color if style else "", href)
+
+def append_end_delim(self, kv, style):
+"""Append an end delimiter.
+Args:
+kv (KeyValue): the KeyValue instance to append
+style (HTMLStyle): the style to use
+"""
+href = style.anchor_gen(kv) if (style and style.anchor_gen) else ""
+return self._append(
+kv.meta.end_delim, style.color if style else "", href
+)
+
+def append_value(self, kv, style):
+"""Append a value.
+Args:
+kv (KeyValue): the KeyValue instance to append
+style (HTMLStyle): the style to use
+"""
+href = style.anchor_gen(kv) if (style and style.anchor_gen) else 

[ovs-dev] [PATCH v5 09/13] python: ovs: flowviz: Add OpenFlow logical view.

2024-07-10 Thread Adrian Moreno
This view is interesting for debugging the logical pipeline. It arranges
the flows in "logical" groups (not to be confused with OVN's
Logical_Flows). A logical group of flows is a set of flows that:
- Have the same table number and priority
- Match on the same fields (regardless of the value they match against)
- Have the same actions, regardless of the arguments for those actions,
  except for output and recirc, for which arguments do care.

Optionally, the cookie can also be force to be unique for the logical
group. By doing so, we can extend the information we show by querying an
external OVN database and running "ovn-detrace" on each cookie. The
result is a compact list of flow groups with interlieved OVN
information.

Furthermore, if connected to an OVN database, we can apply an OVN
regexp filter.

Examples:
$ ovs-ofctl dump-flows br-int | ovs-flowviz openflow logic
$ ovs-ofctl dump-flows br-int | ovs-flowviz openflow logic -s -h
$ export OVN_NB_DB=...
$ export OVN_SB_DB=...
$ ovs-ofctl dump-flows br-int | ovs-flowviz openflow logic -d
$ ovs-ofctl dump-flows br-int | ovs-flowviz openflow logic -d
--ovn-filter="acl.*icmp4"

Acked-by: Eelco Chaudron 
Signed-off-by: Adrian Moreno 
---
 python/automake.mk  |   1 +
 python/ovs/flowviz/ofp/cli.py   | 113 
 python/ovs/flowviz/ofp/logic.py | 303 
 3 files changed, 417 insertions(+)
 create mode 100644 python/ovs/flowviz/ofp/logic.py

diff --git a/python/automake.mk b/python/automake.mk
index b3fef9bed..9640b5886 100644
--- a/python/automake.mk
+++ b/python/automake.mk
@@ -74,6 +74,7 @@ ovs_flowviz = \
python/ovs/flowviz/odp/tree.py \
python/ovs/flowviz/ofp/__init__.py \
python/ovs/flowviz/ofp/cli.py \
+   python/ovs/flowviz/ofp/logic.py \
python/ovs/flowviz/ofp/html.py \
python/ovs/flowviz/ovs-flowviz \
python/ovs/flowviz/process.py
diff --git a/python/ovs/flowviz/ofp/cli.py b/python/ovs/flowviz/ofp/cli.py
index 28f3873b7..a0a94bd3b 100644
--- a/python/ovs/flowviz/ofp/cli.py
+++ b/python/ovs/flowviz/ofp/cli.py
@@ -12,10 +12,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import os
+
 import click
 
 from ovs.flowviz.main import maincli
 from ovs.flowviz.ofp.html import HTMLProcessor
+from ovs.flowviz.ofp.logic import LogicFlowProcessor
 from ovs.flowviz.process import (
 ConsoleProcessor,
 JSONOpenFlowProcessor,
@@ -59,6 +62,116 @@ def console(opts, heat_map):
 proc.print()
 
 
+def ovn_detrace_callback(ctx, param, value):
+"""click callback to add detrace information to config object and
+set general ovn-detrace flag to True
+"""
+ctx.obj[param.name] = value
+if value != param.default:
+ctx.obj["ovn_detrace_flag"] = True
+return value
+
+
+@openflow.command()
+@click.option(
+"-d",
+"--ovn-detrace",
+"ovn_detrace_flag",
+is_flag=True,
+show_default=True,
+help="Use ovn-detrace to extract cookie information (implies '-c')",
+)
+@click.option(
+"--ovn-detrace-path",
+default="/usr/bin",
+type=click.Path(),
+help="Use an alternative path to where ovn_detrace.py is located. "
+"Instead of using this option you can just set PYTHONPATH accordingly.",
+show_default=True,
+callback=ovn_detrace_callback,
+)
+@click.option(
+"--ovnnb-db",
+default=os.getenv("OVN_NB_DB") or "unix:/var/run/ovn/ovnnb_db.sock",
+help="Specify the OVN NB database string (implies -d). "
+"If the OVN_NB_DB environment variable is set, it's used as default. "
+"Otherwise, the default is unix:/var/run/ovn/ovnnb_db.sock",
+callback=ovn_detrace_callback,
+)
+@click.option(
+"--ovnsb-db",
+default=os.getenv("OVN_SB_DB") or "unix:/var/run/ovn/ovnsb_db.sock",
+help="Specify the OVN NB database string (implies -d). "
+"If the OVN_NB_DB environment variable is set, it's used as default. "
+"Otherwise, the default is unix:/var/run/ovn/ovnnb_db.sock",
+callback=ovn_detrace_callback,
+)
+@click.option(
+"-o",
+"--ovn-filter",
+help="Specify a filter to be run on ovn-detrace information (implied -d). "
+"Format: python regular expression "
+"(see https://docs.python.org/3/library/re.html)",
+callback=ovn_detrace_callback,
+)
+@click.option(
+"-s",
+"--show-flows",
+is_flag=True,
+default=False,
+show_default=True,
+help="Show the full flows under each logical flow",
+)
+@click.option(
+"-c",
+"--cookie",
+"cookie_flag",
+is_flag=True,
+default=False,
+show_default=True,
+help="Consider the cookie in the logical flow",
+)
+@click.option(
+"-h",
+"--heat-map",
+is_flag=True,
+default=False,
+show_default=True,
+help="Create heat-map with packet and byte counters (when -s is used)",
+)
+@click.pass_obj
+def logic(
+opts,
+ovn_detrace_flag,
+ovn_detrace_path,
+ovnnb_db,
+

[ovs-dev] [PATCH v5 05/13] python: ovs: flowviz: Add console formatting.

2024-07-10 Thread Adrian Moreno
Add a flow formatting framework and one implementation for console
printing using rich.

The flow formatting framework is a simple set of classes that can be
used to write different flow formatting implementations. It supports
styles to be described by any class, highlighting and config-file based
style definition.

The first flow formatting implementation is also introduced: the
ConsoleFormatter. It uses the an advanced rich-text printing library
[1].

The console printing supports:
- Heatmap: printing the packet/byte statistics of each flow in a color
  that represents its relative size: blue (low) -> red (high).
- Printing a banner with the file name and alias.
- Extensive style definition via config file.

This console format is added to both OpenFlow and Datapath flows.

Examples:
- Highlight drops in datapath flows:
$ ovs-flowviz -i flows.txt --highlight "drop" datapath console
- Quickly detect where most packets are going using heatmap and
  paginated output:
$ ovs-ofctl dump-flows br-int | ovs-flowviz openflow console -h

[1] https://rich.readthedocs.io/en/stable/introduction.html

Signed-off-by: Adrian Moreno 
---
 python/automake.mk|   2 +
 python/ovs/flowviz/console.py | 162 +++
 python/ovs/flowviz/format.py  | 371 ++
 python/ovs/flowviz/main.py|  58 +-
 python/ovs/flowviz/odp/cli.py |  24 ++-
 python/ovs/flowviz/ofp/cli.py |  26 ++-
 python/ovs/flowviz/process.py |  89 
 python/setup.py   |   4 +-
 8 files changed, 732 insertions(+), 4 deletions(-)
 create mode 100644 python/ovs/flowviz/console.py
 create mode 100644 python/ovs/flowviz/format.py

diff --git a/python/automake.mk b/python/automake.mk
index fd5e74081..bd53c5405 100644
--- a/python/automake.mk
+++ b/python/automake.mk
@@ -65,6 +65,8 @@ ovs_pytests = \
 
 ovs_flowviz = \
python/ovs/flowviz/__init__.py \
+   python/ovs/flowviz/console.py \
+   python/ovs/flowviz/format.py \
python/ovs/flowviz/main.py \
python/ovs/flowviz/odp/__init__.py \
python/ovs/flowviz/odp/cli.py \
diff --git a/python/ovs/flowviz/console.py b/python/ovs/flowviz/console.py
new file mode 100644
index 0..c8a78ec11
--- /dev/null
+++ b/python/ovs/flowviz/console.py
@@ -0,0 +1,162 @@
+# Copyright (c) 2023 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import colorsys
+
+from rich.console import Console
+from rich.color import Color
+from rich.text import Text
+from rich.style import Style
+
+from ovs.flowviz.format import FlowFormatter, FlowBuffer
+
+
+def file_header(name):
+return Text(f"### {name} ###")
+
+
+class ConsoleBuffer(FlowBuffer):
+"""ConsoleBuffer implements FlowBuffer to provide console-based text
+formatting based on rich.Text.
+
+Append functions accept a rich.Style.
+
+Args:
+rtext(rich.Text): Optional; text instance to reuse
+"""
+
+def __init__(self, rtext):
+self._text = rtext or Text()
+
+@property
+def text(self):
+return self._text
+
+def _append(self, string, style):
+"""Append to internal text."""
+return self._text.append(string, style)
+
+def append_key(self, kv, style):
+"""Append a key.
+Args:
+kv (KeyValue): the KeyValue instance to append
+style (rich.Style): the style to use
+"""
+return self._append(kv.meta.kstring, style)
+
+def append_delim(self, kv, style):
+"""Append a delimiter.
+Args:
+kv (KeyValue): the KeyValue instance to append
+style (rich.Style): the style to use
+"""
+return self._append(kv.meta.delim, style)
+
+def append_end_delim(self, kv, style):
+"""Append an end delimiter.
+Args:
+kv (KeyValue): the KeyValue instance to append
+style (rich.Style): the style to use
+"""
+return self._append(kv.meta.end_delim, style)
+
+def append_value(self, kv, style):
+"""Append a value.
+Args:
+kv (KeyValue): the KeyValue instance to append
+style (rich.Style): the style to use
+"""
+return self._append(kv.meta.vstring, style)
+
+def append_extra(self, extra, style):
+"""Append extra string.
+Args:
+kv (KeyValue): the KeyValue instance to append
+style (rich.Style): the style to use
+"""
+return 

[ovs-dev] [PATCH v5 04/13] python: ovs: flowviz: Add file processing infra.

2024-07-10 Thread Adrian Moreno
process.py contains a useful base class that processes files. Datapath
flow processing is pmd-thread-aware.

odp.py and ofp.py: contain datapath and openflow subcommand definitions
as well as the first formatting option: json.

Also, this patch adds basic filtering support.

Examples:
$ ovs-ofctl dump-flows br-int | ovs-flowviz openflow json
$ ovs-ofctl dump-flows br-int > flows.txt && ovs-flowviz -i flows.txt openflow 
json
$ ovs-ofctl appctl dpctl/dump-flows | ovs-flowviz -f 'ct' datapath json
$ ovs-ofctl appctl dpctl/dump-flows > flows.txt && ovs-flowviz -i flows.txt -f 
'drop' datapath json

Signed-off-by: Adrian Moreno 
---
 python/automake.mk |   5 +-
 python/ovs/flowviz/__init__.py |   2 +
 python/ovs/flowviz/main.py | 102 -
 python/ovs/flowviz/odp/cli.py  |  34 +
 python/ovs/flowviz/ofp/cli.py  |  34 +
 python/ovs/flowviz/process.py  | 255 +
 6 files changed, 430 insertions(+), 2 deletions(-)
 create mode 100644 python/ovs/flowviz/odp/cli.py
 create mode 100644 python/ovs/flowviz/ofp/cli.py
 create mode 100644 python/ovs/flowviz/process.py

diff --git a/python/automake.mk b/python/automake.mk
index 124032c92..fd5e74081 100644
--- a/python/automake.mk
+++ b/python/automake.mk
@@ -67,8 +67,11 @@ ovs_flowviz = \
python/ovs/flowviz/__init__.py \
python/ovs/flowviz/main.py \
python/ovs/flowviz/odp/__init__.py \
+   python/ovs/flowviz/odp/cli.py \
python/ovs/flowviz/ofp/__init__.py \
-   python/ovs/flowviz/ovs-flowviz
+   python/ovs/flowviz/ofp/cli.py \
+   python/ovs/flowviz/ovs-flowviz \
+   python/ovs/flowviz/process.py
 
 
 # These python files are used at build time but not runtime,
diff --git a/python/ovs/flowviz/__init__.py b/python/ovs/flowviz/__init__.py
index e69de29bb..898dba522 100644
--- a/python/ovs/flowviz/__init__.py
+++ b/python/ovs/flowviz/__init__.py
@@ -0,0 +1,2 @@
+import ovs.flowviz.ofp.cli  # noqa: F401
+import ovs.flowviz.odp.cli  # noqa: F401
diff --git a/python/ovs/flowviz/main.py b/python/ovs/flowviz/main.py
index f5bf142be..64b0e8a0a 100644
--- a/python/ovs/flowviz/main.py
+++ b/python/ovs/flowviz/main.py
@@ -13,17 +13,64 @@
 # limitations under the License.
 
 import click
+import os
+
+from ovs.flow.filter import OFFilter
 
 
 class Options(dict):
 """Options dictionary"""
 
 
+def validate_input(ctx, param, value):
+"""Validate the "-i" option"""
+result = list()
+for input_str in value:
+parts = input_str.strip().split(",")
+if len(parts) == 2:
+file_parts = tuple(parts)
+elif len(parts) == 1:
+file_parts = tuple(["Filename: " + parts[0], parts[0]])
+else:
+raise click.BadParameter(
+"input filename should have the following format: "
+"[alias,]FILENAME"
+)
+
+if not os.path.isfile(file_parts[1]):
+raise click.BadParameter(
+"input filename %s does not exist" % file_parts[1]
+)
+result.append(file_parts)
+return result
+
+
 @click.group(
 context_settings=dict(help_option_names=["-h", "--help"]),
 )
+@click.option(
+"-i",
+"--input",
+"filename",
+help="Read flows from specified filepath. If not provided, flows will be"
+" read from stdin. This option can be specified multiple times."
+" Format [alias,]FILENAME. Where alias is a name that shall be used to"
+" refer to this FILENAME",
+multiple=True,
+type=click.Path(),
+callback=validate_input,
+)
+@click.option(
+"-f",
+"--filter",
+help="Filter flows that match the filter expression."
+"Run 'ovs-flowviz filter' for a detailed description of the filtering "
+"syntax",
+type=str,
+show_default=False,
+)
 @click.pass_context
-def maincli(ctx):
+def maincli(ctx, filename, filter):
 """
 OpenvSwitch flow visualization utility.
 
@@ -31,6 +78,59 @@ def maincli(ctx):
 (such as the output of ovs-ofctl dump-flows or ovs-appctl dpctl/dump-flows)
 and prints them in different formats.
 """
+ctx.obj = Options()
+ctx.obj["filename"] = filename or None
+if filter:
+try:
+ctx.obj["filter"] = OFFilter(filter)
+except Exception as e:
+raise click.BadParameter("Wrong filter syntax: {}".format(e))
+
+
+@maincli.command(hidden=True)
+@click.pass_context
+def filter(ctx):
+"""
+\b
+Filter Syntax
+*
+
+ [! | not ] {key}[[.subkey]...] [OPERATOR] {value})] [LOGICAL OPERATOR] ...
+
+\b
+Comparison operators are:
+=   equality
+<   less than
+>   more than
+~=  masking (valid for IP and Ethernet fields)
+
+\b
+Logical operators are:
+!{expr}:  NOT
+{expr} && {expr}: AND
+{expr} || {expr}: OR
+
+\b
+Matches and flow metadata:
+To compare against a match or info field, use the field 

[ovs-dev] [PATCH v5 11/13] python: ovs: flowviz: Add datapath html format.

2024-07-10 Thread Adrian Moreno
Using the existing FlowTree and HTMLFormatter, create an HTML tree
visualization that also supports collapsing and expanding entire flow
subtrees.

Examples:
$ ovs-appcl dpctl/dump-flows | ovs-flowviz --highlight drop datapath
html > /tmp/flows.html
$ ovs-appcl dpctl/dump-flows | ovs-flowviz -f "output.port=3"
datapath html > /tmp/flows.html

Both light and dark styles are supported.

Signed-off-by: Adrian Moreno 
---
 python/automake.mk|   1 +
 python/ovs/flowviz/html_format.py |  13 +-
 python/ovs/flowviz/odp/cli.py |  10 +
 python/ovs/flowviz/odp/html.py| 337 ++
 4 files changed, 359 insertions(+), 2 deletions(-)
 create mode 100644 python/ovs/flowviz/odp/html.py

diff --git a/python/automake.mk b/python/automake.mk
index 9640b5886..d534b52d9 100644
--- a/python/automake.mk
+++ b/python/automake.mk
@@ -71,6 +71,7 @@ ovs_flowviz = \
python/ovs/flowviz/main.py \
python/ovs/flowviz/odp/__init__.py \
python/ovs/flowviz/odp/cli.py \
+   python/ovs/flowviz/odp/html.py \
python/ovs/flowviz/odp/tree.py \
python/ovs/flowviz/ofp/__init__.py \
python/ovs/flowviz/ofp/cli.py \
diff --git a/python/ovs/flowviz/html_format.py 
b/python/ovs/flowviz/html_format.py
index 3f3550da5..3293089e1 100644
--- a/python/ovs/flowviz/html_format.py
+++ b/python/ovs/flowviz/html_format.py
@@ -98,6 +98,14 @@ class HTMLBuffer(FlowBuffer):
 kv.meta.vstring, style.color if style else "", href
 )
 
+def append_value_omitted(self, kv):
+"""Append an omitted value.
+Args:
+kv (KeyValue): the KeyValue instance to append
+"""
+dots = "." * len(kv.meta.vstring)
+return self._append(dots, "", "")
+
 def append_extra(self, extra, style):
 """Append extra string.
 Args:
@@ -125,14 +133,15 @@ class HTMLFormatter(FlowFormatter):
 self._style_from_opts(opts, "html", HTMLStyle) or FlowStyle()
 )
 
-def format_flow(self, buf, flow, highlighted=None):
+def format_flow(self, buf, flow, highlighted=None, omitted=None):
 """Formats the flow into the provided buffer as a html object.
 
 Args:
 buf (FlowBuffer): the flow buffer to append to
 flow (ovs_dbg.OFPFlow): the flow to format
 highlighted (list): Optional; list of KeyValues to highlight
+omitted (list): Optional; list of KeyValues to omit
 """
 return super(HTMLFormatter, self).format_flow(
-buf, flow, self.style, highlighted
+buf, flow, self.style, highlighted, omitted
 )
diff --git a/python/ovs/flowviz/odp/cli.py b/python/ovs/flowviz/odp/cli.py
index 36f5b3db2..73fadef95 100644
--- a/python/ovs/flowviz/odp/cli.py
+++ b/python/ovs/flowviz/odp/cli.py
@@ -15,6 +15,7 @@
 import click
 
 from ovs.flowviz.main import maincli
+from ovs.flowviz.odp.html import HTMLTreeProcessor
 from ovs.flowviz.odp.tree import ConsoleTreeProcessor
 from ovs.flowviz.process import (
 ConsoleProcessor,
@@ -74,3 +75,12 @@ def tree(opts, heat_map):
 )
 processor.process()
 processor.print()
+
+
+@datapath.command()
+@click.pass_obj
+def html(opts):
+"""Print the flows in an HTML list sorted by recirc_id."""
+processor = HTMLTreeProcessor(opts)
+processor.process()
+processor.print()
diff --git a/python/ovs/flowviz/odp/html.py b/python/ovs/flowviz/odp/html.py
new file mode 100644
index 0..48a2c82d0
--- /dev/null
+++ b/python/ovs/flowviz/odp/html.py
@@ -0,0 +1,337 @@
+# Copyright (c) 2023 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from ovs.flowviz.html_format import HTMLBuffer, HTMLFormatter
+from ovs.flowviz.odp.tree import FlowTree
+from ovs.flowviz.process import FileProcessor
+
+
+class HTMLTree:
+"""Class capable of printing a FlowTree in HTML."""
+
+BODY_STYLE = """
+
+body {{
+background-color: {bg};
+color: {fg};
+}}
+"""
+
+STYLE = """
+
+.recirc {
+font-weight: bold;
+font-family: monospace;
+font-size: 1.1rem;
+border: 3px solid #ccc;
+width: fit-content;
+block-size: fit-content;
+}
+
+.block-matches {
+font-family: monospace;
+border: 1px solid #ccc;
+width: fit-content;
+block-size: fit-content;
+margin-left: 1em;
+padding: 4px;
+}
+
+.block-actions {
+

[ovs-dev] [PATCH v5 10/13] python: ovs: flowviz: Add Openflow cookie format.

2024-07-10 Thread Adrian Moreno
When anaylizing OVN issues, it might be useful to see what OpenFlow
flows were generated from each logical flow. In order to make it simpler
to visualize this, add a cookie format that simply sorts the flows first
by cookie, then by table.

Example:
$ export OVN_NB_DB=...
$ export OVN_SB_DB=...
$ ovs-vsctl dump-flows br-int | ovs-flowviz openflow cookie
--ovn-filter="acl.*icmp4"
$ ovs-vsctl dump-flows br-int | ovs-flowviz openflow cookie
--ovn-detrace

Acked-by: Eelco Chaudron 
Signed-off-by: Adrian Moreno 
---
 python/ovs/flowviz/ofp/cli.py   | 57 +-
 python/ovs/flowviz/ofp/logic.py | 61 +
 2 files changed, 117 insertions(+), 1 deletion(-)

diff --git a/python/ovs/flowviz/ofp/cli.py b/python/ovs/flowviz/ofp/cli.py
index a0a94bd3b..291384bd4 100644
--- a/python/ovs/flowviz/ofp/cli.py
+++ b/python/ovs/flowviz/ofp/cli.py
@@ -18,7 +18,7 @@ import click
 
 from ovs.flowviz.main import maincli
 from ovs.flowviz.ofp.html import HTMLProcessor
-from ovs.flowviz.ofp.logic import LogicFlowProcessor
+from ovs.flowviz.ofp.logic import CookieProcessor, LogicFlowProcessor
 from ovs.flowviz.process import (
 ConsoleProcessor,
 JSONOpenFlowProcessor,
@@ -172,6 +172,61 @@ def logic(
 processor.print(show_flows)
 
 
+@openflow.command()
+@click.option(
+"-d",
+"--ovn-detrace",
+"ovn_detrace_flag",
+is_flag=True,
+show_default=True,
+help="Use ovn-detrace to extract cookie information",
+)
+@click.option(
+"--ovn-detrace-path",
+default="/usr/bin",
+type=click.Path(),
+help="Use an alternative path to where ovn_detrace.py is located. "
+"Instead of using this option you can just set PYTHONPATH accordingly",
+show_default=True,
+callback=ovn_detrace_callback,
+)
+@click.option(
+"--ovnnb-db",
+default=os.getenv("OVN_NB_DB") or "unix:/var/run/ovn/ovnnb_db.sock",
+help="Specify the OVN NB database string (implies -d). "
+"If the OVN_NB_DB environment variable is set, it's used as default. "
+"Otherwise, the default is unix:/var/run/ovn/ovnnb_db.sock",
+callback=ovn_detrace_callback,
+)
+@click.option(
+"--ovnsb-db",
+default=os.getenv("OVN_SB_DB") or "unix:/var/run/ovn/ovnsb_db.sock",
+help="Specify the OVN NB database string (implies -d). "
+"If the OVN_NB_DB environment variable is set, it's used as default. "
+"Otherwise, the default is unix:/var/run/ovn/ovnnb_db.sock",
+callback=ovn_detrace_callback,
+)
+@click.option(
+"-o",
+"--ovn-filter",
+help="Specify a filter to be run on ovn-detrace information (implied -d). "
+"Format: python regular expression "
+"(see https://docs.python.org/3/library/re.html)",
+callback=ovn_detrace_callback,
+)
+@click.pass_obj
+def cookie(
+opts, ovn_detrace_flag, ovn_detrace_path, ovnnb_db, ovnsb_db, ovn_filter
+):
+"""Print the flow tables sorted by cookie."""
+if ovn_detrace_flag:
+opts["ovn_detrace_flag"] = True
+
+processor = CookieProcessor(opts)
+processor.process()
+processor.print()
+
+
 @openflow.command()
 @click.pass_obj
 def html(opts):
diff --git a/python/ovs/flowviz/ofp/logic.py b/python/ovs/flowviz/ofp/logic.py
index dd5c29c5a..db5c2e699 100644
--- a/python/ovs/flowviz/ofp/logic.py
+++ b/python/ovs/flowviz/ofp/logic.py
@@ -301,3 +301,64 @@ cookie_style_gen = hash_pallete(
 saturation=[0.5],
 value=[0.5 + x / 10 * (0.85 - 0.5) for x in range(0, 10)],
 )
+
+
+class CookieProcessor(FileProcessor):
+"""Processor that sorts flows into cookies and tables."""
+
+def __init__(self, opts):
+super().__init__(opts, "ofp")
+self.data = dict()
+self.ovn_detrace = (
+OVNDetrace(opts) if opts.get("ovn_detrace_flag") else None
+)
+
+def start_file(self, name, filename):
+self.cookies = dict()
+
+def stop_file(self, name, filename):
+self.data[name] = self.cookies
+
+def process_flow(self, flow, name):
+"""Sort the flows by table and logical flow."""
+cookie = flow.info.get("cookie") or 0
+if not self.cookies.get(cookie):
+self.cookies[cookie] = dict()
+
+table = flow.info.get("table") or 0
+if not self.cookies[cookie].get(table):
+self.cookies[cookie][table] = list()
+self.cookies[cookie][table].append(flow)
+
+def print(self):
+ofconsole = ConsoleFormatter(opts=self.opts)
+console = ofconsole.console
+for name, cookies in self.data.items():
+console.print("\n")
+console.print(file_header(name))
+tree = Tree("Ofproto Cookie Tree")
+
+for cookie, tables in cookies.items():
+ovn_info = None
+if self.ovn_detrace:
+ovn_info = self.ovn_detrace.get_ovn_info(cookie)
+if self.opts.get("ovn_filter"):
+ovn_regexp = 

[ovs-dev] [PATCH v5 06/13] python: ovs: flowviz: Add default config file.

2024-07-10 Thread Adrian Moreno
It has two basic styles defined: "dark" and "light" intended for
dark and light terminals.

Examples:
$ ovs-flowviz -i /tmp/dpflows --style=dark datapath console
$ ovs-flowviz -i /tmp/ofpflows --style=light openflow console

Acked-by: Eelco Chaudron 
Signed-off-by: Adrian Moreno 
---
 python/automake.mk  |  5 +-
 python/ovs/flowviz/ovs-flowviz.conf | 94 +
 python/setup.py |  1 +
 3 files changed, 99 insertions(+), 1 deletion(-)
 create mode 100644 python/ovs/flowviz/ovs-flowviz.conf

diff --git a/python/automake.mk b/python/automake.mk
index bd53c5405..23212e4b5 100644
--- a/python/automake.mk
+++ b/python/automake.mk
@@ -89,7 +89,8 @@ EXTRA_DIST += \
python/ovs/compat/sortedcontainers/LICENSE \
python/README.rst \
python/setup.py \
-   python/test_requirements.txt
+   python/test_requirements.txt \
+   python/ovs/flowviz/ovs-flowviz.conf
 
 # C extension support.
 EXTRA_DIST += python/ovs/_json.c
@@ -109,6 +110,8 @@ FLAKE8_PYFILES += \
python/setup.py
 
 nobase_pkgdata_DATA = $(ovs_pyfiles) $(ovstest_pyfiles) $(ovs_flowviz)
+nobase_pkgdata_DATA += python/ovs/flowviz/ovs-flowviz.conf
+
 ovs-install-data-local:
$(MKDIR_P) python/ovs
sed \
diff --git a/python/ovs/flowviz/ovs-flowviz.conf 
b/python/ovs/flowviz/ovs-flowviz.conf
new file mode 100644
index 0..3acd0a29e
--- /dev/null
+++ b/python/ovs/flowviz/ovs-flowviz.conf
@@ -0,0 +1,94 @@
+# Create any number of styles.{style_name} sections with a defined style.
+#
+# Syntax:
+#
+#  [FORMAT].[PORTION].[SELECTOR].[ELEMENT] = [VALUE]
+#
+#  * FORMAT: console
+#  * PORTION: The portion of the flow that the style applies to
+# - key: Selects how to print the key of a KeyValue pair
+# - key: Selects how to print the value of a KeyValue pair
+# - flag: Selects how to print the a flag
+# - delim: Selects how to print the delimiters around key and values
+#
+#  * SELECTOR:
+#- highlighted: to apply when the key is highlighted
+#- type.{TYPE}: to apply when the value matches a type
+#   (special types such as IPAddress or EthMask can be used)
+#   (only aplicable to 'value')
+#- {key_name}: to apply when the key matches the key_name
+#
+# Console Styles
+# ==
+#   * ELEMENT:
+# - color: defines the color in hex or a color rich starndard ones [1]
+# - underline: if set to "true", the selected portion will be underlined
+#
+#[1] https://rich.readthedocs.io/en/stable/appendix/colors.html#standard-colors
+
+[styles.dark]
+
+# defaults for key-values
+console.key.color = #5D86BA
+console.value.color= #B0C4DE
+console.delim.color= #B0C4DE
+console.default.color= #FF
+
+# defaults for special types
+console.value.type.IPAddress.color = #008700
+console.value.type.IPMask.color = #008700
+console.value.type.EthMask.color = #008700
+
+# dim some long arguments
+console.value.ct.color = grey66
+console.value.ufid.color = grey66
+console.value.clone.color = grey66
+console.value.controller.color = grey66
+
+# highlight flags
+console.flag.color = #875fff
+
+# show drop and recirculations
+console.key.drop.color = red
+console.key.resubmit.color = #00d700
+console.key.output.color = #00d700
+console.value.output.color = #00d700
+
+# highlights
+console.key.highlighted.color = red
+console.key.highlighted.underline = true
+console.value.highlighted.underline = true
+console.delim.highlighted.underline = true
+
+
+[styles.light]
+# If a color is omitted, the default terminal color will be used
+# highlight keys
+console.key.color = blue
+
+# special types
+console.value.type.IPAddress.color = #008700
+console.value.type.IPMask.color = #008700
+console.value.type.EthMask.color = #008700
+
+# dim long arguments
+console.value.ct.color = bright_black
+console.value.ufid.color = #87
+console.value.clone.color = bright_black
+console.value.controller.color = bright_black
+
+# highlight flags
+console.flag.color = #5F
+
+# show drop and recirculations
+console.key.drop.color = red
+console.key.resubmit.color = #00d700
+console.key.output.color = #005f00
+console.value.output.color = #00d700
+
+# highlights
+console.key.highlighted.color = #f20905
+console.value.highlighted.color = #f20905
+console.key.highlighted.underline = true
+console.value.highlighted.underline = true
+console.delim.highlighted.underline = true
diff --git a/python/setup.py b/python/setup.py
index 76f9fc820..c734f68f3 100644
--- a/python/setup.py
+++ b/python/setup.py
@@ -117,6 +117,7 @@ setup_args = dict(
 [*flow_extras_require, 'click', 'rich'],
 },
 scripts=["ovs/flowviz/ovs-flowviz"],
+data_files=["ovs/flowviz/ovs-flowviz.conf"],
 include_package_data=True,
 )
 
-- 
2.45.2

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


[ovs-dev] [PATCH v5 03/13] python: ovs: Add flowviz scheleton.

2024-07-10 Thread Adrian Moreno
Add a new python package (just the scheleton for now) to hold a flow
visualization tool based on the flow parsing library.

flowviz dependencies are installed via "extras_require", so a user must
run:

$ pip install .[flowviz]
or
$ pip install ovs[flowviz]

Acked-by: Eelco Chaudron 
Signed-off-by: Adrian Moreno 
---
 python/automake.mk | 14 ---
 python/ovs/flowviz/__init__.py |  0
 python/ovs/flowviz/main.py | 40 ++
 python/ovs/flowviz/odp/__init__.py |  0
 python/ovs/flowviz/ofp/__init__.py |  0
 python/ovs/flowviz/ovs-flowviz | 20 +++
 python/setup.py| 11 +---
 7 files changed, 79 insertions(+), 6 deletions(-)
 create mode 100644 python/ovs/flowviz/__init__.py
 create mode 100644 python/ovs/flowviz/main.py
 create mode 100644 python/ovs/flowviz/odp/__init__.py
 create mode 100644 python/ovs/flowviz/ofp/__init__.py
 create mode 100755 python/ovs/flowviz/ovs-flowviz

diff --git a/python/automake.mk b/python/automake.mk
index 84cf2eab5..124032c92 100644
--- a/python/automake.mk
+++ b/python/automake.mk
@@ -63,6 +63,14 @@ ovs_pytests = \
python/ovs/tests/test_odp.py \
python/ovs/tests/test_ofp.py
 
+ovs_flowviz = \
+   python/ovs/flowviz/__init__.py \
+   python/ovs/flowviz/main.py \
+   python/ovs/flowviz/odp/__init__.py \
+   python/ovs/flowviz/ofp/__init__.py \
+   python/ovs/flowviz/ovs-flowviz
+
+
 # These python files are used at build time but not runtime,
 # so they are not installed.
 EXTRA_DIST += \
@@ -81,10 +89,10 @@ EXTRA_DIST += \
 # C extension support.
 EXTRA_DIST += python/ovs/_json.c
 
-PYFILES = $(ovs_pyfiles) python/ovs/dirs.py $(ovstest_pyfiles) $(ovs_pytests)
+PYFILES = $(ovs_pyfiles) python/ovs/dirs.py $(ovstest_pyfiles) $(ovs_pytests) 
$(ovs_flowviz)
 
 EXTRA_DIST += $(PYFILES)
-PYCOV_CLEAN_FILES += $(PYFILES:.py=.py,cover)
+PYCOV_CLEAN_FILES += $($(filter %.py, PYFILES):.py=.py,cover) 
python/ovs/flowviz/ovs-flowviz,cover
 
 FLAKE8_PYFILES += \
$(filter-out python/ovs/compat/% python/ovs/dirs.py,$(PYFILES)) \
@@ -95,7 +103,7 @@ FLAKE8_PYFILES += \
python/ovs/dirs.py.template \
python/setup.py
 
-nobase_pkgdata_DATA = $(ovs_pyfiles) $(ovstest_pyfiles)
+nobase_pkgdata_DATA = $(ovs_pyfiles) $(ovstest_pyfiles) $(ovs_flowviz)
 ovs-install-data-local:
$(MKDIR_P) python/ovs
sed \
diff --git a/python/ovs/flowviz/__init__.py b/python/ovs/flowviz/__init__.py
new file mode 100644
index 0..e69de29bb
diff --git a/python/ovs/flowviz/main.py b/python/ovs/flowviz/main.py
new file mode 100644
index 0..f5bf142be
--- /dev/null
+++ b/python/ovs/flowviz/main.py
@@ -0,0 +1,40 @@
+# Copyright (c) 2023 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import click
+
+
+class Options(dict):
+"""Options dictionary"""
+
+
+@click.group(
+context_settings=dict(help_option_names=["-h", "--help"]),
+)
+@click.pass_context
+def maincli(ctx):
+"""
+OpenvSwitch flow visualization utility.
+
+It reads openflow and datapath flows
+(such as the output of ovs-ofctl dump-flows or ovs-appctl dpctl/dump-flows)
+and prints them in different formats.
+"""
+
+
+def main():
+"""
+Main Function
+"""
+maincli()
diff --git a/python/ovs/flowviz/odp/__init__.py 
b/python/ovs/flowviz/odp/__init__.py
new file mode 100644
index 0..e69de29bb
diff --git a/python/ovs/flowviz/ofp/__init__.py 
b/python/ovs/flowviz/ofp/__init__.py
new file mode 100644
index 0..e69de29bb
diff --git a/python/ovs/flowviz/ovs-flowviz b/python/ovs/flowviz/ovs-flowviz
new file mode 100755
index 0..9d0959812
--- /dev/null
+++ b/python/ovs/flowviz/ovs-flowviz
@@ -0,0 +1,20 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2022,2023 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from ovs.flowviz import main
+
+if __name__ == '__main__':
+main.main()
diff --git 

[ovs-dev] [PATCH v5 01/13] python: ovs: flow: Support dp-extra-info section.

2024-07-10 Thread Adrian Moreno
DPDK flows can have this extra section that, for now, only has one
possible key (miniflow_bits). Add it to the ODPFlow flow.

Signed-off-by: Adrian Moreno 
---
 python/ovs/flow/odp.py | 23 ++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/python/ovs/flow/odp.py b/python/ovs/flow/odp.py
index a8f8c067a..d5faff03e 100644
--- a/python/ovs/flow/odp.py
+++ b/python/ovs/flow/odp.py
@@ -119,7 +119,15 @@ class ODPFlow(Flow):
 ]
 
 action_pos += 8  # len("actions:")
-actions = odp_string[action_pos:]
+
+dp_extra_pos = odp_string[action_pos:].find("dp-extra-info")
+if dp_extra_pos > 0:
+dp_extra_pos += action_pos
+actions = odp_string[action_pos : dp_extra_pos]
+dp_extra_pos += 14  # len("dp-extra-info:")
+dp_extra = odp_string[dp_extra_pos :]
+else:
+actions = odp_string[action_pos:]
 
 field_parts = rest.lstrip(" ").partition(" ")
 
@@ -160,6 +168,19 @@ class ODPFlow(Flow):
 )
 sections.append(asection)
 
+if dp_extra_pos > 0:
+dparser = KVParser(
+dp_extra, KVDecoders({"miniflow_bits": decode_default})
+)
+dparser.parse()
+dsection = Section(
+name="dp_extra_info",
+pos=dp_extra_pos,
+string=dp_extra,
+data=dparser.kv(),
+)
+sections.append(dsection)
+
 super(ODPFlow, self).__init__(sections, odp_string, id)
 
 def __str__(self):
-- 
2.45.2

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


[ovs-dev] [PATCH v5 00/13] Add flow visualization utility.

2024-07-10 Thread Adrian Moreno
The goal of this utility is to read both datapath and Openflow flows
(using the flow library already available) and print them in different
formats and styles to make it easier to understand them and troubleshoot
issues.

The formats are quite opinionated and so are the colors chosen so I'm
eager to hear what is the impression caused to the community.

Here is a summary of the formats and features supported:

- Openflow
   - Console: Prints flows back to the console allowing filtering and
 extensive formatting.
   - Cookie: Arranges flows based on cookie (instead of table) to ease
 visualization of OVN-generated flows.
   - HTML: Prints an HTML file that shows the flows arranged by tables.
 resubmit actions have a hyperlinke to the target table to ease
 navegation.
   - Logic: Many times OVN generates many "logically-equivalent" flows.
 These are flows that have the same structure: match on the same
 values and have the same actions. The only thing that changes is
 the actual value they match against and maybe the arguments of the
 actions. This format collapses these flows so you can visualize the
 logical pipeline easier.
   - JSON: JSON format.

More OpenFlow features:
   - OVN metadata: Both the "cookie" and the "logic" format allow to
 connect to a running OVN NB/SB databases and enrich the flows with
 OVN context based on the flow's cookie.

- Datapath:
   - Console: Prints flows back to the console allowing filtering and
 extensive formatting.
   - Tree: Datapath flows use recirculation to further execute
 additional actions. This format builds a tree of flows following
 the recirculation identifiers and prints it in the console.
   - HTML: Prints the datapath flow tree in HTML. It includes some
 minimal JS to support expanding and collapsing of entire branches.
   - Graph: Following the "tree" format, this one prints the tree in
 graphviz format. 
   - JSON: JSON format.

Additional datapath features:
   - Many datapath formats are based on the tree flow hierarchy. An
 interesting feature of this structure is that filtering is done at
 the branch level. This means that when a flow satisfies the filter,
 the entire sub-tree leading to that flow is shown.

Additional common features:
   - Styling: Styles for both console and HTML formats can be defined
 using a configuration file.
   - Heat maps: Some formats support heat-maps. A color pallete ranging
 from blue (cold) to red (hot) is used to print the number of
 packets and bytes of the flows. That way, the flows that are
 handling more traffic are much easier to spot

--
V4 -> V5:
 - Reworked datapath formats to display flows per pmd-thread if possible
 - Reworked datapath tree format to:
- combine flows with the same action together
- include in_port in recirculation block so we don't show
  impossible-to-match flows
- Removed "rich" banners in console outputs.
- Add a couple of missing datapath flow fields.
- Squash the dark html format into patch 6/13.

V3 -> V4:
 - Add manpage to rpm package
 - Fix Eelco's comments
V2 -> V3:
 - Fix grammar thanks to Eelco's review
V1 -> V2:
 - Fix typos and nits on documentation
 - Split documentation in two: ovs-flowviz.8 man page and a topic
   article with more detailed examples.
RFC -> V1:
 - Addressed Eelco's comments
 - Added a documentation page
 - Added support for dark style HTML pages
 - Patch 3. Small fix in the way a style is looked up. Use the key in
   the KV instead of the metadata string. This helps with "free" values
   such as "output".
*** BLURB HERE ***

Adrian Moreno (13):
  python: ovs: flow: Support dp-extra-info section.
  python: ovs: flow: Add offloaded key to odp flow.
  python: ovs: Add flowviz scheleton.
  python: ovs: flowviz: Add file processing infra.
  python: ovs: flowviz: Add console formatting.
  python: ovs: flowviz: Add default config file.
  python: ovs: flowviz: Add html formatting.
  python: ovs: flowviz: Add datapath tree format.
  python: ovs: flowviz: Add OpenFlow logical view.
  python: ovs: flowviz: Add Openflow cookie format.
  python: ovs: flowviz: Add datapath html format.
  python: ovs: flowviz: Add datapath graph format.
  documentation: Document ovs-flowviz.

 Documentation/automake.mk   |   4 +-
 Documentation/conf.py   |   2 +
 Documentation/ref/index.rst |   1 +
 Documentation/ref/ovs-flowviz.8.rst | 535 
 Documentation/topics/flow-visualization.rst | 314 
 Documentation/topics/index.rst  |   1 +
 python/automake.mk  |  29 +-
 python/ovs/flow/kv.py   |   9 +
 python/ovs/flow/odp.py  |  24 +-
 python/ovs/flowviz/__init__.py  |   2 +
 python/ovs/flowviz/console.py   | 193 +++
 python/ovs/flowviz/format.py| 405 +++
 

[ovs-dev] [PATCH v5 02/13] python: ovs: flow: Add offloaded key to odp flow.

2024-07-10 Thread Adrian Moreno
Add "offloaded" key in the info section of datapath flow.

Signed-off-by: Adrian Moreno 
---
 python/ovs/flow/odp.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/python/ovs/flow/odp.py b/python/ovs/flow/odp.py
index d5faff03e..f51154513 100644
--- a/python/ovs/flow/odp.py
+++ b/python/ovs/flow/odp.py
@@ -211,6 +211,7 @@ class ODPFlow(Flow):
 "used": decode_time,
 "flags": decode_default,
 "dp": decode_default,
+"offloaded": decode_default,
 }
 
 @staticmethod
-- 
2.45.2

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


Re: [ovs-dev] [PATCH v1 06/13] ofproto-dpif-xlate: Use psample for local sample.

2024-07-10 Thread Ilya Maximets
On 7/10/24 15:25, Adrián Moreno wrote:
> On Wed, Jul 10, 2024 at 02:56:44PM GMT, Ilya Maximets wrote:
>> On 7/7/24 22:08, Adrian Moreno wrote:
>>> Use the newly added psample action to implement OpenFlow sample() actions
>>> with local sampling configuration if possible.
>>>
>>> A bit of refactoring in compose_sample_actions arguments helps make it a
>>> bit more readable.
>>>
>>> Signed-off-by: Adrian Moreno 
>>> ---
>>>  ofproto/ofproto-dpif-lsample.c |  16 +++
>>>  ofproto/ofproto-dpif-lsample.h |   5 +
>>>  ofproto/ofproto-dpif-xlate.c   | 251 +++--
>>>  ofproto/ofproto-dpif-xlate.h   |   5 +-
>>>  ofproto/ofproto-dpif.c |   2 +-
>>>  tests/ofproto-dpif.at  | 146 +++
>>>  6 files changed, 345 insertions(+), 80 deletions(-)
>>>
>>> diff --git a/ofproto/ofproto-dpif-lsample.c b/ofproto/ofproto-dpif-lsample.c
>>> index d675a116f..534ad96f0 100644
>>> --- a/ofproto/ofproto-dpif-lsample.c
>>> +++ b/ofproto/ofproto-dpif-lsample.c
>>> @@ -140,6 +140,22 @@ dpif_lsample_set_options(struct dpif_lsample *lsample,
>>>  return changed;
>>>  }
>>>
>>> +/* Returns the group_id for a given collector_set_id, if it exists. */
>>> +bool
>>> +dpif_lsample_get_group_id(struct dpif_lsample *ps, uint32_t 
>>> collector_set_id,
>>> +  uint32_t *group_id)
>>> +{
>>> +struct lsample_exporter_node *node;
>>> +bool found = false;
>>> +
>>> +node = dpif_lsample_find_exporter_node(ps, collector_set_id);
>>> +if (node) {
>>> +found = true;
>>> +*group_id = node->exporter.options.group_id;
>>> +}
>>> +return found;
>>> +}
>>> +
>>>  struct dpif_lsample *
>>>  dpif_lsample_create(void)
>>>  {
>>> diff --git a/ofproto/ofproto-dpif-lsample.h b/ofproto/ofproto-dpif-lsample.h
>>> index bee36c9c5..9c1026551 100644
>>> --- a/ofproto/ofproto-dpif-lsample.h
>>> +++ b/ofproto/ofproto-dpif-lsample.h
>>> @@ -18,6 +18,7 @@
>>>  #define OFPROTO_DPIF_LSAMPLE_H 1
>>>
>>>  #include 
>>> +#include 
>>>  #include 
>>>
>>>  struct dpif_lsample;
>>> @@ -33,4 +34,8 @@ bool dpif_lsample_set_options(struct dpif_lsample *,
>>>const struct ofproto_lsample_options *,
>>>size_t n_opts);
>>>
>>> +bool dpif_lsample_get_group_id(struct dpif_lsample *,
>>> +   uint32_t collector_set_id,
>>> +   uint32_t *group_id);
>>> +
>>>  #endif /* OFPROTO_DPIF_LSAMPLE_H */
>>> diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
>>> index 7c4950895..5e8113d5e 100644
>>> --- a/ofproto/ofproto-dpif-xlate.c
>>> +++ b/ofproto/ofproto-dpif-xlate.c
>>> @@ -47,6 +47,7 @@
>>>  #include "ofproto/ofproto-dpif-ipfix.h"
>>>  #include "ofproto/ofproto-dpif-mirror.h"
>>>  #include "ofproto/ofproto-dpif-monitor.h"
>>> +#include "ofproto/ofproto-dpif-lsample.h"
>>>  #include "ofproto/ofproto-dpif-sflow.h"
>>>  #include "ofproto/ofproto-dpif-trace.h"
>>>  #include "ofproto/ofproto-dpif-xlate-cache.h"
>>> @@ -117,6 +118,7 @@ struct xbridge {
>>>  struct dpif_sflow *sflow; /* SFlow handle, or null. */
>>>  struct dpif_ipfix *ipfix; /* Ipfix handle, or null. */
>>>  struct netflow *netflow;  /* Netflow handle, or null. */
>>> +struct dpif_lsample *lsample; /* Local sample handle, or null. */
>>>  struct stp *stp;  /* STP or null if disabled. */
>>>  struct rstp *rstp;/* RSTP or null if disabled. */
>>>
>>> @@ -686,6 +688,7 @@ static void xlate_xbridge_set(struct xbridge *, struct 
>>> dpif *,
>>>const struct mbridge *,
>>>const struct dpif_sflow *,
>>>const struct dpif_ipfix *,
>>> +  const struct dpif_lsample *,
>>>const struct netflow *,
>>>bool forward_bpdu, bool has_in_band,
>>>const struct dpif_backer_support *,
>>> @@ -1069,6 +1072,7 @@ xlate_xbridge_set(struct xbridge *xbridge,
>>>const struct mbridge *mbridge,
>>>const struct dpif_sflow *sflow,
>>>const struct dpif_ipfix *ipfix,
>>> +  const struct dpif_lsample *lsample,
>>>const struct netflow *netflow,
>>>bool forward_bpdu, bool has_in_band,
>>>const struct dpif_backer_support *support,
>>> @@ -1099,6 +1103,11 @@ xlate_xbridge_set(struct xbridge *xbridge,
>>>  xbridge->ipfix = dpif_ipfix_ref(ipfix);
>>>  }
>>>
>>> +if (xbridge->lsample != lsample) {
>>> +dpif_lsample_unref(xbridge->lsample);
>>> +xbridge->lsample = dpif_lsample_ref(lsample);
>>> +}
>>> +
>>>  if (xbridge->stp != stp) {
>>>  stp_unref(xbridge->stp);
>>>  xbridge->stp = stp_ref(stp);
>>> @@ -1213,9 +1222,10 @@ xlate_xbridge_copy(struct xbridge 

Re: [ovs-dev] [PATCH v1 08/13] ofproto-dpif-lsample: Show stats via unixctl.

2024-07-10 Thread Ilya Maximets
On 7/10/24 18:30, Adrián Moreno wrote:
> On Wed, Jul 10, 2024 at 04:28:55PM GMT, Eelco Chaudron wrote:
>>
>>
>> On 10 Jul 2024, at 15:06, Ilya Maximets wrote:
>>
>>> On 7/7/24 22:09, Adrian Moreno wrote:
 Add a command to dump statistics per exporter.

 Signed-off-by: Adrian Moreno 
 ---
  NEWS   |   2 +
  ofproto/ofproto-dpif-lsample.c | 111 +
  ofproto/ofproto-dpif-lsample.h |   1 +
  ofproto/ofproto-dpif.c |   1 +
  4 files changed, 115 insertions(+)

 diff --git a/NEWS b/NEWS
 index 15faf9fc3..1c53badea 100644
 --- a/NEWS
 +++ b/NEWS
 @@ -20,6 +20,8 @@ Post-v3.3.0
   allows samples to be emitted locally (instead of via IPFIX) in a
   datapath-specific manner. The Linux kernel datapath is the first to
   support this feature by using the new datapath "psample" action.
 + A new unixctl command 'lsample/show' shows packet and bytes 
 statistics
 + per local sample exporter.
>>>
>>> Maybe add this as a separate bullet point.
>>>


  v3.3.0 - 16 Feb 2024
 diff --git a/ofproto/ofproto-dpif-lsample.c 
 b/ofproto/ofproto-dpif-lsample.c
 index 171129d5b..82a87c27d 100644
 --- a/ofproto/ofproto-dpif-lsample.c
 +++ b/ofproto/ofproto-dpif-lsample.c
 @@ -21,7 +21,10 @@
  #include "dpif.h"
  #include "hash.h"
  #include "ofproto.h"
 +#include "ofproto-dpif.h"
 +#include "openvswitch/dynamic-string.h"
  #include "openvswitch/thread.h"
 +#include "unixctl.h"

  /* Dpif local sampling.
   *
 @@ -219,3 +222,111 @@ dpif_lsample_unref(struct dpif_lsample *lsample)
  dpif_lsample_destroy(lsample);
  }
  }
 +
 +static int
 +comp_exporter_collector_id(const void *a_, const void *b_)
 +{
 +const struct lsample_exporter_node *a, *b;
 +
 +a = *(struct lsample_exporter_node **) a_;
 +b = *(struct lsample_exporter_node **) b_;
 +
 +if (a->exporter.options.collector_set_id >
 +b->exporter.options.collector_set_id) {
 +return 1;
 +}
 +if (a->exporter.options.collector_set_id <
 +b->exporter.options.collector_set_id) {
 +return -1;
 +}
 +return 0;
 +}
 +
 +static void
 +lsample_exporter_list(struct dpif_lsample *lsample,
 +  struct lsample_exporter_node ***list,
 +  size_t *num_exporters)
 +{
 +struct lsample_exporter_node **exporter_list;
 +struct lsample_exporter_node *node;
 +size_t k = 0, n;
 +
 +n = cmap_count(>exporters);
 +
 +exporter_list = xcalloc(n, sizeof *exporter_list);
 +
 +CMAP_FOR_EACH (node, node, >exporters) {
 +if (k >= n) {
 +break;
 +}
 +exporter_list[k++] = node;
>>>
>>> There is no guarantee that cmap didn't change between getting the
>>> number of exporters and iterating over them.  Need to either take
>>> a lock or grow the array on demand.
>>
>> I initially thought the same, but it’s covered by the break above.
>>
>> Thinking about it again, we might actually not show entries that were 
>> displayed before, due to a new one being earlier in the map. So I guess we 
>> should probably grow the exporter_list (rather than hold the lock).
>>
> 
> Right. If the map has grown since we took the size we will break before
> iterating over all of them k will be equal to n we will break.
> If the the map has shrinked, CMAP_FOR_EACH will finish.
> 
> AFAICS, in both cases it's safe to access the data (nodes will not be
> freed until the next quiese period).
> 
> What can happen is that we don't show exactly what the current state of
> the map is, e.g: we show a node that has just been deleted from the map
> or we don't show a node that has just been added.
> 
> The only reason for having more than one exporter per bridge is if we
> want to have multiple "observability applications" having differentt
> group ids. In any case, I don't expect the number to be very high nor its
> creation/deletion rate.
> 
> With all this, I considered that having sporadic slighly-inaccurate
> displays was an asumable cost.
> 
> What do you think?

I actually missed the length check.  So, there will be no incorrect memory
accesses.  And for the inaccuracy of the unixctl output, that sounds fine
to me.

Best regards, Ilya Maximets.
___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


Re: [ovs-dev] [PATCH v1 08/13] ofproto-dpif-lsample: Show stats via unixctl.

2024-07-10 Thread Adrián Moreno
On Wed, Jul 10, 2024 at 04:28:55PM GMT, Eelco Chaudron wrote:
>
>
> On 10 Jul 2024, at 15:06, Ilya Maximets wrote:
>
> > On 7/7/24 22:09, Adrian Moreno wrote:
> >> Add a command to dump statistics per exporter.
> >>
> >> Signed-off-by: Adrian Moreno 
> >> ---
> >>  NEWS   |   2 +
> >>  ofproto/ofproto-dpif-lsample.c | 111 +
> >>  ofproto/ofproto-dpif-lsample.h |   1 +
> >>  ofproto/ofproto-dpif.c |   1 +
> >>  4 files changed, 115 insertions(+)
> >>
> >> diff --git a/NEWS b/NEWS
> >> index 15faf9fc3..1c53badea 100644
> >> --- a/NEWS
> >> +++ b/NEWS
> >> @@ -20,6 +20,8 @@ Post-v3.3.0
> >>   allows samples to be emitted locally (instead of via IPFIX) in a
> >>   datapath-specific manner. The Linux kernel datapath is the first to
> >>   support this feature by using the new datapath "psample" action.
> >> + A new unixctl command 'lsample/show' shows packet and bytes 
> >> statistics
> >> + per local sample exporter.
> >
> > Maybe add this as a separate bullet point.
> >
> >>
> >>
> >>  v3.3.0 - 16 Feb 2024
> >> diff --git a/ofproto/ofproto-dpif-lsample.c 
> >> b/ofproto/ofproto-dpif-lsample.c
> >> index 171129d5b..82a87c27d 100644
> >> --- a/ofproto/ofproto-dpif-lsample.c
> >> +++ b/ofproto/ofproto-dpif-lsample.c
> >> @@ -21,7 +21,10 @@
> >>  #include "dpif.h"
> >>  #include "hash.h"
> >>  #include "ofproto.h"
> >> +#include "ofproto-dpif.h"
> >> +#include "openvswitch/dynamic-string.h"
> >>  #include "openvswitch/thread.h"
> >> +#include "unixctl.h"
> >>
> >>  /* Dpif local sampling.
> >>   *
> >> @@ -219,3 +222,111 @@ dpif_lsample_unref(struct dpif_lsample *lsample)
> >>  dpif_lsample_destroy(lsample);
> >>  }
> >>  }
> >> +
> >> +static int
> >> +comp_exporter_collector_id(const void *a_, const void *b_)
> >> +{
> >> +const struct lsample_exporter_node *a, *b;
> >> +
> >> +a = *(struct lsample_exporter_node **) a_;
> >> +b = *(struct lsample_exporter_node **) b_;
> >> +
> >> +if (a->exporter.options.collector_set_id >
> >> +b->exporter.options.collector_set_id) {
> >> +return 1;
> >> +}
> >> +if (a->exporter.options.collector_set_id <
> >> +b->exporter.options.collector_set_id) {
> >> +return -1;
> >> +}
> >> +return 0;
> >> +}
> >> +
> >> +static void
> >> +lsample_exporter_list(struct dpif_lsample *lsample,
> >> +  struct lsample_exporter_node ***list,
> >> +  size_t *num_exporters)
> >> +{
> >> +struct lsample_exporter_node **exporter_list;
> >> +struct lsample_exporter_node *node;
> >> +size_t k = 0, n;
> >> +
> >> +n = cmap_count(>exporters);
> >> +
> >> +exporter_list = xcalloc(n, sizeof *exporter_list);
> >> +
> >> +CMAP_FOR_EACH (node, node, >exporters) {
> >> +if (k >= n) {
> >> +break;
> >> +}
> >> +exporter_list[k++] = node;
> >
> > There is no guarantee that cmap didn't change between getting the
> > number of exporters and iterating over them.  Need to either take
> > a lock or grow the array on demand.
>
> I initially thought the same, but it’s covered by the break above.
>
> Thinking about it again, we might actually not show entries that were 
> displayed before, due to a new one being earlier in the map. So I guess we 
> should probably grow the exporter_list (rather than hold the lock).
>

Right. If the map has grown since we took the size we will break before
iterating over all of them k will be equal to n we will break.
If the the map has shrinked, CMAP_FOR_EACH will finish.

AFAICS, in both cases it's safe to access the data (nodes will not be
freed until the next quiese period).

What can happen is that we don't show exactly what the current state of
the map is, e.g: we show a node that has just been deleted from the map
or we don't show a node that has just been added.

The only reason for having more than one exporter per bridge is if we
want to have multiple "observability applications" having differentt
group ids. In any case, I don't expect the number to be very high nor its
creation/deletion rate.

With all this, I considered that having sporadic slighly-inaccurate
displays was an asumable cost.

What do you think?


> >> +}
> >> +
> >> +qsort(exporter_list, k, sizeof *exporter_list, 
> >> comp_exporter_collector_id);
> >> +
> >> +*list = exporter_list;
> >> +*num_exporters = k;
> >> +}
> >> +
> >> +static void
> >> +lsample_unixctl_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
> >> + const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
> >> +{
> >> +struct lsample_exporter_node **node_list = NULL;
> >> +struct ds ds = DS_EMPTY_INITIALIZER;
> >> +const struct ofproto_dpif *ofproto;
> >> +size_t i, num;
> >> +
> >> +ofproto = ofproto_dpif_lookup_by_name(argv[1]);
> >> +if (!ofproto) {
> >> +unixctl_command_reply_error(conn, "no such bridge");
> >> +  

Re: [ovs-dev] Intel CI not running?

2024-07-10 Thread Ilya Maximets
On 7/10/24 17:41, Phelan, Michael wrote:
> 
>> -Original Message-
>> From: Ilya Maximets 
>> Sent: Monday, July 8, 2024 4:41 PM
>> To: Phelan, Michael 
>> Cc: i.maxim...@ovn.org; ovs-dev ; Aaron Conole
>> ; Chaudron, Eelco 
>> Subject: Re: Intel CI not running?
>>
>> On 7/8/24 11:02, Phelan, Michael wrote:
 -Original Message-
 From: Ilya Maximets 
 Sent: Thursday, July 4, 2024 9:14 PM
 To: Phelan, Michael 
 Cc: i.maxim...@ovn.org; ovs-dev ; Aaron
 Conole ; Chaudron, Eelco 
 Subject: Re: Intel CI not running?

 On 7/4/24 20:46, Ilya Maximets wrote:
> On 7/4/24 13:04, Phelan, Michael wrote:
>> Hi Ilya,
>> The CI got stuck running make check on a patch, I have solved the
>> issue now so reports should be back to normal now.
>
> Thanks for checking!  Though I see only two reports were sent out in
> the past 7 hours with a few hour interval between them.
> Did it get stuck again?

 Got another report.  Looks like we're getting reports at rate of one
 per 3.5 hours.  That doesn't sound right.
>>>
>>> We have added make check to the job parameters so that has increased the
>> duration of the testing.
>>
>> 'make check' in GitHub CI takes about 7 minutes.  And machines there are not
>> very fast.  It shouldn't take hours.
>>
>> In GitHub actions we're running it with TESTSUITEFLAGS='-j4' RECHECK=yes
>>
> 
> I've added these flags, so that should speed up the tests.
>>>
>>> It seems like the test number 98: barrier module from make check is a bit
>> finicky and stalls occasionally also.
>>
>> Hmm. I've never seen this test getting stuck.  Could you try to reproduce 
>> this
>> by running './tests/ovstest test-barrier -v' manually?  Would be also great 
>> to
>> know where exactly it is getting stuck, e.g. by running under gdb.
> 
> I haven't been able to reproduce the issue manually with this command but it 
> is consistently getting stuck when running on CI which is strange.
> 
> Any other suggestions on how to debug this?

You could try to attach gdb to a running process that is stuck
to see where it is waiting and what it is waiting for.

> 
> Kind regards,
> Michael.
> 
>>
>> Best regards, Ilya Maximets.
>>
>>>

>
> Best regards, Ilya Maximets.
>
>>
>> Thanks,
>> Michael.
>>> -Original Message-
>>> From: Ilya Maximets 
>>> Sent: Thursday, July 4, 2024 10:47 AM
>>> To: Phelan, Michael 
>>> Cc: i.maxim...@ovn.org; ovs-dev ; Aaron
>>> Conole ; Chaudron, Eelco
 
>>> Subject: Intel CI not running?
>>>
>>> Hi, Michael!  We seem to not get reports from Intel CI since some
>>> time on Monday.  The last report was:
>>>
>>>
>>> https://mail.openvswitch.org/pipermail/ovs-build/2024-July/039755.
>>> ht
>>> ml
>>>
>>> Could you, please, check?
>>>
>>> Best regards, Ilya Maximets.
>
>>>
> 

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


Re: [ovs-dev] [PATCH v5 ovn] northd: Add bfd, static_routes and route_policies I-P nodes.

2024-07-10 Thread Numan Siddique
On Fri, Jul 5, 2024 at 1:31 PM Lorenzo Bianconi
 wrote:
>
> Introduce bfd, static_routes, route_policies and bfd_nb_sync nodes to northd 
> I-P
> engine to track bfd connections and northd static_route/policy_route
> changes.
>
> Reported-at: https://issues.redhat.com/browse/FDP-600
> Signed-off-by: Lorenzo Bianconi 

Hi Lorenzo,

Thanks for addressing the comments.  Please see below a small comment.
With that addressed :

Acked-by: Numan Siddique 

Numan

> ---
> Changes since v4:
> - introduce bfd_nb_sync node and ger rid of bfd_consumer routine
> Changes since v3:
> - fix bfd_northd_change_handler logic
> - fix route_policies_northd_change_handler logic
> - fix static_routes_northd_change_handler logic
> - add unit-tests
> - cosmetics
> Changes since v2:
> - add incremental processing routines
> - split bfd_consumer node in static_routes and route_policies nodes
> Changes since v1:
> - add incremental processing logic for bfd_consumer node to avoid a full
>   recompute
> ---
>  northd/en-lflow.c|  25 +-
>  northd/en-northd.c   | 215 ++
>  northd/en-northd.h   |  23 ++
>  northd/inc-proc-northd.c |  37 ++-
>  northd/northd.c  | 587 +++
>  northd/northd.h  |  63 -
>  tests/ovn-northd.at  |  56 
>  7 files changed, 810 insertions(+), 196 deletions(-)
>
> diff --git a/northd/en-lflow.c b/northd/en-lflow.c
> index c4b927fb8..3dba5034b 100644
> --- a/northd/en-lflow.c
> +++ b/northd/en-lflow.c
> @@ -41,6 +41,11 @@ lflow_get_input_data(struct engine_node *node,
>   struct lflow_input *lflow_input)
>  {
>  struct northd_data *northd_data = engine_get_input_data("northd", node);
> +struct bfd_data *bfd_data = engine_get_input_data("bfd", node);
> +struct static_routes_data *static_routes_data =
> +engine_get_input_data("static_routes", node);
> +struct route_policies_data *route_policies_data =
> +engine_get_input_data("route_policies", node);
>  struct port_group_data *pg_data =
>  engine_get_input_data("port_group", node);
>  struct sync_meters_data *sync_meters_data =
> @@ -50,10 +55,6 @@ lflow_get_input_data(struct engine_node *node,
>  struct ed_type_ls_stateful *ls_stateful_data =
>  engine_get_input_data("ls_stateful", node);
>
> -lflow_input->nbrec_bfd_table =
> -EN_OVSDB_GET(engine_get_input("NB_bfd", node));
> -lflow_input->sbrec_bfd_table =
> -EN_OVSDB_GET(engine_get_input("SB_bfd", node));
>  lflow_input->sbrec_logical_flow_table =
>  EN_OVSDB_GET(engine_get_input("SB_logical_flow", node));
>  lflow_input->sbrec_multicast_group_table =
> @@ -78,7 +79,10 @@ lflow_get_input_data(struct engine_node *node,
>  lflow_input->meter_groups = _meters_data->meter_groups;
>  lflow_input->lb_datapaths_map = _data->lb_datapaths_map;
>  lflow_input->svc_monitor_map = _data->svc_monitor_map;
> -lflow_input->bfd_connections = NULL;
> +lflow_input->bfd_connections = _data->bfd_connections;
> +lflow_input->parsed_routes = _routes_data->parsed_routes;
> +lflow_input->route_tables = _routes_data->route_tables;
> +lflow_input->route_policies = _policies_data->route_policies;
>
>  struct ed_type_global_config *global_config =
>  engine_get_input_data("global_config", node);
> @@ -95,25 +99,14 @@ void en_lflow_run(struct engine_node *node, void *data)
>  struct lflow_input lflow_input;
>  lflow_get_input_data(node, _input);
>
> -struct hmap bfd_connections = HMAP_INITIALIZER(_connections);
> -lflow_input.bfd_connections = _connections;
> -
>  stopwatch_start(BUILD_LFLOWS_STOPWATCH_NAME, time_msec());
>
>  struct lflow_data *lflow_data = data;
>  lflow_table_clear(lflow_data->lflow_table);
>  lflow_reset_northd_refs(_input);
>
> -build_bfd_table(eng_ctx->ovnsb_idl_txn,
> -lflow_input.nbrec_bfd_table,
> -lflow_input.sbrec_bfd_table,
> -lflow_input.lr_ports,
> -_connections);
>  build_lflows(eng_ctx->ovnsb_idl_txn, _input,
>   lflow_data->lflow_table);
> -bfd_cleanup_connections(lflow_input.nbrec_bfd_table,
> -_connections);
> -hmap_destroy(_connections);
>  stopwatch_stop(BUILD_LFLOWS_STOPWATCH_NAME, time_msec());
>
>  engine_set_node_state(node, EN_UPDATED);
> diff --git a/northd/en-northd.c b/northd/en-northd.c
> index 4479b4aff..7595c6f5f 100644
> --- a/northd/en-northd.c
> +++ b/northd/en-northd.c
> @@ -236,6 +236,162 @@ northd_global_config_handler(struct engine_node *node, 
> void *data OVS_UNUSED)
>  return true;
>  }
>
> +bool
> +route_policies_northd_change_handler(struct engine_node *node,
> + void *data OVS_UNUSED)
> +{
> +struct northd_data *northd_data = engine_get_input_data("northd", node);
> +if 

Re: [ovs-dev] Intel CI not running?

2024-07-10 Thread Phelan, Michael


> -Original Message-
> From: Ilya Maximets 
> Sent: Monday, July 8, 2024 4:41 PM
> To: Phelan, Michael 
> Cc: i.maxim...@ovn.org; ovs-dev ; Aaron Conole
> ; Chaudron, Eelco 
> Subject: Re: Intel CI not running?
> 
> On 7/8/24 11:02, Phelan, Michael wrote:
> >> -Original Message-
> >> From: Ilya Maximets 
> >> Sent: Thursday, July 4, 2024 9:14 PM
> >> To: Phelan, Michael 
> >> Cc: i.maxim...@ovn.org; ovs-dev ; Aaron
> >> Conole ; Chaudron, Eelco 
> >> Subject: Re: Intel CI not running?
> >>
> >> On 7/4/24 20:46, Ilya Maximets wrote:
> >>> On 7/4/24 13:04, Phelan, Michael wrote:
>  Hi Ilya,
>  The CI got stuck running make check on a patch, I have solved the
>  issue now so reports should be back to normal now.
> >>>
> >>> Thanks for checking!  Though I see only two reports were sent out in
> >>> the past 7 hours with a few hour interval between them.
> >>> Did it get stuck again?
> >>
> >> Got another report.  Looks like we're getting reports at rate of one
> >> per 3.5 hours.  That doesn't sound right.
> >
> > We have added make check to the job parameters so that has increased the
> duration of the testing.
> 
> 'make check' in GitHub CI takes about 7 minutes.  And machines there are not
> very fast.  It shouldn't take hours.
> 
> In GitHub actions we're running it with TESTSUITEFLAGS='-j4' RECHECK=yes
> 

I've added these flags, so that should speed up the tests.
> >
> > It seems like the test number 98: barrier module from make check is a bit
> finicky and stalls occasionally also.
> 
> Hmm. I've never seen this test getting stuck.  Could you try to reproduce this
> by running './tests/ovstest test-barrier -v' manually?  Would be also great to
> know where exactly it is getting stuck, e.g. by running under gdb.

I haven't been able to reproduce the issue manually with this command but it is 
consistently getting stuck when running on CI which is strange.

Any other suggestions on how to debug this?

Kind regards,
Michael.

> 
> Best regards, Ilya Maximets.
> 
> >
> >>
> >>>
> >>> Best regards, Ilya Maximets.
> >>>
> 
>  Thanks,
>  Michael.
> > -Original Message-
> > From: Ilya Maximets 
> > Sent: Thursday, July 4, 2024 10:47 AM
> > To: Phelan, Michael 
> > Cc: i.maxim...@ovn.org; ovs-dev ; Aaron
> > Conole ; Chaudron, Eelco
> >> 
> > Subject: Intel CI not running?
> >
> > Hi, Michael!  We seem to not get reports from Intel CI since some
> > time on Monday.  The last report was:
> >
> >
> > https://mail.openvswitch.org/pipermail/ovs-build/2024-July/039755.
> > ht
> > ml
> >
> > Could you, please, check?
> >
> > Best regards, Ilya Maximets.
> >>>
> >

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


Re: [ovs-dev] [PATCH v2 1/1] ofproto-dpif-upcall: Avoid stale ukeys leaks.

2024-07-10 Thread Eelco Chaudron


On 9 Jul 2024, at 23:38, Ilya Maximets wrote:

> On 7/3/24 12:28, Roi Dayan via dev wrote:
>>
>>
>> On 03/07/2024 13:16, Eelco Chaudron wrote:
>>>
>>>
>>> On 3 Jul 2024, at 9:33, Roi Dayan wrote:
>>>
 It is observed in some environments that there are much more ukeys than
 actual DP flows. For example:

 $ ovs-appctl upcall/show
 system@ovs-system:
 flows : (current 7) (avg 6) (max 117) (limit 2125)
 offloaded flows : 525
 dump duration : 1063ms
 ufid enabled : true

 23: (keys 3612)
 24: (keys 3625)
 25: (keys 3485)

 The revalidator threads are busy revalidating the stale ukeys leading to
 high CPU and long dump duration.

 This patch adds checks in the sweep phase for such ukeys and move them
 to DELETE so that they can be cleared eventually.
>>>
>>> Thank Roi for the patch update, one small issue below. Let’s also discuss a 
>>> bit more a potential testcase before sending a v3.
>>>
>>> Cheers,
>>>
>>> Eelco
>>>
>>>
>>
>> I also replied in v0 but replying here so we can continue the discussion 
>> here in v2.
>>
>> I did this for testing this case:
>>
>> - create bridge with 2 veth ports. configure ips.
>> - ping between the ports to have tc rules.
>> - repeated few times: clear the tc rules like this: tc filter del dev veth1 
>> ingress and also on the 2nd port.
>> - set max-idle to 1 and remove it to cause a flush of the rules.
>> - create another set of veth ports. add/del veth4 from the bridge a few 
>> times to cause a sweep.
>> - before the fix: ovs-appctl upcall/show will show ukeys.
>> - after the fix upcall/show will show 0 ukeys.
>>
>>
>> what do you think?
>> I think if there is a cleaner way to do a sweep with purge=false as just
>> will just skip seq mismatch check and just set every ukey to delete.
>
> One problem here is that flow dumps are inherently racy.
> We can dump the same flow multiple times as well as not
> receive some flows that are actually in the datapath.
> So, we can't just remove ukeys if we missed a flow once
> or twice.  If we didn't see the flow in the dumps for the
> max-idle interval, that might be a better indicator that
> something is wrong.
>
> One more problem here however is that ukey statistics can
> keep increasing if there is some traffic that matches.
> Since the datapath flow doesn't exist, all this traffic
> will go to userspace updating the ukey stats, but the
> flow will never be installed again.  And we will not be
> able to fix that in this patch since the stats will grow.

Yes, I noticed this when trying to add a quick testcase for this. The entries 
were used, so it would never hit the code path.


> We need a way to tell that we haven't seen this flow in
> the dumps for a long time and stats are not a good indicator
> in this case.

Agreed, I made a rough testcase and a patch that does this. Please take a look 
and use whatever you need for your patch. I can also try to work on this if you 
want, but it will be another three weeks as I’m about to go on PTO.

Here are the patches (diffs):

diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
index 83609ec62..8b449537d 100644
--- a/ofproto/ofproto-dpif-upcall.c
+++ b/ofproto/ofproto-dpif-upcall.c
@@ -57,6 +57,7 @@ COVERAGE_DEFINE(dumped_inconsistent_flow);
 COVERAGE_DEFINE(dumped_new_flow);
 COVERAGE_DEFINE(handler_duplicate_upcall);
 COVERAGE_DEFINE(revalidate_missed_dp_flow);
+COVERAGE_DEFINE(revalidate_missing_dp_flow);
 COVERAGE_DEFINE(ukey_dp_change);
 COVERAGE_DEFINE(ukey_invalid_stat_reset);
 COVERAGE_DEFINE(ukey_replace_contention);
@@ -278,6 +279,7 @@ enum flow_del_reason {
 FDR_BAD_ODP_FIT,/* Bad ODP flow fit. */
 FDR_FLOW_IDLE,  /* Flow idle timeout. */
 FDR_FLOW_LIMIT, /* Kill all flows condition reached. */
+FDR_FLOW_MISSING_DP,/* Flow is missing from the datapath. */
 FDR_FLOW_WILDCARDED,/* Flow needs a narrower wildcard mask. */
 FDR_NO_OFPROTO, /* Bridge not found. */
 FDR_PURGE,  /* User requested flow deletion. */
@@ -315,6 +317,7 @@ struct udpif_key {
 struct dpif_flow_stats stats OVS_GUARDED; /* Last known stats.*/
 const char *dp_layer OVS_GUARDED; /* Last known dp_layer. */
 long long int created OVS_GUARDED;/* Estimate of creation time. */
+long long int last_dumped OVS_GUARDED;/* Flow last dump time. */
 uint64_t dump_seq OVS_GUARDED;/* Tracks udpif->dump_seq. */
 uint64_t reval_seq OVS_GUARDED;   /* Tracks udpif->reval_seq. */
 enum ukey_state state OVS_GUARDED;/* Tracks ukey lifetime. */
@@ -1819,6 +1822,7 @@ ukey_create__(const struct nlattr *key, size_t key_len,
 ukey->state_thread = ovsthread_id_self();
 ukey->state_where = OVS_SOURCE_LOCATOR;
 ukey->created = ukey->flow_time = time_msec();
+ukey->last_dumped = 0;
 memset(>stats, 0, sizeof ukey->stats);
 ukey->stats.used = used;
 

[ovs-dev] [PATCH v2 ovn] controller: Add the capability to specify a min/max value for ct_zone.

2024-07-10 Thread Lorenzo Bianconi
Introduce the capability to specify boundaries (max and min values) for
the ct_zones dynamically selected by ovn-controller.

Reported-at: https://issues.redhat.com/browse/FDP-383
Signed-off-by: Lorenzo Bianconi 
---
Changes since v1:
- rely on get_chassis_external_id_value() to get ct_zone_range
- allow the user to configure the ct_zone_range instead of min and max values
- improve unit-test
---
 NEWS|  2 +
 controller/ct-zone.c| 81 -
 controller/ct-zone.h|  6 ++-
 controller/ovn-controller.c | 14 +--
 tests/ovn-controller.at | 67 ++
 5 files changed, 156 insertions(+), 14 deletions(-)

diff --git a/NEWS b/NEWS
index 3e392ff08..421f3cd0a 100644
--- a/NEWS
+++ b/NEWS
@@ -38,6 +38,8 @@ Post v24.03.0
 ability to disable "VXLAN mode" to extend available tunnel IDs space for
 datapaths from 4095 to 16711680.  For more details see man ovn-nb(5) for
 mentioned option.
+  - Added support to define boundaries (min and max values) for selected ct
+zones.
 
 OVN v24.03.0 - 01 Mar 2024
 --
diff --git a/controller/ct-zone.c b/controller/ct-zone.c
index e4f66a52a..288ebe816 100644
--- a/controller/ct-zone.c
+++ b/controller/ct-zone.c
@@ -14,7 +14,9 @@
  */
 
 #include 
+#include 
 
+#include "chassis.h"
 #include "ct-zone.h"
 #include "local_data.h"
 #include "openvswitch/vlog.h"
@@ -29,7 +31,8 @@ static void ct_zone_add_pending(struct shash 
*pending_ct_zones,
 int zone, bool add, const char *name);
 static int ct_zone_get_snat(const struct sbrec_datapath_binding *dp);
 static bool ct_zone_assign_unused(struct ct_zone_ctx *ctx,
-  const char *zone_name, int *scan_start);
+  const char *zone_name,
+  int *scan_start, int scan_stop);
 static bool ct_zone_remove(struct ct_zone_ctx *ctx,
struct simap_node *ct_zone);
 
@@ -87,12 +90,61 @@ ct_zones_restore(struct ct_zone_ctx *ctx,
 }
 }
 
+void
+ct_zones_parse_range(const struct ovsrec_open_vswitch_table *ovs_table,
+ int *min_ct_zone, int *max_ct_zone)
+{
+/* Set default values. */
+*min_ct_zone = 1;
+*max_ct_zone = MAX_CT_ZONES + 1;
+
+const struct ovsrec_open_vswitch *cfg =
+ovsrec_open_vswitch_table_first(ovs_table);
+if (!cfg) {
+return;
+}
+
+const char *chassis_id = get_ovs_chassis_id(ovs_table);
+const char *range = get_chassis_external_id_value(>external_ids,
+  chassis_id,
+  "ct_zone_range", NULL);
+if (!range) {
+return;
+}
+
+char *ptr = NULL, *tokstr = xstrdup(range);
+char *range_min = strtok_r(tokstr, "-", );
+if (!range_min) {
+goto out;
+}
+
+int min = strtol(range_min, NULL, 10);
+if (errno == EINVAL || min < 1) {
+goto out;
+}
+*min_ct_zone = min;
+
+char *range_max = strtok_r(NULL, "-", );
+if (!range_max) {
+goto out;
+}
+
+int max = strtol(range_max, NULL, 10);
+if (errno == EINVAL || max > MAX_CT_ZONES + 1) {
+goto out;
+}
+*max_ct_zone = max;
+out:
+free(tokstr);
+}
+
 void
 ct_zones_update(const struct sset *local_lports,
+const struct ovsrec_open_vswitch_table *ovs_table,
 const struct hmap *local_datapaths, struct ct_zone_ctx *ctx)
 {
+int min_ct_zone, max_ct_zone;
 struct simap_node *ct_zone;
-int scan_start = 1;
 const char *user;
 struct sset all_users = SSET_INITIALIZER(_users);
 struct simap req_snat_zones = SIMAP_INITIALIZER(_snat_zones);
@@ -131,9 +183,12 @@ ct_zones_update(const struct sset *local_lports,
 free(snat);
 }
 
+ct_zones_parse_range(ovs_table, _ct_zone, _ct_zone);
+
 /* Delete zones that do not exist in above sset. */
 SIMAP_FOR_EACH_SAFE (ct_zone, >current) {
-if (!sset_contains(_users, ct_zone->name)) {
+if (!sset_contains(_users, ct_zone->name) ||
+ct_zone->data < min_ct_zone || ct_zone->data > max_ct_zone) {
 ct_zone_remove(ctx, ct_zone);
 } else if (!simap_find(_snat_zones, ct_zone->name)) {
 bitmap_set1(unreq_snat_zones_map, ct_zone->data);
@@ -195,7 +250,7 @@ ct_zones_update(const struct sset *local_lports,
 continue;
 }
 
-ct_zone_assign_unused(ctx, user, _start);
+ct_zone_assign_unused(ctx, user, _ct_zone, max_ct_zone);
 }
 
 simap_destroy(_snat_zones);
@@ -296,11 +351,19 @@ ct_zone_handle_dp_update(struct ct_zone_ctx *ctx,
 /* Returns "true" if there was an update to the context. */
 bool
 ct_zone_handle_port_update(struct ct_zone_ctx *ctx, const char *name,
-   bool updated, int *scan_start)
+   bool 

Re: [ovs-dev] [PATCH v1 08/13] ofproto-dpif-lsample: Show stats via unixctl.

2024-07-10 Thread Eelco Chaudron


On 10 Jul 2024, at 15:06, Ilya Maximets wrote:

> On 7/7/24 22:09, Adrian Moreno wrote:
>> Add a command to dump statistics per exporter.
>>
>> Signed-off-by: Adrian Moreno 
>> ---
>>  NEWS   |   2 +
>>  ofproto/ofproto-dpif-lsample.c | 111 +
>>  ofproto/ofproto-dpif-lsample.h |   1 +
>>  ofproto/ofproto-dpif.c |   1 +
>>  4 files changed, 115 insertions(+)
>>
>> diff --git a/NEWS b/NEWS
>> index 15faf9fc3..1c53badea 100644
>> --- a/NEWS
>> +++ b/NEWS
>> @@ -20,6 +20,8 @@ Post-v3.3.0
>>   allows samples to be emitted locally (instead of via IPFIX) in a
>>   datapath-specific manner. The Linux kernel datapath is the first to
>>   support this feature by using the new datapath "psample" action.
>> + A new unixctl command 'lsample/show' shows packet and bytes statistics
>> + per local sample exporter.
>
> Maybe add this as a separate bullet point.
>
>>
>>
>>  v3.3.0 - 16 Feb 2024
>> diff --git a/ofproto/ofproto-dpif-lsample.c b/ofproto/ofproto-dpif-lsample.c
>> index 171129d5b..82a87c27d 100644
>> --- a/ofproto/ofproto-dpif-lsample.c
>> +++ b/ofproto/ofproto-dpif-lsample.c
>> @@ -21,7 +21,10 @@
>>  #include "dpif.h"
>>  #include "hash.h"
>>  #include "ofproto.h"
>> +#include "ofproto-dpif.h"
>> +#include "openvswitch/dynamic-string.h"
>>  #include "openvswitch/thread.h"
>> +#include "unixctl.h"
>>
>>  /* Dpif local sampling.
>>   *
>> @@ -219,3 +222,111 @@ dpif_lsample_unref(struct dpif_lsample *lsample)
>>  dpif_lsample_destroy(lsample);
>>  }
>>  }
>> +
>> +static int
>> +comp_exporter_collector_id(const void *a_, const void *b_)
>> +{
>> +const struct lsample_exporter_node *a, *b;
>> +
>> +a = *(struct lsample_exporter_node **) a_;
>> +b = *(struct lsample_exporter_node **) b_;
>> +
>> +if (a->exporter.options.collector_set_id >
>> +b->exporter.options.collector_set_id) {
>> +return 1;
>> +}
>> +if (a->exporter.options.collector_set_id <
>> +b->exporter.options.collector_set_id) {
>> +return -1;
>> +}
>> +return 0;
>> +}
>> +
>> +static void
>> +lsample_exporter_list(struct dpif_lsample *lsample,
>> +  struct lsample_exporter_node ***list,
>> +  size_t *num_exporters)
>> +{
>> +struct lsample_exporter_node **exporter_list;
>> +struct lsample_exporter_node *node;
>> +size_t k = 0, n;
>> +
>> +n = cmap_count(>exporters);
>> +
>> +exporter_list = xcalloc(n, sizeof *exporter_list);
>> +
>> +CMAP_FOR_EACH (node, node, >exporters) {
>> +if (k >= n) {
>> +break;
>> +}
>> +exporter_list[k++] = node;
>
> There is no guarantee that cmap didn't change between getting the
> number of exporters and iterating over them.  Need to either take
> a lock or grow the array on demand.

I initially thought the same, but it’s covered by the break above.

Thinking about it again, we might actually not show entries that were displayed 
before, due to a new one being earlier in the map. So I guess we should 
probably grow the exporter_list (rather than hold the lock).

>> +}
>> +
>> +qsort(exporter_list, k, sizeof *exporter_list, 
>> comp_exporter_collector_id);
>> +
>> +*list = exporter_list;
>> +*num_exporters = k;
>> +}
>> +
>> +static void
>> +lsample_unixctl_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
>> + const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
>> +{
>> +struct lsample_exporter_node **node_list = NULL;
>> +struct ds ds = DS_EMPTY_INITIALIZER;
>> +const struct ofproto_dpif *ofproto;
>> +size_t i, num;
>> +
>> +ofproto = ofproto_dpif_lookup_by_name(argv[1]);
>> +if (!ofproto) {
>> +unixctl_command_reply_error(conn, "no such bridge");
>> +return;
>> +}
>> +
>> +if (!ofproto->lsample) {
>> +unixctl_command_reply_error(conn,
>> +"no local sampling exporters 
>> configured");
>> +return;
>> +}
>> +
>> +ds_put_format(, "Local sample statistics for bridge \"%s\":\n",
>> +  argv[1]);
>> +
>> +lsample_exporter_list(ofproto->lsample, _list, );
>> +
>> +for (i = 0; i < num; i++) {
>> +uint64_t n_bytes;
>> +uint64_t n_packets;
>> +
>> +struct lsample_exporter_node *node = node_list[i];
>> +
>> +atomic_read_relaxed(>exporter.n_packets, _packets);
>> +atomic_read_relaxed(>exporter.n_bytes, _bytes);
>> +
>> +if (i) {
>> +ds_put_cstr(, "\n");
>> +}
>> +
>> +ds_put_format(, "Collector Set ID: %"PRIu32":\n",
>> +node->exporter.options.collector_set_id);
>> +ds_put_format(, "  Group ID : %"PRIu32"\n",
>> +node->exporter.options.group_id);
>> +ds_put_format(, "  Total packets: %"PRIu64"\n", n_packets);
>> +ds_put_format(, "  Total bytes  : %"PRIu64"\n", 

Re: [ovs-dev] [PATCH ovn] controller: Add the capability to specify a min/max value for ct_zone.

2024-07-10 Thread Lorenzo Bianconi
On Jul 10, Ales Musil wrote:
> On Tue, Jul 9, 2024 at 6:37 PM Lorenzo Bianconi 
> wrote:
> 
> > Introduce the capability to specify boundaries (max and min values) for
> > the ct_zones dynamically selected by ovn-controller.
> >
> > Reported-at: https://issues.redhat.com/browse/FDP-383
> > Signed-off-by: Lorenzo Bianconi 
> > ---
> >
> 
> Hi Lorenzo,
> 
> thank you for the patch, I have a couple of comments down below.

Hi Ales,

thx for the review.

> 
> 
> >  NEWS|  2 ++
> >  controller/ct-zone.c| 37 --
> >  controller/ct-zone.h|  4 ++-
> >  controller/ovn-controller.c | 19 ---
> >  tests/ovn-controller.at | 63 +
> >  5 files changed, 111 insertions(+), 14 deletions(-)
> >
> > diff --git a/NEWS b/NEWS
> > index 3e392ff08..421f3cd0a 100644
> > --- a/NEWS
> > +++ b/NEWS
> > @@ -38,6 +38,8 @@ Post v24.03.0
> >  ability to disable "VXLAN mode" to extend available tunnel IDs space
> > for
> >  datapaths from 4095 to 16711680.  For more details see man ovn-nb(5)
> > for
> >  mentioned option.
> > +  - Added support to define boundaries (min and max values) for selected
> > ct
> > +zones.
> >
> 
> 
> IMO it would be better if it's just one option specifying range instead of
> two.

ack, I will fix it in v2.

> 
> 
> >  OVN v24.03.0 - 01 Mar 2024
> >  --
> > diff --git a/controller/ct-zone.c b/controller/ct-zone.c
> > index e4f66a52a..5191c0fdf 100644
> > --- a/controller/ct-zone.c
> > +++ b/controller/ct-zone.c
> > @@ -29,7 +29,8 @@ static void ct_zone_add_pending(struct shash
> > *pending_ct_zones,
> >  int zone, bool add, const char *name);
> >  static int ct_zone_get_snat(const struct sbrec_datapath_binding *dp);
> >  static bool ct_zone_assign_unused(struct ct_zone_ctx *ctx,
> > -  const char *zone_name, int *scan_start);
> > +  const char *zone_name,
> > +  int *scan_start, int scan_stop);
> >  static bool ct_zone_remove(struct ct_zone_ctx *ctx,
> > struct simap_node *ct_zone);
> >
> > @@ -89,10 +90,11 @@ ct_zones_restore(struct ct_zone_ctx *ctx,
> >
> >  void
> >  ct_zones_update(const struct sset *local_lports,
> > +const struct ovsrec_open_vswitch_table *ovs_table,
> >  const struct hmap *local_datapaths, struct ct_zone_ctx
> > *ctx)
> >  {
> > +int min_ct_zone = 1, max_ct_zone = MAX_CT_ZONES + 1;
> >  struct simap_node *ct_zone;
> > -int scan_start = 1;
> >  const char *user;
> >  struct sset all_users = SSET_INITIALIZER(_users);
> >  struct simap req_snat_zones = SIMAP_INITIALIZER(_snat_zones);
> > @@ -131,9 +133,18 @@ ct_zones_update(const struct sset *local_lports,
> >  free(snat);
> >  }
> >
> > +const struct ovsrec_open_vswitch *cfg =
> > +ovsrec_open_vswitch_table_first(ovs_table);
> > +if (cfg) {
> > +min_ct_zone = smap_get_int(>external_ids, "ct_zone_min_val",
> > 1);
> > +max_ct_zone = smap_get_int(>external_ids, "ct_zone_max_val",
> > +   MAX_CT_ZONES + 1);
> >
> 
> This will break when there are two controllers running over the same OvS.
> We need to use the "get_chassis_external_id_value()" helpers here, see
> "get_bridge_mappings()" for example.

ack, I will fix it in v2.

> 
> 
> > +}
> > +
> >  /* Delete zones that do not exist in above sset. */
> >  SIMAP_FOR_EACH_SAFE (ct_zone, >current) {
> > -if (!sset_contains(_users, ct_zone->name)) {
> > +if (!sset_contains(_users, ct_zone->name) ||
> > +ct_zone->data < min_ct_zone || ct_zone->data > max_ct_zone) {
> >  ct_zone_remove(ctx, ct_zone);
> >  } else if (!simap_find(_snat_zones, ct_zone->name)) {
> >  bitmap_set1(unreq_snat_zones_map, ct_zone->data);
> > @@ -195,7 +206,7 @@ ct_zones_update(const struct sset *local_lports,
> >  continue;
> >  }
> >
> > -ct_zone_assign_unused(ctx, user, _start);
> > +ct_zone_assign_unused(ctx, user, _ct_zone, max_ct_zone);
> >  }
> >
> >  simap_destroy(_snat_zones);
> > @@ -296,11 +307,19 @@ ct_zone_handle_dp_update(struct ct_zone_ctx *ctx,
> >  /* Returns "true" if there was an update to the context. */
> >  bool
> >  ct_zone_handle_port_update(struct ct_zone_ctx *ctx, const char *name,
> > -   bool updated, int *scan_start)
> > +   bool updated, int *scan_start,
> > +   int min_ct_zone, int max_ct_zone)
> >  {
> >  struct simap_node *ct_zone = simap_find(>current, name);
> > +
> > +if (ct_zone &&
> > +(ct_zone->data < min_ct_zone || ct_zone->data > max_ct_zone)) {
> > +ct_zone_remove(ctx, ct_zone);
> > +ct_zone = NULL;
> > +}
> > +
> >  if (updated && 

Re: [ovs-dev] [PATCH v1 06/13] ofproto-dpif-xlate: Use psample for local sample.

2024-07-10 Thread Adrián Moreno
On Wed, Jul 10, 2024 at 02:56:44PM GMT, Ilya Maximets wrote:
> On 7/7/24 22:08, Adrian Moreno wrote:
> > Use the newly added psample action to implement OpenFlow sample() actions
> > with local sampling configuration if possible.
> >
> > A bit of refactoring in compose_sample_actions arguments helps make it a
> > bit more readable.
> >
> > Signed-off-by: Adrian Moreno 
> > ---
> >  ofproto/ofproto-dpif-lsample.c |  16 +++
> >  ofproto/ofproto-dpif-lsample.h |   5 +
> >  ofproto/ofproto-dpif-xlate.c   | 251 +++--
> >  ofproto/ofproto-dpif-xlate.h   |   5 +-
> >  ofproto/ofproto-dpif.c |   2 +-
> >  tests/ofproto-dpif.at  | 146 +++
> >  6 files changed, 345 insertions(+), 80 deletions(-)
> >
> > diff --git a/ofproto/ofproto-dpif-lsample.c b/ofproto/ofproto-dpif-lsample.c
> > index d675a116f..534ad96f0 100644
> > --- a/ofproto/ofproto-dpif-lsample.c
> > +++ b/ofproto/ofproto-dpif-lsample.c
> > @@ -140,6 +140,22 @@ dpif_lsample_set_options(struct dpif_lsample *lsample,
> >  return changed;
> >  }
> >
> > +/* Returns the group_id for a given collector_set_id, if it exists. */
> > +bool
> > +dpif_lsample_get_group_id(struct dpif_lsample *ps, uint32_t 
> > collector_set_id,
> > +  uint32_t *group_id)
> > +{
> > +struct lsample_exporter_node *node;
> > +bool found = false;
> > +
> > +node = dpif_lsample_find_exporter_node(ps, collector_set_id);
> > +if (node) {
> > +found = true;
> > +*group_id = node->exporter.options.group_id;
> > +}
> > +return found;
> > +}
> > +
> >  struct dpif_lsample *
> >  dpif_lsample_create(void)
> >  {
> > diff --git a/ofproto/ofproto-dpif-lsample.h b/ofproto/ofproto-dpif-lsample.h
> > index bee36c9c5..9c1026551 100644
> > --- a/ofproto/ofproto-dpif-lsample.h
> > +++ b/ofproto/ofproto-dpif-lsample.h
> > @@ -18,6 +18,7 @@
> >  #define OFPROTO_DPIF_LSAMPLE_H 1
> >
> >  #include 
> > +#include 
> >  #include 
> >
> >  struct dpif_lsample;
> > @@ -33,4 +34,8 @@ bool dpif_lsample_set_options(struct dpif_lsample *,
> >const struct ofproto_lsample_options *,
> >size_t n_opts);
> >
> > +bool dpif_lsample_get_group_id(struct dpif_lsample *,
> > +   uint32_t collector_set_id,
> > +   uint32_t *group_id);
> > +
> >  #endif /* OFPROTO_DPIF_LSAMPLE_H */
> > diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
> > index 7c4950895..5e8113d5e 100644
> > --- a/ofproto/ofproto-dpif-xlate.c
> > +++ b/ofproto/ofproto-dpif-xlate.c
> > @@ -47,6 +47,7 @@
> >  #include "ofproto/ofproto-dpif-ipfix.h"
> >  #include "ofproto/ofproto-dpif-mirror.h"
> >  #include "ofproto/ofproto-dpif-monitor.h"
> > +#include "ofproto/ofproto-dpif-lsample.h"
> >  #include "ofproto/ofproto-dpif-sflow.h"
> >  #include "ofproto/ofproto-dpif-trace.h"
> >  #include "ofproto/ofproto-dpif-xlate-cache.h"
> > @@ -117,6 +118,7 @@ struct xbridge {
> >  struct dpif_sflow *sflow; /* SFlow handle, or null. */
> >  struct dpif_ipfix *ipfix; /* Ipfix handle, or null. */
> >  struct netflow *netflow;  /* Netflow handle, or null. */
> > +struct dpif_lsample *lsample; /* Local sample handle, or null. */
> >  struct stp *stp;  /* STP or null if disabled. */
> >  struct rstp *rstp;/* RSTP or null if disabled. */
> >
> > @@ -686,6 +688,7 @@ static void xlate_xbridge_set(struct xbridge *, struct 
> > dpif *,
> >const struct mbridge *,
> >const struct dpif_sflow *,
> >const struct dpif_ipfix *,
> > +  const struct dpif_lsample *,
> >const struct netflow *,
> >bool forward_bpdu, bool has_in_band,
> >const struct dpif_backer_support *,
> > @@ -1069,6 +1072,7 @@ xlate_xbridge_set(struct xbridge *xbridge,
> >const struct mbridge *mbridge,
> >const struct dpif_sflow *sflow,
> >const struct dpif_ipfix *ipfix,
> > +  const struct dpif_lsample *lsample,
> >const struct netflow *netflow,
> >bool forward_bpdu, bool has_in_band,
> >const struct dpif_backer_support *support,
> > @@ -1099,6 +1103,11 @@ xlate_xbridge_set(struct xbridge *xbridge,
> >  xbridge->ipfix = dpif_ipfix_ref(ipfix);
> >  }
> >
> > +if (xbridge->lsample != lsample) {
> > +dpif_lsample_unref(xbridge->lsample);
> > +xbridge->lsample = dpif_lsample_ref(lsample);
> > +}
> > +
> >  if (xbridge->stp != stp) {
> >  stp_unref(xbridge->stp);
> >  xbridge->stp = stp_ref(stp);
> > @@ -1213,9 +1222,10 @@ xlate_xbridge_copy(struct xbridge *xbridge)
> >  

Re: [ovs-dev] [PATCH v1 08/13] ofproto-dpif-lsample: Show stats via unixctl.

2024-07-10 Thread Ilya Maximets
On 7/7/24 22:09, Adrian Moreno wrote:
> Add a command to dump statistics per exporter.
> 
> Signed-off-by: Adrian Moreno 
> ---
>  NEWS   |   2 +
>  ofproto/ofproto-dpif-lsample.c | 111 +
>  ofproto/ofproto-dpif-lsample.h |   1 +
>  ofproto/ofproto-dpif.c |   1 +
>  4 files changed, 115 insertions(+)
> 
> diff --git a/NEWS b/NEWS
> index 15faf9fc3..1c53badea 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -20,6 +20,8 @@ Post-v3.3.0
>   allows samples to be emitted locally (instead of via IPFIX) in a
>   datapath-specific manner. The Linux kernel datapath is the first to
>   support this feature by using the new datapath "psample" action.
> + A new unixctl command 'lsample/show' shows packet and bytes statistics
> + per local sample exporter.

Maybe add this as a separate bullet point.

>  
>  
>  v3.3.0 - 16 Feb 2024
> diff --git a/ofproto/ofproto-dpif-lsample.c b/ofproto/ofproto-dpif-lsample.c
> index 171129d5b..82a87c27d 100644
> --- a/ofproto/ofproto-dpif-lsample.c
> +++ b/ofproto/ofproto-dpif-lsample.c
> @@ -21,7 +21,10 @@
>  #include "dpif.h"
>  #include "hash.h"
>  #include "ofproto.h"
> +#include "ofproto-dpif.h"
> +#include "openvswitch/dynamic-string.h"
>  #include "openvswitch/thread.h"
> +#include "unixctl.h"
>  
>  /* Dpif local sampling.
>   *
> @@ -219,3 +222,111 @@ dpif_lsample_unref(struct dpif_lsample *lsample)
>  dpif_lsample_destroy(lsample);
>  }
>  }
> +
> +static int
> +comp_exporter_collector_id(const void *a_, const void *b_)
> +{
> +const struct lsample_exporter_node *a, *b;
> +
> +a = *(struct lsample_exporter_node **) a_;
> +b = *(struct lsample_exporter_node **) b_;
> +
> +if (a->exporter.options.collector_set_id >
> +b->exporter.options.collector_set_id) {
> +return 1;
> +}
> +if (a->exporter.options.collector_set_id <
> +b->exporter.options.collector_set_id) {
> +return -1;
> +}
> +return 0;
> +}
> +
> +static void
> +lsample_exporter_list(struct dpif_lsample *lsample,
> +  struct lsample_exporter_node ***list,
> +  size_t *num_exporters)
> +{
> +struct lsample_exporter_node **exporter_list;
> +struct lsample_exporter_node *node;
> +size_t k = 0, n;
> +
> +n = cmap_count(>exporters);
> +
> +exporter_list = xcalloc(n, sizeof *exporter_list);
> +
> +CMAP_FOR_EACH (node, node, >exporters) {
> +if (k >= n) {
> +break;
> +}
> +exporter_list[k++] = node;

There is no guarantee that cmap didn't change between getting the
number of exporters and iterating over them.  Need to either take
a lock or grow the array on demand.

> +}
> +
> +qsort(exporter_list, k, sizeof *exporter_list, 
> comp_exporter_collector_id);
> +
> +*list = exporter_list;
> +*num_exporters = k;
> +}
> +
> +static void
> +lsample_unixctl_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
> + const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
> +{
> +struct lsample_exporter_node **node_list = NULL;
> +struct ds ds = DS_EMPTY_INITIALIZER;
> +const struct ofproto_dpif *ofproto;
> +size_t i, num;
> +
> +ofproto = ofproto_dpif_lookup_by_name(argv[1]);
> +if (!ofproto) {
> +unixctl_command_reply_error(conn, "no such bridge");
> +return;
> +}
> +
> +if (!ofproto->lsample) {
> +unixctl_command_reply_error(conn,
> +"no local sampling exporters 
> configured");
> +return;
> +}
> +
> +ds_put_format(, "Local sample statistics for bridge \"%s\":\n",
> +  argv[1]);
> +
> +lsample_exporter_list(ofproto->lsample, _list, );
> +
> +for (i = 0; i < num; i++) {
> +uint64_t n_bytes;
> +uint64_t n_packets;
> +
> +struct lsample_exporter_node *node = node_list[i];
> +
> +atomic_read_relaxed(>exporter.n_packets, _packets);
> +atomic_read_relaxed(>exporter.n_bytes, _bytes);
> +
> +if (i) {
> +ds_put_cstr(, "\n");
> +}
> +
> +ds_put_format(, "Collector Set ID: %"PRIu32":\n",
> +node->exporter.options.collector_set_id);
> +ds_put_format(, "  Group ID : %"PRIu32"\n",
> +node->exporter.options.group_id);
> +ds_put_format(, "  Total packets: %"PRIu64"\n", n_packets);
> +ds_put_format(, "  Total bytes  : %"PRIu64"\n", n_bytes);
> +}
> +
> +free(node_list);
> +unixctl_command_reply(conn, ds_cstr());
> +ds_destroy();
> +}
> +
> +void dpif_lsample_init(void)
> +{
> +static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
> +
> +if (ovsthread_once_start()) {
> +unixctl_command_register("lsample/show", "bridge", 1, 1,
> + lsample_unixctl_show, NULL);
> +ovsthread_once_done();
> +}
> +}
> diff --git 

Re: [ovs-dev] [PATCH v1 06/13] ofproto-dpif-xlate: Use psample for local sample.

2024-07-10 Thread Ilya Maximets
On 7/7/24 22:08, Adrian Moreno wrote:
> Use the newly added psample action to implement OpenFlow sample() actions
> with local sampling configuration if possible.
> 
> A bit of refactoring in compose_sample_actions arguments helps make it a
> bit more readable.
> 
> Signed-off-by: Adrian Moreno 
> ---
>  ofproto/ofproto-dpif-lsample.c |  16 +++
>  ofproto/ofproto-dpif-lsample.h |   5 +
>  ofproto/ofproto-dpif-xlate.c   | 251 +++--
>  ofproto/ofproto-dpif-xlate.h   |   5 +-
>  ofproto/ofproto-dpif.c |   2 +-
>  tests/ofproto-dpif.at  | 146 +++
>  6 files changed, 345 insertions(+), 80 deletions(-)
> 
> diff --git a/ofproto/ofproto-dpif-lsample.c b/ofproto/ofproto-dpif-lsample.c
> index d675a116f..534ad96f0 100644
> --- a/ofproto/ofproto-dpif-lsample.c
> +++ b/ofproto/ofproto-dpif-lsample.c
> @@ -140,6 +140,22 @@ dpif_lsample_set_options(struct dpif_lsample *lsample,
>  return changed;
>  }
>  
> +/* Returns the group_id for a given collector_set_id, if it exists. */
> +bool
> +dpif_lsample_get_group_id(struct dpif_lsample *ps, uint32_t collector_set_id,
> +  uint32_t *group_id)
> +{
> +struct lsample_exporter_node *node;
> +bool found = false;
> +
> +node = dpif_lsample_find_exporter_node(ps, collector_set_id);
> +if (node) {
> +found = true;
> +*group_id = node->exporter.options.group_id;
> +}
> +return found;
> +}
> +
>  struct dpif_lsample *
>  dpif_lsample_create(void)
>  {
> diff --git a/ofproto/ofproto-dpif-lsample.h b/ofproto/ofproto-dpif-lsample.h
> index bee36c9c5..9c1026551 100644
> --- a/ofproto/ofproto-dpif-lsample.h
> +++ b/ofproto/ofproto-dpif-lsample.h
> @@ -18,6 +18,7 @@
>  #define OFPROTO_DPIF_LSAMPLE_H 1
>  
>  #include 
> +#include 
>  #include 
>  
>  struct dpif_lsample;
> @@ -33,4 +34,8 @@ bool dpif_lsample_set_options(struct dpif_lsample *,
>const struct ofproto_lsample_options *,
>size_t n_opts);
>  
> +bool dpif_lsample_get_group_id(struct dpif_lsample *,
> +   uint32_t collector_set_id,
> +   uint32_t *group_id);
> +
>  #endif /* OFPROTO_DPIF_LSAMPLE_H */
> diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
> index 7c4950895..5e8113d5e 100644
> --- a/ofproto/ofproto-dpif-xlate.c
> +++ b/ofproto/ofproto-dpif-xlate.c
> @@ -47,6 +47,7 @@
>  #include "ofproto/ofproto-dpif-ipfix.h"
>  #include "ofproto/ofproto-dpif-mirror.h"
>  #include "ofproto/ofproto-dpif-monitor.h"
> +#include "ofproto/ofproto-dpif-lsample.h"
>  #include "ofproto/ofproto-dpif-sflow.h"
>  #include "ofproto/ofproto-dpif-trace.h"
>  #include "ofproto/ofproto-dpif-xlate-cache.h"
> @@ -117,6 +118,7 @@ struct xbridge {
>  struct dpif_sflow *sflow; /* SFlow handle, or null. */
>  struct dpif_ipfix *ipfix; /* Ipfix handle, or null. */
>  struct netflow *netflow;  /* Netflow handle, or null. */
> +struct dpif_lsample *lsample; /* Local sample handle, or null. */
>  struct stp *stp;  /* STP or null if disabled. */
>  struct rstp *rstp;/* RSTP or null if disabled. */
>  
> @@ -686,6 +688,7 @@ static void xlate_xbridge_set(struct xbridge *, struct 
> dpif *,
>const struct mbridge *,
>const struct dpif_sflow *,
>const struct dpif_ipfix *,
> +  const struct dpif_lsample *,
>const struct netflow *,
>bool forward_bpdu, bool has_in_band,
>const struct dpif_backer_support *,
> @@ -1069,6 +1072,7 @@ xlate_xbridge_set(struct xbridge *xbridge,
>const struct mbridge *mbridge,
>const struct dpif_sflow *sflow,
>const struct dpif_ipfix *ipfix,
> +  const struct dpif_lsample *lsample,
>const struct netflow *netflow,
>bool forward_bpdu, bool has_in_band,
>const struct dpif_backer_support *support,
> @@ -1099,6 +1103,11 @@ xlate_xbridge_set(struct xbridge *xbridge,
>  xbridge->ipfix = dpif_ipfix_ref(ipfix);
>  }
>  
> +if (xbridge->lsample != lsample) {
> +dpif_lsample_unref(xbridge->lsample);
> +xbridge->lsample = dpif_lsample_ref(lsample);
> +}
> +
>  if (xbridge->stp != stp) {
>  stp_unref(xbridge->stp);
>  xbridge->stp = stp_ref(stp);
> @@ -1213,9 +1222,10 @@ xlate_xbridge_copy(struct xbridge *xbridge)
>  xlate_xbridge_set(new_xbridge,
>xbridge->dpif, xbridge->ml, xbridge->stp,
>xbridge->rstp, xbridge->ms, xbridge->mbridge,
> -  xbridge->sflow, xbridge->ipfix, xbridge->netflow,
> -  xbridge->forward_bpdu, 

Re: [ovs-dev] [PATCH v1 06/13] ofproto-dpif-xlate: Use psample for local sample.

2024-07-10 Thread Adrián Moreno
On Wed, Jul 10, 2024 at 02:18:35PM GMT, Ilya Maximets wrote:
> On 7/9/24 16:03, Eelco Chaudron wrote:
> >
> >
> > On 9 Jul 2024, at 15:52, Adrián Moreno wrote:
> >
> >> On Tue, Jul 09, 2024 at 11:45:51AM GMT, Eelco Chaudron wrote:
> >>> On 7 Jul 2024, at 22:08, Adrian Moreno wrote:
> >>>
>  Use the newly added psample action to implement OpenFlow sample() actions
>  with local sampling configuration if possible.
> 
>  A bit of refactoring in compose_sample_actions arguments helps make it a
>  bit more readable.
> >>>
> >>> Some comments below.
> >>>
> >>> Cheers,
> >>>
> >>> Eelco
> >>>
>  Signed-off-by: Adrian Moreno 
>  ---
>   ofproto/ofproto-dpif-lsample.c |  16 +++
>   ofproto/ofproto-dpif-lsample.h |   5 +
>   ofproto/ofproto-dpif-xlate.c   | 251 +++--
>   ofproto/ofproto-dpif-xlate.h   |   5 +-
>   ofproto/ofproto-dpif.c |   2 +-
>   tests/ofproto-dpif.at  | 146 +++
>   6 files changed, 345 insertions(+), 80 deletions(-)
> 
>  diff --git a/ofproto/ofproto-dpif-lsample.c 
>  b/ofproto/ofproto-dpif-lsample.c
>  index d675a116f..534ad96f0 100644
>  --- a/ofproto/ofproto-dpif-lsample.c
>  +++ b/ofproto/ofproto-dpif-lsample.c
>  @@ -140,6 +140,22 @@ dpif_lsample_set_options(struct dpif_lsample 
>  *lsample,
>   return changed;
>   }
> 
>  +/* Returns the group_id for a given collector_set_id, if it exists. */
>  +bool
>  +dpif_lsample_get_group_id(struct dpif_lsample *ps, uint32_t 
>  collector_set_id,
>  +  uint32_t *group_id)
>  +{
>  +struct lsample_exporter_node *node;
>  +bool found = false;
>  +
>  +node = dpif_lsample_find_exporter_node(ps, collector_set_id);
>  +if (node) {
>  +found = true;
>  +*group_id = node->exporter.options.group_id;
>  +}
>  +return found;
>  +}
>  +
>   struct dpif_lsample *
>   dpif_lsample_create(void)
>   {
>  diff --git a/ofproto/ofproto-dpif-lsample.h 
>  b/ofproto/ofproto-dpif-lsample.h
>  index bee36c9c5..9c1026551 100644
>  --- a/ofproto/ofproto-dpif-lsample.h
>  +++ b/ofproto/ofproto-dpif-lsample.h
>  @@ -18,6 +18,7 @@
>   #define OFPROTO_DPIF_LSAMPLE_H 1
> 
>   #include 
>  +#include 
>   #include 
> 
>   struct dpif_lsample;
>  @@ -33,4 +34,8 @@ bool dpif_lsample_set_options(struct dpif_lsample *,
> const struct ofproto_lsample_options *,
> size_t n_opts);
> 
>  +bool dpif_lsample_get_group_id(struct dpif_lsample *,
>  +   uint32_t collector_set_id,
>  +   uint32_t *group_id);
>  +
>   #endif /* OFPROTO_DPIF_LSAMPLE_H */
>  diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
>  index 7c4950895..5e8113d5e 100644
>  --- a/ofproto/ofproto-dpif-xlate.c
>  +++ b/ofproto/ofproto-dpif-xlate.c
>  @@ -47,6 +47,7 @@
>   #include "ofproto/ofproto-dpif-ipfix.h"
>   #include "ofproto/ofproto-dpif-mirror.h"
>   #include "ofproto/ofproto-dpif-monitor.h"
>  +#include "ofproto/ofproto-dpif-lsample.h"
> >>>
> >>> Add in alphabetical order?
> >>
> >> Ack.
> >>
> >>>
>   #include "ofproto/ofproto-dpif-sflow.h"
>   #include "ofproto/ofproto-dpif-trace.h"
>   #include "ofproto/ofproto-dpif-xlate-cache.h"
>  @@ -117,6 +118,7 @@ struct xbridge {
>   struct dpif_sflow *sflow; /* SFlow handle, or null. */
>   struct dpif_ipfix *ipfix; /* Ipfix handle, or null. */
>   struct netflow *netflow;  /* Netflow handle, or null. */
>  +struct dpif_lsample *lsample; /* Local sample handle, or null. */
> >>>
> >>> I would move above netflow, as you also do the actual init/unref before 
> >>> netflow.
> >>
> >>
> >> Ack.
> >>
> >>
> >>>
>   struct stp *stp;  /* STP or null if disabled. */
>   struct rstp *rstp;/* RSTP or null if disabled. */
> 
>  @@ -686,6 +688,7 @@ static void xlate_xbridge_set(struct xbridge *, 
>  struct dpif *,
> const struct mbridge *,
> const struct dpif_sflow *,
> const struct dpif_ipfix *,
>  +  const struct dpif_lsample *,
> const struct netflow *,
> bool forward_bpdu, bool has_in_band,
> const struct dpif_backer_support *,
>  @@ -1069,6 +1072,7 @@ xlate_xbridge_set(struct xbridge *xbridge,
> const struct mbridge *mbridge,
> const struct dpif_sflow *sflow,
> const struct dpif_ipfix 

Re: [ovs-dev] [PATCH v1 06/13] ofproto-dpif-xlate: Use psample for local sample.

2024-07-10 Thread Ilya Maximets
On 7/9/24 16:03, Eelco Chaudron wrote:
> 
> 
> On 9 Jul 2024, at 15:52, Adrián Moreno wrote:
> 
>> On Tue, Jul 09, 2024 at 11:45:51AM GMT, Eelco Chaudron wrote:
>>> On 7 Jul 2024, at 22:08, Adrian Moreno wrote:
>>>
 Use the newly added psample action to implement OpenFlow sample() actions
 with local sampling configuration if possible.

 A bit of refactoring in compose_sample_actions arguments helps make it a
 bit more readable.
>>>
>>> Some comments below.
>>>
>>> Cheers,
>>>
>>> Eelco
>>>
 Signed-off-by: Adrian Moreno 
 ---
  ofproto/ofproto-dpif-lsample.c |  16 +++
  ofproto/ofproto-dpif-lsample.h |   5 +
  ofproto/ofproto-dpif-xlate.c   | 251 +++--
  ofproto/ofproto-dpif-xlate.h   |   5 +-
  ofproto/ofproto-dpif.c |   2 +-
  tests/ofproto-dpif.at  | 146 +++
  6 files changed, 345 insertions(+), 80 deletions(-)

 diff --git a/ofproto/ofproto-dpif-lsample.c 
 b/ofproto/ofproto-dpif-lsample.c
 index d675a116f..534ad96f0 100644
 --- a/ofproto/ofproto-dpif-lsample.c
 +++ b/ofproto/ofproto-dpif-lsample.c
 @@ -140,6 +140,22 @@ dpif_lsample_set_options(struct dpif_lsample *lsample,
  return changed;
  }

 +/* Returns the group_id for a given collector_set_id, if it exists. */
 +bool
 +dpif_lsample_get_group_id(struct dpif_lsample *ps, uint32_t 
 collector_set_id,
 +  uint32_t *group_id)
 +{
 +struct lsample_exporter_node *node;
 +bool found = false;
 +
 +node = dpif_lsample_find_exporter_node(ps, collector_set_id);
 +if (node) {
 +found = true;
 +*group_id = node->exporter.options.group_id;
 +}
 +return found;
 +}
 +
  struct dpif_lsample *
  dpif_lsample_create(void)
  {
 diff --git a/ofproto/ofproto-dpif-lsample.h 
 b/ofproto/ofproto-dpif-lsample.h
 index bee36c9c5..9c1026551 100644
 --- a/ofproto/ofproto-dpif-lsample.h
 +++ b/ofproto/ofproto-dpif-lsample.h
 @@ -18,6 +18,7 @@
  #define OFPROTO_DPIF_LSAMPLE_H 1

  #include 
 +#include 
  #include 

  struct dpif_lsample;
 @@ -33,4 +34,8 @@ bool dpif_lsample_set_options(struct dpif_lsample *,
const struct ofproto_lsample_options *,
size_t n_opts);

 +bool dpif_lsample_get_group_id(struct dpif_lsample *,
 +   uint32_t collector_set_id,
 +   uint32_t *group_id);
 +
  #endif /* OFPROTO_DPIF_LSAMPLE_H */
 diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
 index 7c4950895..5e8113d5e 100644
 --- a/ofproto/ofproto-dpif-xlate.c
 +++ b/ofproto/ofproto-dpif-xlate.c
 @@ -47,6 +47,7 @@
  #include "ofproto/ofproto-dpif-ipfix.h"
  #include "ofproto/ofproto-dpif-mirror.h"
  #include "ofproto/ofproto-dpif-monitor.h"
 +#include "ofproto/ofproto-dpif-lsample.h"
>>>
>>> Add in alphabetical order?
>>
>> Ack.
>>
>>>
  #include "ofproto/ofproto-dpif-sflow.h"
  #include "ofproto/ofproto-dpif-trace.h"
  #include "ofproto/ofproto-dpif-xlate-cache.h"
 @@ -117,6 +118,7 @@ struct xbridge {
  struct dpif_sflow *sflow; /* SFlow handle, or null. */
  struct dpif_ipfix *ipfix; /* Ipfix handle, or null. */
  struct netflow *netflow;  /* Netflow handle, or null. */
 +struct dpif_lsample *lsample; /* Local sample handle, or null. */
>>>
>>> I would move above netflow, as you also do the actual init/unref before 
>>> netflow.
>>
>>
>> Ack.
>>
>>
>>>
  struct stp *stp;  /* STP or null if disabled. */
  struct rstp *rstp;/* RSTP or null if disabled. */

 @@ -686,6 +688,7 @@ static void xlate_xbridge_set(struct xbridge *, struct 
 dpif *,
const struct mbridge *,
const struct dpif_sflow *,
const struct dpif_ipfix *,
 +  const struct dpif_lsample *,
const struct netflow *,
bool forward_bpdu, bool has_in_band,
const struct dpif_backer_support *,
 @@ -1069,6 +1072,7 @@ xlate_xbridge_set(struct xbridge *xbridge,
const struct mbridge *mbridge,
const struct dpif_sflow *sflow,
const struct dpif_ipfix *ipfix,
 +  const struct dpif_lsample *lsample,
const struct netflow *netflow,
bool forward_bpdu, bool has_in_band,
const struct dpif_backer_support *support,
 @@ -1099,6 +1103,11 @@ xlate_xbridge_set(struct xbridge *xbridge,

Re: [ovs-dev] [PATCH v1 05/13] vswitchd: Add local sampling to vswitchd schema.

2024-07-10 Thread Ilya Maximets
On 7/7/24 22:08, Adrian Moreno wrote:
> Add as new column in the Flow_Sample_Collector_Set table named
> "local_group_id" which enables this feature.
> 
> Signed-off-by: Adrian Moreno 
> ---
>  NEWS   |  4 ++
>  vswitchd/bridge.c  | 78 +++---
>  vswitchd/vswitch.ovsschema |  9 -
>  vswitchd/vswitch.xml   | 40 +--
>  4 files changed, 120 insertions(+), 11 deletions(-)
> 
> diff --git a/NEWS b/NEWS
> index e0359b759..15faf9fc3 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -16,6 +16,10 @@ Post-v3.3.0
> per interface 'options:dpdk-lsc-interrupt' to 'false'.
> - Python:
>   * Added custom transaction support to the Idl via add_op().
> +   - Local sampling is introduced. It reuses the OpenFlow sample action and
> + allows samples to be emitted locally (instead of via IPFIX) in a
> + datapath-specific manner. The Linux kernel datapath is the first to
> + support this feature by using the new datapath "psample" action.

We try to keep doesble spaces between sentences in the NEWS file.

>  
>  
>  v3.3.0 - 16 Feb 2024
> diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
> index 95a65fcdc..b7db681f3 100644
> --- a/vswitchd/bridge.c
> +++ b/vswitchd/bridge.c
> @@ -288,6 +288,7 @@ static void bridge_configure_mac_table(struct bridge *);
>  static void bridge_configure_mcast_snooping(struct bridge *);
>  static void bridge_configure_sflow(struct bridge *, int 
> *sflow_bridge_number);
>  static void bridge_configure_ipfix(struct bridge *);
> +static void bridge_configure_lsample(struct bridge *);
>  static void bridge_configure_spanning_tree(struct bridge *);
>  static void bridge_configure_tables(struct bridge *);
>  static void bridge_configure_dp_desc(struct bridge *);
> @@ -989,6 +990,7 @@ bridge_reconfigure(const struct ovsrec_open_vswitch 
> *ovs_cfg)
>  bridge_configure_netflow(br);
>  bridge_configure_sflow(br, _bridge_number);
>  bridge_configure_ipfix(br);
> +bridge_configure_lsample(br);
>  bridge_configure_spanning_tree(br);
>  bridge_configure_tables(br);
>  bridge_configure_dp_desc(br);
> @@ -1537,10 +1539,11 @@ ovsrec_ipfix_is_valid(const struct ovsrec_ipfix 
> *ipfix)
>  return ipfix && ipfix->n_targets > 0;
>  }
>  
> -/* Returns whether a Flow_Sample_Collector_Set row is valid. */
> +/* Returns whether a Flow_Sample_Collector_Set row contains a valid IPFIX
> + * configuration. */
>  static bool
> -ovsrec_fscs_is_valid(const struct ovsrec_flow_sample_collector_set *fscs,
> - const struct bridge *br)
> +ovsrec_fscs_is_valid_ipfix(const struct ovsrec_flow_sample_collector_set 
> *fscs,
> +   const struct bridge *br)
>  {
>  return ovsrec_ipfix_is_valid(fscs->ipfix) && fscs->bridge == br->cfg;
>  }
> @@ -1558,7 +1561,7 @@ bridge_configure_ipfix(struct bridge *br)
>  const char *virtual_obs_id;
>  
>  OVSREC_FLOW_SAMPLE_COLLECTOR_SET_FOR_EACH(fe_cfg, idl) {
> -if (ovsrec_fscs_is_valid(fe_cfg, br)) {
> +if (ovsrec_fscs_is_valid_ipfix(fe_cfg, br)) {
>  n_fe_opts++;
>  }
>  }
> @@ -1621,7 +1624,7 @@ bridge_configure_ipfix(struct bridge *br)
>  fe_opts = xcalloc(n_fe_opts, sizeof *fe_opts);
>  opts = fe_opts;
>  OVSREC_FLOW_SAMPLE_COLLECTOR_SET_FOR_EACH(fe_cfg, idl) {
> -if (ovsrec_fscs_is_valid(fe_cfg, br)) {
> +if (ovsrec_fscs_is_valid_ipfix(fe_cfg, br)) {
>  opts->collector_set_id = fe_cfg->id;
>  sset_init(>targets);
>  sset_add_array(>targets, fe_cfg->ipfix->targets,
> @@ -1667,6 +1670,71 @@ bridge_configure_ipfix(struct bridge *br)
>  }
>  }
>  
> +/* Returns whether a Flow_Sample_Collector_Set row contains a valid local
> + * sampling configuration. */
> +static bool
> +ovsrec_fscs_is_valid_local(const struct ovsrec_flow_sample_collector_set 
> *fscs,
> +   const struct bridge *br)
> +{
> +return fscs->local_group_id && fscs->n_local_group_id == 1 &&
> +   fscs->bridge == br->cfg;
> +}
> +
> +/* Set local sample configuration on 'br'. */
> +static void
> +bridge_configure_lsample(struct bridge *br)
> +{
> +static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
> +const struct ovsrec_flow_sample_collector_set *fscs;
> +struct ofproto_lsample_options *opts_array, *opts;
> +size_t n_opts = 0;
> +int ret;
> +
> +/* Iterate the Flow_Sample_Collector_Set table twice.
> + * First to get the number of valid configuration entries, then to 
> process
> + * each of them and build an array of options. */
> +OVSREC_FLOW_SAMPLE_COLLECTOR_SET_FOR_EACH (fscs, idl) {
> +if (ovsrec_fscs_is_valid_local(fscs, br)) {
> +n_opts ++;

Space is not needed.

> +}
> +}
> +
> +if (n_opts == 0) {
> +ofproto_set_local_sample(br->ofproto, NULL, 0);
> +   

Re: [ovs-dev] [PATCH v1 04/13] ofproto: Add ofproto-dpif-lsample.

2024-07-10 Thread Ilya Maximets
On 7/9/24 15:32, Adrián Moreno wrote:
> On Tue, Jul 09, 2024 at 11:45:19AM GMT, Eelco Chaudron wrote:
>> On 7 Jul 2024, at 22:08, Adrian Moreno wrote:
>>
>>> Add a new resource in ofproto-dpif and the corresponding API in
>>> ofproto_provider.h to represent and local sampling configuration.
>>>
>>> Signed-off-by: Adrian Moreno 
>>
>> Some small nits below.
>>
>> //Eelco
>>
>>> ---
>>>  ofproto/automake.mk|   2 +
>>>  ofproto/ofproto-dpif-lsample.c | 187 +
>>>  ofproto/ofproto-dpif-lsample.h |  36 +++
>>>  ofproto/ofproto-dpif.c |  38 +++
>>>  ofproto/ofproto-dpif.h |   1 +
>>>  ofproto/ofproto-provider.h |   9 ++
>>>  ofproto/ofproto.c  |  12 +++
>>>  ofproto/ofproto.h  |   8 ++
>>>  8 files changed, 293 insertions(+)
>>>  create mode 100644 ofproto/ofproto-dpif-lsample.c
>>>  create mode 100644 ofproto/ofproto-dpif-lsample.h
>>>
>>> diff --git a/ofproto/automake.mk b/ofproto/automake.mk
>>> index 7c08b563b..cb1361b8a 100644
>>> --- a/ofproto/automake.mk
>>> +++ b/ofproto/automake.mk
>>> @@ -30,6 +30,8 @@ ofproto_libofproto_la_SOURCES = \
>>> ofproto/ofproto-dpif.h \
>>> ofproto/ofproto-dpif-ipfix.c \
>>> ofproto/ofproto-dpif-ipfix.h \
>>> +   ofproto/ofproto-dpif-lsample.c \
>>> +   ofproto/ofproto-dpif-lsample.h \
>>> ofproto/ofproto-dpif-mirror.c \
>>> ofproto/ofproto-dpif-mirror.h \
>>> ofproto/ofproto-dpif-monitor.c \
>>> diff --git a/ofproto/ofproto-dpif-lsample.c b/ofproto/ofproto-dpif-lsample.c
>>> new file mode 100644
>>> index 0..d675a116f
>>> --- /dev/null
>>> +++ b/ofproto/ofproto-dpif-lsample.c
>>> @@ -0,0 +1,187 @@
>>> +/*
>>> + * Copyright (c) 2024 Red Hat, Inc.
>>> + *
>>> + * Licensed under the Apache License, Version 2.0 (the "License");
>>> + * you may not use this file except in compliance with the License.
>>> + * You may obtain a copy of the License at:
>>> + *
>>> + * http://www.apache.org/licenses/LICENSE-2.0
>>> + *
>>> + * Unless required by applicable law or agreed to in writing, software
>>> + * distributed under the License is distributed on an "AS IS" BASIS,
>>> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
>>> + * See the License for the specific language governing permissions and
>>> + * limitations under the License.
>>> + */
>>> +
>>> +#include 
>>> +#include "ofproto-dpif-lsample.h"
>>> +
>>> +#include "cmap.h"
>>> +#include "hash.h"
>>> +#include "ofproto.h"
>>> +#include "openvswitch/thread.h"
>>> +
>>> +/* Dpif local sampling.
>>> + *
>>> + * Thread safety: dpif_lsample allows lockless concurrent reads of local
>>> + * sampling exporters as long as the following restrictions are met:
>>> + *   1) While the last reference is being dropped, i.e: a thread is calling
>>> + *  "dpif_lsample_unref" on the last reference, other threads cannot 
>>> call
>>> + *  "dpif_lsample_ref".
>>> + *   2) Threads do not quiese while holding references to internal
>>> + *  lsample_exporter objects.
>>> + */
>>> +
>>> +struct dpif_lsample {
>>> +struct cmap exporters;  /* Contains lsample_exporter_node 
>>> instances
>>> +   indexed by collector_set_id. */
>>> +struct ovs_mutex mutex; /* Protects concurrent 
>>> insertion/deletion
>>> + * of exporters. */
>>> +
>>> +struct ovs_refcount ref_cnt;/* Controls references to this 
>>> instance. */
>>> +};
>>> +
>>> +struct lsample_exporter {
>>> +struct ofproto_lsample_options options;
>>> +};
>>> +
>>> +struct lsample_exporter_node {
>>> +struct cmap_node node;  /* In dpif_lsample->exporters. */
>>> +struct lsample_exporter exporter;
>>> +};
>>> +
>>> +static void
>>> +dpif_lsample_delete_exporter(struct dpif_lsample *lsample,
>>> + struct lsample_exporter_node *node)
>>> +{
>>> +ovs_mutex_lock(>mutex);
>>> +cmap_remove(>exporters, >node,
>>> +hash_int(node->exporter.options.collector_set_id, 0));
>>> +ovs_mutex_unlock(>mutex);
>>> +
>>> +ovsrcu_postpone(free, node);
>>> +}
>>> +
>>> +/* Adds an exporter with the provided options which are copied. */
>>> +static struct lsample_exporter_node *
>>> +dpif_lsample_add_exporter(struct dpif_lsample *lsample,
>>> +  const struct ofproto_lsample_options *options)
>>> +{
>>> +struct lsample_exporter_node *node;
>>> +
>>> +node = xzalloc(sizeof *node);
>>> +node->exporter.options = *options;
>>> +
>>> +ovs_mutex_lock(>mutex);
>>> +cmap_insert(>exporters, >node,
>>> +hash_int(options->collector_set_id, 0));
>>> +ovs_mutex_unlock(>mutex);
>>> +
>>> +return node;
>>> +}
>>> +
>>> +static struct lsample_exporter_node *
>>> +dpif_lsample_find_exporter_node(const struct dpif_lsample *lsample,
>>> +const uint32_t collector_set_id)
>>> +{
>>> +struct 

Re: [ovs-dev] [PATCH v1 04/13] ofproto: Add ofproto-dpif-lsample.

2024-07-10 Thread Ilya Maximets
On 7/7/24 22:08, Adrian Moreno wrote:
> Add a new resource in ofproto-dpif and the corresponding API in
> ofproto_provider.h to represent and local sampling configuration.
> 
> Signed-off-by: Adrian Moreno 
> ---
>  ofproto/automake.mk|   2 +
>  ofproto/ofproto-dpif-lsample.c | 187 +
>  ofproto/ofproto-dpif-lsample.h |  36 +++
>  ofproto/ofproto-dpif.c |  38 +++
>  ofproto/ofproto-dpif.h |   1 +
>  ofproto/ofproto-provider.h |   9 ++
>  ofproto/ofproto.c  |  12 +++
>  ofproto/ofproto.h  |   8 ++
>  8 files changed, 293 insertions(+)
>  create mode 100644 ofproto/ofproto-dpif-lsample.c
>  create mode 100644 ofproto/ofproto-dpif-lsample.h
> 
> diff --git a/ofproto/automake.mk b/ofproto/automake.mk
> index 7c08b563b..cb1361b8a 100644
> --- a/ofproto/automake.mk
> +++ b/ofproto/automake.mk
> @@ -30,6 +30,8 @@ ofproto_libofproto_la_SOURCES = \
>   ofproto/ofproto-dpif.h \
>   ofproto/ofproto-dpif-ipfix.c \
>   ofproto/ofproto-dpif-ipfix.h \
> + ofproto/ofproto-dpif-lsample.c \
> + ofproto/ofproto-dpif-lsample.h \
>   ofproto/ofproto-dpif-mirror.c \
>   ofproto/ofproto-dpif-mirror.h \
>   ofproto/ofproto-dpif-monitor.c \
> diff --git a/ofproto/ofproto-dpif-lsample.c b/ofproto/ofproto-dpif-lsample.c
> new file mode 100644
> index 0..d675a116f
> --- /dev/null
> +++ b/ofproto/ofproto-dpif-lsample.c
> @@ -0,0 +1,187 @@
> +/*
> + * Copyright (c) 2024 Red Hat, Inc.
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at:
> + *
> + * http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +
> +#include 
> +#include "ofproto-dpif-lsample.h"
> +
> +#include "cmap.h"
> +#include "hash.h"
> +#include "ofproto.h"
> +#include "openvswitch/thread.h"
> +
> +/* Dpif local sampling.
> + *
> + * Thread safety: dpif_lsample allows lockless concurrent reads of local
> + * sampling exporters as long as the following restrictions are met:
> + *   1) While the last reference is being dropped, i.e: a thread is calling
> + *  "dpif_lsample_unref" on the last reference, other threads cannot call
> + *  "dpif_lsample_ref".
> + *   2) Threads do not quiese while holding references to internal
> + *  lsample_exporter objects.
> + */
> +
> +struct dpif_lsample {
> +struct cmap exporters;  /* Contains lsample_exporter_node 
> instances
> +   indexed by collector_set_id. */

line should start with a '*'.

> +struct ovs_mutex mutex; /* Protects concurrent insertion/deletion
> + * of exporters. */
> +
> +struct ovs_refcount ref_cnt;/* Controls references to this instance. 
> */
> +};
> +
> +struct lsample_exporter {
> +struct ofproto_lsample_options options;
> +};
> +
> +struct lsample_exporter_node {
> +struct cmap_node node;  /* In dpif_lsample->exporters. */
> +struct lsample_exporter exporter;
> +};
> +
> +static void
> +dpif_lsample_delete_exporter(struct dpif_lsample *lsample,
> + struct lsample_exporter_node *node)
> +{
> +ovs_mutex_lock(>mutex);
> +cmap_remove(>exporters, >node,
> +hash_int(node->exporter.options.collector_set_id, 0));
> +ovs_mutex_unlock(>mutex);
> +
> +ovsrcu_postpone(free, node);
> +}
> +
> +/* Adds an exporter with the provided options which are copied. */
> +static struct lsample_exporter_node *
> +dpif_lsample_add_exporter(struct dpif_lsample *lsample,
> +  const struct ofproto_lsample_options *options)
> +{
> +struct lsample_exporter_node *node;
> +
> +node = xzalloc(sizeof *node);
> +node->exporter.options = *options;
> +
> +ovs_mutex_lock(>mutex);
> +cmap_insert(>exporters, >node,
> +hash_int(options->collector_set_id, 0));
> +ovs_mutex_unlock(>mutex);
> +
> +return node;
> +}
> +
> +static struct lsample_exporter_node *
> +dpif_lsample_find_exporter_node(const struct dpif_lsample *lsample,
> +const uint32_t collector_set_id)
> +{
> +struct lsample_exporter_node *node;
> +
> +CMAP_FOR_EACH_WITH_HASH (node, node,
> +hash_int(collector_set_id, 0),
> +>exporters) {
> +if (node->exporter.options.collector_set_id == collector_set_id) {
> +return node;
> +}
> +}
> +return NULL;
> +}
> +
> +/* Sets the lsample 

Re: [ovs-dev] [PATCH v1 03/13] ofproto_dpif: Check for psample support.

2024-07-10 Thread Adrián Moreno
On Wed, Jul 10, 2024 at 01:28:29PM GMT, Ilya Maximets wrote:
> On 7/7/24 22:08, Adrian Moreno wrote:
> > Only kernel datapath supports this action so add a function in dpif.c
> > that checks for that.
> >
> > Signed-off-by: Adrian Moreno 
> > ---
> >  lib/dpif.c |  7 +++
> >  lib/dpif.h |  1 +
> >  ofproto/ofproto-dpif.c | 43 ++
> >  ofproto/ofproto-dpif.h |  7 ++-
> >  4 files changed, 57 insertions(+), 1 deletion(-)
> >
> > diff --git a/lib/dpif.c b/lib/dpif.c
> > index 71728badc..0a964ba89 100644
> > --- a/lib/dpif.c
> > +++ b/lib/dpif.c
> > @@ -1953,6 +1953,13 @@ dpif_supports_lb_output_action(const struct dpif 
> > *dpif)
> >  return dpif_is_netdev(dpif);
> >  }
> >
> > +bool
> > +dpif_may_support_psample(const struct dpif *dpif)
> > +{
> > +/* Userspace datapath does not support this action. */
> > +return !dpif_is_netdev(dpif);
> > +}
> > +
> >  /* Meters */
> >  void
> >  dpif_meter_get_features(const struct dpif *dpif,
> > diff --git a/lib/dpif.h b/lib/dpif.h
> > index a764e8a59..6bef7d5b3 100644
> > --- a/lib/dpif.h
> > +++ b/lib/dpif.h
> > @@ -941,6 +941,7 @@ int dpif_get_pmds_for_port(const struct dpif * dpif, 
> > odp_port_t port_no,
> >  char *dpif_get_dp_version(const struct dpif *);
> >  bool dpif_supports_tnl_push_pop(const struct dpif *);
> >  bool dpif_may_support_explicit_drop_action(const struct dpif *);
> > +bool dpif_may_support_psample(const struct dpif *);
> >  bool dpif_synced_dp_layers(struct dpif *);
> >
> >  /* Log functions. */
> > diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
> > index 4712d10a8..94c84d697 100644
> > --- a/ofproto/ofproto-dpif.c
> > +++ b/ofproto/ofproto-dpif.c
> > @@ -873,6 +873,12 @@ ovs_lb_output_action_supported(struct ofproto_dpif 
> > *ofproto)
> >  return ofproto->backer->rt_support.lb_output_action;
> >  }
> >
> > +bool
> > +ovs_psample_supported(struct ofproto_dpif *ofproto)
> > +{
> > +return ofproto->backer->rt_support.psample;
> > +}
> > +
> >  /* Tests whether 'backer''s datapath supports recirculation.  Only newer
> >   * datapaths support OVS_KEY_ATTR_RECIRC_ID in keys.  We need to disable 
> > some
> >   * features on older datapaths that don't support this feature.
> > @@ -1609,6 +1615,42 @@ check_add_mpls(struct dpif_backer *backer)
> >  return supported;
> >  }
> >
> > +/* Tests whether 'backer''s datapath supports the OVS_ACTION_ATTR_PSAMPLE
> > + * action. */
> > +static bool
> > +check_psample(struct dpif_backer *backer)
> > +{
> > +uint8_t cookie[OVS_PSAMPLE_COOKIE_MAX_SIZE];
> > +struct odputil_keybuf keybuf;
> > +struct ofpbuf actions;
> > +struct ofpbuf key;
> > +struct flow flow;
> > +bool supported;
> > +
> > +struct odp_flow_key_parms odp_parms = {
> > +.flow = ,
> > +.probe = true,
> > +};
> > +
> > +memset(, 0, sizeof flow);
> > +ofpbuf_use_stack(, , sizeof keybuf);
> > +odp_flow_key_from_flow(_parms, );
> > +ofpbuf_init(, 64);
> > +
> > +/* Generate a random max-size cookie. */
> > +random_bytes(cookie, sizeof(cookie));
>
> Don't parenthesize the argument of sizeof.
>

Ack.

> > +
> > +odp_put_psample_action(, 10, cookie, sizeof cookie);
> > +
> > +supported = dpif_may_support_psample(backer->dpif) &&
> > +dpif_probe_feature(backer->dpif, "psample", , , NULL);
>
> This function actually installs the flow into the kernel.
> You need to make sure that no packet can match it, e.g.
> by setting a bogus eth type as a match.  Some existing
> probe functions require specific matches, some are just
> missing this part as well, but we should not blindly copy
> bad patterns.
>

I guess I was always thinking on a freshly started system but you're
right! If OVS is restarted, the installed flow can affect actual
traffic. I'll add a bogus key to make sure it's not problematic.

> > +
> > +ofpbuf_uninit();
> > +VLOG_INFO("%s: Datapath %s psample", dpif_name(backer->dpif),
>
> '%s: Datapath %s psample action'  will be more clear.
>

Ack.

> > +  supported ? "supports" : "does not support");
> > +return supported;
> > +}
> > +
> >  #define CHECK_FEATURE__(NAME, SUPPORT, FIELD, VALUE, ETHTYPE)  
> >  \
> >  static bool
> >  \
> >  check_##NAME(struct dpif_backer *backer)   
> >  \
> > @@ -1698,6 +1740,7 @@ check_support(struct dpif_backer *backer)
> >  dpif_supports_lb_output_action(backer->dpif);
> >  backer->rt_support.ct_zero_snat = dpif_supports_ct_zero_snat(backer);
> >  backer->rt_support.add_mpls = check_add_mpls(backer);
> > +backer->rt_support.psample = check_psample(backer);
> >
> >  /* Flow fields. */
> >  backer->rt_support.odp.ct_state = check_ct_state(backer);
> > diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h
> > index d33f73df8..bc7a19dab 100644
> > --- 

Re: [ovs-dev] [PATCH v1 03/13] ofproto_dpif: Check for psample support.

2024-07-10 Thread Ilya Maximets
On 7/7/24 22:08, Adrian Moreno wrote:
> Only kernel datapath supports this action so add a function in dpif.c
> that checks for that.
> 
> Signed-off-by: Adrian Moreno 
> ---
>  lib/dpif.c |  7 +++
>  lib/dpif.h |  1 +
>  ofproto/ofproto-dpif.c | 43 ++
>  ofproto/ofproto-dpif.h |  7 ++-
>  4 files changed, 57 insertions(+), 1 deletion(-)
> 
> diff --git a/lib/dpif.c b/lib/dpif.c
> index 71728badc..0a964ba89 100644
> --- a/lib/dpif.c
> +++ b/lib/dpif.c
> @@ -1953,6 +1953,13 @@ dpif_supports_lb_output_action(const struct dpif *dpif)
>  return dpif_is_netdev(dpif);
>  }
>  
> +bool
> +dpif_may_support_psample(const struct dpif *dpif)
> +{
> +/* Userspace datapath does not support this action. */
> +return !dpif_is_netdev(dpif);
> +}
> +
>  /* Meters */
>  void
>  dpif_meter_get_features(const struct dpif *dpif,
> diff --git a/lib/dpif.h b/lib/dpif.h
> index a764e8a59..6bef7d5b3 100644
> --- a/lib/dpif.h
> +++ b/lib/dpif.h
> @@ -941,6 +941,7 @@ int dpif_get_pmds_for_port(const struct dpif * dpif, 
> odp_port_t port_no,
>  char *dpif_get_dp_version(const struct dpif *);
>  bool dpif_supports_tnl_push_pop(const struct dpif *);
>  bool dpif_may_support_explicit_drop_action(const struct dpif *);
> +bool dpif_may_support_psample(const struct dpif *);
>  bool dpif_synced_dp_layers(struct dpif *);
>  
>  /* Log functions. */
> diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
> index 4712d10a8..94c84d697 100644
> --- a/ofproto/ofproto-dpif.c
> +++ b/ofproto/ofproto-dpif.c
> @@ -873,6 +873,12 @@ ovs_lb_output_action_supported(struct ofproto_dpif 
> *ofproto)
>  return ofproto->backer->rt_support.lb_output_action;
>  }
>  
> +bool
> +ovs_psample_supported(struct ofproto_dpif *ofproto)
> +{
> +return ofproto->backer->rt_support.psample;
> +}
> +
>  /* Tests whether 'backer''s datapath supports recirculation.  Only newer
>   * datapaths support OVS_KEY_ATTR_RECIRC_ID in keys.  We need to disable some
>   * features on older datapaths that don't support this feature.
> @@ -1609,6 +1615,42 @@ check_add_mpls(struct dpif_backer *backer)
>  return supported;
>  }
>  
> +/* Tests whether 'backer''s datapath supports the OVS_ACTION_ATTR_PSAMPLE
> + * action. */
> +static bool
> +check_psample(struct dpif_backer *backer)
> +{
> +uint8_t cookie[OVS_PSAMPLE_COOKIE_MAX_SIZE];
> +struct odputil_keybuf keybuf;
> +struct ofpbuf actions;
> +struct ofpbuf key;
> +struct flow flow;
> +bool supported;
> +
> +struct odp_flow_key_parms odp_parms = {
> +.flow = ,
> +.probe = true,
> +};
> +
> +memset(, 0, sizeof flow);
> +ofpbuf_use_stack(, , sizeof keybuf);
> +odp_flow_key_from_flow(_parms, );
> +ofpbuf_init(, 64);
> +
> +/* Generate a random max-size cookie. */
> +random_bytes(cookie, sizeof(cookie));

Don't parenthesize the argument of sizeof.

> +
> +odp_put_psample_action(, 10, cookie, sizeof cookie);
> +
> +supported = dpif_may_support_psample(backer->dpif) &&
> +dpif_probe_feature(backer->dpif, "psample", , , NULL);

This function actually installs the flow into the kernel.
You need to make sure that no packet can match it, e.g.
by setting a bogus eth type as a match.  Some existing
probe functions require specific matches, some are just
missing this part as well, but we should not blindly copy
bad patterns.

> +
> +ofpbuf_uninit();
> +VLOG_INFO("%s: Datapath %s psample", dpif_name(backer->dpif),

'%s: Datapath %s psample action'  will be more clear.

> +  supported ? "supports" : "does not support");
> +return supported;
> +}
> +
>  #define CHECK_FEATURE__(NAME, SUPPORT, FIELD, VALUE, ETHTYPE)   \
>  static bool \
>  check_##NAME(struct dpif_backer *backer)\
> @@ -1698,6 +1740,7 @@ check_support(struct dpif_backer *backer)
>  dpif_supports_lb_output_action(backer->dpif);
>  backer->rt_support.ct_zero_snat = dpif_supports_ct_zero_snat(backer);
>  backer->rt_support.add_mpls = check_add_mpls(backer);
> +backer->rt_support.psample = check_psample(backer);
>  
>  /* Flow fields. */
>  backer->rt_support.odp.ct_state = check_ct_state(backer);
> diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h
> index d33f73df8..bc7a19dab 100644
> --- a/ofproto/ofproto-dpif.h
> +++ b/ofproto/ofproto-dpif.h
> @@ -213,7 +213,10 @@ struct group_dpif *group_dpif_lookup(struct ofproto_dpif 
> *,
>  DPIF_SUPPORT_FIELD(bool, ct_zero_snat, "Conntrack all-zero IP SNAT")\
>  \
>  /* True if the datapath supports add_mpls action. */\
> -DPIF_SUPPORT_FIELD(bool, add_mpls, "MPLS Label add")
> +DPIF_SUPPORT_FIELD(bool, add_mpls, "MPLS Label add")\
> +  

Re: [ovs-dev] [PATCH v1 02/13] odp-util: Add support OVS_ACTION_ATTR_PSAMPLE.

2024-07-10 Thread Ilya Maximets
On 7/10/24 13:18, Adrián Moreno wrote:
> On Wed, Jul 10, 2024 at 12:56:57PM GMT, Ilya Maximets wrote:
>> On 7/7/24 22:08, Adrian Moreno wrote:
>>> Add support for parsing and formatting the new action.
>>>
>>> Also, flag OVS_ACTION_ATTR_SAMPLE as requiring datapath assistance if it
>>> contains a nested OVS_ACTION_ATTR_PSAMPLE. The reason is that the
>>> sampling rate form the parent "sample" is made available to the nested
>>> "psample" by the kernel.
>>>
>>> Signed-off-by: Adrian Moreno 
>>> ---
>>>  include/linux/openvswitch.h  | 28 +++
>>>  lib/dpif-netdev.c|  1 +
>>>  lib/dpif.c   |  1 +
>>>  lib/odp-execute.c| 25 +-
>>>  lib/odp-util.c   | 93 
>>>  lib/odp-util.h   |  3 ++
>>>  ofproto/ofproto-dpif-ipfix.c |  1 +
>>>  ofproto/ofproto-dpif-sflow.c |  1 +
>>>  python/ovs/flow/odp.py   |  8 
>>>  tests/odp.at | 16 +++
>>>  10 files changed, 176 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/include/linux/openvswitch.h b/include/linux/openvswitch.h
>>> index d9fb991ef..0023b65fb 100644
>>> --- a/include/linux/openvswitch.h
>>> +++ b/include/linux/openvswitch.h
>>> @@ -992,6 +992,31 @@ struct check_pkt_len_arg {
>>>  };
>>>  #endif
>>>
>>> +#define OVS_PSAMPLE_COOKIE_MAX_SIZE 16
>>> +/**
>>> + * enum ovs_pample_attr - Attributes for %OVS_ACTION_ATTR_PSAMPLE
>>> + * action.
>>> + *
>>> + * @OVS_PSAMPLE_ATTR_GROUP: 32-bit number to identify the source of the
>>> + * sample.
>>> + * @OVS_PSAMPLE_ATTR_COOKIE: An optional variable-length binary cookie that
>>> + * contains user-defined metadata. The maximum length is
>>> + * OVS_PSAMPLE_COOKIE_MAX_SIZE bytes.
>>> + *
>>> + * Sends the packet to the psample multicast group with the specified 
>>> group and
>>> + * cookie. It is possible to combine this action with the
>>> + * %OVS_ACTION_ATTR_TRUNC action to limit the size of the sample.
>>> + */
>>> +enum ovs_psample_attr {
>>> +OVS_PSAMPLE_ATTR_GROUP = 1,/* u32 number. */
>>> +OVS_PSAMPLE_ATTR_COOKIE,   /* Optional, user specified cookie. 
>>> */
>>> +
>>> +/* private: */
>>> +__OVS_PSAMPLE_ATTR_MAX
>>> +};
>>> +
>>> +#define OVS_PSAMPLE_ATTR_MAX (__OVS_PSAMPLE_ATTR_MAX - 1)
>>> +
>>>  /**
>>>   * enum ovs_action_attr - Action types.
>>>   *
>>> @@ -1056,6 +1081,8 @@ struct check_pkt_len_arg {
>>>   * of l3 tunnel flag in the tun_flags field of OVS_ACTION_ATTR_ADD_MPLS
>>>   * argument.
>>>   * @OVS_ACTION_ATTR_DROP: Explicit drop action.
>>> + * @OVS_ACTION_ATTR_PSAMPLE: Send a sample of the packet to external 
>>> observers
>>> + * via psample.
>>>   */
>>>
>>>  enum ovs_action_attr {
>>> @@ -1087,6 +1114,7 @@ enum ovs_action_attr {
>>> OVS_ACTION_ATTR_ADD_MPLS, /* struct ovs_action_add_mpls. */
>>> OVS_ACTION_ATTR_DEC_TTL,  /* Nested OVS_DEC_TTL_ATTR_*. */
>>> OVS_ACTION_ATTR_DROP, /* u32 xlate_error. */
>>> +   OVS_ACTION_ATTR_PSAMPLE,  /* Nested OVS_PSAMPLE_ATTR_*. */
>>>
>>>  #ifndef __KERNEL__
>>> OVS_ACTION_ATTR_TUNNEL_PUSH,   /* struct ovs_action_push_tnl*/
>>> diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
>>> index c7f9e1490..f0594e5f5 100644
>>> --- a/lib/dpif-netdev.c
>>> +++ b/lib/dpif-netdev.c
>>> @@ -9519,6 +9519,7 @@ dp_execute_cb(void *aux_, struct dp_packet_batch 
>>> *packets_,
>>>  case OVS_ACTION_ATTR_DROP:
>>>  case OVS_ACTION_ATTR_ADD_MPLS:
>>>  case OVS_ACTION_ATTR_DEC_TTL:
>>> +case OVS_ACTION_ATTR_PSAMPLE:
>>>  case __OVS_ACTION_ATTR_MAX:
>>>  OVS_NOT_REACHED();
>>>  }
>>> diff --git a/lib/dpif.c b/lib/dpif.c
>>> index 23eb18495..71728badc 100644
>>> --- a/lib/dpif.c
>>> +++ b/lib/dpif.c
>>> @@ -1192,6 +1192,7 @@ dpif_execute_helper_cb(void *aux_, struct 
>>> dp_packet_batch *packets_,
>>>  case OVS_ACTION_ATTR_TUNNEL_PUSH:
>>>  case OVS_ACTION_ATTR_TUNNEL_POP:
>>>  case OVS_ACTION_ATTR_USERSPACE:
>>> +case OVS_ACTION_ATTR_PSAMPLE:
>>>  case OVS_ACTION_ATTR_RECIRC: {
>>>  struct dpif_execute execute;
>>>  struct ofpbuf execute_actions;
>>> diff --git a/lib/odp-execute.c b/lib/odp-execute.c
>>> index 081e4d432..15577d539 100644
>>> --- a/lib/odp-execute.c
>>> +++ b/lib/odp-execute.c
>>> @@ -818,13 +818,13 @@ requires_datapath_assistance(const struct nlattr *a)
>>>  case OVS_ACTION_ATTR_RECIRC:
>>>  case OVS_ACTION_ATTR_CT:
>>>  case OVS_ACTION_ATTR_METER:
>>> +case OVS_ACTION_ATTR_PSAMPLE:
>>>  return true;
>>>
>>>  case OVS_ACTION_ATTR_SET:
>>>  case OVS_ACTION_ATTR_SET_MASKED:
>>>  case OVS_ACTION_ATTR_PUSH_VLAN:
>>>  case OVS_ACTION_ATTR_POP_VLAN:
>>> -case OVS_ACTION_ATTR_SAMPLE:
>>>  case OVS_ACTION_ATTR_HASH:
>>>  case OVS_ACTION_ATTR_PUSH_MPLS:
>>>  case OVS_ACTION_ATTR_POP_MPLS:
>>> @@ -841,6 +841,28 @@ requires_datapath_assistance(const struct nlattr *a)
>>>  case OVS_ACTION_ATTR_DROP:
>>>  return false;
>>>
>>> +

Re: [ovs-dev] [PATCH v1 02/13] odp-util: Add support OVS_ACTION_ATTR_PSAMPLE.

2024-07-10 Thread Adrián Moreno
On Wed, Jul 10, 2024 at 12:56:57PM GMT, Ilya Maximets wrote:
> On 7/7/24 22:08, Adrian Moreno wrote:
> > Add support for parsing and formatting the new action.
> >
> > Also, flag OVS_ACTION_ATTR_SAMPLE as requiring datapath assistance if it
> > contains a nested OVS_ACTION_ATTR_PSAMPLE. The reason is that the
> > sampling rate form the parent "sample" is made available to the nested
> > "psample" by the kernel.
> >
> > Signed-off-by: Adrian Moreno 
> > ---
> >  include/linux/openvswitch.h  | 28 +++
> >  lib/dpif-netdev.c|  1 +
> >  lib/dpif.c   |  1 +
> >  lib/odp-execute.c| 25 +-
> >  lib/odp-util.c   | 93 
> >  lib/odp-util.h   |  3 ++
> >  ofproto/ofproto-dpif-ipfix.c |  1 +
> >  ofproto/ofproto-dpif-sflow.c |  1 +
> >  python/ovs/flow/odp.py   |  8 
> >  tests/odp.at | 16 +++
> >  10 files changed, 176 insertions(+), 1 deletion(-)
> >
> > diff --git a/include/linux/openvswitch.h b/include/linux/openvswitch.h
> > index d9fb991ef..0023b65fb 100644
> > --- a/include/linux/openvswitch.h
> > +++ b/include/linux/openvswitch.h
> > @@ -992,6 +992,31 @@ struct check_pkt_len_arg {
> >  };
> >  #endif
> >
> > +#define OVS_PSAMPLE_COOKIE_MAX_SIZE 16
> > +/**
> > + * enum ovs_pample_attr - Attributes for %OVS_ACTION_ATTR_PSAMPLE
> > + * action.
> > + *
> > + * @OVS_PSAMPLE_ATTR_GROUP: 32-bit number to identify the source of the
> > + * sample.
> > + * @OVS_PSAMPLE_ATTR_COOKIE: An optional variable-length binary cookie that
> > + * contains user-defined metadata. The maximum length is
> > + * OVS_PSAMPLE_COOKIE_MAX_SIZE bytes.
> > + *
> > + * Sends the packet to the psample multicast group with the specified 
> > group and
> > + * cookie. It is possible to combine this action with the
> > + * %OVS_ACTION_ATTR_TRUNC action to limit the size of the sample.
> > + */
> > +enum ovs_psample_attr {
> > +OVS_PSAMPLE_ATTR_GROUP = 1,/* u32 number. */
> > +OVS_PSAMPLE_ATTR_COOKIE,   /* Optional, user specified cookie. 
> > */
> > +
> > +/* private: */
> > +__OVS_PSAMPLE_ATTR_MAX
> > +};
> > +
> > +#define OVS_PSAMPLE_ATTR_MAX (__OVS_PSAMPLE_ATTR_MAX - 1)
> > +
> >  /**
> >   * enum ovs_action_attr - Action types.
> >   *
> > @@ -1056,6 +1081,8 @@ struct check_pkt_len_arg {
> >   * of l3 tunnel flag in the tun_flags field of OVS_ACTION_ATTR_ADD_MPLS
> >   * argument.
> >   * @OVS_ACTION_ATTR_DROP: Explicit drop action.
> > + * @OVS_ACTION_ATTR_PSAMPLE: Send a sample of the packet to external 
> > observers
> > + * via psample.
> >   */
> >
> >  enum ovs_action_attr {
> > @@ -1087,6 +1114,7 @@ enum ovs_action_attr {
> > OVS_ACTION_ATTR_ADD_MPLS, /* struct ovs_action_add_mpls. */
> > OVS_ACTION_ATTR_DEC_TTL,  /* Nested OVS_DEC_TTL_ATTR_*. */
> > OVS_ACTION_ATTR_DROP, /* u32 xlate_error. */
> > +   OVS_ACTION_ATTR_PSAMPLE,  /* Nested OVS_PSAMPLE_ATTR_*. */
> >
> >  #ifndef __KERNEL__
> > OVS_ACTION_ATTR_TUNNEL_PUSH,   /* struct ovs_action_push_tnl*/
> > diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
> > index c7f9e1490..f0594e5f5 100644
> > --- a/lib/dpif-netdev.c
> > +++ b/lib/dpif-netdev.c
> > @@ -9519,6 +9519,7 @@ dp_execute_cb(void *aux_, struct dp_packet_batch 
> > *packets_,
> >  case OVS_ACTION_ATTR_DROP:
> >  case OVS_ACTION_ATTR_ADD_MPLS:
> >  case OVS_ACTION_ATTR_DEC_TTL:
> > +case OVS_ACTION_ATTR_PSAMPLE:
> >  case __OVS_ACTION_ATTR_MAX:
> >  OVS_NOT_REACHED();
> >  }
> > diff --git a/lib/dpif.c b/lib/dpif.c
> > index 23eb18495..71728badc 100644
> > --- a/lib/dpif.c
> > +++ b/lib/dpif.c
> > @@ -1192,6 +1192,7 @@ dpif_execute_helper_cb(void *aux_, struct 
> > dp_packet_batch *packets_,
> >  case OVS_ACTION_ATTR_TUNNEL_PUSH:
> >  case OVS_ACTION_ATTR_TUNNEL_POP:
> >  case OVS_ACTION_ATTR_USERSPACE:
> > +case OVS_ACTION_ATTR_PSAMPLE:
> >  case OVS_ACTION_ATTR_RECIRC: {
> >  struct dpif_execute execute;
> >  struct ofpbuf execute_actions;
> > diff --git a/lib/odp-execute.c b/lib/odp-execute.c
> > index 081e4d432..15577d539 100644
> > --- a/lib/odp-execute.c
> > +++ b/lib/odp-execute.c
> > @@ -818,13 +818,13 @@ requires_datapath_assistance(const struct nlattr *a)
> >  case OVS_ACTION_ATTR_RECIRC:
> >  case OVS_ACTION_ATTR_CT:
> >  case OVS_ACTION_ATTR_METER:
> > +case OVS_ACTION_ATTR_PSAMPLE:
> >  return true;
> >
> >  case OVS_ACTION_ATTR_SET:
> >  case OVS_ACTION_ATTR_SET_MASKED:
> >  case OVS_ACTION_ATTR_PUSH_VLAN:
> >  case OVS_ACTION_ATTR_POP_VLAN:
> > -case OVS_ACTION_ATTR_SAMPLE:
> >  case OVS_ACTION_ATTR_HASH:
> >  case OVS_ACTION_ATTR_PUSH_MPLS:
> >  case OVS_ACTION_ATTR_POP_MPLS:
> > @@ -841,6 +841,28 @@ requires_datapath_assistance(const struct nlattr *a)
> >  case OVS_ACTION_ATTR_DROP:
> >  return false;
> >
> > +case OVS_ACTION_ATTR_SAMPLE: {
> > +   

Re: [ovs-dev] [PATCH ovn 8/8] northd: Add ACL Sampling.

2024-07-10 Thread Dumitru Ceara
On 7/9/24 13:27, Adrián Moreno wrote:
> On Mon, Jul 08, 2024 at 01:24:14PM GMT, Dumitru Ceara wrote:
>> From: Adrian Moreno 
>>
>> Introduce a new table called Sample where per-flow IPFIX configuration
>> can be specified.
>> Also, reference rows from such table from the ACL table to enable the
>> configuration of ACL sampling. If enabled, northd will add a sample
>> action to each ACL related logical flow.
>>
>> Packets that hit stateful ACLs are sampled in different ways depending
>> whether they are initiating a new session or are just forwarded on an
>> existing (already allowed) session.  Two new columns ("sample_new" and
>> "sample_est") are added to the ACL table to allow for potentially
>> different sampling rates for the two cases.
>>
>> Note: If an ACL has both sampling enabled and a label associated to it
>> then the label value overrides the observation point ID defined in the
>> sample configuration.  This is a side effect of the implementation
>> (observation point IDs are stored in conntrack in the same part of the
>> ct_label where ACL labels are also stored).  The two features
>> (sampling and ACL labels) serve however similar purposes so it's not
>> expected that they're both enabled together.
>>
>> When sampling is enabled on an ACL additional logical flows are created
>> for that ACL (one for stateless ACLs and 3 for stateful ACLs) in the ACL
>> action stage of the logical pipeline.  These additional flows match on a
>> combination of conntrack state values and observation point id values
>> (either against a logical register or against the stored ct_label state)
>> in order to determine whether the packets hitting the ACLs must be
>> sampled or not.  This comes with a slight increase in the number of
>> logical flows and in the number of OpenFlow rules.  The number of
>> additional flows _does not_ depend on the original ACL match or action.
>>
>> New --sample-new and --sample-est optional arguments are added to the
>> 'ovn-nbctl acl-add' command to allow configuring these new types of
>> sampling for ACLs.
>>
>> An example workflow of configuring ACL samples is:
>>   # Create Sampling_App mappings for ACL traffic types:
>>   ovn-nbctl create Sampling_App name="acl-new-traffic-sampling" \
>> id="42"
>>   ovn-nbctl create sampling_app name="acl-est-traffic-sampling" \
>>  id="43"
>>   # Create two sample collectors, one that samples all packets (c1)
>>   # and another one that samples with a probability of 10% (c2):
>>   c1=$(ovn-nbctl create Sample_Collector name=c1 \
>>probability=65535 set_id=1)
>>   c2=$(ovn-nbctl create Sample_Collector name=c2 \
>>probability=6553 set_id=2)
>>   # Create two sample configurations (for new and for established
>>   # traffic):
>>   s1=$(ovn-nbctl create sample collector="$c1 $c2" metadata=4301)
>>   s2=$(ovn-nbctl create sample collector="$c1 $c2" metadata=4302)
>>   # Create an ingress ACL to allow IP traffic:
>>   ovn-nbctl --sample-new=$s1 --sample-est=$s2 acl-add ls \
>> from-lport 1 "ip" allow-related
>>
>> The config above will generate IPFIX samples with:
>> - observation domain id set to 42 (Sampling_App
>>   "acl-new-traffic-sampling" config) and observation point id
>>   set to 4301 (Sample s1) for packets that create a new
>>   connection
>> - observation domain id set to 43 (Sampling_app
>>   "acl-est-traffic-sampling" config) and observation point id
>>   set to 4302 (Sample s2) for packets that are part of an already
>>   existing connection
>>
> 
> We assume the dp_key is 0 in this case, right? Maybe worth mentioning
> it.
> 

Well, it will never be 0, I'll update this to mention that the
observation domain ID includes the datapath binding key and this
configured value.

>> Reported-at: https://issues.redhat.com/browse/FDP-305
>> Signed-off-by: Adrian Moreno 
>> Co-authored-by: Dumitru Ceara 
>> Signed-off-by: Dumitru Ceara 
>> ---
>>  NEWS   |   3 +
>>  include/ovn/logical-fields.h   |   2 +
>>  lib/logical-fields.c   |   6 +
>>  northd/northd.c| 519 +++--
>>  northd/ovn-northd.8.xml|  26 ++
>>  ovn-nb.ovsschema   |  44 ++-
>>  ovn-nb.xml |  56 +++
>>  tests/atlocal.in   |   6 +
>>  tests/ovn-macros.at|   4 +
>>  tests/ovn-nbctl.at |  20 +
>>  tests/ovn-northd.at| 240 ++--
>>  tests/ovn.at   |   3 +
>>  tests/system-common-macros.at  |  11 +
>>  tests/system-ovn.at| 149 +++
>>  utilities/containers/fedora/Dockerfile |   1 +
>>  utilities/containers/ubuntu/Dockerfile |   1 +
>>  utilities/ovn-nbctl.8.xml  |   8 +-
>>  utilities/ovn-nbctl.c  |  43 +-
>>  18 files changed, 1079 insertions(+), 63 deletions(-)
> 
> I'm 

Re: [ovs-dev] [PATCH ovn] controller: Add lsp option disable_garp_rarp.

2024-07-10 Thread Shibir Basak
Hi,

Yes, that’s right.

Let’s say, the VM is getting copied to the destination AZ or say it is not yet 
ready to process any traffic, yet.
In such cases we may want OVN to avoid sending RARP/GARP early and lead to 
traffic outage.

Thanks,
Shibir
From: Ales Musil 
Date: Wednesday, 10 July 2024 at 4:20 PM
To: Shibir Basak 
Cc: d...@openvswitch.org 
Subject: Re: [ovs-dev] [PATCH ovn] controller: Add lsp option disable_garp_rarp.
On Wed, Jul 10, 2024 at 12: 26 PM Shibir Basak  
wrote: Hi Ales, The use case we are trying to address is not limited to 
migration within a local AZ. Here, the VM can also be migrated across AZs and 
it is supposed
ZjQcmQRYFpfptBannerStart
CAUTION: External Email

ZjQcmQRYFpfptBannerEnd


On Wed, Jul 10, 2024 at 12:26 PM Shibir Basak 
mailto:shibir.ba...@nutanix.com>> wrote:
Hi Ales,

The use case we are trying to address is not limited to migration within a 
local AZ.
Here, the VM can also be migrated across AZs and it is supposed to retain the 
same MAC & IP addresses.
Hence, requested-chassis along with LSP option "activation-strategy" is not 
applicable for such a case.

Thanks,
Shibir


Hi,

so to make sure I understand the use case, you are migrating
across AZ, and to make it faster you are creating an LSP with
the same IP + MAC on the second AZ in advance. But because
the VM is not there yet you don't want to announce that to the
ToR switch is that assumption correct?


From: Ales Musil mailto:amu...@redhat.com>>
Date: Wednesday, 10 July 2024 at 12:40 PM
To: Shibir Basak mailto:shibir.ba...@nutanix.com>>
Cc: d...@openvswitch.org 
mailto:d...@openvswitch.org>>
Subject: Re: [ovs-dev] [PATCH ovn] controller: Add lsp option disable_garp_rarp.
On Tue, Jul 9, 2024 at 7: 57 AM Shibir Basak  
wrote: If the lsp option 'disable_garp_rarp' is set to true, GARP and RARP 
announcements are not sent by ovn when a VIF port is created on a bridged 
logical
ZjQcmQRYFpfptBannerStart
CAUTION: External Email

ZjQcmQRYFpfptBannerEnd


On Tue, Jul 9, 2024 at 7:57 AM Shibir Basak 
mailto:shibir.ba...@nutanix.com>> wrote:
If the lsp option 'disable_garp_rarp' is set to true,
GARP and RARP announcements are not sent by ovn when a
VIF port is created on a bridged logical switch.

Usecase

This option is useful during VM migration to let the
hypervisor/VM send the RARP/GARP once VM is ready to
process the packets post migration. This helps to reduce
downtime during VM migration.

Signed-off-by: Shibir Basak 
mailto:shibir.ba...@nutanix.com>>
Acked-by: Naveen Yerramneni 
mailto:naveen.yerramn...@nutanix.com>>

Hello,

I would like to avoid yet another config option, have you considered
using "activation-strategy" LSP option along with setting multiple
requested-chassis during the migration process? This should ensure
that the downtime is actually as low as possible. See presentation
from Ihar about this specific option [0].

---
 controller/pinctrl.c |  4 +--
 ovn-nb.xml   |  7 +
 tests/ovn.at 
[ovn.at]
 | 68 
 3 files changed, 77 insertions(+), 2 deletions(-)

diff --git a/controller/pinctrl.c b/controller/pinctrl.c
index 9a2f3f5b3..800c85d21 100644
--- a/controller/pinctrl.c
+++ b/controller/pinctrl.c
@@ -6618,7 +6618,7 @@ send_garp_rarp_prepare(struct ovsdb_idl_txn 
*ovnsb_idl_txn,
 SSET_FOR_EACH (iface_id, _vifs) {
 const struct sbrec_port_binding *pb = lport_lookup_by_name(
 sbrec_port_binding_by_name, iface_id);
-if (pb) {
+if (pb && !smap_get_bool(>options, "disable_garp_rarp", false)) {
 send_garp_rarp_update(ovnsb_idl_txn,
   sbrec_mac_binding_by_lport_ip,
   local_datapaths, pb, _addresses,
@@ -6631,7 +6631,7 @@ send_garp_rarp_prepare(struct ovsdb_idl_txn 
*ovnsb_idl_txn,
 SSET_FOR_EACH (gw_port, _l3gw_ports) {
 const struct sbrec_port_binding *pb
 = lport_lookup_by_name(sbrec_port_binding_by_name, gw_port);
-if (pb) {
+if (pb && !smap_get_bool(>options, "disable_garp_rarp", false)) {
 send_garp_rarp_update(ovnsb_idl_txn, sbrec_mac_binding_by_lport_ip,
   local_datapaths, pb, _addresses,
   garp_max_timeout, garp_continuous);
diff --git a/ovn-nb.xml b/ovn-nb.xml
index 9552534f6..3a0f0e34d 100644
--- a/ovn-nb.xml
+++ b/ovn-nb.xml
@@ -1290,6 +1290,13 @@
   The default value is false.
 

+
+  If set to true, GARP and RARP announcements are not
+  sent when a VIF port is created on a bridged logical switch.
+  The default value is false.
+
+
 
   If set to 

[ovs-dev] [PATCH v9] rhel: Make the version, displayed to the user, customizable.

2024-07-10 Thread Timothy Redaelli
Since on CentOS/RHEL the builds are based on stable branches and not on
tags for debugging purpose it's better to have the downstream version as
version so it's easier to know which commits are included in a build.

This commit adds --with-version-suffix as ./configure option in
order to set an OVS version suffix that should be shown to the user via
ovs-vsctl -V and, so, also on database, on ovs-vsctl show and the other
utilities.

--with-version-suffix is used in Fedora/CentOS/RHEL spec file in order to have
the version be aligned with the downstream one.

Signed-off-by: Timothy Redaelli 
---
v1 -> v2: Use --with-version-suffix= and add version to other utilies
  (as requested by Ilya).

v2 -> v3: Add versioning to python utilities and python library itself
  (as suggested by Aaron).

v3 -> v4: Remove versioning to python library itself to avoid breaking
  PEP440 (as requested by Ilya). Versioning is still used in
  python utilities.

v4 -> v5: Re-add versioning to python library itself, but don't use it on
  setup.py (to avoid breaking PEP440). This will permit to have the
  custom version as ovs.version.VERSION (in case somebody uses it) and,
  so, also in python/ovs/unixctl/server.py (as suggested by Ilya).

v5 -> v6: Fix some setup.py leftovers and change the test as a loop
  (as suggested by Ilya).

v6 -> v7: Rebase with last master (it should pass CI now)

v7 -> v8: Be sure python-sdist depends on python/setup.py and run flake8 on
  setup.py.template instead of setup.py (as suggested by Ilya).
  Fix commit summary to make checkpatch.py happy

v8 -> v9: Fix make distcheck when --with-version-suffix is specified (as
  repoted by Ilya). I know AM_DISTCHECK_CONFIGURE_FLAGS is
  discouraged upstream, but it's also used by GNU m4 for a similar
  scenario so I guess it's ok to use it (see
  
https://www.gnu.org/software/automake/manual/html_node/Checking-the-Distribution.html)
  Restore the loop in setup.py.template (as reported by Ilya)
  Use version suffixalso for libraries (aka test-lib) (as reported by 
Ilya)
  Fix a typo in configure (as reported by Ilya)
---
 Makefile.am|  3 +++
 acinclude.m4   | 13 
 configure.ac   |  1 +
 include/openvswitch/version.h.in   |  2 +-
 lib/ovsdb-error.c  |  2 +-
 lib/util.c |  8 +---
 ovsdb/ovsdb-server.c   |  3 ++-
 python/.gitignore  |  1 +
 python/automake.mk | 22 +---
 python/{setup.py => setup.py.template} | 28 +-
 rhel/openvswitch-fedora.spec.in|  1 +
 utilities/ovs-dpctl-top.in |  2 +-
 utilities/ovs-lib.in   |  2 +-
 utilities/ovs-parse-backtrace.in   |  2 +-
 utilities/ovs-pcap.in  |  2 +-
 utilities/ovs-pki.in   |  2 +-
 utilities/ovs-tcpdump.in   |  4 ++--
 utilities/ovs-tcpundump.in |  2 +-
 utilities/ovs-vlan-test.in |  2 +-
 vswitchd/bridge.c  |  3 ++-
 20 files changed, 64 insertions(+), 41 deletions(-)
 rename python/{setup.py => setup.py.template} (87%)

diff --git a/Makefile.am b/Makefile.am
index e6c90a911..e8f13d76b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -8,6 +8,8 @@
 AUTOMAKE_OPTIONS = foreign subdir-objects
 ACLOCAL_AMFLAGS = -I m4
 
+AM_DISTCHECK_CONFIGURE_FLAGS = --with-version-suffix=$(VERSION_SUFFIX)
+
 AM_CPPFLAGS = $(SSL_CFLAGS)
 AM_LDFLAGS = $(SSL_LDFLAGS)
 AM_LDFLAGS += $(OVS_LDFLAGS)
@@ -163,6 +165,7 @@ SUFFIXES += .in
-e 's,[@]PYTHON3[@],$(PYTHON3),g' \
-e 's,[@]RUNDIR[@],$(RUNDIR),g' \
-e 's,[@]VERSION[@],$(VERSION),g' \
+   -e 's,[@]VERSION_SUFFIX[@],$(VERSION_SUFFIX),g' \
-e 's,[@]localstatedir[@],$(localstatedir),g' \
-e 's,[@]pkgdatadir[@],$(pkgdatadir),g' \
-e 's,[@]sysconfdir[@],$(sysconfdir),g' \
diff --git a/acinclude.m4 b/acinclude.m4
index f1ba046c2..1ace70c92 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -497,6 +497,19 @@ AC_DEFUN([OVS_CHECK_DPDK], [
   AM_CONDITIONAL([DPDK_NETDEV], test "$DPDKLIB_FOUND" = true)
 ])
 
+dnl Append a version suffix.
+
+AC_DEFUN([OVS_CHECK_VERSION_SUFFIX], [
+  AC_ARG_WITH([version-suffix],
+  [AS_HELP_STRING([--with-version-suffix=ver_suffix],
+  [Specify a string that will be appended
+   to OVS version])])
+  AC_DEFINE_UNQUOTED([VERSION_SUFFIX], ["$with_version_suffix"],
+ [Package version suffix])
+  AC_SUBST([VERSION_SUFFIX], [$with_version_suffix])
+  ])
+])
+
 dnl Checks for net/if_dl.h.
 dnl
 dnl (We use this as a proxy for checking whether we're building on FreeBSD
diff --git a/configure.ac b/configure.ac
index 

Re: [ovs-dev] [PATCH v1 02/13] odp-util: Add support OVS_ACTION_ATTR_PSAMPLE.

2024-07-10 Thread Ilya Maximets
On 7/7/24 22:08, Adrian Moreno wrote:
> Add support for parsing and formatting the new action.
> 
> Also, flag OVS_ACTION_ATTR_SAMPLE as requiring datapath assistance if it
> contains a nested OVS_ACTION_ATTR_PSAMPLE. The reason is that the
> sampling rate form the parent "sample" is made available to the nested
> "psample" by the kernel.
> 
> Signed-off-by: Adrian Moreno 
> ---
>  include/linux/openvswitch.h  | 28 +++
>  lib/dpif-netdev.c|  1 +
>  lib/dpif.c   |  1 +
>  lib/odp-execute.c| 25 +-
>  lib/odp-util.c   | 93 
>  lib/odp-util.h   |  3 ++
>  ofproto/ofproto-dpif-ipfix.c |  1 +
>  ofproto/ofproto-dpif-sflow.c |  1 +
>  python/ovs/flow/odp.py   |  8 
>  tests/odp.at | 16 +++
>  10 files changed, 176 insertions(+), 1 deletion(-)
> 
> diff --git a/include/linux/openvswitch.h b/include/linux/openvswitch.h
> index d9fb991ef..0023b65fb 100644
> --- a/include/linux/openvswitch.h
> +++ b/include/linux/openvswitch.h
> @@ -992,6 +992,31 @@ struct check_pkt_len_arg {
>  };
>  #endif
>  
> +#define OVS_PSAMPLE_COOKIE_MAX_SIZE 16
> +/**
> + * enum ovs_pample_attr - Attributes for %OVS_ACTION_ATTR_PSAMPLE
> + * action.
> + *
> + * @OVS_PSAMPLE_ATTR_GROUP: 32-bit number to identify the source of the
> + * sample.
> + * @OVS_PSAMPLE_ATTR_COOKIE: An optional variable-length binary cookie that
> + * contains user-defined metadata. The maximum length is
> + * OVS_PSAMPLE_COOKIE_MAX_SIZE bytes.
> + *
> + * Sends the packet to the psample multicast group with the specified group 
> and
> + * cookie. It is possible to combine this action with the
> + * %OVS_ACTION_ATTR_TRUNC action to limit the size of the sample.
> + */
> +enum ovs_psample_attr {
> +OVS_PSAMPLE_ATTR_GROUP = 1,/* u32 number. */
> +OVS_PSAMPLE_ATTR_COOKIE,   /* Optional, user specified cookie. */
> +
> +/* private: */
> +__OVS_PSAMPLE_ATTR_MAX
> +};
> +
> +#define OVS_PSAMPLE_ATTR_MAX (__OVS_PSAMPLE_ATTR_MAX - 1)
> +
>  /**
>   * enum ovs_action_attr - Action types.
>   *
> @@ -1056,6 +1081,8 @@ struct check_pkt_len_arg {
>   * of l3 tunnel flag in the tun_flags field of OVS_ACTION_ATTR_ADD_MPLS
>   * argument.
>   * @OVS_ACTION_ATTR_DROP: Explicit drop action.
> + * @OVS_ACTION_ATTR_PSAMPLE: Send a sample of the packet to external 
> observers
> + * via psample.
>   */
>  
>  enum ovs_action_attr {
> @@ -1087,6 +1114,7 @@ enum ovs_action_attr {
>   OVS_ACTION_ATTR_ADD_MPLS, /* struct ovs_action_add_mpls. */
>   OVS_ACTION_ATTR_DEC_TTL,  /* Nested OVS_DEC_TTL_ATTR_*. */
>   OVS_ACTION_ATTR_DROP, /* u32 xlate_error. */
> + OVS_ACTION_ATTR_PSAMPLE,  /* Nested OVS_PSAMPLE_ATTR_*. */
>  
>  #ifndef __KERNEL__
>   OVS_ACTION_ATTR_TUNNEL_PUSH,   /* struct ovs_action_push_tnl*/
> diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
> index c7f9e1490..f0594e5f5 100644
> --- a/lib/dpif-netdev.c
> +++ b/lib/dpif-netdev.c
> @@ -9519,6 +9519,7 @@ dp_execute_cb(void *aux_, struct dp_packet_batch 
> *packets_,
>  case OVS_ACTION_ATTR_DROP:
>  case OVS_ACTION_ATTR_ADD_MPLS:
>  case OVS_ACTION_ATTR_DEC_TTL:
> +case OVS_ACTION_ATTR_PSAMPLE:
>  case __OVS_ACTION_ATTR_MAX:
>  OVS_NOT_REACHED();
>  }
> diff --git a/lib/dpif.c b/lib/dpif.c
> index 23eb18495..71728badc 100644
> --- a/lib/dpif.c
> +++ b/lib/dpif.c
> @@ -1192,6 +1192,7 @@ dpif_execute_helper_cb(void *aux_, struct 
> dp_packet_batch *packets_,
>  case OVS_ACTION_ATTR_TUNNEL_PUSH:
>  case OVS_ACTION_ATTR_TUNNEL_POP:
>  case OVS_ACTION_ATTR_USERSPACE:
> +case OVS_ACTION_ATTR_PSAMPLE:
>  case OVS_ACTION_ATTR_RECIRC: {
>  struct dpif_execute execute;
>  struct ofpbuf execute_actions;
> diff --git a/lib/odp-execute.c b/lib/odp-execute.c
> index 081e4d432..15577d539 100644
> --- a/lib/odp-execute.c
> +++ b/lib/odp-execute.c
> @@ -818,13 +818,13 @@ requires_datapath_assistance(const struct nlattr *a)
>  case OVS_ACTION_ATTR_RECIRC:
>  case OVS_ACTION_ATTR_CT:
>  case OVS_ACTION_ATTR_METER:
> +case OVS_ACTION_ATTR_PSAMPLE:
>  return true;
>  
>  case OVS_ACTION_ATTR_SET:
>  case OVS_ACTION_ATTR_SET_MASKED:
>  case OVS_ACTION_ATTR_PUSH_VLAN:
>  case OVS_ACTION_ATTR_POP_VLAN:
> -case OVS_ACTION_ATTR_SAMPLE:
>  case OVS_ACTION_ATTR_HASH:
>  case OVS_ACTION_ATTR_PUSH_MPLS:
>  case OVS_ACTION_ATTR_POP_MPLS:
> @@ -841,6 +841,28 @@ requires_datapath_assistance(const struct nlattr *a)
>  case OVS_ACTION_ATTR_DROP:
>  return false;
>  
> +case OVS_ACTION_ATTR_SAMPLE: {
> +/* Nested "psample" actions rely on the datapath executing the
> + * parent "sample", storing the probability and making it available
> + * when the nested "psample" is run. */
> +const struct nlattr *attr;
> +unsigned int left;
> +
> +NL_NESTED_FOR_EACH 

Re: [ovs-dev] [PATCH ovn] controller: Add lsp option disable_garp_rarp.

2024-07-10 Thread Ales Musil
On Wed, Jul 10, 2024 at 12:26 PM Shibir Basak 
wrote:

> Hi Ales,
>
>
>
> The use case we are trying to address is not limited to migration within a
> local AZ.
>
> Here, the VM can also be migrated across AZs and it is supposed to retain
> the same MAC & IP addresses.
>
> Hence, requested-chassis along with LSP option "activation-strategy" is
> not applicable for such a case.
>
>
>
> Thanks,
>
> Shibir
>
>
>

Hi,

so to make sure I understand the use case, you are migrating
across AZ, and to make it faster you are creating an LSP with
the same IP + MAC on the second AZ in advance. But because
the VM is not there yet you don't want to announce that to the
ToR switch is that assumption correct?



> *From: *Ales Musil 
> *Date: *Wednesday, 10 July 2024 at 12:40 PM
> *To: *Shibir Basak 
> *Cc: *d...@openvswitch.org 
> *Subject: *Re: [ovs-dev] [PATCH ovn] controller: Add lsp option
> disable_garp_rarp.
>
> On Tue, Jul 9, 2024 at 7: 57 AM Shibir Basak 
> wrote: If the lsp option 'disable_garp_rarp' is set to true, GARP and RARP
> announcements are not sent by ovn when a VIF port is created on a bridged
> logical
>
> ZjQcmQRYFpfptBannerStart
>
> *CAUTION: External Email *
>
>
>
> ZjQcmQRYFpfptBannerEnd
>
>
>
>
>
> On Tue, Jul 9, 2024 at 7:57 AM Shibir Basak 
> wrote:
>
> If the lsp option 'disable_garp_rarp' is set to true,
> GARP and RARP announcements are not sent by ovn when a
> VIF port is created on a bridged logical switch.
>
> Usecase
> 
> This option is useful during VM migration to let the
> hypervisor/VM send the RARP/GARP once VM is ready to
> process the packets post migration. This helps to reduce
> downtime during VM migration.
>
> Signed-off-by: Shibir Basak 
> Acked-by: Naveen Yerramneni 
>
>
>
> Hello,
>
> I would like to avoid yet another config option, have you considered
> using "activation-strategy" LSP option along with setting multiple
> requested-chassis during the migration process? This should ensure
> that the downtime is actually as low as possible. See presentation
> from Ihar about this specific option [0].
>
>
>
> ---
>  controller/pinctrl.c |  4 +--
>  ovn-nb.xml   |  7 +
>  tests/ovn.at [ovn.at]
> 
>| 68 
>  3 files changed, 77 insertions(+), 2 deletions(-)
>
> diff --git a/controller/pinctrl.c b/controller/pinctrl.c
> index 9a2f3f5b3..800c85d21 100644
> --- a/controller/pinctrl.c
> +++ b/controller/pinctrl.c
> @@ -6618,7 +6618,7 @@ send_garp_rarp_prepare(struct ovsdb_idl_txn
> *ovnsb_idl_txn,
>  SSET_FOR_EACH (iface_id, _vifs) {
>  const struct sbrec_port_binding *pb = lport_lookup_by_name(
>  sbrec_port_binding_by_name, iface_id);
> -if (pb) {
> +if (pb && !smap_get_bool(>options, "disable_garp_rarp",
> false)) {
>  send_garp_rarp_update(ovnsb_idl_txn,
>sbrec_mac_binding_by_lport_ip,
>local_datapaths, pb, _addresses,
> @@ -6631,7 +6631,7 @@ send_garp_rarp_prepare(struct ovsdb_idl_txn
> *ovnsb_idl_txn,
>  SSET_FOR_EACH (gw_port, _l3gw_ports) {
>  const struct sbrec_port_binding *pb
>  = lport_lookup_by_name(sbrec_port_binding_by_name, gw_port);
> -if (pb) {
> +if (pb && !smap_get_bool(>options, "disable_garp_rarp",
> false)) {
>  send_garp_rarp_update(ovnsb_idl_txn,
> sbrec_mac_binding_by_lport_ip,
>local_datapaths, pb, _addresses,
>garp_max_timeout, garp_continuous);
> diff --git a/ovn-nb.xml b/ovn-nb.xml
> index 9552534f6..3a0f0e34d 100644
> --- a/ovn-nb.xml
> +++ b/ovn-nb.xml
> @@ -1290,6 +1290,13 @@
>The default value is false.
>  
>
> + +type='{"type": "boolean"}'>
> +  If set to true, GARP and RARP announcements are not
> +  sent when a VIF port is created on a bridged logical switch.
> +  The default value is false.
> +
> +
>type='{"type": "string", "enum": ["set",
> ["mc_unknown"]]}'>
>If set to mc_unknown, packets going to this VIF get cloned to
> all
> diff --git a/tests/ovn.at [ovn.at]
> 
> b/tests/ovn.at [ovn.at]
> 
> 

Re: [ovs-dev] [PATCH ovn] controller: Add lsp option disable_garp_rarp.

2024-07-10 Thread Shibir Basak
Hi Ales,

The use case we are trying to address is not limited to migration within a 
local AZ.
Here, the VM can also be migrated across AZs and it is supposed to retain the 
same MAC & IP addresses.
Hence, requested-chassis along with LSP option "activation-strategy" is not 
applicable for such a case.

Thanks,
Shibir

From: Ales Musil 
Date: Wednesday, 10 July 2024 at 12:40 PM
To: Shibir Basak 
Cc: d...@openvswitch.org 
Subject: Re: [ovs-dev] [PATCH ovn] controller: Add lsp option disable_garp_rarp.
On Tue, Jul 9, 2024 at 7: 57 AM Shibir Basak  
wrote: If the lsp option 'disable_garp_rarp' is set to true, GARP and RARP 
announcements are not sent by ovn when a VIF port is created on a bridged 
logical
ZjQcmQRYFpfptBannerStart
CAUTION: External Email

ZjQcmQRYFpfptBannerEnd


On Tue, Jul 9, 2024 at 7:57 AM Shibir Basak 
mailto:shibir.ba...@nutanix.com>> wrote:
If the lsp option 'disable_garp_rarp' is set to true,
GARP and RARP announcements are not sent by ovn when a
VIF port is created on a bridged logical switch.

Usecase

This option is useful during VM migration to let the
hypervisor/VM send the RARP/GARP once VM is ready to
process the packets post migration. This helps to reduce
downtime during VM migration.

Signed-off-by: Shibir Basak 
mailto:shibir.ba...@nutanix.com>>
Acked-by: Naveen Yerramneni 
mailto:naveen.yerramn...@nutanix.com>>

Hello,

I would like to avoid yet another config option, have you considered
using "activation-strategy" LSP option along with setting multiple
requested-chassis during the migration process? This should ensure
that the downtime is actually as low as possible. See presentation
from Ihar about this specific option [0].

---
 controller/pinctrl.c |  4 +--
 ovn-nb.xml   |  7 +
 tests/ovn.at 
[ovn.at]
 | 68 
 3 files changed, 77 insertions(+), 2 deletions(-)

diff --git a/controller/pinctrl.c b/controller/pinctrl.c
index 9a2f3f5b3..800c85d21 100644
--- a/controller/pinctrl.c
+++ b/controller/pinctrl.c
@@ -6618,7 +6618,7 @@ send_garp_rarp_prepare(struct ovsdb_idl_txn 
*ovnsb_idl_txn,
 SSET_FOR_EACH (iface_id, _vifs) {
 const struct sbrec_port_binding *pb = lport_lookup_by_name(
 sbrec_port_binding_by_name, iface_id);
-if (pb) {
+if (pb && !smap_get_bool(>options, "disable_garp_rarp", false)) {
 send_garp_rarp_update(ovnsb_idl_txn,
   sbrec_mac_binding_by_lport_ip,
   local_datapaths, pb, _addresses,
@@ -6631,7 +6631,7 @@ send_garp_rarp_prepare(struct ovsdb_idl_txn 
*ovnsb_idl_txn,
 SSET_FOR_EACH (gw_port, _l3gw_ports) {
 const struct sbrec_port_binding *pb
 = lport_lookup_by_name(sbrec_port_binding_by_name, gw_port);
-if (pb) {
+if (pb && !smap_get_bool(>options, "disable_garp_rarp", false)) {
 send_garp_rarp_update(ovnsb_idl_txn, sbrec_mac_binding_by_lport_ip,
   local_datapaths, pb, _addresses,
   garp_max_timeout, garp_continuous);
diff --git a/ovn-nb.xml b/ovn-nb.xml
index 9552534f6..3a0f0e34d 100644
--- a/ovn-nb.xml
+++ b/ovn-nb.xml
@@ -1290,6 +1290,13 @@
   The default value is false.
 

+
+  If set to true, GARP and RARP announcements are not
+  sent when a VIF port is created on a bridged logical switch.
+  The default value is false.
+
+
 
   If set to mc_unknown, packets going to this VIF get cloned to all
diff --git a/tests/ovn.at 
[ovn.at]
 b/tests/ovn.at 
[ovn.at]
index 87a64499f..a71a83394 100644
--- a/tests/ovn.at 
[ovn.at]
+++ b/tests/ovn.at 
[ovn.at]
@@ -25013,6 +25013,74 @@ 

Re: [ovs-dev] [PATCH v1 02/13] odp-util: Add support OVS_ACTION_ATTR_PSAMPLE.

2024-07-10 Thread Adrián Moreno
On Wed, Jul 10, 2024 at 01:01:03AM GMT, Ilya Maximets wrote:
> On 7/9/24 21:07, Adrián Moreno wrote:
> > On Tue, Jul 09, 2024 at 04:15:12PM GMT, Eelco Chaudron wrote:
> >>
> >>
> >> On 9 Jul 2024, at 15:30, Adrián Moreno wrote:
> >>
> >>> On Tue, Jul 09, 2024 at 11:45:15AM GMT, Eelco Chaudron wrote:
>  On 4 Jul 2024, at 9:52, Adrian Moreno wrote:
> 
> > Add support for parsing and formatting the new action.
> >
> > Also, flag OVS_ACTION_ATTR_SAMPLE as requiring datapath assistance if it
> > contains a nested OVS_ACTION_ATTR_PSAMPLE. The reason is that the
> > sampling rate form the parent "sample" is made available to the nested
> 
>  form -> from
> 
> > "psample" by the kernel.
> 
>  Two small comments below, the rest looks good.
> 
> > Signed-off-by: Adrian Moreno 
> > ---
> >  include/linux/openvswitch.h  | 28 +++
> >  lib/dpif-netdev.c|  1 +
> >  lib/dpif.c   |  1 +
> >  lib/odp-execute.c| 25 +-
> >  lib/odp-util.c   | 93 
> >  lib/odp-util.h   |  3 ++
> >  ofproto/ofproto-dpif-ipfix.c |  1 +
> >  ofproto/ofproto-dpif-sflow.c |  1 +
> >  python/ovs/flow/odp.py   |  8 
> >  tests/odp.at | 16 +++
> >  10 files changed, 176 insertions(+), 1 deletion(-)
> >
> > diff --git a/include/linux/openvswitch.h b/include/linux/openvswitch.h
> > index d9fb991ef..0023b65fb 100644
> > --- a/include/linux/openvswitch.h
> > +++ b/include/linux/openvswitch.h
> > @@ -992,6 +992,31 @@ struct check_pkt_len_arg {
> >  };
> >  #endif
> >
> > +#define OVS_PSAMPLE_COOKIE_MAX_SIZE 16
> > +/**
> > + * enum ovs_pample_attr - Attributes for %OVS_ACTION_ATTR_PSAMPLE
> > + * action.
> > + *
> > + * @OVS_PSAMPLE_ATTR_GROUP: 32-bit number to identify the source of the
> > + * sample.
> > + * @OVS_PSAMPLE_ATTR_COOKIE: An optional variable-length binary cookie 
> > that
> > + * contains user-defined metadata. The maximum length is
> > + * OVS_PSAMPLE_COOKIE_MAX_SIZE bytes.
> > + *
> > + * Sends the packet to the psample multicast group with the specified 
> > group and
> > + * cookie. It is possible to combine this action with the
> > + * %OVS_ACTION_ATTR_TRUNC action to limit the size of the sample.
> > + */
> > +enum ovs_psample_attr {
> > +OVS_PSAMPLE_ATTR_GROUP = 1,/* u32 number. */
> > +OVS_PSAMPLE_ATTR_COOKIE,   /* Optional, user specified 
> > cookie. */
> > +
> > +/* private: */
> 
>  None of the other definitions have this private marking, so I see no 
>  need to
>  start adding it here.
> >>>
> >>> OK. The uAPI file has it (requested by netdev maintainers) but I guess
> >>> it's kernel-specific and this file is not a blind copy of the uAPI
> >>> anyways so I think we can remove it. I'll do on the next version.
>
> I'd keep it.  There is no point in having this header different from
> the kernel one in places where it doesn't surve any purpose.
>
> >>>
> 
> > +__OVS_PSAMPLE_ATTR_MAX
> > +};
> > +
> > +#define OVS_PSAMPLE_ATTR_MAX (__OVS_PSAMPLE_ATTR_MAX - 1)
> > +
> >  /**
> >   * enum ovs_action_attr - Action types.
> >   *
> > @@ -1056,6 +1081,8 @@ struct check_pkt_len_arg {
> >   * of l3 tunnel flag in the tun_flags field of OVS_ACTION_ATTR_ADD_MPLS
> >   * argument.
> >   * @OVS_ACTION_ATTR_DROP: Explicit drop action.
> > + * @OVS_ACTION_ATTR_PSAMPLE: Send a sample of the packet to external 
> > observers
> > + * via psample.
> >   */
> >
> >  enum ovs_action_attr {
> > @@ -1087,6 +1114,7 @@ enum ovs_action_attr {
> > OVS_ACTION_ATTR_ADD_MPLS, /* struct ovs_action_add_mpls. */
> > OVS_ACTION_ATTR_DEC_TTL,  /* Nested OVS_DEC_TTL_ATTR_*. */
> > OVS_ACTION_ATTR_DROP, /* u32 xlate_error. */
> > +   OVS_ACTION_ATTR_PSAMPLE,  /* Nested OVS_PSAMPLE_ATTR_*. */
> >
> >  #ifndef __KERNEL__
> > OVS_ACTION_ATTR_TUNNEL_PUSH,   /* struct ovs_action_push_tnl*/
> > diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
> > index c7f9e1490..f0594e5f5 100644
> > --- a/lib/dpif-netdev.c
> > +++ b/lib/dpif-netdev.c
> > @@ -9519,6 +9519,7 @@ dp_execute_cb(void *aux_, struct dp_packet_batch 
> > *packets_,
> >  case OVS_ACTION_ATTR_DROP:
> >  case OVS_ACTION_ATTR_ADD_MPLS:
> >  case OVS_ACTION_ATTR_DEC_TTL:
> > +case OVS_ACTION_ATTR_PSAMPLE:
> >  case __OVS_ACTION_ATTR_MAX:
> >  OVS_NOT_REACHED();
> >  }
> > diff --git a/lib/dpif.c b/lib/dpif.c
> > index 23eb18495..71728badc 100644
> > --- a/lib/dpif.c
> > +++ b/lib/dpif.c
> > @@ -1192,6 +1192,7 @@ 

Re: [ovs-dev] [PATCH v1 12/13] ofproto: xlate: Make bridge-sampled drops explicit.

2024-07-10 Thread Eelco Chaudron


On 9 Jul 2024, at 21:31, Adrián Moreno wrote:

> On Tue, Jul 09, 2024 at 11:46:09AM GMT, Eelco Chaudron wrote:
>> On 7 Jul 2024, at 22:09, Adrian Moreno wrote:
>>
>>> The decision to add or not the explicit drop action is currently based
>>> on whether the resulting dp action list is empty or not.
>>>
>>> This is OK for most of the cases but if per-flow IPFIX/sFlow sampling
>>> is enabled on the bridge, it doesn't work as expected.
>>>
>>> Fix this by taking into account the size of these sampling actions.
>>
>> Same comments as on the previous patch.
>>
>>> Fixes: a13a0209750c ("userspace: Improved packet drop statistics.")
>>> Cc: anju.tho...@ericsson.com
>>> Signed-off-by: Adrian Moreno 
>>> ---
>>>  ofproto/ofproto-dpif-xlate.c |  5 ++--
>>>  tests/drop-stats.at  | 44 
>>>  tests/ofproto-dpif.at|  4 ++--
>>>  3 files changed, 49 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
>>> index 094fe5d72..323a58cbf 100644
>>> --- a/ofproto/ofproto-dpif-xlate.c
>>> +++ b/ofproto/ofproto-dpif-xlate.c
>>> @@ -8153,6 +8153,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out 
>>> *xout)
>>>  uint64_t action_set_stub[1024 / 8];
>>>  uint64_t frozen_actions_stub[1024 / 8];
>>>  uint64_t actions_stub[256 / 8];
>>> +size_t sample_actions_len = 0;
>>>  struct ofpbuf scratch_actions = OFPBUF_STUB_INITIALIZER(actions_stub);
>>>  struct xlate_ctx ctx = {
>>>  .xin = xin,
>>> @@ -8412,7 +8413,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out 
>>> *xout)
>>>  user_cookie_offset = compose_sflow_action();
>>>  compose_ipfix_action(, ODPP_NONE);
>>>  }
>>> -size_t sample_actions_len = ctx.odp_actions->size;
>>> +sample_actions_len = ctx.odp_actions->size;
>>>  bool ecn_drop = !tnl_process_ecn(flow);
>>>
>>>  if (!ecn_drop
>>> @@ -8575,7 +8576,7 @@ exit:
>>>  }
>>>
>>>  /* Install drop action if datapath supports explicit drop action. */
>>> -if (xin->odp_actions && !xin->odp_actions->size &&
>>> +if (xin->odp_actions && xin->odp_actions->size == sample_actions_len &&
>>>  ovs_explicit_drop_action_supported(ctx.xbridge->ofproto)) {
>>>  put_drop_action(xin->odp_actions, ctx.error);
>>
>> See other patch, do we need ctx.error here?
>
> Here we *do* need it.
>
> This is where it was originally placed to flag xlate errors. We are at
> the end of xlate_actions main function and the one place where we have
> gathered ctx.error.
>
> The change here is not to modify how the drop is added to the action
> list. What this change does is change the condition upon which it's
> added. Before we were checking if the action list was empty under the
> assumption that if do_xlate_actions does not fill in any action, it's a
> drop.
>
> However, if per-bridge IPFIX (or sFlow) is enabled, their corresponding
> actions are added _before_ calling do_xlate_actions. That's why this
> patch only makes the check compare the size of the actions with the one
> it had before calling do_xlate_actions.
>
> Calling do_xlate_actions can yield errors and we should definitely flag
> them.

You are right, I was too quick adding the comment :(

>>
>>>  }
>>> diff --git a/tests/drop-stats.at b/tests/drop-stats.at
>>> index 44c5cc35b..31782ac52 100644
>>> --- a/tests/drop-stats.at
>>> +++ b/tests/drop-stats.at
>>> @@ -192,6 +192,50 @@ ovs-appctl coverage/read-counter 
>>> drop_action_too_many_mpls_labels
>>>  OVS_VSWITCHD_STOP(["/|WARN|/d"])
>>>  AT_CLEANUP
>>>
>>> +AT_SETUP([drop-stats - sampling])
>>
>> Should this maybe be 'bridge sampling'?
>>
>
> Ack.
>
>>> +
>>> +OVS_VSWITCHD_START([dnl
>>> +set bridge br0 datapath_type=dummy \
>>> +protocols=OpenFlow10,OpenFlow13,OpenFlow14,OpenFlow15 -- \
>>> +add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1])
>>> +
>>> +AT_DATA([flows.txt], [dnl
>>> +table=0,in_port=1,actions=drop
>>> +])
>>> +
>>> +AT_CHECK([
>>> +ovs-ofctl del-flows br0
>>> +ovs-ofctl -Oopenflow13 add-flows br0 flows.txt
>>> +ovs-ofctl -Oopenflow13 dump-flows br0 | ofctl_strip | sort | grep 
>>> actions ], [0], [dnl
>>> + in_port=1 actions=drop
>>> +])
>>> +
>>> +AT_CHECK([ovs-vsctl -- set bridge br0 ipfix=@fix -- \
>>> +--id=@fix create ipfix targets=\"127.0.0.1:4739\" \
>>> +  sampling=1],
>>> + [0], [ignore])
>>> +
>>> +AT_CHECK([
>>> +ovs-appctl netdev-dummy/receive p1 
>>> 'in_port(1),packet_type(ns=0,id=0),eth(src=3a:6d:d2:09:9c:ab,dst=1e:2c:e9:2a:66:9e),ipv4(src=192.168.10.10,dst=192.168.10.30,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'
>>> +ovs-appctl netdev-dummy/receive p1 
>>> 'in_port(1),packet_type(ns=0,id=0),eth(src=3a:6d:d2:09:9c:ab,dst=1e:2c:e9:2a:66:9e),ipv4(src=192.168.10.10,dst=192.168.10.30,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'
>>> +ovs-appctl 

[ovs-dev] [PATCH net-next v2] selftests: openvswitch: retry instead of sleep

2024-07-10 Thread Adrian Moreno
There are a couple of places where the test script "sleep"s to wait for
some external condition to be met.

This is error prone, specially in slow systems (identified in CI by
"KSFT_MACHINE_SLOW=yes").

To fix this, add a "ovs_wait" function that tries to execute a command
a few times until it succeeds. The timeout used is set to 5s for
"normal" systems and doubled if a slow CI machine is detected.

This should make the following work:

$ vng --build  \
--config tools/testing/selftests/net/config \
--config kernel/configs/debug.config

$ vng --run . --user root -- "make -C tools/testing/selftests/ \
KSFT_MACHINE_SLOW=yes TARGETS=net/openvswitch run_tests"

Signed-off-by: Adrian Moreno 
---
 .../selftests/net/openvswitch/openvswitch.sh  | 45 +++
 .../selftests/net/openvswitch/ovs-dpctl.py|  1 +
 2 files changed, 38 insertions(+), 8 deletions(-)

diff --git a/tools/testing/selftests/net/openvswitch/openvswitch.sh 
b/tools/testing/selftests/net/openvswitch/openvswitch.sh
index bc71dbc18b21..cc0bfae2bafa 100755
--- a/tools/testing/selftests/net/openvswitch/openvswitch.sh
+++ b/tools/testing/selftests/net/openvswitch/openvswitch.sh
@@ -11,6 +11,11 @@ ksft_skip=4
 PAUSE_ON_FAIL=no
 VERBOSE=0
 TRACING=0
+WAIT_TIMEOUT=5
+
+if test "X$KSFT_MACHINE_SLOW" == "Xyes"; then
+   WAIT_TIMEOUT=10
+fi
 
 tests="
arp_pingeth-arp: Basic arp ping between 
two NS
@@ -29,6 +34,30 @@ info() {
[ $VERBOSE = 0 ] || echo $*
 }
 
+ovs_wait() {
+   info "waiting $WAIT_TIMEOUT s for: $@"
+
+   if "$@" ; then
+   info "wait succeeded immediately"
+   return 0
+   fi
+
+   # A quick re-check helps speed up small races in fast systems.
+   # However, fractional sleeps might not necessarily work.
+   local start=0
+   sleep 0.1 || { sleep 1; start=1; }
+
+   for (( i=start; i/dev/null 2>&1 || 
return 1
+   ovs_wait grep -q "userspace action command" $ovs_dir/s0.out || return 1
 
# client -> server samples should only contain the first 14 bytes of 
the packet.
-   grep -E "rate:4294967295,group:1,cookie:c0ffee data:[0-9a-f]{28}$" \
-$ovs_dir/stdout >/dev/null 2>&1 || return 1
-   grep -E "rate:4294967295,group:2,cookie:eeff0c" \
-$ovs_dir/stdout >/dev/null 2>&1 || return 1
+   ovs_wait grep -qE "rate:4294967295,group:1,cookie:c0ffee 
data:[0-9a-f]{28}$" \
+   $ovs_dir/stdout || return 1
+
+   ovs_wait grep -q "rate:4294967295,group:2,cookie:eeff0c" 
$ovs_dir/stdout || return 1
 
return 0
 }
@@ -711,7 +739,8 @@ test_upcall_interfaces() {
ovs_add_netns_and_veths "test_upcall_interfaces" ui0 upc left0 l0 \
172.31.110.1/24 -u || return 1
 
-   sleep 1
+   ovs_wait grep -q "listening on upcall packet handler" 
${ovs_dir}/left0.out
+
info "sending arping"
ip netns exec upc arping -I l0 172.31.110.20 -c 1 \
>$ovs_dir/arping.stdout 2>$ovs_dir/arping.stderr
diff --git a/tools/testing/selftests/net/openvswitch/ovs-dpctl.py 
b/tools/testing/selftests/net/openvswitch/ovs-dpctl.py
index 1e15b0818074..8a0396bfaf99 100644
--- a/tools/testing/selftests/net/openvswitch/ovs-dpctl.py
+++ b/tools/testing/selftests/net/openvswitch/ovs-dpctl.py
@@ -2520,6 +2520,7 @@ class PsampleEvent(EventSocket):
 marshal_class = psample_msg
 
 def read_samples(self):
+print("listening for psample events", flush=True)
 while True:
 try:
 for msg in self.get():
-- 
2.45.2

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


Re: [ovs-dev] [PATCH v5] netdev-offload-dpdk: Support offload of set dscp action.

2024-07-10 Thread Simon Horman
On Tue, Jul 09, 2024 at 09:18:17PM +0800, Sunyang Wu wrote:
> Add the "set dscp action" parsing function,
> so that the "set dscp action" can be offloaded.
> 
> Signed-off-by: Sunyang Wu 
> ---
>  Documentation/howto/dpdk.rst |  5 +++--
>  lib/netdev-offload-dpdk.c| 27 ++-
>  2 files changed, 29 insertions(+), 3 deletions(-)
> 
> diff --git a/Documentation/howto/dpdk.rst b/Documentation/howto/dpdk.rst
> index 04609b20b..f0e46c95b 100644
> --- a/Documentation/howto/dpdk.rst
> +++ b/Documentation/howto/dpdk.rst
> @@ -395,10 +395,11 @@ Supported actions for hardware offload are:
>  - Output.
>  - Drop.
>  - Modification of Ethernet (mod_dl_src/mod_dl_dst).
> -- Modification of IPv4 (mod_nw_src/mod_nw_dst/mod_nw_ttl).
> +- Modification of IPv4 (mod_nw_src/mod_nw_dst/mod_nw_ttl/mod_nw_tos).
>  - Modification of TCP/UDP (mod_tp_src/mod_tp_dst).
>  - VLAN Push/Pop (push_vlan/pop_vlan).
> -- Modification of IPv6 (set_field:->ipv6_src/ipv6_dst/mod_nw_ttl).
> +- Modification of IPv6 (set_field:->ipv6_src/ipv6_dst/
> +mod_nw_ttl/mod_nw_tos).
>  - Clone/output (tnl_push and output) for encapsulating over a tunnel.
>  - Tunnel pop, for packets received on physical ports.
>  

HI Sunyang Wu,

Unfortunately this causes building documentation to fail.

  Warning, treated as error:
  .../dpdk.rst:402:Bullet list ends without a blank line; unexpected unindent.

> diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c
> index 623005b1c..5a74c6d19 100644
> --- a/lib/netdev-offload-dpdk.c
> +++ b/lib/netdev-offload-dpdk.c
> @@ -791,6 +791,17 @@ dump_flow_action(struct ds *s, struct ds *s_extra,
>  ds_put_format(s, "port %"PRIu16" ", ntohs(set_tp->port));
>  }
>  ds_put_cstr(s, "/ ");
> +} else if (actions->type == RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP ||
> +   actions->type == RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP) {
> +const struct rte_flow_action_set_dscp *set_dscp = actions->conf;
> +char *dirstr = actions->type == RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP
> +   ? "set_ipv4_dscp " : "set_ipv6_dscp ";
> +
> +ds_put_cstr(s, dirstr);
> +if (set_dscp) {
> +ds_put_format(s, "dscp_value %d ", set_dscp->dscp);
> +}
> +ds_put_cstr(s, "/ ");
>  } else if (actions->type == RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN) {
>  const struct rte_flow_action_of_push_vlan *of_push_vlan =
>  actions->conf;
> @@ -1836,11 +1847,22 @@ add_set_flow_action__(struct flow_actions *actions,
>  return 0;
>  }
>  if (!is_all_ones(mask, size)) {
> -VLOG_DBG_RL(, "Partial mask is not supported");
> +if (attr != RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP ||
> +attr != RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP) {

Maybe I am reading it wrong.
But the sense of the condition above seems inverted:
we want this logic iif it is DSCP.

> +if (*(uint8_t *) mask & IP_ECN_MASK) {
> +VLOG_DBG_RL(, "ECN hw offload is not supported!");
> +} else {
> +goto add_action;

I think that with a bit of care we can avoid a goto.
Perhaps a helper for the dscp/ecn case?

And as per Ilya's review of v3, don't we also need to check that all the
DSCP bits are set in the mask?

And likewise, as per Ilya's review of v3, "this function will clear the
whole mask below, but we should only clear DSCP bits in this case."

> +}
> +} else {
> +VLOG_DBG_RL(, "Partial mask is not supported");
> +}
> +
>  return -1;
>  }
>  }
>  
> +add_action:
>  spec = xzalloc(size);
>  memcpy(spec, value, size);
>  add_flow_action(actions, attr, spec);
> @@ -1912,6 +1934,7 @@ parse_set_actions(struct flow_actions *actions,
>  add_set_flow_action(ipv4_src, RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC);
>  add_set_flow_action(ipv4_dst, RTE_FLOW_ACTION_TYPE_SET_IPV4_DST);
>  add_set_flow_action(ipv4_ttl, RTE_FLOW_ACTION_TYPE_SET_TTL);
> +add_set_flow_action(ipv4_tos, 
> RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP);
>  
>  if (mask && !is_all_zeros(mask, sizeof *mask)) {
>  VLOG_DBG_RL(, "Unsupported IPv4 set action");
> @@ -1924,6 +1947,8 @@ parse_set_actions(struct flow_actions *actions,
>  add_set_flow_action(ipv6_src, RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC);
>  add_set_flow_action(ipv6_dst, RTE_FLOW_ACTION_TYPE_SET_IPV6_DST);
>  add_set_flow_action(ipv6_hlimit, RTE_FLOW_ACTION_TYPE_SET_TTL);
> +add_set_flow_action(ipv6_tclass,
> +RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP);
>  
>  if (mask && !is_all_zeros(mask, sizeof *mask)) {
>  VLOG_DBG_RL(, "Unsupported IPv6 set action");
> -- 
> 2.19.0.rc0.windows.1
> 
___
dev mailing list

Re: [ovs-dev] [PATCH ovn] controller: Add the capability to specify a min/max value for ct_zone.

2024-07-10 Thread Ales Musil
On Tue, Jul 9, 2024 at 6:37 PM Lorenzo Bianconi 
wrote:

> Introduce the capability to specify boundaries (max and min values) for
> the ct_zones dynamically selected by ovn-controller.
>
> Reported-at: https://issues.redhat.com/browse/FDP-383
> Signed-off-by: Lorenzo Bianconi 
> ---
>

Hi Lorenzo,

thank you for the patch, I have a couple of comments down below.


>  NEWS|  2 ++
>  controller/ct-zone.c| 37 --
>  controller/ct-zone.h|  4 ++-
>  controller/ovn-controller.c | 19 ---
>  tests/ovn-controller.at | 63 +
>  5 files changed, 111 insertions(+), 14 deletions(-)
>
> diff --git a/NEWS b/NEWS
> index 3e392ff08..421f3cd0a 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -38,6 +38,8 @@ Post v24.03.0
>  ability to disable "VXLAN mode" to extend available tunnel IDs space
> for
>  datapaths from 4095 to 16711680.  For more details see man ovn-nb(5)
> for
>  mentioned option.
> +  - Added support to define boundaries (min and max values) for selected
> ct
> +zones.
>


IMO it would be better if it's just one option specifying range instead of
two.


>  OVN v24.03.0 - 01 Mar 2024
>  --
> diff --git a/controller/ct-zone.c b/controller/ct-zone.c
> index e4f66a52a..5191c0fdf 100644
> --- a/controller/ct-zone.c
> +++ b/controller/ct-zone.c
> @@ -29,7 +29,8 @@ static void ct_zone_add_pending(struct shash
> *pending_ct_zones,
>  int zone, bool add, const char *name);
>  static int ct_zone_get_snat(const struct sbrec_datapath_binding *dp);
>  static bool ct_zone_assign_unused(struct ct_zone_ctx *ctx,
> -  const char *zone_name, int *scan_start);
> +  const char *zone_name,
> +  int *scan_start, int scan_stop);
>  static bool ct_zone_remove(struct ct_zone_ctx *ctx,
> struct simap_node *ct_zone);
>
> @@ -89,10 +90,11 @@ ct_zones_restore(struct ct_zone_ctx *ctx,
>
>  void
>  ct_zones_update(const struct sset *local_lports,
> +const struct ovsrec_open_vswitch_table *ovs_table,
>  const struct hmap *local_datapaths, struct ct_zone_ctx
> *ctx)
>  {
> +int min_ct_zone = 1, max_ct_zone = MAX_CT_ZONES + 1;
>  struct simap_node *ct_zone;
> -int scan_start = 1;
>  const char *user;
>  struct sset all_users = SSET_INITIALIZER(_users);
>  struct simap req_snat_zones = SIMAP_INITIALIZER(_snat_zones);
> @@ -131,9 +133,18 @@ ct_zones_update(const struct sset *local_lports,
>  free(snat);
>  }
>
> +const struct ovsrec_open_vswitch *cfg =
> +ovsrec_open_vswitch_table_first(ovs_table);
> +if (cfg) {
> +min_ct_zone = smap_get_int(>external_ids, "ct_zone_min_val",
> 1);
> +max_ct_zone = smap_get_int(>external_ids, "ct_zone_max_val",
> +   MAX_CT_ZONES + 1);
>

This will break when there are two controllers running over the same OvS.
We need to use the "get_chassis_external_id_value()" helpers here, see
"get_bridge_mappings()" for example.


> +}
> +
>  /* Delete zones that do not exist in above sset. */
>  SIMAP_FOR_EACH_SAFE (ct_zone, >current) {
> -if (!sset_contains(_users, ct_zone->name)) {
> +if (!sset_contains(_users, ct_zone->name) ||
> +ct_zone->data < min_ct_zone || ct_zone->data > max_ct_zone) {
>  ct_zone_remove(ctx, ct_zone);
>  } else if (!simap_find(_snat_zones, ct_zone->name)) {
>  bitmap_set1(unreq_snat_zones_map, ct_zone->data);
> @@ -195,7 +206,7 @@ ct_zones_update(const struct sset *local_lports,
>  continue;
>  }
>
> -ct_zone_assign_unused(ctx, user, _start);
> +ct_zone_assign_unused(ctx, user, _ct_zone, max_ct_zone);
>  }
>
>  simap_destroy(_snat_zones);
> @@ -296,11 +307,19 @@ ct_zone_handle_dp_update(struct ct_zone_ctx *ctx,
>  /* Returns "true" if there was an update to the context. */
>  bool
>  ct_zone_handle_port_update(struct ct_zone_ctx *ctx, const char *name,
> -   bool updated, int *scan_start)
> +   bool updated, int *scan_start,
> +   int min_ct_zone, int max_ct_zone)
>  {
>  struct simap_node *ct_zone = simap_find(>current, name);
> +
> +if (ct_zone &&
> +(ct_zone->data < min_ct_zone || ct_zone->data > max_ct_zone)) {
> +ct_zone_remove(ctx, ct_zone);
> +ct_zone = NULL;
> +}
> +
>  if (updated && !ct_zone) {
> -ct_zone_assign_unused(ctx, name, scan_start);
> +ct_zone_assign_unused(ctx, name, scan_start, max_ct_zone);
>  return true;
>  } else if (!updated && ct_zone_remove(ctx, ct_zone)) {
>  return true;
> @@ -312,11 +331,11 @@ ct_zone_handle_port_update(struct ct_zone_ctx *ctx,
> const char *name,
>
>  static bool
>  

Re: [ovs-dev] [PATCH ovn] controller: Add lsp option disable_garp_rarp.

2024-07-10 Thread Ales Musil
On Tue, Jul 9, 2024 at 7:57 AM Shibir Basak 
wrote:

> If the lsp option 'disable_garp_rarp' is set to true,
> GARP and RARP announcements are not sent by ovn when a
> VIF port is created on a bridged logical switch.
>
> Usecase
> 
> This option is useful during VM migration to let the
> hypervisor/VM send the RARP/GARP once VM is ready to
> process the packets post migration. This helps to reduce
> downtime during VM migration.
>
> Signed-off-by: Shibir Basak 
> Acked-by: Naveen Yerramneni 
>

Hello,

I would like to avoid yet another config option, have you considered
using "activation-strategy" LSP option along with setting multiple
requested-chassis during the migration process? This should ensure
that the downtime is actually as low as possible. See presentation
from Ihar about this specific option [0].


> ---
>  controller/pinctrl.c |  4 +--
>  ovn-nb.xml   |  7 +
>  tests/ovn.at | 68 
>  3 files changed, 77 insertions(+), 2 deletions(-)
>
> diff --git a/controller/pinctrl.c b/controller/pinctrl.c
> index 9a2f3f5b3..800c85d21 100644
> --- a/controller/pinctrl.c
> +++ b/controller/pinctrl.c
> @@ -6618,7 +6618,7 @@ send_garp_rarp_prepare(struct ovsdb_idl_txn
> *ovnsb_idl_txn,
>  SSET_FOR_EACH (iface_id, _vifs) {
>  const struct sbrec_port_binding *pb = lport_lookup_by_name(
>  sbrec_port_binding_by_name, iface_id);
> -if (pb) {
> +if (pb && !smap_get_bool(>options, "disable_garp_rarp",
> false)) {
>  send_garp_rarp_update(ovnsb_idl_txn,
>sbrec_mac_binding_by_lport_ip,
>local_datapaths, pb, _addresses,
> @@ -6631,7 +6631,7 @@ send_garp_rarp_prepare(struct ovsdb_idl_txn
> *ovnsb_idl_txn,
>  SSET_FOR_EACH (gw_port, _l3gw_ports) {
>  const struct sbrec_port_binding *pb
>  = lport_lookup_by_name(sbrec_port_binding_by_name, gw_port);
> -if (pb) {
> +if (pb && !smap_get_bool(>options, "disable_garp_rarp",
> false)) {
>  send_garp_rarp_update(ovnsb_idl_txn,
> sbrec_mac_binding_by_lport_ip,
>local_datapaths, pb, _addresses,
>garp_max_timeout, garp_continuous);
> diff --git a/ovn-nb.xml b/ovn-nb.xml
> index 9552534f6..3a0f0e34d 100644
> --- a/ovn-nb.xml
> +++ b/ovn-nb.xml
> @@ -1290,6 +1290,13 @@
>The default value is false.
>  
>
> + +type='{"type": "boolean"}'>
> +  If set to true, GARP and RARP announcements are not
> +  sent when a VIF port is created on a bridged logical switch.
> +  The default value is false.
> +
> +
>type='{"type": "string", "enum": ["set",
> ["mc_unknown"]]}'>
>If set to mc_unknown, packets going to this VIF get cloned to
> all
> diff --git a/tests/ovn.at b/tests/ovn.at
> index 87a64499f..a71a83394 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -25013,6 +25013,74 @@ OVN_CLEANUP([hv1])
>  AT_CLEANUP
>  ])
>
> +OVN_FOR_EACH_NORTHD([
> +AT_SETUP([Disabling RARP/GARP announcements])
> +ovn_start
> +
> +# In this test case we create 1 switch and bring up 4 VIFs on it.
> +# Two VIFs will be assigned MAC addresses only (i.e. without ips)
> +# and two VIFs will be assigned IP addresses along with MAC addresses.
> +# VIFs with IPs are supposed to send GARPs and VIFs with only MAC
> +# addresses are supposed to send RARP. However, we test the lsp
> +# option disable_garp_rarp, which when set to true for an lsp does
> +# not send the GARP/RARP announcements.
> +
> +ovn-nbctl ls-add ls1
> +ovn-nbctl lsp-add ls1 ln1 "" 101
> +ovn-nbctl lsp-set-addresses ln1 unknown
> +ovn-nbctl lsp-set-type ln1 localnet
> +ovn-nbctl lsp-set-options ln1 network_name=phys
> +
> +ovn-nbctl lsp-add ls1 lp11
> +ovn-nbctl lsp-set-addresses lp11 "f0:00:00:00:00:11"
> +
> +ovn-nbctl lsp-add ls1 lp12
> +ovn-nbctl lsp-set-addresses lp12 "f0:00:00:00:00:12"
> +ovn-nbctl set logical_switch_port lp12 options:disable_garp_rarp=true
> +
> +ovn-nbctl lsp-add ls1 lp13
> +ovn-nbctl lsp-set-addresses lp13 "f0:00:00:00:00:13 192.168.1.3"
> +
> +ovn-nbctl lsp-add ls1 lp14
> +ovn-nbctl lsp-set-addresses lp14 "f0:00:00:00:00:14 192.168.1.4"
> +ovn-nbctl set logical_switch_port lp14 options:disable_garp_rarp=true
> +
> +net_add n1
> +
> +sim_add hv1
> +as hv1
> +ovs-vsctl add-br br-phys
> +ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
> +ovn_attach n1 br-phys 192.168.0.1
> +
> +AT_CHECK([ovs-vsctl add-port br-phys snoopvif -- set Interface snoopvif
> options:tx_pcap=hv1/snoopvif-tx.pcap options:rxq_pcap=hv1/snoopvif-rx.pcap])
> +
> +ovs-vsctl add-port br-int vif11 -- \
> +set Interface vif11 external-ids:iface-id=lp11
> +
> +ovs-vsctl add-port br-int vif12 -- \
> +set Interface vif12 external-ids:iface-id=lp12
> +
> +ovs-vsctl add-port br-int vif13 -- \
> +set Interface 

Re: [ovs-dev] [PATCH ovn] northd: Fix issues for Forwarding_Group

2024-07-10 Thread Ales Musil
On Mon, Jul 8, 2024 at 5:01 PM Qiang Qiang45 Zhang via dev <
ovs-dev@openvswitch.org> wrote:

> When a logical switch has 2 FWGs and each FWG has 3 ports,
> Logical-Flow only has one fwg_group() action.
> Submitted-at: northd: Fix issues for Forwarding_Group by ZhangQiang3 *
> Pull Request #250 * ovn-org/ovn (github.com)<
> https://github.com/ovn-org/ovn/pull/250>
>
> From 02186da234426bc361615eb6b5142c76f296202f Mon Sep 17 00:00:00 2001
> From: zhangqiang45 zhangqian...@lenovo.com
> Date: Mon, 8 Jul 2024 14:25:04 +0800
> Subject: [PATCH ovn] northd: Fix issues for Forwarding_Group The use of
> variables from the outer loop in the inner loop causes the outer loop to
> terminate prematurely. eg. LVS are three fwgs,
> fwg1(p1,p2,p3,p4),fwg2(p11,p22),fwg3(p31,p32),only fwg1 in logical_flows
>
> ---
>

Hello,

thank you for the fix. The commit message seems to be broken as it
includes the email header for some reason. Also could you please add
test to ovn-northd.at that ensures this won't happen in future?

northd/northd.c | 7 +--
> 1 file changed, 5 insertions(+), 2 deletions(-)
>
> diff --git a/northd/northd.c b/northd/northd.c
> index 6898daa00..21ab0bb91 100644
> --- a/northd/northd.c
> +++ b/northd/northd.c
> @@ -7929,6 +7929,9 @@ build_fwd_group_lflows(struct ovn_datapath *od,
> struct lflow_table *lflows,
>  continue;
>  }
>
> +ds_clear();
> +ds_clear();
> +
>  /* ARP responder for the forwarding group's virtual IP */
>  ds_put_format(, "arp.tpa == %s && arp.op == 1",
>fwd_group->vip);
> @@ -7959,9 +7962,9 @@ build_fwd_group_lflows(struct ovn_datapath *od,
> struct lflow_table *lflows,
>  ds_put_cstr(_ports, "liveness=\"true\",");
>  }
>  ds_put_cstr(_ports, "childports=");
> -for (i = 0; i < (fwd_group->n_child_port - 1); ++i) {
> +for (int j = 0; j < (fwd_group->n_child_port - 1); ++j) {
>

nit: Please use size_t as the "j" type.

 ds_put_format(_ports, "\"%s\",",
> - fwd_group->child_port[i]);
> + fwd_group->child_port[j]);
>  }
>  ds_put_format(_ports, "\"%s\"",
>fwd_group->child_port[fwd_group->n_child_port - 1]);
> --
> 2.39.3
>
> ___
> dev mailing list
> d...@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
>
Thanks,
Ales

-- 

Ales Musil

Senior Software Engineer - OVN Core

Red Hat EMEA 

amu...@redhat.com

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


Re: [ovs-dev] [PATCH ovn] tests: Fix ssl-ciphers RO sb test with old openssl.

2024-07-10 Thread Ales Musil
On Sat, Jul 6, 2024 at 4:21 PM Vladislav Odintsov  wrote:

> The test "read-only sb db:pssl access with ssl-ciphers and ssl-protocols"
> fails when running with openssl which doesn't support some of passed
> values.
> For instance, on openssl 1.0.2 there is no support for 'SECLEVEL' and
> test fails due to extra string in stderr, which is asserted as a part of
> test:
>
>   ./ovn.at:37851: ovn-sbctl --db=ssl:127.0.0.1:$TCP_PORT \
> --private-key=$PKIDIR/testpki-test-privkey.pem \
>   --certificate=$PKIDIR/testpki-test-cert.pem \
>   --ca-cert=$PKIDIR/testpki-cacert.pem \
>   --ssl-ciphers='HIGH:!aNULL:!MD5:@SECLEVEL=1' \
>   --ssl-protocols='TLSv1,TLSv1.1,TLSv1.2' \
> chassis-add ch vxlan 1.2.4.8
>   --- - 2024-07-05 13:48:11.697647047 +0300
>   +++
> /builddir/build/BUILD/ovn-24.03.90/tests/testsuite.dir/at-groups/520/stderr
> 2024-07-05 13:48:11.694353357 +0300
>   @@ -1,2 +1,3 @@
>   +2024-07-05T10:48:11Z|1|stream_ssl|ERR|SSL_CTX_set_cipher_list:
> error:140E6118:SSL routines:SSL_CIPHER_PROCESS_RULESTR:invalid command
>ovn-sbctl: transaction error: {"details":"insert operation not allowed
> when database server is in read only mode","error":"not allowed"}
>
> This patch fixes the test adding grep of expected transaction error.
>
> CC: Aliasgar Ginwala 
> Fixes: 620203f9f0d9 ("Fix segfault due to ssl-ciphers.")
> Signed-off-by: Vladislav Odintsov 
> ---
>  tests/ovn.at | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/tests/ovn.at b/tests/ovn.at
> index 87a64499f..2341f52d5 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -37854,9 +37854,9 @@ AT_CHECK([ovn-sbctl --db=ssl:127.0.0.1:$TCP_PORT \
>  --ca-cert=$PKIDIR/testpki-cacert.pem \
>  --ssl-ciphers='HIGH:!aNULL:!MD5:@SECLEVEL=1' \
>  --ssl-protocols='TLSv1,TLSv1.1,TLSv1.2' \
> -chassis-add ch vxlan 1.2.4.8], [1], [ignore],
> -[ovn-sbctl: transaction error: {"details":"insert operation not allowed
> when database server is in read only mode","error":"not allowed"}
> -])
> +chassis-add ch vxlan 1.2.4.8 2>&1 | grep 'transaction
> error]', [0], [dnl
> +ovn-sbctl: transaction error: {"details":"insert operation not allowed
> when database server is in read only mode","error":"not allowed"}
> +], [ignore])
>
>  OVS_APP_EXIT_AND_WAIT([ovsdb-server])
>  AT_CLEANUP
> --
> 2.45.2
>
> ___
> dev mailing list
> d...@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
>
Looks good to me, thanks.

Acked-by: Ales Musil 

-- 

Ales Musil

Senior Software Engineer - OVN Core

Red Hat EMEA 

amu...@redhat.com

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev