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 <amore...@redhat.com> > > 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 000000000..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 <config.h> > > +#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(&lsample->mutex); > > + cmap_remove(&lsample->exporters, &node->node, > > + hash_int(node->exporter.options.collector_set_id, 0)); > > + ovs_mutex_unlock(&lsample->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(&lsample->mutex); > > + cmap_insert(&lsample->exporters, &node->node, > > + hash_int(options->collector_set_id, 0)); > > + ovs_mutex_unlock(&lsample->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), > > + &lsample->exporters) { > > + if (node->exporter.options.collector_set_id == collector_set_id) { > > + return node; > > + } > > + } > > + return NULL; > > +} > > + > > +/* Sets the lsample configuration and returns true if the configuration > > + * has changed. */ > > +bool > > +dpif_lsample_set_options(struct dpif_lsample *lsample, > > + const struct ofproto_lsample_options *options, > > + size_t n_options) > > +{ > > + const struct ofproto_lsample_options *opt; > > + struct lsample_exporter_node *node; > > + bool changed = false; > > + int i; > > + > > + for (i = 0; i < n_options; i++) { > > + opt = &options[i]; > > + node = dpif_lsample_find_exporter_node(lsample, > > + opt->collector_set_id); > > + if (!node) { > > + dpif_lsample_add_exporter(lsample, opt); > > + changed = true; > > + } else if (memcmp(&node->exporter.options, opt, sizeof(*opt))) { > > + dpif_lsample_delete_exporter(lsample, node); > > + dpif_lsample_add_exporter(lsample, opt); > > + changed = true; > > + } > > + } > > + > > + /* Delete exporters that have been removed. */ > > + CMAP_FOR_EACH (node, node, &lsample->exporters) { > > + for (i = 0; i < n_options; i++) { > > + if (node->exporter.options.collector_set_id > > + == options[i].collector_set_id) { > > + break; > > + } > > + } > > + if (i == n_options) { > > + dpif_lsample_delete_exporter(lsample, node); > > + changed = true; > > + } > > + } > > + > > + return changed; > > +} > > + > > +struct dpif_lsample * > > +dpif_lsample_create(void) > > +{ > > + struct dpif_lsample *lsample; > > + > > + lsample = xzalloc(sizeof *lsample); > > + cmap_init(&lsample->exporters); > > + ovs_mutex_init(&lsample->mutex); > > + ovs_refcount_init(&lsample->ref_cnt); > > + > > + return lsample; > > +} > > + > > +static void > > +dpif_lsample_destroy(struct dpif_lsample *lsample) > > +{ > > + if (lsample) { > > + struct lsample_exporter_node *node; > > + > > + CMAP_FOR_EACH (node, node, &lsample->exporters) { > > + dpif_lsample_delete_exporter(lsample, node); > > + } > > + cmap_destroy(&lsample->exporters); > > + free(lsample); > > + } > > +} > > + > > +struct dpif_lsample * > > +dpif_lsample_ref(const struct dpif_lsample *lsample_) > > +{ > > + struct dpif_lsample *lsample = CONST_CAST(struct dpif_lsample *, > > lsample_); > > + > > + if (lsample) { > > + ovs_refcount_ref(&lsample->ref_cnt); > > + } > > + return lsample; > > +} > > + > > +void > > +dpif_lsample_unref(struct dpif_lsample *lsample) > > +{ > > + if (lsample && ovs_refcount_unref_relaxed(&lsample->ref_cnt) == 1) { > > + dpif_lsample_destroy(lsample); > > + } > > +} > > diff --git a/ofproto/ofproto-dpif-lsample.h b/ofproto/ofproto-dpif-lsample.h > > new file mode 100644 > > index 000000000..bee36c9c5 > > --- /dev/null > > +++ b/ofproto/ofproto-dpif-lsample.h > > @@ -0,0 +1,36 @@ > > +/* > > + * 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. > > + */ > > + > > +#ifndef OFPROTO_DPIF_LSAMPLE_H > > +#define OFPROTO_DPIF_LSAMPLE_H 1 > > + > > +#include <stdbool.h> > > +#include <stdlib.h> > > + > > +struct dpif_lsample; > > +struct ofproto_lsample_options; > > + > > +struct dpif_lsample *dpif_lsample_create(void); > > + > > +void dpif_lsample_unref(struct dpif_lsample *); > > + > > +struct dpif_lsample *dpif_lsample_ref(const struct dpif_lsample *); > > I would define ref before unref. > > > + > > +bool dpif_lsample_set_options(struct dpif_lsample *, > > + const struct ofproto_lsample_options *, > > + size_t n_opts); > > Also not sure what would be the right way to group, not group, add extra > new lines in include files. Looks like we sort of group similar function, > and add new lines between groups. If we follow that it should probably look > something like this: > > struct dpif_lsample *dpif_lsample_create(void); > > struct dpif_lsample *dpif_lsample_ref(const struct dpif_lsample *); > void dpif_lsample_unref(struct dpif_lsample *); > > bool dpif_lsample_set_options(struct dpif_lsample *, > const struct ofproto_lsample_options *, > size_t n_opts); > > But I have no real preferences, maybe Ilya has. >
I don't either, your sorting looks good. > > +#endif /* OFPROTO_DPIF_LSAMPLE_H */ > > diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c > > index 94c84d697..56830c630 100644 > > --- a/ofproto/ofproto-dpif.c > > +++ b/ofproto/ofproto-dpif.c > > @@ -49,6 +49,7 @@ > > #include "ofproto-dpif-sflow.h" > > #include "ofproto-dpif-trace.h" > > #include "ofproto-dpif-upcall.h" > > +#include "ofproto-dpif-lsample.h" > > #include "ofproto-dpif-xlate.h" > > #include "ofproto-dpif-xlate-cache.h" > > #include "openvswitch/ofp-actions.h" > > @@ -1954,6 +1955,7 @@ destruct(struct ofproto *ofproto_, bool del) > > netflow_unref(ofproto->netflow); > > dpif_sflow_unref(ofproto->sflow); > > dpif_ipfix_unref(ofproto->ipfix); > > + dpif_lsample_unref(ofproto->lsample); > > hmap_destroy(&ofproto->bundles); > > mac_learning_unref(ofproto->ml); > > mcast_snooping_unref(ofproto->ms); > > @@ -2513,6 +2515,41 @@ get_ipfix_stats(const struct ofproto *ofproto_, > > return dpif_ipfix_get_stats(di, bridge_ipfix, replies); > > } > > > > +static int > > +set_local_sample(struct ofproto *ofproto_, > > + const struct ofproto_lsample_options *options, > > + size_t n_opts) > > +{ > > + struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); > > + struct dpif_lsample *lsample = ofproto->lsample; > > + bool changed = false; > > + > > + if (!ofproto->backer->rt_support.psample) { > > + return ENOTSUP; > > + } > > + > > + if (n_opts && !lsample) { > > + lsample = ofproto->lsample = dpif_lsample_create(); > > + changed = true; > > + } > > + > > + if (lsample) { > > + if (!n_opts) { > > + dpif_lsample_unref(lsample); > > + lsample = ofproto->lsample = NULL; > > + changed = true; > > + } else { > > + changed |= dpif_lsample_set_options(lsample, options, n_opts); > > + } > > + } > > + > > + if (changed) { > > + ofproto->backer->need_revalidate = REV_RECONFIGURE; > > + } > > + > > + return 0; > > +} > > + > > static int > > set_cfm(struct ofport *ofport_, const struct cfm_settings *s) > > { > > @@ -7100,6 +7137,7 @@ const struct ofproto_class ofproto_dpif_class = { > > get_netflow_ids, > > set_sflow, > > set_ipfix, > > + set_local_sample, > > get_ipfix_stats, > > set_cfm, > > cfm_status_changed, > > diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h > > index bc7a19dab..420c350fd 100644 > > --- a/ofproto/ofproto-dpif.h > > +++ b/ofproto/ofproto-dpif.h > > @@ -331,6 +331,7 @@ struct ofproto_dpif { > > struct netflow *netflow; > > struct dpif_sflow *sflow; > > struct dpif_ipfix *ipfix; > > + struct dpif_lsample *lsample; > > struct hmap bundles; /* Contains "struct ofbundle"s. */ > > struct mac_learning *ml; > > struct mcast_snooping *ms; > > diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h > > index 83c509fcf..02e6710d9 100644 > > --- a/ofproto/ofproto-provider.h > > +++ b/ofproto/ofproto-provider.h > > @@ -1479,6 +1479,15 @@ struct ofproto_class { > > const struct ofproto_ipfix_flow_exporter_options > > *flow_exporters_options, size_t n_flow_exporters_options); > > > > + /* Configures local sampling on 'ofproto' according to the options > > array > > + * of 'options' which contains 'n_options' elements. > > + * > > + * EOPNOTSUPP as a return value indicates that 'ofproto' does not > > support > > + * local sampling. */ > > + int (*set_local_sample)(struct ofproto *ofproto, > > + const struct ofproto_lsample_options *options, > > + size_t n_options); > > + > > /* Gets IPFIX stats on 'ofproto' according to the exporter of birdge > > * IPFIX or flow-based IPFIX. > > * > > diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c > > index 21c6a1d82..2a1db8a0a 100644 > > --- a/ofproto/ofproto.c > > +++ b/ofproto/ofproto.c > > @@ -1000,6 +1000,18 @@ ofproto_get_datapath_cap(const char *datapath_type, > > struct smap *dp_cap) > > } > > } > > > > +int ofproto_set_local_sample(struct ofproto *ofproto, > > + const struct ofproto_lsample_options *options, > > + size_t n_options) > > +{ > > + if (ofproto->ofproto_class->set_local_sample) { > > + return ofproto->ofproto_class->set_local_sample(ofproto, options, > > + n_options); > > + } else { > > + return ENOTSUP; > > + } > > +} > > + > > /* Connection tracking configuration. */ > > void > > ofproto_ct_set_zone_timeout_policy(const char *datapath_type, uint16_t > > zone_id, > > diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h > > index 1c07df275..fded3a3db 100644 > > --- a/ofproto/ofproto.h > > +++ b/ofproto/ofproto.h > > @@ -103,6 +103,11 @@ struct ofproto_ipfix_flow_exporter_options { > > char *virtual_obs_id; > > }; > > > > +struct ofproto_lsample_options { > > + uint32_t collector_set_id; > > + uint32_t group_id; > > +}; > > + > > struct ofproto_rstp_status { > > bool enabled; /* If false, ignore other members. */ > > rstp_identifier root_id; > > @@ -390,6 +395,9 @@ void ofproto_ct_zone_limit_protection_update(const char > > *datapath_type, > > bool protected); > > void ofproto_get_datapath_cap(const char *datapath_type, > > struct smap *dp_cap); > > +int ofproto_set_local_sample(struct ofproto *ofproto, > > + const struct ofproto_lsample_options *, > > + size_t n_options); > > nit: Maybe move below ofproto_set_ipfix() so all sampling is grouped together. > Ack. > > > > /* Configuration of ports. */ > > void ofproto_port_unregister(struct ofproto *, ofp_port_t ofp_port); > > -- > > 2.45.2 > _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev