diff --git a/lib/ovn-util.c b/lib/ovn-util.c
index 5dca72714..4f939f460 100644
--- a/lib/ovn-util.c
+++ b/lib/ovn-util.c
@@ -938,3 +938,33 @@ daemon_started_recently(void)
     /* Ensure that at least an amount of time has passed. */
     return time_wall_msec() - startup_ts <= DAEMON_STARTUP_DELAY_MS;
 }
+
+/* Builds a unique address set compatible name ([a-zA-Z_.][a-zA-Z_.0-9]*)
+ * for the router's load balancer VIP address set, combining the logical
+ * router's datapath tunnel key and address family.
+ *
+ * Also prefixes the name with 'prefix'.
+ */
+static char *
+lr_lb_address_set_name_(uint32_t lr_tunnel_key, const char *prefix,
+                        int addr_family)
+{
+    return xasprintf("%s_rtr_lb_%"PRIu32"_ip%s", prefix, lr_tunnel_key,
+                     addr_family == AF_INET ? "4" : "6");
+}
+
+/* Builds the router's load balancer VIP address set name. */
+char *
+lr_lb_address_set_name(uint32_t lr_tunnel_key, int addr_family)
+{
+    return lr_lb_address_set_name_(lr_tunnel_key, "", addr_family);
+}
+
+/* Builds a string that refers to the the router's load balancer VIP address
+ * set name, that is: $<address_set_name>.
+ */
+char *
+lr_lb_address_set_ref(uint32_t lr_tunnel_key, int addr_family)
+{
+    return lr_lb_address_set_name_(lr_tunnel_key, "$", addr_family);
+}
diff --git a/lib/ovn-util.h b/lib/ovn-util.h
index a1f1cf0ad..809ff1d36 100644
--- a/lib/ovn-util.h
+++ b/lib/ovn-util.h
@@ -315,4 +315,7 @@ void daemon_started_recently_ignore(void);
 bool daemon_started_recently(void);
 int64_t daemon_startup_ts(void);
 
+char *lr_lb_address_set_name(uint32_t lr_tunnel_key, int addr_family);
+char *lr_lb_address_set_ref(uint32_t lr_tunnel_key, int addr_family);
+
 #endif /* OVN_UTIL_H */
diff --git a/northd/automake.mk b/northd/automake.mk
index 81582867d..138b7b32e 100644
--- a/northd/automake.mk
+++ b/northd/automake.mk
@@ -10,6 +10,10 @@ northd_ovn_northd_SOURCES = \
 	northd/en-northd.h \
 	northd/en-lflow.c \
 	northd/en-lflow.h \
+	northd/en-northd-output.c \
+	northd/en-northd-output.h \
+	northd/en-sb-sync.c \
+	northd/en-sb-sync.h \
 	northd/inc-proc-northd.c \
 	northd/inc-proc-northd.h \
 	northd/ipam.c \
