diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c
index 56902ff..8b0cd46 100644
--- a/ovn/controller/ovn-controller.c
+++ b/ovn/controller/ovn-controller.c
@@ -291,13 +291,24 @@ get_chassis_id(const struct ovsdb_idl *ovs_idl)
 /* Iterate address sets in the southbound database.  Create and update the
  * corresponding symtab entries as necessary. */
 static void
-addr_sets_init(struct controller_ctx *ctx, struct shash *addr_sets)
+addr_sets_update(struct controller_ctx *ctx, struct shash *addr_sets,
+                 struct sset *new, struct sset *deleted, struct sset *updated)
 {
     const struct sbrec_address_set *as;
-    SBREC_ADDRESS_SET_FOR_EACH (as, ctx->ovnsb_idl) {
-        expr_const_sets_add(addr_sets, as->name,
-                            (const char *const *) as->addresses,
-                            as->n_addresses, true);
+    SBREC_ADDRESS_SET_FOR_EACH_TRACKED (as, ctx->ovnsb_idl) {
+        if (sbrec_address_set_is_deleted(as)) {
+            expr_const_sets_remove(addr_sets, as->name);
+            sset_add(deleted, as->name);
+        } else {
+            expr_const_sets_add(addr_sets, as->name,
+                                (const char *const *) as->addresses,
+                                as->n_addresses, true);
+            if (sbrec_address_set_is_new(as)) {
+                sset_add(new, as->name);
+            } else {
+                sset_add(updated, as->name);
+            }
+        }
     }
 }
 
@@ -606,6 +617,53 @@ ENGINE_FUNC_SB(gateway_chassis);
 ENGINE_FUNC_OVS(port);
 ENGINE_FUNC_OVS(interface);
 
+struct ed_type_addr_sets {
+    struct shash addr_sets;
+    struct sset new;
+    struct sset deleted;
+    struct sset updated;
+};
+
+static void
+en_addr_sets_init(struct engine_node *node)
+{
+    struct ed_type_addr_sets *as = (struct ed_type_addr_sets *)node->data;
+    shash_init(&as->addr_sets);
+    sset_init(&as->new);
+    sset_init(&as->deleted);
+    sset_init(&as->updated);
+}
+
+static void
+en_addr_sets_cleanup(struct engine_node *node)
+{
+    struct ed_type_addr_sets *as = (struct ed_type_addr_sets *)node->data;
+    expr_const_sets_destroy(&as->addr_sets);
+    shash_destroy(&as->addr_sets);
+    sset_destroy(&as->new);
+    sset_destroy(&as->deleted);
+    sset_destroy(&as->updated);
+}
+
+/* For en_addr_sets, the run function handles changes since there is only
+ * one input */
+static void
+en_addr_sets_run(struct engine_node *node)
+{
+    struct controller_ctx *ctx = (struct controller_ctx *)node->context;
+    struct ed_type_addr_sets *as = (struct ed_type_addr_sets *)node->data;
+
+    sset_clear(&as->new);
+    sset_clear(&as->deleted);
+    sset_clear(&as->updated);
+
+    addr_sets_update(ctx, &as->addr_sets, &as->new,
+                     &as->deleted, &as->updated);
+
+    node->changed = !sset_is_empty(&as->new) || !sset_is_empty(&as->deleted)
+                    || !sset_is_empty(&as->updated);
+}
+
 struct ed_type_runtime_data {
     struct chassis_index chassis_index;
 
@@ -623,7 +681,6 @@ struct ed_type_runtime_data {
      * <datapath-tunnel-key>_<port-tunnel-key> */
     struct sset local_lport_ids;
     struct sset active_tunnels;
-    struct shash addr_sets;
     struct shash port_groups;
 
     /* connection tracking zones. */
@@ -642,7 +699,6 @@ en_runtime_data_init(struct engine_node *node)
     sset_init(&data->local_lports);
     sset_init(&data->local_lport_ids);
     sset_init(&data->active_tunnels);
-    shash_init(&data->addr_sets);
     shash_init(&data->port_groups);
     shash_init(&data->pending_ct_zones);
     simap_init(&data->ct_zones);
@@ -659,8 +715,6 @@ en_runtime_data_cleanup(struct engine_node *node)
     struct ed_type_runtime_data *data =
         (struct ed_type_runtime_data *)node->data;
 
-    expr_const_sets_destroy(&data->addr_sets);
-    shash_destroy(&data->addr_sets);
     expr_const_sets_destroy(&data->port_groups);
     shash_destroy(&data->port_groups);
 
@@ -693,7 +747,6 @@ en_runtime_data_run(struct engine_node *node)
     struct sset *local_lport_ids = &data->local_lport_ids;
     struct sset *active_tunnels = &data->active_tunnels;
     struct chassis_index *chassis_index = &data->chassis_index;
-    struct shash *addr_sets = &data->addr_sets;
     struct shash *port_groups = &data->port_groups;
     unsigned long *ct_zone_bitmap = data->ct_zone_bitmap;
     struct shash *pending_ct_zones = &data->pending_ct_zones;
@@ -715,7 +768,6 @@ en_runtime_data_run(struct engine_node *node)
         sset_destroy(local_lport_ids);
         sset_destroy(active_tunnels);
         chassis_index_destroy(chassis_index);
-        expr_const_sets_destroy(addr_sets);
         expr_const_sets_destroy(port_groups);
         sset_init(local_lports);
         sset_init(local_lport_ids);
@@ -737,7 +789,6 @@ en_runtime_data_run(struct engine_node *node)
                 chassis_index, active_tunnels, local_datapaths,
                 local_lports, local_lport_ids);
 
-    addr_sets_init(ctx, addr_sets);
     port_groups_init(ctx, port_groups);
     update_ct_zones(local_lports, local_datapaths, ct_zones,
                     ct_zone_bitmap, pending_ct_zones);
@@ -815,10 +866,13 @@ en_flow_output_run(struct engine_node *node)
     struct sset *local_lport_ids = &rt_data->local_lport_ids;
     struct sset *active_tunnels = &rt_data->active_tunnels;
     struct chassis_index *chassis_index = &rt_data->chassis_index;
-    struct shash *addr_sets = &rt_data->addr_sets;
     struct shash *port_groups = &rt_data->port_groups;
     struct simap *ct_zones = &rt_data->ct_zones;
 
+    struct ed_type_addr_sets *as_data =
+        (struct ed_type_addr_sets *)engine_get_input("addr_sets", node)->data;
+    struct shash *addr_sets = &as_data->addr_sets;
+
     const struct ovsrec_bridge *br_int = get_br_int(ctx);
 
     const char *chassis_id = get_chassis_id(ctx->ovs_idl);
@@ -873,8 +927,11 @@ flow_output_sb_logical_flow_handler(struct engine_node *node)
     struct sset *local_lport_ids = &data->local_lport_ids;
     struct sset *active_tunnels = &data->active_tunnels;
     struct chassis_index *chassis_index = &data->chassis_index;
-    struct shash *addr_sets = &data->addr_sets;
     struct shash *port_groups = &data->port_groups;
+    struct ed_type_addr_sets *as_data =
+        (struct ed_type_addr_sets *)engine_get_input("addr_sets", node)->data;
+    struct shash *addr_sets = &as_data->addr_sets;
+
     const struct ovsrec_bridge *br_int = get_br_int(ctx);
 
     const char *chassis_id = get_chassis_id(ctx->ovs_idl);
@@ -1068,6 +1125,7 @@ main(int argc, char *argv[])
     };
     struct ed_type_runtime_data ed_runtime_data;
     struct ed_type_flow_output ed_flow_output;
+    struct ed_type_addr_sets ed_addr_sets;
 
     ENGINE_NODE_SB(chassis, "chassis", &ctx);
     ENGINE_NODE_SB(encap, "encap", &ctx);
@@ -1086,8 +1144,13 @@ main(int argc, char *argv[])
     ENGINE_NODE_OVS(port, "ovs_table_port", &ctx);
     ENGINE_NODE_OVS(interface, "ovs_table_interface", &ctx);
 
+    ENGINE_NODE(addr_sets, "addr_sets", &ctx);
     ENGINE_NODE(runtime_data, "runtime_data", &ctx);
     ENGINE_NODE(flow_output, "flow_output", &ctx);
+
+    engine_add_input(&en_addr_sets, &en_sb_address_set, NULL);
+
+    engine_add_input(&en_flow_output, &en_addr_sets, NULL);
     engine_add_input(&en_flow_output, &en_runtime_data, NULL);
 
     engine_add_input(&en_flow_output, &en_ovs_port, NULL);
@@ -1109,7 +1172,6 @@ main(int argc, char *argv[])
     engine_add_input(&en_runtime_data, &en_ovs_interface, NULL);
 
     engine_add_input(&en_runtime_data, &en_sb_chassis, NULL);
-    engine_add_input(&en_runtime_data, &en_sb_address_set, NULL);
     engine_add_input(&en_runtime_data, &en_sb_port_group, NULL);
     engine_add_input(&en_runtime_data, &en_sb_datapath_binding, NULL);
     engine_add_input(&en_runtime_data, &en_sb_port_binding, runtime_data_sb_port_binding_handler);
@@ -1217,7 +1279,7 @@ main(int argc, char *argv[])
             if (br_int && chassis) {
                 char *error = ofctrl_inject_pkt(br_int, pending_pkt.flow_s,
                                                 &ed_runtime_data.port_groups,
-                                                &ed_runtime_data.addr_sets);
+                                                &ed_addr_sets.addr_sets);
                 if (error) {
                     unixctl_command_reply_error(pending_pkt.conn, error);
                     free(error);
