5f9769
From d2b69af321ad8064d42aad2fd3d15857334e2d63 Mon Sep 17 00:00:00 2001
5f9769
From: Dumitru Ceara <dceara@redhat.com>
5f9769
Date: Fri, 15 Jan 2021 14:41:19 +0100
5f9769
Subject: [PATCH] northd: Fix ACL fair log meters for Port_Group ACLs.
5f9769
5f9769
Commit 880dca99eaf7 added support for fair meters but didn't cover the
5f9769
case when an ACL is configured on a port group instead of a logical
5f9769
switch.
5f9769
5f9769
Iterate over PG ACLs too when syncing fair meters to the Southbound
5f9769
database.  Due to the fact that a meter might be used for ACLs that are
5f9769
applied on multiple logical datapaths (through port groups) we also need
5f9769
to change the logic of deleting stale SB Meter records.
5f9769
5f9769
Fixes: 880dca99eaf7 ("northd: Enhance the implementation of ACL log meters (pre-ddlog merge).")
5f9769
Reported-by: Dmitry Yusupov <dyusupov@nvidia.com>
5f9769
Signed-off-by: Dumitru Ceara <dceara@redhat.com>
5f9769
Acked-by: Flavio Fernandes <flavio@flaviof.com>
5f9769
Signed-off-by: Numan Siddique <numans@ovn.org>
5f9769
(cherry picked from master commit bf4f75f90c3309dbcfac8e098a2c1ff2d822e77d)
5f9769
5f9769
Change-Id: If6f19df6fe0b84abc2fbb7356bf59c2d5eb496e1
5f9769
---
5f9769
 northd/ovn-northd.c | 61 ++++++++++++++++++++++++++++++++++++++++-------------
5f9769
 tests/ovn-northd.at | 42 ++++++++++++++++++++++++------------
5f9769
 2 files changed, 74 insertions(+), 29 deletions(-)
5f9769
5f9769
diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
5f9769
index fa2bd73..49afc2f 100644
5f9769
--- a/northd/ovn-northd.c
5f9769
+++ b/northd/ovn-northd.c
5f9769
@@ -12250,17 +12250,20 @@ static void
5f9769
 sync_meters_iterate_nb_meter(struct northd_context *ctx,
5f9769
                              const char *meter_name,
5f9769
                              const struct nbrec_meter *nb_meter,
5f9769
-                             struct shash *sb_meters)
5f9769
+                             struct shash *sb_meters,
5f9769
+                             struct sset *used_sb_meters)
5f9769
 {
5f9769
+    const struct sbrec_meter *sb_meter;
5f9769
     bool new_sb_meter = false;
5f9769
 
5f9769
-    const struct sbrec_meter *sb_meter = shash_find_and_delete(sb_meters,
5f9769
-                                                               meter_name);
5f9769
+    sb_meter = shash_find_data(sb_meters, meter_name);
5f9769
     if (!sb_meter) {
5f9769
         sb_meter = sbrec_meter_insert(ctx->ovnsb_txn);
5f9769
         sbrec_meter_set_name(sb_meter, meter_name);
5f9769
+        shash_add(sb_meters, sb_meter->name, sb_meter);
5f9769
         new_sb_meter = true;
5f9769
     }
5f9769
+    sset_add(used_sb_meters, meter_name);
5f9769
 
5f9769
     if (new_sb_meter || bands_need_update(nb_meter, sb_meter)) {
5f9769
         struct sbrec_meter_band **sb_bands;
5f9769
@@ -12282,6 +12285,24 @@ sync_meters_iterate_nb_meter(struct northd_context *ctx,
5f9769
     sbrec_meter_set_unit(sb_meter, nb_meter->unit);
5f9769
 }
5f9769
 
5f9769
+static void
5f9769
+sync_acl_fair_meter(struct northd_context *ctx, struct shash *meter_groups,
5f9769
+                    const struct nbrec_acl *acl, struct shash *sb_meters,
5f9769
+                    struct sset *used_sb_meters)
5f9769
+{
5f9769
+    const struct nbrec_meter *nb_meter =
5f9769
+        fair_meter_lookup_by_name(meter_groups, acl->meter);
5f9769
+
5f9769
+    if (!nb_meter) {
5f9769
+        return;
5f9769
+    }
5f9769
+
5f9769
+    char *meter_name = alloc_acl_log_unique_meter_name(acl);
5f9769
+    sync_meters_iterate_nb_meter(ctx, meter_name, nb_meter, sb_meters,
5f9769
+                                 used_sb_meters);
5f9769
+    free(meter_name);
5f9769
+}
5f9769
+
5f9769
 /* Each entry in the Meter and Meter_Band tables in OVN_Northbound have
5f9769
  * a corresponding entries in the Meter and Meter_Band tables in
5f9769
  * OVN_Southbound. Additionally, ACL logs that use fair meters have
5f9769
@@ -12289,9 +12310,10 @@ sync_meters_iterate_nb_meter(struct northd_context *ctx,
5f9769
  */
5f9769
 static void
5f9769
 sync_meters(struct northd_context *ctx, struct hmap *datapaths,
5f9769
-            struct shash *meter_groups)
5f9769
+            struct shash *meter_groups, struct hmap *port_groups)
5f9769
 {
5f9769
     struct shash sb_meters = SHASH_INITIALIZER(&sb_meters);
5f9769
+    struct sset used_sb_meters = SSET_INITIALIZER(&used_sb_meters);
5f9769
 
5f9769
     const struct sbrec_meter *sb_meter;
5f9769
     SBREC_METER_FOR_EACH (sb_meter, ctx->ovnsb_idl) {
5f9769
@@ -12301,7 +12323,7 @@ sync_meters(struct northd_context *ctx, struct hmap *datapaths,
5f9769
     const struct nbrec_meter *nb_meter;
5f9769
     NBREC_METER_FOR_EACH (nb_meter, ctx->ovnnb_idl) {
5f9769
         sync_meters_iterate_nb_meter(ctx, nb_meter->name, nb_meter,
5f9769
-                                     &sb_meters);
5f9769
+                                     &sb_meters, &used_sb_meters);
5f9769
     }
5f9769
 
5f9769
     /*
5f9769
@@ -12315,19 +12337,28 @@ sync_meters(struct northd_context *ctx, struct hmap *datapaths,
5f9769
             continue;
5f9769
         }
5f9769
         for (size_t i = 0; i < od->nbs->n_acls; i++) {
5f9769
-            struct nbrec_acl *acl = od->nbs->acls[i];
5f9769
-            nb_meter = fair_meter_lookup_by_name(meter_groups, acl->meter);
5f9769
-            if (!nb_meter) {
5f9769
-                continue;
5f9769
+            sync_acl_fair_meter(ctx, meter_groups, od->nbs->acls[i],
5f9769
+                                &sb_meters, &used_sb_meters);
5f9769
+        }
5f9769
+        struct ovn_port_group *pg;
5f9769
+        HMAP_FOR_EACH (pg, key_node, port_groups) {
5f9769
+            if (ovn_port_group_ls_find(pg, &od->nbs->header_.uuid)) {
5f9769
+                for (size_t i = 0; i < pg->nb_pg->n_acls; i++) {
5f9769
+                    sync_acl_fair_meter(ctx, meter_groups, pg->nb_pg->acls[i],
5f9769
+                                        &sb_meters, &used_sb_meters);
5f9769
+                }
5f9769
             }
5f9769
-
5f9769
-            char *meter_name = alloc_acl_log_unique_meter_name(acl);
5f9769
-            sync_meters_iterate_nb_meter(ctx, meter_name, nb_meter,
5f9769
-                                         &sb_meters);
5f9769
-            free(meter_name);
5f9769
         }
5f9769
     }
5f9769
 
5f9769
+    const char *used_meter;
5f9769
+    const char *used_meter_next;
5f9769
+    SSET_FOR_EACH_SAFE (used_meter, used_meter_next, &used_sb_meters) {
5f9769
+        shash_find_and_delete(&sb_meters, used_meter);
5f9769
+        sset_delete(&used_sb_meters, SSET_NODE_FROM_NAME(used_meter));
5f9769
+    }
5f9769
+    sset_destroy(&used_sb_meters);
5f9769
+
5f9769
     struct shash_node *node, *next;
5f9769
     SHASH_FOR_EACH_SAFE (node, next, &sb_meters) {
5f9769
         sbrec_meter_delete(node->data);
5f9769
@@ -12825,7 +12856,7 @@ ovnnb_db_run(struct northd_context *ctx,
5f9769
 
5f9769
     sync_address_sets(ctx);
5f9769
     sync_port_groups(ctx, &port_groups);
5f9769
-    sync_meters(ctx, datapaths, &meter_groups);
5f9769
+    sync_meters(ctx, datapaths, &meter_groups, &port_groups);
5f9769
     sync_dns_entries(ctx, datapaths);
5f9769
 
5f9769
     struct ovn_northd_lb *lb;
5f9769
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
5f9769
index 91eb9a3..df03b6e 100644
5f9769
--- a/tests/ovn-northd.at
5f9769
+++ b/tests/ovn-northd.at
5f9769
@@ -1843,20 +1843,25 @@ AT_KEYWORDS([acl log meter fair])
5f9769
 ovn_start
5f9769
 
5f9769
 check ovn-nbctl ls-add sw0
5f9769
+check ovn-nbctl ls-add sw1
5f9769
 check ovn-nbctl lsp-add sw0 sw0-p1 -- lsp-set-addresses sw0-p1 "50:54:00:00:00:01 10.0.0.11"
5f9769
 check ovn-nbctl lsp-add sw0 sw0-p2 -- lsp-set-addresses sw0-p2 "50:54:00:00:00:02 10.0.0.12"
5f9769
-check ovn-nbctl lsp-add sw0 sw0-p3 -- lsp-set-addresses sw0-p3 "50:54:00:00:00:03 10.0.0.13"
5f9769
+check ovn-nbctl lsp-add sw1 sw1-p3 -- lsp-set-addresses sw1-p3 "50:54:00:00:00:03 10.0.0.13"
5f9769
+check ovn-nbctl pg-add pg0 sw0-p1 sw0-p2 sw1-p3
5f9769
 
5f9769
 check ovn-nbctl meter-add meter_me drop 1 pktps
5f9769
 nb_meter_uuid=$(fetch_column nb:Meter _uuid name=meter_me)
5f9769
 
5f9769
 check ovn-nbctl acl-add sw0 to-lport 1002 'outport == "sw0-p1" && ip4.src == 10.0.0.12' allow
5f9769
 check ovn-nbctl acl-add sw0 to-lport 1002 'outport == "sw0-p1" && ip4.src == 10.0.0.13' allow
5f9769
+check ovn-nbctl acl-add pg0 to-lport 1002 'outport == "pg0" && ip4.src == 10.0.0.11' drop
5f9769
 
5f9769
 acl1=$(ovn-nbctl --bare --column _uuid,match find acl | grep -B1 '10.0.0.12' | head -1)
5f9769
 acl2=$(ovn-nbctl --bare --column _uuid,match find acl | grep -B1 '10.0.0.13' | head -1)
5f9769
+acl3=$(ovn-nbctl --bare --column _uuid,match find acl | grep -B1 '10.0.0.11' | head -1)
5f9769
 check ovn-nbctl set acl $acl1 log=true severity=alert meter=meter_me name=acl_one
5f9769
 check ovn-nbctl set acl $acl2 log=true severity=info  meter=meter_me name=acl_two
5f9769
+check ovn-nbctl set acl $acl3 log=true severity=info  meter=meter_me name=acl_three
5f9769
 check ovn-nbctl --wait=sb sync
5f9769
 
5f9769
 check_row_count nb:meter 1
5f9769
@@ -1865,8 +1870,9 @@ check_column meter_me nb:meter name
5f9769
 check_acl_lflow() {
5f9769
     acl_log_name=$1
5f9769
     meter_name=$2
5f9769
+    ls=$3
5f9769
     # echo checking that logical flow for acl log $acl_log_name has $meter_name
5f9769
-    AT_CHECK([ovn-sbctl lflow-list | grep ls_out_acl | \
5f9769
+    AT_CHECK([ovn-sbctl lflow-list $ls | grep ls_out_acl | \
5f9769
               grep "\"${acl_log_name}\"" | \
5f9769
               grep -c "meter=\"${meter_name}\""], [0], [1
5f9769
 ])
5f9769
@@ -1882,55 +1888,63 @@ check_meter_by_name() {
5f9769
 
5f9769
 # Make sure 'fair' value properly affects the Meters in SB
5f9769
 check_meter_by_name meter_me
5f9769
-check_meter_by_name NOT meter_me__${acl1} meter_me__${acl2}
5f9769
+check_meter_by_name NOT meter_me__${acl1} meter_me__${acl2} meter_me__${acl3}
5f9769
 
5f9769
 check ovn-nbctl --wait=sb set Meter $nb_meter_uuid fair=true
5f9769
-check_meter_by_name meter_me meter_me__${acl1} meter_me__${acl2}
5f9769
+check_meter_by_name meter_me meter_me__${acl1} meter_me__${acl2} meter_me__${acl3}
5f9769
 
5f9769
 check ovn-nbctl --wait=sb set Meter $nb_meter_uuid fair=false
5f9769
 check_meter_by_name meter_me
5f9769
-check_meter_by_name NOT meter_me__${acl1} meter_me__${acl2}
5f9769
+check_meter_by_name NOT meter_me__${acl1} meter_me__${acl2} meter_me__${acl3}
5f9769
 
5f9769
 check ovn-nbctl --wait=sb set Meter $nb_meter_uuid fair=true
5f9769
-check_meter_by_name meter_me meter_me__${acl1} meter_me__${acl2}
5f9769
+check_meter_by_name meter_me meter_me__${acl1} meter_me__${acl2} meter_me__${acl3}
5f9769
 
5f9769
 # Change template meter and make sure that is reflected on acl meters as well
5f9769
 template_band=$(fetch_column nb:meter bands name=meter_me)
5f9769
 check ovn-nbctl --wait=sb set meter_band $template_band rate=123
5f9769
 # Make sure that every Meter_Band has the right rate.  (ovn-northd
5f9769
-# creates 3 identical Meter_Band rows, all identical; ovn-northd-ddlog
5f9769
+# creates 4 identical Meter_Band rows, all identical; ovn-northd-ddlog
5f9769
 # creates just 1.  It doesn't matter, they work just as well.)
5f9769
 n_meter_bands=$(count_rows meter_band)
5f9769
-AT_FAIL_IF([test "$n_meter_bands" != 1 && test "$n_meter_bands" != 3])
5f9769
+AT_FAIL_IF([test "$n_meter_bands" != 1 && test "$n_meter_bands" != 4])
5f9769
 check_row_count meter_band $n_meter_bands rate=123
5f9769
 
5f9769
 # Check meter in logical flows for acl logs
5f9769
-check_acl_lflow acl_one meter_me__${acl1}
5f9769
-check_acl_lflow acl_two meter_me__${acl2}
5f9769
+check_acl_lflow acl_one meter_me__${acl1} sw0
5f9769
+check_acl_lflow acl_two meter_me__${acl2} sw0
5f9769
+check_acl_lflow acl_three meter_me__${acl3} sw0
5f9769
+check_acl_lflow acl_three meter_me__${acl3} sw1
5f9769
 
5f9769
 # Stop using meter for acl1
5f9769
 check ovn-nbctl --wait=sb clear acl $acl1 meter
5f9769
 check_meter_by_name meter_me meter_me__${acl2}
5f9769
 check_meter_by_name NOT meter_me__${acl1}
5f9769
-check_acl_lflow acl_two meter_me__${acl2}
5f9769
+check_acl_lflow acl_two meter_me__${acl2} sw0
5f9769
+check_acl_lflow acl_three meter_me__${acl3} sw0
5f9769
+check_acl_lflow acl_three meter_me__${acl3} sw1
5f9769
 
5f9769
 # Remove template Meter should remove all others as well
5f9769
 check ovn-nbctl --wait=sb meter-del meter_me
5f9769
 check_row_count meter 0
5f9769
 # Check that logical flow remains but uses non-unique meter since fair
5f9769
 # attribute is lost by the removal of the Meter row.
5f9769
-check_acl_lflow acl_two meter_me
5f9769
+check_acl_lflow acl_two meter_me sw0
5f9769
+check_acl_lflow acl_three meter_me sw0
5f9769
+check_acl_lflow acl_three meter_me sw1
5f9769
 
5f9769
 # Re-add template meter and make sure acl2's meter is back in sb
5f9769
 check ovn-nbctl --wait=sb --fair meter-add meter_me drop 1 pktps
5f9769
 check_meter_by_name meter_me meter_me__${acl2}
5f9769
 check_meter_by_name NOT meter_me__${acl1}
5f9769
-check_acl_lflow acl_two meter_me__${acl2}
5f9769
+check_acl_lflow acl_two meter_me__${acl2} sw0
5f9769
+check_acl_lflow acl_three meter_me__${acl3} sw0
5f9769
+check_acl_lflow acl_three meter_me__${acl3} sw1
5f9769
 
5f9769
 # Remove acl2
5f9769
 sw0=$(fetch_column nb:logical_switch _uuid name=sw0)
5f9769
 check ovn-nbctl --wait=sb remove logical_switch $sw0 acls $acl2
5f9769
-check_meter_by_name meter_me
5f9769
+check_meter_by_name meter_me meter_me__${acl3}
5f9769
 check_meter_by_name NOT meter_me__${acl1} meter_me__${acl2}
5f9769
 
5f9769
 AT_CLEANUP
5f9769
-- 
5f9769
1.8.3.1
5f9769