diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index cf955e5..a6edf4d 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -52,6 +52,7 @@
 #include "keepalive.h"
 #include "latch.h"
 #include "netdev.h"
+#include "netdev-provider.h"
 #include "netdev-vport.h"
 #include "netlink.h"
 #include "odp-execute.h"
@@ -981,9 +982,41 @@ sorted_poll_thread_list(struct dp_netdev *dp,
 }
 
 static void
-pmd_health_check(struct dp_netdev_pmd_thread *pmd OVS_UNUSED)
+pmd_health_check(struct dp_netdev_pmd_thread *pmd)
 {
-    /* Nothing */
+    int port_link_status = 0;
+    struct rxq_poll *poll;
+
+    struct svec pmd_poll_list;
+    svec_init(&pmd_poll_list);
+    HMAP_FOR_EACH (poll, node, &pmd->poll_list) {
+        svec_add(&pmd_poll_list, netdev_rxq_get_name(poll->rxq->rx));
+    }
+
+    /* With MQ enabled, remove the duplicates. */
+    svec_sort_unique(&pmd_poll_list);
+
+    const char *port_name;
+    int i = 0;
+    SVEC_FOR_EACH (i, port_name, &pmd_poll_list) {
+        struct netdev *dev = netdev_from_name(port_name);
+        if (dev) {
+            char *link_state = netdev_get_carrier(dev) ? "up" : "down";
+            ka_info_update_port_status(port_name, 0, link_state,
+                                        pmd->core_id, i);
+            netdev_close(dev);
+        }
+    }
+    svec_destroy(&pmd_poll_list);
+
+    port_link_status = ka_get_polled_ports_status(pmd->core_id);
+
+    int pmd_hc_state = ka_get_pmd_health_check_state(pmd->core_id);
+    if (PMD_HC_COMPLETE == pmd_hc_state) {
+        if (port_link_status == ACTIVE_RUN_STATE) {
+            ka_set_pmd_state_ts(pmd->core_id, KA_STATE_ALIVE, 0);
+        }
+    }
 }
 
 static void
diff --git a/lib/keepalive.c b/lib/keepalive.c
index b4d33cc..c306839 100644
--- a/lib/keepalive.c
+++ b/lib/keepalive.c
@@ -437,6 +437,58 @@ ka_stats_run(void)
     return ka_stats;
 }
 
+enum pmdhealth_status ka_get_polled_ports_status(unsigned core_id)
+{
+    if (OVS_UNLIKELY(!ka_info)) {
+        return FAILURE_STATE;
+    }
+
+    int failed = 0;
+    int n_ports = ka_info->ext_stats[core_id].num_poll_ports;
+    for (int i = 0; i < n_ports; i++) {
+        int state;
+        state =
+          ka_info->ext_stats[core_id].port_stats[i].state[PORT_LINK_CHECK];
+        if (state == FAILURE_STATE) {
+            failed = 1;
+            break;
+        }
+    }
+
+    if (!failed) {
+        return ACTIVE_RUN_STATE;
+    } else {
+        return FAILURE_STATE;
+    }
+}
+
+void
+ka_info_update_port_status(const char *port, int qid OVS_UNUSED,
+                           char *link_state, int core_id, int idx)
+{
+    if (OVS_UNLIKELY(!ka_info)) {
+        return;
+    }
+
+    ka_info->ext_stats[core_id].num_poll_ports = idx;
+
+    if (OVS_LIKELY(core_id != NON_PMD_CORE_ID)) {
+        ka_info->ext_stats[core_id].port_stats[idx].port = port;
+        ka_info->ext_stats[core_id].port_stats[idx].link_state =
+                                                           link_state;
+    }
+
+    int state;
+    if (!strcmp(link_state, "down")) {
+        state = FAILURE_STATE;
+    } else {
+        state = ACTIVE_RUN_STATE;
+    }
+
+    ka_info->ext_stats[core_id].port_stats[idx].state[PORT_LINK_CHECK] =
+                                                               state;
+}
+
 static void
 ka_unixctl_pmd_health_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
                            const char *argv[] OVS_UNUSED, void *ka_info_)
diff --git a/lib/keepalive.h b/lib/keepalive.h
index 61697b2..ff4aa3c 100644
--- a/lib/keepalive.h
+++ b/lib/keepalive.h
@@ -47,6 +47,12 @@ enum pmdhealth_check {
     PMD_HC_COMPLETE
 };
 
+enum port_health_check {
+    PORT_LINK_CHECK = 0,
+    PORT_STATS_CHECK,
+    PORT_NUM_CHECKS
+};
+
 struct ka_process_info {
     char name[16];
     int tid;
@@ -60,10 +66,12 @@ struct ka_process_info {
 
 struct poll_port_stats {
     const char *port;
-    int qid;
+    char *link_state;
+    int state[PORT_NUM_CHECKS];
 };
 
 struct pmd_extended_stats {
+    char *health_status;
     struct poll_port_stats *port_stats;
     int num_poll_ports;
 };
@@ -92,6 +100,11 @@ enum keepalive_status {
     ka_init_success
 };
 
+enum pmdhealth_status {
+    FAILURE_STATE = 0,
+    ACTIVE_RUN_STATE
+};
+
 void ka_init(const struct smap *);
 void ka_destroy(void);
 void ka_set_pmd_state_ts(unsigned, enum keepalive_state, uint64_t);
@@ -120,4 +133,7 @@ struct smap *ka_stats_run(void);
 void ka_load_process_list(struct hmap **);
 
 void dispatch_heartbeats(void);
+void ka_info_update_port_status(const char *,int,char *,int,int);
+enum pmdhealth_status ka_get_polled_ports_status(unsigned);
+
 #endif /* keepalive.h */
