diff --git a/ovn/controller/pinctrl.c b/ovn/controller/pinctrl.c
index a0bf602..d01e57f 100644
--- a/ovn/controller/pinctrl.c
+++ b/ovn/controller/pinctrl.c
@@ -2185,8 +2185,47 @@ get_nat_addresses_and_keys(struct ovsdb_idl_index *sbrec_chassis_by_name,
                            struct sset *local_l3gw_ports,
                            const struct sbrec_chassis *chassis,
                            const struct sset *active_tunnels,
-                           struct shash *nat_addresses)
+                           struct shash *nat_addresses,
+                           const struct hmap *local_datapaths)
 {
+    /* When a router has tenant vlan networks, gARP for distributed gateway
+     * router port has to be sent through internal tenant vlan network's
+     * localnet port, so that external switches can learn this MAC and forward
+     * tenant vlan network traffic with distributed gateway router port MAC
+     * as destination MAC address */
+
+    struct local_datapath *ldp;
+    struct shash router_vlan_ports;
+
+    shash_init(&router_vlan_ports);
+    HMAP_FOR_EACH (ldp, hmap_node, local_datapaths) {
+        const struct sbrec_port_binding *crp;
+        crp = ldp->chassisredirect_port;
+        /* check if it a router with chassis redirect port,
+         * get corresponding distributed port */
+        if (crp && crp->chassis &&
+            !strcmp(crp->chassis->name, chassis->name)) {
+            const struct sbrec_port_binding *dp = NULL;
+            for (int i = 0; i < ldp->n_peer_dps; i++) {
+                if (!strcmp(ldp->peer_dps[i]->patch->logical_port,
+                            smap_get(&crp->options, "distributed-port"))) {
+                    dp = ldp->peer_dps[i]->peer;
+                    break;
+                }
+            }
+
+            /* Save router internal port (patch port on tenant vlan network)
+             * along with distributed port. */
+            for (int i = 0; i < ldp->n_peer_dps; i++) {
+                if (strcmp(ldp->peer_dps[i]->patch->logical_port,
+                           smap_get(&crp->options, "distributed-port"))) {
+                    shash_add(&router_vlan_ports,
+                              ldp->peer_dps[i]->peer->logical_port, dp);
+                }
+            }
+        }
+    }
+
     const char *gw_port;
     SSET_FOR_EACH(gw_port, local_l3gw_ports) {
         const struct sbrec_port_binding *pb;
@@ -2196,11 +2235,16 @@ get_nat_addresses_and_keys(struct ovsdb_idl_index *sbrec_chassis_by_name,
             continue;
         }
 
-        if (pb->n_nat_addresses) {
-            for (int i = 0; i < pb->n_nat_addresses; i++) {
+        /* Router internal ports should send gARP for distributed port
+         * NAT addresses */
+        const struct sbrec_port_binding *dp;
+        dp = shash_find_data(&router_vlan_ports, pb->logical_port);
+        const struct sbrec_port_binding *nat_port = dp ? dp : pb;
+        if (nat_port->n_nat_addresses) {
+            for (int i = 0; i < nat_port->n_nat_addresses; i++) {
                 consider_nat_address(sbrec_chassis_by_name,
                                      sbrec_port_binding_by_name,
-                                     pb->nat_addresses[i], pb,
+                                     nat_port->nat_addresses[i], pb,
                                      nat_address_keys, chassis,
                                      active_tunnels,
                                      nat_addresses);
@@ -2208,7 +2252,7 @@ get_nat_addresses_and_keys(struct ovsdb_idl_index *sbrec_chassis_by_name,
         } else {
             /* Continue to support options:nat-addresses for version
              * upgrade. */
-            const char *nat_addresses_options = smap_get(&pb->options,
+            const char *nat_addresses_options = smap_get(&nat_port->options,
                                                          "nat-addresses");
             if (nat_addresses_options) {
                 consider_nat_address(sbrec_chassis_by_name,
@@ -2220,6 +2264,7 @@ get_nat_addresses_and_keys(struct ovsdb_idl_index *sbrec_chassis_by_name,
             }
         }
     }
+    shash_destroy(&router_vlan_ports);
 }
 
 static void
@@ -2255,7 +2300,7 @@ send_garp_run(struct ovsdb_idl_index *sbrec_chassis_by_name,
                                sbrec_port_binding_by_name,
                                &nat_ip_keys, &local_l3gw_ports,
                                chassis, active_tunnels,
-                               &nat_addresses);
+                               &nat_addresses, local_datapaths);
     /* For deleted ports and deleted nat ips, remove from send_garp_data. */
     struct shash_node *iter, *next;
     SHASH_FOR_EACH_SAFE (iter, next, &send_garp_data) {
diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
index 2497a5b..bcf0b66 100644
--- a/ovn/northd/ovn-northd.c
+++ b/ovn/northd/ovn-northd.c
@@ -5043,6 +5043,63 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
                           ds_cstr(&match), ds_cstr(&actions));
         }
 
+        /* ARP requests for distributed port IP address but coming from router
+         * internal network vlan, should be replied through router internal
+         * network vlan ports */
+        if (op->od->l3dgw_port && (op == op->od->l3dgw_port)
+            && op->od->l3redirect_port) {
+            for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {
+                ds_clear(&match);
+                ds_put_format(&match,
+                              "flags.rcv_from_vlan == 1 && "
+                              "arp.tpa == %s && arp.op == 1 && "
+                              "is_chassis_resident(%s)",
+                               op->lrp_networks.ipv4_addrs[i].addr_s,
+                               op->od->l3redirect_port->json_key);
+
+                ds_clear(&actions);
+                ds_put_format(&actions,
+                    "eth.dst = eth.src; "
+                    "eth.src = %s; "
+                    "arp.op = 2; /* ARP reply */ "
+                    "arp.tha = arp.sha; "
+                    "arp.sha = %s; "
+                    "arp.tpa = arp.spa; "
+                    "arp.spa = %s; "
+                    "flags.loopback = 1; ",
+                    op->lrp_networks.ea_s,
+                    op->lrp_networks.ea_s,
+                    op->lrp_networks.ipv4_addrs[i].addr_s);
+
+                /* Add internal vlan network ports as output ports */
+                bool router_ports_exist = false;
+                struct ovn_datapath *dp;
+                HMAP_FOR_EACH (dp, key_node, datapaths) {
+                    if (!dp->nbs) {
+                        continue;
+                    }
+                    if (!dp->localnet_port) {
+                        continue;
+                    }
+                    for (size_t j = 0; j < dp->n_router_ports; j++) {
+                        struct ovn_port *rp = dp->router_ports[j];
+                        if (rp->peer && rp->peer->od == op->od &&
+                            rp->peer != op) {
+                            router_ports_exist = true;
+                            ds_put_format(&actions,
+                                "outport = %s; "
+                                "output;",
+                                rp->peer->json_key);
+                        }
+                    }
+                }
+                if (router_ports_exist) {
+                    ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90,
+                        ds_cstr(&match), ds_cstr(&actions));
+                }
+            }
+        }
+
         /* A set to hold all load-balancer vips that need ARP responses. */
         struct sset all_ips = SSET_INITIALIZER(&all_ips);
         int addr_family;
diff --git a/tests/ovn.at b/tests/ovn.at
index fb9b516..314f0ad 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -7981,6 +7981,12 @@ foo_mac="000001010203"
 gw_mac="000002010203"
 nexthop_mac="f00000010204"
 
+# gARP for distributed port has to be sent through router internal patch port
+# which is connected to vlan network
+garp=ffffffffffff${gw_mac}8100000208060001080006040001${gw_mac}${gw_ip}000000000000${gw_ip}
+echo $garp >> hv1-br-ex_n2-rx.expected
+OVN_CHECK_PACKETS([hv1/br-ex_n2-rx.pcap], [hv1-br-ex_n2-rx.expected])
+
 # Send ip packet from foo1 to 8.8.8.8
 src_mac="f00000010203"
 dst_mac="000001010203"
