diff --git a/northd/northd.c b/northd/northd.c
index 2c3560ce2..870427fce 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -91,7 +91,6 @@ static bool use_ct_inv_match = true;
 static bool default_acl_drop;
 
 #define MAX_OVN_TAGS 4096
-
 
 /* Due to various hard-coded priorities need to implement ACLs, the
  * northbound database supports a smaller range of ACL priorities than
@@ -153,6 +152,8 @@ static bool default_acl_drop;
 #define REGBIT_LOOKUP_NEIGHBOR_IP_RESULT "reg9[3]"
 #define REGBIT_DST_NAT_IP_LOCAL "reg9[4]"
 #define REGBIT_KNOWN_LB_SESSION "reg9[6]"
+#define REGBIT_DHCP_RELAY_REQ_CHK "reg9[7]"
+#define REGBIT_DHCP_RELAY_RESP_CHK "reg9[8]"
 
 /* Register to store the eth address associated to a router port for packets
  * received in S_ROUTER_IN_ADMISSION.
@@ -168,6 +169,7 @@ static bool default_acl_drop;
 #define REG_NEXT_HOP_IPV6 "xxreg0"
 #define REG_SRC_IPV4 "reg1"
 #define REG_SRC_IPV6 "xxreg1"
+#define REG_DHCP_RELAY_DIP_IPV4 "reg2"
 #define REG_ROUTE_TABLE_ID "reg7"
 
 /* Register used to store backend ipv6 address
@@ -232,7 +234,7 @@ static bool default_acl_drop;
  * | R1  |   SRC_IPV4 for ARP-REQ    | 0 |                 | R |                                    |
  * |     |      (>= IP_INPUT)        |   |                 | E |     NEXT_HOP_IPV6 (>= DEFRAG )     |
  * +-----+---------------------------+---+-----------------+ G |                                    |
- * | R2  |        UNUSED             | X |                 | 0 |                                    |
+ * | R2     REG_DHCP_RELAY_DIP_IPV4  | X |                 | 0 |                                    |
  * |     |                           | R |                 |   |                                    |
  * +-----+---------------------------+ E |     UNUSED      |   |                                    |
  * | R3  |        UNUSED             | G |                 |   |                                    |
@@ -259,7 +261,9 @@ static bool default_acl_drop;
  * |     |   EGRESS_LOOPBACK/        | G |     UNUSED      |
  * | R9  |   PKT_LARGER/             | 4 |                 |
  * |     |   LOOKUP_NEIGHBOR_RESULT/ |   |                 |
- * |     |   SKIP_LOOKUP_NEIGHBOR}   |   |                 |
+ * |     |   SKIP_LOOKUP_NEIGHBOR/   |   |                 |
+ * |     |REGBIT_DHCP_RELAY_REQ_CHK/ |   |                 |
+ * |     |REGBIT_DHCP_RELAY_RESP_CHK}|   |                 |
  * |     |                           |   |                 |
  * |     | REG_ORIG_TP_DPORT_ROUTER  |   |                 |
  * |     |                           |   |                 |
@@ -8555,6 +8559,85 @@ build_dhcpv6_options_flows(struct ovn_port *op,
     ds_destroy(&match);
 }
 
+static const char *
+ls_dhcp_relay_port(const struct ovn_datapath *od)
+{
+    return smap_get(&od->nbs->other_config, "dhcp_relay_port");
+}
+
+static void
+build_lswitch_dhcp_relay_flows(struct ovn_port *op,
+                           const struct hmap *ls_ports,
+                           struct lflow_table *lflows)
+{
+    if (op->nbrp || !op->nbsp) {
+        return;
+    }
+
+    /* consider only ports attached to VMs */
+    if (strcmp(op->nbsp->type, "")) {
+        return;
+    }
+
+    if (!op->od || !op->od->n_router_ports ||
+        !op->od->nbs) {
+        return;
+    }
+
+    /* configure dhcp relay flows only when peer router  has
+     * relay config enabled */
+    const char *dhcp_relay_port = ls_dhcp_relay_port(op->od);
+    if (!dhcp_relay_port) {
+        return;
+    }
+
+    struct ds match = DS_EMPTY_INITIALIZER;
+    struct ds action = DS_EMPTY_INITIALIZER;
+    struct ovn_port *sp = ovn_port_find(ls_ports, dhcp_relay_port);
+
+    if (!sp || !sp->nbsp || !sp->peer) {
+        return;
+    }
+
+    struct ovn_port *rp = sp->peer;
+    if (!rp || !rp->nbrp || !rp->nbrp->dhcp_relay || rp->peer != sp) {
+        return;
+    }
+
+    char *server_ip_str = NULL;
+    uint16_t port;
+    int addr_family;
+    struct in6_addr server_ip;
+    struct nbrec_dhcp_relay *dhcp_relay = rp->nbrp->dhcp_relay;
+
+    if (!ip_address_and_port_from_lb_key(dhcp_relay->servers, &server_ip_str,
+                                         &server_ip, &port, &addr_family)) {
+        return;
+    }
+
+    if (server_ip_str == NULL) {
+        return;
+    }
+
+    ds_put_format(
+        &match, "inport == %s && eth.src == %s && "
+        "ip4.src == 0.0.0.0 && ip4.dst == 255.255.255.255 && "
+        "udp.src == 68 && udp.dst == 67",
+        op->json_key, op->lsp_addrs[0].ea_s);
+    ds_put_format(&action,
+                  "eth.dst=%s;outport=%s;next;/* DHCP_RELAY_REQ */",
+                  rp->lrp_networks.ea_s,sp->json_key);
+    ovn_lflow_add_with_hint__(lflows, op->od,
+                              S_SWITCH_IN_L2_LKUP, 100,
+                              ds_cstr(&match),
+                              ds_cstr(&action),
+                              op->key,
+                              NULL,
+                              &op->nbsp->header_,
+                              op->lflow_ref);
+    free(server_ip_str);
+}
+
 static void
 build_drop_arp_nd_flows_for_unbound_router_ports(struct ovn_port *op,
                                                  const struct ovn_port *port,
@@ -9156,6 +9239,13 @@ build_lswitch_dhcp_options_and_response(struct ovn_port *op,
         return;
     }
 
+    if (op->od && op->od->nbs
+        && ls_dhcp_relay_port(op->od)) {
+        /* Don't add the DHCP server flows if DHCP Relay is enabled on the
+         * logical switch. */
+        return;
+    }
+
     bool is_external = lsp_is_external(op->nbsp);
     if (is_external && (!op->od->n_localnet_ports ||
                         !op->nbsp->ha_chassis_group)) {
@@ -13636,6 +13726,165 @@ build_dhcpv6_reply_flows_for_lrouter_port(
     }
 }
 
+static void
+build_dhcp_relay_flows_for_lrouter_port(
+        struct ovn_port *op, struct lflow_table *lflows,
+        struct ds *match, struct lflow_ref *lflow_ref)
+{
+    if (!op->nbrp || !op->nbrp->dhcp_relay) {
+        return;
+
+    }
+
+    /* configure dhcp relay flows only when peer switch has
+     * relay config enabled */
+    struct ovn_port *sp = op->peer;
+    if (!sp || !sp->nbsp || sp->peer != op ||
+        !sp->od || !ls_dhcp_relay_port(sp->od)) {
+        return;
+    }
+
+    struct nbrec_dhcp_relay *dhcp_relay = op->nbrp->dhcp_relay;
+    if (!dhcp_relay->servers) {
+        return;
+    }
+
+    int addr_family;
+    /* currently not supporting custom port,
+     * dhcp server port is always set to 67 when installing flows */
+    uint16_t port;
+    char *server_ip_str = NULL;
+    struct in6_addr server_ip;
+
+    if (!ip_address_and_port_from_lb_key(dhcp_relay->servers, &server_ip_str,
+                                         &server_ip, &port, &addr_family)) {
+        return;
+    }
+
+    if (server_ip_str == NULL) {
+        return;
+    }
+
+    struct ds dhcp_action = DS_EMPTY_INITIALIZER;
+    ds_clear(match);
+    ds_put_format(
+        match, "inport == %s && "
+        "ip4.src == 0.0.0.0 && ip4.dst == 255.255.255.255 && "
+        "ip.frag == 0 && udp.src == 68 && udp.dst == 67",
+        op->json_key);
+    ds_put_format(&dhcp_action,
+                REGBIT_DHCP_RELAY_REQ_CHK
+                " = dhcp_relay_req_chk(%s, %s);"
+                "next; /* DHCP_RELAY_REQ */",
+                op->lrp_networks.ipv4_addrs[0].addr_s, server_ip_str);
+
+    ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 110,
+                            ds_cstr(match), ds_cstr(&dhcp_action),
+                            &op->nbrp->header_, lflow_ref);
+
+    ds_clear(match);
+    ds_clear(&dhcp_action);
+
+    ds_put_format(
+        match, "inport == %s && "
+        "ip4.src == 0.0.0.0 && ip4.dst == 255.255.255.255 && "
+        "udp.src == 68 && udp.dst == 67 && "
+        REGBIT_DHCP_RELAY_REQ_CHK,
+        op->json_key);
+    ds_put_format(&dhcp_action,
+                "ip4.src=%s;ip4.dst=%s;udp.src=67;next; /* DHCP_RELAY_REQ */",
+                op->lrp_networks.ipv4_addrs[0].addr_s, server_ip_str);
+
+    ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_DHCP_RELAY_REQ, 100,
+                            ds_cstr(match), ds_cstr(&dhcp_action),
+                            &op->nbrp->header_, lflow_ref);
+
+    ds_clear(match);
+    ds_clear(&dhcp_action);
+
+    ds_put_format(
+        match, "inport == %s && "
+        "ip4.src == 0.0.0.0 && ip4.dst == 255.255.255.255 && "
+        "udp.src == 68 && udp.dst == 67 && "
+        REGBIT_DHCP_RELAY_REQ_CHK" == 0",
+        op->json_key);
+    ds_put_format(&dhcp_action,
+                "drop; /* DHCP_RELAY_REQ */");
+
+    ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_DHCP_RELAY_REQ, 1,
+                            ds_cstr(match), ds_cstr(&dhcp_action),
+                            &op->nbrp->header_, lflow_ref);
+
+    ds_clear(match);
+    ds_clear(&dhcp_action);
+
+    ds_put_format(
+        match, "ip4.src == %s && ip4.dst == %s && "
+        "ip.frag == 0 && udp.src == 67 && udp.dst == 67",
+        server_ip_str, op->lrp_networks.ipv4_addrs[0].addr_s);
+    ds_put_format(&dhcp_action, "next;/* DHCP_RELAY_RESP */");
+    ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 110,
+                            ds_cstr(match), ds_cstr(&dhcp_action),
+                            &op->nbrp->header_, lflow_ref);
+
+    ds_clear(match);
+    ds_clear(&dhcp_action);
+
+    ds_put_format(
+        match, "ip4.src == %s && ip4.dst == %s && "
+        "udp.src == 67 && udp.dst == 67",
+        server_ip_str, op->lrp_networks.ipv4_addrs[0].addr_s);
+    ds_put_format(&dhcp_action,
+          REG_DHCP_RELAY_DIP_IPV4" = ip4.dst;"
+          REGBIT_DHCP_RELAY_RESP_CHK
+          " = dhcp_relay_resp_chk(%s, %s);next;/* DHCP_RELAY_RESP */",
+          op->lrp_networks.ipv4_addrs[0].addr_s, server_ip_str);
+
+    ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_DHCP_RELAY_RESP_CHK,
+                            100,
+                            ds_cstr(match), ds_cstr(&dhcp_action),
+                            &op->nbrp->header_, lflow_ref);
+
+
+    ds_clear(match);
+    ds_clear(&dhcp_action);
+
+    ds_put_format(
+        match, "ip4.src == %s && "
+        REG_DHCP_RELAY_DIP_IPV4" == %s && "
+        "udp.src == 67 && udp.dst == 67 && "
+        REGBIT_DHCP_RELAY_RESP_CHK,
+        server_ip_str, op->lrp_networks.ipv4_addrs[0].addr_s);
+    ds_put_format(&dhcp_action,
+          "ip4.src=%s;udp.dst=68;"
+          "outport=%s;output; /* DHCP_RELAY_RESP */",
+          op->lrp_networks.ipv4_addrs[0].addr_s, op->json_key);
+    ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_DHCP_RELAY_RESP,
+                            100,
+                            ds_cstr(match), ds_cstr(&dhcp_action),
+                            &op->nbrp->header_, lflow_ref);
+
+    ds_clear(match);
+    ds_clear(&dhcp_action);
+
+    ds_put_format(
+        match, "ip4.src == %s && "
+        REG_DHCP_RELAY_DIP_IPV4" == %s && "
+        "udp.src == 67 && udp.dst == 67 && "
+        REGBIT_DHCP_RELAY_RESP_CHK" == 0",
+        server_ip_str, op->lrp_networks.ipv4_addrs[0].addr_s);
+    ds_put_format(&dhcp_action,
+          "drop; /* DHCP_RELAY_RESP */");
+    ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_DHCP_RELAY_RESP,
+                            1,
+                            ds_cstr(match), ds_cstr(&dhcp_action),
+                            &op->nbrp->header_, lflow_ref);
+    ds_clear(match);
+    ds_clear(&dhcp_action);
+
+    free(server_ip_str);
+}
+
 static void
 build_ipv6_input_flows_for_lrouter_port(
         struct ovn_port *op, struct lflow_table *lflows,
@@ -14906,6 +15155,13 @@ static void build_lr_nat_defrag_and_lb_default_flows(
                   lflow_ref);
     ovn_lflow_add(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 0, "1", "next;",
                   lflow_ref);
+    ovn_lflow_add(lflows, od, S_ROUTER_IN_DHCP_RELAY_REQ, 0, "1",
+                  "next;", lflow_ref);
+    ovn_lflow_add(lflows, od, S_ROUTER_IN_DHCP_RELAY_RESP_CHK, 0, "1",
+                  "next;", lflow_ref);
+    ovn_lflow_add(lflows, od, S_ROUTER_IN_DHCP_RELAY_RESP, 0, "1",
+                  "next;", lflow_ref);
+
 
     /* Send the IPv6 NS packets to next table. When ovn-controller
      * generates IPv6 NS (for the action - nd_ns{}), the injected
@@ -15670,6 +15926,7 @@ build_lswitch_and_lrouter_iterate_by_lsp(struct ovn_port *op,
     build_lswitch_icmp_packet_toobig_admin_flows(op, lflows, match, actions);
     build_lswitch_ip_unicast_lookup(op, lflows, actions,
                                     match);
+    build_lswitch_dhcp_relay_flows(op, ls_ports, lflows);
 
     /* Build Logical Router Flows. */
     build_arp_resolve_flows_for_lsp(op, lflows, lr_ports, match, actions);
@@ -15699,6 +15956,8 @@ build_lswitch_and_lrouter_iterate_by_lrp(struct ovn_port *op,
                                                  op->lflow_ref);
     build_dhcpv6_reply_flows_for_lrouter_port(op, lsi->lflows, &lsi->match,
                                               op->lflow_ref);
+    build_dhcp_relay_flows_for_lrouter_port(op, lsi->lflows, &lsi->match,
+                                              op->lflow_ref);
     build_ipv6_input_flows_for_lrouter_port(op, lsi->lflows,
                                             &lsi->match, &lsi->actions,
                                             lsi->meter_groups,
diff --git a/northd/northd.h b/northd/northd.h
index 3f1cd8341..0a349c8f7 100644
--- a/northd/northd.h
+++ b/northd/northd.h
@@ -437,24 +437,29 @@ enum ovn_stage {
     PIPELINE_STAGE(ROUTER, IN,  LOOKUP_NEIGHBOR, 1, "lr_in_lookup_neighbor") \
     PIPELINE_STAGE(ROUTER, IN,  LEARN_NEIGHBOR,  2, "lr_in_learn_neighbor") \
     PIPELINE_STAGE(ROUTER, IN,  IP_INPUT,        3, "lr_in_ip_input")     \
-    PIPELINE_STAGE(ROUTER, IN,  UNSNAT,          4, "lr_in_unsnat")       \
-    PIPELINE_STAGE(ROUTER, IN,  DEFRAG,          5, "lr_in_defrag")       \
-    PIPELINE_STAGE(ROUTER, IN,  LB_AFF_CHECK,    6, "lr_in_lb_aff_check") \
-    PIPELINE_STAGE(ROUTER, IN,  DNAT,            7, "lr_in_dnat")         \
-    PIPELINE_STAGE(ROUTER, IN,  LB_AFF_LEARN,    8, "lr_in_lb_aff_learn") \
-    PIPELINE_STAGE(ROUTER, IN,  ECMP_STATEFUL,   9, "lr_in_ecmp_stateful") \
-    PIPELINE_STAGE(ROUTER, IN,  ND_RA_OPTIONS,   10, "lr_in_nd_ra_options") \
-    PIPELINE_STAGE(ROUTER, IN,  ND_RA_RESPONSE,  11, "lr_in_nd_ra_response") \
-    PIPELINE_STAGE(ROUTER, IN,  IP_ROUTING_PRE,  12, "lr_in_ip_routing_pre")  \
-    PIPELINE_STAGE(ROUTER, IN,  IP_ROUTING,      13, "lr_in_ip_routing")      \
-    PIPELINE_STAGE(ROUTER, IN,  IP_ROUTING_ECMP, 14, "lr_in_ip_routing_ecmp") \
-    PIPELINE_STAGE(ROUTER, IN,  POLICY,          15, "lr_in_policy")          \
-    PIPELINE_STAGE(ROUTER, IN,  POLICY_ECMP,     16, "lr_in_policy_ecmp")     \
-    PIPELINE_STAGE(ROUTER, IN,  ARP_RESOLVE,     17, "lr_in_arp_resolve")     \
-    PIPELINE_STAGE(ROUTER, IN,  CHK_PKT_LEN,     18, "lr_in_chk_pkt_len")     \
-    PIPELINE_STAGE(ROUTER, IN,  LARGER_PKTS,     19, "lr_in_larger_pkts")     \
-    PIPELINE_STAGE(ROUTER, IN,  GW_REDIRECT,     20, "lr_in_gw_redirect")     \
-    PIPELINE_STAGE(ROUTER, IN,  ARP_REQUEST,     21, "lr_in_arp_request")     \
+    PIPELINE_STAGE(ROUTER, IN,  DHCP_RELAY_REQ,  4, "lr_in_dhcp_relay_req") \
+    PIPELINE_STAGE(ROUTER, IN,  UNSNAT,          5, "lr_in_unsnat")       \
+    PIPELINE_STAGE(ROUTER, IN,  DEFRAG,          6, "lr_in_defrag")       \
+    PIPELINE_STAGE(ROUTER, IN,  LB_AFF_CHECK,    7, "lr_in_lb_aff_check") \
+    PIPELINE_STAGE(ROUTER, IN,  DNAT,            8, "lr_in_dnat")         \
+    PIPELINE_STAGE(ROUTER, IN,  LB_AFF_LEARN,    9, "lr_in_lb_aff_learn") \
+    PIPELINE_STAGE(ROUTER, IN,  ECMP_STATEFUL,   10, "lr_in_ecmp_stateful") \
+    PIPELINE_STAGE(ROUTER, IN,  ND_RA_OPTIONS,   11, "lr_in_nd_ra_options") \
+    PIPELINE_STAGE(ROUTER, IN,  ND_RA_RESPONSE,  12, "lr_in_nd_ra_response") \
+    PIPELINE_STAGE(ROUTER, IN,  IP_ROUTING_PRE,  13, "lr_in_ip_routing_pre")  \
+    PIPELINE_STAGE(ROUTER, IN,  IP_ROUTING,      14, "lr_in_ip_routing")      \
+    PIPELINE_STAGE(ROUTER, IN,  IP_ROUTING_ECMP, 15, "lr_in_ip_routing_ecmp") \
+    PIPELINE_STAGE(ROUTER, IN,  POLICY,          16, "lr_in_policy")          \
+    PIPELINE_STAGE(ROUTER, IN,  POLICY_ECMP,     17, "lr_in_policy_ecmp")     \
+    PIPELINE_STAGE(ROUTER, IN,  DHCP_RELAY_RESP_CHK, 18,                      \
+                  "lr_in_dhcp_relay_resp_chk")                                \
+    PIPELINE_STAGE(ROUTER, IN,  DHCP_RELAY_RESP, 19,                          \
+                  "lr_in_dhcp_relay_resp")                                    \
+    PIPELINE_STAGE(ROUTER, IN,  ARP_RESOLVE,     20, "lr_in_arp_resolve")     \
+    PIPELINE_STAGE(ROUTER, IN,  CHK_PKT_LEN,     21, "lr_in_chk_pkt_len")     \
+    PIPELINE_STAGE(ROUTER, IN,  LARGER_PKTS,     22, "lr_in_larger_pkts")     \
+    PIPELINE_STAGE(ROUTER, IN,  GW_REDIRECT,     23, "lr_in_gw_redirect")     \
+    PIPELINE_STAGE(ROUTER, IN,  ARP_REQUEST,     24, "lr_in_arp_request")     \
                                                                       \
     /* Logical router egress stages. */                               \
     PIPELINE_STAGE(ROUTER, OUT, CHECK_DNAT_LOCAL,   0,                       \
diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema
index a9c5b7af5..a616dbd6b 100644
--- a/ovn-nb.ovsschema
+++ b/ovn-nb.ovsschema
@@ -1,7 +1,7 @@
 {
     "name": "OVN_Northbound",
     "version": "7.3.0",
-    "cksum": "3546526738 34483",
+    "cksum": "3858903371 35372",
     "tables": {
         "NB_Global": {
             "columns": {
@@ -436,6 +436,11 @@
                 "ipv6_prefix": {"type": {"key": "string",
                                       "min": 0,
                                       "max": "unlimited"}},
+                "dhcp_relay": {"type": {"key": {"type": "uuid",
+                                            "refTable": "DHCP_Relay",
+                                            "refType": "strong"},
+                                            "min": 0,
+                                            "max": 1}},
                 "external_ids": {
                     "type": {"key": "string", "value": "string",
                              "min": 0, "max": "unlimited"}},
@@ -534,6 +539,18 @@
                     "type": {"key": "string", "value": "string",
                              "min": 0, "max": "unlimited"}}},
             "isRoot": true},
+        "DHCP_Relay": {
+            "columns": {
+                "name": {"type": "string"},
+                "servers": {"type": {"key": "string",
+                                       "min": 0,
+                                       "max": 1}},
+                "options": {"type": {"key": "string", "value": "string",
+                                     "min": 0, "max": "unlimited"}},
+                "external_ids": {
+                    "type": {"key": "string", "value": "string",
+                             "min": 0, "max": "unlimited"}}},
+            "isRoot": true},
         "Connection": {
             "columns": {
                 "target": {"type": "string"},
diff --git a/ovn-nb.xml b/ovn-nb.xml
index e0b983ed6..6f0210325 100644
--- a/ovn-nb.xml
+++ b/ovn-nb.xml
@@ -703,6 +703,13 @@
         </ul>
       </column>
 
+      <column name="other_config" key="dhcp_relay_port">
+        If set to the name of logical switch port of type <code>router</code>
+        then, DHCP Relay is enabled for this logical switch provided the
+        corresponding <ref table="Logical_Router_Port"/> has DHCP Relay
+        configured.
+      </column>
+
       <column name="other_config" key="mac_only" type='{"type": "boolean"}'>
         Value used to request to assign L2 address only if neither subnet
         nor ipv6_prefix are specified
@@ -3059,6 +3066,11 @@ or
       port has all ingress and egress traffic dropped.
     </column>
 
+    <column name="dhcp_relay">
+      This column is used to enabled DHCP Relay. Please refer
+      to <ref table="DHCP_Relay"/> table.
+    </column>
+
     <group title="Distributed Gateway Ports">
       <p>
         Gateways, as documented under <code>Gateways</code> in the OVN
@@ -4372,6 +4384,33 @@ or
     </group>
   </table>
 
+  <table name="DHCP_Relay" title="DHCP Relay">
+    <p>
+      OVN implements native DHCPv4 relay support which caters to the common
+      use case of relaying the DHCP requests to external DHCP server.
+    </p>
+    <column name="name">
+      <p>
+        A name for the DHCP Relay.
+      </p>
+    </column>
+    <column name="servers">
+      <p>
+        The DHCPv4 server IP address.
+      </p>
+    </column>
+    <column name="options">
+      <p>
+        Future purpose.
+      </p>
+    </column>
+    <group title="Common Columns">
+      <column name="external_ids">
+        See <em>External IDs</em> at the beginning of this document.
+      </column>
+    </group>
+  </table>
+
   <table name="Connection" title="OVSDB client connections.">
     <p>
       Configuration for a database connection to an Open vSwitch database
diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c
index e0f1c3ec9..dd7016fc3 100644
--- a/utilities/ovn-trace.c
+++ b/utilities/ovn-trace.c
@@ -2329,6 +2329,63 @@ execute_put_dhcp_opts(const struct ovnact_put_opts *pdo,
     execute_put_opts(pdo, name, uflow, super);
 }
 
+static void
+execute_dhcpv4_relay_req_chk(const struct ovnact_dhcp_relay *dr,
+                             struct flow *uflow, struct ovs_list *super)
+{
+    ovntrace_node_append(
+        super, OVNTRACE_NODE_ERROR,
+        "/* We assume that this packet is DHCPDISCOVER or DHCPREQUEST. */");
+
+    struct ds s = DS_EMPTY_INITIALIZER;
+    struct mf_subfield dst = expr_resolve_field(&dr->dst);
+    if (!mf_is_register(dst.field->id)) {
+        /* Format assignment. */
+        ds_clear(&s);
+        expr_field_format(&dr->dst, &s);
+        ovntrace_node_append(super, OVNTRACE_NODE_MODIFY,
+                             "%s = 1", ds_cstr(&s));
+    }
+    ds_destroy(&s);
+
+    struct mf_subfield sf = expr_resolve_field(&dr->dst);
+    union mf_subvalue sv = { .u8_val = 1 };
+    mf_write_subfield_flow(&sf, &sv, uflow);
+}
+
+static void
+execute_dhcpv4_relay_resp_chk(const struct ovnact_dhcp_relay *dr,
+                              struct flow *uflow, struct ovs_list *super)
+{
+    ovntrace_node_append(
+        super, OVNTRACE_NODE_ERROR,
+        "/* We assume that this packet is DHCPOFFER or DHCPACK and "
+            "DHCP broadcast flag is set. Dest IP is set to broadcast. "
+            "Dest MAC is set to broadcast but in real network this is unicast "
+            "which is extracted from DHCP header. */");
+
+    /* Assume DHCP broadcast flag is set */
+    uflow->nw_dst = htonl(0xFFFFFFFF);
+    /* Dest MAC is set to broadcast but in real network this is unicast */
+    struct eth_addr bcast_mac = { .ea = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}};
+    uflow->dl_dst = bcast_mac;
+
+    struct ds s = DS_EMPTY_INITIALIZER;
+    struct mf_subfield dst = expr_resolve_field(&dr->dst);
+    if (!mf_is_register(dst.field->id)) {
+        /* Format assignment. */
+        ds_clear(&s);
+        expr_field_format(&dr->dst, &s);
+        ovntrace_node_append(super, OVNTRACE_NODE_MODIFY,
+                             "%s = 1", ds_cstr(&s));
+    }
+    ds_destroy(&s);
+
+    struct mf_subfield sf = expr_resolve_field(&dr->dst);
+    union mf_subvalue sv = { .u8_val = 1 };
+    mf_write_subfield_flow(&sf, &sv, uflow);
+}
+
 static void
 execute_put_nd_ra_opts(const struct ovnact_put_opts *pdo,
                        const char *name, struct flow *uflow,
@@ -3216,6 +3273,16 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len,
                                   "put_dhcpv6_opts", uflow, super);
             break;
 
+        case OVNACT_DHCPV4_RELAY_REQ_CHK:
+            execute_dhcpv4_relay_req_chk(ovnact_get_DHCPV4_RELAY_REQ_CHK(a),
+                                    uflow, super);
+            break;
+
+        case OVNACT_DHCPV4_RELAY_RESP_CHK:
+            execute_dhcpv4_relay_resp_chk(ovnact_get_DHCPV4_RELAY_RESP_CHK(a),
+                                    uflow, super);
+            break;
+
         case OVNACT_PUT_ND_RA_OPTS:
             execute_put_nd_ra_opts(ovnact_get_PUT_DHCPV6_OPTS(a),
                                    "put_nd_ra_opts", uflow, super);
