773311
From 74e1bf4dd0f6c62602ab708eabb5534a274a4d75 Mon Sep 17 00:00:00 2001
773311
From: Dumitru Ceara <dceara@redhat.com>
773311
Date: Tue, 28 Apr 2020 12:39:26 +0200
773311
Subject: [PATCH] ovn-northd: Optimize flows for LB Hairpin traffic.
773311
773311
In order to detect that traffic was hairpinned due to logical switch load
773311
balancers we need to match on source and destination IPs of packets (and
773311
protocol ports potentially) in table ls_in_pre_hairpin.
773311
773311
For this, until now, we created 2 logical flows for each backend of a load
773311
balancer VIP. However, in scenarios where large load balancers (i.e.,
773311
with large numbers of backends) are applied to multiple logical
773311
switches, this might generate logical flow count explosion.
773311
773311
One optimization is to generate a single logical flow per VIP that
773311
combines all conditions generated for each backend. This reduces load on
773311
the SB DB because of lower number of logical flows and also reduces
773311
overall DB size because of less overhead due to other fields on the
773311
logical_flow records.
773311
773311
Comparison of various performance aspects when running OVN with the NB
773311
database attached to the bug report on a deployment with all VIFs bound
773311
to a single node (62 load balancer VIPs with 513 load balancer
773311
backends, applied on 106 logical switches):
773311
773311
Without this patch:
773311
- SB database size: 60MB
773311
- # of pre-hairpin logical flows: 109074
773311
- # of logical flows: 159414
773311
- ovn-controller max loop iteration time when processing SB DB: 8803ms
773311
- ovn-northd max loop iteration time: 3988ms
773311
773311
With this patch:
773311
- SB database size: 29MB (~50% decrease)
773311
- # of pre-hairpin logical flows: 13250 (~88% decrease)
773311
- # of logical flows: 63590 (~60% decrease)
773311
- ovn-controller max loop iteration time when processing SB DB: 5585ms
773311
- ovn-northd max loop iteration time: 1594ms
773311
773311
Reported-by: Aniket Bhat <anbhat@redhat.com>
773311
Reported-at: https://bugzilla.redhat.com/1827403
773311
Fixes: 1be8ac65bc60 ("ovn-northd: Support hairpinning for logical switch load balancing.")
773311
Signed-off-by: Dumitru Ceara <dceara@redhat.com>
773311
Signed-off-by: Numan Siddique <numans@ovn.org>
773311
(cherry picked from upstream commit 97e82ae5f135a088c9e95b49122d8217718d23f4)
773311
773311
Change-Id: Id713209f8bd159e8ad924e91681bab784606faff
773311
---
773311
 northd/ovn-northd.8.xml |  4 +--
773311
 northd/ovn-northd.c     | 79 ++++++++++++++++++++++++++++++++-----------------
773311
 2 files changed, 54 insertions(+), 29 deletions(-)
773311
773311
diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
773311
index d39e259..1f81742 100644
773311
--- a/northd/ovn-northd.8.xml
773311
+++ b/northd/ovn-northd.8.xml
773311
@@ -559,14 +559,14 @@
773311
     

Ingress Table 11: Pre-Hairpin

