On 28 Jun 2024, at 15:53, Adrián Moreno wrote:
> On Thu, Jun 27, 2024 at 03:57:03PM GMT, Eelco Chaudron wrote: >> >> >> 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. >> > > Sorry, my head is not working very well today and I'm not understanding > your point. > > n_local_sample_group might 1 or 0 indicating whether there is local > sampling or not in this collector. The actual value can be anything > between 1 and 2^32 -1 and it is completely up to the user to configure > something that will be unique in their system (e.g: do not collide > with other act_sample actions they might have installed). > > I don't expect many FSCS rows to be configured. Let's take en example. > Let's say we have 2 bridges, 10 FSCS entries, 5 for each bridge. From > them, only 3 have local sampling (the other 2 have only IPFIX > configuration). So, n_local_sample_group is 1 in 6 of the entries and 0 > in the rest. The actual number can be on 10001-10006 for instance. > > Here we are configuring one ofproto (i.e: one bridge). Since we're > storing the configuration in an array, we need to iterate twice. First > time we realize that, out of the 10 rows, only 3 of them return true in > ovsrec_fscs_is_valid_local(). So we allocate an array of size 3, create > configuration objects for those and send them down to ofproto-dpif. > > The only other way I can see of avoiding the double loop is to allocate > the total number of rows, 10 in the previous example, and add a boolean > in the configuration that tells the ofproto layer that the option must > be ignored because, it either didn't have local sampling > (n_local_sample_group=0) or it belongs to another bridge. My bad, this is what I was suggesting to see if it would make sense. I miss quoted n_local_sample_group, which caused the confusion. > Considering the amount of rows we expect to have is low, I think a > double loop yields cleaner code in this case. ACK. >>>>> + 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