Add support for configuring multiple IPFIX collectors for per-flow packet sampling.
Signed-off-by: Romain Lenglet <rleng...@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 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev