On Thu, Jun 29, 2023 at 10:10 PM Numan Siddique <[email protected]> wrote: > > On Fri, Jun 30, 2023 at 7:00 AM Han Zhou <[email protected]> wrote: > > > > On Thu, Jun 29, 2023 at 9:19 AM Dumitru Ceara <[email protected]> wrote: > > > > > > On 6/27/23 10:23, Numan Siddique wrote: > > > > On Mon, Jun 26, 2023 at 10:34 PM Han Zhou <[email protected]> wrote: > > > >> > > > >> On Mon, Jun 26, 2023 at 7:25 AM Numan Siddique <[email protected]> wrote: > > > >>> > > > >>> On Sun, Jun 18, 2023 at 11:48 AM Han Zhou <[email protected]> wrote: > > > >>>> > > > >>>> For incremental processing, it is important to maintain relationship > > > >>>> between the inputs and the logical flows generated. This patch > > creates > > > >>>> the links between ovn_port and logical flows. The same data structure > > > >>>> may be expanded to maintain links between logical flows and other > > types > > > >>>> of inputs. > > > >>>> > > > >>>> This patch also refactors the temp_lflow_list operations to > > > >>>> collected_lflows with helper functions to start and end collecting. > > It > > > >>>> still uses global variables just to avoid updating all the > > lflow_add_... > > > >>>> related code all over the northd.c file. > > > >>>> > > > >>>> Signed-off-by: Han Zhou <[email protected]> > > > >>> > > > >>> Hi Han, > > > >>> > > > >>> Please see a few comments below. I did review all the 3 patches in > > the > > > >> series. > > > >>> They LGTM overall. I'd like to do some more testing before providing > > my > > > >> Acks. > > > >>> > > > >> > > > >> Thanks for your review! > > > >> > > > >>> > > > >>>> --- > > > >>>> northd/northd.c | 271 > > +++++++++++++++++++++++++++++++----------------- > > > >>>> 1 file changed, 178 insertions(+), 93 deletions(-) > > > >>>> > > > >>>> diff --git a/northd/northd.c b/northd/northd.c > > > >>>> index 98f528f93cfc..aa0f853ce2db 100644 > > > >>>> --- a/northd/northd.c > > > >>>> +++ b/northd/northd.c > > > >>>> @@ -1457,6 +1457,19 @@ struct ovn_port_routable_addresses { > > > >>>> size_t n_addrs; > > > >>>> }; > > > >>>> > > > >>>> +/* A node that maintains link between an object (such as an > > ovn_port) > > > >> and > > > >>>> + * a lflow. */ > > > >>>> +struct lflow_ref_node { > > > >>>> + /* This list follows different lflows referenced by the same > > > >> object. List > > > >>>> + * head is, for example, ovn_port->lflows. */ > > > >>>> + struct ovs_list lflow_list_node; > > > >>>> + /* This list follows different objects that reference the same > > > >> lflow. List > > > >>>> + * head is ovn_lflow->referenced_by. */ > > > >>>> + struct ovs_list ref_list_node; > > > >>>> + /* The lflow. */ > > > >>>> + struct ovn_lflow *lflow; > > > >>>> +}; > > > >>>> + > > > >>>> /* A logical switch port or logical router port. > > > >>>> * > > > >>>> * In steady state, an ovn_port points to a northbound > > > >> Logical_Switch_Port > > > >>>> @@ -1548,6 +1561,28 @@ struct ovn_port { > > > >>>> > > > >>>> /* Temporarily used for traversing a list (or hmap) of ports. */ > > > >>>> bool visited; > > > >>>> + > > > >>>> + /* List of struct lflow_ref_node that points to the lflows > > > >> generated by > > > >>>> + * this ovn_port. > > > >>>> + * > > > >>>> + * This data is initialized and destroyed by the en_northd node, > > > >> but > > > >>>> + * populated and used only by the en_lflow node. Ideally this > > data > > > >> should > > > >>>> + * be maintained as part of en_lflow's data (struct > > lflow_data): a > > > >> hash > > > >>>> + * index from ovn_port key to lflows. However, it would be less > > > >> efficient > > > >>>> + * and more complex: > > > >>>> + * > > > >>>> + * 1. It would require an extra search (using the index) to find > > > >> the > > > >>>> + * lflows. > > > >>>> + * > > > >>>> + * 2. Building the index needs to be thread-safe, using either a > > > >> global > > > >>>> + * lock which is obviously less efficient, or hash-based lock > > > >> array which > > > >>>> + * is more complex. > > > >>>> + * > > > >>>> + * Adding the list here is more straightforward. The drawback is > > > >> that we > > > >>>> + * need to keep in mind that this data belongs to en_lflow node, > > > >> so never > > > >>>> + * access it from any other nodes. > > > >>>> + */ > > > >>>> + struct ovs_list lflows; > > > >>>> }; > > > >>> > > > >>> > > > >>>> > > > >>>> static bool lsp_can_be_inc_processed(const struct > > > >> nbrec_logical_switch_port *); > > > >>>> @@ -1635,6 +1670,8 @@ ovn_port_create(struct hmap *ports, const char > > > >> *key, > > > >>>> ovn_port_set_nb(op, nbsp, nbrp); > > > >>>> op->l3dgw_port = op->cr_port = NULL; > > > >>>> hmap_insert(ports, &op->key_node, hash_string(op->key, 0)); > > > >>>> + > > > >>>> + ovs_list_init(&op->lflows); > > > >>>> return op; > > > >>>> } > > > >>>> > > > >>>> @@ -1665,6 +1702,13 @@ ovn_port_destroy_orphan(struct ovn_port *port) > > > >>>> destroy_lport_addresses(&port->proxy_arp_addrs); > > > >>>> free(port->json_key); > > > >>>> free(port->key); > > > >>>> + > > > >>>> + struct lflow_ref_node *l; > > > >>>> + LIST_FOR_EACH_SAFE (l, lflow_list_node, &port->lflows) { > > > >>>> + ovs_list_remove(&l->lflow_list_node); > > > >>>> + ovs_list_remove(&l->ref_list_node); > > > >>>> + free(l); > > > >>>> + } > > > >>>> free(port); > > > >>>> } > > > >>>> > > > >>>> @@ -4893,6 +4937,7 @@ static struct ovn_port * > > > >>>> ls_port_create(struct ovsdb_idl_txn *ovnsb_txn, struct hmap > > *ls_ports, > > > >>>> const char *key, const struct > > nbrec_logical_switch_port > > > >> *nbsp, > > > >>>> struct ovn_datapath *od, const struct > > > >> sbrec_port_binding *sb, > > > >>>> + struct ovs_list *lflows, > > > >>>> const struct sbrec_mirror_table *sbrec_mirror_table, > > > >>>> const struct sbrec_chassis_table > > *sbrec_chassis_table, > > > >>>> struct ovsdb_idl_index *sbrec_chassis_by_name, > > > >>>> @@ -4903,6 +4948,9 @@ ls_port_create(struct ovsdb_idl_txn *ovnsb_txn, > > > >> struct hmap *ls_ports, > > > >>>> parse_lsp_addrs(op); > > > >>>> op->od = od; > > > >>>> hmap_insert(&od->ports, &op->dp_node, > > > >> hmap_node_hash(&op->key_node)); > > > >>>> + if (lflows) { > > > >>>> + ovs_list_splice(&op->lflows, lflows->next, lflows); > > > >>>> + } > > > >>>> > > > >>>> /* Assign explicitly requested tunnel ids first. */ > > > >>>> if (!ovn_port_assign_requested_tnl_id(sbrec_chassis_table, op)) > > { > > > >>>> @@ -5082,7 +5130,7 @@ northd_handle_ls_changes(struct ovsdb_idl_txn > > > >> *ovnsb_idl_txn, > > > >>>> goto fail; > > > >>>> } > > > >>>> op = ls_port_create(ovnsb_idl_txn, &nd->ls_ports, > > > >>>> - new_nbsp->name, new_nbsp, od, > > NULL, > > > >>>> + new_nbsp->name, new_nbsp, od, > > > >> NULL, NULL, > > > >>>> ni->sbrec_mirror_table, > > > >>>> ni->sbrec_chassis_table, > > > >>>> ni->sbrec_chassis_by_name, > > > >>>> @@ -5114,13 +5162,16 @@ northd_handle_ls_changes(struct ovsdb_idl_txn > > > >> *ovnsb_idl_txn, > > > >>>> op->visited = true; > > > >>>> continue; > > > >>>> } > > > >>>> + struct ovs_list lflows = > > OVS_LIST_INITIALIZER(&lflows); > > > >>>> + ovs_list_splice(&lflows, op->lflows.next, > > &op->lflows); > > > >>>> ovn_port_destroy(&nd->ls_ports, op); > > > >>>> op = ls_port_create(ovnsb_idl_txn, &nd->ls_ports, > > > >>>> - new_nbsp->name, new_nbsp, od, > > sb, > > > >>>> + new_nbsp->name, new_nbsp, od, > > sb, > > > >> &lflows, > > > >>>> ni->sbrec_mirror_table, > > > >>>> ni->sbrec_chassis_table, > > > >>>> ni->sbrec_chassis_by_name, > > > >>>> ni->sbrec_chassis_by_hostname); > > > >>>> + ovs_assert(ovs_list_is_empty(&lflows)); > > > >>>> if (!op) { > > > >>>> goto fail; > > > >>>> } > > > >>>> @@ -5577,7 +5628,8 @@ ovn_igmp_group_destroy(struct hmap > > *igmp_groups, > > > >>>> > > > >>>> struct ovn_lflow { > > > >>>> struct hmap_node hmap_node; > > > >>>> - struct ovs_list list_node; > > > >>>> + struct ovs_list list_node; /* For temporary list of lflows. > > > >> Don't remove > > > >>>> + at destroy. */ > > > >>>> > > > >>>> struct ovn_datapath *od; /* 'logical_datapath' in SB schema. > > > >> */ > > > >>>> unsigned long *dpg_bitmap; /* Bitmap of all datapaths by their > > > >> 'index'.*/ > > > >>>> @@ -5591,6 +5643,8 @@ struct ovn_lflow { > > > >>>> size_t n_ods; /* Number of datapaths referenced > > by > > > >> 'od' and > > > >>>> * 'dpg_bitmap'. */ > > > >>>> struct ovn_dp_group *dpg; /* Link to unique Sb datapath > > group. > > > >> */ > > > >>>> + > > > >>>> + struct ovs_list referenced_by; /* List of struct > > lflow_ref_node. > > > >> */ > > > >>>> const char *where; > > > >>>> > > > >>>> struct uuid sb_uuid; /* SB DB row uuid, specified by > > > >> northd. */ > > > >>>> @@ -5640,6 +5694,7 @@ ovn_lflow_init(struct ovn_lflow *lflow, struct > > > >> ovn_datapath *od, > > > >>>> char *stage_hint, const char *where) > > > >>>> { > > > >>>> ovs_list_init(&lflow->list_node); > > > >>>> + ovs_list_init(&lflow->referenced_by); > > > >>>> lflow->dpg_bitmap = bitmap_allocate(dp_bitmap_len); > > > >>>> lflow->od = od; > > > >>>> lflow->stage = stage; > > > >>>> @@ -5767,20 +5822,30 @@ ovn_dp_group_add_with_reference(struct > > > >> ovn_lflow *lflow_ref, > > > >>>> } > > > >>>> } > > > >>>> > > > >>>> +/* This global variable collects the lflows generated by > > > >> do_ovn_lflow_add(). > > > >>>> + * start_collecting_lflows() will enable the lflow collection and > > the > > > >> calls to > > > >>>> + * do_ovn_lflow_add (or the macros ovn_lflow_add_...) will add > > > >> generated lflows > > > >>>> + * to the list. end_collecting_lflows() will disable it. */ > > > >>>> +static thread_local struct ovs_list collected_lflows; > > > >>>> +static thread_local bool collecting_lflows = false; > > > >>>> + > > > >>>> +static void > > > >>>> +start_collecting_lflows(void) > > > >>>> +{ > > > >>>> + ovs_assert(!collecting_lflows); > > > >>>> + ovs_list_init(&collected_lflows); > > > >>>> + collecting_lflows = true; > > > >>>> +} > > > >>>> + > > > >>>> +static void > > > >>>> +end_collecting_lflows(void) > > > >>>> +{ > > > >>>> + ovs_assert(collecting_lflows); > > > >>>> + collecting_lflows = false; > > > >>>> +} > > > >>>> + > > > >>> > > > >>> I think we can avoid these functions and the thread local variable > > > >>> "collected_lflows". > > > >>> > > > >>> I'd suggest the below > > > >>> > > > >>> ---------------------------- > > > >>> > > > >>> static void > > > >>> do_ovn_lflow_add(struct hmap *lflow_map, const struct ovn_datapath > > *od, > > > >>> const unsigned long *dp_bitmap, size_t dp_bitmap_len, > > > >>> uint32_t hash, enum ovn_stage stage, uint16_t > > priority, > > > >>> const char *match, const char *actions, const char > > > >> *io_port, > > > >>> struct ovs_list *lflow_ref_list, > > > >>> const struct ovsdb_idl_row *stage_hint, > > > >>> const char *where, const char *ctrl_meter) > > > >>> OVS_REQUIRES(fake_hash_mutex) > > > >>> { > > > >>> ... > > > >>> ... > > > >>> /* At the end. */ > > > >>> if (lflow_ref_list) { > > > >>> struct lflow_ref_node *lfrn = xmalloc(sizeof *lfrn); > > > >>> lfrn->lflow = lflow; > > > >>> ovs_list_insert(lflow_ref_list, &lfrn->lflow_list_node); > > > >>> ovs_list_insert(&lflow->referenced_by, &lfrn->ref_list_node); > > > >>> } > > > >>> } > > > >>> > > > >>> > > > >>> #define ovn_lflow_add_with_lport_and_hint(LFLOW_MAP, OD, STAGE, > > PRIORITY, > > > >> \ > > > >>> MATCH, ACTIONS, > > IN_OUT_PORT, \ > > > >>> LFLOW_REF_LIST, STAGE_HINT) > > \ > > > >>> ovn_lflow_add_at(LFLOW_MAP, OD, NULL, 0, STAGE, PRIORITY, MATCH, > > > >> ACTIONS, \ > > > >>> IN_OUT_PORT, LFLOW_REF_LIST, NULL, STAGE_HINT, \ > > > >>> OVS_SOURCE_LOCATOR) > > > >>> > > > >>> And pass &op->lflows in ovn_lflow_add_with_lport_and_hint() > > > >>> > > > >>> ----------------------------- > > > >>> > > > >>> What do you think ? Definitely this would result in a bit more work > > > >>> as it would require a lot of (tedious) changes. > > > >>> I think this is a better approach. > > > >>> > > > >> Firstly, I think it is not good to use "lflow_ref_list" directly in the > > > >> parameter, because there can be more than one object contributing to > > the > > > >> lflow generation. When we implement I-P for more inputs, a single > > lflow may > > > >> be referenced by multiple objects. We can't pass multiple > > lflow_ref_list to > > > >> the function either, because the number of such lists is unknown. For > > > >> example, a lflow may be generated as a result of a LSP, a DP and a LB > > > >> backend. If we want to implement I-P for LSP, DP and LB backend, we > > need to > > > >> track the reference for all of them. So the current idea is just to > > collect > > > >> a list of lflows generated by a higher level function, such as the > > > >> build_lswitch_and_lrouter_iterate_by_lsp. When implementing I-P for > > more > > > >> than one object of the same lflow, this needs to be more fine-grained. > > > > > > I'm still reviewing this patch but my first impression was that we can > > > probably try to use 'struct objdep_mgr' (defined in lib/objdep.h) to > > > model all these (potentially many-to-many) relationships. We do similar > > > things in ovn-controller. > > > > > My first impression was similar, but later I figured out it is different > > (and more complex than ovn-controller in general) and we will need to make > > changes to objdep_mgr. However, until more input I-P is implemented I am > > not sure if I will be able to get a general enough abstraction in > > objdep_mgr that can handle all the use cases. On the other hand, the > > references between LSP and related lflows are quite simple, so I went ahead > > and implemented the lists (embeded into ovn_port and lflow without extra > > hash tables), with minimum effort, to make it work at least for this > > scenario and should also work for similar scenarios. I think we can > > refactor the reference implementation any time but it may be better to get > > more I-P implemented, during the process we can always revisit and see if > > objdep_mgr can be extended or another common dependency/reference library > > for ovn-northd can be created, etc. What do you think? > > As part of my refactor and northd I-P for load balancers and data > paths, I'll try to see > if objdep_mgr can be used. For now with just lport I-P, I suppose it's fine. > > Acked-by: Numan Siddique <[email protected]> > Haven't heard back from Dumitru for a while, so I assume you are fine with this (but please share any time if you have more comments). Thank you both, Numan and Dumitru. I applied this to main.
Han > Numan > > > > > Regards, > > Han > > > > > > > > > > Agree. I'm working on the I-P for datapath changes in lflow engine and > > > > as a flow can be referenced by multiple datapaths, I agree this needs > > to > > > > be tracked properly. And definitely that is out of scope of this patch > > series. > > > > > > > > > > > >> > > > >> Secondly, I agree with you adding a new parameter to the > > do_ovn_lflow_add > > > >> is cleaner. For the collected list I mentioned, it can be a parameter > > > >> instead of a thread local variable. However, as you mentioned, the > > change > > > >> is going to be all over the northd.c code, not only for the > > > >> ovn_lflow_add_xxx, but also the functions calling the ovn_lflow_add_xxx > > > >> macros, and upper layer functions calling those functions, and so on. > > > >> Unfortunately C doesn't support optional args. At this moment I am not > > sure > > > >> if the interface is stable enough for the incremental-processing, so I > > am > > > >> not sure if it is worth such a big change. If we need to modify them > > again > > > >> later, all such changes are going to be wasted. On the other hand, > > although > > > >> the thread local variable is not the best way, I think it is still > > clear > > > >> and manageable, if we call the start_collecting_lflows and > > > >> end_collecting_lflows in pairs. So, is it ok to leave it for this > > patch and > > > >> in the future when this mechanism proves to work well for more I-P, we > > can > > > >> have a separate patch to refactor (which will include all the tedious > > > >> function call changes). What do you think? > > > > > > > > I agree. It is definitely tedious to do all the changes. I'm ok with > > > > the approach taken > > > > in this patch series. > > > > > > > > Also request to please take a look at the load balancer I-P patch > > > > series - > > http://patchwork.ozlabs.org/project/ovn/list/?series=361083&state=* > > > > > > > > Thanks > > > > Numan > > > > > > > >> > > > >> Thanks, > > > >> Han > > > >> > > > >>> Also I'm planning to work on top of your patches to add I-P for load > > > >>> balancers in lflow engine (or perhaps I-P for datapath changes) > > > >>> > > > >>> My idea is to have a lflow ref list stored in "struct ovn_datapath" > > > >>> similar to the way you have done in this patch in "struct ovn_port" > > > >>> > > > >>> And while adding the flows using one of the macro variants > > > >>> 'ovn_lflow_add*' pass &od->lflows. > > > >>> > > > >>> Please let me know your comments. > > > >>> > > > >>> Only concern I have with this patch is the "op->lflows" modified by > > > >>> the lflow engine node. > > > >>> But I agree with your added comments and also thinking to use the same > > > >>> approach for datapath I-P handling, > > > >>> And I don't have a better approach at the moment. So I'm fine with it. > > > >>> > > > >>> Thanks > > > >>> Numan > > > >>> > > > >>> > > > >>>> /* Adds a row with the specified contents to the Logical_Flow table. > > > >>>> - * Version to use when hash bucket locking is NOT required. > > > >>>> - * > > > >>>> - * Note: This function can add generated lflows to the global > > variable > > > >>>> - * temp_lflow_list as its output, controlled by the global variable > > > >>>> - * add_lflow_to_temp_list. The caller of the ovn_lflow_add_... > > marcros > > > >> can get > > > >>>> - * a list of lflows generated by setting add_lflow_to_temp_list to > > > >> true. The > > > >>>> - * caller is responsible for initializing the temp_lflow_list, and > > also > > > >>>> - * reset the add_lflow_to_temp_list to false when it is no longer > > > >> needed. > > > >>>> - * XXX: this mechanism is temporary and will be replaced when we add > > > >> hash index > > > >>>> - * to lflow_data and refactor related functions. > > > >>>> - */ > > > >>>> -static bool add_lflow_to_temp_list = false; > > > >>>> -static struct ovs_list temp_lflow_list; > > > >>>> + * Version to use when hash bucket locking is NOT required. */ > > > >>>> static void > > > >>>> do_ovn_lflow_add(struct hmap *lflow_map, const struct ovn_datapath > > *od, > > > >>>> const unsigned long *dp_bitmap, size_t > > dp_bitmap_len, > > > >>>> @@ -5797,7 +5862,7 @@ do_ovn_lflow_add(struct hmap *lflow_map, const > > > >> struct ovn_datapath *od, > > > >>>> size_t bitmap_len = od ? ods_size(od->datapaths) : > > dp_bitmap_len; > > > >>>> ovs_assert(bitmap_len); > > > >>>> > > > >>>> - if (add_lflow_to_temp_list) { > > > >>>> + if (collecting_lflows) { > > > >>>> ovs_assert(od); > > > >>>> ovs_assert(!dp_bitmap); > > > >>>> } else { > > > >>>> @@ -5829,8 +5894,8 @@ do_ovn_lflow_add(struct hmap *lflow_map, const > > > >> struct ovn_datapath *od, > > > >>>> thread_lflow_counter++; > > > >>>> } > > > >>>> > > > >>>> - if (add_lflow_to_temp_list) { > > > >>>> - ovs_list_insert(&temp_lflow_list, &lflow->list_node); > > > >>>> + if (collecting_lflows) { > > > >>>> + ovs_list_insert(&collected_lflows, &lflow->list_node); > > > >>>> } > > > >>>> } > > > >>>> > > > >>>> @@ -5950,10 +6015,28 @@ ovn_lflow_destroy(struct hmap *lflows, struct > > > >> ovn_lflow *lflow) > > > >>>> free(lflow->io_port); > > > >>>> free(lflow->stage_hint); > > > >>>> free(lflow->ctrl_meter); > > > >>>> + struct lflow_ref_node *l; > > > >>>> + LIST_FOR_EACH_SAFE (l, ref_list_node, > > &lflow->referenced_by) { > > > >>>> + ovs_list_remove(&l->lflow_list_node); > > > >>>> + ovs_list_remove(&l->ref_list_node); > > > >>>> + free(l); > > > >>>> + } > > > >>>> free(lflow); > > > >>>> } > > > >>>> } > > > >>>> > > > >>>> +static void > > > >>>> +link_ovn_port_to_lflows(struct ovn_port *op, struct ovs_list > > *lflows) > > > >>>> +{ > > > >>>> + struct ovn_lflow *f; > > > >>>> + LIST_FOR_EACH (f, list_node, lflows) { > > > >>>> + struct lflow_ref_node *lfrn = xmalloc(sizeof *lfrn); > > > >>>> + lfrn->lflow = f; > > > >>>> + ovs_list_insert(&op->lflows, &lfrn->lflow_list_node); > > > >>>> + ovs_list_insert(&f->referenced_by, &lfrn->ref_list_node); > > > >>>> + } > > > >>>> +} > > > >>>> + > > > >>>> static bool > > > >>>> build_dhcpv4_action(struct ovn_port *op, ovs_be32 offer_ip, > > > >>>> struct ds *options_action, struct ds > > > >> *response_action, > > > >>>> @@ -15483,6 +15566,7 @@ > > build_lswitch_and_lrouter_iterate_by_lsp(struct > > > >> ovn_port *op, > > > >>>> struct hmap *lflows) > > > >>>> { > > > >>>> ovs_assert(op->nbsp); > > > >>>> + start_collecting_lflows(); > > > >>>> > > > >>>> /* Build Logical Switch Flows. */ > > > >>>> build_lswitch_port_sec_op(op, lflows, actions, match); > > > >>>> @@ -15497,6 +15581,9 @@ > > build_lswitch_and_lrouter_iterate_by_lsp(struct > > > >> ovn_port *op, > > > >>>> /* Build Logical Router Flows. */ > > > >>>> build_ip_routing_flows_for_router_type_lsp(op, lr_ports, > > lflows); > > > >>>> build_arp_resolve_flows_for_lsp(op, lflows, lr_ports, match, > > > >> actions); > > > >>>> + > > > >>>> + link_ovn_port_to_lflows(op, &collected_lflows); > > > >>>> + end_collecting_lflows(); > > > >>>> } > > > >>>> > > > >>>> /* Helper function to combine all lflow generation which is iterated > > > >> by logical > > > >>>> @@ -16223,14 +16310,10 @@ bool lflow_handle_northd_ls_changes(struct > > > >> ovsdb_idl_txn *ovnsb_txn, > > > >>>> { > > > >>>> struct ls_change *ls_change; > > > >>>> LIST_FOR_EACH (ls_change, list_node, &ls_changes->updated) { > > > >>>> - ovs_list_init(&temp_lflow_list); > > > >>>> - add_lflow_to_temp_list = true; > > > >>>> if (!ovs_list_is_empty(&ls_change->updated_ports) || > > > >>>> !ovs_list_is_empty(&ls_change->deleted_ports)) { > > > >>>> /* XXX: implement lflow index so that we can handle > > > >> updated and > > > >>>> * deleted LSPs incrementally. */ > > > >>>> - ovs_list_init(&temp_lflow_list); > > > >>>> - add_lflow_to_temp_list = false; > > > >>>> return false; > > > >>>> } > > > >>>> > > > >>>> @@ -16277,83 +16360,85 @@ bool lflow_handle_northd_ls_changes(struct > > > >> ovsdb_idl_txn *ovnsb_txn, > > > >>>> > > > >> sbrec_multicast_group_update_ports_addvalue(sbmc_unknown, > > > >>>> op->sb); > > > >>>> } > > > >>>> - } > > > >>>> - /* Sync the newly added flows to SB. */ > > > >>>> - struct ovn_lflow *lflow; > > > >>>> - LIST_FOR_EACH (lflow, list_node, &temp_lflow_list) { > > > >>>> - size_t n_datapaths; > > > >>>> - struct ovn_datapath **datapaths_array; > > > >>>> - if (ovn_stage_to_datapath_type(lflow->stage) == > > DP_SWITCH) > > > >> { > > > >>>> - n_datapaths = ods_size(lflow_input->ls_datapaths); > > > >>>> - datapaths_array = lflow_input->ls_datapaths->array; > > > >>>> - } else { > > > >>>> - n_datapaths = ods_size(lflow_input->lr_datapaths); > > > >>>> - datapaths_array = lflow_input->lr_datapaths->array; > > > >>>> - } > > > >>>> - uint32_t n_ods = bitmap_count1(lflow->dpg_bitmap, > > > >> n_datapaths); > > > >>>> - ovs_assert(n_ods == 1); > > > >>>> - /* There is only one datapath, so it should be moved out > > > >> of the > > > >>>> - * group to a single 'od'. */ > > > >>>> - size_t index = bitmap_scan(lflow->dpg_bitmap, true, 0, > > > >>>> - n_datapaths); > > > >>>> > > > >>>> - bitmap_set0(lflow->dpg_bitmap, index); > > > >>>> - lflow->od = datapaths_array[index]; > > > >>>> - > > > >>>> - /* Logical flow should be re-hashed to allow lookups. */ > > > >>>> - uint32_t hash = hmap_node_hash(&lflow->hmap_node); > > > >>>> - /* Remove from lflows. */ > > > >>>> - hmap_remove(lflows, &lflow->hmap_node); > > > >>>> - hash = > > > >> ovn_logical_flow_hash_datapath(&lflow->od->sb->header_.uuid, > > > >>>> - hash); > > > >>>> - /* Add back. */ > > > >>>> - hmap_insert(lflows, &lflow->hmap_node, hash); > > > >>>> - > > > >>>> - /* Sync to SB. */ > > > >>>> - const struct sbrec_logical_flow *sbflow; > > > >>>> - lflow->sb_uuid = uuid_random(); > > > >>>> - sbflow = > > sbrec_logical_flow_insert_persist_uuid(ovnsb_txn, > > > >>>> - > > > >> &lflow->sb_uuid); > > > >>>> - const char *pipeline = > > > >> ovn_stage_get_pipeline_name(lflow->stage); > > > >>>> - uint8_t table = ovn_stage_get_table(lflow->stage); > > > >>>> - sbrec_logical_flow_set_logical_datapath(sbflow, > > > >> lflow->od->sb); > > > >>>> - sbrec_logical_flow_set_logical_dp_group(sbflow, NULL); > > > >>>> - sbrec_logical_flow_set_pipeline(sbflow, pipeline); > > > >>>> - sbrec_logical_flow_set_table_id(sbflow, table); > > > >>>> - sbrec_logical_flow_set_priority(sbflow, > > lflow->priority); > > > >>>> - sbrec_logical_flow_set_match(sbflow, lflow->match); > > > >>>> - sbrec_logical_flow_set_actions(sbflow, lflow->actions); > > > >>>> - if (lflow->io_port) { > > > >>>> - struct smap tags = SMAP_INITIALIZER(&tags); > > > >>>> - smap_add(&tags, "in_out_port", lflow->io_port); > > > >>>> - sbrec_logical_flow_set_tags(sbflow, &tags); > > > >>>> - smap_destroy(&tags); > > > >>>> - } > > > >>>> - sbrec_logical_flow_set_controller_meter(sbflow, > > > >> lflow->ctrl_meter); > > > >>>> - /* Trim the source locator lflow->where, which looks > > > >> something like > > > >>>> - * "ovn/northd/northd.c:1234", down to just the part > > > >> following the > > > >>>> - * last slash, e.g. "northd.c:1234". */ > > > >>>> - const char *slash = strrchr(lflow->where, '/'); > > > >>>> + /* Sync the newly added flows to SB. */ > > > >>>> + struct lflow_ref_node *lfrn; > > > >>>> + LIST_FOR_EACH (lfrn, lflow_list_node, &op->lflows) { > > > >>>> + struct ovn_lflow *lflow = lfrn->lflow; > > > >>>> + size_t n_datapaths; > > > >>>> + struct ovn_datapath **datapaths_array; > > > >>>> + if (ovn_stage_to_datapath_type(lflow->stage) == > > > >> DP_SWITCH) { > > > >>>> + n_datapaths = > > ods_size(lflow_input->ls_datapaths); > > > >>>> + datapaths_array = > > lflow_input->ls_datapaths->array; > > > >>>> + } else { > > > >>>> + n_datapaths = > > ods_size(lflow_input->lr_datapaths); > > > >>>> + datapaths_array = > > lflow_input->lr_datapaths->array; > > > >>>> + } > > > >>>> + uint32_t n_ods = bitmap_count1(lflow->dpg_bitmap, > > > >> n_datapaths); > > > >>>> + ovs_assert(n_ods == 1); > > > >>>> + /* There is only one datapath, so it should be moved > > > >> out of the > > > >>>> + * group to a single 'od'. */ > > > >>>> + size_t index = bitmap_scan(lflow->dpg_bitmap, true, > > 0, > > > >>>> + n_datapaths); > > > >>>> + > > > >>>> + bitmap_set0(lflow->dpg_bitmap, index); > > > >>>> + lflow->od = datapaths_array[index]; > > > >>>> + > > > >>>> + /* Logical flow should be re-hashed to allow > > lookups. > > > >> */ > > > >>>> + uint32_t hash = hmap_node_hash(&lflow->hmap_node); > > > >>>> + /* Remove from lflows. */ > > > >>>> + hmap_remove(lflows, &lflow->hmap_node); > > > >>>> + hash = ovn_logical_flow_hash_datapath( > > > >>>> + > > > >> &lflow->od->sb->header_.uuid, hash); > > > >>>> + /* Add back. */ > > > >>>> + hmap_insert(lflows, &lflow->hmap_node, hash); > > > >>>> + > > > >>>> + /* Sync to SB. */ > > > >>>> + const struct sbrec_logical_flow *sbflow; > > > >>>> + lflow->sb_uuid = uuid_random(); > > > >>>> + sbflow = sbrec_logical_flow_insert_persist_uuid( > > > >>>> + ovnsb_txn, > > > >> &lflow->sb_uuid); > > > >>>> + const char *pipeline = ovn_stage_get_pipeline_name( > > > >>>> + > > > >> lflow->stage); > > > >>>> + uint8_t table = ovn_stage_get_table(lflow->stage); > > > >>>> + sbrec_logical_flow_set_logical_datapath(sbflow, > > > >> lflow->od->sb); > > > >>>> + sbrec_logical_flow_set_logical_dp_group(sbflow, > > NULL); > > > >>>> + sbrec_logical_flow_set_pipeline(sbflow, pipeline); > > > >>>> + sbrec_logical_flow_set_table_id(sbflow, table); > > > >>>> + sbrec_logical_flow_set_priority(sbflow, > > > >> lflow->priority); > > > >>>> + sbrec_logical_flow_set_match(sbflow, lflow->match); > > > >>>> + sbrec_logical_flow_set_actions(sbflow, > > lflow->actions); > > > >>>> + if (lflow->io_port) { > > > >>>> + struct smap tags = SMAP_INITIALIZER(&tags); > > > >>>> + smap_add(&tags, "in_out_port", lflow->io_port); > > > >>>> + sbrec_logical_flow_set_tags(sbflow, &tags); > > > >>>> + smap_destroy(&tags); > > > >>>> + } > > > >>>> + sbrec_logical_flow_set_controller_meter(sbflow, > > > >>>> + > > > >> lflow->ctrl_meter); > > > >>>> + /* Trim the source locator lflow->where, which looks > > > >> something > > > >>>> + * like "ovn/northd/northd.c:1234", down to just the > > > >> part > > > >>>> + * following the last slash, e.g. "northd.c:1234". > > */ > > > >>>> + const char *slash = strrchr(lflow->where, '/'); > > > >>>> #if _WIN32 > > > >>>> - const char *backslash = strrchr(lflow->where, '\\'); > > > >>>> - if (!slash || backslash > slash) { > > > >>>> - slash = backslash; > > > >>>> - } > > > >>>> + const char *backslash = strrchr(lflow->where, '\\'); > > > >>>> + if (!slash || backslash > slash) { > > > >>>> + slash = backslash; > > > >>>> + } > > > >>>> #endif > > > >>>> - const char *where = slash ? slash + 1 : lflow->where; > > > >>>> + const char *where = slash ? slash + 1 : > > lflow->where; > > > >>>> > > > >>>> - struct smap ids = SMAP_INITIALIZER(&ids); > > > >>>> - smap_add(&ids, "stage-name", > > > >> ovn_stage_to_str(lflow->stage)); > > > >>>> - smap_add(&ids, "source", where); > > > >>>> - if (lflow->stage_hint) { > > > >>>> - smap_add(&ids, "stage-hint", lflow->stage_hint); > > > >>>> + struct smap ids = SMAP_INITIALIZER(&ids); > > > >>>> + smap_add(&ids, "stage-name", > > > >> ovn_stage_to_str(lflow->stage)); > > > >>>> + smap_add(&ids, "source", where); > > > >>>> + if (lflow->stage_hint) { > > > >>>> + smap_add(&ids, "stage-hint", lflow->stage_hint); > > > >>>> + } > > > >>>> + sbrec_logical_flow_set_external_ids(sbflow, &ids); > > > >>>> + smap_destroy(&ids); > > > >>>> } > > > >>>> - sbrec_logical_flow_set_external_ids(sbflow, &ids); > > > >>>> - smap_destroy(&ids); > > > >>>> } > > > >>>> } > > > >>>> - ovs_list_init(&temp_lflow_list); > > > >>>> - add_lflow_to_temp_list = false; > > > >>>> return true; > > > >>>> > > > >>>> } > > > >>>> -- > > > >>>> 2.30.2 > > > >>>> > > > >>>> _______________________________________________ > > > >>>> dev mailing list > > > >>>> [email protected] > > > >>>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > > >>>> > > > >> _______________________________________________ > > > >> dev mailing list > > > >> [email protected] > > > >> https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > > > _______________________________________________ > > > > dev mailing list > > > > [email protected] > > > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > > > > _______________________________________________ > > dev mailing list > > [email protected] > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
