Acked-by: Jarno Rajahalme <ja...@ovn.org> With questions for clarification below,
Jarno > On Dec 9, 2016, at 3:12 PM, Ben Pfaff <b...@ovn.org> wrote: > > 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.leng...@berabera.info> > Fixes: 29089a540cfa ("Implement IPFIX export") > Signed-off-by: Ben Pfaff <b...@ovn.org> > --- > ofproto/ofproto-dpif-ipfix.c | 47 ++++++++++++++++++++++---------------------- > tests/ofproto-dpif.at | 11 ++++++++++- > 2 files changed, 33 insertions(+), 25 deletions(-) > > diff --git a/ofproto/ofproto-dpif-ipfix.c b/ofproto/ofproto-dpif-ipfix.c > index 86a6646..23a04ce 100644 > --- a/ofproto/ofproto-dpif-ipfix.c > +++ b/ofproto/ofproto-dpif-ipfix.c > @@ -859,6 +859,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, > @@ -869,7 +878,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, > @@ -888,38 +896,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) { This comparison is removed due to the broken exporters not being in the map, but they are still in the count? > - 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) { It is not possible that this would succeed on a broken ‘options’? I.e., it does not matter that the broken options are still being iterated through here? > + 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); > } > > diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at > index cd90424..4876fde 100644 > --- a/tests/ofproto-dpif.at > +++ b/tests/ofproto-dpif.at > @@ -6279,6 +6279,13 @@ AT_SETUP([ofproto-dpif - Flow IPFIX sanity check]) > OVS_VSWITCHD_START > add_of_ports br0 1 2 > > +# Check for regression against a bug where an invalid target caused an > +# assertion failure and a crash. > +AT_CHECK([ovs-vsctl -- --id=@br0 get Bridge br0 \ > + -- --id=@ipfix create IPFIX targets=\"xyzzy\" \ > + -- --id=@cs create Flow_Sample_Collector_Set id=0 > bridge=@br0 ipfix=@ipfix], > + [0], [ignore]) > + > AT_CHECK([ovs-vsctl -- --id=@br0 get Bridge br0 \ > -- --id=@ipfix create IPFIX targets=\"127.0.0.1:4739\" \ > -- --id=@cs create Flow_Sample_Collector_Set id=1 > bridge=@br0 ipfix=@ipfix], > @@ -6312,7 +6319,9 @@ flow-dump from non-dpdk interfaces: > packets:2, bytes:68, used:0.001s, actions:drop > ]) > > -OVS_VSWITCHD_STOP(["/sending to collector failed/d"]) > +OVS_VSWITCHD_STOP(["/sending to collector failed/d > +/xyzzy/d > +/no collectors/d"]) > AT_CLEANUP > > dnl Flow IPFIX sanity check for tunnel set > -- > 2.10.2 > > _______________________________________________ > dev mailing list > d...@openvswitch.org > https://mail.openvswitch.org/mailman/listinfo/ovs-dev _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev