773311
From 3cdc2f9cdd9b4911a236c731dfa76535e3af38e6 Mon Sep 17 00:00:00 2001
773311
From: Dumitru Ceara <dceara@redhat.com>
773311
Date: Mon, 29 Jun 2020 17:24:41 +0200
773311
Subject: [PATCH] Split SB Port_Group per datapath.
773311
773311
In order to avoid ovn-controller reinstalling all logical flows that
773311
refer a port_group when some ports are added/removed from the port group
773311
we now change the way ovn-northd populates the Southbound DB Port_Group
773311
table.
773311
773311
Instead of copying NB.Port_Group.name to SB.Port_Group.name we now
773311
create one SB.Port_Group record for every datapath that has ports
773311
referenced by the NB.Port_Group.ports field. In order to maintain the
773311
SB.Port_Group.name uniqueness constraint, ovn-northd populates the field
773311
with the value: <SB.Logical_Datapath.tunnel_key>_<NB.Port_Group.name>.
773311
773311
In specific scenarios we see significant improvements in time to
773311
install/remove all logical flows to/from OVS. One such scenario, in the
773311
BZ referenced below has:
773311
773311
$ ovn-nbctl acl-list pg
773311
  from-lport  1001 (inport == @pg && ip) drop
773311
    to-lport  1001 (outport == @pg && ip) drop
773311
773311
Then, incrementally, creates new logical ports on different logical
773311
switches, binds them to OVS interfaces and adds them to the port_group.
773311
773311
Measuring the total time to perform the above steps 500 times (for 500
773311
new ports attached to 100 switches, 5 per switch) on a test setup
773311
we observe an improvement of 50% in time it takes to install all
773311
openflow rules when port_groups are split in the SB database.
773311
773311
Suggested-by: Numan Siddique <numans@ovn.org>
773311
Reported-by: Venkata Anil <anilvenkata@redhat.com>
773311
Reported-at: https://bugzilla.redhat.com/1818128
773311
Signed-off-by: Dumitru Ceara <dceara@redhat.com>
773311
Acked-by: Numan Siddique <numans@ovn.org>
773311
Signed-off-by: Mark Michelson <mmichels@redhat.com>
773311
773311
Conflicts:
773311
	TODO.rst
773311
	lib/ovn-util.h
773311
773311
Change-Id: Ibb8ffc5dbf4deb33a46e94b3f7b57c248d669073
773311
---
773311
 TODO.rst              |  8 ++++++
773311
 controller/lflow.c    |  4 ++-
773311
 include/ovn/expr.h    |  4 ++-
773311
 lib/actions.c         |  2 +-
773311
 lib/expr.c            | 48 ++++++++++++++++++++++++-------
773311
 lib/ovn-util.h        |  7 +++++
773311
 northd/ovn-northd.c   | 79 ++++++++++++++++++++++++++++++++++-----------------
773311
 tests/ovn-northd.at   | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++
773311
 tests/test-ovn.c      | 10 +++----
773311
 utilities/ovn-trace.c |  3 +-
773311
 10 files changed, 198 insertions(+), 46 deletions(-)
773311
773311
diff --git a/TODO.rst b/TODO.rst
773311
index 809d1c9..cfd33be 100644
773311
--- a/TODO.rst
773311
+++ b/TODO.rst
773311
@@ -149,3 +149,11 @@ OVN To-do List
773311
 * OVN Interconnection
773311
 
773311
   * Packaging for RHEL, Debian, etc.
773311
+
773311
+* ovn-controller: Remove backwards compatibility for Southbound DB Port_Group
773311
+  names in expr.c a few releases after the 20.09 version. Right now
773311
+  ovn-controller maintains backwards compatibility when connecting to a
773311
+  SB database that doesn't store Port_Group.name as
773311
+  <Logical_Datapath.tunnel_key_NB-Port_Group.name>. This causes an additional
773311
+  hashtable lookup in parse_port_group() which can be avoided when we are sure
773311
+  that the Southbound DB uses the new format.
773311
diff --git a/controller/lflow.c b/controller/lflow.c
773311
index 01214a3..0e57327 100644
773311
--- a/controller/lflow.c
773311
+++ b/controller/lflow.c
773311
@@ -552,7 +552,9 @@ consider_logical_flow(const struct sbrec_logical_flow *lflow,
773311
     struct sset port_groups_ref = SSET_INITIALIZER(&port_groups_ref);
773311
     expr = expr_parse_string(lflow->match, &symtab, l_ctx_in->addr_sets,
773311
                              l_ctx_in->port_groups,
773311
-                             &addr_sets_ref, &port_groups_ref, &error);
773311
+                             &addr_sets_ref, &port_groups_ref,
773311
+                             lflow->logical_datapath->tunnel_key,
773311
+                             &error);
773311
     const char *addr_set_name;
