Skip to content

Commit

Permalink
ofproto-dpif-ipfix: Fix assertion failure for bad configuration.
Browse files Browse the repository at this point in the history
The assertions in dpif_ipfix_set_options() made some bad assumptions about
flow exporters.  The code that added and removed exporters would add a flow
exporter even if it had an invalid configuration ("broken"), but the
assertions checked that broken flow exporters were not added.  Thus, the
when a flow exporter was broken, ovs-vswitchd would crash due to an
assertion failure.

Here is an example vsctl command that, run in the sandbox, would crash
ovs-vswitchd:

    ovs-vsctl \
        -- add-br br0 \
        -- --id=@br0 get bridge br0 \
        -- --id=@ipfix create ipfix target='["xyzzy"]' \
        -- create flow_sample_collector_set id=1 bridge=@br0 ipfix=@ipfix

The minimal fix would be to remove the assertions, but this would leave
broken flow exporters in place.  This commit goes a little farther and
actually removes broken flow exporters.

This fix pulls code out of an "if" statement to a higher level, so it is a
smaller fix when viewed igoring space changes.

This bug dates back to the introduction of IPFIX in 2013.

VMware-BZ: #1779123
CC: Romain Lenglet <romain.lenglet@berabera.info>
Fixes: 29089a5 ("Implement IPFIX export")
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Jarno Rajahalme <jarno@ovn.org>
  • Loading branch information
blp committed Dec 10, 2016
1 parent e701118 commit ddcfd8e
Showing 1 changed file with 23 additions and 24 deletions.
47 changes: 23 additions & 24 deletions ofproto/ofproto-dpif-ipfix.c
Expand Up @@ -581,6 +581,15 @@ dpif_ipfix_flow_exporter_set_options(
return true;
}

static void
remove_flow_exporter(struct dpif_ipfix *di,
struct dpif_ipfix_flow_exporter_map_node *node)
{
hmap_remove(&di->flow_exporter_map, &node->node);
dpif_ipfix_flow_exporter_destroy(&node->exporter);
free(node);
}

void
dpif_ipfix_set_options(
struct dpif_ipfix *di,
Expand All @@ -591,7 +600,6 @@ dpif_ipfix_set_options(
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;

ovs_mutex_lock(&mutex);
dpif_ipfix_bridge_exporter_set_options(&di->bridge_exporter,
Expand All @@ -610,38 +618,29 @@ dpif_ipfix_set_options(
hash_int(options->collector_set_id, 0));
}
if (!dpif_ipfix_flow_exporter_set_options(&node->exporter, options)) {
n_broken_flow_exporters_options++;
remove_flow_exporter(di, node);
}
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_destroy(&node->exporter);
free(node);
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.
remove_flow_exporter(di, node);
}
}

ovs_assert(hmap_count(&di->flow_exporter_map) ==
(n_flow_exporters_options - n_broken_flow_exporters_options));
ovs_mutex_unlock(&mutex);
}

Expand Down

0 comments on commit ddcfd8e

Please sign in to comment.