Add support for configuring multiple IPFIX collectors for per-flow packet sampling.
Signed-off-by: Romain Lenglet <[email protected]> --- ofproto/ofproto-dpif-ipfix.c | 221 ++++++++++++++++++++++++++++++++++++++++--- 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 | 21 +++- vswitchd/bridge.c | 74 ++++++++++++--- vswitchd/vswitch.ovsschema | 22 ++++- vswitchd/vswitch.xml | 34 ++++++- 11 files changed, 375 insertions(+), 47 deletions(-) diff --git a/ofproto/ofproto-dpif-ipfix.c b/ofproto/ofproto-dpif-ipfix.c index c5b1fb8..b7cff6b 100644 --- a/ofproto/ofproto-dpif-ipfix.c +++ b/ofproto/ofproto-dpif-ipfix.c @@ -17,6 +17,8 @@ #include <config.h> #include "ofproto-dpif-ipfix.h" #include "collectors.h" +#include "hash.h" +#include "hmap.h" #include "ofproto.h" #include "sset.h" #include "util.h" @@ -29,14 +31,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,11 +87,62 @@ 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 bool +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 false; + } + return true; +} + +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; @@ -87,7 +155,7 @@ dpif_ipfix_bridge_exporter_set_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; @@ -103,15 +171,10 @@ 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); + if (!dpif_ipfix_exporter_set_options(&exporter->exporter, + &options->targets)) { return; } } @@ -127,13 +190,133 @@ dpif_ipfix_bridge_exporter_set_options( MAX(1, UINT32_MAX / exporter->options->sampling_rate); } +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, + hash_int(collector_set_id, 0), + &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 bool +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 true; + } + + 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 false; + } + } + + /* Avoid reconfiguring if options didn't change. */ + if (!options_changed) { + return true; + } + + ofproto_ipfix_flow_exporter_options_destroy(exporter->options); + exporter->options = ofproto_ipfix_flow_exporter_options_clone(options); + + return true; +} + 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), + int i; + struct ofproto_ipfix_flow_exporter_options *options; + struct dpif_ipfix_flow_exporter_map_node *node, *next; + size_t n_broken_flow_exporters_options = 0; + + dpif_ipfix_bridge_exporter_set_options(&di->bridge_exporter, bridge_exporter_options); + + /* 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, + hash_int(options->collector_set_id, 0)); + } + if (!dpif_ipfix_flow_exporter_set_options(&node->exporter, options)) { + n_broken_flow_exporters_options++; + } + options++; + } + + ovs_assert(hmap_count(&di->flow_exporter_map) >= + (n_flow_exporters_options - n_broken_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); + } + } + } + + ovs_assert(hmap_count(&di->flow_exporter_map) == + (n_flow_exporters_options - n_broken_flow_exporters_options)); } struct dpif_ipfix * @@ -141,13 +324,22 @@ dpif_ipfix_create(void) { struct dpif_ipfix *di; di = xzalloc(sizeof *di); + hmap_init(&di->flow_exporter_map); return di; } static 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); + } } void @@ -155,6 +347,7 @@ dpif_ipfix_destroy(struct dpif_ipfix *di) { if (di) { dpif_ipfix_clear(di); + hmap_destroy(&di->flow_exporter_map); free(di); } } diff --git a/ofproto/ofproto-dpif-ipfix.h b/ofproto/ofproto-dpif-ipfix.h index 7829965..dc9a9cb 100644 --- a/ofproto/ofproto-dpif-ipfix.h +++ b/ofproto/ofproto-dpif-ipfix.h @@ -17,12 +17,16 @@ #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); #endif /* ofproto/ofproto-dpif-ipfix.h */ diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 69ea0a8..fb70320 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -1920,16 +1920,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 d8a71d0..85fe781 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -643,12 +643,14 @@ 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) { 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 e67c470..bb799b5 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..fd29b06 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 "\fBFlow_Sample_Collector_Set\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 758aca5..19ab472 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_flow_sample_collector_set *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_FLOW_SAMPLE_COLLECTOR_SET_FOR_EACH_SAFE (fscset, next_fscset, idl) { + ovsrec_flow_sample_collector_set_delete(fscset); + } + vsctl_context_invalidate_cache(ctx); } @@ -1675,6 +1680,7 @@ del_bridge(struct vsctl_context *ctx, struct vsctl_bridge *br) { struct vsctl_bridge *child, *next_child; struct vsctl_port *port, *next_port; + const struct ovsrec_flow_sample_collector_set *fscset, *next_fscset; HMAP_FOR_EACH_SAFE (child, next_child, children_node, &br->children) { del_bridge(ctx, child); @@ -1684,6 +1690,13 @@ del_bridge(struct vsctl_context *ctx, struct vsctl_bridge *br) del_port(ctx, port); } + OVSREC_FLOW_SAMPLE_COLLECTOR_SET_FOR_EACH_SAFE (fscset, next_fscset, + ctx->idl) { + if (fscset->bridge == br->br_cfg) { + ovsrec_flow_sample_collector_set_delete(fscset); + } + } + del_cached_bridge(ctx, br); } @@ -2471,7 +2484,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_flow_sample_collector_set, NULL, + &ovsrec_flow_sample_collector_set_col_bridge}}}, {&ovsrec_table_controller, {{&ovsrec_table_bridge, @@ -2529,6 +2543,11 @@ static const struct vsctl_table_class tables[] = { {{&ovsrec_table_bridge, &ovsrec_bridge_col_name, &ovsrec_bridge_col_ipfix}, + {&ovsrec_table_flow_sample_collector_set, NULL, + &ovsrec_flow_sample_collector_set_col_ipfix}}}, + + {&ovsrec_table_flow_sample_collector_set, + {{NULL, NULL, NULL}, {NULL, NULL, NULL}}}, {NULL, {{NULL, NULL, NULL}, {NULL, NULL, NULL}}} diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index 77b4d5f..899fd64 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -391,6 +391,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_flow_sample_collector_set_col_external_ids); ovsdb_idl_omit(idl, &ovsrec_manager_col_external_ids); ovsdb_idl_omit(idl, &ovsrec_manager_col_inactivity_probe); @@ -950,30 +951,73 @@ 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 *be_cfg = br->cfg->ipfix; + const struct ovsrec_flow_sample_collector_set *fe_cfg; + struct ofproto_ipfix_bridge_exporter_options be_opts; + struct ofproto_ipfix_flow_exporter_options *fe_opts = NULL; + size_t n_fe_opts = 0; + + OVSREC_FLOW_SAMPLE_COLLECTOR_SET_FOR_EACH(fe_cfg, idl) { + if (fe_cfg->bridge == br->cfg) { + n_fe_opts++; + } + } - if (!cfg) { - ofproto_set_ipfix(br->ofproto, NULL); + if (!be_cfg && n_fe_opts == 0) { + ofproto_set_ipfix(br->ofproto, NULL, NULL, 0); return; } - memset(&oibeo, 0, sizeof oibeo); + if (be_cfg) { + memset(&be_opts, 0, sizeof be_opts); - /* Collectors. */ - sset_init(&oibeo.targets); - sset_add_array(&oibeo.targets, cfg->targets, cfg->n_targets); + sset_init(&be_opts.targets); + sset_add_array(&be_opts.targets, be_cfg->targets, be_cfg->n_targets); - oibeo.sampling_rate = SFL_DEFAULT_SAMPLING_RATE; - if (cfg->sampling) { - oibeo.sampling_rate = *cfg->sampling; + if (be_cfg->sampling) { + be_opts.sampling_rate = *be_cfg->sampling; + } else { + be_opts.sampling_rate = SFL_DEFAULT_SAMPLING_RATE; + } + if (be_cfg->obs_domain_id) { + be_opts.obs_domain_id = *be_cfg->obs_domain_id; + } + if (be_cfg->obs_point_id) { + be_opts.obs_point_id = *be_cfg->obs_point_id; + } } - oibeo.obs_domain_id = *cfg->obs_domain_id; - oibeo.obs_point_id = *cfg->obs_point_id; - ofproto_set_ipfix(br->ofproto, &oibeo); + if (n_fe_opts > 0) { + struct ofproto_ipfix_flow_exporter_options *opts; + fe_opts = xcalloc(n_fe_opts, sizeof *fe_opts); + opts = fe_opts; + OVSREC_FLOW_SAMPLE_COLLECTOR_SET_FOR_EACH(fe_cfg, idl) { + if (fe_cfg->bridge == br->cfg) { + opts->collector_set_id = fe_cfg->id; + sset_init(&opts->targets); + sset_add_array(&opts->targets, fe_cfg->ipfix->targets, + fe_cfg->ipfix->n_targets); + opts++; + } + } + } - sset_destroy(&oibeo.targets); + ofproto_set_ipfix(br->ofproto, be_cfg ? &be_opts : NULL, fe_opts, + n_fe_opts); + + if (be_cfg) { + sset_destroy(&be_opts.targets); + } + + if (n_fe_opts > 0) { + struct ofproto_ipfix_flow_exporter_options *opts = fe_opts; + size_t i; + for (i = 0; i < n_fe_opts; i++) { + sset_destroy(&opts->targets); + opts++; + } + free(fe_opts); + } } static void diff --git a/vswitchd/vswitch.ovsschema b/vswitchd/vswitch.ovsschema index 0d1f4fd..3f2ce3a 100644 --- a/vswitchd/vswitch.ovsschema +++ b/vswitchd/vswitch.ovsschema @@ -1,6 +1,6 @@ {"name": "Open_vSwitch", "version": "7.1.0", - "cksum": "4242091849 18457", + "cksum": "432130924 19191", "tables": { "Open_vSwitch": { "columns": { @@ -409,6 +409,26 @@ "external_ids": { "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}}}, + "Flow_Sample_Collector_Set": { + "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..e0dccb1 100644 --- a/vswitchd/vswitch.xml +++ b/vswitchd/vswitch.xml @@ -3180,7 +3180,7 @@ defaults to 400, which means one out of 400 packets, on average, will be sent to each target collector. Ignored for per-flow sampling, i.e. when this row is referenced from a <ref - table="FlowSampleCollectorSet"/>. + table="Flow_Sample_Collector_Set"/>. </column> <column name="obs_domain_id"> @@ -3188,7 +3188,7 @@ from a <ref table="Bridge"/>, the IPFIX Observation Domain ID sent in each IPFIX packet. If not specified, defaults to 0. Ignored for per-flow sampling, i.e. when this row is referenced - from a <ref table="FlowSampleCollectorSet"/>. + from a <ref table="Flow_Sample_Collector_Set"/>. </column> <column name="obs_point_id"> @@ -3196,7 +3196,35 @@ from a <ref table="Bridge"/>, the IPFIX Observation Point ID sent in each IPFIX flow record. If not specified, defaults to 0. Ignored for per-flow sampling, i.e. when this row is - referenced from a <ref table="FlowSampleCollectorSet"/>. + referenced from a <ref table="Flow_Sample_Collector_Set"/>. + </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> + + <table name="Flow_Sample_Collector_Set"> + <p>A set of IPFIX collectors of packet samples generated by + OpenFlow <code>sample</code> actions.</p> + + <column name="id"> + The ID of this collector set, unique among the bridge's + collector sets, to be used as the <code>collector_set_id</code> + in OpenFlow <code>sample</code> actions. + </column> + + <column name="bridge"> + The bridge into which OpenFlow <code>sample</code> actions can + be added to send packet samples to this set of IPFIX collectors. + </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"> -- 1.8.1.3 _______________________________________________ dev mailing list [email protected] http://openvswitch.org/mailman/listinfo/dev
