On 6/27/23 10:23, Numan Siddique wrote:
> On Mon, Jun 26, 2023 at 10:34 PM Han Zhou <hz...@ovn.org> wrote:
>>
>> On Mon, Jun 26, 2023 at 7:25 AM Numan Siddique <num...@ovn.org> wrote:
>>>
>>> On Sun, Jun 18, 2023 at 11:48 AM Han Zhou <hz...@ovn.org> 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 <hz...@ovn.org>
>>>
>>> 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.

> 
> 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
>>>> 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
> _______________________________________________
> 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

Reply via email to