mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 01:51:26 +00:00
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. Acked-by: Eelco Chaudron <echaudro@redhat.com> Signed-off-by: Adrian Moreno <amorenoz@redhat.com> Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
200 lines
5.9 KiB
C
200 lines
5.9 KiB
C
/*
|
|
* 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;
|
|
}
|
|
|
|
/* 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;
|
|
|
|
node = dpif_lsample_find_exporter_node(ps, collector_set_id);
|
|
if (node) {
|
|
*group_id = node->exporter.options.group_id;
|
|
}
|
|
return !!node;
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|