2
0
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:
Adrian Moreno 2024-07-13 23:23:40 +02:00 committed by Ilya Maximets
parent d0afbf0944
commit 5b99ebc268
8 changed files with 290 additions and 0 deletions

View File

@ -30,6 +30,8 @@ ofproto_libofproto_la_SOURCES = \
ofproto/ofproto-dpif.h \ ofproto/ofproto-dpif.h \
ofproto/ofproto-dpif-ipfix.c \ ofproto/ofproto-dpif-ipfix.c \
ofproto/ofproto-dpif-ipfix.h \ ofproto/ofproto-dpif-ipfix.h \
ofproto/ofproto-dpif-lsample.c \
ofproto/ofproto-dpif-lsample.h \
ofproto/ofproto-dpif-mirror.c \ ofproto/ofproto-dpif-mirror.c \
ofproto/ofproto-dpif-mirror.h \ ofproto/ofproto-dpif-mirror.h \
ofproto/ofproto-dpif-monitor.c \ ofproto/ofproto-dpif-monitor.c \

View 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);
}
}

View 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 */

View File

@ -50,6 +50,7 @@
#include "ofproto-dpif-sflow.h" #include "ofproto-dpif-sflow.h"
#include "ofproto-dpif-trace.h" #include "ofproto-dpif-trace.h"
#include "ofproto-dpif-upcall.h" #include "ofproto-dpif-upcall.h"
#include "ofproto-dpif-lsample.h"
#include "ofproto-dpif-xlate.h" #include "ofproto-dpif-xlate.h"
#include "ofproto-dpif-xlate-cache.h" #include "ofproto-dpif-xlate-cache.h"
#include "openvswitch/ofp-actions.h" #include "openvswitch/ofp-actions.h"
@ -1957,6 +1958,7 @@ destruct(struct ofproto *ofproto_, bool del)
netflow_unref(ofproto->netflow); netflow_unref(ofproto->netflow);
dpif_sflow_unref(ofproto->sflow); dpif_sflow_unref(ofproto->sflow);
dpif_ipfix_unref(ofproto->ipfix); dpif_ipfix_unref(ofproto->ipfix);
dpif_lsample_unref(ofproto->lsample);
hmap_destroy(&ofproto->bundles); hmap_destroy(&ofproto->bundles);
mac_learning_unref(ofproto->ml); mac_learning_unref(ofproto->ml);
mcast_snooping_unref(ofproto->ms); 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); 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 static int
set_cfm(struct ofport *ofport_, const struct cfm_settings *s) set_cfm(struct ofport *ofport_, const struct cfm_settings *s)
{ {
@ -7201,6 +7238,7 @@ const struct ofproto_class ofproto_dpif_class = {
set_sflow, set_sflow,
set_ipfix, set_ipfix,
get_ipfix_stats, get_ipfix_stats,
set_local_sample,
set_cfm, set_cfm,
cfm_status_changed, cfm_status_changed,
get_cfm_status, get_cfm_status,

View File

@ -331,6 +331,7 @@ struct ofproto_dpif {
struct netflow *netflow; struct netflow *netflow;
struct dpif_sflow *sflow; struct dpif_sflow *sflow;
struct dpif_ipfix *ipfix; struct dpif_ipfix *ipfix;
struct dpif_lsample *lsample;
struct hmap bundles; /* Contains "struct ofbundle"s. */ struct hmap bundles; /* Contains "struct ofbundle"s. */
struct mac_learning *ml; struct mac_learning *ml;
struct mcast_snooping *ms; struct mcast_snooping *ms;

View File

@ -1489,6 +1489,15 @@ struct ofproto_class {
bool bridge_ipfix, struct ovs_list *replies 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'. /* Configures connectivity fault management on 'ofport'.
* *
* If 'cfm_settings' is nonnull, configures CFM according to its members. * If 'cfm_settings' is nonnull, configures CFM according to its members.

View File

@ -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. */ /* Connection tracking configuration. */
void void
ofproto_ct_set_zone_timeout_policy(const char *datapath_type, uint16_t zone_id, ofproto_ct_set_zone_timeout_policy(const char *datapath_type, uint16_t zone_id,

View File

@ -103,6 +103,11 @@ struct ofproto_ipfix_flow_exporter_options {
char *virtual_obs_id; char *virtual_obs_id;
}; };
struct ofproto_lsample_options {
uint32_t collector_set_id;
uint32_t group_id;
};
struct ofproto_rstp_status { struct ofproto_rstp_status {
bool enabled; /* If false, ignore other members. */ bool enabled; /* If false, ignore other members. */
rstp_identifier root_id; 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_bridge_exporter_options *,
const struct ofproto_ipfix_flow_exporter_options *, const struct ofproto_ipfix_flow_exporter_options *,
size_t); 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); void ofproto_set_flow_restore_wait(bool flow_restore_wait_db);
bool ofproto_get_flow_restore_wait(void); bool ofproto_get_flow_restore_wait(void);
int ofproto_set_stp(struct ofproto *, const struct ofproto_stp_settings *); int ofproto_set_stp(struct ofproto *, const struct ofproto_stp_settings *);