773311
     SSET_FOR_EACH (addr_set_name, &addr_sets_ref) {
773311
         lflow_resource_add(l_ctx_out->lfrr, REF_TYPE_ADDRSET, addr_set_name,
773311
diff --git a/include/ovn/expr.h b/include/ovn/expr.h
773311
index 21bf51c..9838251 100644
773311
--- a/include/ovn/expr.h
773311
+++ b/include/ovn/expr.h
773311
@@ -391,12 +391,14 @@ struct expr *expr_parse(struct lexer *, const struct shash *symtab,
773311
                         const struct shash *addr_sets,
773311
                         const struct shash *port_groups,
773311
                         struct sset *addr_sets_ref,
773311
-                        struct sset *port_groups_ref);
773311
+                        struct sset *port_groups_ref,
773311
+                        int64_t dp_id);
773311
 struct expr *expr_parse_string(const char *, const struct shash *symtab,
773311
                                const struct shash *addr_sets,
773311
                                const struct shash *port_groups,
773311
                                struct sset *addr_sets_ref,
773311
                                struct sset *port_groups_ref,
773311
+                               int64_t dp_id,
773311
                                char **errorp);
773311
 
773311
 struct expr *expr_clone(struct expr *);
773311
diff --git a/lib/actions.c b/lib/actions.c
773311
index 3181126..d107871 100644
773311
--- a/lib/actions.c
773311
+++ b/lib/actions.c
773311
@@ -242,7 +242,7 @@ add_prerequisite(struct action_context *ctx, const char *prerequisite)
773311
     char *error;
773311
 
773311
     expr = expr_parse_string(prerequisite, ctx->pp->symtab, NULL, NULL,
773311
-                             NULL, NULL, &error);
773311
+                             NULL, NULL, 0, &error);
773311
     ovs_assert(!error);
773311
     ctx->prereqs = expr_combine(EXPR_T_AND, ctx->prereqs, expr);
773311
 }
773311
diff --git a/lib/expr.c b/lib/expr.c
773311
index 078d178..497b2ac 100644
773311
--- a/lib/expr.c
773311
+++ b/lib/expr.c
773311
@@ -29,6 +29,7 @@
773311
 #include "simap.h"
773311
 #include "sset.h"
773311
 #include "util.h"
773311
+#include "ovn-util.h"
773311
 
773311
 VLOG_DEFINE_THIS_MODULE(expr);
773311
 
773311
@@ -482,6 +483,10 @@ struct expr_context {
773311
     const struct shash *port_groups; /* Port group table. */
773311
     struct sset *addr_sets_ref;      /* The set of address set referenced. */
773311
     struct sset *port_groups_ref;    /* The set of port groups referenced. */
773311
+    int64_t dp_id;                   /* The tunnel_key of the datapath for
773311
+                                        which we're parsing the current
773311
+                                        expression. */
773311
+
773311
     bool not;                    /* True inside odd number of NOT operators. */
773311
     unsigned int paren_depth;    /* Depth of nested parentheses. */
773311
 };
773311
@@ -783,14 +788,32 @@ static bool
773311
 parse_port_group(struct expr_context *ctx, struct expr_constant_set *cs,
773311
                  size_t *allocated_values)
