diff --git a/ovn/controller/binding.c b/ovn/controller/binding.c
index bb76608..f40273f 100644
--- a/ovn/controller/binding.c
+++ b/ovn/controller/binding.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, 2016, 2017 Nicira, Inc.
+/* Copyright (c) 2015, 2016, 2017 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -33,13 +33,26 @@ VLOG_DEFINE_THIS_MODULE(binding);
 
 #define OVN_QOS_TYPE "linux-htb"
 
+#define IS_SUB_PORT(PB)  (PB->parent_port && \
+        PB->parent_port[0])
+
 struct qos_queue {
     struct hmap_node node;
     uint32_t queue_id;
-    uint32_t max_rate;
-    uint32_t burst;
+    uint32_t ingress_max_rate;
+    uint32_t ingress_burst;
+    uint32_t egress_max_rate;
+    uint32_t egress_burst;
 };
 
+static void
+add_column_noalert(struct ovsdb_idl *idl,
+                   const struct ovsdb_idl_column *column)
+{
+    ovsdb_idl_add_column(idl, column);
+    ovsdb_idl_omit_alert(idl, column);
+}
+
 void
 binding_register_ovs_idl(struct ovsdb_idl *ovs_idl)
 {
@@ -59,16 +72,28 @@ binding_register_ovs_idl(struct ovsdb_idl *ovs_idl)
     ovsdb_idl_add_column(ovs_idl, &ovsrec_interface_col_name);
     ovsdb_idl_add_column(ovs_idl, &ovsrec_interface_col_external_ids);
     ovsdb_idl_add_column(ovs_idl, &ovsrec_interface_col_status);
+    add_column_noalert(ovs_idl, 
&ovsrec_interface_col_ingress_policing_rate);
+    add_column_noalert(ovs_idl, 
&ovsrec_interface_col_ingress_policing_burst);
+    add_column_noalert(ovs_idl, &ovsrec_port_col_qos);
 
     ovsdb_idl_add_table(ovs_idl, &ovsrec_table_qos);
-    ovsdb_idl_add_column(ovs_idl, &ovsrec_qos_col_type);
+    add_column_noalert(ovs_idl, &ovsrec_qos_col_external_ids);
+    add_column_noalert(ovs_idl, &ovsrec_qos_col_other_config);
+    add_column_noalert(ovs_idl, &ovsrec_qos_col_type);
+    add_column_noalert(ovs_idl, &ovsrec_qos_col_queues);
+
+    ovsdb_idl_add_table(ovs_idl, &ovsrec_table_queue);
+    add_column_noalert(ovs_idl, &ovsrec_queue_col_external_ids);
+    add_column_noalert(ovs_idl, &ovsrec_queue_col_other_config);
+    add_column_noalert(ovs_idl, &ovsrec_queue_col_dscp);
 }
 
 static void
 get_local_iface_ids(const struct ovsrec_bridge *br_int,
                     struct shash *lport_to_iface,
                     struct sset *local_lports,
-                    struct sset *egress_ifaces)
+                    struct sset *egress_ifaces,
+                    struct shash *lport_to_pport)
 {
     int i;
 
@@ -90,6 +115,7 @@ get_local_iface_ids(const struct ovsrec_bridge *br_int,
 
             if (iface_id && ofport > 0) {
                 shash_add(lport_to_iface, iface_id, iface_rec);
+                shash_add(lport_to_pport, iface_id, port_rec);
                 sset_add(local_lports, iface_id);
             }
 
@@ -163,206 +189,39 @@ add_local_datapath(const struct ldatapath_index 
*ldatapaths,
                          local_datapaths);
 }
 
-static void
-get_qos_params(const struct sbrec_port_binding *pb, struct hmap 
*queue_map)
+static  bool
+get_qos_params(const struct sbrec_port_binding *pb, struct qos_queue 
*queue)
 {
-    uint32_t max_rate = smap_get_int(&pb->options, "qos_max_rate", 0);
-    uint32_t burst = smap_get_int(&pb->options, "qos_burst", 0);
+    uint32_t ingress_max_rate = smap_get_int(&pb->options, 
"qos_ingress_max_rate", 0);
+    uint32_t ingress_burst = smap_get_int(&pb->options, 
"qos_ingress_burst", 0);
+    uint32_t egress_max_rate = smap_get_int(&pb->options, 
"qos_egress_max_rate", 0);
+    uint32_t egress_burst = smap_get_int(&pb->options, 
"qos_egress_burst", 0);
     uint32_t queue_id = smap_get_int(&pb->options, "qdisc_queue_id", 0);
-
-    if ((!max_rate && !burst) || !queue_id) {
+ 
+    if (!queue_id) {
         /* Qos is not configured for this port. */
-        return;
-    }
-
-    struct qos_queue *node = xzalloc(sizeof *node);
-    hmap_insert(queue_map, &node->node, hash_int(queue_id, 0));
-    node->max_rate = max_rate;
-    node->burst = burst;
-    node->queue_id = queue_id;
-}
-
-static const struct ovsrec_qos *
-get_noop_qos(struct controller_ctx *ctx)
-{
-    const struct ovsrec_qos *qos;
-    OVSREC_QOS_FOR_EACH (qos, ctx->ovs_idl) {
-        if (!strcmp(qos->type, "linux-noop")) {
-            return qos;
-        }
-    }
-
-    if (!ctx->ovs_idl_txn) {
-        return NULL;
-    }
-    qos = ovsrec_qos_insert(ctx->ovs_idl_txn);
-    ovsrec_qos_set_type(qos, "linux-noop");
-    return qos;
-}
-
-static bool
-set_noop_qos(struct controller_ctx *ctx, struct sset *egress_ifaces)
-{
-    if (!ctx->ovs_idl_txn) {
-        return false;
-    }
-
-    const struct ovsrec_qos *noop_qos = get_noop_qos(ctx);
-    if (!noop_qos) {
         return false;
     }
 
-    const struct ovsrec_port *port;
-    size_t count = 0;
-
-    OVSREC_PORT_FOR_EACH (port, ctx->ovs_idl) {
-        if (sset_contains(egress_ifaces, port->name)) {
-            ovsrec_port_set_qos(port, noop_qos);
-            count++;
-        }
-        if (sset_count(egress_ifaces) == count) {
-            break;
-        }
-    }
+    queue->ingress_max_rate = ingress_max_rate;
+    queue->ingress_burst = ingress_burst;
+    queue->egress_max_rate = egress_max_rate;
+    queue->egress_burst = egress_burst;
+ 
+    queue->queue_id = queue_id;
     return true;
 }
 
 static void
