On 27 Jun 2024, at 13:37, Adrián Moreno wrote:

> On Wed, Jun 26, 2024 at 02:11:00PM GMT, Eelco Chaudron wrote:
>> On 5 Jun 2024, at 22:23, Adrian Moreno wrote:
>>
>>> Add as new column in the Flow_Sample_Collector_Set table named
>>> "local_sample_group" which enables this feature.
>>>
>>> Signed-off-by: Adrian Moreno <amore...@redhat.com>
>>> ---
>>>  NEWS                       |  4 ++
>>>  vswitchd/bridge.c          | 78 +++++++++++++++++++++++++++++++++++---
>>>  vswitchd/vswitch.ovsschema |  9 ++++-
>>>  vswitchd/vswitch.xml       | 39 +++++++++++++++++--
>>>  4 files changed, 119 insertions(+), 11 deletions(-)
>>>
>>> diff --git a/NEWS b/NEWS
>>> index b92cec532..1c05a7120 100644
>>> --- a/NEWS
>>> +++ b/NEWS
>>> @@ -7,6 +7,10 @@ Post-v3.3.0
>>>     - The primary development branch has been renamed from 'master' to 
>>> 'main'.
>>>       The OVS tree remains hosted on GitHub.
>>>    https://github.com/openvswitch/ovs.git
>>> +   - 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 via the new datapath action called 
>>> "emit_sample".
>>> +     Linux kernel datapath is the first to support this feature.
>>>
>>>
>>>  v3.3.0 - 16 Feb 2024
>>> diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
>>> index 95a65fcdc..cd7dc6646 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, &sflow_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 constains valid IPFIX
>>
>> constains -> 'contains a'
>>
>
> Ack.
>
>>> + * 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(&opts->targets);
>>>                  sset_add_array(&opts->targets, fe_cfg->ipfix->targets,
>>> @@ -1667,6 +1670,71 @@ bridge_configure_ipfix(struct bridge *br)
>>>      }
>>>  }
>>>
>>> +/* Returns whether a Flow_Sample_Collector_Set row contains valid local
>>> + * sampling configuraiton. */
>>
>> ...row contains a valid local...
>>                ++
>>
>> configuraiton -> configuration
>
> Ack.
>
>>
>>> +static bool
>>> +ovsrec_fscs_is_valid_local(const struct ovsrec_flow_sample_collector_set 
>>> *fscs,
>>> +                           const struct bridge *br)
>>> +{
>>> +    return fscs->local_sample_group && fscs->n_local_sample_group == 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 ++;
>>> +        }
>>> +    }
>>
>> Did you consider just allocating n_local_sample_group entries and only use
>> the ones needed? Or are we assuming there is a large gap between the actual
>> entries and the ones having a valid local entry?
>
> n_local_sample_group is just the number of "local_sample_group" defined
> in one particular FSCS row. It's optional so it can be 0 or 1.
>
> Were allocating one configuration object for each valid row in the FSCS
> table. This is done because FSCS rows can be configured with different
> bridges and since this is a OVSDB relationship, the ofproto layer and
> below cannot tell if the configuration entry is aplicable to that
> ofproto or not.


I understand that part, was just wondering if there is a big discrepancy 
between the actual n_local_sample_group number and the amount local entries we 
are interested in, ovsrec_fscs_is_valid_local(), in a typical configuration. 
This to avoid two loops through all of them. But this is more of a nit than an 
important part.

