diff mbox series

[ovs-dev,55/62] Fix crash and port get bug with meter

Message ID 20201228092520.11807-56-taoyunxiang@cmss.chinamobile.com
State Not Applicable
Headers show
Series DPDK Offload API to test | expand

Commit Message

Tao YunXiang Dec. 28, 2020, 9:25 a.m. UTC
From: Taoyunxiang <taoyunxiang@cmss.chinamobile.com>

Code Source From: Self Code
Description:
Fix crash and port get bug when offload meter and vxlan

Jira:  #[Optional]
市场项目编号(名称):[Optional]
---
 include/openvswitch/ofp-meter.h |   2 +-
 lib/dpif-netdev.c               |  10 --
 lib/netdev-offload-dpdk.c       | 319 ++++++++++++++++++++++++++--------------
 lib/ofp-meter.c                 |  15 +-
 4 files changed, 219 insertions(+), 127 deletions(-)
diff mbox series

Patch

diff --git a/include/openvswitch/ofp-meter.h b/include/openvswitch/ofp-meter.h
index c6678f5..2490c0e 100644
--- a/include/openvswitch/ofp-meter.h
+++ b/include/openvswitch/ofp-meter.h
@@ -62,7 +62,7 @@  int ofputil_decode_meter_config(struct ofpbuf *,
                                 struct ofpbuf *bands);
 void ofputil_format_meter_config(struct ds *,
                                  const struct ofputil_meter_config *);