diff --git a/northd/en-northd-output.c b/northd/en-northd-output.c
new file mode 100644
index 000000000..0033d371e
--- /dev/null
+++ b/northd/en-northd-output.c
@@ -0,0 +1,57 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+
+#include <getopt.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "openvswitch/util.h"
+
+#include "en-northd-output.h"
+#include "lib/inc-proc-eng.h"
+
+void *
+en_northd_output_init(struct engine_node *node OVS_UNUSED,
+                      struct engine_arg *arg OVS_UNUSED)
+{
+    return NULL;
+}
+
+void
+en_northd_output_run(struct engine_node *node, void *data OVS_UNUSED)
+{
+    engine_set_node_state(node, EN_UPDATED);
+}
+
+void
+en_northd_output_cleanup(void *data OVS_UNUSED)
+{
+
+}
+
+bool
+northd_output_sb_sync_handler(struct engine_node *node, void *data OVS_UNUSED)
+{
+    engine_set_node_state(node, EN_UPDATED);
+    return true;
+}
+
+bool
+northd_output_lflow_handler(struct engine_node *node, void *data OVS_UNUSED)
+{
+    engine_set_node_state(node, EN_UPDATED);
+    return true;
+}
diff --git a/northd/en-northd-output.h b/northd/en-northd-output.h
new file mode 100644
index 000000000..1258ead94
--- /dev/null
+++ b/northd/en-northd-output.h
@@ -0,0 +1,17 @@
+#ifndef EN_NORTHD_OUTPUT_H
+#define EN_NORTHD_OUTPUT_H 1
+
+#include "lib/inc-proc-eng.h"
+
+void *en_northd_output_init(struct engine_node *node OVS_UNUSED,
+                            struct engine_arg *arg OVS_UNUSED);
+void en_northd_output_run(struct engine_node *node OVS_UNUSED,
+                          void *data OVS_UNUSED);
+
+void en_northd_output_cleanup(void *data);
+bool northd_output_sb_sync_handler(struct engine_node *node,
+                                   void *data OVS_UNUSED);
+bool northd_output_lflow_handler(struct engine_node *node,
+                                 void *data OVS_UNUSED);
+
+#endif
diff --git a/northd/en-sb-sync.c b/northd/en-sb-sync.c
new file mode 100644
index 000000000..c3ba315df
--- /dev/null
+++ b/northd/en-sb-sync.c
@@ -0,0 +1,230 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+
+#include <getopt.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "lib/svec.h"
+#include "openvswitch/util.h"
+
+#include "en-sb-sync.h"
+#include "lib/inc-proc-eng.h"
+#include "lib/lb.h"
+#include "lib/ovn-nb-idl.h"
+#include "lib/ovn-sb-idl.h"
+#include "lib/ovn-util.h"
+#include "northd.h"
+
+#include "openvswitch/vlog.h"
+
+VLOG_DEFINE_THIS_MODULE(en_sb_sync);
+
+static void sync_address_set(struct ovsdb_idl_txn *ovnsb_txn, const char *name,
+                             const char **addrs, size_t n_addrs,
+                             struct shash *sb_address_sets);
+static void sync_address_sets(const struct nbrec_address_set_table *,
+                              const struct nbrec_port_group_table *,
+                              const struct sbrec_address_set_table *,
+                              struct ovsdb_idl_txn *ovnsb_txn,
+                              struct hmap *datapaths);
+
+void *
+en_sb_sync_init(struct engine_node *node OVS_UNUSED,
+                struct engine_arg *arg OVS_UNUSED)
+{
+    return NULL;
+}
+
+void
+en_sb_sync_run(struct engine_node *node, void *data OVS_UNUSED)
+{
+    engine_set_node_state(node, EN_UPDATED);
+}
+
+void
+en_sb_sync_cleanup(void *data OVS_UNUSED)
+{
+
+}
+
+void *
+en_address_set_sync_init(struct engine_node *node OVS_UNUSED,
+                     struct engine_arg *arg OVS_UNUSED)
+{
+    return NULL;
+}
+
+void
+en_address_set_sync_run(struct engine_node *node, void *data OVS_UNUSED)
+{
+    const struct nbrec_address_set_table *nb_address_set_table =
+        EN_OVSDB_GET(engine_get_input("NB_address_set", node));
+    const struct nbrec_port_group_table *nb_port_group_table =
+        EN_OVSDB_GET(engine_get_input("NB_port_group", node));
+    const struct sbrec_address_set_table *sb_address_set_table =
+        EN_OVSDB_GET(engine_get_input("SB_address_set", node));
+
+    const struct engine_context *eng_ctx = engine_get_context();
+    struct northd_data *northd_data = engine_get_input_data("northd", node);
+
+    sync_address_sets(nb_address_set_table, nb_port_group_table,
+                      sb_address_set_table, eng_ctx->ovnsb_idl_txn,
+                      &northd_data->datapaths);
+
+    engine_set_node_state(node, EN_UPDATED);
+}
+
+void
+en_address_set_sync_cleanup(void *data OVS_UNUSED)
+{
+
+}
+
+/* static functions. */
+static void
+sync_address_set(struct ovsdb_idl_txn *ovnsb_txn, const char *name,
+                 const char **addrs, size_t n_addrs,
+                 struct shash *sb_address_sets)
+{
+    const struct sbrec_address_set *sb_address_set;
+    sb_address_set = shash_find_and_delete(sb_address_sets,
+                                           name);
+    if (!sb_address_set) {
+        sb_address_set = sbrec_address_set_insert(ovnsb_txn);
+        sbrec_address_set_set_name(sb_address_set, name);
+    }
+
+    sbrec_address_set_set_addresses(sb_address_set,
+                                    addrs, n_addrs);
+}
+
+/* OVN_Southbound Address_Set table contains same records as in north
+ * bound, plus the records generated from Port_Group table in north bound.
+ *
+ * There are 2 records generated from each port group, one for IPv4, and
+ * one for IPv6, named in the format: <port group name>_ip4 and
+ * <port group name>_ip6 respectively. MAC addresses are ignored.
+ *
+ * We always update OVN_Southbound to match the Address_Set and Port_Group
+ * in OVN_Northbound, so that the address sets used in Logical_Flows in
+ * OVN_Southbound is checked against the proper set.*/
+static void
+sync_address_sets(
+    const struct nbrec_address_set_table *nb_address_set_table,
+    const struct nbrec_port_group_table *nb_port_group_table,
+    const struct sbrec_address_set_table *sb_address_set_table,
+    struct ovsdb_idl_txn *ovnsb_txn, struct hmap *datapaths)
+{
+    struct shash sb_address_sets = SHASH_INITIALIZER(&sb_address_sets);
+
+    const struct sbrec_address_set *sb_address_set;
+    SBREC_ADDRESS_SET_TABLE_FOR_EACH (sb_address_set,
+                                      sb_address_set_table) {
+        shash_add(&sb_address_sets, sb_address_set->name, sb_address_set);
+    }
+
+    /* Service monitor MAC. */
+    const char *svc_monitor_macp = northd_get_svc_monitor_mac();
+    sync_address_set(ovnsb_txn, "svc_monitor_mac", &svc_monitor_macp, 1,
+                     &sb_address_sets);
+
+    /* sync port group generated address sets first */
+    const struct nbrec_port_group *nb_port_group;
+    NBREC_PORT_GROUP_TABLE_FOR_EACH (nb_port_group,
+                                     nb_port_group_table) {
+        struct svec ipv4_addrs = SVEC_EMPTY_INITIALIZER;
+        struct svec ipv6_addrs = SVEC_EMPTY_INITIALIZER;
+        for (size_t i = 0; i < nb_port_group->n_ports; i++) {
+            for (size_t j = 0; j < nb_port_group->ports[i]->n_addresses; j++) {
+                const char *addrs = nb_port_group->ports[i]->addresses[j];
+                if (!is_dynamic_lsp_address(addrs)) {
+                    split_addresses(addrs, &ipv4_addrs, &ipv6_addrs);
+                }
+            }
+            if (nb_port_group->ports[i]->dynamic_addresses) {
+                split_addresses(nb_port_group->ports[i]->dynamic_addresses,
+                                &ipv4_addrs, &ipv6_addrs);
+            }
+        }
+        char *ipv4_addrs_name = xasprintf("%s_ip4", nb_port_group->name);
+        char *ipv6_addrs_name = xasprintf("%s_ip6", nb_port_group->name);
+        sync_address_set(ovnsb_txn, ipv4_addrs_name,
+                         /* "char **" is not compatible with "const char **" */
+                         (const char **) ipv4_addrs.names,
+                         ipv4_addrs.n, &sb_address_sets);
+        sync_address_set(ovnsb_txn, ipv6_addrs_name,
+                         /* "char **" is not compatible with "const char **" */
+                         (const char **) ipv6_addrs.names,
+                         ipv6_addrs.n, &sb_address_sets);
+        free(ipv4_addrs_name);
+        free(ipv6_addrs_name);
+        svec_destroy(&ipv4_addrs);
+        svec_destroy(&ipv6_addrs);
+    }
+
+    /* Sync router load balancer VIP generated address sets. */
+    struct ovn_datapath *od;
+    HMAP_FOR_EACH (od, key_node, datapaths) {
+        if (!od->nbr) {
+            continue;
+        }
+
+        if (sset_count(&od->lb_ips->ips_v4_reachable)) {
+            char *ipv4_addrs_name = lr_lb_address_set_name(od->tunnel_key,
+                                                           AF_INET);
+            const char **ipv4_addrs =
+                sset_array(&od->lb_ips->ips_v4_reachable);
+
+            sync_address_set(ovnsb_txn, ipv4_addrs_name, ipv4_addrs,
+                             sset_count(&od->lb_ips->ips_v4_reachable),
+                             &sb_address_sets);
+            free(ipv4_addrs_name);
+            free(ipv4_addrs);
+        }
+
+        if (sset_count(&od->lb_ips->ips_v6_reachable)) {
+            char *ipv6_addrs_name = lr_lb_address_set_name(od->tunnel_key,
+                                                           AF_INET6);
+            const char **ipv6_addrs =
+                sset_array(&od->lb_ips->ips_v6_reachable);
+
+            sync_address_set(ovnsb_txn, ipv6_addrs_name, ipv6_addrs,
+                             sset_count(&od->lb_ips->ips_v6_reachable),
+                             &sb_address_sets);
+            free(ipv6_addrs_name);
+            free(ipv6_addrs);
+        }
+    }
+
+    /* sync user defined address sets, which may overwrite port group
+     * generated address sets if same name is used */
+    const struct nbrec_address_set *nb_address_set;
+    NBREC_ADDRESS_SET_TABLE_FOR_EACH (nb_address_set,
+                                      nb_address_set_table) {
+        sync_address_set(ovnsb_txn, nb_address_set->name,
+            /* "char **" is not compatible with "const char **" */
+            (const char **) nb_address_set->addresses,
+            nb_address_set->n_addresses, &sb_address_sets);
+    }
+
+    struct shash_node *node;
+    SHASH_FOR_EACH_SAFE (node, &sb_address_sets) {
+        sbrec_address_set_delete(node->data);
+        shash_delete(&sb_address_sets, node);
+    }
+    shash_destroy(&sb_address_sets);
+}
diff --git a/northd/en-sb-sync.h b/northd/en-sb-sync.h
new file mode 100644
index 000000000..f99d6a9fc
--- /dev/null
+++ b/northd/en-sb-sync.h
@@ -0,0 +1,14 @@
+#ifndef EN_SB_SYNC_H
+#define EN_SB_SYNC_H 1
+
+#include "lib/inc-proc-eng.h"
+
+void *en_sb_sync_init(struct engine_node *, struct engine_arg *);
+void en_sb_sync_run(struct engine_node *, void *data);
+void en_sb_sync_cleanup(void *data);
+
+void *en_address_set_sync_init(struct engine_node *, struct engine_arg *);
+void en_address_set_sync_run(struct engine_node *, void *data);
+void en_address_set_sync_cleanup(void *data);
+
+#endif
diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c
index 54e0ad3b0..b48f53f17 100644
--- a/northd/inc-proc-northd.c
+++ b/northd/inc-proc-northd.c
@@ -32,6 +32,8 @@
 #include "inc-proc-northd.h"
 #include "en-northd.h"
 #include "en-lflow.h"
