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