On 6/30/21 11:34 AM, Lorenzo Bianconi wrote:
> Remove add_router_lb_flow routine and move leftover lb flow
> installation code in build_lrouter_snat_flows_for_lb routine
>
> Signed-off-by: Lorenzo Bianconi <[email protected]>
> ---
> northd/ovn-northd.c | 258 ++++++++++++++++++++------------------------
> 1 file changed, 119 insertions(+), 139 deletions(-)
>
> diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
> index ddbc6289e..2e69394b3 100644
> --- a/northd/ovn-northd.c
> +++ b/northd/ovn-northd.c
> @@ -8767,92 +8767,6 @@ enum lb_snat_type {
> SKIP_SNAT,
> };
>
> -static void
> -add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od,
> - enum lb_snat_type snat_type, struct ovn_lb_vip *lb_vip,
> - const char *proto, struct nbrec_load_balancer *lb,
> - struct sset *nat_entries)
> -{
> - const char *ip_match = NULL;
> - if (IN6_IS_ADDR_V4MAPPED(&lb_vip->vip)) {
> - ip_match = "ip4";
> - } else {
> - ip_match = "ip6";
> - }
> -
> - if (sset_contains(nat_entries, lb_vip->vip_str)) {
> - /* The load balancer vip is also present in the NAT entries.
> - * So add a high priority lflow to advance the the packet
> - * destined to the vip (and the vip port if defined)
> - * in the S_ROUTER_IN_UNSNAT stage.
> - * There seems to be an issue with ovs-vswitchd. When the new
> - * connection packet destined for the lb vip is received,
> - * it is dnat'ed in the S_ROUTER_IN_DNAT stage in the dnat
> - * conntrack zone. For the next packet, if it goes through
> - * unsnat stage, the conntrack flags are not set properly, and
> - * it doesn't hit the established state flows in
> - * S_ROUTER_IN_DNAT stage. */
> - struct ds unsnat_match = DS_EMPTY_INITIALIZER;
> - ds_put_format(&unsnat_match, "%s && %s.dst == %s && %s",
> - ip_match, ip_match, lb_vip->vip_str, proto);
> - if (lb_vip->vip_port) {
> - ds_put_format(&unsnat_match, " && %s.dst == %d", proto,
> - lb_vip->vip_port);
> - }
> -
> - ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_UNSNAT, 120,
> - ds_cstr(&unsnat_match), "next;",
> &lb->header_);
> -
> - ds_destroy(&unsnat_match);
> - }
> -
> - if (!od->l3dgw_port || !od->l3redirect_port || !lb_vip->n_backends) {
> - return;
> - }
> -
> - /* Add logical flows to UNDNAT the load balanced reverse traffic in
> - * the router egress pipleine stage - S_ROUTER_OUT_UNDNAT if the logical
> - * router has a gateway router port associated.
> - */
> - struct ds undnat_match = DS_EMPTY_INITIALIZER;
> - ds_put_format(&undnat_match, "%s && (", ip_match);
> -
> - for (size_t i = 0; i < lb_vip->n_backends; i++) {
> - struct ovn_lb_backend *backend = &lb_vip->backends[i];
> - ds_put_format(&undnat_match, "(%s.src == %s", ip_match,
> - backend->ip_str);
> -
> - if (backend->port) {
> - ds_put_format(&undnat_match, " && %s.src == %d) || ",
> - proto, backend->port);
> - } else {
> - ds_put_cstr(&undnat_match, ") || ");
> - }
> - }
> -
> - ds_chomp(&undnat_match, ' ');
> - ds_chomp(&undnat_match, '|');
> - ds_chomp(&undnat_match, '|');
> - ds_chomp(&undnat_match, ' ');
> - ds_put_format(&undnat_match, ") && outport == %s && "
> - "is_chassis_resident(%s)", od->l3dgw_port->json_key,
> - od->l3redirect_port->json_key);
> - if (snat_type == FORCE_SNAT || snat_type == SKIP_SNAT) {
> - char *action = xasprintf("flags.%s_snat_for_lb = 1; ct_dnat;",
> - snat_type == SKIP_SNAT ? "skip" : "force");
> - ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_UNDNAT, 120,
> - ds_cstr(&undnat_match), action,
> - &lb->header_);
> - free(action);
> - } else {
> - ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_UNDNAT, 120,
> - ds_cstr(&undnat_match), "ct_dnat;",
> - &lb->header_);
> - }
> -
> - ds_destroy(&undnat_match);
> -}
> -
> static void
> build_lrouter_snat_flows_for_lb(struct ovn_lb_vip *lb_vip,
> struct ovn_northd_lb *lb,
> @@ -8901,9 +8815,88 @@ build_lrouter_snat_flows_for_lb(struct ovn_lb_vip
> *lb_vip,
> new_match = xasprintf("ct.new && %s", ds_cstr(&match));
> est_match = xasprintf("ct.est && %s", ds_cstr(&match));
>
> + const char *ip_match = NULL;
> + if (IN6_IS_ADDR_V4MAPPED(&lb_vip->vip)) {
> + ip_match = "ip4";
> + } else {
> + ip_match = "ip6";
> + }
> +
> + /* Add logical flows to UNDNAT the load balanced reverse traffic in
> + * the router egress pipleine stage - S_ROUTER_OUT_UNDNAT if the logical
> + * router has a gateway router port associated.
> + */
> + struct ds undnat_match = DS_EMPTY_INITIALIZER;
> + ds_put_format(&undnat_match, "%s && (", ip_match);
> +
> + for (size_t i = 0; i < lb_vip->n_backends; i++) {
> + struct ovn_lb_backend *backend = &lb_vip->backends[i];
> + ds_put_format(&undnat_match, "(%s.src == %s", ip_match,
> + backend->ip_str);
> +
> + if (backend->port) {
> + ds_put_format(&undnat_match, " && %s.src == %d) || ",
> + proto, backend->port);
> + } else {
> + ds_put_cstr(&undnat_match, ") || ");
> + }
> + }
> + ds_chomp(&undnat_match, ' ');
> + ds_chomp(&undnat_match, '|');
> + ds_chomp(&undnat_match, '|');
> + ds_chomp(&undnat_match, ' ');
> +
> + struct sset nat_entries = SSET_INITIALIZER(&nat_entries);
> + for (int i = 0; i < lb->n_nb_lr; i++) {
> + struct ovn_datapath *od = lb->nb_lr[i];
> + for (int j = 0; j < od->nbr->n_nat; j++) {
> + const struct nbrec_nat *nat = nat = od->nbr->nat[j];
> +
> + if (od->l3dgw_port) {
> + if (!sset_contains(&nat_entries, nat->external_ip)) {
This doesn't seem right, we're now building a set of nat->external_ips
from *all* datapaths on which the load balancer was created. We
actually still need to do this per datapath (like before).
> + sset_add(&nat_entries, nat->external_ip);
> + }
> + } else {
> + sset_add(&nat_entries, nat->external_ip);
> + }
> + }
> + }
> +
> + if (sset_contains(&nat_entries, lb_vip->vip_str)) {
> + /* The load balancer vip is also present in the NAT entries.
> + * So add a high priority lflow to advance the the packet
> + * destined to the vip (and the vip port if defined)
> + * in the S_ROUTER_IN_UNSNAT stage.
> + * There seems to be an issue with ovs-vswitchd. When the new
> + * connection packet destined for the lb vip is received,
> + * it is dnat'ed in the S_ROUTER_IN_DNAT stage in the dnat
> + * conntrack zone. For the next packet, if it goes through
> + * unsnat stage, the conntrack flags are not set properly, and
> + * it doesn't hit the established state flows in
> + * S_ROUTER_IN_DNAT stage. */
> + struct ds unsnat_match = DS_EMPTY_INITIALIZER;
> + ds_put_format(&unsnat_match, "%s && %s.dst == %s && %s",
> + ip_match, ip_match, lb_vip->vip_str, proto);
> + if (lb_vip->vip_port) {
> + ds_put_format(&unsnat_match, " && %s.dst == %d", proto,
> + lb_vip->vip_port);
> + }
> +
> + for (int i = 0; i < lb->n_nb_lr; i++) {
> + struct ovn_datapath *od = lb->nb_lr[i];
> + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_UNSNAT, 120,
> + ds_cstr(&unsnat_match), "next;",
> + &lb->nlb->header_);
> + }
> +
> + ds_destroy(&unsnat_match);
> + }
> + sset_destroy(&nat_entries);
> +
> for (int i = 0; i < lb->n_nb_lr; i++) {
> char *new_match_p = new_match, *est_match_p = est_match;
> struct ovn_datapath *od = lb->nb_lr[i];
> + char *est_actions = NULL;
>
> if (od->l3redirect_port &&
> (lb_vip->n_backends || !lb_vip->empty_backend_rej)) {
> @@ -8936,12 +8929,11 @@ build_lrouter_snat_flows_for_lb(struct ovn_lb_vip
> *lb_vip,
> &lb->nlb->header_);
> free(new_actions);
>
> - char *est_actions = xasprintf("flags.force_snat_for_lb = 1; "
> - "ct_dnat;");
> + est_actions = xasprintf("flags.force_snat_for_lb = 1; "
> + "ct_dnat;");
> ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, prio,
> est_match_p, est_actions,
> &lb->nlb->header_);
> - free(est_actions);
> } else {
> ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, prio,
> new_match_p, ds_cstr(&action),
> @@ -8957,8 +8949,37 @@ build_lrouter_snat_flows_for_lb(struct ovn_lb_vip
> *lb_vip,
> if (est_match_p != est_match) {
> free(est_match_p);
> }
> +
> + if (!od->l3dgw_port || !od->l3redirect_port || !lb_vip->n_backends) {
> + goto next;
> + }
> +
> + char *undnat_match_p = xasprintf("%s) && outport == %s && "
> + "is_chassis_resident(%s)",
> + ds_cstr(&undnat_match),
> + od->l3dgw_port->json_key,
> + od->l3redirect_port->json_key);
> + if (snat_type == SKIP_SNAT) {
> + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_UNDNAT, 120,
> + undnat_match_p, skip_snat_est_action,
> + &lb->nlb->header_);
> + } else if (snat_type == FORCE_SNAT) {
> + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_UNDNAT, 120,
> + undnat_match_p, est_actions,
> + &lb->nlb->header_);
> + } else {
> + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_UNDNAT, 120,
> + undnat_match_p, "ct_dnat;",
> + &lb->nlb->header_);
> + }
> + free(undnat_match_p);
> +next:
> + if (est_actions) {
> + free(est_actions);
> + }
No need for the if, "free(est_actions);" is enough.
> }
>
> + ds_destroy(&undnat_match);
> ds_destroy(&action);
> ds_destroy(&match);
>
> @@ -9001,19 +9022,23 @@ build_lrouter_flows_for_lb(struct ovn_northd_lb *lb,
> struct hmap *lflows,
> lflows);
> }
>
> + if (smap_get_bool(&lb->nlb->options, "skip_snat", false)) {
> + for (int i = 0; i < lb->n_nb_lr; i++) {
s/int i/size_t i/
> + ovn_lflow_add(lflows, lb->nb_lr[i], S_ROUTER_OUT_SNAT, 120,
> + "flags.skip_snat_for_lb == 1 && ip", "next;");
> + }
> + }
> +
> ds_destroy(&action);
> ds_destroy(&match);
> }
>
> static void
> build_lrouter_lb_flows(struct hmap *lflows, struct ovn_datapath *od,
> - struct hmap *lbs, struct sset *nat_entries,
> - struct ds *match, struct ds *actions)
> + struct hmap *lbs, struct ds *match)
> {
> /* A set to hold all ips that need defragmentation and tracking. */
> struct sset all_ips = SSET_INITIALIZER(&all_ips);
> - bool lb_force_snat_ip =
> - !lport_addresses_is_empty(&od->lb_force_snat_addrs);
>
> for (int i = 0; i < od->nbr->n_load_balancer; i++) {
> struct nbrec_load_balancer *nb_lb = od->nbr->load_balancer[i];
> @@ -9021,21 +9046,8 @@ build_lrouter_lb_flows(struct hmap *lflows, struct
> ovn_datapath *od,
> ovn_northd_lb_find(lbs, &nb_lb->header_.uuid);
> ovs_assert(lb);
>
> - enum lb_snat_type snat_type = NO_FORCE_SNAT;
> - if (smap_get_bool(&nb_lb->options, "skip_snat", false)) {
> - ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, 120,
> - "flags.skip_snat_for_lb == 1 && ip", "next;");
> - snat_type = SKIP_SNAT;
> - } else if (lb_force_snat_ip || od->lb_force_snat_router_ip) {
> - snat_type = FORCE_SNAT;
> - }
> -
> for (size_t j = 0; j < lb->n_vips; j++) {
> struct ovn_lb_vip *lb_vip = &lb->vips[j];
> - struct ovn_northd_lb_vip *lb_vip_nb = &lb->vips_nb[j];
> - ds_clear(actions);
> - build_lb_vip_actions(lb_vip, lb_vip_nb, actions,
> - lb->selection_fields, false);
>
> if (!sset_contains(&all_ips, lb_vip->vip_str)) {
> sset_add(&all_ips, lb_vip->vip_str);
> @@ -9059,38 +9071,6 @@ build_lrouter_lb_flows(struct hmap *lflows, struct
> ovn_datapath *od,
> 100, ds_cstr(match), "ct_next;",
> &nb_lb->header_);
> }
> -
> - /* Higher priority rules are added for load-balancing in DNAT
> - * table. For every match (on a VIP[:port]), we add two flows
> - * via add_router_lb_flow(). One flow is for specific matching
> - * on ct.new with an action of "ct_lb($targets);". The other
> - * flow is for ct.est with an action of "ct_dnat;". */
> - ds_clear(match);
> - if (IN6_IS_ADDR_V4MAPPED(&lb_vip->vip)) {
> - ds_put_format(match, "ip && ip4.dst == %s",
> - lb_vip->vip_str);
> - } else {
> - ds_put_format(match, "ip && ip6.dst == %s",
> - lb_vip->vip_str);
> - }
> -
> - bool is_udp = nullable_string_is_equal(nb_lb->protocol, "udp");
> - bool is_sctp = nullable_string_is_equal(nb_lb->protocol,
> - "sctp");
> - const char *proto = is_udp ? "udp" : is_sctp ? "sctp" : "tcp";
> -
> - if (lb_vip->vip_port) {
> - ds_put_format(match, " && %s && %s.dst == %d", proto,
> - proto, lb_vip->vip_port);
> - }
> -
> - if (od->l3redirect_port &&
> - (lb_vip->n_backends || !lb_vip->empty_backend_rej)) {
> - ds_put_format(match, " && is_chassis_resident(%s)",
> - od->l3redirect_port->json_key);
> - }
> - add_router_lb_flow(lflows, od, snat_type, lb_vip, proto, nb_lb,
> - nat_entries);
> }
> }
> sset_destroy(&all_ips);
> @@ -12039,7 +12019,7 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath
> *od,
> return;
> }
>
> - build_lrouter_lb_flows(lflows, od, lbs, &nat_entries, match, actions);
> + build_lrouter_lb_flows(lflows, od, lbs, match);
>
> sset_destroy(&nat_entries);
> }
>
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev