Add a new resource in ofproto-dpif and the corresponding API in
ofproto_provider.h to represent and change psample configuration.

Signed-off-by: Adrian Moreno <amore...@redhat.com>
---
 ofproto/automake.mk            |   2 +
 ofproto/ofproto-dpif-psample.c | 167 +++++++++++++++++++++++++++++++++
 ofproto/ofproto-dpif-psample.h |  31 ++++++
 ofproto/ofproto-dpif.c         |  33 +++++++
 ofproto/ofproto-dpif.h         |   1 +
 ofproto/ofproto-provider.h     |   9 ++
 ofproto/ofproto.c              |  10 ++
 ofproto/ofproto.h              |   8 ++
 8 files changed, 261 insertions(+)
 create mode 100644 ofproto/ofproto-dpif-psample.c
 create mode 100644 ofproto/ofproto-dpif-psample.h

diff --git a/ofproto/automake.mk b/ofproto/automake.mk
index 7c08b563b..340003e12 100644
--- a/ofproto/automake.mk
+++ b/ofproto/automake.mk
@@ -34,6 +34,8 @@ ofproto_libofproto_la_SOURCES = \
        ofproto/ofproto-dpif-mirror.h \
        ofproto/ofproto-dpif-monitor.c \
        ofproto/ofproto-dpif-monitor.h \
+       ofproto/ofproto-dpif-psample.c \
+       ofproto/ofproto-dpif-psample.h \
        ofproto/ofproto-dpif-rid.c \
        ofproto/ofproto-dpif-rid.h \
        ofproto/ofproto-dpif-sflow.c \
