On Wed, Nov 27, 2019 at 5:16 AM Dumitru Ceara <dce...@redhat.com> wrote: > > The incremental processing engine might stop a run before the > en_runtime_data node is processed. In such cases the ed_runtime_data > fields might contain pointers to already deleted SB records. For > example, if a port binding corresponding to a patch port is removed from > the SB database and the incremental processing engine aborts before the > en_runtime_data node is processed then the corresponding local_datapath > hashtable entry in ed_runtime_data is stale and will store a pointer to > the already freed sbrec_port_binding record. > > This will cause invalid memory accesses in various places (e.g., > pinctrl_run() -> prepare_ipv6_ras()). > > To fix the issue we introduce the concept of "internal_data" vs "data" in > engine nodes. The first field, "internal_data", is data that can be accessed > by the incremental engine nodes handlers (data from other nodes must be > considered read-only and data from other nodes must not be accessed if the > nodes haven't been refreshed in the current iteration). The second field, > "data" is a pointer reset at engine_run() and if non-NULL indicates to > users outside the incremental engine that the data is safe to use. > > This commit also adds an "is_valid()" method to engine nodes to allow > users to override the default behavior of determining if data is valid in a > node (e.g., for the ct-zones node the data is always safe to access). > > CC: Han Zhou <hzh...@ebay.com> > Fixes: ca278d98a4f5 ("ovn-controller: Initial use of incremental engine - quiet mode.") > Signed-off-by: Dumitru Ceara <dce...@redhat.com> > --- > controller/ovn-controller.c | 230 ++++++++++++++++++++++--------------------- > lib/inc-proc-eng.c | 36 ++++++- > lib/inc-proc-eng.h | 28 +++++ > 3 files changed, 174 insertions(+), 120 deletions(-) > > diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c > index f5a83f9..18cc5fe 100644 > --- a/controller/ovn-controller.c > +++ b/controller/ovn-controller.c > @@ -741,8 +741,7 @@ struct ed_type_ofctrl_is_connected { > static void > en_ofctrl_is_connected_init(struct engine_node *node) > { > - struct ed_type_ofctrl_is_connected *data = > - (struct ed_type_ofctrl_is_connected *)node->data; > + struct ed_type_ofctrl_is_connected *data = node->internal_data; > data->connected = false; > } > > @@ -754,8 +753,7 @@ en_ofctrl_is_connected_cleanup(struct engine_node *node OVS_UNUSED) > static void > en_ofctrl_is_connected_run(struct engine_node *node) > { > - struct ed_type_ofctrl_is_connected *data = > - (struct ed_type_ofctrl_is_connected *)node->data; > + struct ed_type_ofctrl_is_connected *data = node->internal_data; > if (data->connected != ofctrl_is_connected()) { > data->connected = !data->connected; > engine_set_node_state(node, EN_UPDATED); > @@ -775,7 +773,7 @@ struct ed_type_addr_sets { > static void > en_addr_sets_init(struct engine_node *node) > { > - struct ed_type_addr_sets *as = (struct ed_type_addr_sets *)node->data; > + struct ed_type_addr_sets *as = node->internal_data; > shash_init(&as->addr_sets); > as->change_tracked = false; > sset_init(&as->new); > @@ -786,7 +784,7 @@ en_addr_sets_init(struct engine_node *node) > static void > en_addr_sets_cleanup(struct engine_node *node) > { > - struct ed_type_addr_sets *as = (struct ed_type_addr_sets *)node->data; > + struct ed_type_addr_sets *as = node->internal_data; > expr_const_sets_destroy(&as->addr_sets); > shash_destroy(&as->addr_sets); > sset_destroy(&as->new); > @@ -797,7 +795,7 @@ en_addr_sets_cleanup(struct engine_node *node) > static void > en_addr_sets_run(struct engine_node *node) > { > - struct ed_type_addr_sets *as = (struct ed_type_addr_sets *)node->data; > + struct ed_type_addr_sets *as = node->internal_data; > > sset_clear(&as->new); > sset_clear(&as->deleted); > @@ -817,7 +815,7 @@ en_addr_sets_run(struct engine_node *node) > static bool > addr_sets_sb_address_set_handler(struct engine_node *node) > { > - struct ed_type_addr_sets *as = (struct ed_type_addr_sets *)node->data; > + struct ed_type_addr_sets *as = node->internal_data; > > sset_clear(&as->new); > sset_clear(&as->deleted); > @@ -852,7 +850,7 @@ struct ed_type_port_groups{ > static void > en_port_groups_init(struct engine_node *node) > { > - struct ed_type_port_groups *pg = (struct ed_type_port_groups *)node->data; > + struct ed_type_port_groups *pg = node->internal_data; > shash_init(&pg->port_groups); > pg->change_tracked = false; > sset_init(&pg->new); > @@ -863,7 +861,7 @@ en_port_groups_init(struct engine_node *node) > static void > en_port_groups_cleanup(struct engine_node *node) > { > - struct ed_type_port_groups *pg = (struct ed_type_port_groups *)node->data; > + struct ed_type_port_groups *pg = node->internal_data; > expr_const_sets_destroy(&pg->port_groups); > shash_destroy(&pg->port_groups); > sset_destroy(&pg->new); > @@ -874,7 +872,7 @@ en_port_groups_cleanup(struct engine_node *node) > static void > en_port_groups_run(struct engine_node *node) > { > - struct ed_type_port_groups *pg = (struct ed_type_port_groups *)node->data; > + struct ed_type_port_groups *pg = node->internal_data; > > sset_clear(&pg->new); > sset_clear(&pg->deleted); > @@ -894,7 +892,7 @@ en_port_groups_run(struct engine_node *node) > static bool > port_groups_sb_port_group_handler(struct engine_node *node) > { > - struct ed_type_port_groups *pg = (struct ed_type_port_groups *)node->data; > + struct ed_type_port_groups *pg = node->internal_data; > > sset_clear(&pg->new); > sset_clear(&pg->deleted); > @@ -938,8 +936,7 @@ struct ed_type_runtime_data { > static void > en_runtime_data_init(struct engine_node *node) > { > - struct ed_type_runtime_data *data = > - (struct ed_type_runtime_data *)node->data; > + struct ed_type_runtime_data *data = node->internal_data; > > hmap_init(&data->local_datapaths); > sset_init(&data->local_lports); > @@ -950,8 +947,7 @@ en_runtime_data_init(struct engine_node *node) > static void > en_runtime_data_cleanup(struct engine_node *node) > { > - struct ed_type_runtime_data *data = > - (struct ed_type_runtime_data *)node->data; > + struct ed_type_runtime_data *data = node->internal_data; > > sset_destroy(&data->local_lports); > sset_destroy(&data->local_lport_ids); > @@ -970,8 +966,7 @@ en_runtime_data_cleanup(struct engine_node *node) > static void > en_runtime_data_run(struct engine_node *node) > { > - struct ed_type_runtime_data *data = > - (struct ed_type_runtime_data *)node->data; > + struct ed_type_runtime_data *data = node->internal_data; > struct hmap *local_datapaths = &data->local_datapaths; > struct sset *local_lports = &data->local_lports; > struct sset *local_lport_ids = &data->local_lport_ids; > @@ -1019,8 +1014,7 @@ en_runtime_data_run(struct engine_node *node) > ovs_assert(chassis); > > struct ed_type_ofctrl_is_connected *ed_ofctrl_is_connected = > - (struct ed_type_ofctrl_is_connected *)engine_get_input( > - "ofctrl_is_connected", node)->data; > + engine_get_input("ofctrl_is_connected", node)->internal_data; > if (ed_ofctrl_is_connected->connected) { > /* Calculate the active tunnels only if have an an active > * OpenFlow connection to br-int. > @@ -1076,8 +1070,7 @@ en_runtime_data_run(struct engine_node *node) > static bool > runtime_data_sb_port_binding_handler(struct engine_node *node) > { > - struct ed_type_runtime_data *data = > - (struct ed_type_runtime_data *)node->data; > + struct ed_type_runtime_data *data = node->internal_data; > struct sset *local_lports = &data->local_lports; > struct sset *active_tunnels = &data->active_tunnels; > > @@ -1121,7 +1114,7 @@ struct ed_type_ct_zones { > static void > en_ct_zones_init(struct engine_node *node) > { > - struct ed_type_ct_zones *data = node->data; > + struct ed_type_ct_zones *data = node->internal_data; > struct ovsrec_open_vswitch_table *ovs_table = > (struct ovsrec_open_vswitch_table *)EN_OVSDB_GET( > engine_get_input("OVS_open_vswitch", node)); > @@ -1140,7 +1133,7 @@ en_ct_zones_init(struct engine_node *node) > static void > en_ct_zones_cleanup(struct engine_node *node) > { > - struct ed_type_ct_zones *data = node->data; > + struct ed_type_ct_zones *data = node->internal_data; > > simap_destroy(&data->current); > shash_destroy(&data->pending); > @@ -1149,10 +1142,9 @@ en_ct_zones_cleanup(struct engine_node *node) > static void > en_ct_zones_run(struct engine_node *node) > { > - struct ed_type_ct_zones *data = node->data; > + struct ed_type_ct_zones *data = node->internal_data; > struct ed_type_runtime_data *rt_data = > - (struct ed_type_runtime_data *)engine_get_input( > - "runtime_data", node)->data; > + engine_get_input("runtime_data", node)->internal_data; > > update_ct_zones(&rt_data->local_lports, &rt_data->local_datapaths, > &data->current, data->bitmap, &data->pending); > @@ -1160,6 +1152,13 @@ en_ct_zones_run(struct engine_node *node) > engine_set_node_state(node, EN_UPDATED); > } > > +/* The data in the ct_zones node is always valid (i.e., no stale pointers). */ > +static bool > +en_ct_zones_is_valid(struct engine_node *node OVS_UNUSED) > +{ > + return true; > +} > + > struct ed_type_mff_ovn_geneve { > enum mf_field_id mff_ovn_geneve; > }; > @@ -1167,8 +1166,7 @@ struct ed_type_mff_ovn_geneve { > static void > en_mff_ovn_geneve_init(struct engine_node *node) > { > - struct ed_type_mff_ovn_geneve *data = > - (struct ed_type_mff_ovn_geneve *)node->data; > + struct ed_type_mff_ovn_geneve *data = node->internal_data; > data->mff_ovn_geneve = 0; > } > > @@ -1180,8 +1178,7 @@ en_mff_ovn_geneve_cleanup(struct engine_node *node OVS_UNUSED) > static void > en_mff_ovn_geneve_run(struct engine_node *node) > { > - struct ed_type_mff_ovn_geneve *data = > - (struct ed_type_mff_ovn_geneve *)node->data; > + struct ed_type_mff_ovn_geneve *data = node->internal_data; > enum mf_field_id mff_ovn_geneve = ofctrl_get_mf_field_id(); > if (data->mff_ovn_geneve != mff_ovn_geneve) { > data->mff_ovn_geneve = mff_ovn_geneve; > @@ -1207,8 +1204,7 @@ struct ed_type_flow_output { > static void > en_flow_output_init(struct engine_node *node) > { > - struct ed_type_flow_output *data = > - (struct ed_type_flow_output *)node->data; > + struct ed_type_flow_output *data = node->internal_data; > ovn_desired_flow_table_init(&data->flow_table); > ovn_extend_table_init(&data->group_table); > ovn_extend_table_init(&data->meter_table); > @@ -1219,8 +1215,7 @@ en_flow_output_init(struct engine_node *node) > static void > en_flow_output_cleanup(struct engine_node *node) > { > - struct ed_type_flow_output *data = > - (struct ed_type_flow_output *)node->data; > + struct ed_type_flow_output *data = node->internal_data; > ovn_desired_flow_table_destroy(&data->flow_table); > ovn_extend_table_destroy(&data->group_table); > ovn_extend_table_destroy(&data->meter_table); > @@ -1231,21 +1226,18 @@ static void > en_flow_output_run(struct engine_node *node) > { > struct ed_type_runtime_data *rt_data = > - (struct ed_type_runtime_data *)engine_get_input( > - "runtime_data", node)->data; > + engine_get_input("runtime_data", node)->internal_data; > struct hmap *local_datapaths = &rt_data->local_datapaths; > struct sset *local_lports = &rt_data->local_lports; > struct sset *local_lport_ids = &rt_data->local_lport_ids; > struct sset *active_tunnels = &rt_data->active_tunnels; > > struct ed_type_ct_zones *ct_zones_data = > - (struct ed_type_ct_zones *)engine_get_input( > - "ct_zones", node)->data; > + engine_get_input("ct_zones", node)->internal_data; > struct simap *ct_zones = &ct_zones_data->current; > > struct ed_type_mff_ovn_geneve *ed_mff_ovn_geneve = > - (struct ed_type_mff_ovn_geneve *)engine_get_input( > - "mff_ovn_geneve", node)->data; > + engine_get_input("mff_ovn_geneve", node)->internal_data; > enum mf_field_id mff_ovn_geneve = ed_mff_ovn_geneve->mff_ovn_geneve; > > struct ovsrec_open_vswitch_table *ovs_table = > @@ -1262,12 +1254,11 @@ en_flow_output_run(struct engine_node *node) > engine_get_input("SB_chassis", node), > "name"); > struct ed_type_addr_sets *as_data = > - (struct ed_type_addr_sets *)engine_get_input("addr_sets", node)->data; > + engine_get_input("addr_sets", node)->internal_data; > struct shash *addr_sets = &as_data->addr_sets; > > struct ed_type_port_groups *pg_data = > - (struct ed_type_port_groups *)engine_get_input( > - "port_groups", node)->data; > + engine_get_input("port_groups", node)->internal_data; > struct shash *port_groups = &pg_data->port_groups; > > const struct sbrec_chassis *chassis = NULL; > @@ -1277,8 +1268,7 @@ en_flow_output_run(struct engine_node *node) > > ovs_assert(br_int && chassis); > > - struct ed_type_flow_output *fo = > - (struct ed_type_flow_output *)node->data; > + struct ed_type_flow_output *fo = node->internal_data; > struct ovn_desired_flow_table *flow_table = &fo->flow_table; > struct ovn_extend_table *group_table = &fo->group_table; > struct ovn_extend_table *meter_table = &fo->meter_table; > @@ -1361,18 +1351,16 @@ static bool > flow_output_sb_logical_flow_handler(struct engine_node *node) > { > struct ed_type_runtime_data *data = > - (struct ed_type_runtime_data *)engine_get_input( > - "runtime_data", node)->data; > + engine_get_input("runtime_data", node)->internal_data; > struct hmap *local_datapaths = &data->local_datapaths; > struct sset *local_lport_ids = &data->local_lport_ids; > struct sset *active_tunnels = &data->active_tunnels; > struct ed_type_addr_sets *as_data = > - (struct ed_type_addr_sets *)engine_get_input("addr_sets", node)->data; > + engine_get_input("addr_sets", node)->internal_data; > struct shash *addr_sets = &as_data->addr_sets; > > struct ed_type_port_groups *pg_data = > - (struct ed_type_port_groups *)engine_get_input( > - "port_groups", node)->data; > + engine_get_input("port_groups", node)->internal_data; > struct shash *port_groups = &pg_data->port_groups; > > struct ovsrec_open_vswitch_table *ovs_table = > @@ -1396,8 +1384,7 @@ flow_output_sb_logical_flow_handler(struct engine_node *node) > > ovs_assert(br_int && chassis); > > - struct ed_type_flow_output *fo = > - (struct ed_type_flow_output *)node->data; > + struct ed_type_flow_output *fo = node->internal_data; > struct ovn_desired_flow_table *flow_table = &fo->flow_table; > struct ovn_extend_table *group_table = &fo->group_table; > struct ovn_extend_table *meter_table = &fo->meter_table; > @@ -1452,8 +1439,7 @@ flow_output_sb_mac_binding_handler(struct engine_node *node) > (struct sbrec_mac_binding_table *)EN_OVSDB_GET( > engine_get_input("SB_mac_binding", node)); > > - struct ed_type_flow_output *fo = > - (struct ed_type_flow_output *)node->data; > + struct ed_type_flow_output *fo = node->internal_data; > struct ovn_desired_flow_table *flow_table = &fo->flow_table; > > lflow_handle_changed_neighbors(sbrec_port_binding_by_name, > @@ -1467,19 +1453,16 @@ static bool > flow_output_sb_port_binding_handler(struct engine_node *node) > { > struct ed_type_runtime_data *data = > - (struct ed_type_runtime_data *)engine_get_input( > - "runtime_data", node)->data; > + engine_get_input("runtime_data", node)->internal_data; > struct hmap *local_datapaths = &data->local_datapaths; > struct sset *active_tunnels = &data->active_tunnels; > > struct ed_type_ct_zones *ct_zones_data = > - (struct ed_type_ct_zones *)engine_get_input( > - "ct_zones", node)->data; > + engine_get_input("ct_zones", node)->internal_data; > struct simap *ct_zones = &ct_zones_data->current; > > struct ed_type_mff_ovn_geneve *ed_mff_ovn_geneve = > - (struct ed_type_mff_ovn_geneve *)engine_get_input( > - "mff_ovn_geneve", node)->data; > + engine_get_input("mff_ovn_geneve", node)->internal_data; > enum mf_field_id mff_ovn_geneve = ed_mff_ovn_geneve->mff_ovn_geneve; > > struct ovsrec_open_vswitch_table *ovs_table = > @@ -1501,8 +1484,7 @@ flow_output_sb_port_binding_handler(struct engine_node *node) > } > ovs_assert(br_int && chassis); > > - struct ed_type_flow_output *fo = > - (struct ed_type_flow_output *)node->data; > + struct ed_type_flow_output *fo = node->internal_data; > struct ovn_desired_flow_table *flow_table = &fo->flow_table; > > struct ovsdb_idl_index *sbrec_port_binding_by_name = > @@ -1575,18 +1557,15 @@ static bool > flow_output_sb_multicast_group_handler(struct engine_node *node) > { > struct ed_type_runtime_data *data = > - (struct ed_type_runtime_data *)engine_get_input( > - "runtime_data", node)->data; > + engine_get_input("runtime_data", node)->internal_data; > struct hmap *local_datapaths = &data->local_datapaths; > > struct ed_type_ct_zones *ct_zones_data = > - (struct ed_type_ct_zones *)engine_get_input( > - "ct_zones", node)->data; > + engine_get_input("ct_zones", node)->internal_data; > struct simap *ct_zones = &ct_zones_data->current; > > struct ed_type_mff_ovn_geneve *ed_mff_ovn_geneve = > - (struct ed_type_mff_ovn_geneve *)engine_get_input( > - "mff_ovn_geneve", node)->data; > + engine_get_input("mff_ovn_geneve", node)->internal_data; > enum mf_field_id mff_ovn_geneve = ed_mff_ovn_geneve->mff_ovn_geneve; > > struct ovsrec_open_vswitch_table *ovs_table = > @@ -1608,8 +1587,7 @@ flow_output_sb_multicast_group_handler(struct engine_node *node) > } > ovs_assert(br_int && chassis); > > - struct ed_type_flow_output *fo = > - (struct ed_type_flow_output *)node->data; > + struct ed_type_flow_output *fo = node->internal_data; > struct ovn_desired_flow_table *flow_table = &fo->flow_table; > > struct sbrec_multicast_group_table *multicast_group_table = > @@ -1630,19 +1608,17 @@ _flow_output_resource_ref_handler(struct engine_node *node, > enum ref_type ref_type) > { > struct ed_type_runtime_data *data = > - (struct ed_type_runtime_data *)engine_get_input( > - "runtime_data", node)->data; > + engine_get_input("runtime_data", node)->internal_data; > struct hmap *local_datapaths = &data->local_datapaths; > struct sset *local_lport_ids = &data->local_lport_ids; > struct sset *active_tunnels = &data->active_tunnels; > > struct ed_type_addr_sets *as_data = > - (struct ed_type_addr_sets *)engine_get_input("addr_sets", node)->data; > + engine_get_input("addr_sets", node)->internal_data; > struct shash *addr_sets = &as_data->addr_sets; > > struct ed_type_port_groups *pg_data = > - (struct ed_type_port_groups *)engine_get_input( > - "port_groups", node)->data; > + engine_get_input("port_groups", node)->internal_data; > struct shash *port_groups = &pg_data->port_groups; > > struct ovsrec_open_vswitch_table *ovs_table = > @@ -1666,7 +1642,7 @@ _flow_output_resource_ref_handler(struct engine_node *node, > ovs_assert(br_int && chassis); > > struct ed_type_flow_output *fo = > - (struct ed_type_flow_output *)node->data; > + node->internal_data; > struct ovn_desired_flow_table *flow_table = &fo->flow_table; > struct ovn_extend_table *group_table = &fo->group_table; > struct ovn_extend_table *meter_table = &fo->meter_table; > @@ -1899,7 +1875,7 @@ main(int argc, char *argv[]) > struct ed_type_addr_sets ed_addr_sets; > struct ed_type_port_groups ed_port_groups; > > - ENGINE_NODE(ct_zones, "ct_zones"); > + ENGINE_NODE_CUSTOM_DATA(ct_zones, "ct_zones"); > ENGINE_NODE(runtime_data, "runtime_data"); > ENGINE_NODE(mff_ovn_geneve, "mff_ovn_geneve"); > ENGINE_NODE(ofctrl_is_connected, "ofctrl_is_connected"); > @@ -2061,7 +2037,10 @@ main(int argc, char *argv[]) > } > > if (br_int) { > - ofctrl_run(br_int, &ed_ct_zones.pending); > + if (en_ct_zones.data) { > + struct ed_type_ct_zones *ct_zones = en_ct_zones.data; > + ofctrl_run(br_int, &ct_zones->pending); > + } > > if (chassis) { > patch_run(ovs_idl_txn, > @@ -2102,40 +2081,53 @@ main(int argc, char *argv[]) > stopwatch_stop(CONTROLLER_LOOP_STOPWATCH_NAME, > time_msec()); > if (ovs_idl_txn) { > - commit_ct_zones(br_int, &ed_ct_zones.pending); > + if (en_ct_zones.data) { > + struct ed_type_ct_zones *ct_zones = > + en_ct_zones.data; > + commit_ct_zones(br_int, &ct_zones->pending); > + } > bfd_run(ovsrec_interface_table_get(ovs_idl_loop.idl), > br_int, chassis, > sbrec_ha_chassis_group_table_get( > ovnsb_idl_loop.idl), > sbrec_sb_global_table_get(ovnsb_idl_loop.idl)); > } > - ofctrl_put(&ed_flow_output.flow_table, > - &ed_ct_zones.pending, > - sbrec_meter_table_get(ovnsb_idl_loop.idl), > - get_nb_cfg(sbrec_sb_global_table_get( > - ovnsb_idl_loop.idl)), > - engine_node_changed(&en_flow_output)); > - pinctrl_run(ovnsb_idl_txn, > - sbrec_datapath_binding_by_key, > - sbrec_port_binding_by_datapath, > - sbrec_port_binding_by_key, > - sbrec_port_binding_by_name, > - sbrec_mac_binding_by_lport_ip, > - sbrec_igmp_group, > - sbrec_ip_multicast, > - sbrec_dns_table_get(ovnsb_idl_loop.idl), > - sbrec_controller_event_table_get( > - ovnsb_idl_loop.idl), > - sbrec_service_monitor_table_get( > - ovnsb_idl_loop.idl), > - br_int, chassis, > - &ed_runtime_data.local_datapaths, > - &ed_runtime_data.active_tunnels); > - > - if (engine_node_changed(&en_runtime_data)) { > - update_sb_monitors(ovnsb_idl_loop.idl, chassis, > - &ed_runtime_data.local_lports, > - &ed_runtime_data.local_datapaths); > + if (en_flow_output.data && en_ct_zones.data) { > + struct ed_type_ct_zones *ct_zones = > + en_ct_zones.data; > + struct ed_type_flow_output *flow_output = > + en_flow_output.data; > + ofctrl_put(&flow_output->flow_table, > + &ct_zones->pending, > + sbrec_meter_table_get(ovnsb_idl_loop.idl), > + get_nb_cfg(sbrec_sb_global_table_get( > + ovnsb_idl_loop.idl)), > + engine_node_changed(&en_flow_output)); > + } > + if (en_runtime_data.data) { > + struct ed_type_runtime_data *rt_data = > + en_runtime_data.data; > + pinctrl_run(ovnsb_idl_txn, > + sbrec_datapath_binding_by_key, > + sbrec_port_binding_by_datapath, > + sbrec_port_binding_by_key, > + sbrec_port_binding_by_name, > + sbrec_mac_binding_by_lport_ip, > + sbrec_igmp_group, > + sbrec_ip_multicast, > + sbrec_dns_table_get(ovnsb_idl_loop.idl), > + sbrec_controller_event_table_get( > + ovnsb_idl_loop.idl), > + sbrec_service_monitor_table_get( > + ovnsb_idl_loop.idl), > + br_int, chassis, > + &rt_data->local_datapaths, > + &rt_data->active_tunnels); > + if (engine_node_changed(&en_runtime_data)) { > + update_sb_monitors(ovnsb_idl_loop.idl, chassis, > + &rt_data->local_lports, > + &rt_data->local_datapaths); > + } > } > } > > @@ -2170,9 +2162,14 @@ main(int argc, char *argv[]) > > > if (pending_pkt.conn) { > - if (br_int && chassis) { > + if (br_int && chassis && en_addr_sets.data && > + en_port_groups.data) { > + struct ed_type_addr_sets *as_data = > + en_addr_sets.data; > + struct ed_type_port_groups *pg_data = > + en_port_groups.data; > char *error = ofctrl_inject_pkt(br_int, pending_pkt.flow_s, > - &ed_addr_sets.addr_sets, &ed_port_groups.port_groups); > + &as_data->addr_sets, &pg_data->port_groups); > if (error) { > unixctl_command_reply_error(pending_pkt.conn, error); > free(error); > @@ -2210,12 +2207,15 @@ main(int argc, char *argv[]) > } > > if (ovsdb_idl_loop_commit_and_wait(&ovs_idl_loop) == 1) { > - struct shash_node *iter, *iter_next; > - SHASH_FOR_EACH_SAFE (iter, iter_next, &ed_ct_zones.pending) { > - struct ct_zone_pending_entry *ctzpe = iter->data; > - if (ctzpe->state == CT_ZONE_DB_SENT) { > - shash_delete(&ed_ct_zones.pending, iter); > - free(ctzpe); > + if (en_ct_zones.data) { > + struct ed_type_ct_zones *ct_zones = en_ct_zones.data; > + struct shash_node *iter, *iter_next; > + SHASH_FOR_EACH_SAFE (iter, iter_next, &ct_zones->pending) { > + struct ct_zone_pending_entry *ctzpe = iter->data; > + if (ctzpe->state == CT_ZONE_DB_SENT) { > + shash_delete(&ct_zones->pending, iter); > + free(ctzpe); > + } > } > } > } > diff --git a/lib/inc-proc-eng.c b/lib/inc-proc-eng.c > index 59b5cac..569c93d 100644 > --- a/lib/inc-proc-eng.c > +++ b/lib/inc-proc-eng.c > @@ -153,7 +153,7 @@ engine_add_input(struct engine_node *node, struct engine_node *input, > struct ovsdb_idl_index * > engine_ovsdb_node_get_index(struct engine_node *node, const char *name) > { > - struct ed_type_ovsdb_table *ed = (struct ed_type_ovsdb_table *)node->data; > + struct ed_type_ovsdb_table *ed = node->internal_data; > for (size_t i = 0; i < ed->n_indexes; i++) { > if (!strcmp(ed->indexes[i].name, name)) { > return ed->indexes[i].index; > @@ -167,7 +167,7 @@ void > engine_ovsdb_node_add_index(struct engine_node *node, const char *name, > struct ovsdb_idl_index *index) > { > - struct ed_type_ovsdb_table *ed = (struct ed_type_ovsdb_table *)node->data; > + struct ed_type_ovsdb_table *ed = node->internal_data; > ovs_assert(ed->n_indexes < ENGINE_MAX_OVSDB_INDEX); > > ed->indexes[ed->n_indexes].name = name; > @@ -192,6 +192,19 @@ engine_set_node_state_at(struct engine_node *node, > node->state = state; > } > > +static bool > +engine_node_valid(struct engine_node *node) > +{ > + if (node->state == EN_UPDATED || node->state == EN_VALID) { > + return true; > + } > + > + if (node->is_valid) { > + return node->is_valid(node); > + } > + return false; > +} > + > bool > engine_node_changed(struct engine_node *node) > { > @@ -215,12 +228,26 @@ engine_aborted(void) > return engine_run_aborted; > } > > +static void * > +engine_get_data(struct engine_node *node) > +{ > + if (engine_node_valid(node)) { > + return node->internal_data; > + } > + return NULL; > +} > + > void > engine_init_run(void) > { > VLOG_DBG("Initializing new run"); > for (size_t i = 0; i < engine_n_nodes; i++) { > engine_set_node_state(engine_nodes[i], EN_STALE); > + > + /* Make sure we reset the data pointer for outside users. > + * For nodes that always store valid data the value will be non-NULL. > + */ > + engine_nodes[i]->data = engine_get_data(engine_nodes[i]); > } > } > > @@ -333,6 +360,11 @@ engine_run(bool recompute_allowed) > engine_run_aborted = true; > return; > } > + > + /* Make sure we reset the data pointer for outside users as the > + * node's state might have changed. > + */ > + engine_nodes[i]->data = engine_get_data(engine_nodes[i]); > } > } > > diff --git a/lib/inc-proc-eng.h b/lib/inc-proc-eng.h > index bb8df07..e0d26ea 100644 > --- a/lib/inc-proc-eng.h > +++ b/lib/inc-proc-eng.h > @@ -111,6 +111,12 @@ struct engine_node { > * and run() function of the current node. Users should ensure that the > * data is read-only in change-handlers of the nodes that depends on this > * node. */ > + void *internal_data; > + > + /* A pointer to node data accessible for users outside the processing > + * engine. The value of the pointer is updated by the engine itself and > + * users should ensure that the data is only read. > + */ > void *data; > > /* State of the node after the last engine run. */ > @@ -125,6 +131,13 @@ struct engine_node { > /* Fully processes all inputs of this node and regenerates the data > * of this node */ > void (*run)(struct engine_node *); > + > + /* Method to validate if the 'internal_data' is valid. This allows users > + * to customize when 'internal_data' can be used (e.g., even if the node > + * hasn't been refreshed in the last iteration, if 'internal_data' > + * doesn't store pointers to DB records it's still safe to use). > + */ > + bool (*is_valid)(struct engine_node *); > }; > > /* Initialize the data for the engine nodes. It calls each node's > @@ -201,7 +214,7 @@ struct ed_type_ovsdb_table { > }; > > #define EN_OVSDB_GET(NODE) \ > - (((struct ed_type_ovsdb_table *)NODE->data)->table) > + (((struct ed_type_ovsdb_table *)NODE->internal_data)->table) > > struct ovsdb_idl_index * engine_ovsdb_node_get_index(struct engine_node *, > const char *name); > @@ -210,16 +223,25 @@ void engine_ovsdb_node_add_index(struct engine_node *, const char *name, > struct ovsdb_idl_index *); > > /* Macro to define an engine node. */ > -#define ENGINE_NODE(NAME, NAME_STR) \ > +#define ENGINE_NODE_DEF(NAME, NAME_STR) \ > struct engine_node en_##NAME = { \ > .name = NAME_STR, \ > - .data = &ed_##NAME, \ > + .internal_data = &ed_##NAME, \ > + .data = NULL, \ > .state = EN_STALE, \ > .init = en_##NAME##_init, \ > .run = en_##NAME##_run, \ > .cleanup = en_##NAME##_cleanup, \ > + .is_valid = en_##NAME##_is_valid, \ > }; > > +#define ENGINE_NODE_CUSTOM_DATA(NAME, NAME_STR) \ > + ENGINE_NODE_DEF(NAME, NAME_STR) > + > +#define ENGINE_NODE(NAME, NAME_STR) \ > + static bool (*en_##NAME##_is_valid)(struct engine_node *node) = NULL; \ > + ENGINE_NODE_DEF(NAME, NAME_STR) > + > /* Macro to define member functions of an engine node which represents > * a table of OVSDB */ > #define ENGINE_FUNC_OVSDB(DB_NAME, TBL_NAME) \ >
Thanks Dumitru. The approach looks valid. However, I think it could be improved a little, to avoid introducing the internal_data and make it easier to ensure there is no direct access to the node's data without validation. I think we can expose the engine_get_data() interface and force it to be used before accessing the data. The rules can be simply: always use this engine_get_data() to get engine node's data before accessing, except for accessing its own data in an engine node's handler (because it needs to be computed to become valid/updated). We can remove the ed_xxx variables such as: "struct ed_type_flow_output ed_flow_output;" so that we can avoid accessing data directly such as "&ed_flow_output.flow_table". Otherwise, it is hard to ensure the correctness if someone just update the code to bypass the if (...data) check. Code review would help, but it is still hard to guarantee. To remove the ed_xxx variable, we just need to move the data memory allocation in each node's init() function (and free it in cleanup()). I think I proposed this in an earlier version but I totally understand it is easy to get lost because of too much information exchanged. I really appreciate your effort for the fixes and improvements. I think I have no problem of merging this last patch with current version, but it could be even better. Please let me know if you are ok with the above suggestion, or I can merge it and let's address it with a separate patch. Thanks, Han _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev