5f9769
From 5336b5cb342b8f81115299540f3268f734a6d009 Mon Sep 17 00:00:00 2001
5f9769
From: Dumitru Ceara <dceara@redhat.com>
5f9769
Date: Wed, 10 Feb 2021 12:20:17 +0100
5f9769
Subject: [PATCH] northd: Skip matching on ct flags for stateless
5f9769
 configurations.
5f9769
5f9769
If no load balancers or "allow-related" ACLs are configured on a logical
5f9769
switch, no packets will be sent to conntrack in the logical switch
5f9769
pipeline and ACL flows in tables ls_in/out_acl will not match on
5f9769
conntrack state.  In this case there's no need to try to set ACL hints
5f9769
in tables ls_in/out_acl_hint.
5f9769
5f9769
Furthermore, setting the hints translates to always generating flows
5f9769
that match on ct.state.  Depending on the underlying hardware such flows
5f9769
may not be offloadable inducing a hit in performance even when no
5f9769
conntrack recirculations are required.
5f9769
5f9769
To avoid iterating through all configured ACLs and load balancers
5f9769
multiple times, we now store two new fields in the 'ovn_datapath'
5f9769
structure:
5f9769
- has_stateful_acl
5f9769
- has_lb_vip
5f9769
5f9769
Also, rename the 'has_lb_vip()' and 'has_stateful_acl()' functions,
5f9769
prefixing them with 'ls_' to match other helper function names.
5f9769
5f9769
Fixes: 209ea46bbf9d ("ovn-northd: Reduce number of flows generated for stateful ACLs.")
5f9769
Reported-by: Haresh Khandelwal <hakhande@redhat.com>
5f9769
Reported-at: https://bugzilla.redhat.com/1927211
5f9769
Signed-off-by: Dumitru Ceara <dceara@redhat.com>
5f9769
Signed-off-by: Mark Michelson <mmichels@redhat.com>
5f9769
Acked-by: Mark Michelson <mmichels@redhat.com>
5f9769
---
5f9769
 northd/ovn-northd.8.xml |  3 +-
5f9769
 northd/ovn-northd.c     | 34 +++++++++++-------
5f9769
 tests/ovn-northd.at     | 77 +++++++++++++++++++++++++++++++++++++++++
5f9769
 3 files changed, 101 insertions(+), 13 deletions(-)
5f9769
5f9769
diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
5f9769
index 70065a36d..2f8b4e8c3 100644
5f9769
--- a/northd/ovn-northd.8.xml
5f9769
+++ b/northd/ovn-northd.8.xml
5f9769
@@ -415,7 +415,8 @@
5f9769
     

5f9769
       This table consists of logical flows that set hints
5f9769
       (reg0 bits) to be used in the next stage, in the ACL
5f9769
-      processing table. Multiple hints can be set for the same packet.
5f9769
+      processing table, if stateful ACLs or load balancers are configured.
5f9769
+      Multiple hints can be set for the same packet.
5f9769
       The possible hints are:
5f9769
     