diff --git a/ofproto/ofproto-dpif-psample.c b/ofproto/ofproto-dpif-psample.c
new file mode 100644
index 000000000..a83530ed8
--- /dev/null
+++ b/ofproto/ofproto-dpif-psample.c
@@ -0,0 +1,167 @@
+/*
+ * 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-psample.h"
+
+#include "hash.h"
+#include "ofproto.h"
+#include "openvswitch/hmap.h"
+#include "openvswitch/thread.h"
+#include "openvswitch/vlog.h"
+
+VLOG_DEFINE_THIS_MODULE(psample);
+
+static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
+
+struct psample_exporter {
+    uint32_t group_id;
+    uint32_t collector_set_id;
+};
+
+struct psample_exporter_map_node {
+    struct hmap_node node;
+    struct psample_exporter exporter;
+};
+
+struct dpif_psample {
+    struct hmap exporters_map;     /* Contains psample_exporter_map_node. */
+
+    struct ovs_refcount ref_cnt;
+};
+
+/* Exporter handling */
+static void
+dpif_psample_clear(struct dpif_psample *ps) OVS_REQUIRES(mutex)
+{
+    struct psample_exporter_map_node *node;
+
+    HMAP_FOR_EACH_POP (node, node, &ps->exporters_map) {
+        free(node);
+    }
+}
+
+static struct psample_exporter_map_node*
+dpif_psample_new_exporter_node(struct dpif_psample *ps,
+                               const struct ofproto_psample_options *options)
+    OVS_REQUIRES(mutex)
+{
+    struct psample_exporter_map_node *node;
+    node = xzalloc(sizeof *node);
+    node->exporter.collector_set_id = options->collector_set_id;
+    node->exporter.group_id = options->group_id;
+    hmap_insert(&ps->exporters_map, &node->node,
+                hash_int(options->collector_set_id, 0));
+    return node;
+}
+
+static struct psample_exporter_map_node*
+dpif_psample_find_exporter_node(const struct dpif_psample *ps,
+                                const uint32_t collector_set_id)
+    OVS_REQUIRES(mutex)
+{
+    struct psample_exporter_map_node *node;
+    HMAP_FOR_EACH_WITH_HASH (node, node,
+                             hash_int(collector_set_id, 0),
+                             &ps->exporters_map) {
+        if (node->exporter.collector_set_id == collector_set_id) {
+            return node;
+        }
+    }
+    return NULL;
+}
+
+/* Configuration. */
+
+/* Sets the psample configuration.
+ * Returns true if the configuration has changed. */
+bool
+dpif_psample_set_options(struct dpif_psample *ps,
+                         const struct ovs_list *options_list)
+OVS_EXCLUDED(mutex)
+{
+    struct ofproto_psample_options *options;
+    struct psample_exporter_map_node *node;
+    bool changed = false;
+
+    ovs_mutex_lock(&mutex);
+
+    /* psample exporters do not hold any runtime memory so we do not need to
+     * be extra careful at detecting which exporter changed and which did
+     * not. As soon as we detect any change we can just recreate them all. */
+    LIST_FOR_EACH(options, list_node, options_list) {
+        node = dpif_psample_find_exporter_node(ps, options->collector_set_id);
+        if (!node ||
+            node->exporter.collector_set_id != options->collector_set_id ||
+            node->exporter.group_id != options->group_id) {
+            changed = true;
+            break;
+        }
+    }
+    changed |= (hmap_count(&ps->exporters_map) != ovs_list_size(options_list));
+
+    if (changed) {
+        dpif_psample_clear(ps);
+        LIST_FOR_EACH(options, list_node, options_list) {
+            dpif_psample_new_exporter_node(ps, options);
+        }
+    }
+
+    ovs_mutex_unlock(&mutex);
+
+    return changed;
+}
+
+/* Creation and destruction. */
+struct dpif_psample *
+dpif_psample_create(void)
+{
+    struct dpif_psample *ps;
+    ps = xzalloc(sizeof *ps);
+    hmap_init(&ps->exporters_map);
+    ovs_refcount_init(&ps->ref_cnt);
+    return ps;
+}
+
+static void
+dpif_psample_destroy(struct dpif_psample *ps) OVS_EXCLUDED(mutex)
+{
+    if (ps) {
+        ovs_mutex_lock(&mutex);
+        dpif_psample_clear(ps);
+        free(ps);
+        ovs_mutex_unlock(&mutex);
+    }
+}
+
+/* Reference counting. */
+struct dpif_psample*
+dpif_psample_ref(const struct dpif_psample *ps_)
+{
+    struct dpif_psample *ps = CONST_CAST(struct dpif_psample*, ps_);
+    if (ps) {
+        ovs_refcount_ref(&ps->ref_cnt);
+    }
+    return ps;
+}
+
+void
+dpif_psample_unref(struct dpif_psample *ps) OVS_EXCLUDED(mutex)
+{
+    if (ps && ovs_refcount_unref_relaxed(&ps->ref_cnt) == 1) {
+        dpif_psample_destroy(ps);
+    }
+}
diff --git a/ofproto/ofproto-dpif-psample.h b/ofproto/ofproto-dpif-psample.h
new file mode 100644
index 000000000..80ba44fb9
--- /dev/null
+++ b/ofproto/ofproto-dpif-psample.h
@@ -0,0 +1,31 @@
+/*
+ * 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_PSAMPLE_H
+#define OFPROTO_DPIF_PSAMPLE_H 1
+
+#include <stdbool.h>
+
+struct dpif_psample;
+struct ovs_list;
+
+struct dpif_psample *dpif_psample_create(void);
+void dpif_psample_unref(struct dpif_psample *);
+struct dpif_psample* dpif_psample_ref(const struct dpif_psample *);
+
+bool dpif_psample_set_options(struct dpif_psample *, const struct ovs_list *);
+
+#endif // OFPROTO_DPIF_PSAMPLE_H
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 3cee2795a..fbb83a9ec 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -50,6 +50,7 @@
 #include "ofproto-dpif-sflow.h"
 #include "ofproto-dpif-trace.h"
 #include "ofproto-dpif-upcall.h"
+#include "ofproto-dpif-psample.h"
 #include "ofproto-dpif-xlate.h"
 #include "ofproto-dpif-xlate-cache.h"
 #include "openvswitch/ofp-actions.h"
@@ -2529,6 +2530,37 @@ get_ipfix_stats(const struct ofproto *ofproto_,
     return dpif_ipfix_get_stats(di, bridge_ipfix, replies);
 }
 
+static int
+set_psample(struct ofproto *ofproto_, const struct ovs_list *pso)
+{
+    struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
+    struct dpif_psample *ps = ofproto->psample;
+    bool changed = false;
+    bool has_options = pso && !ovs_list_is_empty(pso);
+
+    if(!ofproto->backer->rt_support.psample)
+        return ENOTSUP;
+
+    if (has_options && !ps) {
+        ps = ofproto->psample = dpif_psample_create();
+        changed = true;
+    }
+
+    if (ps) {
+        if (!has_options) {
+            dpif_psample_unref(ps);
+            ofproto->psample = NULL;
+            changed = true;
+        } else {
+            changed |= dpif_psample_set_options(ps, pso);
+        }
+    }
+
+    if (changed)
+        ofproto->backer->need_revalidate = REV_RECONFIGURE;
+    return 0;
+}
+
 static int
 set_cfm(struct ofport *ofport_, const struct cfm_settings *s)
 {
@@ -7099,6 +7131,7 @@ const struct ofproto_class ofproto_dpif_class = {
     get_netflow_ids,
     set_sflow,
     set_ipfix,
+    set_psample,
     get_ipfix_stats,
     set_cfm,
     cfm_status_changed,
diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h
index 3db4263c7..97b2e78f1 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_psample *psample;
     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..2ed7ebfbe 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 psample on 'ofproto' according to the options in
+     * 'options' or turns off psample if 'options' is NULL.
+     *
+     * 'options' contains 'struct ofproto_psample_options'.
+     * EOPNOTSUPP as a return value indicates that 'ofproto' does not support
+     * psample, as does a null pointer. */
+    int (*set_psample)(struct ofproto *ofproto,
+                       const struct ovs_list *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..22f584740 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -1000,6 +1000,16 @@ ofproto_get_datapath_cap(const char *datapath_type, 
struct smap *dp_cap)
     }
 }
 
+int ofproto_set_psample(struct ofproto *ofproto,
+                        const struct ovs_list *pso)
+{
+    if (ofproto->ofproto_class->set_psample) {
+        return ofproto->ofproto_class->set_psample(ofproto, pso);
+    } else {
+        return (!pso || ovs_list_is_empty(pso)) ? 0: 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..dc1c470dd 100644
--- a/ofproto/ofproto.h
+++ b/ofproto/ofproto.h
@@ -103,6 +103,12 @@ struct ofproto_ipfix_flow_exporter_options {
     char *virtual_obs_id;
 };
 
+struct ofproto_psample_options {
+    struct ovs_list list_node;
+    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 +396,8 @@ 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_psample(struct ofproto *,
+                        const struct ovs_list *);
 
 /* Configuration of ports. */
 void ofproto_port_unregister(struct ofproto *, ofp_port_t ofp_port);
-- 
2.44.0

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

Reply via email to