+#include "en-northd-output.h"
+#include "en-sb-sync.h"
 #include "util.h"
 
 VLOG_DEFINE_THIS_MODULE(inc_proc_northd);
@@ -153,6 +155,9 @@ static ENGINE_NODE(northd, "northd");
 static ENGINE_NODE(lflow, "lflow");
 static ENGINE_NODE(mac_binding_aging, "mac_binding_aging");
 static ENGINE_NODE(mac_binding_aging_waker, "mac_binding_aging_waker");
+static ENGINE_NODE(northd_output, "northd_output");
+static ENGINE_NODE(sb_sync, "sb_sync");
+static ENGINE_NODE(address_set_sync, "address_set_sync");
 
 void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
                           struct ovsdb_idl_loop *sb)
@@ -229,6 +234,29 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
      * once I-P engine allows multiple root nodes. */
     engine_add_input(&en_lflow, &en_mac_binding_aging, NULL);
 
+    /* en_address_set_sync engine node syncs the SB database tables from
+     * the NB database tables.
+     * Right now this engine only syncs the SB Address_Set table.
+     */
+    engine_add_input(&en_address_set_sync, &en_nb_address_set, NULL);
+    engine_add_input(&en_address_set_sync, &en_nb_port_group, NULL);
+    engine_add_input(&en_address_set_sync, &en_nb_load_balancer, NULL);
+    engine_add_input(&en_address_set_sync, &en_nb_load_balancer_group, NULL);
+    engine_add_input(&en_address_set_sync, &en_nb_logical_router, NULL);
+    engine_add_input(&en_address_set_sync, &en_sb_address_set,
+                     engine_noop_handler);
+
+    /* We need the en_northd generated data as input to en_address_set_sync
+     * node to access the data generated by it (eg. struct ovn_datapath).
+     */
+    engine_add_input(&en_address_set_sync, &en_northd, NULL);
+
+    engine_add_input(&en_sb_sync, &en_address_set_sync, NULL);
+    engine_add_input(&en_northd_output, &en_sb_sync,
+                     northd_output_sb_sync_handler);
+    engine_add_input(&en_northd_output, &en_lflow,
+                     northd_output_lflow_handler);
+
     struct engine_arg engine_arg = {
         .nb_idl = nb->idl,
         .sb_idl = sb->idl,
@@ -249,7 +277,7 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
     struct ovsdb_idl_index *sbrec_mac_binding_by_datapath
         = mac_binding_by_datapath_index_create(sb->idl);
 
-    engine_init(&en_lflow, &engine_arg);
+    engine_init(&en_northd_output, &engine_arg);
 
     engine_ovsdb_node_add_index(&en_sb_chassis,
                                 "sbrec_chassis_by_name",
diff --git a/northd/northd.c b/northd/northd.c
index b7388afc5..238c925e0 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -787,37 +787,6 @@ lr_has_lb_vip(struct ovn_datapath *od)
     return false;
 }
 
-/* Builds a unique address set compatible name ([a-zA-Z_.][a-zA-Z_.0-9]*)
- * for the router's load balancer VIP address set, combining the logical
- * router's datapath tunnel key and address family.
- *
- * Also prefixes the name with 'prefix'.
- */
-static char *
-lr_lb_address_set_name_(const struct ovn_datapath *od, const char *prefix,
-                        int addr_family)
-{
-    ovs_assert(od->nbr);
-    return xasprintf("%s_rtr_lb_%"PRIu32"_ip%s", prefix, od->tunnel_key,
-                     addr_family == AF_INET ? "4" : "6");
-}
-
-/* Builds the router's load balancer VIP address set name. */
-static char *
-lr_lb_address_set_name(const struct ovn_datapath *od, int addr_family)
-{
-    return lr_lb_address_set_name_(od, "", addr_family);
-}
-
-/* Builds a string that refers to the the router's load balancer VIP address
- * set name, that is: $<address_set_name>.
- */
-static char *
-lr_lb_address_set_ref(const struct ovn_datapath *od, int addr_family)
-{
-    return lr_lb_address_set_name_(od, "$", addr_family);
-}
-
 static void
 init_lb_for_datapath(struct ovn_datapath *od)
 {
@@ -12865,7 +12834,8 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op,
             }
 
             /* Create a single ARP rule for all IPs that are used as VIPs. */
-            char *lb_ips_v4_as = lr_lb_address_set_ref(op->od, AF_INET);
+            char *lb_ips_v4_as = lr_lb_address_set_ref(op->od->tunnel_key,
+                                                       AF_INET);
             build_lrouter_arp_flow(op->od, op, lb_ips_v4_as,
                                    REG_INPORT_ETH_ADDR,
                                    match, false, 90, NULL, lflows);
@@ -12881,7 +12851,8 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op,
             }
 
             /* Create a single ND rule for all IPs that are used as VIPs. */