-set_qos_type(struct netdev *netdev, const char *type)
-{
-    int error = netdev_set_qos(netdev, type, NULL);
-    if (error) {
-        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
-        VLOG_WARN_RL(&rl, "%s: could not set qdisc type \"%s\" (%s)",
-                     netdev_get_name(netdev), type, ovs_strerror(error));
-    }
-}
-
-static void
-setup_qos(const char *egress_iface, struct hmap *queue_map)
-{
-    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5);
-    struct netdev *netdev_phy;
-
-    if (!egress_iface) {
-        /* Queues cannot be configured. */
-        return;
-    }
-
-    int error = netdev_open(egress_iface, NULL, &netdev_phy);
-    if (error) {
-        VLOG_WARN_RL(&rl, "%s: could not open netdev (%s)",
-                     egress_iface, ovs_strerror(error));
-        return;
-    }
-
-    /* Check current qdisc. */
-    const char *qdisc_type;
-    struct smap qdisc_details;
-
-    smap_init(&qdisc_details);
-    if (netdev_get_qos(netdev_phy, &qdisc_type, &qdisc_details) != 0 ||
-        qdisc_type[0] == '\0') {
-        smap_destroy(&qdisc_details);
-        netdev_close(netdev_phy);
-        /* Qos is not supported. */
-        return;
-    }
-    smap_destroy(&qdisc_details);
-
-    /* If we're not actually being requested to do any QoS:
-     *
-     *     - If the current qdisc type is OVN_QOS_TYPE, then we clear the 
qdisc
-     *       type to "".  Otherwise, it's possible that our own leftover 
qdisc
-     *       settings could cause strange behavior on egress.  Also, QoS 
is
-     *       expensive and may waste CPU time even if it's not really in 
use.
-     *
-     *       OVN isn't the only software that can configure qdiscs, and
-     *       physical interfaces are shared resources, so there is some 
risk in
-     *       this strategy: we could disrupt some other program's QoS.
-     *       Probably, to entirely avoid this possibility we would need 
to add
-     *       a configuration setting.
-     *
-     *     - Otherwise leave the qdisc alone. */
-    if (hmap_is_empty(queue_map)) {
-        if (!strcmp(qdisc_type, OVN_QOS_TYPE)) {
-            set_qos_type(netdev_phy, "");
-        }
-        netdev_close(netdev_phy);
-        return;
-    }
-
-    /* Configure qdisc. */
-    if (strcmp(qdisc_type, OVN_QOS_TYPE)) {
-        set_qos_type(netdev_phy, OVN_QOS_TYPE);
-    }
-
-    /* Check and delete if needed. */
-    struct netdev_queue_dump dump;
-    unsigned int queue_id;
-    struct smap queue_details;
-    struct qos_queue *sb_info;
-    struct hmap consistent_queues;
-
-    smap_init(&queue_details);
-    hmap_init(&consistent_queues);
-    NETDEV_QUEUE_FOR_EACH (&queue_id, &queue_details, &dump, netdev_phy) 
{
-        bool is_queue_needed = false;
-
-        HMAP_FOR_EACH_WITH_HASH (sb_info, node, hash_int(queue_id, 0),
-                                 queue_map) {
-            is_queue_needed = true;
-            if (sb_info->max_rate ==
-                smap_get_int(&queue_details, "max-rate", 0)
-                && sb_info->burst == smap_get_int(&queue_details, 
"burst", 0)) {
-                /* This queue is consistent. */
-                hmap_insert(&consistent_queues, &sb_info->node,
-                            hash_int(queue_id, 0));
-                break;
-            }
-        }
-
-        if (!is_queue_needed) {
-            error = netdev_delete_queue(netdev_phy, queue_id);
-            if (error) {
-                VLOG_WARN_RL(&rl, "%s: could not delete queue %u (%s)",
-                             egress_iface, queue_id, 
ovs_strerror(error));
-            }
-        }
-    }
-
-    /* Create/Update queues. */
-    HMAP_FOR_EACH (sb_info, node, queue_map) {
-        if (hmap_contains(&consistent_queues, &sb_info->node)) {
-            hmap_remove(&consistent_queues, &sb_info->node);
-            continue;
-        }
-
-        smap_clear(&queue_details);
-        smap_add_format(&queue_details, "max-rate", "%d", 
sb_info->max_rate);
-        smap_add_format(&queue_details, "burst", "%d", sb_info->burst);
-        error = netdev_set_queue(netdev_phy, sb_info->queue_id,
-                                 &queue_details);
-        if (error) {
-            VLOG_WARN_RL(&rl, "%s: could not configure queue %u (%s)",
-                         egress_iface, sb_info->queue_id, 
ovs_strerror(error));
-        }
-    }
-    smap_destroy(&queue_details);
-    hmap_destroy(&consistent_queues);
-    netdev_close(netdev_phy);
-}
-
-static void
 consider_local_datapath(struct controller_ctx *ctx,
                         const struct ldatapath_index *ldatapaths,
                         const struct lport_index *lports,
                         const struct sbrec_chassis *chassis_rec,
                         const struct sbrec_port_binding *binding_rec,
-                        struct hmap *qos_map,
                         struct hmap *local_datapaths,
                         struct shash *lport_to_iface,
-                        struct sset *local_lports)
+                        struct sset *local_lports,
+                        struct shash *lport_to_pport)
 {
     const struct ovsrec_interface *iface_rec
         = shash_find_data(lport_to_iface, binding_rec->logical_port);
@@ -374,12 +233,15 @@ consider_local_datapath(struct controller_ctx *ctx,
         if (binding_rec->parent_port && binding_rec->parent_port[0]) {
             /* Add child logical port to the set of all local ports. */
             sset_add(local_lports, binding_rec->logical_port);
+            const struct  ovsrec_port *port_rec =
+                shash_find_data(lport_to_pport, 
binding_rec->parent_port);
+            if (port_rec) {
+                VLOG_INFO("port_rec exist, port-name is %s", 
binding_rec->logical_port);
+                shash_add(lport_to_pport, binding_rec->logical_port, 
port_rec);
+            }
         }
         add_local_datapath(ldatapaths, lports, binding_rec->datapath,
                            false, local_datapaths);
-        if (iface_rec && qos_map && ctx->ovs_idl_txn) {
-            get_qos_params(binding_rec, qos_map);
-        }
         /* This port is in our chassis unless it is a localport. */
            if (strcmp(binding_rec->type, "localport")) {
             our_chassis = true;
@@ -442,6 +304,266 @@ consider_local_datapath(struct controller_ctx *ctx,
     }
 }
 
+static void
+del_qos(const struct ovsrec_qos *qos)
+{
+    int n_queue;
+    struct shash queues = SHASH_INITIALIZER(&queues);
+    char uuid_s[UUID_LEN + 1];
+    for (n_queue = 0; n_queue< qos->n_queues; n_queue++) {
+        struct ovsrec_queue *queue = qos->value_queues[n_queue];
+        sprintf(uuid_s, UUID_FMT, UUID_ARGS(&queue->header_.uuid));
+        shash_add(&queues, uuid_s, queue);
+    }
+    ovsrec_qos_delete(qos);
+ 
+    struct shash_node *node, *next_node;
+    SHASH_FOR_EACH_SAFE(node, next_node, &queues) {
+        ovsrec_queue_delete(node->data);
+    }
+}
+
+static void
+clear_port_qos(struct ovsrec_port *port_rec,
+               const struct sbrec_port_binding *binding_rec)
+{
+    if (IS_SUB_PORT(binding_rec) && port_rec->qos) {
+        int n_queue;
+        for (n_queue = 0; n_queue< port_rec->qos->n_queues; n_queue++) {
+            struct ovsrec_queue *queue = 
port_rec->qos->value_queues[n_queue];
+            const char *port_id = smap_get(&queue->external_ids, 
"port_id");
+            if (!strcmp(binding_rec->logical_port, port_id)) {
+                ovsrec_qos_update_queues_delkey(port_rec->qos,
+ port_rec->qos->key_queues[n_queue]);
+                ovsrec_queue_delete(queue);
+                break;
+            }
+        }
+    } else if (port_rec->qos) {
+        if (port_rec->qos) {
+            struct ovsrec_qos *qos = port_rec->qos;
+            ovsrec_port_set_qos(port_rec, NULL);
+            del_qos(qos);
+        }
+ 
+        for (int j = 0; j < port_rec->n_interfaces; j++) {
+            struct ovsrec_interface *iface_rec = port_rec->interfaces[j];
+            const char *iface_id = smap_get(&iface_rec->external_ids,
+                                                "iface-id");
+            if (iface_id && !strcmp(binding_rec->logical_port, iface_id)) 
{
+                if (iface_rec->ingress_policing_burst != 0) {
+ ovsrec_interface_set_ingress_policing_burst(iface_rec,
+                                          0);
+                }
+                if (iface_rec->ingress_policing_rate != 0) {
+                    ovsrec_interface_set_ingress_policing_rate(iface_rec,
+                                          0);
+                }
+            }
+        }
+    }
+}
+
+static char *
+get_port_id(const struct sbrec_port_binding *binding_rec)
+{
+    if (IS_SUB_PORT(binding_rec)) {
+        return binding_rec->parent_port;
+    } else {
+        return binding_rec->logical_port;
+    }
+}
+
+static void
+set_interface_param( struct ovsrec_port *port_rec,
+                           struct qos_queue *qos_param,
+                           const struct sbrec_port_binding *binding_rec)
+{
+    for (int j = 0; j < port_rec->n_interfaces; j++) {
+        /* configure interface  policing burst and policing rate*/
+        struct ovsrec_interface *iface_rec = port_rec->interfaces[j];
+        const char *iface_id = smap_get(&iface_rec->external_ids,
+                                            "iface-id");
+        if (iface_id && !strcmp(binding_rec->logical_port, iface_id)) {
+            if(qos_param->ingress_burst
+                != iface_rec->ingress_policing_burst) {
+                ovsrec_interface_set_ingress_policing_burst(iface_rec,
+ (int64_t)qos_param->ingress_burst);
+            }
+
+            if(qos_param->ingress_max_rate
+                != iface_rec->ingress_policing_rate) {
+                ovsrec_interface_set_ingress_policing_rate(iface_rec,
+ (int64_t)qos_param->ingress_max_rate);
+            }
+            break;
+        }
+    }
+}
+
+static const struct ovsrec_queue *
+get_queue_by_port(struct controller_ctx *ctx,
+                              const char *port_name)
+{
+    const struct ovsrec_queue *queue, *next_queue;
+    OVSREC_QUEUE_FOR_EACH_SAFE(queue, next_queue, ctx->ovs_idl) {
+        const char *port_id =  smap_get(&queue->external_ids, "port_id");
+        if (port_id && !strcmp(port_name, port_id)) {
+            return queue;
+        }
+    }
+    struct ovsrec_queue *newqueue = 
+        ovsrec_queue_insert(ctx->ovs_idl_txn);
+    ovsrec_queue_update_external_ids_setkey(newqueue, "port_id",
+                                   port_name);
+    return newqueue;
+ 
+}
+
+static void
+set_queue(struct controller_ctx *ctx,
+          const struct ovsrec_qos *qos,
+          struct qos_queue *qos_param,
+          const struct sbrec_port_binding *binding_rec)
+{
+    int n_queue;
+    for (n_queue = 0; n_queue< qos->n_queues; n_queue++) {
+        struct ovsrec_queue *queue = qos->value_queues[n_queue];
+        const char *port_id = smap_get(&queue->external_ids, "port_id");
+        if (!strcmp(port_id, binding_rec->logical_port)) {
+            struct smap other_config;
+            smap_init(&other_config);
+            smap_add_format(&other_config, "max-rate", "%d",
+                            qos_param->egress_max_rate*1000);
+            smap_add_format(&other_config, "burst", "%d",
+                            qos_param->egress_burst*1000);
+            ovsrec_queue_set_other_config(queue, &other_config);
+            return;
+        }
+    }
+
+    const struct ovsrec_queue * queue = 
+        get_queue_by_port(ctx, binding_rec->logical_port);
+    struct smap other_config;
+    smap_init(&other_config);
+    smap_add_format(&other_config, "max-rate", "%d",
+                    qos_param->egress_max_rate);
+    smap_add_format(&other_config, "burst", "%d",
+                    qos_param->egress_burst);
+    ovsrec_queue_set_other_config(queue, &other_config);
+    ovsrec_qos_update_queues_setkey(qos,
+                                    (int64_t)qos_param->queue_id,
+                                    queue);
+
+}
+
+static void
+set_qos_para(const struct ovsrec_qos *qos, 
+                           const struct qos_queue *qos_param,
+                           const char *dptype)
+{
+    if (!strcmp(dptype, "netdev")) {
+        ovsrec_qos_set_type(qos, "egress-policer");
+        struct smap other_config;
+        smap_init(&other_config);
+        smap_add_format(&other_config, "cir", "%d",
+                        qos_param->egress_max_rate*1000/8);
+        smap_add_format(&other_config, "cbs", "%d",
+                        qos_param->egress_burst*1000/8);
+        ovsrec_qos_set_other_config(qos, &other_config);
+    } else {
+        ovsrec_qos_set_type(qos, "linux-htb");
+    }
+}
+
+
+static const struct ovsrec_qos *
+get_qos_by_port(struct controller_ctx *ctx,
+                                  const char *port_name) 
+{
+    const struct ovsrec_qos *qos, *next_qos;
+    OVSREC_QOS_FOR_EACH_SAFE(qos, next_qos, ctx->ovs_idl) {
+        const char *port_id =  smap_get(&qos->external_ids, "port_id");
+        if (port_id && !strcmp(port_name, port_id)) {
+            return qos;
+        }
+    } 
+    struct ovsrec_qos *qosnew = ovsrec_qos_insert(ctx->ovs_idl_txn);
+     /* set port_id to external_id of qos */
+    struct smap new_ids;
+    smap_clone(&new_ids, &qosnew->external_ids);
+    smap_add(&new_ids, "port_id", port_name);
+    ovsrec_qos_set_external_ids(qosnew, &new_ids);
+    smap_destroy(&new_ids);
+    return qosnew;
+}
+ 
+static void
+setup_qos(struct controller_ctx *ctx,
+          const struct shash *lport_to_pport,
+          const char *dptype)
+{
+ 
+    struct qos_queue qos_param;
+    struct sset exist_pb = SSET_INITIALIZER(&exist_pb);
+    if (!ctx->ovs_idl_txn) {
+        return;
+    }
+    /* add queue and qos */
+    const struct sbrec_port_binding *binding_rec, *next_bind;
+    SBREC_PORT_BINDING_FOR_EACH_SAFE(binding_rec, next_bind, 
ctx->ovnsb_idl) {
+        sset_add(&exist_pb, binding_rec->logical_port);
+ 
+        struct ovsrec_port *port_rec = shash_find_data(lport_to_pport,
+ binding_rec->logical_port);
+        if (!port_rec) {
+            continue;
+        }
+        if (!get_qos_params(binding_rec, &qos_param)) {
+            clear_port_qos(port_rec, binding_rec);
+            continue;
+        }
+        if (port_rec->qos) {
+            if (!IS_SUB_PORT(binding_rec)) {
+                /* not sub port */
+                set_interface_param(port_rec, &qos_param,
+                                    binding_rec);
+            }
+            set_qos_para(port_rec->qos, &qos_param, dptype);
+            set_queue(ctx, port_rec->qos, &qos_param, binding_rec);
+        } else {
+            char *port_name = get_port_id(binding_rec);
+            const struct ovsrec_qos *qos = get_qos_by_port(ctx, 
port_name);
+            set_qos_para(qos, &qos_param, dptype);
+            ovsrec_port_set_qos(port_rec, qos);
+            if (!IS_SUB_PORT(binding_rec)) {
+                /* not sub port */
+                set_interface_param(port_rec, &qos_param, binding_rec);
+            }
+            set_queue(ctx, qos, &qos_param, binding_rec);
+        }
+    }
+    /* delete not used qos */
+    const struct ovsrec_qos *qos, *next_qos;
+    OVSREC_QOS_FOR_EACH_SAFE(qos, next_qos, ctx->ovs_idl) {
+        const char *port_id =  smap_get(&qos->external_ids, "port_id");
+        if (port_id && !shash_find_data(lport_to_pport, port_id)) {
+            del_qos(qos);
+        }
+    }
+
+    /* delete not used queue */
+    const struct ovsrec_queue *queue, *next_queue;
+    OVSREC_QUEUE_FOR_EACH_SAFE(queue, next_queue, ctx->ovs_idl) {
+        const char *port_id =  smap_get(&queue->external_ids, "port_id");
+        if (port_id && !sset_contains(&exist_pb, port_id)) {
+            ovsrec_queue_delete(queue);
+        }
+    }
+    sset_destroy(&exist_pb);
+ 
+}
+
 void
 binding_run(struct controller_ctx *ctx, const struct ovsrec_bridge 
*br_int,
             const struct sbrec_chassis *chassis_rec,
@@ -455,13 +577,11 @@ binding_run(struct controller_ctx *ctx, const struct 
ovsrec_bridge *br_int,
 
     const struct sbrec_port_binding *binding_rec;
     struct shash lport_to_iface = SHASH_INITIALIZER(&lport_to_iface);
+    struct shash lport_to_pport = SHASH_INITIALIZER(&lport_to_pport);
     struct sset egress_ifaces = SSET_INITIALIZER(&egress_ifaces);
-    struct hmap qos_map;
-
-    hmap_init(&qos_map);
     if (br_int) {
         get_local_iface_ids(br_int, &lport_to_iface, local_lports,
-                            &egress_ifaces);
+                            &egress_ifaces, &lport_to_pport);
     }
 
     /* Run through each binding record to see if it is resident on this
@@ -470,23 +590,16 @@ binding_run(struct controller_ctx *ctx, const struct 
ovsrec_bridge *br_int,
     SBREC_PORT_BINDING_FOR_EACH(binding_rec, ctx->ovnsb_idl) {
         consider_local_datapath(ctx, ldatapaths, lports,
                                 chassis_rec, binding_rec,
-                                sset_is_empty(&egress_ifaces) ? NULL :
-                                &qos_map, local_datapaths, 
&lport_to_iface,
-                                local_lports);
+                                local_datapaths, &lport_to_iface,
+                                local_lports, &lport_to_pport);
 
     }
 
-    if (!sset_is_empty(&egress_ifaces)
-        && set_noop_qos(ctx, &egress_ifaces)) {
-        const char *entry;
-        SSET_FOR_EACH (entry, &egress_ifaces) {
-            setup_qos(entry, &qos_map);
-        }
-    }
+    setup_qos(ctx, &lport_to_pport, br_int->datapath_type);
 
     shash_destroy(&lport_to_iface);
+    shash_destroy(&lport_to_pport);
     sset_destroy(&egress_ifaces);
-    hmap_destroy(&qos_map);
 }
 
 /* Returns true if the database is all cleaned up, false if more work is
diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
index be3b371..c683953 100644
--- a/ovn/northd/ovn-northd.c
+++ b/ovn/northd/ovn-northd.c
@@ -1,4 +1,4 @@
-/*
+/*
  * 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:
@@ -371,8 +371,10 @@ free_chassis_queueid(struct hmap *set, struct 
sbrec_chassis *chassis,
 static inline bool
 port_has_qos_params(const struct smap *opts)
 {
-    return (smap_get(opts, "qos_max_rate") ||
-            smap_get(opts, "qos_burst"));
+    return (smap_get(opts, "qos_ingress_max_rate") ||
+            smap_get(opts, "qos_ingress_burst") ||
+            smap_get(opts, "qos_egress_max_rate") ||
+            smap_get(opts, "qos_egress_burst"));
 }
 
 
@@ -3715,12 +3717,19 @@ build_lswitch_flows(struct hmap *datapaths, struct 
hmap *ports,
         }
 
         ds_clear(&match);
+        ds_clear(&actions);
         ds_put_format(&match, "outport == %s", op->json_key);
         if (lsp_is_enabled(op->nbsp)) {
             build_port_security_l2("eth.dst", op->ps_addrs, 
op->n_ps_addrs,
                                    &match);
+            const char *queue_id = smap_get(&op->sb->options,
+                                            "qdisc_queue_id");
+            if (queue_id) {
+                ds_put_format(&actions, "set_queue(%s); ", queue_id);
+            }
+            ds_put_cstr(&actions, "output;");
             ovn_lflow_add(lflows, op->od, S_SWITCH_OUT_PORT_SEC_L2, 50,
-                          ds_cstr(&match), "output;");
+                          ds_cstr(&match), ds_cstr(&actions));
         } else {
             ovn_lflow_add(lflows, op->od, S_SWITCH_OUT_PORT_SEC_L2, 150,
                           ds_cstr(&match), "drop;");
diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml
index 32c10c1..56229e9 100644
--- a/ovn/ovn-nb.xml
+++ b/ovn/ovn-nb.xml
@@ -435,14 +435,24 @@
           (empty string)
         </p>
 
-        <column name="options" key="qos_max_rate">
+        <column name="options" key="qos_ingress_max_rate">
           If set, indicates the maximum rate for data sent from this 
interface,
-          in bit/s. The traffic will be shaped according to this limit.
+          in kbps. The traffic will be shaped according to this limit.
         </column>
 
-        <column name="options" key="qos_burst">
+        <column name="options" key="qos_ingress_burst">
           If set, indicates the maximum burst size for data sent from 
this
-          interface, in bits.
+          interface, in kb.
+        </column>
+
+        <column name="options" key="qos_egress_max_rate">
+          If set, indicates the maximum rate for data sent to this 
interface,
+          in kbps. The traffic will be shaped according to this limit.
+        </column>
+
+        <column name="options" key="qos_egress_burst">
+          If set, indicates the maximum burst size for data sent to this
+          interface, in kb.
         </column>
       </group>
     </group>
diff --git a/ovn/ovn-sb.xml b/ovn/ovn-sb.xml
index b22d1ac..c8b940d 100644
--- a/ovn/ovn-sb.xml
+++ b/ovn/ovn-sb.xml
@@ -2103,14 +2103,24 @@ tcp.flags = RST;
         (empty string)
       </p>
 
-      <column name="options" key="qos_max_rate">
+      <column name="options" key="qos_ingress_max_rate">
         If set, indicates the maximum rate for data sent from this 
interface,
-        in bit/s. The traffic will be shaped according to this limit.
+        in kbps. The traffic will be shaped according to this limit.
       </column>
 
-      <column name="options" key="qos_burst">
+      <column name="options" key="qos_ingress_burst">
         If set, indicates the maximum burst size for data sent from this
-        interface, in bits.
+        interface, in kb.
+      </column>
+
+      <column name="options" key="qos_egress_max_rate">
+        If set, indicates the maximum rate for data sent to this 
interface,
+        in kbps. The traffic will be shaped according to this limit.
+      </column>
+
+      <column name="options" key="qos_egress_burst">
+        If set, indicates the maximum burst size for data sent to this
+        interface, in kb.
       </column>
