diff mbox series

[ovs-dev] dpif-netlink: add revalidator for offload of meters

Message ID 20220923083514.296638-1-simon.horman@corigine.com
State Changes Requested
Headers show
Series [ovs-dev] dpif-netlink: add revalidator for offload of meters | expand

Checks

Context Check Description
ovsrobot/apply-robot warning apply and check: warning
ovsrobot/github-robot-_Build_and_Test success github build: passed
ovsrobot/intel-ovs-compilation success test: success

Commit Message

Simon Horman Sept. 23, 2022, 8:35 a.m. UTC
From: Yifan Li <yifan.li@corigine.com>

Allow revalidator for hardware offload of meters via OVS-TC.
Without revalidator, tc meter action can not be deleted while
flow exists. The revalidator fix this bug by continuously
checking existing meters and delete the unneeded ones. The
autotest cases of revalidator are also added.

Signed-off-by: Yifan Li <yifan.li@corigine.com>
Signed-off-by: Simon Horman <simon.horman@corigine.com>
---
 lib/dpif-netdev.c                |   1 +
 lib/dpif-netlink.c               | 257 +++++++++++++++++++++++++++----
 lib/dpif-netlink.h               |   2 +
 lib/dpif-provider.h              |   5 +
 lib/dpif.c                       |  15 +-
 lib/id-pool.c                    |  13 ++
 lib/id-pool.h                    |   4 +-
 lib/netdev-linux.c               |   6 +
 lib/netdev-offload-tc.c          |  11 +-
 lib/tc.c                         |   5 -
 lib/tc.h                         |  10 +-
 ofproto/ofproto-dpif-upcall.c    |   5 +
 ofproto/ofproto-dpif.h           |   2 +
 tests/system-offloads-traffic.at |   4 +
 14 files changed, 301 insertions(+), 39 deletions(-)

Comments

0-day Robot Sept. 23, 2022, 8:58 a.m. UTC | #1
References:  <20220923083514.296638-1-simon.horman@corigine.com>
 

Bleep bloop.  Greetings Simon Horman, I am a robot and I have tried out your patch.
Thanks for your contribution.

I encountered some error that I wasn't expecting.  See the details below.


checkpatch:
WARNING: Unexpected sign-offs from developers who are not authors or co-authors or committers: Simon Horman <simon.horman@corigine.com>
Lines checked: 715, Warnings: 1, Errors: 0


Please check this out.  If you feel there has been an error, please email aconole@redhat.com

Thanks,
0-day Robot
Eelco Chaudron Sept. 23, 2022, 1:10 p.m. UTC | #2
On 23 Sep 2022, at 10:35, Simon Horman wrote:

> From: Yifan Li <yifan.li@corigine.com>
>
> Allow revalidator for hardware offload of meters via OVS-TC.
> Without revalidator, tc meter action can not be deleted while
> flow exists. The revalidator fix this bug by continuously
> checking existing meters and delete the unneeded ones. The
> autotest cases of revalidator are also added.

This is not a review, but just some quick observations/questions.

- Please undo the n_handlers to _n_handlers renames, as it does not make sense for this patch.
- New TC related code was added to dpif-netdev.c this is not the place where such code should live.
- Log messages do not need a trailing \n, and please have them uniform, i.e. start with a capital for all new log messages.
- Can you explain why we need this expensive revalidate process and isn’t there a better way to make sure they are cleaned up properly?

Also including Jianbo who added the initial code.


//Eelco

