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.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 \
|
||||||
|
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-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,
|
||||||
|
@ -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;
|
||||||
|
@ -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.
|
||||||
|
@ -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,
|
||||||
|
@ -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 *);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user