773311
 {
773311
+    struct ds sb_name = DS_EMPTY_INITIALIZER;
773311
+
773311
+    get_sb_port_group_name(ctx->lexer->token.s, ctx->dp_id, &sb_name);
773311
     if (ctx->port_groups_ref) {
773311
-        sset_add(ctx->port_groups_ref, ctx->lexer->token.s);
773311
+        sset_add(ctx->port_groups_ref, ds_cstr(&sb_name));
773311
+    }
773311
+
773311
+    struct expr_constant_set *port_group = NULL;
773311
+
773311
+    if (ctx->port_groups) {
773311
+        port_group = shash_find_data(ctx->port_groups, ds_cstr(&sb_name));
773311
+        if (!port_group) {
773311
+            /* For backwards compatibility (e.g., ovn-controller was
773311
+             * upgraded but ovn-northd not yet), perform an additional
773311
+             * lookup because the NB Port_Group.name might have been
773311
+             * stored as is in the SB Port_Group.name field.
773311
+             */
773311
+            port_group = shash_find_data(ctx->port_groups,
773311
+                                         ctx->lexer->token.s);
773311
+            if (ctx->port_groups_ref) {
773311
+                sset_add(ctx->port_groups_ref, ctx->lexer->token.s);
773311
+            }
773311
+        }
773311
     }
773311
+    ds_destroy(&sb_name);
773311
 
773311
-    struct expr_constant_set *port_group
773311
-        = (ctx->port_groups
773311
-           ? shash_find_data(ctx->port_groups, ctx->lexer->token.s)
773311
-           : NULL);
773311
     if (!port_group) {
773311
         lexer_syntax_error(ctx->lexer, "expecting port group name");
773311
         return false;
773311
@@ -1302,14 +1325,16 @@ expr_parse(struct lexer *lexer, const struct shash *symtab,
773311
            const struct shash *addr_sets,
773311
            const struct shash *port_groups,
773311
            struct sset *addr_sets_ref,
773311
-           struct sset *port_groups_ref)
773311
+           struct sset *port_groups_ref,
773311
+           int64_t dp_id)
773311
 {
773311
     struct expr_context ctx = { .lexer = lexer,
773311
                                 .symtab = symtab,
773311
                                 .addr_sets = addr_sets,
773311
                                 .port_groups = port_groups,
773311
                                 .addr_sets_ref = addr_sets_ref,
773311
-                                .port_groups_ref = port_groups_ref };
773311
+                                .port_groups_ref = port_groups_ref,
773311
+                                .dp_id = dp_id };
773311
     return lexer->error ? NULL : expr_parse__(&ctx;;
773311
 }
773311
 
773311
@@ -1325,6 +1350,7 @@ expr_parse_string(const char *s, const struct shash *symtab,
773311
                   const struct shash *port_groups,
773311
                   struct sset *addr_sets_ref,
773311
                   struct sset *port_groups_ref,
773311
+                  int64_t dp_id,
773311
                   char **errorp)
773311
 {
773311
     struct lexer lexer;
773311
@@ -1332,7 +1358,7 @@ expr_parse_string(const char *s, const struct shash *symtab,
773311
     lexer_init(&lexer, s);
773311
     lexer_get(&lexer);
773311
     struct expr *expr = expr_parse(&lexer, symtab, addr_sets, port_groups,
773311
-                                   addr_sets_ref, port_groups_ref);
773311
+                                   addr_sets_ref, port_groups_ref, dp_id);
773311
     lexer_force_end(&lexer);
773311
     *errorp = lexer_steal_error(&lexer);
773311
     if (*errorp) {
773311
@@ -1558,7 +1584,7 @@ expr_get_level(const struct expr *expr)
773311
 static enum expr_level
773311
 expr_parse_level(const char *s, const struct shash *symtab, char **errorp)
773311
 {
773311
-    struct expr *expr = expr_parse_string(s, symtab, NULL, NULL, NULL, NULL,
773311
+    struct expr *expr = expr_parse_string(s, symtab, NULL, NULL, NULL, NULL, 0,
773311
                                           errorp);
773311
     enum expr_level level = expr ? expr_get_level(expr) : EXPR_L_NOMINAL;
773311
     expr_destroy(expr);
773311
@@ -1730,7 +1756,7 @@ parse_and_annotate(const char *s, const struct shash *symtab,
773311
     char *error;
773311
     struct expr *expr;
773311
 
773311
-    expr = expr_parse_string(s, symtab, NULL, NULL, NULL, NULL, &error);
773311
+    expr = expr_parse_string(s, symtab, NULL, NULL, NULL, NULL, 0, &error);
773311
     if (expr) {
773311
         expr = expr_annotate_(expr, symtab, nesting, &error);
773311
     }
773311
@@ -3456,7 +3482,7 @@ expr_parse_microflow(const char *s, const struct shash *symtab,
773311
     lexer_get(&lexer);
773311
 
773311
     struct expr *e = expr_parse(&lexer, symtab, addr_sets, port_groups,
773311
-                                NULL, NULL);
773311
+                                NULL, NULL, 0);
773311
     lexer_force_end(&lexer);
773311
 
773311
     if (e) {
773311
diff --git a/lib/ovn-util.h b/lib/ovn-util.h
773311
index ec5f2cf..9c6d357 100644
773311
--- a/lib/ovn-util.h
773311
+++ b/lib/ovn-util.h
773311
@@ -111,6 +111,13 @@ bool ovn_tnlid_in_use(const struct hmap *set, uint32_t tnlid);
773311
 uint32_t ovn_allocate_tnlid(struct hmap *set, const char *name, uint32_t min,
773311
                             uint32_t max, uint32_t *hint);
773311
 
773311
+static inline void
773311
+get_sb_port_group_name(const char *nb_pg_name, int64_t dp_tunnel_key,
773311
+                       struct ds *sb_pg_name)
773311
+{
773311
+    ds_put_format(sb_pg_name, "%"PRId64"_%s", dp_tunnel_key, nb_pg_name);
773311
+}
773311
+
773311
 char *ovn_chassis_redirect_name(const char *port_name);
773311
 void ovn_set_pidfile(const char *name);
773311
 
773311
diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
773311
index fc25031..8a809d0 100644
773311
--- a/northd/ovn-northd.c
773311
+++ b/northd/ovn-northd.c
773311
@@ -4457,7 +4457,11 @@ build_dhcpv6_action(struct ovn_port *op, struct in6_addr *offer_ip,
773311
 struct ovn_port_group_ls {
773311
     struct hmap_node key_node;  /* Index on 'key'. */
773311
     struct uuid key;            /* nb_ls->header_.uuid. */
773311
-    const struct nbrec_logical_switch *nb_ls;
773311
+    struct ovn_datapath *od;
773311
+
773311
+    struct ovn_port **ports; /* Ports in 'od' referrenced by the PG. */
773311
+    size_t n_ports;
773311
+    size_t n_allocated_ports;
773311
 };
773311
 
773311
 struct ovn_port_group {
773311
@@ -4467,14 +4471,14 @@ struct ovn_port_group {
773311
     struct hmap nb_lswitches;   /* NB lswitches related to the port group */
773311
 };
773311
 
773311
-static void
773311
-ovn_port_group_ls_add(struct ovn_port_group *pg,
773311
-                      const struct nbrec_logical_switch *nb_ls)
773311
+static struct ovn_port_group_ls *
773311
+ovn_port_group_ls_add(struct ovn_port_group *pg, struct ovn_datapath *od)
773311
 {
773311
     struct ovn_port_group_ls *pg_ls = xzalloc(sizeof *pg_ls);
773311
-    pg_ls->key = nb_ls->header_.uuid;
773311
-    pg_ls->nb_ls = nb_ls;
773311
+    pg_ls->key = od->nbs->header_.uuid;
773311
+    pg_ls->od = od;
773311
     hmap_insert(&pg->nb_lswitches, &pg_ls->key_node, uuid_hash(&pg_ls->key));
773311
+    return pg_ls;
773311
 }
773311
 
773311
 static struct ovn_port_group_ls *
773311
@@ -4491,6 +4495,18 @@ ovn_port_group_ls_find(struct ovn_port_group *pg, const struct uuid *ls_uuid)
773311
     return NULL;
773311
 }
773311
 
773311
+static void
773311
+ovn_port_group_ls_add_port(struct ovn_port_group_ls *pg_ls,
773311
+                           struct ovn_port *op)
773311
+{
773311
+    if (pg_ls->n_ports == pg_ls->n_allocated_ports) {
773311
+        pg_ls->ports = x2nrealloc(pg_ls->ports,
773311
+                                  &pg_ls->n_allocated_ports,
773311
+                                  sizeof *pg_ls->ports);
773311
+    }
773311
+    pg_ls->ports[pg_ls->n_ports++] = op;
773311
+}
773311
+
773311
 struct ovn_ls_port_group {
773311
     struct hmap_node key_node;  /* Index on 'key'. */
773311
     struct uuid key;            /* nb_pg->header_.uuid. */
773311
@@ -5250,6 +5266,7 @@ ovn_port_group_destroy(struct hmap *pgs, struct ovn_port_group *pg)
773311
         hmap_remove(pgs, &pg->key_node);
773311
         struct ovn_port_group_ls *ls;
773311
         HMAP_FOR_EACH_POP (ls, key_node, &pg->nb_lswitches) {
773311
+            free(ls->ports);
773311
             free(ls);
773311
         }
773311
         hmap_destroy(&pg->nb_lswitches);
773311
@@ -5287,9 +5304,10 @@ build_port_group_lswitches(struct northd_context *ctx, struct hmap *pgs,
773311
             struct ovn_port_group_ls *pg_ls =
773311
                 ovn_port_group_ls_find(pg, &op->od->nbs->header_.uuid);
773311
             if (!pg_ls) {
773311
-                ovn_port_group_ls_add(pg, op->od->nbs);
773311
+                pg_ls = ovn_port_group_ls_add(pg, op->od);
773311
                 ovn_ls_port_group_add(&op->od->nb_pgs, nb_pg);
773311
             }
773311
+            ovn_port_group_ls_add_port(pg_ls, op);
773311
         }
773311
     }
773311
 }
773311
@@ -10454,7 +10472,7 @@ sync_address_sets(struct northd_context *ctx)
773311
  * contains lport uuids, while in OVN_Southbound we store the lport names.
773311
  */
773311
 static void
773311
-sync_port_groups(struct northd_context *ctx)
773311
+sync_port_groups(struct northd_context *ctx, struct hmap *pgs)
773311
 {
773311
     struct shash sb_port_groups = SHASH_INITIALIZER(&sb_port_groups);
773311
 
773311
@@ -10463,26 +10481,35 @@ sync_port_groups(struct northd_context *ctx)
773311
         shash_add(&sb_port_groups, sb_port_group->name, sb_port_group);
773311
     }
773311
 
773311
-    const struct nbrec_port_group *nb_port_group;
773311
-    NBREC_PORT_GROUP_FOR_EACH (nb_port_group, ctx->ovnnb_idl) {
773311
-        sb_port_group = shash_find_and_delete(&sb_port_groups,
773311
-                                               nb_port_group->name);
773311
-        if (!sb_port_group) {
773311
-            sb_port_group = sbrec_port_group_insert(ctx->ovnsb_txn);
773311
-            sbrec_port_group_set_name(sb_port_group, nb_port_group->name);
773311
-        }
773311
+    struct ds sb_name = DS_EMPTY_INITIALIZER;
773311
 
773311
-        const char **nb_port_names = xcalloc(nb_port_group->n_ports,
773311
-                                             sizeof *nb_port_names);
773311
-        int i;
773311
-        for (i = 0; i < nb_port_group->n_ports; i++) {
773311
-            nb_port_names[i] = nb_port_group->ports[i]->name;
773311
+    struct ovn_port_group *pg;
773311
+    HMAP_FOR_EACH (pg, key_node, pgs) {
773311
+
773311
+        struct ovn_port_group_ls *pg_ls;
773311
+        HMAP_FOR_EACH (pg_ls, key_node, &pg->nb_lswitches) {
773311
+            ds_clear(&sb_name);
773311
+            get_sb_port_group_name(pg->nb_pg->name, pg_ls->od->sb->tunnel_key,
773311
+                                   &sb_name);
773311
+            sb_port_group = shash_find_and_delete(&sb_port_groups,
773311
+                                                  ds_cstr(&sb_name));
773311
+            if (!sb_port_group) {
773311
+                sb_port_group = sbrec_port_group_insert(ctx->ovnsb_txn);
773311
+                sbrec_port_group_set_name(sb_port_group, ds_cstr(&sb_name));
773311
+            }
773311
+
773311
+            const char **nb_port_names = xcalloc(pg_ls->n_ports,
773311
+                                                 sizeof *nb_port_names);
773311
+            for (size_t i = 0; i < pg_ls->n_ports; i++) {
773311
+                nb_port_names[i] = pg_ls->ports[i]->nbsp->name;
773311
+            }
773311
+            sbrec_port_group_set_ports(sb_port_group,
773311
+                                       nb_port_names,
773311
+                                       pg_ls->n_ports);
773311
+            free(nb_port_names);
773311
         }
773311
-        sbrec_port_group_set_ports(sb_port_group,
773311
-                                   nb_port_names,
773311
-                                   nb_port_group->n_ports);
773311
-        free(nb_port_names);
773311
     }
773311
+    ds_destroy(&sb_name);
773311
 
773311
     struct shash_node *node, *next;
773311
     SHASH_FOR_EACH_SAFE (node, next, &sb_port_groups) {
773311
@@ -11081,7 +11108,7 @@ ovnnb_db_run(struct northd_context *ctx,
773311
     ovn_update_ipv6_prefix(ports);
773311
 
773311
     sync_address_sets(ctx);
773311
-    sync_port_groups(ctx);
773311
+    sync_port_groups(ctx, &port_groups);
773311
     sync_meters(ctx);
773311
     sync_dns_entries(ctx, datapaths);
773311
     destroy_ovn_lbs(&lbs;;
773311
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
773311
index e6a8c04..37805d3 100644
773311
--- a/tests/ovn-northd.at
773311
+++ b/tests/ovn-northd.at
773311
@@ -1406,3 +1406,82 @@ AT_CHECK([ovn-nbctl --wait=sb sync], [0])
773311
 AT_CHECK([test 0 = $(ovn-sbctl list Ha_Chassis_Group | wc -l)])
773311
 
773311
 AT_CLEANUP
773311
+
773311
+AT_SETUP([ovn -- check NB/SB Port_Group translation (lsp add/del)])
773311
+ovn_start
773311
+
773311
+ovn-nbctl ls-add ls1
773311
+ovn-nbctl ls-add ls2
773311
+ovn-nbctl lsp-add ls1 lsp1
773311
+ovn-nbctl lsp-add ls2 lsp2
773311
+ovn-nbct --wait=sb sync
773311
+ls1_key=$(ovn-sbctl --columns tunnel_key --bare list Datapath_Binding ls1)
773311
+ls2_key=$(ovn-sbctl --columns tunnel_key --bare list Datapath_Binding ls2)
773311
+
773311
+# Add an empty port group. This should generate no entry in the SB.
773311
+ovn-nbctl --wait=sb pg-add pg_test
773311
+AT_CHECK([test 0 = $(ovn-sbctl --columns _uuid list Port_Group | grep uuid -c)])
773311
+
773311
+# Add lsp1 to the port group. This should generate an entry in the SB only
773311
+# for ls1.
773311
+ovn-nbctl --wait=sb pg-set-ports pg_test lsp1
773311
+AT_CHECK([test 1 = $(ovn-sbctl --columns _uuid list Port_Group | grep uuid -c)])
773311
+AT_CHECK([ovn-sbctl --columns ports --bare find Port_Group name=${ls1_key}_pg_test], [0], [dnl
773311
+lsp1
773311
+])
773311
+
773311
+# Add lsp2 to the port group. This should generate a new entry in the SB, for
773311
+# ls2.
773311
+ovn-nbctl --wait=sb pg-set-ports pg_test lsp1 lsp2
773311
+AT_CHECK([test 2 = $(ovn-sbctl --columns _uuid list Port_Group | grep uuid -c)])
773311
+AT_CHECK([ovn-sbctl --columns ports --bare find Port_Group name=${ls1_key}_pg_test], [0], [dnl
773311
+lsp1
773311
+])
773311
+AT_CHECK([ovn-sbctl --columns ports --bare find Port_Group name=${ls2_key}_pg_test], [0], [dnl
773311
+lsp2
773311
+])
773311
+
773311
+# Remove lsp1 from the port group. The SB Port_Group for ls1 should be
773311
+# removed.
773311
+ovn-nbctl --wait=sb pg-set-ports pg_test lsp2
773311
+AT_CHECK([test 1 = $(ovn-sbctl --columns _uuid list Port_Group | grep uuid -c)])
773311
+AT_CHECK([ovn-sbctl --columns ports --bare find Port_Group name=${ls2_key}_pg_test], [0], [dnl
773311
+lsp2
773311
+])
773311
+
773311
+# Remove lsp2 from the port group. All SB Port_Groups should be purged.
773311
+ovn-nbctl --wait=sb clear Port_Group pg_test ports
773311
+AT_CHECK([test 0 = $(ovn-sbctl --columns _uuid list Port_Group | grep uuid -c)])
773311
+
773311
+AT_CLEANUP
773311
+
773311
+AT_SETUP([ovn -- check NB/SB Port_Group translation (ls del)])
773311
+ovn_start
773311
+
773311
+ovn-nbctl ls-add ls1
773311
+ovn-nbctl ls-add ls2
773311
+ovn-nbctl lsp-add ls1 lsp1
773311
+ovn-nbctl lsp-add ls2 lsp2
773311
+ovn-nbct --wait=sb sync
773311
+ls1_key=$(ovn-sbctl --columns tunnel_key --bare list Datapath_Binding ls1)
773311
+ls2_key=$(ovn-sbctl --columns tunnel_key --bare list Datapath_Binding ls2)
773311
+
773311
+# Add lsp1 & lsp2 to a port group. This should generate two entries in the
773311
+# SB (one per logical switch).
773311
+ovn-nbctl --wait=sb pg-add pg_test lsp1 lsp2
773311
+AT_CHECK([test 2 = $(ovn-sbctl --columns _uuid list Port_Group | grep uuid -c)])
773311
+AT_CHECK([ovn-sbctl --columns ports --bare find Port_Group name=${ls1_key}_pg_test], [0], [dnl
773311
+lsp1
773311
+])
773311
+AT_CHECK([ovn-sbctl --columns ports --bare find Port_Group name=${ls2_key}_pg_test], [0], [dnl
773311
+lsp2
773311
+])
773311
+
773311
+# Delete logical switch ls1. This should remove the associated SB Port_Group.
773311
+ovn-nbctl --wait=sb ls-del ls1
773311
+AT_CHECK([test 1 = $(ovn-sbctl --columns _uuid list Port_Group | grep uuid -c)])
773311
+AT_CHECK([ovn-sbctl --columns ports --bare find Port_Group name=${ls2_key}_pg_test], [0], [dnl
773311
+lsp2
773311
+])
773311
+
773311
+AT_CLEANUP
773311
diff --git a/tests/test-ovn.c b/tests/test-ovn.c
773311
index 11697eb..9f74c5c 100644
773311
--- a/tests/test-ovn.c
773311
+++ b/tests/test-ovn.c
773311
@@ -235,8 +235,8 @@ create_port_groups(struct shash *port_groups)
773311
     };
773311
     static const char *const pg2[] = { NULL };
773311
 
773311
-    expr_const_sets_add(port_groups, "pg1", pg1, 3, false);
773311
-    expr_const_sets_add(port_groups, "pg_empty", pg2, 0, false);
773311
+    expr_const_sets_add(port_groups, "0_pg1", pg1, 3, false);
773311
+    expr_const_sets_add(port_groups, "0_pg_empty", pg2, 0, false);
773311
 }
773311
 
773311
 static bool
773311
@@ -302,7 +302,7 @@ test_parse_expr__(int steps)
773311
         char *error;
773311
 
773311
         expr = expr_parse_string(ds_cstr(&input), &symtab, &addr_sets,
773311
-                                 &port_groups, NULL, NULL, &error);
773311
+                                 &port_groups, NULL, NULL, 0, &error);
773311
         if (!error && steps > 0) {
773311
             expr = expr_annotate(expr, &symtab, &error);
773311
         }
773311
@@ -428,7 +428,7 @@ test_evaluate_expr(struct ovs_cmdl_context *ctx)
773311
         struct expr *expr;
773311
 
773311
         expr = expr_parse_string(ds_cstr(&input), &symtab, NULL, NULL,
773311
-                                 NULL, NULL, &error);
773311
+                                 NULL, NULL, 0, &error);
773311
         if (!error) {
773311
             expr = expr_annotate(expr, &symtab, &error);
773311
         }
773311
@@ -903,7 +903,7 @@ test_tree_shape_exhaustively(struct expr *expr, struct shash *symtab,
773311
 
773311
             char *error;
773311
             modified = expr_parse_string(ds_cstr(&s), symtab, NULL,
773311
-                                         NULL, NULL, NULL, &error);
773311
+                                         NULL, NULL, NULL, 0, &error);
773311
             if (error) {
773311
                 fprintf(stderr, "%s fails to parse (%s)\n",
773311
                         ds_cstr(&s), error);
773311
diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c
773311
index d7251e7..2666c10 100644
773311
--- a/utilities/ovn-trace.c
773311
+++ b/utilities/ovn-trace.c
773311
@@ -889,7 +889,8 @@ read_flows(void)
773311
         char *error;
773311
         struct expr *match;
773311
         match = expr_parse_string(sblf->match, &symtab, &address_sets,
773311
-                                  &port_groups, NULL, NULL, &error);
773311
+                                  &port_groups, NULL, NULL, dp->tunnel_key,
773311
+                                  &error);
773311
         if (error) {
773311
             VLOG_WARN("%s: parsing expression failed (%s)",
773311
                       sblf->match, error);
773311
-- 
773311
1.8.3.1
773311