[ovs-dev] [PATCH 5/6] vswitchd: Add new configuration table for per-flow packet sampling.
Romain Lenglet
rlenglet at vmware.com
Tue Mar 26 01:33:06 UTC 2013
Add support for configuring multiple IPFIX collectors for per-flow
packet sampling.
Signed-off-by: Romain Lenglet <rlenglet at vmware.com>
---
ofproto/ofproto-dpif-ipfix.c | 238 +++++++++++++++++++++++++++++++++++++++----
ofproto/ofproto-dpif-ipfix.h | 6 +-
ofproto/ofproto-dpif.c | 10 +-
ofproto/ofproto-provider.h | 9 +-
ofproto/ofproto.c | 8 +-
ofproto/ofproto.h | 10 +-
utilities/ovs-vsctl.8.in | 7 +-
utilities/ovs-vsctl.c | 13 ++-
vswitchd/bridge.c | 80 ++++++++++++---
vswitchd/vswitch.ovsschema | 22 +++-
vswitchd/vswitch.xml | 23 +++++
11 files changed, 377 insertions(+), 49 deletions(-)
diff --git a/ofproto/ofproto-dpif-ipfix.c b/ofproto/ofproto-dpif-ipfix.c
index 446f2c6..529c016 100644
--- a/ofproto/ofproto-dpif-ipfix.c
+++ b/ofproto/ofproto-dpif-ipfix.c
@@ -17,6 +17,7 @@
#include <config.h>
#include "ofproto-dpif-ipfix.h"
#include "collectors.h"
+#include "hmap.h"
#include "ofproto.h"
#include "sset.h"
#include "util.h"
@@ -29,14 +30,29 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
/* Cf. IETF RFC 5101 Section 10.3.4. */
#define IPFIX_DEFAULT_COLLECTOR_PORT 4739
-struct dpif_ipfix_bridge_exporter {
+struct dpif_ipfix_exporter {
struct collectors *collectors;
+};
+
+struct dpif_ipfix_bridge_exporter {
+ struct dpif_ipfix_exporter exporter;
struct ofproto_ipfix_bridge_exporter_options *options;
uint32_t probability;
};
+struct dpif_ipfix_flow_exporter {
+ struct dpif_ipfix_exporter exporter;
+ struct ofproto_ipfix_flow_exporter_options *options;
+};
+
+struct dpif_ipfix_flow_exporter_map_node {
+ struct hmap_node node;
+ struct dpif_ipfix_flow_exporter exporter;
+};
+
struct dpif_ipfix {
struct dpif_ipfix_bridge_exporter bridge_exporter;
+ struct hmap flow_exporter_map; /* dpif_ipfix_flow_exporter_map_nodes. */
};
static bool
@@ -70,27 +86,78 @@ ofproto_ipfix_bridge_exporter_options_destroy(
}
}
+static bool
+ofproto_ipfix_flow_exporter_options_equal(
+ const struct ofproto_ipfix_flow_exporter_options *a,
+ const struct ofproto_ipfix_flow_exporter_options *b)
+{
+ return (a->collector_set_id == b->collector_set_id
+ && sset_equals(&a->targets, &b->targets));
+}
+
+static struct ofproto_ipfix_flow_exporter_options *
+ofproto_ipfix_flow_exporter_options_clone(
+ const struct ofproto_ipfix_flow_exporter_options *old)
+{
+ struct ofproto_ipfix_flow_exporter_options *new =
+ xmemdup(old, sizeof *old);
+ sset_clone(&new->targets, &old->targets);
+ return new;
+}
+
static void
-dpif_ipfix_bridge_exporter_clear(struct dpif_ipfix_bridge_exporter *exporter)
+ofproto_ipfix_flow_exporter_options_destroy(
+ struct ofproto_ipfix_flow_exporter_options *options)
+{
+ if (options) {
+ sset_destroy(&options->targets);
+ free(options);
+ }
+}
+
+static void
+dpif_ipfix_exporter_clear(struct dpif_ipfix_exporter *exporter)
{
collectors_destroy(exporter->collectors);
exporter->collectors = NULL;
+}
+
+static int
+dpif_ipfix_exporter_set_options(struct dpif_ipfix_exporter *exporter,
+ const struct sset *targets)
+{
+ collectors_destroy(exporter->collectors);
+ collectors_create(targets, IPFIX_DEFAULT_COLLECTOR_PORT,
+ &exporter->collectors);
+ if (exporter->collectors == NULL) {
+ VLOG_WARN_RL(&rl, "no collectors could be initialized, "
+ "IPFIX exporter disabled");
+ dpif_ipfix_exporter_clear(exporter);
+ return -1;
+ }
+ return 0;
+}
+
+static void
+dpif_ipfix_bridge_exporter_clear(struct dpif_ipfix_bridge_exporter *exporter)
+{
+ dpif_ipfix_exporter_clear(&exporter->exporter);
ofproto_ipfix_bridge_exporter_options_destroy(exporter->options);
exporter->options = NULL;
exporter->probability = 0;
}
-static void
+static int
dpif_ipfix_bridge_exporter_set_options(
struct dpif_ipfix_bridge_exporter *exporter,
const struct ofproto_ipfix_bridge_exporter_options *options)
{
bool options_changed;
- if (sset_is_empty(&options->targets)) {
+ if (!options || sset_is_empty(&options->targets)) {
/* No point in doing any work if there are no targets. */
dpif_ipfix_bridge_exporter_clear(exporter);
- return;
+ return 0;
}
options_changed = (
@@ -103,37 +170,160 @@ dpif_ipfix_bridge_exporter_set_options(
* more of the configured collectors failed, so that we should
* retry). */
if (options_changed
- || collectors_count(exporter->collectors)
+ || collectors_count(exporter->exporter.collectors)
< sset_count(&options->targets)) {
- collectors_destroy(exporter->collectors);
- collectors_create(&options->targets, IPFIX_DEFAULT_COLLECTOR_PORT,
- &exporter->collectors);
- if (exporter->collectors == NULL) {
- VLOG_WARN_RL(&rl, "no collectors could be initialized, "
- "IPFIX exporter disabled");
- dpif_ipfix_bridge_exporter_clear(exporter);
- return;
+ if (dpif_ipfix_exporter_set_options(&exporter->exporter,
+ &options->targets)) {
+ return -1;
}
}
/* Avoid reconfiguring if options didn't change. */
if (!options_changed) {
- return;
+ return 0;
}
ofproto_ipfix_bridge_exporter_options_destroy(exporter->options);
exporter->options = ofproto_ipfix_bridge_exporter_options_clone(options);
exporter->probability =
MAX(1, UINT32_MAX / exporter->options->sampling_rate);
+
+ return 0;
+}
+
+/* Hash into 16 bits since that's the standard size for size_t. */
+#define COLLECTOR_SET_ID_HASH(ID) (((ID) & 0xffff) ^ ((ID) >> 16))
+
+static struct dpif_ipfix_flow_exporter_map_node*
+dpif_ipfix_find_flow_exporter_map_node(
+ const struct dpif_ipfix *di, const uint32_t collector_set_id)
+{
+ struct dpif_ipfix_flow_exporter_map_node *exporter_node;
+
+ HMAP_FOR_EACH_WITH_HASH (exporter_node, node,
+ COLLECTOR_SET_ID_HASH(collector_set_id),
+ &di->flow_exporter_map) {
+ if (exporter_node->exporter.options->collector_set_id
+ == collector_set_id) {
+ return exporter_node;
+ }
+ }
+
+ return NULL;
+}
+
+static void
+dpif_ipfix_flow_exporter_clear(struct dpif_ipfix_flow_exporter *exporter)
+{
+ dpif_ipfix_exporter_clear(&exporter->exporter);
+ ofproto_ipfix_flow_exporter_options_destroy(exporter->options);
+ exporter->options = NULL;
+}
+
+static int
+dpif_ipfix_flow_exporter_set_options(
+ struct dpif_ipfix_flow_exporter *exporter,
+ const struct ofproto_ipfix_flow_exporter_options *options)
+{
+ bool options_changed;
+
+ if (sset_is_empty(&options->targets)) {
+ /* No point in doing any work if there are no targets. */
+ dpif_ipfix_flow_exporter_clear(exporter);
+ return 0;
+ }
+
+ options_changed = (
+ !exporter->options
+ || !ofproto_ipfix_flow_exporter_options_equal(
+ options, exporter->options));
+
+ /* Configure collectors if options have changed or if we're
+ * shortchanged in collectors (which indicates that opening one or
+ * more of the configured collectors failed, so that we should
+ * retry). */
+ if (options_changed
+ || collectors_count(exporter->exporter.collectors)
+ < sset_count(&options->targets)) {
+ if (dpif_ipfix_exporter_set_options(&exporter->exporter,
+ &options->targets)) {
+ return -1;
+ }
+ }
+
+ /* Avoid reconfiguring if options didn't change. */
+ if (!options_changed) {
+ return 0;
+ }
+
+ ofproto_ipfix_flow_exporter_options_destroy(exporter->options);
+ exporter->options = ofproto_ipfix_flow_exporter_options_clone(options);
+
+ return 0;
}
void
dpif_ipfix_set_options(
struct dpif_ipfix *di,
- const struct ofproto_ipfix_bridge_exporter_options *bridge_exporter_options)
+ const struct ofproto_ipfix_bridge_exporter_options *bridge_exporter_options,
+ const struct ofproto_ipfix_flow_exporter_options *flow_exporters_options,
+ size_t n_flow_exporters_options)
{
- dpif_ipfix_bridge_exporter_set_options(&(di->bridge_exporter),
- bridge_exporter_options);
+ int i;
+ struct ofproto_ipfix_flow_exporter_options *options;
+ struct dpif_ipfix_flow_exporter_map_node *node, *next;
+
+ if (dpif_ipfix_bridge_exporter_set_options(&di->bridge_exporter,
+ bridge_exporter_options)) {
+ return;
+ }
+
+ /* Add new flow exporters and update current flow exporters. */
+ options = (struct ofproto_ipfix_flow_exporter_options *)
+ flow_exporters_options;
+ for (i = 0; i < n_flow_exporters_options; i++) {
+ node = dpif_ipfix_find_flow_exporter_map_node(
+ di, options->collector_set_id);
+ if (!node) {
+ node = xzalloc(sizeof *node);
+ hmap_insert(&di->flow_exporter_map, &node->node,
+ COLLECTOR_SET_ID_HASH(options->collector_set_id));
+ }
+ if (dpif_ipfix_flow_exporter_set_options(&node->exporter, options)) {
+ return;
+ }
+ options++;
+ }
+
+ /*
+ * assert(hmap_count(&di->flow_exporter_map) >= n_flow_exporters_options);
+ */
+
+ /* Remove dropped flow exporters, if any needs to be removed. */
+ if (hmap_count(&di->flow_exporter_map) > n_flow_exporters_options) {
+ HMAP_FOR_EACH_SAFE (node, next, node, &di->flow_exporter_map) {
+ /* This is slow but doesn't take any extra memory, and
+ * this table is not supposed to contain many rows anyway. */
+ options = (struct ofproto_ipfix_flow_exporter_options *)
+ flow_exporters_options;
+ for (i = 0; i < n_flow_exporters_options; i++) {
+ if (node->exporter.options->collector_set_id
+ == options->collector_set_id) {
+ break;
+ options++;
+ }
+ }
+ if (i == n_flow_exporters_options) { // Not found.
+ hmap_remove(&di->flow_exporter_map, &node->node);
+ dpif_ipfix_flow_exporter_clear(&node->exporter);
+ free(node);
+ }
+ }
+ }
+
+ /*
+ * assert(hmap_count(&di->flow_exporter_map) == n_flow_exporters_options);
+ */
}
struct dpif_ipfix *
@@ -141,6 +331,7 @@ dpif_ipfix_create(void)
{
struct dpif_ipfix *di;
di = xzalloc(sizeof *di);
+ hmap_init(&di->flow_exporter_map);
return di;
}
@@ -149,6 +340,7 @@ dpif_ipfix_destroy(struct dpif_ipfix *di)
{
if (di) {
dpif_ipfix_clear(di);
+ hmap_destroy(&di->flow_exporter_map);
free(di);
}
}
@@ -156,5 +348,13 @@ dpif_ipfix_destroy(struct dpif_ipfix *di)
void
dpif_ipfix_clear(struct dpif_ipfix *di)
{
- dpif_ipfix_bridge_exporter_clear(&(di->bridge_exporter));
+ struct dpif_ipfix_flow_exporter_map_node *node, *next;
+
+ dpif_ipfix_bridge_exporter_clear(&di->bridge_exporter);
+
+ HMAP_FOR_EACH_SAFE (node, next, node, &di->flow_exporter_map) {
+ hmap_remove(&di->flow_exporter_map, &node->node);
+ dpif_ipfix_flow_exporter_clear(&node->exporter);
+ free(node);
+ }
}
diff --git a/ofproto/ofproto-dpif-ipfix.h b/ofproto/ofproto-dpif-ipfix.h
index 297be56..5b46c6b 100644
--- a/ofproto/ofproto-dpif-ipfix.h
+++ b/ofproto/ofproto-dpif-ipfix.h
@@ -17,13 +17,17 @@
#ifndef OFPROTO_DPIF_IPFIX_H
#define OFPROTO_DPIF_IPFIX_H 1
+#include <stddef.h>
+
struct ofproto_ipfix_bridge_exporter_options;
+struct ofproto_ipfix_flow_exporter_options;
struct dpif_ipfix *dpif_ipfix_create(void);
void dpif_ipfix_destroy(struct dpif_ipfix *);
void dpif_ipfix_set_options(
struct dpif_ipfix *,
- const struct ofproto_ipfix_bridge_exporter_options *);
+ const struct ofproto_ipfix_bridge_exporter_options *,
+ const struct ofproto_ipfix_flow_exporter_options *, size_t);
void dpif_ipfix_clear(struct dpif_ipfix *);
#endif /* ofproto/ofproto-dpif-ipfix.h */
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index bd92694..9d5fa74 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -1793,16 +1793,20 @@ set_sflow(struct ofproto *ofproto_,
static int
set_ipfix(
struct ofproto *ofproto_,
- const struct ofproto_ipfix_bridge_exporter_options *bridge_exporter_options)
+ const struct ofproto_ipfix_bridge_exporter_options *bridge_exporter_options,
+ const struct ofproto_ipfix_flow_exporter_options *flow_exporters_options,
+ size_t n_flow_exporters_options)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
struct dpif_ipfix *di = ofproto->ipfix;
- if (bridge_exporter_options) {
+ if (bridge_exporter_options || flow_exporters_options) {
if (!di) {
di = ofproto->ipfix = dpif_ipfix_create();
}
- dpif_ipfix_set_options(di, bridge_exporter_options);
+ dpif_ipfix_set_options(
+ di, bridge_exporter_options, flow_exporters_options,
+ n_flow_exporters_options);
} else {
if (di) {
dpif_ipfix_destroy(di);
diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
index 2272ff2..2f429e0 100644
--- a/ofproto/ofproto-provider.h
+++ b/ofproto/ofproto-provider.h
@@ -1110,15 +1110,18 @@ struct ofproto_class {
const struct ofproto_sflow_options *sflow_options);
/* Configures IPFIX on 'ofproto' according to the options in
- * 'bridge_exporter_options', or turns off IPFIX if
- * 'bridge_exporter_options' is NULL.
+ * 'bridge_exporter_options' and the 'flow_exporters_options'
+ * array, or turns off IPFIX if 'bridge_exporter_options' and
+ * 'flow_exporters_options' is NULL.
*
* EOPNOTSUPP as a return value indicates that 'ofproto' does not support
* IPFIX, as does a null pointer. */
int (*set_ipfix)(
struct ofproto *ofproto,
const struct ofproto_ipfix_bridge_exporter_options
- *bridge_exporter_options);
+ *bridge_exporter_options,
+ const struct ofproto_ipfix_flow_exporter_options
+ *flow_exporters_options, size_t n_flow_exporters_options);
/* Configures connectivity fault management on 'ofport'.
*
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index e142759..b85b3e0 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -643,13 +643,15 @@ ofproto_set_sflow(struct ofproto *ofproto,
int
ofproto_set_ipfix(struct ofproto *ofproto,
- const struct ofproto_ipfix_bridge_exporter_options *oibeo)
+ const struct ofproto_ipfix_bridge_exporter_options *bo,
+ const struct ofproto_ipfix_flow_exporter_options *fo,
+ size_t n_fo)
{
/* TODO: Check the options. */
if (ofproto->ofproto_class->set_ipfix) {
- return ofproto->ofproto_class->set_ipfix(ofproto, oibeo);
+ return ofproto->ofproto_class->set_ipfix(ofproto, bo, fo, n_fo);
} else {
- return oibeo ? EOPNOTSUPP : 0;
+ return (bo || fo) ? EOPNOTSUPP : 0;
}
}
diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h
index 5cec201..d05b999 100644
--- a/ofproto/ofproto.h
+++ b/ofproto/ofproto.h
@@ -68,6 +68,7 @@ struct ofproto_sflow_options {
char *control_ip;
};
+
struct ofproto_ipfix_bridge_exporter_options {
struct sset targets;
uint32_t sampling_rate;
@@ -75,6 +76,11 @@ struct ofproto_ipfix_bridge_exporter_options {
uint32_t obs_point_id; /* Bridge-wide Observation Point ID. */
};
+struct ofproto_ipfix_flow_exporter_options {
+ uint32_t collector_set_id;
+ struct sset targets;
+};
+
struct ofproto_stp_settings {
stp_identifier system_id;
uint16_t priority;
@@ -237,7 +243,9 @@ int ofproto_set_netflow(struct ofproto *,
const struct netflow_options *nf_options);
int ofproto_set_sflow(struct ofproto *, const struct ofproto_sflow_options *);
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 *,
+ size_t);
int ofproto_set_stp(struct ofproto *, const struct ofproto_stp_settings *);
int ofproto_get_stp_status(struct ofproto *, struct ofproto_stp_status *);
diff --git a/utilities/ovs-vsctl.8.in b/utilities/ovs-vsctl.8.in
index 003e99a..79e4b78 100644
--- a/utilities/ovs-vsctl.8.in
+++ b/utilities/ovs-vsctl.8.in
@@ -527,11 +527,14 @@ The global SSL configuration for \fBovs\-vswitchd\fR. The record
attached to the \fBOpen_vSwitch\fR table may be identified by
specifying \fB.\fR as the record name.
.IP "\fBsFlow\fR"
-An sFlow configuration attached to a bridge. Records may be
+An sFlow exporter configuration attached to a bridge. Records may be
identified by bridge name.
.IP "\fBIPFIX\fR"
-An IPFIX configuration attached to a bridge. Records may be
+An IPFIX exporter configuration attached to a bridge. Records may be
identified by bridge name.
+.IP "\fBFlowSampleCollectorSet\fR"
+An IPFIX exporter configuration attached to a bridge for sampling
+packets on a per-flow basis using OpenFlow \fBsample\fR actions.
.PP
Record names must be specified in full and with correct
capitalization. Names of tables and columns are not case-sensitive,
diff --git a/utilities/ovs-vsctl.c b/utilities/ovs-vsctl.c
index 4c1ec17..ef7beec 100644
--- a/utilities/ovs-vsctl.c
+++ b/utilities/ovs-vsctl.c
@@ -1479,6 +1479,7 @@ cmd_emer_reset(struct vsctl_context *ctx)
const struct ovsrec_ssl *ssl, *next_ssl;
const struct ovsrec_sflow *sflow, *next_sflow;
const struct ovsrec_ipfix *ipfix, *next_ipfix;
+ const struct ovsrec_flowsamplecollectorset *fscset, *next_fscset;
/* Reset the Open_vSwitch table. */
ovsrec_open_vswitch_set_manager_options(ctx->ovs, NULL, 0);
@@ -1546,6 +1547,10 @@ cmd_emer_reset(struct vsctl_context *ctx)
ovsrec_ipfix_delete(ipfix);
}
+ OVSREC_FLOWSAMPLECOLLECTORSET_FOR_EACH_SAFE (fscset, next_fscset, idl) {
+ ovsrec_flowsamplecollectorset_delete(fscset);
+ }
+
vsctl_context_invalidate_cache(ctx);
}
@@ -2471,7 +2476,8 @@ struct vsctl_table_class {
static const struct vsctl_table_class tables[] = {
{&ovsrec_table_bridge,
{{&ovsrec_table_bridge, &ovsrec_bridge_col_name, NULL},
- {NULL, NULL, NULL}}},
+ {&ovsrec_table_flowsamplecollectorset, NULL,
+ &ovsrec_flowsamplecollectorset_col_bridge}}},
{&ovsrec_table_controller,
{{&ovsrec_table_bridge,
@@ -2529,6 +2535,11 @@ static const struct vsctl_table_class tables[] = {
{{&ovsrec_table_bridge,
&ovsrec_bridge_col_name,
&ovsrec_bridge_col_ipfix},
+ {&ovsrec_table_flowsamplecollectorset, NULL,
+ &ovsrec_flowsamplecollectorset_col_ipfix}}},
+
+ {&ovsrec_table_flowsamplecollectorset,
+ {{NULL, NULL, NULL},
{NULL, NULL, NULL}}},
{NULL, {{NULL, NULL, NULL}, {NULL, NULL, NULL}}}
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index d2c3907..15c2aeb 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -374,6 +374,7 @@ bridge_init(const char *remote)
ovsdb_idl_omit(idl, &ovsrec_netflow_col_external_ids);
ovsdb_idl_omit(idl, &ovsrec_sflow_col_external_ids);
ovsdb_idl_omit(idl, &ovsrec_ipfix_col_external_ids);
+ ovsdb_idl_omit(idl, &ovsrec_flowsamplecollectorset_col_external_ids);
ovsdb_idl_omit(idl, &ovsrec_manager_col_external_ids);
ovsdb_idl_omit(idl, &ovsrec_manager_col_inactivity_probe);
@@ -942,30 +943,79 @@ bridge_configure_sflow(struct bridge *br, int *sflow_bridge_number)
static void
bridge_configure_ipfix(struct bridge *br)
{
- const struct ovsrec_ipfix *cfg = br->cfg->ipfix;
- struct ofproto_ipfix_bridge_exporter_options oibeo;
+ const struct ovsrec_ipfix *bridge_exporter_cfg = br->cfg->ipfix;
+ const struct ovsrec_flowsamplecollectorset *flow_exporter_cfg;
+ struct ofproto_ipfix_bridge_exporter_options bridge_exporter_options;
+ struct ofproto_ipfix_flow_exporter_options *flow_exporters_options = NULL;
+ size_t n_flow_exporters_options = 0;
+
+ OVSREC_FLOWSAMPLECOLLECTORSET_FOR_EACH(flow_exporter_cfg, idl) {
+ if (flow_exporter_cfg->bridge == br->cfg) {
+ n_flow_exporters_options++;
+ }
+ }
- if (!cfg) {
- ofproto_set_ipfix(br->ofproto, NULL);
+ if (!bridge_exporter_cfg && n_flow_exporters_options == 0) {
+ ofproto_set_ipfix(br->ofproto, NULL, NULL, 0);
return;
}
- memset(&oibeo, 0, sizeof oibeo);
+ if (bridge_exporter_cfg) {
+ memset(&bridge_exporter_options, 0, sizeof bridge_exporter_options);
- /* Collectors. */
- sset_init(&oibeo.targets);
- sset_add_array(&oibeo.targets, cfg->targets, cfg->n_targets);
+ sset_init(&bridge_exporter_options.targets);
+ sset_add_array(&bridge_exporter_options.targets,
+ bridge_exporter_cfg->targets,
+ bridge_exporter_cfg->n_targets);
- oibeo.sampling_rate = SFL_DEFAULT_SAMPLING_RATE;
- if (cfg->sampling) {
- oibeo.sampling_rate = *cfg->sampling;
+ bridge_exporter_options.sampling_rate = SFL_DEFAULT_SAMPLING_RATE;
+ if (bridge_exporter_cfg->sampling) {
+ bridge_exporter_options.sampling_rate =
+ *bridge_exporter_cfg->sampling;
+ }
+ bridge_exporter_options.obs_domain_id =
+ *bridge_exporter_cfg->obs_domain_id;
+ bridge_exporter_options.obs_point_id =
+ *bridge_exporter_cfg->obs_point_id;
+ }
+
+ if (n_flow_exporters_options > 0) {
+ struct ofproto_ipfix_flow_exporter_options *options;
+ flow_exporters_options = xcalloc(n_flow_exporters_options,
+ sizeof *flow_exporters_options);
+ options = flow_exporters_options;
+ OVSREC_FLOWSAMPLECOLLECTORSET_FOR_EACH(flow_exporter_cfg, idl) {
+ if (flow_exporter_cfg->bridge == br->cfg) {
+ options->collector_set_id = flow_exporter_cfg->id;
+ sset_init(&options->targets);
+ sset_add_array(&options->targets,
+ flow_exporter_cfg->ipfix->targets,
+ flow_exporter_cfg->ipfix->n_targets);
+
+ options++;
+ }
+ }
}
- oibeo.obs_domain_id = *cfg->obs_domain_id;
- oibeo.obs_point_id = *cfg->obs_point_id;
- ofproto_set_ipfix(br->ofproto, &oibeo);
+ ofproto_set_ipfix(
+ br->ofproto,
+ bridge_exporter_cfg ? &bridge_exporter_options : NULL,
+ flow_exporters_options, n_flow_exporters_options);
+
+ if (bridge_exporter_cfg) {
+ sset_destroy(&bridge_exporter_options.targets);
+ }
- sset_destroy(&oibeo.targets);
+ if (n_flow_exporters_options > 0) {
+ struct ofproto_ipfix_flow_exporter_options *options =
+ flow_exporters_options;
+ size_t i;
+ for (i = 0; i < n_flow_exporters_options; i++) {
+ sset_destroy(&options->targets);
+ options++;
+ }
+ free(flow_exporters_options);
+ }
}
static void
diff --git a/vswitchd/vswitch.ovsschema b/vswitchd/vswitch.ovsschema
index 0d1f4fd..2cf6ce5 100644
--- a/vswitchd/vswitch.ovsschema
+++ b/vswitchd/vswitch.ovsschema
@@ -1,6 +1,6 @@
{"name": "Open_vSwitch",
"version": "7.1.0",
- "cksum": "4242091849 18457",
+ "cksum": "1616135014 19188",
"tables": {
"Open_vSwitch": {
"columns": {
@@ -409,6 +409,26 @@
"external_ids": {
"type": {"key": "string", "value": "string",
"min": 0, "max": "unlimited"}}}},
+ "FlowSampleCollectorSet": {
+ "columns": {
+ "id": {
+ "type": {"key": {"type": "integer",
+ "minInteger": 0,
+ "maxInteger": 4294967295},
+ "min": 1, "max": 1}},
+ "bridge": {
+ "type": {"key": {"type": "uuid",
+ "refTable": "Bridge"},
+ "min": 1, "max": 1}},
+ "ipfix": {
+ "type": {"key": {"type": "uuid",
+ "refTable": "IPFIX"},
+ "min": 0, "max": 1}},
+ "external_ids": {
+ "type": {"key": "string", "value": "string",
+ "min": 0, "max": "unlimited"}}},
+ "isRoot": true,
+ "indexes": [["id", "bridge"]]},
"Controller": {
"columns": {
"target": {
diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
index 24452b1..415717c 100644
--- a/vswitchd/vswitch.xml
+++ b/vswitchd/vswitch.xml
@@ -3207,4 +3207,27 @@
</group>
</table>
+ <table name="FlowSampleCollectorSet">
+ <p>A set of IPFIX collectors of packet samples generated by
+ OpenFlow <code>sample</code> actions.</p>
+
+ <column name="id">
+ Unique ID of this collector set, to be used as the
+ <code>collector_set_id</code> in OpenFlow <code>sample</code>
+ actions.
+ </column>
+
+ <column name="ipfix">
+ Configuration of the set of IPFIX collectors to send one flow
+ record per sampled packet to.
+ </column>
+
+ <group title="Common Columns">
+ The overall purpose of these columns is described under <code>Common
+ Columns</code> at the beginning of this document.
+
+ <column name="external_ids"/>
+ </group>
+ </table>
+
</database>
--
1.8.1.3
More information about the dev
mailing list