-            char *lb_ips_v6_as = lr_lb_address_set_ref(op->od, AF_INET6);
+            char *lb_ips_v6_as = lr_lb_address_set_ref(op->od->tunnel_key,
+                                                       AF_INET6);
             build_lrouter_nd_flow(op->od, op, "nd_na", lb_ips_v6_as, NULL,
                                   REG_INPORT_ETH_ADDR, match, false, 90,
                                   NULL, lflows, meter_groups);
@@ -14641,136 +14612,6 @@ void build_lflows(struct lflow_input *input_data,
     hmap_destroy(&mcast_groups);
 }
 
-static void
-sync_address_set(struct ovsdb_idl_txn *ovnsb_txn, const char *name,
-                 const char **addrs, size_t n_addrs,
-                 struct shash *sb_address_sets)
-{
-    const struct sbrec_address_set *sb_address_set;
-    sb_address_set = shash_find_and_delete(sb_address_sets,
-                                           name);
-    if (!sb_address_set) {
-        sb_address_set = sbrec_address_set_insert(ovnsb_txn);
-        sbrec_address_set_set_name(sb_address_set, name);
-    }
-
-    sbrec_address_set_set_addresses(sb_address_set,
-                                    addrs, n_addrs);
-}
-
-/* OVN_Southbound Address_Set table contains same records as in north
- * bound, plus the records generated from Port_Group table in north bound.
- *
- * There are 2 records generated from each port group, one for IPv4, and
- * one for IPv6, named in the format: <port group name>_ip4 and
- * <port group name>_ip6 respectively. MAC addresses are ignored.
- *
- * We always update OVN_Southbound to match the Address_Set and Port_Group
- * in OVN_Northbound, so that the address sets used in Logical_Flows in
- * OVN_Southbound is checked against the proper set.*/
-static void
-sync_address_sets(struct northd_input *input_data,
-                  struct ovsdb_idl_txn *ovnsb_txn,
-                  struct hmap *datapaths)
-{
-    struct shash sb_address_sets = SHASH_INITIALIZER(&sb_address_sets);
-
-    const struct sbrec_address_set *sb_address_set;
-    SBREC_ADDRESS_SET_TABLE_FOR_EACH (sb_address_set,
-                                   input_data->sbrec_address_set_table) {
-        shash_add(&sb_address_sets, sb_address_set->name, sb_address_set);
-    }
-
-    /* Service monitor MAC. */
-    const char *svc_monitor_macp = svc_monitor_mac;
-    sync_address_set(ovnsb_txn, "svc_monitor_mac", &svc_monitor_macp, 1,
-                     &sb_address_sets);
-
-    /* sync port group generated address sets first */
-    const struct nbrec_port_group *nb_port_group;
-    NBREC_PORT_GROUP_TABLE_FOR_EACH (nb_port_group,
-                                     input_data->nbrec_port_group_table) {
-        struct svec ipv4_addrs = SVEC_EMPTY_INITIALIZER;
-        struct svec ipv6_addrs = SVEC_EMPTY_INITIALIZER;
-        for (size_t i = 0; i < nb_port_group->n_ports; i++) {
-            for (size_t j = 0; j < nb_port_group->ports[i]->n_addresses; j++) {
-                const char *addrs = nb_port_group->ports[i]->addresses[j];
-                if (!is_dynamic_lsp_address(addrs)) {
-                    split_addresses(addrs, &ipv4_addrs, &ipv6_addrs);
-                }
-            }
-            if (nb_port_group->ports[i]->dynamic_addresses) {
-                split_addresses(nb_port_group->ports[i]->dynamic_addresses,
-                                &ipv4_addrs, &ipv6_addrs);
-            }
-        }
-        char *ipv4_addrs_name = xasprintf("%s_ip4", nb_port_group->name);
-        char *ipv6_addrs_name = xasprintf("%s_ip6", nb_port_group->name);
-        sync_address_set(ovnsb_txn, ipv4_addrs_name,
-                         /* "char **" is not compatible with "const char **" */
-                         (const char **)ipv4_addrs.names,
-                         ipv4_addrs.n, &sb_address_sets);
-        sync_address_set(ovnsb_txn, ipv6_addrs_name,
-                         /* "char **" is not compatible with "const char **" */
-                         (const char **)ipv6_addrs.names,
-                         ipv6_addrs.n, &sb_address_sets);
-        free(ipv4_addrs_name);
-        free(ipv6_addrs_name);
-        svec_destroy(&ipv4_addrs);
-        svec_destroy(&ipv6_addrs);
-    }
-
-    /* Sync router load balancer VIP generated address sets. */
-    struct ovn_datapath *od;
-    HMAP_FOR_EACH (od, key_node, datapaths) {
-        if (!od->nbr) {
-            continue;
-        }
-
-        if (sset_count(&od->lb_ips->ips_v4_reachable)) {
-            char *ipv4_addrs_name = lr_lb_address_set_name(od, AF_INET);
-            const char **ipv4_addrs =
-                sset_array(&od->lb_ips->ips_v4_reachable);
-
-            sync_address_set(ovnsb_txn, ipv4_addrs_name, ipv4_addrs,
-                             sset_count(&od->lb_ips->ips_v4_reachable),
-                             &sb_address_sets);
-            free(ipv4_addrs_name);
-            free(ipv4_addrs);
-        }
-
-        if (sset_count(&od->lb_ips->ips_v6_reachable)) {
-            char *ipv6_addrs_name = lr_lb_address_set_name(od, AF_INET6);
-            const char **ipv6_addrs =
-                sset_array(&od->lb_ips->ips_v6_reachable);
-
-            sync_address_set(ovnsb_txn, ipv6_addrs_name, ipv6_addrs,
-                             sset_count(&od->lb_ips->ips_v6_reachable),
-                             &sb_address_sets);
-            free(ipv6_addrs_name);
-            free(ipv6_addrs);
-        }
-    }
-
-    /* sync user defined address sets, which may overwrite port group
-     * generated address sets if same name is used */
-    const struct nbrec_address_set *nb_address_set;
-    NBREC_ADDRESS_SET_TABLE_FOR_EACH (nb_address_set,
-                              input_data->nbrec_address_set_table) {
-        sync_address_set(ovnsb_txn, nb_address_set->name,
-            /* "char **" is not compatible with "const char **" */
-            (const char **)nb_address_set->addresses,
-            nb_address_set->n_addresses, &sb_address_sets);
-    }
-
-    struct shash_node *node;
-    SHASH_FOR_EACH_SAFE (node, &sb_address_sets) {
-        sbrec_address_set_delete(node->data);
-        shash_delete(&sb_address_sets, node);
-    }
-    shash_destroy(&sb_address_sets);
-}
-
 /* Each port group in Port_Group table in OVN_Northbound has a corresponding
  * entry in Port_Group table in OVN_Southbound. In OVN_Northbound the entries
  * contains lport uuids, while in OVN_Southbound we store the lport names.
@@ -15641,7 +15482,6 @@ ovnnb_db_run(struct northd_input *input_data,
     ovn_update_ipv6_prefix(&data->ports);
 
     sync_lbs(input_data, ovnsb_txn, &data->datapaths, &data->lbs);
-    sync_address_sets(input_data, ovnsb_txn, &data->datapaths);
     sync_port_groups(input_data, ovnsb_txn, &data->port_groups);
     sync_meters(input_data, ovnsb_txn, &data->meter_groups);
     sync_dns_entries(input_data, ovnsb_txn, &data->datapaths);
@@ -15918,3 +15758,8 @@ void northd_run(struct northd_input *input_data,
     stopwatch_stop(OVNSB_DB_RUN_STOPWATCH_NAME, time_msec());
 }
 
+const char *
+northd_get_svc_monitor_mac(void)
+{
+    return svc_monitor_mac;
+}
diff --git a/northd/northd.h b/northd/northd.h
index da90e2815..48edcb310 100644
--- a/northd/northd.h
+++ b/northd/northd.h
@@ -281,4 +281,5 @@ void bfd_cleanup_connections(struct lflow_input *input_data,
                              struct hmap *bfd_map);
 void run_update_worker_pool(int n_threads);
 
+const char *northd_get_svc_monitor_mac(void);
 #endif /* NORTHD_H */
