diff --git a/northd/en-lflow.c b/northd/en-lflow.c index fa1f0236d9..32ddfb70ff 100644 --- a/northd/en-lflow.c +++ b/northd/en-lflow.c @@ -127,6 +127,10 @@ lflow_northd_handler(struct engine_node *node, return false; } + if (northd_has_lswitchs_in_tracked_data(&northd_data->trk_data)) { + return false; + } + const struct engine_context *eng_ctx = engine_get_context(); struct lflow_data *lflow_data = data; diff --git a/northd/en-ls-stateful.c b/northd/en-ls-stateful.c index 44f74ea08e..6c78f73390 100644 --- a/northd/en-ls-stateful.c +++ b/northd/en-ls-stateful.c @@ -138,6 +138,10 @@ ls_stateful_northd_handler(struct engine_node *node, void *data_) return false; } + if (northd_has_lswitchs_in_tracked_data(&northd_data->trk_data)) { + return false; + } + if (!northd_has_ls_lbs_in_tracked_data(&northd_data->trk_data) && !northd_has_ls_acls_in_tracked_data(&northd_data->trk_data)) { return true; diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c index 6e0aa04c46..4edc109ce9 100644 --- a/northd/inc-proc-northd.c +++ b/northd/inc-proc-northd.c @@ -193,10 +193,8 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, engine_add_input(&en_northd, &en_sb_chassis, NULL); engine_add_input(&en_northd, &en_sb_mirror, NULL); engine_add_input(&en_northd, &en_sb_meter, NULL); - engine_add_input(&en_northd, &en_sb_datapath_binding, NULL); engine_add_input(&en_northd, &en_sb_dns, NULL); engine_add_input(&en_northd, &en_sb_ha_chassis_group, NULL); - engine_add_input(&en_northd, &en_sb_ip_multicast, NULL); engine_add_input(&en_northd, &en_sb_service_monitor, NULL); engine_add_input(&en_northd, &en_sb_static_mac_binding, NULL); engine_add_input(&en_northd, &en_sb_chassis_template_var, NULL); @@ -223,6 +221,11 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, northd_nb_logical_router_handler); engine_add_input(&en_northd, &en_lb_data, northd_lb_data_handler); + /* No need for an explicit handler for the SB datapath and + * SB IP Multicast changes.*/ + engine_add_input(&en_northd, &en_sb_datapath_binding, engine_noop_handler); + engine_add_input(&en_northd, &en_sb_ip_multicast, engine_noop_handler); + engine_add_input(&en_lr_nat, &en_northd, lr_nat_northd_handler); engine_add_input(&en_lr_stateful, &en_northd, lr_stateful_northd_handler); diff --git a/northd/northd.c b/northd/northd.c index fc14e8ef3c..1abdce4756 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -989,6 +989,19 @@ ovn_datapath_assign_requested_tnl_id( } } +static bool +ovn_datapath_assign_or_allocate_tnl_id(struct hmap *dp_tnlids, + struct ovn_datapath *od, uint32_t *hint) +{ + ovn_datapath_assign_requested_tnl_id(dp_tnlids, od); + if (!od->tunnel_key) { + od->tunnel_key = ovn_allocate_tnlid(dp_tnlids, "datapath", + OVN_MIN_DP_KEY_LOCAL, get_ovn_max_dp_key_local(vxlan_mode), hint); + } + + return od->tunnel_key != 0; +} + static void ods_build_array_index(struct ovn_datapaths *datapaths) { @@ -997,8 +1010,11 @@ ods_build_array_index(struct ovn_datapaths *datapaths) * doesn't matter if they are different on every iteration. */ size_t index = 0; - datapaths->array = xrealloc(datapaths->array, - ods_size(datapaths) * sizeof *datapaths->array); + datapaths->n_array = ods_size(datapaths); + datapaths->n_allocated_array = datapaths->n_array + 10; + datapaths->array = xrealloc( + datapaths->array, + datapaths->n_allocated_array * sizeof *datapaths->array); struct ovn_datapath *od; HMAP_FOR_EACH (od, key_node, &datapaths->datapaths) { @@ -1008,6 +1024,22 @@ ods_build_array_index(struct ovn_datapaths *datapaths) } } +static void +ods_assign_array_index(struct ovn_datapaths *datapaths, struct ovn_datapath *od) +{ + ovs_assert(ods_size(datapaths) == (datapaths->n_array + 1)); + od->index = datapaths->n_array; + + if (datapaths->n_array == datapaths->n_allocated_array) { + datapaths->n_allocated_array += 10; + datapaths->array = xrealloc( + datapaths->array, + datapaths->n_allocated_array * sizeof *datapaths->array); + } + datapaths->array[datapaths->n_array++] = od; + od->datapaths = datapaths; +} + /* Updates the southbound Datapath_Binding table so that it contains the * logical switches and routers specified by the northbound database. * @@ -4299,6 +4331,12 @@ build_ports(struct ovsdb_idl_txn *ovnsb_txn, sset_destroy(&active_ha_chassis_grps); } +static void +destroy_tracked_dps(struct tracked_dps *trk_dps) +{ + hmapx_clear(&trk_dps->crupdated); +} + static void destroy_tracked_ovn_ports(struct tracked_ovn_ports *trk_ovn_ports) { @@ -4335,6 +4373,7 @@ void destroy_northd_data_tracked_changes(struct northd_data *nd) { struct northd_tracked_data *trk_changes = &nd->trk_data; + destroy_tracked_dps(&trk_changes->trk_switches); destroy_tracked_ovn_ports(&trk_changes->trk_lsps); destroy_tracked_lbs(&trk_changes->trk_lbs); hmapx_clear(&trk_changes->trk_nat_lrs); @@ -4348,6 +4387,7 @@ init_northd_tracked_data(struct northd_data *nd) { struct northd_tracked_data *trk_data = &nd->trk_data; trk_data->type = NORTHD_TRACKED_NONE; + hmapx_init(&trk_data->trk_switches.crupdated); hmapx_init(&trk_data->trk_lsps.created); hmapx_init(&trk_data->trk_lsps.updated); hmapx_init(&trk_data->trk_lsps.deleted); @@ -4363,6 +4403,7 @@ destroy_northd_tracked_data(struct northd_data *nd) { struct northd_tracked_data *trk_data = &nd->trk_data; trk_data->type = NORTHD_TRACKED_NONE; + hmapx_destroy(&trk_data->trk_switches.crupdated); hmapx_destroy(&trk_data->trk_lsps.created); hmapx_destroy(&trk_data->trk_lsps.updated); hmapx_destroy(&trk_data->trk_lsps.deleted); @@ -4780,12 +4821,60 @@ northd_handle_ls_changes(struct ovsdb_idl_txn *ovnsb_idl_txn, const struct nbrec_logical_switch *changed_ls; struct northd_tracked_data *trk_data = &nd->trk_data; + nd->trk_data.type = NORTHD_TRACKED_NONE; + + /* Loop to handle deleted logical switches. */ NBREC_LOGICAL_SWITCH_TABLE_FOR_EACH_TRACKED (changed_ls, ni->nbrec_logical_switch_table) { - if (nbrec_logical_switch_is_new(changed_ls) || - nbrec_logical_switch_is_deleted(changed_ls)) { + if (nbrec_logical_switch_is_deleted(changed_ls)) { + return false; + } + } + + + uint32_t hint = 0; + /* Loop to handle newly created logical switches. */ + NBREC_LOGICAL_SWITCH_TABLE_FOR_EACH_TRACKED ( + changed_ls, ni->nbrec_logical_switch_table) { + if (!nbrec_logical_switch_is_new(changed_ls)) { + continue; + } + + struct ovn_datapath *od = ovn_datapath_create( + &nd->ls_datapaths.datapaths, &changed_ls->header_.uuid, changed_ls, + NULL, NULL); + + ods_assign_array_index(&nd->ls_datapaths, od); + + /* Assign tunnel id if requested or allocate a new one. */ + if (!ovn_datapath_assign_or_allocate_tnl_id(&nd->dp_tnlids, + od, &hint)) { + ovn_datapath_destroy(&nd->ls_datapaths.datapaths, od); goto fail; } + + init_ipam_info_for_datapath(od); + init_mcast_info_for_datapath(od); + + od->sb = sbrec_datapath_binding_insert(ovnsb_idl_txn); + ovn_datapath_update_external_ids(od); + sbrec_datapath_binding_set_tunnel_key(od->sb, od->tunnel_key); + + /* Create SB:IP_Multicast for the logical switch. */ + const struct sbrec_ip_multicast *ip_mcast = + sbrec_ip_multicast_insert(ovnsb_idl_txn); + store_mcast_info_for_switch_datapath(ip_mcast, od); + + hmapx_add(&trk_data->trk_switches.crupdated, od); + } + + /* Loop to handle updated logical switches. */ + NBREC_LOGICAL_SWITCH_TABLE_FOR_EACH_TRACKED (changed_ls, + ni->nbrec_logical_switch_table) { + if (nbrec_logical_switch_is_new(changed_ls)) { + continue; + } + struct ovn_datapath *od = ovn_datapath_find_( &nd->ls_datapaths.datapaths, &changed_ls->header_.uuid); @@ -4812,6 +4901,10 @@ northd_handle_ls_changes(struct ovsdb_idl_txn *ovnsb_idl_txn, } } + if (!hmapx_is_empty(&trk_data->trk_switches.crupdated)) { + trk_data->type |= NORTHD_TRACKED_SWITCHES; + } + if (!hmapx_is_empty(&trk_data->trk_lsps.created) || !hmapx_is_empty(&trk_data->trk_lsps.updated) || !hmapx_is_empty(&trk_data->trk_lsps.deleted)) { diff --git a/northd/northd.h b/northd/northd.h index 198b9f2270..d7b5814dcd 100644 --- a/northd/northd.h +++ b/northd/northd.h @@ -79,6 +79,8 @@ struct ovn_datapaths { /* The array index of each element in 'datapaths'. */ struct ovn_datapath **array; + size_t n_array; + size_t n_allocated_array; }; static inline size_t @@ -99,6 +101,11 @@ enum redirected_routing_protcol_flag_type { REDIRECT_BFD = (1 << 1), }; +struct tracked_dps { + /* Tracked created or updated datapaths. */ + struct hmapx crupdated; +}; + struct tracked_ovn_ports { /* tracked created ports. * hmapx node data is 'struct ovn_port *' */ @@ -130,6 +137,7 @@ enum northd_tracked_data_type { NORTHD_TRACKED_LR_NATS = (1 << 2), NORTHD_TRACKED_LS_LBS = (1 << 3), NORTHD_TRACKED_LS_ACLS = (1 << 4), + NORTHD_TRACKED_SWITCHES = (1 << 5), }; /* Track what's changed in the northd engine node. @@ -138,6 +146,7 @@ enum northd_tracked_data_type { struct northd_tracked_data { /* Indicates the type of data tracked. One or all of NORTHD_TRACKED_*. */ enum northd_tracked_data_type type; + struct tracked_dps trk_switches; struct tracked_ovn_ports trk_lsps; struct tracked_lbs trk_lbs; @@ -840,6 +849,12 @@ northd_has_ls_acls_in_tracked_data(struct northd_tracked_data *trk_nd_changes) return trk_nd_changes->type & NORTHD_TRACKED_LS_ACLS; } +static inline bool +northd_has_lswitchs_in_tracked_data(struct northd_tracked_data *trk_nd_changes) +{ + return trk_nd_changes->type & NORTHD_TRACKED_SWITCHES; +} + /* Returns 'true' if the IPv4 'addr' is on the same subnet with one of the * IPs configured on the router port. */ diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at index 4eae1c67c1..ed37b7f30e 100644 --- a/tests/ovn-northd.at +++ b/tests/ovn-northd.at @@ -14253,3 +14253,72 @@ AT_CHECK([grep "lr_in_dnat" lr1flows | ovn_strip_lflows | grep "30.0.0.1"], [0], AT_CLEANUP ]) + + +OVN_FOR_EACH_NORTHD_NO_HV([ +AT_SETUP([Logical switch incremental processing]) + +ovn_start + +net_add n1 +sim_add hv1 +as hv1 +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.11 + +ovn-sbctl chassis-add gw1 geneve 127.0.0.1 +check ovn-nbctl --wait=sb sync + +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats +check ovn-nbctl --wait=sb ls-add sw0 +check_engine_stats northd norecompute compute +check_engine_stats ls_stateful recompute nocompute +check_engine_stats lflow recompute nocompute + +# For the below engine nodes, en_northd is input. So check +# their engine status. +check_engine_stats lr_stateful norecompute compute +check_engine_stats route_policies norecompute compute +check_engine_stats static_routes norecompute compute +check_engine_stats bfd_sync norecompute compute +check_engine_stats sync_to_sb_lb norecompute compute +check_engine_stats sync_to_sb_pb norecompute compute + +CHECK_NO_CHANGE_AFTER_RECOMPUTE((1)) + +# Update the logical switch. +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats +check ovn-nbctl --wait=sb set logical_switch sw0 other_config:foo=bar + +check_engine_stats northd recompute nocompute +check_engine_stats ls_stateful recompute nocompute +check_engine_stats lflow recompute nocompute + +# For the below engine nodes, en_northd is input. So check +# their engine status. +check_engine_stats lr_stateful norecompute nocompute +check_engine_stats route_policies norecompute nocompute +check_engine_stats static_routes norecompute nocompute +check_engine_stats bfd_sync norecompute nocompute +check_engine_stats sync_to_sb_lb norecompute nocompute +check_engine_stats sync_to_sb_pb norecompute nocompute + +# Delete the logical switch +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats +check ovn-nbctl --wait=sb ls-del sw0 +check_engine_stats northd recompute nocompute +check_engine_stats ls_stateful recompute nocompute +check_engine_stats lflow recompute nocompute + +# For the below engine nodes, en_northd is input. So check +# their engine status. +check_engine_stats lr_stateful recompute nocompute +check_engine_stats route_policies recompute nocompute +check_engine_stats static_routes recompute nocompute +check_engine_stats bfd_sync recompute nocompute +check_engine_stats sync_to_sb_lb recompute nocompute +check_engine_stats sync_to_sb_pb recompute nocompute + +OVN_CLEANUP([hv1]) +AT_CLEANUP +])