diff --git a/ovn/controller/lflow.c b/ovn/controller/lflow.c
index dc69047..5713c46 100644
--- a/ovn/controller/lflow.c
+++ b/ovn/controller/lflow.c
@@ -38,14 +38,10 @@ VLOG_DEFINE_THIS_MODULE(lflow);
 /* Contains "struct expr_symbol"s for fields supported by OVN lflows. */
 static struct shash symtab;
 
-/* Contains an internal expr datastructure that represents an address set. */
-static struct shash expr_address_sets;
-
 void
 lflow_init(void)
 {
     ovn_init_symtab(&symtab);
-    shash_init(&expr_address_sets);
 }
 
 /* Details of an address set currently in address_sets. We keep a cached
@@ -56,54 +52,6 @@ struct address_set {
     size_t n_addresses;
 };
 
-/* struct address_set instances for address sets currently in the symtab,
- * hashed on the address set name. */
-static struct shash local_address_sets = SHASH_INITIALIZER(&local_address_sets);
-
-static int
-addr_cmp(const void *p1, const void *p2)
-{
-    const char *s1 = p1;
-    const char *s2 = p2;
-    return strcmp(s1, s2);
-}
-
-/* Return true if the address sets match, false otherwise. */
-static bool
-address_sets_match(const struct address_set *addr_set,
-                   const struct sbrec_address_set *addr_set_rec)
-{
-    char **addrs1;
-    char **addrs2;
-
-    if (addr_set->n_addresses != addr_set_rec->n_addresses) {
-        return false;
-    }
-    size_t n_addresses = addr_set->n_addresses;
-
-    addrs1 = xmemdup(addr_set->addresses,
-                     n_addresses * sizeof addr_set->addresses[0]);
-    addrs2 = xmemdup(addr_set_rec->addresses,
-                     n_addresses * sizeof addr_set_rec->addresses[0]);
-
-    qsort(addrs1, n_addresses, sizeof *addrs1, addr_cmp);
-    qsort(addrs2, n_addresses, sizeof *addrs2, addr_cmp);
-
-    bool res = true;
-    size_t i;
-    for (i = 0; i <  n_addresses; i++) {
-        if (strcmp(addrs1[i], addrs2[i])) {
-            res = false;
-            break;
-        }
-    }
-
-    free(addrs1);
-    free(addrs2);
-
-    return res;
-}
-
 static void
 address_set_destroy(struct address_set *addr_set)
 {
@@ -118,79 +66,34 @@ address_set_destroy(struct address_set *addr_set)
 }
 
 static void