5f9769
     
    5f9769
    diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
    5f9769
    index db6572a62..b85e6e78a 100644
    5f9769
    --- a/northd/ovn-northd.c
    5f9769
    +++ b/northd/ovn-northd.c
    5f9769
    @@ -597,6 +597,8 @@ struct ovn_datapath {
    5f9769
         struct hmap port_tnlids;
    5f9769
         uint32_t port_key_hint;
    5f9769
     
    5f9769
    +    bool has_stateful_acl;
    5f9769
    +    bool has_lb_vip;
    5f9769
         bool has_unknown;
    5f9769
     
    5f9769
         /* IPAM data. */
    5f9769
    @@ -635,6 +637,9 @@ struct ovn_datapath {
    5f9769
         struct hmap nb_pgs;
    5f9769
     };
    5f9769
     
    5f9769
    +static bool ls_has_stateful_acl(struct ovn_datapath *od);
    5f9769
    +static bool ls_has_lb_vip(struct ovn_datapath *od);
    5f9769
    +
    5f9769
     /* Contains a NAT entry with the external addresses pre-parsed. */
    5f9769
     struct ovn_nat {
    5f9769
         const struct nbrec_nat *nb;
    5f9769
    @@ -4635,7 +4640,7 @@ ovn_ls_port_group_destroy(struct hmap *nb_pgs)
    5f9769
     }
    5f9769
     
    5f9769
     static bool
    5f9769
    -has_stateful_acl(struct ovn_datapath *od)
    5f9769
    +ls_has_stateful_acl(struct ovn_datapath *od)
    5f9769
     {
    5f9769
         for (size_t i = 0; i < od->nbs->n_acls; i++) {
    5f9769
             struct nbrec_acl *acl = od->nbs->acls[i];
    5f9769
    @@ -4814,8 +4819,6 @@ skip_port_from_conntrack(struct ovn_datapath *od, struct ovn_port *op,
    5f9769
     static void
    5f9769
     build_pre_acls(struct ovn_datapath *od, struct hmap *lflows)
    5f9769
     {
    5f9769
    -    bool has_stateful = has_stateful_acl(od);
    5f9769
    -
    5f9769
         /* Ingress and Egress Pre-ACL Table (Priority 0): Packets are
    5f9769
          * allowed by default. */
    5f9769
         ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 0, "1", "next;");
    5f9769
    @@ -4830,7 +4833,7 @@ build_pre_acls(struct ovn_datapath *od, struct hmap *lflows)
    5f9769
         /* If there are any stateful ACL rules in this datapath, we must
    5f9769
          * send all IP packets through the conntrack action, which handles
    5f9769
          * defragmentation, in order to match L4 headers. */
    5f9769
    -    if (has_stateful) {
    5f9769
    +    if (od->has_stateful_acl) {
    5f9769
             for (size_t i = 0; i < od->n_router_ports; i++) {
    5f9769
                 skip_port_from_conntrack(od, od->router_ports[i],
    5f9769
                                          S_SWITCH_IN_PRE_ACL, S_SWITCH_OUT_PRE_ACL,
    5f9769
    @@ -4933,7 +4936,7 @@ build_empty_lb_event_flow(struct ovn_datapath *od, struct hmap *lflows,
    5f9769
     }
    5f9769
     
    5f9769
     static bool
    5f9769
    -has_lb_vip(struct ovn_datapath *od)
    5f9769
    +ls_has_lb_vip(struct ovn_datapath *od)
    5f9769
     {
    5f9769
         for (int i = 0; i < od->nbs->n_load_balancer; i++) {
    5f9769
             struct nbrec_load_balancer *nb_lb = od->nbs->load_balancer[i];
    5f9769
    @@ -5076,6 +5079,13 @@ build_acl_hints(struct ovn_datapath *od, struct hmap *lflows)
    5f9769
         for (size_t i = 0; i < ARRAY_SIZE(stages); i++) {
    5f9769
             enum ovn_stage stage = stages[i];
    5f9769
     
    5f9769
    +        /* In any case, advance to the next stage. */
    5f9769
    +        ovn_lflow_add(lflows, od, stage, 0, "1", "next;");
    5f9769
    +
    5f9769
    +        if (!od->has_stateful_acl && !od->has_lb_vip) {
    5f9769
    +            continue;
    5f9769
    +        }
    5f9769
    +
    5f9769
             /* New, not already established connections, may hit either allow
    5f9769
              * or drop ACLs. For allow ACLs, the connection must also be committed
    5f9769
              * to conntrack so we set REGBIT_ACL_HINT_ALLOW_NEW.
    5f9769
    @@ -5136,9 +5146,6 @@ build_acl_hints(struct ovn_datapath *od, struct hmap *lflows)
    5f9769
             ovn_lflow_add(lflows, od, stage, 1, "ct.est && ct_label.blocked == 0",
    5f9769
                           REGBIT_ACL_HINT_BLOCK " = 1; "
    5f9769
                           "next;");
    5f9769
    -
    5f9769
    -        /* In any case, advance to the next stage. */
    5f9769
    -        ovn_lflow_add(lflows, od, stage, 0, "1", "next;");
    5f9769
         }
    5f9769
     }
    5f9769
     
    5f9769
    @@ -5470,7 +5477,7 @@ static void
    5f9769
     build_acls(struct ovn_datapath *od, struct hmap *lflows,
    5f9769
                struct hmap *port_groups, const struct shash *meter_groups)
    5f9769
     {
    5f9769
    -    bool has_stateful = (has_stateful_acl(od) || has_lb_vip(od));
    5f9769
    +    bool has_stateful = od->has_stateful_acl || od->has_lb_vip;
    5f9769
     
    5f9769
         /* Ingress and Egress ACL Table (Priority 0): Packets are allowed by
    5f9769
          * default.  A related rule at priority 1 is added below if there
    5f9769
    @@ -5739,7 +5746,7 @@ build_lb(struct ovn_datapath *od, struct hmap *lflows)
    5f9769
             }
    5f9769
         }
    5f9769
     
    5f9769
    -    if (has_lb_vip(od)) {
    5f9769
    +    if (od->has_lb_vip) {
    5f9769
             /* Ingress and Egress LB Table (Priority 65534).
    5f9769
              *
    5f9769
              * Send established traffic through conntrack for just NAT. */
    5f9769
    @@ -5860,7 +5867,7 @@ build_lb_hairpin(struct ovn_datapath *od, struct hmap *lflows)
    5f9769
         ovn_lflow_add(lflows, od, S_SWITCH_IN_NAT_HAIRPIN, 0, "1", "next;");
    5f9769
         ovn_lflow_add(lflows, od, S_SWITCH_IN_HAIRPIN, 0, "1", "next;");
    5f9769
     
    5f9769
    -    if (has_lb_vip(od)) {
    5f9769
    +    if (od->has_lb_vip) {
    5f9769
             /* Check if the packet needs to be hairpinned. */
    5f9769
             ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_PRE_HAIRPIN, 100,
    5f9769
                                     "ip && ct.trk && ct.dnat",
    5f9769
    @@ -6597,7 +6604,10 @@ build_lswitch_lflows_pre_acl_and_acl(struct ovn_datapath *od,
    5f9769
                                          struct shash *meter_groups,
    5f9769
                                          struct hmap *lbs)
    5f9769
     {
    5f9769
    -   if (od->nbs) {
    5f9769
    +    if (od->nbs) {
    5f9769
    +        od->has_stateful_acl = ls_has_stateful_acl(od);
    5f9769
    +        od->has_lb_vip = ls_has_lb_vip(od);
    5f9769
    +
    5f9769
             build_pre_acls(od, lflows);
    5f9769
             build_pre_lb(od, lflows, meter_groups, lbs);
    5f9769
             build_pre_stateful(od, lflows);
    5f9769
    diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
    5f9769
    index 7240e22ba..64a788067 100644
    5f9769
    --- a/tests/ovn-northd.at
    5f9769
    +++ b/tests/ovn-northd.at
    5f9769
    @@ -1912,6 +1912,83 @@ check_meter_by_name NOT meter_me__${acl1} meter_me__${acl2}
    5f9769
     
    5f9769
     AT_CLEANUP
    5f9769
     
    5f9769
    +AT_SETUP([ovn -- ACL skip hints for stateless config])
    5f9769
    +AT_KEYWORDS([acl])
    5f9769
    +ovn_start
    5f9769
    +
    5f9769
    +check ovn-nbctl --wait=sb \
    5f9769
    +    -- ls-add ls \
    5f9769
    +    -- lsp-add ls lsp \
    5f9769
    +    -- acl-add ls from-lport 1 "ip" allow \
    5f9769
    +    -- acl-add ls to-lport 1 "ip" allow
    5f9769
    +
    5f9769
    +AS_BOX([Check no match on ct_state with stateless ACLs])
    5f9769
    +AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e ls_in_acl -e ls_out_acl | grep 'ct\.' | sort], [0], [dnl
    5f9769
    +])
    5f9769
    +
    5f9769
    +AS_BOX([Check match ct_state with stateful ACLs])
    5f9769
    +check ovn-nbctl --wait=sb \
    5f9769
    +    -- acl-add ls from-lport 2 "udp" allow-related \
    5f9769
    +    -- acl-add ls to-lport 2 "udp" allow-related
    5f9769
    +AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e ls_in_acl -e ls_out_acl | grep 'ct\.' | sort], [0], [dnl
    5f9769
    +  table=4 (ls_out_acl_hint    ), priority=1    , match=(ct.est && ct_label.blocked == 0), action=(reg0[[10]] = 1; next;)
    5f9769
    +  table=4 (ls_out_acl_hint    ), priority=2    , match=(ct.est && ct_label.blocked == 1), action=(reg0[[9]] = 1; next;)
    5f9769
    +  table=4 (ls_out_acl_hint    ), priority=3    , match=(!ct.est), action=(reg0[[9]] = 1; next;)
    5f9769
    +  table=4 (ls_out_acl_hint    ), priority=4    , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
    5f9769
    +  table=4 (ls_out_acl_hint    ), priority=5    , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
    5f9769
    +  table=4 (ls_out_acl_hint    ), priority=6    , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
    5f9769
    +  table=4 (ls_out_acl_hint    ), priority=7    , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
    5f9769
    +  table=5 (ls_out_acl         ), priority=1    , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;)
    5f9769
    +  table=5 (ls_out_acl         ), priority=65535, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;)
    5f9769
    +  table=5 (ls_out_acl         ), priority=65535, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(next;)
    5f9769
    +  table=5 (ls_out_acl         ), priority=65535, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;)
    5f9769
    +  table=6 (ls_in_acl_hint     ), priority=1    , match=(ct.est && ct_label.blocked == 0), action=(reg0[[10]] = 1; next;)
    5f9769
    +  table=6 (ls_in_acl_hint     ), priority=2    , match=(ct.est && ct_label.blocked == 1), action=(reg0[[9]] = 1; next;)
    5f9769
    +  table=6 (ls_in_acl_hint     ), priority=3    , match=(!ct.est), action=(reg0[[9]] = 1; next;)
    5f9769
    +  table=6 (ls_in_acl_hint     ), priority=4    , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
    5f9769
    +  table=6 (ls_in_acl_hint     ), priority=5    , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
    5f9769
    +  table=6 (ls_in_acl_hint     ), priority=6    , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
    5f9769
    +  table=6 (ls_in_acl_hint     ), priority=7    , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
    5f9769
    +  table=7 (ls_in_acl          ), priority=1    , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;)
    5f9769
    +  table=7 (ls_in_acl          ), priority=65535, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;)
    5f9769
    +  table=7 (ls_in_acl          ), priority=65535, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(next;)
    5f9769
    +  table=7 (ls_in_acl          ), priority=65535, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;)
    5f9769
    +])
    5f9769
    +
    5f9769
    +AS_BOX([Check match ct_state with load balancer])
    5f9769
    +check ovn-nbctl --wait=sb \
    5f9769
    +    -- acl-del ls from-lport 2 "udp" \
    5f9769
    +    -- acl-del ls to-lport 2 "udp" \
    5f9769
    +    -- lb-add lb "10.0.0.1" "10.0.0.2" \
    5f9769
    +    -- ls-lb-add ls lb
    5f9769
    +
    5f9769
    +AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e ls_in_acl -e ls_out_acl | grep 'ct\.' | sort], [0], [dnl
    5f9769
    +  table=4 (ls_out_acl_hint    ), priority=1    , match=(ct.est && ct_label.blocked == 0), action=(reg0[[10]] = 1; next;)
    5f9769
    +  table=4 (ls_out_acl_hint    ), priority=2    , match=(ct.est && ct_label.blocked == 1), action=(reg0[[9]] = 1; next;)
    5f9769
    +  table=4 (ls_out_acl_hint    ), priority=3    , match=(!ct.est), action=(reg0[[9]] = 1; next;)
    5f9769
    +  table=4 (ls_out_acl_hint    ), priority=4    , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
    5f9769
    +  table=4 (ls_out_acl_hint    ), priority=5    , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
    5f9769
    +  table=4 (ls_out_acl_hint    ), priority=6    , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
    5f9769
    +  table=4 (ls_out_acl_hint    ), priority=7    , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
    5f9769
    +  table=5 (ls_out_acl         ), priority=1    , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;)
    5f9769
    +  table=5 (ls_out_acl         ), priority=65535, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;)
    5f9769
    +  table=5 (ls_out_acl         ), priority=65535, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(next;)
    5f9769
    +  table=5 (ls_out_acl         ), priority=65535, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;)
    5f9769
    +  table=6 (ls_in_acl_hint     ), priority=1    , match=(ct.est && ct_label.blocked == 0), action=(reg0[[10]] = 1; next;)
    5f9769
    +  table=6 (ls_in_acl_hint     ), priority=2    , match=(ct.est && ct_label.blocked == 1), action=(reg0[[9]] = 1; next;)
    5f9769
    +  table=6 (ls_in_acl_hint     ), priority=3    , match=(!ct.est), action=(reg0[[9]] = 1; next;)
    5f9769
    +  table=6 (ls_in_acl_hint     ), priority=4    , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;)
    5f9769
    +  table=6 (ls_in_acl_hint     ), priority=5    , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;)
    5f9769
    +  table=6 (ls_in_acl_hint     ), priority=6    , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
    5f9769
    +  table=6 (ls_in_acl_hint     ), priority=7    , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;)
    5f9769
    +  table=7 (ls_in_acl          ), priority=1    , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;)
    5f9769
    +  table=7 (ls_in_acl          ), priority=65535, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;)
    5f9769
    +  table=7 (ls_in_acl          ), priority=65535, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(next;)
    5f9769
    +  table=7 (ls_in_acl          ), priority=65535, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;)
    5f9769
    +])
    5f9769
    +
    5f9769
    +AT_CLEANUP
    5f9769
    +
    5f9769
     AT_SETUP([datapath requested-tnl-key])
    5f9769
     AT_KEYWORDS([requested tnl tunnel key keys])
    5f9769
     ovn_start
    5f9769
    -- 
    5f9769
    2.29.2
    5f9769