>>> +    if (n_opts == 0) {
>>> +        ofproto_set_local_sample(br->ofproto, NULL, 0);
>>> +        return;
>>> +    }
>>> +
>>> +    opts_array = xcalloc(n_opts, sizeof *opts_array);
>>> +    opts = opts_array;
>>> +
>>> +    OVSREC_FLOW_SAMPLE_COLLECTOR_SET_FOR_EACH (fscs, idl) {
>>> +        if (!ovsrec_fscs_is_valid_local(fscs, br)) {
>>> +            continue;
>>> +        }
>>> +        opts->collector_set_id = fscs->id;
>>> +        opts->group_id = *fscs->local_sample_group;
>>> +        opts++;
>>> +    }
>>> +
>>> +    ret = ofproto_set_local_sample(br->ofproto, opts_array, n_opts);
>>> +
>>> +    if (ret == ENOTSUP) {
>>> +        if (n_opts) {
>>> +            VLOG_WARN_RL(&rl,
>>> +                         "bridge %s: ignoring local sampling 
>>> configuration: "
>>> +                         "not supported by this datapath",
>>> +                         br->name);
>>> +        }
>>> +    } else if (ret) {
>>> +        VLOG_ERR_RL(&rl, "bridge %s: error configuring local sampling: %s",
>>> +                    br->name, ovs_strerror(ret));
>>> +    }
>>> +
>>> +    if (n_opts > 0) {
>>> +        free(opts_array);
>>> +    }
>>> +}
>>> +
>>>  static void
>>>  port_configure_stp(const struct ofproto *ofproto, struct port *port,
>>>                     struct ofproto_port_stp_settings *port_s,
>>> diff --git a/vswitchd/vswitch.ovsschema b/vswitchd/vswitch.ovsschema
>>> index e2d5e2e85..f945451cd 100644
>>> --- a/vswitchd/vswitch.ovsschema
>>> +++ b/vswitchd/vswitch.ovsschema
>>> @@ -1,6 +1,6 @@
>>>  {"name": "Open_vSwitch",
>>> - "version": "8.5.0",
>>> - "cksum": "4040946650 27557",
>>> + "version": "8.6.0",
>>> + "cksum": "3864090052 27769",
>>>   "tables": {
>>>     "Open_vSwitch": {
>>>       "columns": {
>>> @@ -562,6 +562,11 @@
>>>           "type": {"key": {"type": "uuid",
>>>                            "refTable": "IPFIX"},
>>>                    "min": 0, "max": 1}},
>>> +       "local_sample_group": {
>>> +         "type": {"key": {"type": "integer",
>>> +                          "minInteger": 0,
>>> +                          "maxInteger": 4294967295},
>>> +                  "min": 0, "max": 1}},
>>>         "external_ids": {
>>>           "type": {"key": "string", "value": "string",
>>>                    "min": 0, "max": "unlimited"}}},
>>> diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
>>> index 8a1b607d7..2a5223203 100644
>>> --- a/vswitchd/vswitch.xml
>>> +++ b/vswitchd/vswitch.xml
>>> @@ -7008,10 +7008,37 @@ ovs-vsctl add-port br0 p0 -- set Interface p0 
>>> type=patch options:peer=p1 \
>>>
>>>    <table name="Flow_Sample_Collector_Set">
>>>      <p>
>>> -      A set of IPFIX collectors of packet samples generated by OpenFlow
>>> -      <code>sample</code> actions.  This table is used only for IPFIX
>>> -      flow-based sampling, not for per-bridge sampling (see the <ref
>>> -      table="IPFIX"/> table for a description of the two forms).
>>> +      A set of IPFIX or local sampling collectors of packet samples 
>>> generated
>>> +      by OpenFlow <code>sample</code> actions.
>>> +    </p>
>>> +
>>> +    <p>
>>> +      If the column <code>ipfix</code> contains a reference to a
>>> +      valid IPFIX entry, samples will be emitted via IPFIX. This mechanism
>>> +      is known as flow-based IPFIX sampling, as opposed to bridge-based
>>> +      sampling (see the <ref table="IPFIX"/> table for a description of the
>>> +      two forms).
>>> +    </p>
>>> +
>>> +    <p>
>>> +      If the column <code>local_sample_group</code> contains an integer 
>>> and the
>>
>> Can we call this local_group instead (or local_group_id)? This will avoid the
>> long name, as this option is already in the Flow_Sample_Collector_Set table.
>>
>
> Sure, local group is fine.
>
>>> +      running datapath supports local sample emission, packets will be sent
>>> +      to some local sample collector. Samples will contain the group number
>>> +      specified by <code>local_sample_group</code> which helps identify 
>>> their
>>> +      source as well as a 64-bit cookie result from the concatenation of 
>>> the
>>> +      observation_domain_id an the observation_point_id.
>>
>> I guess this needs some clarification regarding endianness, etc., based on 
>> your discussion with Ilya.
>>
>
> Yep.
>
>>> +
>>> +      The way the sample is emitted and made available for local collectors
>>> +      is datapath-specific.
>>> +
>>> +      Currently only Linux kernel datapath supports local sampling which is
>>> +      implemented by sending the packet to the <code>psample</code> netlink
>>> +      multicast group.
>>> +    </p>
>>> +
>>> +    <p>
>>> +      Note both <code>local_sample_group</code> and <code>ipfix</code> can 
>>> be
>>> +      configured simultaneously.
>>>      </p>
>>>
>>>      <column name="id">
>>> @@ -7030,6 +7057,10 @@ ovs-vsctl add-port br0 p0 -- set Interface p0 
>>> type=patch options:peer=p1 \
>>>        record per sampled packet to.
>>>      </column>
>>>
>>> +    <column name="local_sample_group">
>>> +      Configuration of the sample group to be used in local sampling.
>>> +    </column>
>>> +
>>
>> Not sure if we prefer putting the type here also, like other options
>> do for documentation:
>>
>> type='{"type": "integer", "minInteger": 0, "maxInteger": 4294967295}'>
>>
>> Or is having it in the ovsschema enough?
>
> It doesn't harm to document it here as well.
>
>>
>>>      <group title="Common Columns">
>>>        The overall purpose of these columns is described under <code>Common
>>>        Columns</code> at the beginning of this document.
>>> --
>>> 2.45.1
>>

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

Reply via email to