-update_address_sets(struct controller_ctx *ctx)
-{
-    /* Remember the names of all address sets currently in expr_address_sets
-     * so we can detect address sets that have been deleted. */
-    struct sset cur_addr_set_names = SSET_INITIALIZER(&cur_addr_set_names);
-
-    struct shash_node *node;
-    SHASH_FOR_EACH (node, &local_address_sets) {
-        sset_add(&cur_addr_set_names, node->name);
-    }
+update_address_sets(struct controller_ctx *ctx,
+                    struct shash *local_address_sets_p,
+                    struct shash *expr_address_sets_p)
 
+{
     /* Iterate address sets in the southbound database.  Create and update the
      * corresponding symtab entries as necessary. */
     const struct sbrec_address_set *addr_set_rec;
     SBREC_ADDRESS_SET_FOR_EACH (addr_set_rec, ctx->ovnsb_idl) {
-        struct address_set *addr_set =
-            shash_find_data(&local_address_sets, addr_set_rec->name);
-
-        bool create_set = false;
-        if (addr_set) {
-            /* This address set has already been added.  We must determine
-             * if the symtab entry needs to be updated due to a change. */
-            sset_find_and_delete(&cur_addr_set_names, addr_set_rec->name);
-            if (!address_sets_match(addr_set, addr_set_rec)) {
-                shash_find_and_delete(&local_address_sets, addr_set_rec->name);
-                expr_macros_remove(&expr_address_sets, addr_set_rec->name);
-                address_set_destroy(addr_set);
-                addr_set = NULL;
-                create_set = true;
+        /* Create a symbol that resolves to the full set of addresses.
+         * Store it in address_sets to remember that we created this
+         * symbol. */
+        struct address_set *addr_set = xzalloc(sizeof *addr_set);
+        addr_set->n_addresses = addr_set_rec->n_addresses;
+        if (addr_set_rec->n_addresses) {
+            addr_set->addresses = xmalloc(addr_set_rec->n_addresses
+                                          * sizeof addr_set->addresses[0]);
+            size_t i;
+            for (i = 0; i < addr_set_rec->n_addresses; i++) {
+                addr_set->addresses[i] = xstrdup(addr_set_rec->addresses[i]);
             }
-        } else {
-            /* This address set is not yet in the symtab, so add it. */
-            create_set = true;
         }
+        shash_add(local_address_sets_p, addr_set_rec->name, addr_set);
 
-        if (create_set) {
-            /* The address set is either new or has changed.  Create a symbol
-             * that resolves to the full set of addresses.  Store it in
-             * address_sets to remember that we created this symbol. */
-            addr_set = xzalloc(sizeof *addr_set);
-            addr_set->n_addresses = addr_set_rec->n_addresses;
-            if (addr_set_rec->n_addresses) {
-                addr_set->addresses = xmalloc(addr_set_rec->n_addresses
-                                              * sizeof addr_set->addresses[0]);
-                size_t i;
-                for (i = 0; i < addr_set_rec->n_addresses; i++) {
-                    addr_set->addresses[i] = xstrdup(addr_set_rec->addresses[i]);
-                }
-            }
-            shash_add(&local_address_sets, addr_set_rec->name, addr_set);
-
-            expr_macros_add(&expr_address_sets, addr_set_rec->name,
-                            (const char * const *) addr_set->addresses,
-                            addr_set->n_addresses);
-        }
-    }
-
-    /* Anything remaining in cur_addr_set_names refers to an address set that
-     * has been deleted from the southbound database.  We should delete
-     * the corresponding symtab entry. */
-    const char *cur_node, *next_node;
-    SSET_FOR_EACH_SAFE (cur_node, next_node, &cur_addr_set_names) {
-        expr_macros_remove(&expr_address_sets, cur_node);
-
-        struct address_set *addr_set
-            = shash_find_and_delete(&local_address_sets, cur_node);
-        address_set_destroy(addr_set);
-
-        struct sset_node *sset_node = SSET_NODE_FROM_NAME(cur_node);
-        sset_delete(&cur_addr_set_names, sset_node);
+        expr_macros_add(expr_address_sets_p, addr_set_rec->name,
+                        (const char * const *) addr_set->addresses,
+                        addr_set->n_addresses);
     }
-
-    sset_destroy(&cur_addr_set_names);
 }
 
 struct lookup_port_aux {
@@ -209,7 +112,8 @@ static void consider_logical_flow(const struct lport_index *lports,
                                   struct hmap *dhcp_opts_p,
                                   struct hmap *dhcpv6_opts_p,
                                   uint32_t *conj_id_ofs_p,
-                                  struct hmap *flow_table);
+                                  struct hmap *flow_table,
+                                  struct shash *expr_address_sets_p);
 
 static bool
 lookup_port_cb(const void *aux_, const char *port_name, unsigned int *portp)
@@ -248,7 +152,8 @@ add_logical_flows(struct controller_ctx *ctx, const struct lport_index *lports,
                   const struct hmap *patched_datapaths,
                   struct group_table *group_table,
                   const struct simap *ct_zones,
-                  struct hmap *flow_table)
+                  struct hmap *flow_table,
+                  struct shash *expr_address_sets_p)
 {
     uint32_t conj_id_ofs = 1;
     const struct sbrec_logical_flow *lflow;
@@ -272,7 +177,7 @@ add_logical_flows(struct controller_ctx *ctx, const struct lport_index *lports,
         consider_logical_flow(lports, mcgroups, lflow, local_datapaths,
                               patched_datapaths, group_table, ct_zones,
                               &dhcp_opts, &dhcpv6_opts, &conj_id_ofs,
-                              flow_table);
+                              flow_table, expr_address_sets_p);
     }
 
     dhcp_opts_destroy(&dhcp_opts);
@@ -290,7 +195,8 @@ consider_logical_flow(const struct lport_index *lports,
                       struct hmap *dhcp_opts_p,
                       struct hmap *dhcpv6_opts_p,
                       uint32_t *conj_id_ofs_p,
-                      struct hmap *flow_table)
+                      struct hmap *flow_table,
+                      struct shash *expr_address_sets_p)
 {
     /* Determine translation of logical table IDs to physical table IDs. */
     bool ingress = !strcmp(lflow->pipeline, "ingress");
@@ -399,7 +305,7 @@ consider_logical_flow(const struct lport_index *lports,
     struct expr *expr;
 
     expr = expr_parse_string(lflow->match, &symtab,
-                             &expr_address_sets, &error);
+                             expr_address_sets_p, &error);
     if (!error) {
         if (prereqs) {
             expr = expr_combine(EXPR_T_AND, expr, prereqs);
@@ -555,10 +461,22 @@ lflow_run(struct controller_ctx *ctx, const struct lport_index *lports,
           const struct simap *ct_zones,
           struct hmap *flow_table)
 {
-    update_address_sets(ctx);
+    struct shash local_address_sets = SHASH_INITIALIZER(&local_address_sets);
+    struct shash expr_address_sets = SHASH_INITIALIZER(&expr_address_sets);
+
+    update_address_sets(ctx, &local_address_sets, &expr_address_sets);
     add_logical_flows(ctx, lports, mcgroups, local_datapaths,
-                      patched_datapaths, group_table, ct_zones, flow_table);
+                      patched_datapaths, group_table, ct_zones, flow_table,
+                      &expr_address_sets);
     add_neighbor_flows(ctx, lports, flow_table);
+
+    struct shash_node *node;
+    SHASH_FOR_EACH (node, &local_address_sets) {
+        address_set_destroy(node->data);
+    }
+    shash_destroy(&local_address_sets);
+    expr_macros_destroy(&expr_address_sets);
+    shash_destroy(&expr_address_sets);
 }
 
 void
@@ -566,6 +484,4 @@ lflow_destroy(void)
 {
     expr_symtab_destroy(&symtab);
     shash_destroy(&symtab);
-    expr_macros_destroy(&expr_address_sets);
-    shash_destroy(&expr_address_sets);
 }
diff --git a/ovn/lib/expr.c b/ovn/lib/expr.c
index e0a14ec..4ae6b0b 100644
--- a/ovn/lib/expr.c
+++ b/ovn/lib/expr.c
@@ -964,6 +964,7 @@ expr_macros_destroy(struct shash *macros)
 
         shash_delete(macros, node);
         expr_constant_set_destroy(cs);
+        free(cs);
     }
 }
 
