mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 01:51:26 +00:00
ofproto: Add ofproto-dpif-lsample.
Add a new resource in ofproto-dpif and the corresponding API in ofproto_provider.h to represent and local sampling configuration. Acked-by: Eelco Chaudron <echaudro@redhat.com> Signed-off-by: Adrian Moreno <amorenoz@redhat.com> Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
This commit is contained in:
parent
d0afbf0944
commit
5b99ebc268
@ -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 \
|
||||
|
185
ofproto/ofproto-dpif-lsample.c
Normal file
185
ofproto/ofproto-dpif-lsample.c
Normal file
@ -0,0 +1,185 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
35
ofproto/ofproto-dpif-lsample.h
Normal file
35
ofproto/ofproto-dpif-lsample.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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);
|
||||
|
||||
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);
|
||||
|
||||
#endif /* OFPROTO_DPIF_LSAMPLE_H */
|
@ -50,6 +50,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"
|
||||
@ -1957,6 +1958,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);
|
||||
@ -2516,6 +2518,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 EOPNOTSUPP;
|
||||
}
|
||||
|
||||
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 if (dpif_lsample_set_options(lsample, options, n_opts)) {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
ofproto->backer->need_revalidate = REV_RECONFIGURE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
set_cfm(struct ofport *ofport_, const struct cfm_settings *s)
|
||||
{
|
||||
@ -7201,6 +7238,7 @@ const struct ofproto_class ofproto_dpif_class = {
|
||||
set_sflow,
|
||||
set_ipfix,
|
||||
get_ipfix_stats,
|
||||
set_local_sample,
|
||||
set_cfm,
|
||||
cfm_status_changed,
|
||||
get_cfm_status,
|
||||
|
@ -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;
|
||||
|
@ -1489,6 +1489,15 @@ struct ofproto_class {
|
||||
bool bridge_ipfix, struct ovs_list *replies
|
||||
);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Configures connectivity fault management on 'ofport'.
|
||||
*
|
||||
* If 'cfm_settings' is nonnull, configures CFM according to its members.
|
||||
|
@ -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 EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
/* Connection tracking configuration. */
|
||||
void
|
||||
ofproto_ct_set_zone_timeout_policy(const char *datapath_type, uint16_t zone_id,
|
||||
|
@ -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;
|
||||
@ -371,6 +376,9 @@ int ofproto_set_ipfix(struct ofproto *,
|
||||
const struct ofproto_ipfix_bridge_exporter_options *,
|
||||
const struct ofproto_ipfix_flow_exporter_options *,
|
||||
size_t);
|
||||
int ofproto_set_local_sample(struct ofproto *ofproto,
|
||||
const struct ofproto_lsample_options *,
|
||||
size_t n_options);
|
||||
void ofproto_set_flow_restore_wait(bool flow_restore_wait_db);
|
||||
bool ofproto_get_flow_restore_wait(void);
|
||||
int ofproto_set_stp(struct ofproto *, const struct ofproto_stp_settings *);
|
||||
|
Loading…
x
Reference in New Issue
Block a user