773311
     
    773311
           
  • 773311
    -        For all configured load balancer backends a priority-2 flow that
    773311
    +        For all configured load balancer VIPs a priority-2 flow that
    773311
             matches on traffic that needs to be hairpinned, i.e., after load
    773311
             balancing the destination IP matches the source IP, which sets
    773311
             reg0[6] = 1  and executes ct_snat(VIP)
    773311
             to force replies to these packets to come back through OVN.
    773311
           
    773311
           
  • 773311
    -        For all configured load balancer backends a priority-1 flow that
    773311
    +        For all configured load balancer VIPs a priority-1 flow that
    773311
             matches on replies to hairpinned traffic, i.e., destination IP is VIP,
    773311
             source IP is the backend IP and source L4 port is backend port, which
    773311
             sets reg0[6] = 1  and executes ct_snat;.
    773311
    diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
    773311
    index 0082e2e..5ada3ae 100644
    773311
    --- a/northd/ovn-northd.c
    773311
    +++ b/northd/ovn-northd.c
    773311
    @@ -5542,52 +5542,77 @@ build_lb_hairpin_rules(struct ovn_datapath *od, struct hmap *lflows,
    773311
                            struct ovn_lb *lb, struct lb_vip *lb_vip,
    773311
                            const char *ip_match, const char *proto)
    773311
     {
    773311
    +    if (lb_vip->n_backends == 0) {
    773311
    +        return;
    773311
    +    }
    773311
    +
    773311
    +    struct ds action = DS_EMPTY_INITIALIZER;
    773311
    +    struct ds match_initiator = DS_EMPTY_INITIALIZER;
    773311
    +    struct ds match_reply = DS_EMPTY_INITIALIZER;
    773311
    +    struct ds proto_match = DS_EMPTY_INITIALIZER;
    773311
    +
    773311
         /* Ingress Pre-Hairpin table.
    773311
    -     * - Priority 2: SNAT load balanced traffic that needs to be hairpinned.
    773311
    +     * - Priority 2: SNAT load balanced traffic that needs to be hairpinned:
    773311
    +     *   - Both SRC and DST IP match backend->ip and destination port
    773311
    +     *     matches backend->port.
    773311
          * - Priority 1: unSNAT replies to hairpinned load balanced traffic.
    773311
    +     *   - SRC IP matches backend->ip, DST IP matches LB VIP and source port
    773311
    +     *     matches backend->port.
    773311
          */
    773311
    +    ds_put_char(&match_reply, '(');
    773311
         for (size_t i = 0; i < lb_vip->n_backends; i++) {
    773311
             struct lb_vip_backend *backend = &lb_vip->backends[i];
    773311
    -        struct ds action = DS_EMPTY_INITIALIZER;
    773311
    -        struct ds match = DS_EMPTY_INITIALIZER;
    773311
    -        struct ds proto_match = DS_EMPTY_INITIALIZER;
    773311
     
    773311
             /* Packets that after load balancing have equal source and
    773311
    -         * destination IPs should be hairpinned. SNAT them so that the reply
    773311
    -         * traffic is directed also through OVN.
    773311
    +         * destination IPs should be hairpinned.
    773311
              */
    773311
             if (lb_vip->vip_port) {
    773311
    -            ds_put_format(&proto_match, " && %s && %s.dst == %"PRIu16,
    773311
    -                          proto, proto, backend->port);
    773311
    +            ds_put_format(&proto_match, " && %s.dst == %"PRIu16,
    773311
    +                          proto, backend->port);
    773311
             }
    773311
    -        ds_put_format(&match, "%s.src == %s && %s.dst == %s%s",
    773311
    +        ds_put_format(&match_initiator, "(%s.src == %s && %s.dst == %s%s)",
    773311
                           ip_match, backend->ip, ip_match, backend->ip,
    773311
                           ds_cstr(&proto_match));
    773311
    -        ds_put_format(&action, REGBIT_HAIRPIN " = 1; ct_snat(%s);",
    773311
    -                      lb_vip->vip);
    773311
    -        ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_PRE_HAIRPIN, 2,
    773311
    -                                ds_cstr(&match), ds_cstr(&action),
    773311
    -                                &lb->nlb->header_);
    773311
     
    773311
    -        /* If the packets are replies for hairpinned traffic, UNSNAT them. */
    773311
    +        /* Replies to hairpinned traffic are originated by backend->ip:port. */
    773311
             ds_clear(&proto_match);
    773311
    -        ds_clear(&match);
    773311
             if (lb_vip->vip_port) {
    773311
    -            ds_put_format(&proto_match, " && %s && %s.src == %"PRIu16,
    773311
    -                          proto, proto, backend->port);
    773311
    +            ds_put_format(&proto_match, " && %s.src == %"PRIu16, proto,
    773311
    +                          backend->port);
    773311
             }
    773311
    -        ds_put_format(&match, "%s.src == %s && %s.dst == %s%s",
    773311
    -                      ip_match, backend->ip, ip_match, lb_vip->vip,
    773311
    +        ds_put_format(&match_reply, "(%s.src == %s%s)", ip_match, backend->ip,
    773311
                           ds_cstr(&proto_match));
    773311
    -        ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_PRE_HAIRPIN, 1,
    773311
    -                                ds_cstr(&match),
    773311
    -                                REGBIT_HAIRPIN " = 1; ct_snat;",
    773311
    -                                &lb->nlb->header_);
    773311
    +        ds_clear(&proto_match);
    773311
     
    773311
    -        ds_destroy(&action);
    773311
    -        ds_destroy(&match);
    773311
    -        ds_destroy(&proto_match);
    773311
    +        if (i < lb_vip->n_backends - 1) {
    773311
    +            ds_put_cstr(&match_initiator, " || ");
    773311
    +            ds_put_cstr(&match_reply, " || ");
    773311
    +        }
    773311
         }
    773311
    +    ds_put_char(&match_reply, ')');
    773311
    +
    773311
    +    /* SNAT hairpinned initiator traffic so that the reply traffic is
    773311
    +     * also directed through OVN.
    773311
    +     */
    773311
    +    ds_put_format(&action, REGBIT_HAIRPIN " = 1; ct_snat(%s);",
    773311
    +                  lb_vip->vip);
    773311
    +    ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_PRE_HAIRPIN, 2,
    773311
    +                            ds_cstr(&match_initiator), ds_cstr(&action),
    773311
    +                            &lb->nlb->header_);
    773311
    +
    773311
    +    /* Replies to hairpinned traffic are destined to the LB VIP. */
    773311
    +    ds_put_format(&match_reply, " && %s.dst == %s", ip_match, lb_vip->vip);
    773311
    +
    773311
    +    /* UNSNAT replies for hairpinned traffic. */
    773311
    +    ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_PRE_HAIRPIN, 1,
    773311
    +                            ds_cstr(&match_reply),
    773311
    +                            REGBIT_HAIRPIN " = 1; ct_snat;",
    773311
    +                            &lb->nlb->header_);
    773311
    +
    773311
    +    ds_destroy(&action);
    773311
    +    ds_destroy(&match_initiator);
    773311
    +    ds_destroy(&match_reply);
    773311
    +    ds_destroy(&proto_match);
    773311
     }
    773311
     
    773311
     static void
    773311
    -- 
    773311
    1.8.3.1
    773311