diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
index 2fba68f..23e3532 100644
--- a/ovn/northd/ovn-northd.c
+++ b/ovn/northd/ovn-northd.c
@@ -480,11 +480,20 @@ struct ovn_port {
     char *key;                  /* nbs->name, nbr->name, sb->logical_port. */
     char *json_key;             /* 'key', quoted for use in JSON. */
 
-    const struct nbrec_logical_switch_port *nbs; /* May be NULL. */
-    const struct nbrec_logical_router_port *nbr; /* May be NULL. */
     const struct sbrec_port_binding *sb;         /* May be NULL. */
 
+    /* Logical switch port data. */
+    const struct nbrec_logical_switch_port *nbs; /* May be NULL. */
+
+    struct lport_addresses *lsp_addrs;  /* Logical switch port addresses. */
+    unsigned int n_lsp_addrs;
+
+    struct lport_addresses *ps_addrs;   /* Port security addresses. */
+    unsigned int n_ps_addrs;
+
     /* Logical router port data. */
+    const struct nbrec_logical_router_port *nbr; /* May be NULL. */
+
     char *ip_s;                 /* "192.168.10.123" */
     char *network_s;            /* "192.168.10.0" */
     char *bcast_s;              /* "192.168.10.255" */
@@ -530,6 +539,17 @@ ovn_port_destroy(struct hmap *ports, struct ovn_port *port)
          * private list and once we've exited that function it is not safe to
          * use it. */
         hmap_remove(ports, &port->key_node);
+
+        for (int i = 0; i < port->n_lsp_addrs; i++) {
+            destroy_lport_addresses(&port->lsp_addrs[i]);
+        }
+        free(port->lsp_addrs);
+
+        for (int i = 0; i < port->n_ps_addrs; i++) {
+            destroy_lport_addresses(&port->ps_addrs[i]);
+        }
+        free(port->ps_addrs);
+
         free(port->bcast_s);
         free(port->network_s);
         free(port->ip_s);
@@ -594,11 +614,49 @@ join_logical_ports(struct northd_context *ctx,
                     op->nbs = nbs;
                     ovs_list_remove(&op->list);
                     ovs_list_push_back(both, &op->list);
+
+                    /* This port exists due to a SB binding, but should
+                     * not have been initialized fully. */
+                    ovs_assert(!op->n_lsp_addrs && !op->n_ps_addrs);
                 } else {
                     op = ovn_port_create(ports, nbs->name, nbs, NULL, NULL);
                     ovs_list_push_back(nb_only, &op->list);
                 }
 
+                op->lsp_addrs
+                    = xmalloc(sizeof *op->lsp_addrs * nbs->n_addresses);
+                for (size_t j = 0; j < nbs->n_addresses; j++) {
+                    if (!strcmp(nbs->addresses[j], "unknown")) {
+                        continue;
+                    }
+                    if (!extract_lsp_addresses(nbs->addresses[j],
+                                           &op->lsp_addrs[op->n_lsp_addrs])) {
+                        static struct vlog_rate_limit rl
+                            = VLOG_RATE_LIMIT_INIT(1, 1);
+                        VLOG_INFO_RL(&rl, "invalid syntax '%s' in logical "
+                                          "switch port addresses. No MAC "
+                                          "address found",
+                                          op->nbs->addresses[j]);
+                        continue;
+                    }
+                    op->n_lsp_addrs++;
+                }
+
+                op->ps_addrs
+                    = xmalloc(sizeof *op->ps_addrs * nbs->n_port_security);
+                for (size_t j = 0; j < nbs->n_port_security; j++) {
+                    if (!extract_lsp_addresses(nbs->port_security[j],
+                                               &op->ps_addrs[op->n_ps_addrs])) {
+                        static struct vlog_rate_limit rl
+                            = VLOG_RATE_LIMIT_INIT(1, 1);
+                        VLOG_INFO_RL(&rl, "invalid syntax '%s' in port "
+                                          "security. No MAC address found",
+                                          op->nbs->port_security[j]);
+                        continue;
+                    }
+                    op->n_ps_addrs++;
+                }
+
                 op->od = od;
             }
         } else {
@@ -985,33 +1043,27 @@ ovn_lflow_destroy(struct hmap *lflows, struct ovn_lflow *lflow)
 }
 
 /* Appends port security constraints on L2 address field 'eth_addr_field'
- * (e.g. "eth.src" or "eth.dst") to 'match'.  'port_security', with
- * 'n_port_security' elements, is the collection of port_security constraints
- * from an OVN_NB Logical_Switch_Port row. */
+ * (e.g. "eth.src" or "eth.dst") to 'match'.  'ps_addrs', with 'n_ps_addrs'
+ * elements, is the collection of port_security constraints from an
+ * OVN_NB Logical_Switch_Port row generated by extract_lsp_addresses(). */
 static void
 build_port_security_l2(const char *eth_addr_field,
-                       char **port_security, size_t n_port_security,
+                       struct lport_addresses *ps_addrs,
+                       unsigned int n_ps_addrs,
                        struct ds *match)
 {
-    size_t base_len = match->length;
-    ds_put_format(match, " && %s == {", eth_addr_field);
+    if (!n_ps_addrs) {
+        return;
+    }
 
-    size_t n = 0;
-    for (size_t i = 0; i < n_port_security; i++) {
-        struct eth_addr ea;
+    ds_put_format(match, " && %s == {", eth_addr_field);
 
-        if (eth_addr_from_string(port_security[i], &ea)) {
-            ds_put_format(match, ETH_ADDR_FMT, ETH_ADDR_ARGS(ea));
-            ds_put_char(match, ' ');
-            n++;
-        }
+    for (size_t i = 0; i < n_ps_addrs; i++) {
+        ds_put_format(match, "%s", ps_addrs[i].ea_s);
+        ds_put_char(match, ' ');
     }
     ds_chomp(match, ' ');
     ds_put_cstr(match, "}");
-
-    if (!n) {
-        match->length = base_len;
-    }
 }
 
 static void
@@ -1099,69 +1151,60 @@ build_port_security_ipv6_flow(
 static void
 build_port_security_nd(struct ovn_port *op, struct hmap *lflows)
 {
-    for (size_t i = 0; i < op->nbs->n_port_security; i++) {
-        struct lport_addresses ps;
-        if (!extract_lsp_addresses(op->nbs->port_security[i], &ps)) {
-            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
-            VLOG_INFO_RL(&rl, "invalid syntax '%s' in port security. No MAC"
-                         " address found", op->nbs->port_security[i]);
-            continue;
-        }
+    struct ds match = DS_EMPTY_INITIALIZER;
+
+    for (size_t i = 0; i < op->n_ps_addrs; i++) {
+        struct lport_addresses *ps = &op->ps_addrs[i];
 
-        bool no_ip = !(ps.n_ipv4_addrs || ps.n_ipv6_addrs);
-        struct ds match = DS_EMPTY_INITIALIZER;
+        bool no_ip = !(ps->n_ipv4_addrs || ps->n_ipv6_addrs);
 
-        if (ps.n_ipv4_addrs || no_ip) {
-            ds_put_format(
-                &match, "inport == %s && eth.src == "ETH_ADDR_FMT" && arp.sha == "
-                ETH_ADDR_FMT, op->json_key, ETH_ADDR_ARGS(ps.ea),
-                ETH_ADDR_ARGS(ps.ea));
+        ds_clear(&match);
+        if (ps->n_ipv4_addrs || no_ip) {
+            ds_put_format(&match,
+                          "inport == %s && eth.src == %s && arp.sha == %s",
+                          op->json_key, ps->ea_s, ps->ea_s);
 
-            if (ps.n_ipv4_addrs) {
-                ds_put_cstr(&match, " && (");
-                for (size_t i = 0; i < ps.n_ipv4_addrs; i++) {
-                    ds_put_cstr(&match, "arp.spa == ");
-                    ovs_be32 mask = be32_prefix_mask(ps.ipv4_addrs[i].plen);
+            if (ps->n_ipv4_addrs) {
+                ds_put_cstr(&match, " && arp.spa == {");
+                for (size_t i = 0; i < ps->n_ipv4_addrs; i++) {
                     /* When the netmask is applied, if the host portion is
                      * non-zero, the host can only use the specified
                      * address in the arp.spa.  If zero, the host is allowed
                      * to use any address in the subnet. */
-                    if (ps.ipv4_addrs[i].addr & ~mask) {
-                        ds_put_format(&match, IP_FMT,
-                                      IP_ARGS(ps.ipv4_addrs[i].addr));
+                    if (ps->ipv4_addrs[i].plen == 32
+                        || ps->ipv4_addrs[i].addr & ~ps->ipv4_addrs[i].mask) {
+                        ds_put_format(&match, "%s", ps->ipv4_addrs[i].addr_s);
                     } else {
-                       ip_format_masked(ps.ipv4_addrs[i].addr & mask, mask,
-                                        &match);
+                        ds_put_format(&match, "%s/%d",
+                                      ps->ipv4_addrs[i].network_s,
+                                      ps->ipv4_addrs[i].plen);
                     }
-                    ds_put_cstr(&match, " || ");
+                    ds_put_cstr(&match, ", ");
                 }
                 ds_chomp(&match, ' ');
-                ds_chomp(&match, '|');
-                ds_chomp(&match, '|');
-                ds_put_cstr(&match, ")");
+                ds_chomp(&match, ',');
+                ds_put_cstr(&match, "}");
             }
             ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC_ND, 90,
                           ds_cstr(&match), "next;");
-            ds_destroy(&match);
         }
 
-        if (ps.n_ipv6_addrs || no_ip) {
-            ds_init(&match);
-            ds_put_format(&match, "inport == %s && eth.src == "ETH_ADDR_FMT,
-                          op->json_key, ETH_ADDR_ARGS(ps.ea));
-            build_port_security_ipv6_nd_flow(&match, ps.ea, ps.ipv6_addrs,
-                                             ps.n_ipv6_addrs);
+        if (ps->n_ipv6_addrs || no_ip) {
+            ds_clear(&match);
+            ds_put_format(&match, "inport == %s && eth.src == %s",
+                          op->json_key, ps->ea_s);
+            build_port_security_ipv6_nd_flow(&match, ps->ea, ps->ipv6_addrs,
+                                             ps->n_ipv6_addrs);
             ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC_ND, 90,
                           ds_cstr(&match), "next;");
-            ds_destroy(&match);
         }
-        destroy_lport_addresses(&ps);
     }
 
-    char *match = xasprintf("inport == %s && (arp || nd)", op->json_key);
+    ds_clear(&match);
+    ds_put_format(&match, "inport == %s && (arp || nd)", op->json_key);
     ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC_ND, 80,
-                  match, "drop;");
-    free(match);
+                  ds_cstr(&match), "drop;");
+    ds_destroy(&match);
 }
 
 /**
@@ -1193,60 +1236,56 @@ build_port_security_ip(enum ovn_pipeline pipeline, struct ovn_port *op,
         stage = S_SWITCH_OUT_PORT_SEC_IP;
     }
 
-    for (size_t i = 0; i < op->nbs->n_port_security; i++) {
-        struct lport_addresses ps;
-        if (!extract_lsp_addresses(op->nbs->port_security[i], &ps)) {
-            continue;
-        }
+    for (size_t i = 0; i < op->n_ps_addrs; i++) {
+        struct lport_addresses *ps = &op->ps_addrs[i];
 
-        if (!(ps.n_ipv4_addrs || ps.n_ipv6_addrs)) {
+        if (!(ps->n_ipv4_addrs || ps->n_ipv6_addrs)) {
             continue;
         }
 
-        if (ps.n_ipv4_addrs) {
+        if (ps->n_ipv4_addrs) {
             struct ds match = DS_EMPTY_INITIALIZER;
             if (pipeline == P_IN) {
                 /* Permit use of the unspecified address for DHCP discovery */
                 struct ds dhcp_match = DS_EMPTY_INITIALIZER;
                 ds_put_format(&dhcp_match, "inport == %s"
-                              " && eth.src == "ETH_ADDR_FMT
+                              " && eth.src == %s"
                               " && ip4.src == 0.0.0.0"
                               " && ip4.dst == 255.255.255.255"
-                              " && udp.src == 68 && udp.dst == 67", op->json_key,
-                              ETH_ADDR_ARGS(ps.ea));
+                              " && udp.src == 68 && udp.dst == 67",
+                              op->json_key, ps->ea_s);
                 ovn_lflow_add(lflows, op->od, stage, 90,
                               ds_cstr(&dhcp_match), "next;");
                 ds_destroy(&dhcp_match);
-                ds_put_format(&match, "inport == %s && eth.src == "ETH_ADDR_FMT
+                ds_put_format(&match, "inport == %s && eth.src == %s"
                               " && ip4.src == {", op->json_key,
-                              ETH_ADDR_ARGS(ps.ea));
+                              ps->ea_s);
             } else {
-                ds_put_format(&match, "outport == %s && eth.dst == "ETH_ADDR_FMT
+                ds_put_format(&match, "outport == %s && eth.dst == %s"
                               " && ip4.dst == {255.255.255.255, 224.0.0.0/4, ",
-                              op->json_key, ETH_ADDR_ARGS(ps.ea));
+                              op->json_key, ps->ea_s);
             }
 
-            for (int i = 0; i < ps.n_ipv4_addrs; i++) {
-                ovs_be32 mask = be32_prefix_mask(ps.ipv4_addrs[i].plen);
+            for (int i = 0; i < ps->n_ipv4_addrs; i++) {
+                ovs_be32 mask = ps->ipv4_addrs[i].mask;
                 /* When the netmask is applied, if the host portion is
                  * non-zero, the host can only use the specified
                  * address.  If zero, the host is allowed to use any
                  * address in the subnet.
-                 * */
-                if (ps.ipv4_addrs[i].addr & ~mask) {
-                    ds_put_format(&match, IP_FMT,
-                                  IP_ARGS(ps.ipv4_addrs[i].addr));
-                    if (pipeline == P_OUT && ps.ipv4_addrs[i].plen != 32) {
-                         /* Host is also allowed to receive packets to the
-                         * broadcast address in the specified subnet.
-                         */
-                        ds_put_format(&match, ", "IP_FMT,
-                                      IP_ARGS(ps.ipv4_addrs[i].addr | ~mask));
+                 */
+                if (ps->ipv4_addrs[i].plen == 32
+                    || ps->ipv4_addrs[i].addr & ~mask) {
+                    ds_put_format(&match, "%s", ps->ipv4_addrs[i].addr_s);
+                    if (pipeline == P_OUT && ps->ipv4_addrs[i].plen != 32) {
+                        /* Host is also allowed to receive packets to the
+                         * broadcast address in the specified subnet. */
+                        ds_put_format(&match, ", %s",
+                                      ps->ipv4_addrs[i].bcast_s);
                     }
                 } else {
                     /* host portion is zero */
-                    ip_format_masked(ps.ipv4_addrs[i].addr & mask, mask,
-                                     &match);
+                    ds_put_format(&match, "%s/%d", ps->ipv4_addrs[i].network_s,
+                                  ps->ipv4_addrs[i].plen);
                 }
                 ds_put_cstr(&match, ", ");
             }
@@ -1259,39 +1298,36 @@ build_port_security_ip(enum ovn_pipeline pipeline, struct ovn_port *op,
             ds_destroy(&match);
         }
 
-        if (ps.n_ipv6_addrs) {
+        if (ps->n_ipv6_addrs) {
             struct ds match = DS_EMPTY_INITIALIZER;
             if (pipeline == P_IN) {
                 /* Permit use of unspecified address for duplicate address
                  * detection */
                 struct ds dad_match = DS_EMPTY_INITIALIZER;
                 ds_put_format(&dad_match, "inport == %s"
-                              " && eth.src == "ETH_ADDR_FMT
+                              " && eth.src == %s"
                               " && ip6.src == ::"
                               " && ip6.dst == ff02::/16"
                               " && icmp6.type == {131, 135, 143}", op->json_key,
-                              ETH_ADDR_ARGS(ps.ea));
+                              ps->ea_s);
                 ovn_lflow_add(lflows, op->od, stage, 90,
                               ds_cstr(&dad_match), "next;");
                 ds_destroy(&dad_match);
             }
-            ds_put_format(&match, "%s == %s && %s == "ETH_ADDR_FMT"",
+            ds_put_format(&match, "%s == %s && %s == %s",
                           port_direction, op->json_key,
-                          pipeline == P_IN ? "eth.src" : "eth.dst",
-                          ETH_ADDR_ARGS(ps.ea));
-            build_port_security_ipv6_flow(pipeline, &match, ps.ea,
-                                          ps.ipv6_addrs, ps.n_ipv6_addrs);
+                          pipeline == P_IN ? "eth.src" : "eth.dst", ps->ea_s);
+            build_port_security_ipv6_flow(pipeline, &match, ps->ea,
+                                          ps->ipv6_addrs, ps->n_ipv6_addrs);
             ovn_lflow_add(lflows, op->od, stage, 90,
                           ds_cstr(&match), "next;");
             ds_destroy(&match);
         }
 
-        destroy_lport_addresses(&ps);
-
-        char *match = xasprintf(
-            "%s == %s && %s == "ETH_ADDR_FMT" && ip", port_direction,
-            op->json_key, pipeline == P_IN ? "eth.src" : "eth.dst",
-            ETH_ADDR_ARGS(ps.ea));
+        char *match = xasprintf("%s == %s && %s == %s && ip",
+                                port_direction, op->json_key,
+                                pipeline == P_IN ? "eth.src" : "eth.dst",
+                                ps->ea_s);
         ovn_lflow_add(lflows, op->od, stage, 80, match, "drop;");
         free(match);
     }
@@ -1775,9 +1811,8 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
 
         ds_clear(&match);
         ds_put_format(&match, "inport == %s", op->json_key);
-        build_port_security_l2(
-            "eth.src", op->nbs->port_security, op->nbs->n_port_security,
-            &match);
+        build_port_security_l2("eth.src", op->ps_addrs, op->n_ps_addrs,
+                               &match);
         ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC_L2, 50,
                       ds_cstr(&match), "next;");
 
@@ -1829,48 +1864,40 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
             continue;
         }
 
-        for (size_t i = 0; i < op->nbs->n_addresses; i++) {
-            struct lport_addresses laddrs;
-            if (!extract_lsp_addresses(op->nbs->addresses[i], &laddrs)) {
-                continue;
-            }
-            for (size_t j = 0; j < laddrs.n_ipv4_addrs; j++) {
+        for (size_t i = 0; i < op->n_lsp_addrs; i++) {
+            for (size_t j = 0; j < op->lsp_addrs[i].n_ipv4_addrs; j++) {
                 ds_clear(&match);
-                ds_put_format(&match, "arp.tpa == "IP_FMT" && arp.op == 1",
-                              IP_ARGS(laddrs.ipv4_addrs[j].addr));
+                ds_put_format(&match, "arp.tpa == %s && arp.op == 1",
+                              op->lsp_addrs[i].ipv4_addrs[j].addr_s);
                 ds_clear(&actions);
                 ds_put_format(&actions,
                     "eth.dst = eth.src; "
-                    "eth.src = "ETH_ADDR_FMT"; "
+                    "eth.src = %s; "
                     "arp.op = 2; /* ARP reply */ "
                     "arp.tha = arp.sha; "
-                    "arp.sha = "ETH_ADDR_FMT"; "
+                    "arp.sha = %s; "
                     "arp.tpa = arp.spa; "
-                    "arp.spa = "IP_FMT"; "
+                    "arp.spa = %s; "
                     "outport = inport; "
                     "inport = \"\"; /* Allow sending out inport. */ "
                     "output;",
-                    ETH_ADDR_ARGS(laddrs.ea),
-                    ETH_ADDR_ARGS(laddrs.ea),
-                    IP_ARGS(laddrs.ipv4_addrs[j].addr));
+                    op->lsp_addrs[i].ea_s, op->lsp_addrs[i].ea_s,
+                    op->lsp_addrs[i].ipv4_addrs[j].addr_s);
                 ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, 50,
                               ds_cstr(&match), ds_cstr(&actions));
             }
 
-            if (laddrs.n_ipv6_addrs > 0) {
-                char ip6_str[INET6_ADDRSTRLEN + 1];
+            if (op->lsp_addrs[i].n_ipv6_addrs > 0) {
                 ds_clear(&match);
                 ds_put_cstr(&match, "icmp6 && icmp6.type == 135 && ");
-                if (laddrs.n_ipv6_addrs == 1) {
-                    ipv6_string_mapped(ip6_str,
-                                       &(laddrs.ipv6_addrs[0].addr));
-                    ds_put_format(&match, "nd.target == %s", ip6_str);
+                if (op->lsp_addrs[i].n_ipv6_addrs == 1) {
+                    ds_put_format(&match, "nd.target == %s",
+                                  op->lsp_addrs[i].ipv6_addrs[0].addr_s);
                 } else {
                     ds_put_cstr(&match, "(");
-                    for (size_t j = 0; j < laddrs.n_ipv6_addrs; j++) {
-                        ipv6_string_mapped(ip6_str,
-                                           &(laddrs.ipv6_addrs[j].addr));
-                        ds_put_format(&match, "nd.target == %s || ", ip6_str);
+                    for (size_t j = 0; j < op->lsp_addrs[i].n_ipv6_addrs; j++) {
+                        ds_put_format(&match, "nd.target == %s || ",
+                                      op->lsp_addrs[i].ipv6_addrs[j].addr_s);
                     }
                     ds_chomp(&match, ' ');
                     ds_chomp(&match, '|');
@@ -1880,20 +1907,18 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
                 }
                 ds_clear(&actions);
                 ds_put_format(&actions,
-                    "na { eth.src = "ETH_ADDR_FMT"; "
-                    "nd.tll = "ETH_ADDR_FMT"; "
+                    "na { eth.src = %s; "
+                    "nd.tll = %s; "
                     "outport = inport; "
                     "inport = \"\"; /* Allow sending out inport. */ "
                     "output; };",
-                    ETH_ADDR_ARGS(laddrs.ea),
-                    ETH_ADDR_ARGS(laddrs.ea));
+                    op->lsp_addrs[i].ea_s,
+                    op->lsp_addrs[i].ea_s);
 
                 ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, 50,
                               ds_cstr(&match), ds_cstr(&actions));
 
             }
-
-            destroy_lport_addresses(&laddrs);
         }
     }
 
@@ -2002,8 +2027,8 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
         ds_clear(&match);
         ds_put_format(&match, "outport == %s", op->json_key);
         if (lsp_is_enabled(op->nbs)) {
-            build_port_security_l2("eth.dst", op->nbs->port_security,
-                                   op->nbs->n_port_security, &match);
+            build_port_security_l2("eth.dst", op->ps_addrs, op->n_ps_addrs,
+                                   &match);
             ovn_lflow_add(lflows, op->od, S_SWITCH_OUT_PORT_SEC_L2, 50,
                           ds_cstr(&match), "output;");
         } else {
@@ -2547,27 +2572,21 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
              * connects) and if the address in question is reachable from the
              * router port, add an ARP entry in that router's pipeline. */
 
-            for (size_t i = 0; i < op->nbs->n_addresses; i++) {
-                struct lport_addresses laddrs;
-                if (!extract_lsp_addresses(op->nbs->addresses[i], &laddrs)) {
-                    continue;
-                }
-
-                for (size_t k = 0; k < laddrs.n_ipv4_addrs; k++) {
-                    ovs_be32 ip = laddrs.ipv4_addrs[k].addr;
-                    for (size_t j = 0; j < op->od->n_router_ports; j++) {
+            for (size_t i = 0; i < op->n_lsp_addrs; i++) {
+                for (size_t j = 0; j < op->lsp_addrs[i].n_ipv4_addrs; j++) {
+                    ovs_be32 ip = op->lsp_addrs[i].ipv4_addrs[j].addr;
+                    for (size_t k = 0; k < op->od->n_router_ports; k++) {
                         /* Get the Logical_Router_Port that the
                          * Logical_Switch_Port is connected to, as
                          * 'peer'. */
                         const char *peer_name = smap_get(
-                            &op->od->router_ports[j]->nbs->options,
+                            &op->od->router_ports[k]->nbs->options,
                             "router-port");
                         if (!peer_name) {
                             continue;
                         }
 
-                        struct ovn_port *peer
-                            = ovn_port_find(ports, peer_name);
+                        struct ovn_port *peer = ovn_port_find(ports, peer_name);
                         if (!peer || !peer->nbr) {
                             continue;
                         }
@@ -2578,20 +2597,18 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
                         }
 
                         ds_clear(&match);
-                        ds_put_format(&match, "outport == %s && reg0 == "IP_FMT,
-                                      peer->json_key, IP_ARGS(ip));
+                        ds_put_format(&match, "outport == %s && reg0 == %s",
+                                      peer->json_key,
+                                      op->lsp_addrs[i].ipv4_addrs[j].addr_s);
                         ds_clear(&actions);
-                        ds_put_format(&actions,
-                                      "eth.dst = "ETH_ADDR_FMT"; next;",
-                                      ETH_ADDR_ARGS(laddrs.ea));
+                        ds_put_format(&actions, "eth.dst = %s; next;",
+                                      op->lsp_addrs[i].ea_s);
                         ovn_lflow_add(lflows, peer->od,
                                       S_ROUTER_IN_ARP_RESOLVE, 100,
                                       ds_cstr(&match), ds_cstr(&actions));
                         break;
                     }
                 }
-
-                destroy_lport_addresses(&laddrs);
             }
         } else if (!strcmp(op->nbs->type, "router")) {
             /* This is a logical switch port that connects to a router. */