> Signed-off-by: Yifan Li <yifan.li@corigine.com>
> Signed-off-by: Simon Horman <simon.horman@corigine.com>
> ---
>  lib/dpif-netdev.c                |   1 +
>  lib/dpif-netlink.c               | 257 +++++++++++++++++++++++++++----
>  lib/dpif-netlink.h               |   2 +
>  lib/dpif-provider.h              |   5 +
>  lib/dpif.c                       |  15 +-
>  lib/id-pool.c                    |  13 ++
>  lib/id-pool.h                    |   4 +-
>  lib/netdev-linux.c               |   6 +
>  lib/netdev-offload-tc.c          |  11 +-
>  lib/tc.c                         |   5 -
>  lib/tc.h                         |  10 +-
>  ofproto/ofproto-dpif-upcall.c    |   5 +
>  ofproto/ofproto-dpif.h           |   2 +
>  tests/system-offloads-traffic.at |   4 +
>  14 files changed, 301 insertions(+), 39 deletions(-)
>
> diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
> index a45b460145c6..365aacadb03a 100644
> --- a/lib/dpif-netdev.c
> +++ b/lib/dpif-netdev.c
> @@ -9583,6 +9583,7 @@ const struct dpif_class dpif_netdev_class = {
>      dpif_netdev_meter_set,
>      dpif_netdev_meter_get,
>      dpif_netdev_meter_del,
> +    NULL,                       /* meter_revalidate */
>      dpif_netdev_bond_add,
>      dpif_netdev_bond_del,
>      dpif_netdev_bond_stats_get,
> diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
> index a620a6ec52dd..4eee4761dc6b 100644
> --- a/lib/dpif-netlink.c
> +++ b/lib/dpif-netlink.c
> @@ -25,6 +25,7 @@
>  #include <net/if.h>
>  #include <linux/types.h>
>  #include <linux/pkt_sched.h>
> +#include <linux/rtnetlink.h>
>  #include <poll.h>
>  #include <stdlib.h>
>  #include <strings.h>
> @@ -48,6 +49,7 @@
>  #include "netlink.h"
>  #include "netnsid.h"
>  #include "odp-util.h"
> +#include "ofproto/ofproto-dpif.h"
>  #include "openvswitch/dynamic-string.h"
>  #include "openvswitch/flow.h"
>  #include "openvswitch/hmap.h"
> @@ -61,6 +63,7 @@
>  #include "packets.h"
>  #include "random.h"
>  #include "sset.h"
> +#include "tc.h"
>  #include "timeval.h"
>  #include "unaligned.h"
>  #include "util.h"
> @@ -2571,18 +2574,18 @@ static uint32_t
>  dpif_netlink_calculate_n_handlers(void)
>  {
>      uint32_t total_cores = count_total_cores();
> -    uint32_t n_handlers = count_cpu_cores();
> +    uint32_t _n_handlers = count_cpu_cores();
>      uint32_t next_prime_num;
>
>      /* If not all cores are available to OVS, create additional handler
>       * threads to ensure more fair distribution of load between them.
>       */
> -    if (n_handlers < total_cores && total_cores > 2) {
> -        next_prime_num = next_prime(n_handlers + 1);
> -        n_handlers = MIN(next_prime_num, total_cores);
> +    if (_n_handlers < total_cores && total_cores > 2) {
> +        next_prime_num = next_prime(_n_handlers + 1);
> +        _n_handlers = MIN(next_prime_num, total_cores);
>      }
>
> -    return n_handlers;
> +    return _n_handlers;
>  }
>
>  static int
> @@ -2591,17 +2594,17 @@ dpif_netlink_refresh_handlers_cpu_dispatch(struct dpif_netlink *dpif)
>  {
>      int handler_id;
>      int error = 0;
> -    uint32_t n_handlers;
>      uint32_t *upcall_pids;
> +    uint32_t _n_handlers;
>
> -    n_handlers = dpif_netlink_calculate_n_handlers();
> -    if (dpif->n_handlers != n_handlers) {
> +    _n_handlers = dpif_netlink_calculate_n_handlers();
> +    if (dpif->n_handlers != _n_handlers) {
>          VLOG_DBG("Dispatch mode(per-cpu): initializing %d handlers",
> -                   n_handlers);
> +                   _n_handlers);
>          destroy_all_handlers(dpif);
> -        upcall_pids = xzalloc(n_handlers * sizeof *upcall_pids);
> -        dpif->handlers = xzalloc(n_handlers * sizeof *dpif->handlers);
> -        for (handler_id = 0; handler_id < n_handlers; handler_id++) {
> +        upcall_pids = xzalloc(_n_handlers * sizeof *upcall_pids);
> +        dpif->handlers = xzalloc(_n_handlers * sizeof *dpif->handlers);
> +        for (handler_id = 0; handler_id < _n_handlers; handler_id++) {
>              struct dpif_handler *handler = &dpif->handlers[handler_id];
>              error = create_nl_sock(dpif, &handler->sock);
>              if (error) {
> @@ -2615,9 +2618,9 @@ dpif_netlink_refresh_handlers_cpu_dispatch(struct dpif_netlink *dpif)
>                        handler_id, upcall_pids[handler_id]);
>          }
>
> -        dpif->n_handlers = n_handlers;
> +        dpif->n_handlers = _n_handlers;
>          error = dpif_netlink_set_handler_pids(&dpif->dpif, upcall_pids,
> -                                              n_handlers);
> +                                              _n_handlers);
>          free(upcall_pids);
>      }
>      return error;
> @@ -2629,7 +2632,7 @@ dpif_netlink_refresh_handlers_cpu_dispatch(struct dpif_netlink *dpif)
>   * backing kernel vports. */
>  static int
>  dpif_netlink_refresh_handlers_vport_dispatch(struct dpif_netlink *dpif,
> -                                             uint32_t n_handlers)
> +                                             uint32_t _n_handlers)
>      OVS_REQ_WRLOCK(dpif->upcall_lock)
>  {
>      unsigned long int *keep_channels;
> @@ -2641,13 +2644,13 @@ dpif_netlink_refresh_handlers_vport_dispatch(struct dpif_netlink *dpif,
>      int retval = 0;
>      size_t i;
>
> -    ovs_assert(!WINDOWS || n_handlers <= 1);
> +    ovs_assert(!WINDOWS || _n_handlers <= 1);
>      ovs_assert(!WINDOWS || dpif->n_handlers <= 1);
>
> -    if (dpif->n_handlers != n_handlers) {
> +    if (dpif->n_handlers != _n_handlers) {
>          destroy_all_channels(dpif);
> -        dpif->handlers = xzalloc(n_handlers * sizeof *dpif->handlers);
> -        for (i = 0; i < n_handlers; i++) {
> +        dpif->handlers = xzalloc(_n_handlers * sizeof *dpif->handlers);
> +        for (i = 0; i < _n_handlers; i++) {
>              int error;
>              struct dpif_handler *handler = &dpif->handlers[i];
>
> @@ -2665,10 +2668,10 @@ dpif_netlink_refresh_handlers_vport_dispatch(struct dpif_netlink *dpif,
>                  return error;
>              }
>          }
> -        dpif->n_handlers = n_handlers;
> +        dpif->n_handlers = _n_handlers;
>      }
>
> -    for (i = 0; i < n_handlers; i++) {
> +    for (i = 0; i < _n_handlers; i++) {
>          struct dpif_handler *handler = &dpif->handlers[i];
>
>          handler->event_offset = handler->n_events = 0;
> @@ -2801,7 +2804,7 @@ dpif_netlink_recv_set(struct dpif *dpif_, bool enable)
>  }
>
>  static int
> -dpif_netlink_handlers_set(struct dpif *dpif_, uint32_t n_handlers)
> +dpif_netlink_handlers_set(struct dpif *dpif_, uint32_t _n_handlers)
>  {
>      struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
>      int error = 0;
> @@ -2809,7 +2812,7 @@ dpif_netlink_handlers_set(struct dpif *dpif_, uint32_t n_handlers)
>  #ifdef _WIN32
>      /* Multiple upcall handlers will be supported once kernel datapath supports
>       * it. */
> -    if (n_handlers > 1) {
> +    if (_n_handlers > 1) {
>          return error;
>      }
>  #endif
> @@ -2820,7 +2823,7 @@ dpif_netlink_handlers_set(struct dpif *dpif_, uint32_t n_handlers)
>              error = dpif_netlink_refresh_handlers_cpu_dispatch(dpif);
>          } else {
>              error = dpif_netlink_refresh_handlers_vport_dispatch(dpif,
> -                                                                 n_handlers);
> +                                                                 _n_handlers);
>          }
>      }
>      fat_rwlock_unlock(&dpif->upcall_lock);
> @@ -2829,12 +2832,13 @@ dpif_netlink_handlers_set(struct dpif *dpif_, uint32_t n_handlers)
>  }
>
>  static bool
> -dpif_netlink_number_handlers_required(struct dpif *dpif_, uint32_t *n_handlers)
> +dpif_netlink_number_handlers_required(struct dpif *dpif_,
> +                                      uint32_t *_n_handlers)
>  {
>      struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
>
>      if (dpif_netlink_upcall_per_cpu(dpif)) {
> -        *n_handlers = dpif_netlink_calculate_n_handlers();
> +        *_n_handlers = dpif_netlink_calculate_n_handlers();
>          return true;
>      }
>
> @@ -2843,7 +2847,7 @@ dpif_netlink_number_handlers_required(struct dpif *dpif_, uint32_t *n_handlers)
>
>  static int
>  dpif_netlink_queue_to_priority(const struct dpif *dpif OVS_UNUSED,
> -                             uint32_t queue_id, uint32_t *priority)
> +                               uint32_t queue_id, uint32_t *priority)
>  {
>      if (queue_id < 0xf000) {
>          *priority = TC_H_MAKE(1 << 16, queue_id + 1);
> @@ -4161,6 +4165,191 @@ dpif_netlink_meter_get_features(const struct dpif *dpif_,
>      ofpbuf_delete(msg);
>  }
>
> +static bool dpif_netlink_meter_should_revalidate(struct dpif_backer *backer,
> +                                                 uint32_t meter_id)
> +{
> +    return !id_pool_id_exist(backer->meter_ids, meter_id);
> +}
> +
> +static void
> +dpif_tc_meter_revalidate(struct dpif *dpif_ OVS_UNUSED,
> +                         struct dpif_backer *backer, struct ofpbuf *reply)
> +{
> +    static struct nl_policy actions_orders_policy[ACT_MAX_NUM + 1] = {};
> +    struct nlattr *actions_orders[ARRAY_SIZE(actions_orders_policy)];
> +    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5,20);
> +    static const struct nl_policy tca_root_policy[] = {
> +        [TCA_ACT_TAB] = { .type = NL_A_NESTED, .optional = false },
> +        [TCA_ROOT_COUNT] = { .type = NL_A_U32, .optional = false },
> +    };
> +    struct nlattr *action_root_attrs[ARRAY_SIZE(tca_root_policy)];
> +    static const struct nl_policy police_policy[] = {
> +        [TCA_POLICE_TBF] = { .type = NL_A_UNSPEC,
> +                             .min_len = sizeof(struct tc_police),
> +                             .optional = false},
> +    };
> +    struct nlattr *action_police_tab[ARRAY_SIZE(police_policy)];
> +    static const struct nl_policy act_policy[] = {
> +        [TCA_ACT_KIND] = { .type = NL_A_STRING, .optional = false, },
> +        [TCA_ACT_COOKIE] = { .type = NL_A_UNSPEC, .optional = true, },
> +        [TCA_ACT_OPTIONS] = { .type = NL_A_NESTED, .optional = true, },
> +        [TCA_ACT_STATS] = { .type = NL_A_NESTED, .optional = false, },
> +    };
> +    struct nlattr *action_police_attrs[ARRAY_SIZE(act_policy)];
> +    const int max_size = ARRAY_SIZE(actions_orders_policy);
> +    const struct tc_police *tc_police = NULL;
> +    ofproto_meter_id meter_id;
> +    size_t revalidate_num;
> +    size_t act_count;
> +    uint32_t index;
> +    int i;
> +
> +    if (!reply) {
> +        VLOG_ERR_RL(&rl, "null reply message during meter revalidation\n");
> +        return;
> +    }
> +
> +    if (reply->size <= NLMSG_ALIGNTO + NLMSG_HDRLEN) {
> +        VLOG_DBG_RL(&rl, "no meters present in tc during meter "
> +                    "revalidation\n");
> +        return;
> +    }
> +
> +    if (!nl_policy_parse(reply, NLMSG_HDRLEN + sizeof(struct tcamsg),
> +                        tca_root_policy, action_root_attrs,
> +                        ARRAY_SIZE(action_root_attrs))) {
> +        VLOG_ERR_RL(&rl, "failed to parse reply message during meter "
> +                    "revalidation\n");
> +        return;
> +    }
> +
> +    act_count = nl_attr_get_u32(action_root_attrs[TCA_ROOT_COUNT]);
> +    if (!act_count) {
> +        VLOG_ERR_RL(&rl, "no police action returned in message during "
> +                    "meter revalidation\n");
> +        return;
> +    }
> +
> +    for (i = 0; i < max_size; i++) {
> +        actions_orders_policy[i].type = NL_A_NESTED;
> +        actions_orders_policy[i].optional = true;
> +    }
> +
> +    revalidate_num = act_count > ACT_MAX_NUM ?
> +                                (ACT_MAX_NUM + 1) : (act_count + 1);
> +    if (!nl_parse_nested(action_root_attrs[TCA_ACT_TAB], actions_orders_policy,
> +                        actions_orders, revalidate_num)) {
> +        VLOG_ERR_RL(&rl, "failed to parse TCA_ACT_TAB during meter "
> +                    "revalidation of act_count\n");
> +        return;
> +    }
> +
> +    for (i = 0; i < revalidate_num; i++) {
> +        if (!actions_orders[i]) {
> +            continue;
> +        }
> +
> +        if (!nl_parse_nested(actions_orders[i], act_policy,
> +                            action_police_attrs, ARRAY_SIZE(act_policy))) {
> +            VLOG_ERR_RL(&rl, "failed to parse police action during meter "
> +                      "revalidation\n");
> +            return;
> +        }
> +
> +        if (strcmp(nl_attr_get_string(action_police_attrs[TCA_KIND]),
> +                                    "police")) {
> +            VLOG_EMER("non-police action found during meter revalidation\n");
> +            continue;
> +        }
> +
> +        if (!nl_parse_nested(action_police_attrs[TCA_ACT_OPTIONS],
> +                             police_policy, action_police_tab,
> +                             ARRAY_SIZE(action_police_tab))) {
> +            VLOG_ERR_RL(&rl, "failed to parse the single police action "
> +                        "during meter revalidation\n");
> +            return;
> +        }
> +
> +        tc_police = nl_attr_get_unspec(action_police_tab[TCA_POLICE_TBF],
> +                                       sizeof *tc_police);
> +        if (!tc_police) {
> +            VLOG_ERR_RL(&rl, "can not get police struct during meter "
> +                        "revalidation\n");
> +            continue;
> +        }
> +        index = tc_police->index;
> +        /* The range of meter index is 0x10000000 to 0x1fffffff
> +         * If not meter, continue */
> +        if (!tc_is_meter_index(index)) {
> +            VLOG_DBG_RL(&rl, "Meter index : %d is not meter:"
> +                        "action = %d, rate = %d, burst = %d, mtu = %d",
> +                        index, tc_police->action, tc_police->rate.rate,
> +                        tc_police->burst, tc_police->mtu);
> +            continue;
> +        }
> +
> +        /* transform police index to meter id */
> +        index = POLICY_INDEX_TO_METER_ID(index);
> +        if (dpif_netlink_meter_should_revalidate(backer, index)) {
> +            meter_id.uint32 = index;
> +            VLOG_DBG_RL(&rl, "revalidate meter id %u for police index "
> +                        "%08x\n", index, tc_police->index);
> +            meter_offload_del(meter_id, NULL);
> +        }
> +    }
> +}
> +
> +static int
> +dpif_netlink_meter_revalidate__(struct dpif *dpif_ OVS_UNUSED,
> +                                struct dpif_backer *backer)
> +{
> +    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5,20);
> +    struct nla_bitfield32 dump_flags = { TCA_DUMP_FLAGS_TERSE,
> +                                         TCA_DUMP_FLAGS_TERSE};
> +    struct ofpbuf request;
> +    struct ofpbuf *reply;
> +    struct tcamsg *tcmsg;
> +    size_t total_offset;
> +    size_t act_offset;
> +    int prio = 0;
> +    int error;
> +
> +    if (!netdev_is_flow_api_enabled()) {
> +        return 0;
> +    }
> +    /* Make tc action request */
> +    ofpbuf_init(&request, 16384);
> +    nl_msg_put_nlmsghdr(&request, sizeof *tcmsg, RTM_GETACTION,
> +                        NLM_F_REQUEST | NLM_F_DUMP);
> +    tcmsg = ofpbuf_put_zeros(&request, sizeof *tcmsg);
> +    tcmsg->tca_family = AF_UNSPEC;
> +    if (!tcmsg) {
> +        return ENODEV;
> +    }
> +
> +    /* Data path interface netlink police start */
> +    total_offset = nl_msg_start_nested(&request, TCA_ACT_TAB);
> +    act_offset = nl_msg_start_nested(&request, ++prio);
> +    /* Send request */
> +    nl_msg_put_string(&request, TCA_KIND, "police");
> +
> +    /* Data path interface netlink police end */
> +    nl_msg_end_nested(&request, act_offset);
> +    nl_msg_end_nested(&request, total_offset);
> +
> +    nl_msg_put_unspec(&request, TCA_ROOT_FLAGS, &dump_flags,
> +                      sizeof dump_flags);
> +    error = tc_transact(&request, &reply);
> +    if (error) {
> +        VLOG_ERR_RL(&rl, "failed to send dump netlink msg for revalidate "
> +                    "error %d\n", error);
> +        return error;
> +    }
> +    dpif_tc_meter_revalidate(dpif_, backer, reply);
> +    ofpbuf_delete(reply);
> +    return 0;
> +}
> +
>  static int
>  dpif_netlink_meter_set__(struct dpif *dpif_, ofproto_meter_id meter_id,
>                           struct ofputil_meter_config *config)
> @@ -4370,6 +4559,19 @@ dpif_netlink_meter_del(struct dpif *dpif, ofproto_meter_id meter_id,
>      return err;
>  }
>
> +static int
> +dpif_netlink_meter_revalidate(struct dpif *dpif_, struct dpif_backer *backer)
> +{
> +    int err;
> +
> +    if (probe_broken_meters(dpif_)) {
> +        return ENOMEM;
> +    }
> +    err = dpif_netlink_meter_revalidate__(dpif_, backer);
> +
> +    return err;
> +}
> +
>  static bool
>  probe_broken_meters__(struct dpif *dpif)
>  {
> @@ -4589,6 +4791,7 @@ const struct dpif_class dpif_netlink_class = {
>      dpif_netlink_meter_set,
>      dpif_netlink_meter_get,
>      dpif_netlink_meter_del,
> +    dpif_netlink_meter_revalidate,
>      NULL,                       /* bond_add */
>      NULL,                       /* bond_del */
>      NULL,                       /* bond_stats_get */
> diff --git a/lib/dpif-netlink.h b/lib/dpif-netlink.h
> index 24294bc42dc3..b3b113dc407c 100644
> --- a/lib/dpif-netlink.h
> +++ b/lib/dpif-netlink.h
> @@ -17,6 +17,8 @@
>  #ifndef DPIF_NETLINK_H
>  #define DPIF_NETLINK_H 1
>
> +#include <linux/pkt_cls.h>
> +
>  #include <stdbool.h>
>  #include <stddef.h>
>  #include <stdint.h>
> diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
> index 12477a24feee..efc6ca989fa9 100644
> --- a/lib/dpif-provider.h
> +++ b/lib/dpif-provider.h
> @@ -25,6 +25,7 @@
>  #include "openflow/openflow.h"
>  #include "dpif.h"
>  #include "util.h"
> +#include "ofproto/ofproto-dpif.h"
>
>  #ifdef  __cplusplus
>  extern "C" {
> @@ -631,6 +632,10 @@ struct dpif_class {
>      int (*meter_del)(struct dpif *, ofproto_meter_id meter_id,
>                       struct ofputil_meter_stats *, uint16_t n_bands);
>
> +    /* Checks unneeded meters from 'dpif' and removes them. They may
> +     * be caused by deleting in-use meters. */
> +    int (*meter_revalidate)(struct dpif *, struct dpif_backer *);
> +
>      /* Adds a bond with 'bond_id' and the member-map to 'dpif'. */
>      int (*bond_add)(struct dpif *dpif, uint32_t bond_id,
>                      odp_port_t *member_map);
> diff --git a/lib/dpif.c b/lib/dpif.c
> index 40f5fe44606e..ceee076af195 100644
> --- a/lib/dpif.c
> +++ b/lib/dpif.c
> @@ -1491,12 +1491,12 @@ dpif_recv_set(struct dpif *dpif, bool enable)
>   *
>   * Returns 0 if successful, otherwise a positive errno value. */
>  int
> -dpif_handlers_set(struct dpif *dpif, uint32_t n_handlers)
> +dpif_handlers_set(struct dpif *dpif, uint32_t _n_handlers)
>  {
>      int error = 0;
>
>      if (dpif->dpif_class->handlers_set) {
> -        error = dpif->dpif_class->handlers_set(dpif, n_handlers);
> +        error = dpif->dpif_class->handlers_set(dpif, _n_handlers);
>          log_operation(dpif, "handlers_set", error);
>      }
>      return error;
> @@ -1510,10 +1510,10 @@ dpif_handlers_set(struct dpif *dpif, uint32_t n_handlers)
>   * If not, returns 'false'
>   */
>  bool
> -dpif_number_handlers_required(struct dpif *dpif, uint32_t *n_handlers)
> +dpif_number_handlers_required(struct dpif *dpif, uint32_t *_n_handlers)
>  {
>      if (dpif->dpif_class->number_handlers_required) {
> -        return dpif->dpif_class->number_handlers_required(dpif, n_handlers);
> +        return dpif->dpif_class->number_handlers_required(dpif, _n_handlers);
>      }
>      return false;
>  }
> @@ -2028,6 +2028,13 @@ dpif_meter_del(struct dpif *dpif, ofproto_meter_id meter_id,
>      return error;
>  }
>
> +int
> +dpif_meter_revalidate(struct dpif *dpif, struct dpif_backer *backer){
> +    return dpif->dpif_class->meter_revalidate
> +           ? dpif->dpif_class->meter_revalidate(dpif, backer)
> +           : EOPNOTSUPP;
> +}
> +
>  int
>  dpif_bond_add(struct dpif *dpif, uint32_t bond_id, odp_port_t *member_map)
>  {
> diff --git a/lib/id-pool.c b/lib/id-pool.c
> index 69910ad08e83..64096a184563 100644
> --- a/lib/id-pool.c
> +++ b/lib/id-pool.c
> @@ -155,3 +155,16 @@ id_pool_free_id(struct id_pool *pool, uint32_t id)
>          }
>      }
>  }
> +
> +bool
> +id_pool_id_exist(struct  id_pool *pool, uint32_t id)
> +{
> +    return !!id_pool_find(pool, id);
> +}
> +
> +uint32_t id_pool_base(struct id_pool *pool){
> +    return pool->base;
> +}
> +uint32_t id_pool_n(struct id_pool *pool){
> +    return pool->n_ids;
> +}
> diff --git a/lib/id-pool.h b/lib/id-pool.h
> index 8721f87934bb..b3bfd79386db 100644
> --- a/lib/id-pool.h
> +++ b/lib/id-pool.h
> @@ -29,7 +29,9 @@ void id_pool_destroy(struct id_pool *);
>  bool id_pool_alloc_id(struct id_pool *, uint32_t *id);
>  void id_pool_free_id(struct id_pool *, uint32_t id);
>  void id_pool_add(struct id_pool *, uint32_t id);
> -
> +bool id_pool_id_exist(struct id_pool *pool, uint32_t id);
> +uint32_t id_pool_base(struct id_pool *pool);
> +uint32_t id_pool_n(struct id_pool *pool);
>  /*
>   * ID pool.
>   * ========
> diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
> index cdc66246ced3..2bb0eda9d581 100644
> --- a/lib/netdev-linux.c
> +++ b/lib/netdev-linux.c
> @@ -5823,6 +5823,12 @@ tc_del_policer_action(uint32_t index, struct ofputil_meter_stats *stats)
>
>      error = tc_transact(&request, &replyp);
>      if (error) {
> +        if (error == EPERM || error == ENOENT) {
> +            /* EPERM means flow exists, it is right that meter deletion is
> +             * not permited.
> +             * ENOENT means meter has already been deleted. */
> +            return error;
> +        }
>          VLOG_ERR_RL(&rl, "Failed to delete police action (index: %u), err=%d",
>                      index, error);
>          return error;
> diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c
> index f6f90a741fde..df0247dc264c 100644
> --- a/lib/netdev-offload-tc.c
> +++ b/lib/netdev-offload-tc.c
> @@ -2953,10 +2953,19 @@ meter_tc_del_policer(ofproto_meter_id meter_id,
>      if (!meter_id_lookup(meter_id.uint32, &police_index)) {
>          err = tc_del_policer_action(police_index, stats);
>          if (err && err != ENOENT) {
> +            if (err == EPERM) {
> +                /* Flow exists, it is right that meter deletion is not
> +                 * permited. */
> +                return err;
> +            }
>              VLOG_ERR_RL(&error_rl,
> -                        "Failed to del police %u for meter %u: %s",
> +                        "Deletion of police %u for meter %u failed: %s",
>                          police_index, meter_id.uint32, ovs_strerror(err));
> +            return err;
>          } else {
> +            VLOG_DBG("Deletion of police %u for meter %u succeeded: %s",
> +                        police_index, meter_id.uint32, ovs_strerror(err));
> +            err = 0;
>              meter_free_police_index(police_index);
>          }
>          meter_id_remove(meter_id.uint32);
> diff --git a/lib/tc.c b/lib/tc.c
> index 94044cde6060..c7d539562fc6 100644
> --- a/lib/tc.c
> +++ b/lib/tc.c
> @@ -51,9 +51,6 @@
>  #define TCM_IFINDEX_MAGIC_BLOCK (0xFFFFFFFFU)
>  #endif
>
> -#ifndef TCA_DUMP_FLAGS_TERSE
> -#define TCA_DUMP_FLAGS_TERSE (1 << 0)
> -#endif
>
>  #if TCA_MAX < 15
>  #define TCA_CHAIN 11
> @@ -1987,8 +1984,6 @@ tc_parse_action_stats(struct nlattr *action, struct ovs_flow_stats *stats_sw,
>                                   stats_hw, stats_dropped);
>  }
>
> -#define TCA_ACT_MIN_PRIO 1
> -
>  static int
>  nl_parse_flower_actions(struct nlattr **attrs, struct tc_flower *flower,
>                          bool terse)
> diff --git a/lib/tc.h b/lib/tc.h
> index 2e64ad372592..8e7107d1bd74 100644
> --- a/lib/tc.h
> +++ b/lib/tc.h
> @@ -60,6 +60,10 @@ enum tc_qdisc_hook {
>
>  #define METER_POLICE_IDS_BASE 0x10000000
>  #define METER_POLICE_IDS_MAX  0x1FFFFFFF
> +/* Mapping meter_id.uint32 into a 32-bit integer */
> +#define METER_ID_TO_POLICY_INDEX(meter_id) (meter_id | METER_POLICE_IDS_BASE)
> +/* Mapping policy_index to meter_id */
> +#define POLICY_INDEX_TO_METER_ID(index) (index & ~METER_POLICE_IDS_BASE)
>
>  static inline bool
>  tc_is_meter_index(uint32_t index) {
> @@ -300,8 +304,12 @@ enum tc_offloaded_state {
>      TC_OFFLOADED_STATE_IN_HW,
>      TC_OFFLOADED_STATE_NOT_IN_HW,
>  };
> -
> +#ifndef TCA_DUMP_FLAGS_TERSE
> +#define TCA_DUMP_FLAGS_TERSE (1 << 0)
> +#endif
> +#define ACT_MAX_NUM 1024
>  #define TCA_ACT_MAX_NUM 16
> +#define TCA_ACT_MIN_PRIO 1
>
>  struct tcf_id {
>      enum tc_qdisc_hook hook;
> diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
> index 7ad728adffdb..09c1c7aedc34 100644
> --- a/ofproto/ofproto-dpif-upcall.c
> +++ b/ofproto/ofproto-dpif-upcall.c
> @@ -2659,6 +2659,7 @@ revalidate(struct revalidator *revalidator)
>      struct udpif *udpif = revalidator->udpif;
>      struct dpif_flow_dump_thread *dump_thread;
>      uint64_t dump_seq, reval_seq;
> +    bool flow_delete_exist = false;
>      bool kill_warn_print = true;
>      unsigned int flow_limit;
>
> @@ -2790,6 +2791,7 @@ revalidate(struct revalidator *revalidator)
>
>              if (result != UKEY_KEEP) {
>                  /* Takes ownership of 'recircs'. */
> +                flow_delete_exist = true;
>                  reval_op_init(&ops[n_ops++], result, udpif, ukey, &recircs,
>                                &odp_actions);
>              }
> @@ -2803,6 +2805,9 @@ revalidate(struct revalidator *revalidator)
>          ovsrcu_quiesce();
>      }
>      dpif_flow_dump_thread_destroy(dump_thread);
> +    if (flow_delete_exist) {
> +        dpif_meter_revalidate(udpif->dpif, udpif->backer);
> +    }
>      ofpbuf_uninit(&odp_actions);
>  }
>
> diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h
> index d8e0cd37ac5b..ef0c7338e04e 100644
> --- a/ofproto/ofproto-dpif.h
> +++ b/ofproto/ofproto-dpif.h
> @@ -404,4 +404,6 @@ bool ofproto_dpif_ct_zone_timeout_policy_get_name(
>
>  bool ovs_explicit_drop_action_supported(struct ofproto_dpif *);
>
> +int dpif_meter_revalidate(struct dpif *dpif, struct dpif_backer *backer);
> +
>  #endif /* ofproto-dpif.h */
> diff --git a/tests/system-offloads-traffic.at b/tests/system-offloads-traffic.at
> index 1a60570801e1..0ca3897a721f 100644
> --- a/tests/system-offloads-traffic.at
> +++ b/tests/system-offloads-traffic.at
> @@ -273,6 +273,10 @@ meter:1 flow_count:1 packet_in_count:11 byte_in_count:377 duration:0.001s bands:
>  0: packet_count:9 byte_count:0
>  ])
>
> +AT_CHECK([ovs-ofctl -O Openflow13 del-meter br0])
> +sleep 10
> +AT_CHECK([tc actions ls action police], [0], [])
> +
>  OVS_TRAFFIC_VSWITCHD_STOP
>  AT_CLEANUP
>
> -- 
> 2.30.2
diff mbox series

Patch

diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index a45b460145c6..365aacadb03a 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -9583,6 +9583,7 @@  const struct dpif_class dpif_netdev_class = {
     dpif_netdev_meter_set,
     dpif_netdev_meter_get,
     dpif_netdev_meter_del,
+    NULL,                       /* meter_revalidate */
     dpif_netdev_bond_add,
     dpif_netdev_bond_del,
     dpif_netdev_bond_stats_get,
diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
index a620a6ec52dd..4eee4761dc6b 100644
--- a/lib/dpif-netlink.c
+++ b/lib/dpif-netlink.c
@@ -25,6 +25,7 @@ 
 #include <net/if.h>
 #include <linux/types.h>
 #include <linux/pkt_sched.h>
+#include <linux/rtnetlink.h>
 #include <poll.h>
 #include <stdlib.h>
 #include <strings.h>
@@ -48,6 +49,7 @@ 
 #include "netlink.h"
 #include "netnsid.h"
 #include "odp-util.h"
+#include "ofproto/ofproto-dpif.h"
 #include "openvswitch/dynamic-string.h"
 #include "openvswitch/flow.h"
 #include "openvswitch/hmap.h"
@@ -61,6 +63,7 @@ 
 #include "packets.h"
 #include "random.h"
 #include "sset.h"
+#include "tc.h"
 #include "timeval.h"
 #include "unaligned.h"
 #include "util.h"
@@ -2571,18 +2574,18 @@  static uint32_t
 dpif_netlink_calculate_n_handlers(void)
 {
     uint32_t total_cores = count_total_cores();
-    uint32_t n_handlers = count_cpu_cores();
+    uint32_t _n_handlers = count_cpu_cores();
     uint32_t next_prime_num;
 
     /* If not all cores are available to OVS, create additional handler
      * threads to ensure more fair distribution of load between them.
      */
-    if (n_handlers < total_cores && total_cores > 2) {
-        next_prime_num = next_prime(n_handlers + 1);
-        n_handlers = MIN(next_prime_num, total_cores);
+    if (_n_handlers < total_cores && total_cores > 2) {
+        next_prime_num = next_prime(_n_handlers + 1);
+        _n_handlers = MIN(next_prime_num, total_cores);
     }
 
-    return n_handlers;
+    return _n_handlers;
 }
 
 static int
@@ -2591,17 +2594,17 @@  dpif_netlink_refresh_handlers_cpu_dispatch(struct dpif_netlink *dpif)
 {
     int handler_id;
     int error = 0;
-    uint32_t n_handlers;
     uint32_t *upcall_pids;
+    uint32_t _n_handlers;
 
-    n_handlers = dpif_netlink_calculate_n_handlers();
-    if (dpif->n_handlers != n_handlers) {
+    _n_handlers = dpif_netlink_calculate_n_handlers();
+    if (dpif->n_handlers != _n_handlers) {
         VLOG_DBG("Dispatch mode(per-cpu): initializing %d handlers",
-                   n_handlers);
+                   _n_handlers);
         destroy_all_handlers(dpif);
-        upcall_pids = xzalloc(n_handlers * sizeof *upcall_pids);
-        dpif->handlers = xzalloc(n_handlers * sizeof *dpif->handlers);
-        for (handler_id = 0; handler_id < n_handlers; handler_id++) {
+        upcall_pids = xzalloc(_n_handlers * sizeof *upcall_pids);
+        dpif->handlers = xzalloc(_n_handlers * sizeof *dpif->handlers);
+        for (handler_id = 0; handler_id < _n_handlers; handler_id++) {
             struct dpif_handler *handler = &dpif->handlers[handler_id];
             error = create_nl_sock(dpif, &handler->sock);
             if (error) {
@@ -2615,9 +2618,9 @@  dpif_netlink_refresh_handlers_cpu_dispatch(struct dpif_netlink *dpif)
                       handler_id, upcall_pids[handler_id]);
         }
 
-        dpif->n_handlers = n_handlers;
+        dpif->n_handlers = _n_handlers;
         error = dpif_netlink_set_handler_pids(&dpif->dpif, upcall_pids,
-                                              n_handlers);
+                                              _n_handlers);
         free(upcall_pids);
     }
     return error;
@@ -2629,7 +2632,7 @@  dpif_netlink_refresh_handlers_cpu_dispatch(struct dpif_netlink *dpif)
  * backing kernel vports. */
 static int
 dpif_netlink_refresh_handlers_vport_dispatch(struct dpif_netlink *dpif,
-                                             uint32_t n_handlers)
+                                             uint32_t _n_handlers)
     OVS_REQ_WRLOCK(dpif->upcall_lock)
 {
     unsigned long int *keep_channels;
@@ -2641,13 +2644,13 @@  dpif_netlink_refresh_handlers_vport_dispatch(struct dpif_netlink *dpif,
     int retval = 0;
     size_t i;
 
-    ovs_assert(!WINDOWS || n_handlers <= 1);
+    ovs_assert(!WINDOWS || _n_handlers <= 1);
     ovs_assert(!WINDOWS || dpif->n_handlers <= 1);
 
-    if (dpif->n_handlers != n_handlers) {
+    if (dpif->n_handlers != _n_handlers) {
         destroy_all_channels(dpif);
-        dpif->handlers = xzalloc(n_handlers * sizeof *dpif->handlers);
-        for (i = 0; i < n_handlers; i++) {
+        dpif->handlers = xzalloc(_n_handlers * sizeof *dpif->handlers);
+        for (i = 0; i < _n_handlers; i++) {
             int error;
             struct dpif_handler *handler = &dpif->handlers[i];
 
@@ -2665,10 +2668,10 @@  dpif_netlink_refresh_handlers_vport_dispatch(struct dpif_netlink *dpif,
                 return error;
             }
         }
-        dpif->n_handlers = n_handlers;
+        dpif->n_handlers = _n_handlers;
     }
 
-    for (i = 0; i < n_handlers; i++) {
+    for (i = 0; i < _n_handlers; i++) {
         struct dpif_handler *handler = &dpif->handlers[i];
 
         handler->event_offset = handler->n_events = 0;
@@ -2801,7 +2804,7 @@  dpif_netlink_recv_set(struct dpif *dpif_, bool enable)
 }
 
 static int
-dpif_netlink_handlers_set(struct dpif *dpif_, uint32_t n_handlers)
+dpif_netlink_handlers_set(struct dpif *dpif_, uint32_t _n_handlers)
 {
     struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
     int error = 0;
@@ -2809,7 +2812,7 @@  dpif_netlink_handlers_set(struct dpif *dpif_, uint32_t n_handlers)
 #ifdef _WIN32
     /* Multiple upcall handlers will be supported once kernel datapath supports
      * it. */
-    if (n_handlers > 1) {
+    if (_n_handlers > 1) {
         return error;
     }
 #endif
@@ -2820,7 +2823,7 @@  dpif_netlink_handlers_set(struct dpif *dpif_, uint32_t n_handlers)
             error = dpif_netlink_refresh_handlers_cpu_dispatch(dpif);
         } else {
             error = dpif_netlink_refresh_handlers_vport_dispatch(dpif,
-                                                                 n_handlers);
+                                                                 _n_handlers);
         }
     }
     fat_rwlock_unlock(&dpif->upcall_lock);
@@ -2829,12 +2832,13 @@  dpif_netlink_handlers_set(struct dpif *dpif_, uint32_t n_handlers)
 }
 
 static bool
-dpif_netlink_number_handlers_required(struct dpif *dpif_, uint32_t *n_handlers)
+dpif_netlink_number_handlers_required(struct dpif *dpif_,
+                                      uint32_t *_n_handlers)
 {
     struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
 
     if (dpif_netlink_upcall_per_cpu(dpif)) {
-        *n_handlers = dpif_netlink_calculate_n_handlers();
+        *_n_handlers = dpif_netlink_calculate_n_handlers();
         return true;
     }
 
@@ -2843,7 +2847,7 @@  dpif_netlink_number_handlers_required(struct dpif *dpif_, uint32_t *n_handlers)
 
 static int
 dpif_netlink_queue_to_priority(const struct dpif *dpif OVS_UNUSED,
-                             uint32_t queue_id, uint32_t *priority)
+                               uint32_t queue_id, uint32_t *priority)
 {
     if (queue_id < 0xf000) {
         *priority = TC_H_MAKE(1 << 16, queue_id + 1);
@@ -4161,6 +4165,191 @@  dpif_netlink_meter_get_features(const struct dpif *dpif_,
     ofpbuf_delete(msg);
 }
 
+static bool dpif_netlink_meter_should_revalidate(struct dpif_backer *backer,
+                                                 uint32_t meter_id)
+{
+    return !id_pool_id_exist(backer->meter_ids, meter_id);
+}
+
+static void
+dpif_tc_meter_revalidate(struct dpif *dpif_ OVS_UNUSED,
+                         struct dpif_backer *backer, struct ofpbuf *reply)
+{
+    static struct nl_policy actions_orders_policy[ACT_MAX_NUM + 1] = {};
+    struct nlattr *actions_orders[ARRAY_SIZE(actions_orders_policy)];
+    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5,20);
+    static const struct nl_policy tca_root_policy[] = {
+        [TCA_ACT_TAB] = { .type = NL_A_NESTED, .optional = false },
+        [TCA_ROOT_COUNT] = { .type = NL_A_U32, .optional = false },
+    };
+    struct nlattr *action_root_attrs[ARRAY_SIZE(tca_root_policy)];
+    static const struct nl_policy police_policy[] = {
+        [TCA_POLICE_TBF] = { .type = NL_A_UNSPEC,
+                             .min_len = sizeof(struct tc_police),
+                             .optional = false},
+    };
+    struct nlattr *action_police_tab[ARRAY_SIZE(police_policy)];
+    static const struct nl_policy act_policy[] = {
+        [TCA_ACT_KIND] = { .type = NL_A_STRING, .optional = false, },
+        [TCA_ACT_COOKIE] = { .type = NL_A_UNSPEC, .optional = true, },
+        [TCA_ACT_OPTIONS] = { .type = NL_A_NESTED, .optional = true, },
+        [TCA_ACT_STATS] = { .type = NL_A_NESTED, .optional = false, },
+    };
+    struct nlattr *action_police_attrs[ARRAY_SIZE(act_policy)];
+    const int max_size = ARRAY_SIZE(actions_orders_policy);
+    const struct tc_police *tc_police = NULL;
+    ofproto_meter_id meter_id;
+    size_t revalidate_num;
+    size_t act_count;
+    uint32_t index;
+    int i;
+
+    if (!reply) {
+        VLOG_ERR_RL(&rl, "null reply message during meter revalidation\n");
+        return;
+    }
+
+    if (reply->size <= NLMSG_ALIGNTO + NLMSG_HDRLEN) {
+        VLOG_DBG_RL(&rl, "no meters present in tc during meter "
+                    "revalidation\n");
+        return;
+    }
+
+    if (!nl_policy_parse(reply, NLMSG_HDRLEN + sizeof(struct tcamsg),
+                        tca_root_policy, action_root_attrs,
+                        ARRAY_SIZE(action_root_attrs))) {
+        VLOG_ERR_RL(&rl, "failed to parse reply message during meter "
+                    "revalidation\n");
+        return;
+    }
+
+    act_count = nl_attr_get_u32(action_root_attrs[TCA_ROOT_COUNT]);
+    if (!act_count) {
+        VLOG_ERR_RL(&rl, "no police action returned in message during "
+                    "meter revalidation\n");
+        return;
+    }
+
+    for (i = 0; i < max_size; i++) {
+        actions_orders_policy[i].type = NL_A_NESTED;
+        actions_orders_policy[i].optional = true;
+    }
+
+    revalidate_num = act_count > ACT_MAX_NUM ?
+                                (ACT_MAX_NUM + 1) : (act_count + 1);
+    if (!nl_parse_nested(action_root_attrs[TCA_ACT_TAB], actions_orders_policy,
+                        actions_orders, revalidate_num)) {
+        VLOG_ERR_RL(&rl, "failed to parse TCA_ACT_TAB during meter "
+                    "revalidation of act_count\n");
+        return;
+    }
+
+    for (i = 0; i < revalidate_num; i++) {
+        if (!actions_orders[i]) {
+            continue;
+        }
+
+        if (!nl_parse_nested(actions_orders[i], act_policy,
+                            action_police_attrs, ARRAY_SIZE(act_policy))) {
+            VLOG_ERR_RL(&rl, "failed to parse police action during meter "
+                      "revalidation\n");
+            return;
+        }
+
+        if (strcmp(nl_attr_get_string(action_police_attrs[TCA_KIND]),
+                                    "police")) {
+            VLOG_EMER("non-police action found during meter revalidation\n");
+            continue;
+        }
+
+        if (!nl_parse_nested(action_police_attrs[TCA_ACT_OPTIONS],
+                             police_policy, action_police_tab,
+                             ARRAY_SIZE(action_police_tab))) {
+            VLOG_ERR_RL(&rl, "failed to parse the single police action "
+                        "during meter revalidation\n");
+            return;
+        }
+
+        tc_police = nl_attr_get_unspec(action_police_tab[TCA_POLICE_TBF],
+                                       sizeof *tc_police);
+        if (!tc_police) {
+            VLOG_ERR_RL(&rl, "can not get police struct during meter "
+                        "revalidation\n");
+            continue;
+        }
+        index = tc_police->index;
+        /* The range of meter index is 0x10000000 to 0x1fffffff
+         * If not meter, continue */
+        if (!tc_is_meter_index(index)) {
+            VLOG_DBG_RL(&rl, "Meter index : %d is not meter:"
+                        "action = %d, rate = %d, burst = %d, mtu = %d",
+                        index, tc_police->action, tc_police->rate.rate,
+                        tc_police->burst, tc_police->mtu);
+            continue;
+        }
+
+        /* transform police index to meter id */
+        index = POLICY_INDEX_TO_METER_ID(index);
+        if (dpif_netlink_meter_should_revalidate(backer, index)) {
+            meter_id.uint32 = index;
+            VLOG_DBG_RL(&rl, "revalidate meter id %u for police index "
+                        "%08x\n", index, tc_police->index);
+            meter_offload_del(meter_id, NULL);
+        }
+    }
+}
+
+static int
+dpif_netlink_meter_revalidate__(struct dpif *dpif_ OVS_UNUSED,
+                                struct dpif_backer *backer)
+{
+    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5,20);
+    struct nla_bitfield32 dump_flags = { TCA_DUMP_FLAGS_TERSE,
+                                         TCA_DUMP_FLAGS_TERSE};
+    struct ofpbuf request;
+    struct ofpbuf *reply;
+    struct tcamsg *tcmsg;
+    size_t total_offset;
+    size_t act_offset;
+    int prio = 0;
+    int error;
+
+    if (!netdev_is_flow_api_enabled()) {
+        return 0;
+    }
+    /* Make tc action request */
+    ofpbuf_init(&request, 16384);
+    nl_msg_put_nlmsghdr(&request, sizeof *tcmsg, RTM_GETACTION,
+                        NLM_F_REQUEST | NLM_F_DUMP);
+    tcmsg = ofpbuf_put_zeros(&request, sizeof *tcmsg);
+    tcmsg->tca_family = AF_UNSPEC;
+    if (!tcmsg) {
+        return ENODEV;
+    }
+
+    /* Data path interface netlink police start */
+    total_offset = nl_msg_start_nested(&request, TCA_ACT_TAB);
+    act_offset = nl_msg_start_nested(&request, ++prio);
+    /* Send request */
+    nl_msg_put_string(&request, TCA_KIND, "police");
+
+    /* Data path interface netlink police end */
+    nl_msg_end_nested(&request, act_offset);
+    nl_msg_end_nested(&request, total_offset);
+
+    nl_msg_put_unspec(&request, TCA_ROOT_FLAGS, &dump_flags,
+                      sizeof dump_flags);
+    error = tc_transact(&request, &reply);
+    if (error) {
+        VLOG_ERR_RL(&rl, "failed to send dump netlink msg for revalidate "
+                    "error %d\n", error);
+        return error;
+    }
+    dpif_tc_meter_revalidate(dpif_, backer, reply);
+    ofpbuf_delete(reply);
+    return 0;
+}
+
 static int
 dpif_netlink_meter_set__(struct dpif *dpif_, ofproto_meter_id meter_id,
                          struct ofputil_meter_config *config)
@@ -4370,6 +4559,19 @@  dpif_netlink_meter_del(struct dpif *dpif, ofproto_meter_id meter_id,
     return err;
 }
 
+static int
+dpif_netlink_meter_revalidate(struct dpif *dpif_, struct dpif_backer *backer)
+{
+    int err;
+
+    if (probe_broken_meters(dpif_)) {
+        return ENOMEM;
+    }
+    err = dpif_netlink_meter_revalidate__(dpif_, backer);
+
+    return err;
+}
+
 static bool
 probe_broken_meters__(struct dpif *dpif)
 {
@@ -4589,6 +4791,7 @@  const struct dpif_class dpif_netlink_class = {
     dpif_netlink_meter_set,
     dpif_netlink_meter_get,
     dpif_netlink_meter_del,
+    dpif_netlink_meter_revalidate,
     NULL,                       /* bond_add */
     NULL,                       /* bond_del */
     NULL,                       /* bond_stats_get */
diff --git a/lib/dpif-netlink.h b/lib/dpif-netlink.h
index 24294bc42dc3..b3b113dc407c 100644
--- a/lib/dpif-netlink.h
+++ b/lib/dpif-netlink.h
@@ -17,6 +17,8 @@ 
 #ifndef DPIF_NETLINK_H
 #define DPIF_NETLINK_H 1
 
+#include <linux/pkt_cls.h>
+
 #include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
index 12477a24feee..efc6ca989fa9 100644
--- a/lib/dpif-provider.h
+++ b/lib/dpif-provider.h
@@ -25,6 +25,7 @@ 
 #include "openflow/openflow.h"
 #include "dpif.h"
 #include "util.h"
+#include "ofproto/ofproto-dpif.h"
 
 #ifdef  __cplusplus
 extern "C" {
@@ -631,6 +632,10 @@  struct dpif_class {
     int (*meter_del)(struct dpif *, ofproto_meter_id meter_id,
                      struct ofputil_meter_stats *, uint16_t n_bands);
 
+    /* Checks unneeded meters from 'dpif' and removes them. They may
+     * be caused by deleting in-use meters. */
+    int (*meter_revalidate)(struct dpif *, struct dpif_backer *);
+
     /* Adds a bond with 'bond_id' and the member-map to 'dpif'. */
     int (*bond_add)(struct dpif *dpif, uint32_t bond_id,
                     odp_port_t *member_map);
diff --git a/lib/dpif.c b/lib/dpif.c
index 40f5fe44606e..ceee076af195 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -1491,12 +1491,12 @@  dpif_recv_set(struct dpif *dpif, bool enable)
  *
  * Returns 0 if successful, otherwise a positive errno value. */
 int
-dpif_handlers_set(struct dpif *dpif, uint32_t n_handlers)
+dpif_handlers_set(struct dpif *dpif, uint32_t _n_handlers)
 {
     int error = 0;
 
     if (dpif->dpif_class->handlers_set) {
-        error = dpif->dpif_class->handlers_set(dpif, n_handlers);
+        error = dpif->dpif_class->handlers_set(dpif, _n_handlers);
         log_operation(dpif, "handlers_set", error);
     }
     return error;
@@ -1510,10 +1510,10 @@  dpif_handlers_set(struct dpif *dpif, uint32_t n_handlers)
  * If not, returns 'false'
  */
 bool
-dpif_number_handlers_required(struct dpif *dpif, uint32_t *n_handlers)
+dpif_number_handlers_required(struct dpif *dpif, uint32_t *_n_handlers)
 {
     if (dpif->dpif_class->number_handlers_required) {
-        return dpif->dpif_class->number_handlers_required(dpif, n_handlers);
+        return dpif->dpif_class->number_handlers_required(dpif, _n_handlers);
     }
     return false;
 }
@@ -2028,6 +2028,13 @@  dpif_meter_del(struct dpif *dpif, ofproto_meter_id meter_id,
     return error;
 }
 
+int
+dpif_meter_revalidate(struct dpif *dpif, struct dpif_backer *backer){
+    return dpif->dpif_class->meter_revalidate
+           ? dpif->dpif_class->meter_revalidate(dpif, backer)
+           : EOPNOTSUPP;
+}
+
 int
 dpif_bond_add(struct dpif *dpif, uint32_t bond_id, odp_port_t *member_map)
 {
diff --git a/lib/id-pool.c b/lib/id-pool.c
index 69910ad08e83..64096a184563 100644
--- a/lib/id-pool.c
+++ b/lib/id-pool.c
@@ -155,3 +155,16 @@  id_pool_free_id(struct id_pool *pool, uint32_t id)
         }
     }
 }
+
+bool
+id_pool_id_exist(struct  id_pool *pool, uint32_t id)
+{
+    return !!id_pool_find(pool, id);
+}
+
+uint32_t id_pool_base(struct id_pool *pool){
+    return pool->base;
+}
+uint32_t id_pool_n(struct id_pool *pool){
+    return pool->n_ids;
+}
diff --git a/lib/id-pool.h b/lib/id-pool.h
index 8721f87934bb..b3bfd79386db 100644
--- a/lib/id-pool.h
+++ b/lib/id-pool.h
@@ -29,7 +29,9 @@  void id_pool_destroy(struct id_pool *);
 bool id_pool_alloc_id(struct id_pool *, uint32_t *id);
 void id_pool_free_id(struct id_pool *, uint32_t id);
 void id_pool_add(struct id_pool *, uint32_t id);
-
+bool id_pool_id_exist(struct id_pool *pool, uint32_t id);
+uint32_t id_pool_base(struct id_pool *pool);
+uint32_t id_pool_n(struct id_pool *pool);
 /*
  * ID pool.
  * ========
diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
index cdc66246ced3..2bb0eda9d581 100644
--- a/lib/netdev-linux.c
+++ b/lib/netdev-linux.c
@@ -5823,6 +5823,12 @@  tc_del_policer_action(uint32_t index, struct ofputil_meter_stats *stats)
 
     error = tc_transact(&request, &replyp);
     if (error) {
+        if (error == EPERM || error == ENOENT) {
+            /* EPERM means flow exists, it is right that meter deletion is
+             * not permited.
+             * ENOENT means meter has already been deleted. */
+            return error;
+        }
         VLOG_ERR_RL(&rl, "Failed to delete police action (index: %u), err=%d",
                     index, error);
         return error;
diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c
index f6f90a741fde..df0247dc264c 100644
--- a/lib/netdev-offload-tc.c
+++ b/lib/netdev-offload-tc.c
@@ -2953,10 +2953,19 @@  meter_tc_del_policer(ofproto_meter_id meter_id,
     if (!meter_id_lookup(meter_id.uint32, &police_index)) {
         err = tc_del_policer_action(police_index, stats);
         if (err && err != ENOENT) {
+            if (err == EPERM) {
+                /* Flow exists, it is right that meter deletion is not
+                 * permited. */
+                return err;
+            }
             VLOG_ERR_RL(&error_rl,
-                        "Failed to del police %u for meter %u: %s",
+                        "Deletion of police %u for meter %u failed: %s",
                         police_index, meter_id.uint32, ovs_strerror(err));
+            return err;
         } else {
+            VLOG_DBG("Deletion of police %u for meter %u succeeded: %s",
+                        police_index, meter_id.uint32, ovs_strerror(err));
+            err = 0;
             meter_free_police_index(police_index);
         }
         meter_id_remove(meter_id.uint32);
diff --git a/lib/tc.c b/lib/tc.c
index 94044cde6060..c7d539562fc6 100644
--- a/lib/tc.c
+++ b/lib/tc.c
@@ -51,9 +51,6 @@ 
 #define TCM_IFINDEX_MAGIC_BLOCK (0xFFFFFFFFU)
 #endif
 
-#ifndef TCA_DUMP_FLAGS_TERSE
-#define TCA_DUMP_FLAGS_TERSE (1 << 0)
-#endif
 
 #if TCA_MAX < 15
 #define TCA_CHAIN 11
@@ -1987,8 +1984,6 @@  tc_parse_action_stats(struct nlattr *action, struct ovs_flow_stats *stats_sw,
                                  stats_hw, stats_dropped);
 }
 
-#define TCA_ACT_MIN_PRIO 1
-
 static int
 nl_parse_flower_actions(struct nlattr **attrs, struct tc_flower *flower,
                         bool terse)
diff --git a/lib/tc.h b/lib/tc.h
index 2e64ad372592..8e7107d1bd74 100644
--- a/lib/tc.h
+++ b/lib/tc.h
@@ -60,6 +60,10 @@  enum tc_qdisc_hook {
 
 #define METER_POLICE_IDS_BASE 0x10000000
 #define METER_POLICE_IDS_MAX  0x1FFFFFFF
+/* Mapping meter_id.uint32 into a 32-bit integer */
+#define METER_ID_TO_POLICY_INDEX(meter_id) (meter_id | METER_POLICE_IDS_BASE)
+/* Mapping policy_index to meter_id */
+#define POLICY_INDEX_TO_METER_ID(index) (index & ~METER_POLICE_IDS_BASE)
 
 static inline bool
 tc_is_meter_index(uint32_t index) {
@@ -300,8 +304,12 @@  enum tc_offloaded_state {
     TC_OFFLOADED_STATE_IN_HW,
     TC_OFFLOADED_STATE_NOT_IN_HW,
 };
-
+#ifndef TCA_DUMP_FLAGS_TERSE
+#define TCA_DUMP_FLAGS_TERSE (1 << 0)
+#endif
+#define ACT_MAX_NUM 1024
 #define TCA_ACT_MAX_NUM 16
+#define TCA_ACT_MIN_PRIO 1
 
 struct tcf_id {
     enum tc_qdisc_hook hook;
diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
index 7ad728adffdb..09c1c7aedc34 100644
--- a/ofproto/ofproto-dpif-upcall.c
+++ b/ofproto/ofproto-dpif-upcall.c
@@ -2659,6 +2659,7 @@  revalidate(struct revalidator *revalidator)
     struct udpif *udpif = revalidator->udpif;
     struct dpif_flow_dump_thread *dump_thread;
     uint64_t dump_seq, reval_seq;
+    bool flow_delete_exist = false;
     bool kill_warn_print = true;
     unsigned int flow_limit;
 
@@ -2790,6 +2791,7 @@  revalidate(struct revalidator *revalidator)
 
             if (result != UKEY_KEEP) {
                 /* Takes ownership of 'recircs'. */
+                flow_delete_exist = true;
                 reval_op_init(&ops[n_ops++], result, udpif, ukey, &recircs,
                               &odp_actions);
             }
@@ -2803,6 +2805,9 @@  revalidate(struct revalidator *revalidator)
         ovsrcu_quiesce();
     }
     dpif_flow_dump_thread_destroy(dump_thread);
+    if (flow_delete_exist) {
+        dpif_meter_revalidate(udpif->dpif, udpif->backer);
+    }
     ofpbuf_uninit(&odp_actions);
 }
 
diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h
index d8e0cd37ac5b..ef0c7338e04e 100644
--- a/ofproto/ofproto-dpif.h
+++ b/ofproto/ofproto-dpif.h
@@ -404,4 +404,6 @@  bool ofproto_dpif_ct_zone_timeout_policy_get_name(
 
 bool ovs_explicit_drop_action_supported(struct ofproto_dpif *);
 
+int dpif_meter_revalidate(struct dpif *dpif, struct dpif_backer *backer);
+
 #endif /* ofproto-dpif.h */
diff --git a/tests/system-offloads-traffic.at b/tests/system-offloads-traffic.at
index 1a60570801e1..0ca3897a721f 100644
--- a/tests/system-offloads-traffic.at
+++ b/tests/system-offloads-traffic.at
@@ -273,6 +273,10 @@  meter:1 flow_count:1 packet_in_count:11 byte_in_count:377 duration:0.001s bands:
 0: packet_count:9 byte_count:0
 ])
 
+AT_CHECK([ovs-ofctl -O Openflow13 del-meter br0])
+sleep 10
+AT_CHECK([tc actions ls action police], [0], [])
+
 OVS_TRAFFIC_VSWITCHD_STOP
 AT_CLEANUP