diff --git a/ovn/controller/automake.mk b/ovn/controller/automake.mk
index cadfa9c..fdd6788 100644
--- a/ovn/controller/automake.mk
+++ b/ovn/controller/automake.mk
@@ -16,6 +16,8 @@ ovn_controller_ovn_controller_SOURCES = \
 	ovn/controller/patch.h \
 	ovn/controller/ovn-controller.c \
 	ovn/controller/ovn-controller.h \
+	ovn/controller/ovn-dhcp.c \
+	ovn/controller/ovn-dhcp.h \
 	ovn/controller/physical.c \
 	ovn/controller/physical.h
 ovn_controller_ovn_controller_LDADD = ovn/lib/libovn.la lib/libopenvswitch.la
diff --git a/ovn/controller/ovn-dhcp.c b/ovn/controller/ovn-dhcp.c
new file mode 100644
index 0000000..db4442b
--- /dev/null
+++ b/ovn/controller/ovn-dhcp.c
@@ -0,0 +1,493 @@
+
+/* Copyright (c) 2015 Red Hat, Inc.
+ *
+ * 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 "csum.h"
+#include "dp-packet.h"
+#include "dhcp.h"
+#include "lib/dhcp.h"
+#include "ofpbuf.h"
+#include "ofp-actions.h"
+#include "ofp-util.h"
+#include "ovn-controller.h"
+#include "ovn-dhcp.h"
+
+#define DHCP_SERVER_ID     ((uint32_t)0x01010101)
+#define DHCP_LEASE_PERIOD  ((uint32_t)60*60*24) /* 1 day */
+
+#define DHCP_MAGIC_COOKIE (uint32_t)0x63825363
+
+#define DHCP_DEFAULT_NETMASK (uint32_t)0xFFFFFF00
+
+#define DHCP_DEFAULT_IFACE_MTU (uint16_t)1400
+
+#define DHCP_OP_REQUEST  ((uint8_t)1)
+#define DHCP_OP_REPLY    ((uint8_t)2)
+
+#define DHCP_MSG_DISCOVER ((uint8_t)1)
+#define DHCP_MSG_OFFER    ((uint8_t)2)
+#define DHCP_MSG_REQUEST  ((uint8_t)3)
+#define DHCP_MSG_ACK      ((uint8_t)5)
+#define DHCP_MSG_NACK     ((uint8_t)6)
+
+/* DHCP options */
+#define DHCP_OPT_NETMASK              ((uint8_t)1)
+#define DHCP_OPT_ROUTER               ((uint8_t)3)
+#define DHCP_OPT_DNS_SERVER           ((uint8_t)6)
+#define DHCP_OPT_LOG_SERVER           ((uint8_t)7)
+#define DHCP_OPT_LPR_SERVER           ((uint8_t)9)
+#define DHCP_OPT_BOOT_FILE_SIZE       ((uint8_t)13)
+#define DHCP_OPT_DOMAIN_NAME          ((uint8_t)15)
+#define DHCP_OPT_SWAP_SERVER          ((uint8_t)16)
+#define DHCP_OPT_IP_FORWARD_ENABLE    ((uint8_t)19)
+#define DHCP_OPT_POLICY_FILTER        ((uint8_t)21)
+#define DHCP_OPT_DEFAULT_TTL          ((uint8_t)23)
+#define DHCP_OPT_IFACE_MTU            ((uint8_t)26)
+#define DHCP_OPT_RD                   ((uint8_t)31)
+#define DHCP_OPT_ROUTER_SOLICITATION  ((uint8_t)32)
+#define DHCP_OPT_ARP_TIMEOUT          ((uint8_t)35)
+#define DHCP_OPT_ETH_ENCAP            ((uint8_t)36)
+#define DHCP_OPT_TCP_TTL              ((uint8_t)37)
+#define DHCP_OPT_TCP_KEEPALIVE        ((uint8_t)38)
+#define DHCP_OPT_NIS_DOMAIN           ((uint8_t)40)
+#define DHCP_OPT_NIS_SERVER           ((uint8_t)41)
+#define DHCP_OPT_NTP_SERVER           ((uint8_t)42)
+#define DHCP_OPT_ADDR_REQ             ((uint8_t)50)
+#define DHCP_OPT_LEASE_TIME           ((uint8_t)51)
+#define DHCP_OPT_MSG_TYPE             ((uint8_t)53)
+#define DHCP_OPT_SERVER_ID            ((uint8_t)54)
+#define DHCP_OPT_PARAMS               ((uint8_t)55)
+#define DHCP_OPT_TFTP_SERVER          ((uint8_t)66)
+#define DHCP_OPT_END                  ((uint8_t)255)
+
+#define DHCP_OPT_NETMASK_KEY "dhcp-opt-1"
+#define DHCP_OPT_ROUTER_KEY "dhcp-opt-3"
+
+struct dhcp_packet_ctx {
+    struct controller_ctx *ctrl_ctx;
+    struct ofputil_packet_in *pin;
+    struct flow *flow;
+    struct dp_packet *packet;
+    const struct sbrec_port_binding *binding;
+    uint8_t message_type;
+    ovs_be32 requested_ipv4;
+    ovs_be32 offered_ipv4;
+};
+
+struct dhcp_option_header {
+    uint8_t option;
+    uint8_t len;
+};
+
+#define OPTION_PAYLOAD(opt) ((char *)opt + sizeof(struct dhcp_option_header))
+#define OPTION_PAYLOAD_END(opt) ((char *)opt + \
+        sizeof(struct dhcp_option_header) + opt->len)
+
+static int
+add_option_to_dhcp_resp_buf(char *buf, uint8_t dhcp_option, char *option_data)
+{
+    struct dhcp_option_header *opt;
+    int ret_len = 0;
+    switch(dhcp_option) {
+    case DHCP_OPT_NETMASK:
+    case DHCP_OPT_ROUTER:
+    case DHCP_OPT_DNS_SERVER:
+    case DHCP_OPT_LOG_SERVER:
+    case DHCP_OPT_LPR_SERVER:
+    case DHCP_OPT_SWAP_SERVER:
+    case DHCP_OPT_POLICY_FILTER:
+    case DHCP_OPT_ROUTER_SOLICITATION:
+    case DHCP_OPT_NIS_SERVER:
+    case DHCP_OPT_NTP_SERVER:
+    case DHCP_OPT_TFTP_SERVER:
+    {
+        /* option value type - ip address(es) */
+        ovs_be32 ip_addr;
+        opt = (struct dhcp_option_header *) buf;
+        opt->option = dhcp_option;
+        opt->len = 0;
+        int scan_len = 0;
+        ret_len = 2;
+        /* option value can have multiple ip addresses.
+         * Eg. dhcp-opt-6=8.8.8.8 10.10.10.10" for DNS option
+         */
+        while(ovs_scan_len(option_data, &scan_len, IP_SCAN_FMT,
+                           IP_SCAN_ARGS(&ip_addr))) {
+            *((uint32_t *) OPTION_PAYLOAD_END(opt)) = ip_addr;
+            opt->len += sizeof(ovs_be32);
+            option_data += (scan_len + 1);
+            ret_len += 4;
+            scan_len = 0;
+        }
+        break;
+    }
+    /* option value type - bool */
+    case DHCP_OPT_IP_FORWARD_ENABLE:
+    case DHCP_OPT_ETH_ENCAP:
+    case DHCP_OPT_RD:
+    /* option value type - uint8_t */
+    case DHCP_OPT_DEFAULT_TTL:
+    case DHCP_OPT_TCP_TTL:
+    {
+        buf[0] = dhcp_option;
+        buf[1] = 1;
+        uint8_t value;
+        if (ovs_scan(option_data, "%hhu", &value)) {
+            ret_len = 3;
+            buf[2] = (uint8_t) value;
+        }
+        break;
+    }
+    /* option value type - uint16_t */
+    case DHCP_OPT_BOOT_FILE_SIZE:
+    case DHCP_OPT_IFACE_MTU:
+    {
+        buf[0] = dhcp_option;
+        buf[1] = 2;
+        uint16_t value;
+        if (ovs_scan(option_data, "%h"PRIu16, &value)) {
+            ret_len = 4;
+            (*(uint16_t *)&buf[2]) = htons(value);
+        }
+        break;
+    }
+    /* option value type - uint32_t */
+    case DHCP_OPT_ARP_TIMEOUT:
+    case DHCP_OPT_TCP_KEEPALIVE:
+        buf[0] = dhcp_option;
+        buf[1] = 4;
+        uint32_t value;
+        if (ovs_scan(option_data, "%"PRIu32, &value)) {
+            ret_len = 6;
+            (*(uint32_t *)&buf[2]) = htonl(value);
+        }
+        break;
+
+    /* option value type - string */
+    case DHCP_OPT_DOMAIN_NAME:
+    case DHCP_OPT_NIS_DOMAIN:
+    {
+        size_t len = strlen(option_data);
+        buf[0] = dhcp_option;
+        buf[1] = (uint8_t) len;
+        memcpy((void *)&buf[2], option_data, len);
+        ret_len = 2 + len;
+    }
+    }
+
+    return ret_len;
+}
+
+static void
+compose_dhcp_options(struct dhcp_packet_ctx *ctx, char *ret,
+                     uint32_t * ret_len)
+{
+    char *start = ret;
+
+    /* Magic cookie */
+    *(uint32_t *) ret = htonl(DHCP_MAGIC_COOKIE);
+    ret += (sizeof (uint32_t));
+
+    /* Dhcp option - type */
+    ret[0] = (uint8_t) DHCP_OPT_MSG_TYPE;
+    ret[1] = (uint8_t) 1;
+
+    if (ctx->message_type == DHCP_MSG_DISCOVER) {
+        /* DHCP DISCOVER. Set the dhcp message type as DHCP OFFER */
+        ret[2] = (uint8_t)DHCP_MSG_OFFER;
+    }
+    else {
+        /* DHCP REQUEST, set the message type as DHCP ACK */
+        ret[2] = (uint8_t) DHCP_MSG_ACK;
+    }
+    ret += 3;
+
+    /* Dhcp server id*/
+    ret[0] = (uint8_t)DHCP_OPT_SERVER_ID;
+    ret[1] = (uint8_t)4;
+    *((uint32_t *)&ret[2]) = htonl(DHCP_SERVER_ID);
+    ret += 6;
+
+    int option_code;
+    struct smap_node *node;
+    int len;
+    bool mtu_set = false;
+    bool lease_period_set = false;
+    SMAP_FOR_EACH(node, &ctx->binding->options) {
+        if (strncmp(node->key, "dhcp-opt-", 9)) {
+            continue;
+        }
+        option_code = 0;
+        if(!ovs_scan(&node->key[9], "%d", &option_code)) {
+            continue;
+        }
+        if (!option_code) {
+            continue;
+        }
+        len = add_option_to_dhcp_resp_buf(ret, option_code,
+                                          node->value);
+        if (len) {
+            if (option_code == DHCP_OPT_IFACE_MTU) {
+                mtu_set = true;
+            }else if(option_code == DHCP_OPT_LEASE_TIME) {
+                lease_period_set = true;
+            }
+            ret += len;
+        }
+    }
+
+    if (!lease_period_set) {
+        ret[0] = (uint8_t)DHCP_OPT_LEASE_TIME;
+        ret[1] = (uint8_t)4;
+        *((uint32_t *)&ret[2]) = htonl(DHCP_LEASE_PERIOD);
+        ret += 6;
+    }
+
+    if (!mtu_set) {
+        /*  Set the default MTU to 1400 to ensure that the the VM traffic
+         * after adding the tunnel headers
+         * do not exceed the MTU of underlying network
+         */
+        ret[0] = (uint8_t)DHCP_OPT_IFACE_MTU;
+        ret[1] = (uint8_t)2;
+        *((uint16_t *)&ret[2]) = htons(DHCP_DEFAULT_IFACE_MTU);
+        ret += 4;
+    }
+
+    /* Padding */
+    *((uint32_t *) ret) = 0;
+    ret += 4;
+
+    /* End */
+    ret[0] = DHCP_OPT_END;
+    ret += 1;
+
+    /* Padding */
+    *((uint32_t *) ret) = 0;
+    ret += 4;
+
+    *ret_len = (ret - start);
+}
+
+static bool
+is_dhcp_enabled_for_port(struct dhcp_packet_ctx *ctx)
+{
+    const struct sbrec_port_binding *binding;
+    struct eth_addr mac;
+
+    ctx->binding = NULL;
+    SBREC_PORT_BINDING_FOR_EACH(binding, ctx->ctrl_ctx->ovnsb_idl) {
+        for (size_t i = 0; i < binding->n_mac; i++) {
+            if (!ovs_scan(binding->mac[i],
+                          ETH_ADDR_SCAN_FMT" "IP_SCAN_FMT,
+                          ETH_ADDR_SCAN_ARGS(mac),
+                          IP_SCAN_ARGS(&ctx->offered_ipv4))) {
+                continue;
+            }
+            if (eth_addr_to_uint64(mac) ==
+                eth_addr_to_uint64(ctx->flow->dl_src)) {
+                ctx->binding = binding;
+                break;
+            }
+        }
+        if (ctx->binding) {
+            break;
+        }
+    }
+    if (!ctx->binding) {
+        return false;
+    }
+
+    /* check if dhcp options - netmask and router are set */
+    bool opt_netmask_present = false;
+    bool opt_router_present = false;
+    struct smap_node *node;
+    SMAP_FOR_EACH(node, &ctx->binding->options) {
+        if (!strcmp(node->key, DHCP_OPT_NETMASK_KEY)) {
+            opt_netmask_present = true;
+        }
+        else if(!strcmp(node->key, DHCP_OPT_ROUTER_KEY)) {
+            opt_router_present = true;
+        }
+
+        if (opt_netmask_present && opt_router_present) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+static bool
+compose_dhcp_response(struct dhcp_packet_ctx *ctx,
+                      struct dhcp_header const *in_dhcp,
+                      struct dp_packet *out_packet)
+{
+    /* TODO: Frame the proper eth_addr */
+    struct eth_addr eth_addr = {.ea = {0x9a, 0x56, 0x02, 0x53, 0xc2, 0x40} };
+    char options[1024];
+    uint32_t options_length = 0;
+
+    memset(options, 0, sizeof (options));
+
+    compose_dhcp_options(ctx, options, &options_length);
+
+    size_t out_packet_length = ETH_HEADER_LEN + IP_HEADER_LEN + \
+                               UDP_HEADER_LEN + DHCP_HEADER_LEN + \
+                               options_length;
+
+    dp_packet_init(out_packet, out_packet_length);
+    dp_packet_clear(out_packet);
+    dp_packet_prealloc_tailroom(out_packet, out_packet_length);
+
+    struct eth_header *eth;
+
+    eth = dp_packet_put_zeros(out_packet, sizeof (*eth));
+    eth->eth_dst = ctx->flow->dl_src;
+    eth->eth_src = eth_addr;
+    eth->eth_type = ctx->flow->dl_type;
+
+    struct ip_header *ip;
+
+    ip = dp_packet_put_zeros(out_packet, sizeof (*ip));
+    ip->ip_ihl_ver = IP_IHL_VER(5, 4);
+    ip->ip_tos = ctx->flow->nw_tos;
+    ip->ip_ttl = ctx->flow->nw_ttl;
+    ip->ip_proto = IPPROTO_UDP;
+    put_16aligned_be32(&ip->ip_src, (ovs_be32) 0x0);
+    put_16aligned_be32(&ip->ip_dst, ctx->offered_ipv4);
+
+    struct udp_header *udp;
+
+    udp = dp_packet_put_zeros(out_packet, sizeof (*udp));
+    udp->udp_src = htons(ofp_to_u16(DHCP_SERVER_PORT));
+    udp->udp_dst = htons(ofp_to_u16(DHCP_CLIENT_PORT));
+    struct dhcp_header *dhcp;
+
+    dhcp = dp_packet_put_zeros(out_packet, sizeof (*dhcp));
+    memcpy(dhcp, in_dhcp, sizeof (struct dhcp_header));
+    dhcp->op = DHCP_OP_REPLY;
+    dhcp->yiaddr = ctx->offered_ipv4;
+
+    void *opts = dp_packet_put_zeros(out_packet, options_length);
+
+    memcpy(opts, options, options_length);
+
+    int udp_len = sizeof (*dhcp) + options_length + UDP_HEADER_LEN;
+
+    udp->udp_len = htons(ofp_to_u16(udp_len));
+    ip->ip_tot_len = htons(ofp_to_u16(IP_HEADER_LEN + udp_len));
+    ip->ip_csum = csum(ip, sizeof *ip);
+    udp->udp_csum = 0;
+    return true;
+}
+
+static struct ofpbuf *
+process_dhcp_packet(struct dhcp_packet_ctx *ctx,
+                    enum ofputil_protocol of_proto)
+{
+    struct dhcp_header const *dhcp_data =
+        dp_packet_get_udp_payload(ctx->packet);
+    struct dp_packet out;
+    struct ofputil_packet_out ofpacket_out;
+    struct ofpbuf ofpacts, *buf;
+    char const *footer = (char *) dhcp_data + sizeof (*dhcp_data);
+    uint32_t cookie = *(uint32_t *) footer;
+
+    if (dhcp_data->op != DHCP_OP_REQUEST) {
+        return NULL;
+    }
+    if (cookie != htonl(DHCP_MAGIC_COOKIE)) {
+        /* Cookie validation failed */
+        return NULL;
+    }
+
+    footer += sizeof (uint32_t);
+    size_t dhcp_data_size = dp_packet_l4_size(ctx->packet);
+
+    for (struct dhcp_option_header const *opt =
+         (struct dhcp_option_header *)footer;
+         footer < (char *) dhcp_data + dhcp_data_size;
+         footer += (sizeof (*opt) + opt->len)) {
+        opt = (struct dhcp_option_header *) footer;
+        switch (opt->option) {
+        case DHCP_OPT_MSG_TYPE:
+            {
+                ctx->message_type = *(uint8_t *) OPTION_PAYLOAD(opt);
+                if (ctx->message_type != DHCP_MSG_DISCOVER &&
+                    ctx->message_type != DHCP_MSG_REQUEST) {
+                    return NULL;
+                }
+                break;
+            }
+        case DHCP_OPT_ADDR_REQ:
+            /* requested ip address */
+            ctx->requested_ipv4 = *(ovs_be32 *) OPTION_PAYLOAD(opt);
+            break;
+        case DHCP_OPT_PARAMS:
+            /* XXX: Ignoring opt params from the client for now as
+             * we are sending the dhcp options set by the CMS for the port.
+             * May be this needs to be revisited.
+             */
+            break;
+        }
+
+    }
+
+    ofpbuf_init(&ofpacts, 0);
+    ofpbuf_clear(&ofpacts);
+
+    if (is_dhcp_enabled_for_port(ctx)) {
+        compose_dhcp_response(ctx, dhcp_data, &out);
+        ofpact_put_OUTPUT(&ofpacts)->port = OFPP_IN_PORT;
+        ofpacket_out.packet = dp_packet_data(&out);
+        ofpacket_out.packet_len = dp_packet_size(&out);
+    } else {
+        /* ovn controller doesn't have enough information to handle the dhcp
+         * request. Flood the packet so that the dhcp server if running can
+         * respond
+         */
+        ofpact_put_OUTPUT(&ofpacts)->port = OFPP_FLOOD;
+        ofpacket_out.packet = dp_packet_data(ctx->packet);
+        ofpacket_out.packet_len = dp_packet_size(ctx->packet);
+    }
+
+    ofpacket_out.buffer_id = UINT32_MAX;
+    ofpacket_out.in_port = ctx->pin->flow_metadata.flow.in_port.ofp_port;
+    ofpacket_out.ofpacts = ofpacts.data;
+    ofpacket_out.ofpacts_len = ofpacts.size;
+    buf = ofputil_encode_packet_out(&ofpacket_out, of_proto);
+    ofpbuf_uninit(&ofpacts);
+    return buf;
+}
+
+bool
+ovn_dhcp_process_packet(struct controller_ctx * ctx,
+                        struct ofputil_packet_in * pin,
+                        enum ofputil_protocol ofp_proto,
+                        struct flow *flow,
+                        struct dp_packet *packet,
+                        struct ofpbuf **ret_buf)
+{
+    struct dhcp_packet_ctx dhcp_ctx = {
+        .ctrl_ctx = ctx,
+        .pin = pin,
+        .flow = flow,
+        .packet = packet,
+    };
+    *ret_buf = process_dhcp_packet(&dhcp_ctx, ofp_proto);
+    return (*ret_buf != NULL);
+}
diff --git a/ovn/controller/ovn-dhcp.h b/ovn/controller/ovn-dhcp.h
new file mode 100644
index 0000000..9d8c500
--- /dev/null
+++ b/ovn/controller/ovn-dhcp.h
@@ -0,0 +1,34 @@
+
+/* Copyright (c) 2015 Red Hat, Inc.
+ *
+ * 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.
+ */
+
+#ifndef OVN_DHCP_H
+#define OVN_DHCP_H
+
+#include "ofp-util.h"
+
+struct controller_ctx;
+struct ofpbuf;
+struct flow;
+struct dp_packet;
+
+bool ovn_dhcp_process_packet(struct controller_ctx * ctx,
+                             struct ofputil_packet_in * pin,
+                             enum ofputil_protocol ofp_proto,
+                             struct flow *flow,
+                             struct dp_packet *packet,
+                             struct ofpbuf **ret_buf);
+
+#endif
diff --git a/ovn/controller/pinctrl.c b/ovn/controller/pinctrl.c
index 9e7caf4..73d36b6 100644
--- a/ovn/controller/pinctrl.c
+++ b/ovn/controller/pinctrl.c
@@ -16,6 +16,7 @@
 
 #include <config.h>
 #include "dirs.h"
+#include "dp-packet.h"
 #include "pinctrl.h"
 #include "ofp-msgs.h"
 #include "ofp-print.h"
@@ -24,9 +25,13 @@
 #include "openvswitch/vlog.h"
 #include "socket-util.h"
 #include "vswitch-idl.h"
+#include "ovn-dhcp.h"
 
 VLOG_DEFINE_THIS_MODULE(pinctrl);
 
+#define DHCP_CLIENT_PORT 68
+#define DHCP_SERVER_PORT 67
+
 /* OpenFlow connection to the switch. */
 static struct rconn *swconn;
 
@@ -73,11 +78,35 @@ set_switch_config(struct rconn *swconn, const struct ofp_switch_config *config)
     queue_msg(request);
 }
 
+static enum ofputil_protocol
+pinctrl_ofp_proto(void)
+{
+    enum ofp_version version;
+
+    version = rconn_get_version(swconn);
+    return ofputil_protocol_from_ofp_version(version);
+}
+
+static inline bool
+is_dhcp_packet(struct flow *flow)
+{
+    if (flow->dl_type == htons(ETH_TYPE_IP) &&
+        flow->nw_proto == IPPROTO_UDP &&
+        flow->nw_src == INADDR_ANY &&
+        flow->nw_dst == INADDR_BROADCAST &&
+        flow->tp_src == htons(DHCP_CLIENT_PORT) &&
+        flow->tp_dst == htons(DHCP_SERVER_PORT)) {
+        return true;
+    }
+    return false;
+}
+
 static void
 process_packet_in(struct controller_ctx *ctx OVS_UNUSED,
                   const struct ofp_header *msg)
 {
     struct ofputil_packet_in pin;
+    struct ofpbuf *buf = NULL;
 
     if (ofputil_decode_packet_in(&pin, msg) != 0) {
         return;
@@ -86,7 +115,19 @@ process_packet_in(struct controller_ctx *ctx OVS_UNUSED,
         return;
     }
 
-    /* XXX : process the received packet */
+    struct flow flow;
+    struct dp_packet packet;
+    dp_packet_use_const(&packet, pin.packet, pin.packet_len);
+    flow_extract(&packet, &flow);
+
+    if (is_dhcp_packet(&flow)) {
+        ovn_dhcp_process_packet(ctx, &pin, pinctrl_ofp_proto(),
+                                &flow, &packet, &buf);
+        if (buf) {
+            rconn_send(swconn, buf, NULL);
+        }
+    }
+
 }
 
 static void
diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml
index b6eef03..2aae07e 100644
--- a/ovn/ovn-nb.xml
+++ b/ovn/ovn-nb.xml
@@ -181,6 +181,35 @@
           Required.  A logical switch name connected by the VTEP gateway.
         </column>
       </group>
+
+      <group title="Dhcp options for vm ports">
+        <p>
+          These options apply when <ref column="type"/> is
+          <code>(empty string)</code>. These options are used by the
+          <code>ovn-controller</code> to reply to the dhcp requests from the
+          vm ports.
+          The format of the key should be "dhcp-opt-OPTCODE" where OPTCODE is
+          the dhcp option code.
+          Eg. To set netmask dhcp option, the key should be "dhcp-opt-1".
+          <code>ovn-controller</code> will reply to the dhcp packet only
+          if dhcp option netmask - "dhcp-opt-1" and  dhcp option router
+          "dhcp-opt-3" are set.
+          <code>ovn-controller</code> expects the CMS plugin to set the values
+          of the dhcp options as defined in the RFC 2132.
+        </p>
+
+        <column name="options" key="dhcp-opt-1">
+          Optional. Dhcp option netmask value to be returned by the
+          <code>ovn-controller</code> to the DHCP discover/request
+          from the vm port.
+        </column>
+
+        <column name="options" key="dhcp-opt-3">
+          Optional. Dhcp option router value to be returned by the
+          <code>ovn-controller</code> to the DHCP discover/request
+          from the vm port.
+        </column>
+      </group>
     </group>
 
     <group title="Containers">
diff --git a/ovn/ovn-sb.xml b/ovn/ovn-sb.xml
index e674f3a..03f96fc 100644
--- a/ovn/ovn-sb.xml
+++ b/ovn/ovn-sb.xml
@@ -1300,6 +1300,35 @@ tcp.flags = RST;
       </column>
     </group>
 
+    <group title="Dhcp options for vm ports">
+        <p>
+          These options apply when <ref column="type"/> is
+          <code>(empty string)</code>. These options are used by the
+          <code>ovn-controller</code> to reply to the dhcp requests from the
+          vm ports.
+          The format of the key should be "dhcp-opt-OPTCODE" where OPTCODE is
+          the dhcp option code.
+          Eg. To set netmask dhcp option, the key should be "dhcp-opt-1".
+          <code>ovn-controller</code> will reply to the dhcp packet only
+          if dhcp option netmask - "dhcp-opt-1" and  dhcp option router
+          "dhcp-opt-3" are set.
+          <code>ovn-controller</code> expects the CMS plugin to set the values
+          of the dhcp options as defined in the RFC 2132.
+        </p>
+
+        <column name="options" key="dhcp-opt-1">
+          Optional. Dhcp option netmask value to be returned by the
+          <code>ovn-controller</code> to the DHCP discover/request
+          from the vm port.
+        </column>
+
+        <column name="options" key="dhcp-opt-3">
+          Optional. Dhcp option router value to be returned by the
+          <code>ovn-controller</code> to the DHCP discover/request
+          from the vm port.
+        </column>
+    </group>
+
     <group title="Nested Containers">
       <p>
         These columns support containers nested within a VM.  Specifically,