-uint32_t ofputil_meter_config_max_rate(struct ofputil_meter_config *conf);
+uint32_t *ofputil_meter_config_rate_burst(struct ofputil_meter_config *conf);
 
 struct ofputil_meter_mod {
     uint16_t command;
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index b03a2ab..e127396 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -2773,16 +2773,6 @@  queue_netdev_flow_put(struct dp_netdev_pmd_thread *pmd,
         return;
     }
 
-    VLOG_DBG("TIMO DBG: in queue_netdev_flow_put:recirc %x mod %x \n", match->flow.recirc_id,
-             match->flow.skb_priority);
-    VLOG_DBG("TIMO DBG: in queue_netdev_flow_put:nw_src %x ct_nw_src %x \n",
-             ntohl(match->flow.nw_src), ntohl(match->flow.ct_nw_src));
-    VLOG_DBG("TIMO DBG: in queue_netdev_flow_put:nat action %x \n",
-             nat_action.nat_action);
-    VLOG_DBG("TIMO DBG: in queue_netdev_flow_put:nat min addr %x \n",
-             ntohl(nat_action.min_addr.ipv4));
-    VLOG_DBG("TIMO DBG: in queue_netdev_flow_put:nat max addr %x \n",
-             ntohl(nat_action.max_addr.ipv4));
     if (ovsthread_once_start(&offload_thread_once)) {
         xpthread_cond_init(&dp_flow_offload.cond, NULL);
         ovs_thread_create("dp_netdev_flow_offload",
diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c
index 0a440eb..9fc8cb2 100644
--- a/lib/netdev-offload-dpdk.c
+++ b/lib/netdev-offload-dpdk.c
@@ -21,6 +21,7 @@ 
 
 #include <rte_flow.h>
 #include <rte_mtr.h>
+#include <rte_ethdev.h>
 
 #include "cmap.h"
 #include "dpif-netdev.h"
@@ -642,6 +643,16 @@  dump_flow_action(struct ds *s, const struct rte_flow_action *actions)
         ds_put_format(s, "  Set-Jump to : %"PRIu32"\n", jump->group);
     } else if (actions->type == RTE_FLOW_ACTION_TYPE_CT) {
         ds_put_cstr(s, "  Set-CT-enable bit\n");
+
+    } else if (actions->type == RTE_FLOW_ACTION_TYPE_METER) {
+        const struct rte_flow_action_meter *meter = actions->conf;
+
+        ds_put_cstr(s, "rte flow meter action:\n");
+        if (meter) {
+            ds_put_format(s, " Meter: %d\n", meter->mtr_id);
+        } else {
+            ds_put_cstr(s, "  Meter = null\n"); 
+        }
     } else {
         ds_put_format(s, "unknown rte flow action (%d)\n", actions->type);
     }
@@ -864,7 +875,6 @@  parse_geneve_match(struct flow_patterns *patterns,
             uint8_t val = *(buf+i);
             opt_data = opt_data | val ;
             opt_data = (i==data_len-1)? opt_data: opt_data<< 8;
-            VLOG_DBG("TIMO DBG. geneve op hdr =0x%08x",opt_data);
         }
         /* GENEVE option */
         op_spec = xzalloc(sizeof *op_spec);
@@ -1162,8 +1172,6 @@  parse_flow_match(struct flow_patterns *patterns,
             *next_proto_mask = 0;
         }
     }
-    VLOG_DBG("TIMO DBG. ct_state mask =0x%04x,ct_state =0x%04x",
-                match->wc.masks.ct_state, match->flow.ct_state);
     /* ct state */
     if (match->wc.masks.ct_state &&
         (match->wc.masks.ct_state & match->flow.ct_state & CS_ESTABLISHED) ){
@@ -1186,13 +1194,25 @@  static void dpdk_meter_destroy(void *priv_data)
 {
     struct dpdk_meter_offload *dmo = priv_data;
     struct rte_mtr_error mtr_error;
-    
+    int ret;
+
     if (dmo) {
-        rte_mtr_meter_profile_delete(dmo->port_id,
+        ret = rte_mtr_meter_profile_delete(dmo->port_id,
                                      dmo->mc.mtr_id,
                                      &mtr_error);
-        rte_mtr_destroy(dmo->port_id, dmo->mc.mtr_id,
+        if (ret && ret != -EEXIST) {
+            VLOG_ERR("rte_mtr_meter_profile_delete fail: err_type: %d err_msg: %s, portid: %d\n",
+                       mtr_error.type, mtr_error.message, dmo->port_id);
+        }
+        VLOG_DBG("yunxiang_DBG:in dpdk_meter_destroy1, port_id is %d,mtr_id is %d", dmo->port_id, dmo->mc.mtr_id); 
+
+        ret = rte_mtr_destroy(dmo->port_id, dmo->mc.mtr_id,
                         &mtr_error);
+        if (ret && ret != -EEXIST) {
+            VLOG_ERR("rte_mtr_destroy fail: err_type: %d err_msg: %s, portid: %d\n",
+                       mtr_error.type, mtr_error.message, dmo->port_id);
+        }
+        VLOG_DBG("yunxiang_DBG:in dpdk_meter_destroy2, port_id is %d,mtr_id is %d", dmo->port_id, dmo->mc.mtr_id); 
         free(dmo);
     }
 }
@@ -1743,8 +1763,6 @@  parse_clone_actions(struct netdev *netdev,
     NL_ATTR_FOR_EACH_UNSAFE (ca, cleft, clone_actions, clone_actions_len) {
         int clone_type = nl_attr_type(ca);
 
-        VLOG_DBG("TIMO DBG: in parse_clone_action %0d:%d",i++,clone_type);
-
         if (clone_type == OVS_ACTION_ATTR_TUNNEL_PUSH) {
             const struct ovs_action_push_tnl *tnl_push = nl_attr_get(ca);
 
@@ -1790,10 +1808,81 @@  parse_clone_actions(struct netdev *netdev,
     return 0;
 }
 
+#define DPDK_METER_UPATE_UP 65536 
+
+static void dpdk_meter_update(void *priv_data, void *config)
+{
+    struct dpdk_meter_offload *dmo = priv_data;
+    struct rte_mtr_meter_profile mp;
+    struct rte_mtr_error mtr_error;
+    uint32_t mp_id, new_mp_id;
+    uint32_t *rate_and_burst;
+    uint32_t max_rate;
+    uint32_t burst_size;
+    uint32_t ret;
+
+    if (!priv_data || !config) {
+        return;
+    }
+    
+    rate_and_burst = ofputil_meter_config_rate_burst(config);
+    max_rate = *rate_and_burst;
+    burst_size = *(rate_and_burst + 1);
+    VLOG_DBG("yunxiang_DBG:in dpdk_meter_update, max_rate is %d,burst is %d,dmo->nax_rate is %d", max_rate, burst_size, dmo->max_rate);
+
+    if (dmo->max_rate == max_rate) {
+        return;
+    }
+
+    memset(&mp, 0, sizeof(struct rte_mtr_meter_profile));
+    mp.alg = RTE_MTR_TRTCM_RFC2698;
+    mp.trtcm_rfc2698.cir = max_rate *1000 /8;   /* rate_max Kbps*/
+    mp.trtcm_rfc2698.cbs = burst_size /8;       /* busrt_size bit*/
+
+    if (dmo->mp_id < DPDK_METER_UPATE_UP) {
+        new_mp_id = dmo->mp_id + DPDK_METER_UPATE_UP;
+    } else {
+        new_mp_id = dmo->mp_id - DPDK_METER_UPATE_UP;
+    }
+
+    ret = rte_mtr_meter_profile_add(dmo->port_id, new_mp_id,
+                                    &mp, &mtr_error);
+    VLOG_DBG("yunxiang_DBG: in dpdk_meter_update_profile_add, port_id is %d,device name is %s, new_mp_id is %d, max_rate is %d, burst_size is %d", dmo->port_id, rte_eth_devices[dmo->port_id].data->name, new_mp_id,max_rate, burst_size);
+    if (ret) {
+        VLOG_ERR("rte_mtr_meter_profile_add fail: err_type: %d err_msg: %s\n",
+                 mtr_error.type, mtr_error.message);
+        return;
+    }
+
+    ret = rte_mtr_meter_profile_update(dmo->port_id, dmo->mc.mtr_id,
+                                       new_mp_id, &mtr_error);
+    VLOG_DBG("yunxiang_DBG: in dpdk_meter_update_profile_update, max_rate is %d, burst_size is %d, mid is %d, new_mp_id is %d", max_rate, burst_size, dmo->mc.mtr_id, new_mp_id);   
+    if (ret) {
+        VLOG_ERR("rte_mtr_meter_profile_update fail: err_type: %d err_msg: %s\n",
+                 mtr_error.type, mtr_error.message);
+        mp_id = new_mp_id;
+        goto out;
+    }
+
+    mp_id = dmo->mp_id;
+    dmo->mp_id = new_mp_id;
+out:
+    ret = rte_mtr_meter_profile_delete(dmo->port_id, mp_id, &mtr_error);
+    if (ret) {
+        VLOG_ERR("rte_mtr_meter_profile_update fail: err_type: %d err_msg: %s\n",
+                 mtr_error.type, mtr_error.message);
+    }
+}
+
+static struct netdev_offload_meter_api dpdk_meter_offload_api = {
+    .meter_destroy  = dpdk_meter_destroy,
+    .meter_update   = dpdk_meter_update,
+};
+
 static struct rte_flow_action_meter*
 dpdk_meter_create(struct dpif *dpif, struct netdev *netdev, uint32_t mid)
 {
-    uint32_t port_id = netdev_dpdk_get_portid(netdev);
+    uint32_t port_id;
     struct netdev_offload_meter *nom;
     struct dpdk_meter_offload *dmo;
     struct ofputil_meter_config config;
@@ -1801,9 +1890,10 @@  dpdk_meter_create(struct dpif *dpif, struct netdev *netdev, uint32_t mid)
     struct rte_mtr_meter_profile mp;
     struct rte_mtr_params params;
     struct rte_mtr_error mtr_error;
+    uint32_t *rate_and_burst;
     uint32_t max_rate;
+    uint32_t burst_size;
     int ret;
-    static struct netdev_offload_meter_api dpdk_meter_offload_api;
 
     meter_id.uint32 = mid;
     
@@ -1811,6 +1901,34 @@  dpdk_meter_create(struct dpif *dpif, struct netdev *netdev, uint32_t mid)
         return NULL;
     }
 
+    /* check if the device port is a useful rep port. If it is a vport, we
+     * we will get any rep port from all netdev */
+    if (netdev_vport_is_vport_class(netdev->netdev_class)) {
+        struct netdev_flow_dump **netdev_dumps;
+        int num_ports = 0;
+        int i;
+
+        netdev_dumps = netdev_ports_flow_dump_create(netdev->dpif_type,
+                                                     &num_ports);
+        for (i = 0; i < num_ports; i++) {
+            if (!netdev_dpdk_is_vfrep_port(netdev_dumps[i]->netdev)) {
+                continue;
+            }
+            port_id = netdev_dpdk_get_portid(netdev_dumps[i]->netdev);
+            break;
+        }
+        for (i = 0; i < num_ports; i++) {
+            int err = netdev_flow_dump_destroy(netdev_dumps[i]);
+
+            if (err != 0 && err != EOPNOTSUPP) {
+                VLOG_ERR("failed dumping netdev: %s", ovs_strerror(err));
+            }
+        }
+
+    } else {
+        port_id = netdev_dpdk_get_portid(netdev);
+    }
+
     nom = xmalloc(sizeof *nom);
     dmo = xmalloc(sizeof *dmo);
 
@@ -1818,39 +1936,39 @@  dpdk_meter_create(struct dpif *dpif, struct netdev *netdev, uint32_t mid)
     nom->priv_data = dmo;
 
     memset(&mp, 0, sizeof(struct rte_mtr_meter_profile));
-    max_rate = ofputil_meter_config_max_rate(&config);
+    rate_and_burst = ofputil_meter_config_rate_burst(&config);
+    max_rate = *rate_and_burst;
+    burst_size = *(rate_and_burst + 1);
 
     dmo->mc.mtr_id = mid;
     dmo->port_id = port_id;
     dmo->max_rate = max_rate;
     dmo->mp_id = mid;
 
-    mp.alg = RTE_MTR_SRTCM_RFC2697;
-    mp.srtcm_rfc2697.cir = max_rate *1024 /8; /* rate_max Kbps*/
-    mp.srtcm_rfc2697.cbs = max_rate *1024 /8;
-    mp.srtcm_rfc2697.ebs = 0;
-
+    mp.alg = RTE_MTR_TRTCM_RFC2698;
+    mp.trtcm_rfc2698.cir = max_rate *1000 /8; /* rate_max Kbps*/
+    mp.trtcm_rfc2698.cbs = burst_size /8;    /* busrt_size bit*/
+    
+    VLOG_DBG("yunxiang_DBG: in dpdk_meter_create, port_id1 is %d,device name is %s", dmo->port_id, rte_eth_devices[port_id].data->name);
     ret = rte_mtr_meter_profile_add(dmo->port_id, dmo->mc.mtr_id,
                                     &mp, &mtr_error);
+    VLOG_DBG("yunxiang_DBG: in dpdk_meter_create, max_rate is %d, burst_size is %d, mid is %d", max_rate, burst_size, dmo->mc.mtr_id);   
     if (ret && ret != -EEXIST) {
         VLOG_ERR("rte_mtr_meter_profile_add fail: err_type: %d err_msg: %s, portid: %d\n",
                    mtr_error.type, mtr_error.message, netdev_dpdk_get_portid(netdev));
         goto profile_err;
     }
 
-    enum rte_color dscp_table[2];
-    dscp_table[0] = RTE_COLOR_YELLOW;
-    dscp_table[1] = RTE_COLOR_RED;
 
     params.meter_profile_id = dmo->mc.mtr_id;
-    params.dscp_table = dscp_table;
     params.meter_enable = 1;
     params.use_prev_mtr_color = 0;
+    params.stats_mask = 0;
     params.action[RTE_COLOR_GREEN]  = MTR_POLICER_ACTION_COLOR_GREEN;
     params.action[RTE_COLOR_YELLOW] = MTR_POLICER_ACTION_DROP;
     params.action[RTE_COLOR_RED]    = MTR_POLICER_ACTION_DROP;
 
-    ret = rte_mtr_create(dmo->port_id, dmo->mc.mtr_id, &params, 0, &mtr_error);
+    ret = rte_mtr_create(dmo->port_id, dmo->mc.mtr_id, &params, 1, &mtr_error);
     if (ret && ret != -EEXIST) {
         VLOG_ERR("rte_mtr_create fail: err_type: %d err_msg: %s, portid: %d\n",
                    mtr_error.type, mtr_error.message, netdev_dpdk_get_portid(netdev));
@@ -1875,7 +1993,7 @@  profile_err:
 static struct rte_flow_action_meter *
 netdev_offload_dpdk_meter_conf(struct dpif *dpif, struct netdev *netdev, uint32_t mid)
 {
-    uint32_t port_id = netdev_dpdk_get_portid(netdev);
+    /*uint32_t port_id = netdev_dpdk_get_portid(netdev);*/
     struct netdev_offload_meter *nom = NULL;
     struct dpdk_meter_offload *dmo;
     ofproto_meter_id meter_id;
@@ -1891,16 +2009,11 @@  netdev_offload_dpdk_meter_conf(struct dpif *dpif, struct netdev *netdev, uint32_
 
     if (!nom) {
         return dpdk_meter_create(dpif, netdev, mid);
+    } else {
+        dmo = (struct dpdk_meter_offload *)(nom->priv_data);
+        return &(dmo->mc);
     }
 
-    dmo = (struct dpdk_meter_offload *)nom->priv_data;
-    if (port_id != dmo->port_id) {
-        VLOG_INFO("dpdk meter %d is used on %d, can't be used for : %d",
-                  mid, dmo->port_id, port_id);
-        return NULL;
-    }
-
-    return &dmo->mc;
 }
 
 static int
@@ -1980,12 +2093,17 @@  parse_flow_actions(struct dpif *dpif,
         /* for ct && ct clear no need to translate*/
         } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_METER) {
             struct rte_flow_action_meter *mc;
-            mc = netdev_offload_dpdk_meter_conf(dpif,
+            struct rte_flow_action_meter *mc_ori;
+            mc_ori = netdev_offload_dpdk_meter_conf(dpif,
                                                 netdev,
                                                 nl_attr_get_u32(nla));
-            if (mc) {
+            if (mc_ori) {
+                mc = xzalloc(sizeof *mc);
+                mc->mtr_id = nl_attr_get_u32(nla);
                 add_flow_action(actions, RTE_FLOW_ACTION_TYPE_METER, mc);
-            }           
+            } else {
+                return -1;
+            }
 
         }
           else if (nl_attr_type(nla) == OVS_ACTION_ATTR_CT_CLEAR ||
@@ -2053,7 +2171,6 @@  netdev_offload_dpdk_actions(struct dpif *dpif,
             if (!netdev_dpdk_is_uplink_port(netdev_dumps[i]->netdev)) {
                 continue;
             }
-            VLOG_DBG("TIMO DBG: in netdev_offload_dpdk_flow_create, netdev dpdk");
             flow = netdev_offload_dpdk_flow_create(netdev_dumps[i]->netdev,
                                                &flow_attr, patterns->items,
                                                actions.actions, &error);
@@ -2063,7 +2180,7 @@  netdev_offload_dpdk_actions(struct dpif *dpif,
             int err = netdev_flow_dump_destroy(netdev_dumps[i]);
 
             if (err != 0 && err != EOPNOTSUPP) {
-                VLOG_ERR("failed dumping netdev: %s", ovs_strerror(err));
+                VLOG_ERR("dpdk_action:failed dumping netdev: %s", ovs_strerror(err));
             }
         }
 
@@ -2076,71 +2193,6 @@  out:
     return flow;
 }
 
-#define DPDK_METER_UPATE_UP 65536 
-
-static void dpdk_meter_update(void *priv_data, void *config)
-{
-    struct dpdk_meter_offload *dmo = priv_data;
-    struct rte_mtr_meter_profile mp;
-    struct rte_mtr_error mtr_error;
-    uint32_t mp_id, new_mp_id;
-    uint32_t max_rate;
-    uint32_t ret;
-
-    if (!priv_data || !config) {
-        return;
-    }
-    
-    max_rate = ofputil_meter_config_max_rate(config);
-    if (dmo->max_rate == max_rate) {
-        return;
-    }
-
-    memset(&mp, 0, sizeof(struct rte_mtr_meter_profile));
-    mp.alg = RTE_MTR_SRTCM_RFC2697;
-    mp.srtcm_rfc2697.cir = max_rate *1024 /8;
-    mp.srtcm_rfc2697.cbs = max_rate *1024 /8;
-    mp.srtcm_rfc2697.ebs = 0;
-
-    if (dmo->mp_id < DPDK_METER_UPATE_UP) {
-        new_mp_id = dmo->mp_id + DPDK_METER_UPATE_UP;
-    } else {
-        new_mp_id = dmo->mp_id - DPDK_METER_UPATE_UP;
-    }
-
-    ret = rte_mtr_meter_profile_add(dmo->port_id, new_mp_id,
-                                    &mp, &mtr_error);
-    if (ret) {
-        VLOG_ERR("rte_mtr_meter_profile_add fail: err_type: %d err_msg: %s\n",
-                 mtr_error.type, mtr_error.message);
-        return;
-    }
-
-    ret = rte_mtr_meter_profile_update(dmo->port_id, dmo->mc.mtr_id,
-                                       new_mp_id, &mtr_error);
-    if (ret) {
-        VLOG_ERR("rte_mtr_meter_profile_update fail: err_type: %d err_msg: %s\n",
-                 mtr_error.type, mtr_error.message);
-        mp_id = new_mp_id;
-        goto out;
-    }
-
-    mp_id = dmo->mp_id;
-    dmo->mp_id = new_mp_id;
-out:
-    ret = rte_mtr_meter_profile_delete(dmo->port_id, mp_id, &mtr_error);
-    if (ret) {
-        VLOG_ERR("rte_mtr_meter_profile_update fail: err_type: %d err_msg: %s\n",
-                 mtr_error.type, mtr_error.message);
-    }
-}
-
-static struct netdev_offload_meter_api dpdk_meter_offload_api = {
-    .meter_destroy  = dpdk_meter_destroy,
-    .meter_update   = dpdk_meter_update,
-};
-
-
 
 static int
 netdev_offload_dpdk_add_flow(struct dpif *dpif, struct netdev *netdev,
@@ -2158,12 +2210,10 @@  netdev_offload_dpdk_add_flow(struct dpif *dpif, struct netdev *netdev,
     ret = parse_flow_match(&patterns, match, netdev, info);
     if (ret) {
         goto out;
-        VLOG_DBG("yunxiang_debug_netdev_offload_dpdk_add_flow: ret %p \n",ret);
     }
     
     flow = netdev_offload_dpdk_actions(dpif, netdev, &patterns, nl_actions,
                                        actions_len, info);
-    VLOG_DBG("yunxiang_debug_netdev_offload_dpdk_add_flow: flow %p \n",flow);
     if (!flow) {
         /* If we failed to offload the rule actions fallback to MARK+RSS
          * actions.
@@ -2197,7 +2247,6 @@  netdev_offload_dpdk_validate_flow(const struct match *match)
 
     /* Create a wc-zeroed version of flow. */
     match_init(&match_zero_wc, &match->flow, &match->wc);
-
     /* support tunnel now so mark this checker
     if (!is_all_zeros(&match_zero_wc.flow.tunnel,
                       sizeof match_zero_wc.flow.tunnel)) {
@@ -2306,12 +2355,35 @@  netdev_offload_dpdk_flow_put(struct dpif *dpif, struct netdev *netdev,
      * Here destroy the old rte flow first before adding a new one.
      */
     rte_flow_data = ufid_to_rte_flow_data_find(ufid);
-    VLOG_DBG("yunxiang_debug_netdev_offload_dpdk_flow_put,rte_flow_data=%p",rte_flow_data);
     if (rte_flow_data && rte_flow_data->rte_flow) {
-        ret = netdev_offload_dpdk_destroy_flow(netdev, ufid,
-                                               rte_flow_data->rte_flow);
+        if (netdev_vport_is_vport_class(netdev->netdev_class)) {
+            struct netdev_flow_dump **netdev_dumps;
+            int num_ports = 0;
+            int i;
+
+            netdev_dumps = netdev_ports_flow_dump_create(netdev->dpif_type,
+                                                         &num_ports);
+            for (i = 0; i < num_ports; i++) {
+                if (!netdev_dpdk_is_uplink_port(netdev_dumps[i]->netdev)) {
+                    continue;
+                }
+                ret = netdev_offload_dpdk_destroy_flow(netdev_dumps[i]->netdev, ufid,
+                                                        rte_flow_data->rte_flow);
+                break;
+            }
+            for (i = 0; i < num_ports; i++) {
+                int err = netdev_flow_dump_destroy(netdev_dumps[i]);
+
+                if (err != 0 && err != EOPNOTSUPP) {
+                    VLOG_ERR("flow_del:failed dumping netdev: %s", ovs_strerror(err));
+                }
+            }
+
+        } else {
+            ret = netdev_offload_dpdk_destroy_flow(netdev, ufid, 
+                                                   rte_flow_data->rte_flow);
+        }
         if (ret < 0) {
-            VLOG_DBG("yunxiang_debug_netdev_offload_dpdk_flow_put,ret=%p",ret);
             return ret;
         }
     }
@@ -2333,17 +2405,44 @@  netdev_offload_dpdk_flow_del(struct netdev *netdev, const ovs_u128 *ufid,
                              struct dpif_flow_stats *stats)
 {
     struct ufid_to_rte_flow_data *rte_flow_data;
+    int ret = -1;
 
     rte_flow_data = ufid_to_rte_flow_data_find(ufid);
     if (!rte_flow_data || !rte_flow_data->rte_flow) {
-        return -1;
+        return ret;
     }
 
     if (stats) {
         memset(stats, 0, sizeof *stats);
     }
-    return netdev_offload_dpdk_destroy_flow(netdev, ufid,
-                                            rte_flow_data->rte_flow);
+    if (netdev_vport_is_vport_class(netdev->netdev_class)) {
+        struct netdev_flow_dump **netdev_dumps;
+        int num_ports = 0;
+        int i;
+
+        netdev_dumps = netdev_ports_flow_dump_create(netdev->dpif_type,
+                                                     &num_ports);
+        for (i = 0; i < num_ports; i++) {
+            if (!netdev_dpdk_is_uplink_port(netdev_dumps[i]->netdev)) {
+                continue;
+            }
+            ret = netdev_offload_dpdk_destroy_flow(netdev_dumps[i]->netdev, ufid,
+                                                    rte_flow_data->rte_flow);
+            break;
+        }
+        for (i = 0; i < num_ports; i++) {
+            int err = netdev_flow_dump_destroy(netdev_dumps[i]);
+
+            if (err != 0 && err != EOPNOTSUPP) {
+                VLOG_ERR("flow_del:failed dumping netdev: %s", ovs_strerror(err));
+            }
+        }
+
+    } else {
+        ret = netdev_offload_dpdk_destroy_flow(netdev, ufid, 
+                                               rte_flow_data->rte_flow);
+    }
+    return ret;
 }
 
 static int
diff --git a/lib/ofp-meter.c b/lib/ofp-meter.c
index 633924e..cc36aea 100644
--- a/lib/ofp-meter.c
+++ b/lib/ofp-meter.c
@@ -808,16 +808,19 @@  ofputil_format_meter_mod(struct ds *s, const struct ofputil_meter_mod *mm)
     ofputil_format_meter_config(s, &mm->meter);
 }
 
-uint32_t
-ofputil_meter_config_max_rate(struct ofputil_meter_config *conf)
+uint32_t *
+ofputil_meter_config_rate_burst(struct ofputil_meter_config *conf)
 {
-    uint32_t i, max_rate = 0;
+    uint32_t i, max_rate = 0, burst_size = 0;
+    uint32_t rate_and_burst[2];
     for (i = 0; i < conf->n_bands; i++) {
         if (max_rate < conf->bands[i].rate) {
             max_rate = conf->bands[i].rate;
+            burst_size = conf->bands[i].burst_size;
         }
     }
-
-    return max_rate;
+    rate_and_burst[0] = max_rate;
+    rate_and_burst[1] = burst_size;
+    
+    return rate_and_burst;
 }
-