On 5/13/22 12:54, Dumitru Ceara wrote:
> On 5/3/22 21:20, Lorenzo Bianconi wrote:
>> Group together gw routers where a given load balancer is installed
>> dividing them according to snat_type flag (skip_snat, force_snat).
>> This is a preliminary patch to reduce load balancer logical flows
>> computation cost for gw routers.
>>
>> Signed-off-by: Lorenzo Bianconi <[email protected]>
>> ---
> 
> Hi Lorenzo,
> 
> I think the idea in this patch (and following ones) is OK.  There is
> however an issue we need to fix.  Please see below.
> 
>>  northd/northd.c | 83 ++++++++++++++++++++++++++++++++++++++++++-------
>>  1 file changed, 71 insertions(+), 12 deletions(-)
>>
>> diff --git a/northd/northd.c b/northd/northd.c
>> index bcb470043..d90879eeb 100644
>> --- a/northd/northd.c
>> +++ b/northd/northd.c
>> @@ -9832,6 +9832,29 @@ enum lb_snat_type {
>>      SKIP_SNAT,
>>  };
>>  
>> +static void
>> +build_gw_lrouter_nat_flows_for_lb(struct ovn_northd_lb *lb,
>> +                                  struct ovn_datapath **dplist, int 
>> n_dplist,
>> +                                  bool reject, char *new_match,
>> +                                  char *new_action, char *est_match,
>> +                                  char *est_action, struct hmap *lflows,
>> +                                  int prio, const struct shash 
>> *meter_groups)
>> +{
>> +    for (size_t i = 0; i < n_dplist; i++) {
>> +        struct ovn_datapath *od = dplist[i];
>> +        const char *meter = NULL;
>> +
>> +        if (reject) {
>> +            meter = copp_meter_get(COPP_REJECT, od->nbr->copp, 
>> meter_groups);
>> +        }
>> +        ovn_lflow_add_with_hint__(lflows, od, S_ROUTER_IN_DNAT, prio,
>> +                                  new_match, new_action, NULL, meter,
>> +                                  &lb->nlb->header_);
>> +        ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, prio,
>> +                                est_match, est_action, &lb->nlb->header_);
>> +    }
>> +}
>> +
>>  static void
>>  build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip,
>>                                 struct ovn_northd_lb *lb,
>> @@ -9929,6 +9952,42 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip 
>> *lb_vip,
>>                        lb_vip->vip_port);
>>      }
>>  
>> +    struct ovn_datapath **gw_router_skip_snat =
>> +        xcalloc(lb->n_nb_lr, sizeof *gw_router_skip_snat);
>> +    int n_gw_router_skip_snat = 0;
>> +
>> +    struct ovn_datapath **gw_router_force_snat =
>> +        xcalloc(lb->n_nb_lr, sizeof *gw_router_force_snat);
>> +    int n_gw_router_force_snat = 0;
>> +
>> +    struct ovn_datapath **gw_router =
>> +        xcalloc(lb->n_nb_lr, sizeof *gw_router);
>> +    int n_gw_router = 0;
>> +
>> +    /* Group gw router since we do not have datapath dependency in
>> +     * lflow generation for them.
>> +     */
>> +    for (size_t i = 0; i < lb->n_nb_lr; i++) {
>> +        struct ovn_datapath *od = lb->nb_lr[i];
>> +        if (!od->n_l3dgw_ports) {
>> +            if (snat_type == SKIP_SNAT) {
>> +                gw_router_skip_snat[n_gw_router_skip_snat++] = od;
>> +            } else if (!lport_addresses_is_empty(&od->lb_force_snat_addrs) 
>> ||
>> +                       od->lb_force_snat_router_ip) {
>> +                gw_router_force_snat[n_gw_router_force_snat++] = od;
>> +                snat_type = FORCE_SNAT;
>> +            } else {
>> +                gw_router[n_gw_router++] = od;
>> +            }
>> +        }
>> +    }
> 
> At this point, if at least one router has lb_force_snat_router_ip or
> lb_force_snat_addrs set, then snat_type is FORCE_SNAT.
> 
>> +
>> +    build_gw_lrouter_nat_flows_for_lb(lb, gw_router_skip_snat,
>> +            n_gw_router_skip_snat, reject, new_match,
>> +            skip_snat_new_action, est_match,
>> +            skip_snat_est_action, lflows, prio, meter_groups);
>> +
>> +
>>      for (size_t i = 0; i < lb->n_nb_lr; i++) {
> 
> Here we iterate again through all routers on which the LB is applied.
> Each of these might need a different "force snat" behavior.
> 

Patch 4/5 "fixes" this by skipping the second part of the loop for
gw-routers.  But we still have this problem for non-gw-routers on which
the LB is applied.

Thanks,
Dumitru

>>          struct ovn_datapath *od = lb->nb_lr[i];
>>          char *new_match_p = new_match;
>> @@ -9967,19 +10026,15 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip 
>> *lb_vip,
>>                                      od->l3dgw_ports[0]->cr_port->json_key);
>>          }
>>  
>> -        if (snat_type == NO_FORCE_SNAT &&
>> -            (!lport_addresses_is_empty(&od->lb_force_snat_addrs) ||
>> -             od->lb_force_snat_router_ip)) {
>> -            snat_type = FORCE_SNAT;
>> -        }
>> -
>>          if (snat_type == SKIP_SNAT) {
>> -            ovn_lflow_add_with_hint__(lflows, od, S_ROUTER_IN_DNAT, prio,
>> -                                      new_match_p, skip_snat_new_action, 
>> NULL,
>> -                                      meter, &lb->nlb->header_);
>> -            ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, prio,
>> -                                    est_match_p, skip_snat_est_action,
>> -                                    &lb->nlb->header_);
>> +            if (od->n_l3dgw_ports) {
>> +                ovn_lflow_add_with_hint__(lflows, od, S_ROUTER_IN_DNAT, 
>> prio,
>> +                                          new_match_p, skip_snat_new_action,
>> +                                          NULL, meter, &lb->nlb->header_);
>> +                ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, prio,
>> +                                        est_match_p, skip_snat_est_action,
>> +                                        &lb->nlb->header_);
>> +            }
>>          } else if (snat_type == FORCE_SNAT) {
> 
> But if snat_type was FORCE_SNAT before the loop then we will always
> enter this "if" which is not correct.
> 
> I think the way to correctly implement this is to actually build 6 sets
> of routers:
> 
> 1. gw_router_skip_snat
> 2. gw_router_force_snat
> 3. gw_router_no_snat
> 
> These first 3 are the ones you already built above.  We need the
> following 3 extra ones:
> 
> 4. distrib_router_skip_snat
> 5. distrib_router_force_snat
> 6. distrib_router_no_snat
> 
> Maybe we can change the snat type enum to:
> 
> enum lb_snat_type {
>     GW_RTR_NO_FORCE_SNAT,
>     GW_RTR_FORCE_SNAT,
>     GW_RTR_SKIP_SNAT,
>     DIST_RTR_NO_FORCE_SNAT,
>     DIST_RTR_FORCE_SNAT,
>     DIST_RTR_SKIP_SNAT,
>     LB_SNAT_TYPE_MAX,
> };
> 
> And then build an array of routers per snat type, e.g.:
> 
> struct ovn_datapath **rtr_by_snat_type[LB_SNAT_TYPE_MAX];
> size_t n_rtr_by_snat_type[LB_SNAT_TYPE_MAX];
> 
> We could then factor out the body of this second loop into a function,
> e.g., build_lrouter_snat_flows_for_lb(), and use it like:
> 
> for (snat_type = 0; snat_type < LB_SNAT_TYPE_MAX; snat_type++) {
>     for each od in rtr_by_snat_type[snat_type] {
>         build_lrouter_snat_flows_for_lb(od, snat_type, ...);
>     }
> }
> 
> What do you think?
> 
> Thanks,
> Dumitru
> 
>>              char *new_actions = xasprintf("flags.force_snat_for_lb = 1; %s",
>>                                            ds_cstr(action));
>> @@ -10044,6 +10099,10 @@ next:
>>      free(skip_snat_est_action);
>>      free(est_match);
>>      free(new_match);
>> +
>> +    free(gw_router_force_snat);
>> +    free(gw_router_skip_snat);
>> +    free(gw_router);
>>  }
>>  
>>  static void
> 

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to