diff mbox series

[ovs-dev,v4,6/8] netdev-offload-tc: Cleanup police actions with reserved indexes on startup

Message ID 20220503030836.28783-7-jianbol@nvidia.com
State Superseded
Headers show
Series Add support for ovs metering with tc offload | expand

Checks

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

Commit Message

Jianbo Liu May 3, 2022, 3:08 a.m. UTC
As the police actions with indexes of 0x10000000-0x1fffffff are
reserved for meter offload, to provide a clean environment for OVS,
these reserved police actions should be deleted on startup. So dump
all the police actions, delete those actions with indexes in this
range.

Signed-off-by: Jianbo Liu <jianbol@nvidia.com>
---
 lib/netdev-offload-tc.c | 75 +++++++++++++++++++++++++++++++++++++++++
 lib/tc.c                | 61 +++++++++++++++++++++++++++++++++
 lib/tc.h                |  2 ++
 3 files changed, 138 insertions(+)

Comments

Eelco Chaudron May 16, 2022, 10:45 a.m. UTC | #1
On 3 May 2022, at 5:08, Jianbo Liu via dev wrote:

> As the police actions with indexes of 0x10000000-0x1fffffff are
> reserved for meter offload, to provide a clean environment for OVS,
> these reserved police actions should be deleted on startup. So dump
> all the police actions, delete those actions with indexes in this
> range.
>
> Signed-off-by: Jianbo Liu <jianbol@nvidia.com>
> ---
>  lib/netdev-offload-tc.c | 75 +++++++++++++++++++++++++++++++++++++++++
>  lib/tc.c                | 61 +++++++++++++++++++++++++++++++++
>  lib/tc.h                |  2 ++
>  3 files changed, 138 insertions(+)
>
> diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c
> index b3c60c125..bded4bc8c 100644
> --- a/lib/netdev-offload-tc.c
> +++ b/lib/netdev-offload-tc.c
> @@ -69,6 +69,11 @@ struct meter_id_to_police_idx_data {
>      uint32_t police_idx;
>  };
>
> +struct policer_node {
> +    struct hmap_node node;
> +    uint32_t police_idx;
> +};
> +
>  #define METER_POLICE_IDS_BASE 0x10000000
>  #define METER_POLICE_IDS_MAX  0x1FFFFFFF
>  /* Protects below meter ids pool and hashmaps. */
> @@ -2252,6 +2257,74 @@ probe_tc_block_support(int ifindex)
>      }
>  }
>
> +static int
> +tc_get_policer_action_ids(struct hmap *map)
> +{
> +    uint32_t police_idx[TCA_ACT_MAX_PRIO] = {};
> +    struct policer_node *policer_node;
> +    struct netdev_flow_dump *dump;
> +    struct ofpbuf rbuffer, reply;
> +    size_t hash;
> +    int i, err;
> +
> +    dump = xzalloc(sizeof *dump);
> +    dump->nl_dump = xzalloc(sizeof *dump->nl_dump);
> +
> +    ofpbuf_init(&rbuffer, NL_DUMP_BUFSIZE);
> +    tc_dump_tc_action_start("police", dump->nl_dump);
> +
> +    while (nl_dump_next(dump->nl_dump, &reply, &rbuffer)) {
> +        if (parse_netlink_to_tc_policer(&reply, police_idx)) {
> +            continue;
> +        }
> +
> +        for (i = 0; i < TCA_ACT_MAX_PRIO; i++) {
> +            if (!police_idx[i]) {
> +                break;
> +            }
> +            policer_node = xzalloc(sizeof *policer_node);
> +            policer_node->police_idx = police_idx[i];
> +            hash = hash_int(police_idx[i], 0);
> +            hmap_insert(map, &policer_node->node, hash);
> +        }
> +        memset(police_idx, 0, TCA_ACT_MAX_PRIO * sizeof(uint32_t));
> +    }
> +
> +    err = nl_dump_done(dump->nl_dump);
> +    ofpbuf_uninit(&rbuffer);
> +    free(dump->nl_dump);
> +    free(dump);
> +
> +    return err;
> +}
> +
> +static void
> +tc_cleanup_policer_action(struct id_pool *police_ids,

Should the function name not be tc_cleanup_policer_actions(), as it cleans up all configured actions?

> +                          uint32_t id_min, uint32_t id_max)
> +{
> +    struct policer_node *policer_node;
> +    uint32_t police_idx;
> +    struct hmap map;
> +    int err;
> +
> +    hmap_init(&map);
> +    tc_get_policer_action_ids(&map);
> +
> +    HMAP_FOR_EACH_POP (policer_node, node, &map) {
> +        police_idx = policer_node->police_idx;
> +        if (police_idx >= id_min && police_idx <= id_max) {
> +            err = tc_del_policer_action(police_idx, NULL);
> +            if (err) {

Are we ok to do this on all errors? Maybe ignore the error if the action can not be found, as it might have been cleaned up in the meanwhile?

> +                /* don't use this police any more */

Comments should start with a capital and end with a dot.

> +                id_pool_add(police_ids, police_idx);
> +            }
> +        }
> +        free(policer_node);
> +    }
> +
> +    hmap_destroy(&map);
> +}
> +
>  static int
>  netdev_tc_init_flow_api(struct netdev *netdev)
>  {
> @@ -2304,6 +2377,8 @@ netdev_tc_init_flow_api(struct netdev *netdev)
>
>          meter_police_ids = id_pool_create(METER_POLICE_IDS_BASE,
>                              METER_POLICE_IDS_MAX - METER_POLICE_IDS_BASE + 1);
> +        tc_cleanup_policer_action(meter_police_ids, METER_POLICE_IDS_BASE,
> +                                  METER_POLICE_IDS_MAX);
>
>          ovsthread_once_done(&once);
>      }
> diff --git a/lib/tc.c b/lib/tc.c
> index ee16364ea..16d4ae3da 100644
> --- a/lib/tc.c
> +++ b/lib/tc.c
> @@ -2067,6 +2067,67 @@ tc_dump_tc_chain_start(struct tcf_id *id, struct nl_dump *dump)
>      return 0;
>  }
>
> +int
> +tc_dump_tc_action_start(char *name, struct nl_dump *dump)
> +{
> +    size_t offset, root_offset;
> +    struct ofpbuf request;
> +    uint32_t prio = 0;
> +
> +    tc_make_action_request(RTM_GETACTION, NLM_F_DUMP, &request);
> +    root_offset = nl_msg_start_nested(&request, TCA_ACT_TAB);
> +    offset = nl_msg_start_nested(&request, ++prio);

Same as earlier, why prio++?

> +    nl_msg_put_string(&request, TCA_ACT_KIND, name);
> +    nl_msg_end_nested(&request, offset);
> +    nl_msg_end_nested(&request, root_offset);
> +
> +    nl_dump_start(dump, NETLINK_ROUTE, &request);
> +    ofpbuf_uninit(&request);
> +
> +    return 0;
> +}
> +
> +int
> +parse_netlink_to_tc_policer(struct ofpbuf *reply, uint32_t police_idx[])
> +{
> +    static struct nl_policy actions_orders_policy[TCA_ACT_MAX_PRIO] = {};
> +    struct nlattr *actions_orders[ARRAY_SIZE(actions_orders_policy)];
> +    const int max_size = ARRAY_SIZE(actions_orders_policy);
> +    const struct nlattr *actions;
> +    struct tc_flower flower;
> +    struct tcamsg *tca;
> +    int i, cnt = 0;
> +    int err;
> +
> +    for (i = 0; i < max_size; i++) {
> +        actions_orders_policy[i].type = NL_A_NESTED;
> +        actions_orders_policy[i].optional = true;
> +    }
> +
> +    tca = ofpbuf_at_assert(reply, NLMSG_HDRLEN, sizeof *tca);
> +    actions = nl_attr_find(reply, NLMSG_HDRLEN + sizeof *tca, TCA_ACT_TAB);
> +    if (!actions || !nl_parse_nested(actions, actions_orders_policy,
> +                                     actions_orders, max_size)) {
> +        VLOG_ERR_RL(&error_rl, "failed to parse police actions");

"Failed..."

> +        return EPROTO;
> +    }
> +
> +    for (i = 0; i < TCA_ACT_MAX_PRIO; i++) {
> +        if (actions_orders[i]) {
> +            memset(&flower, 0, sizeof(struct tc_flower));
> +            err = tc_parse_single_action(actions_orders[i], &flower, false);
> +            if (err) {
> +                continue;
> +            }
> +            if (flower.actions[0].police.index) {

This could be any kind of action, should we not explicitly check for policy and skip all other ones?

> +                police_idx[cnt++] = flower.actions[0].police.index;
> +            }
> +        }
> +    }
> +
> +    return 0;
> +}
> +
>  int
>  tc_del_filter(struct tcf_id *id)
>  {
> diff --git a/lib/tc.h b/lib/tc.h
> index 96b9e6ccc..f6d1ed91c 100644
> --- a/lib/tc.h
> +++ b/lib/tc.h
> @@ -382,5 +382,7 @@ int parse_netlink_to_tc_chain(struct ofpbuf *reply, uint32_t *chain);
>  void tc_set_policy(const char *policy);
>  int tc_parse_single_action(struct nlattr *action, struct tc_flower *flower,
>                             bool terse);
> +int tc_dump_tc_action_start(char *name, struct nl_dump *dump);
> +int parse_netlink_to_tc_policer(struct ofpbuf *reply, uint32_t police_idx[]);
>
>  #endif /* tc.h */
> -- 
> 2.26.2
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
diff mbox series

Patch

diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c
index b3c60c125..bded4bc8c 100644
--- a/lib/netdev-offload-tc.c
+++ b/lib/netdev-offload-tc.c
@@ -69,6 +69,11 @@  struct meter_id_to_police_idx_data {
     uint32_t police_idx;
 };
 
+struct policer_node {
+    struct hmap_node node;
+    uint32_t police_idx;
+};
+
 #define METER_POLICE_IDS_BASE 0x10000000
 #define METER_POLICE_IDS_MAX  0x1FFFFFFF
 /* Protects below meter ids pool and hashmaps. */
@@ -2252,6 +2257,74 @@  probe_tc_block_support(int ifindex)
     }
 }
 
+static int
+tc_get_policer_action_ids(struct hmap *map)
+{
+    uint32_t police_idx[TCA_ACT_MAX_PRIO] = {};
+    struct policer_node *policer_node;
+    struct netdev_flow_dump *dump;
+    struct ofpbuf rbuffer, reply;
+    size_t hash;
+    int i, err;
+
+    dump = xzalloc(sizeof *dump);
+    dump->nl_dump = xzalloc(sizeof *dump->nl_dump);
+
+    ofpbuf_init(&rbuffer, NL_DUMP_BUFSIZE);
+    tc_dump_tc_action_start("police", dump->nl_dump);
+
+    while (nl_dump_next(dump->nl_dump, &reply, &rbuffer)) {
+        if (parse_netlink_to_tc_policer(&reply, police_idx)) {
+            continue;
+        }
+
+        for (i = 0; i < TCA_ACT_MAX_PRIO; i++) {
+            if (!police_idx[i]) {
+                break;
+            }
+            policer_node = xzalloc(sizeof *policer_node);
+            policer_node->police_idx = police_idx[i];
+            hash = hash_int(police_idx[i], 0);
+            hmap_insert(map, &policer_node->node, hash);
+        }
+        memset(police_idx, 0, TCA_ACT_MAX_PRIO * sizeof(uint32_t));
+    }
+
+    err = nl_dump_done(dump->nl_dump);
+    ofpbuf_uninit(&rbuffer);
+    free(dump->nl_dump);
+    free(dump);
+
+    return err;
+}
+
+static void
+tc_cleanup_policer_action(struct id_pool *police_ids,
+                          uint32_t id_min, uint32_t id_max)
+{
+    struct policer_node *policer_node;
+    uint32_t police_idx;
+    struct hmap map;
+    int err;
+
+    hmap_init(&map);
+    tc_get_policer_action_ids(&map);
+
+    HMAP_FOR_EACH_POP (policer_node, node, &map) {
+        police_idx = policer_node->police_idx;
+        if (police_idx >= id_min && police_idx <= id_max) {
+            err = tc_del_policer_action(police_idx, NULL);
+            if (err) {
+                /* don't use this police any more */
+                id_pool_add(police_ids, police_idx);
+            }
+        }
+        free(policer_node);
+    }
+
+    hmap_destroy(&map);
+}
+
 static int
 netdev_tc_init_flow_api(struct netdev *netdev)
 {
@@ -2304,6 +2377,8 @@  netdev_tc_init_flow_api(struct netdev *netdev)
 
         meter_police_ids = id_pool_create(METER_POLICE_IDS_BASE,
                             METER_POLICE_IDS_MAX - METER_POLICE_IDS_BASE + 1);
+        tc_cleanup_policer_action(meter_police_ids, METER_POLICE_IDS_BASE,
+                                  METER_POLICE_IDS_MAX);
 
         ovsthread_once_done(&once);
     }
diff --git a/lib/tc.c b/lib/tc.c
index ee16364ea..16d4ae3da 100644
--- a/lib/tc.c
+++ b/lib/tc.c
@@ -2067,6 +2067,67 @@  tc_dump_tc_chain_start(struct tcf_id *id, struct nl_dump *dump)
     return 0;
 }
 
+int
+tc_dump_tc_action_start(char *name, struct nl_dump *dump)
+{
+    size_t offset, root_offset;
+    struct ofpbuf request;
+    uint32_t prio = 0;
+
+    tc_make_action_request(RTM_GETACTION, NLM_F_DUMP, &request);
+    root_offset = nl_msg_start_nested(&request, TCA_ACT_TAB);
+    offset = nl_msg_start_nested(&request, ++prio);
+    nl_msg_put_string(&request, TCA_ACT_KIND, name);
+    nl_msg_end_nested(&request, offset);
+    nl_msg_end_nested(&request, root_offset);
+
+    nl_dump_start(dump, NETLINK_ROUTE, &request);
+    ofpbuf_uninit(&request);
+
+    return 0;
+}
+
+int
+parse_netlink_to_tc_policer(struct ofpbuf *reply, uint32_t police_idx[])
+{
+    static struct nl_policy actions_orders_policy[TCA_ACT_MAX_PRIO] = {};
+    struct nlattr *actions_orders[ARRAY_SIZE(actions_orders_policy)];
+    const int max_size = ARRAY_SIZE(actions_orders_policy);
+    const struct nlattr *actions;
+    struct tc_flower flower;
+    struct tcamsg *tca;
+    int i, cnt = 0;
+    int err;
+
+    for (i = 0; i < max_size; i++) {
+        actions_orders_policy[i].type = NL_A_NESTED;
+        actions_orders_policy[i].optional = true;
+    }
+
+    tca = ofpbuf_at_assert(reply, NLMSG_HDRLEN, sizeof *tca);
+    actions = nl_attr_find(reply, NLMSG_HDRLEN + sizeof *tca, TCA_ACT_TAB);
+    if (!actions || !nl_parse_nested(actions, actions_orders_policy,
+                                     actions_orders, max_size)) {
+        VLOG_ERR_RL(&error_rl, "failed to parse police actions");
+        return EPROTO;
+    }
+
+    for (i = 0; i < TCA_ACT_MAX_PRIO; i++) {
+        if (actions_orders[i]) {
+            memset(&flower, 0, sizeof(struct tc_flower));
+            err = tc_parse_single_action(actions_orders[i], &flower, false);
+            if (err) {
+                continue;
+            }
+            if (flower.actions[0].police.index) {
+                police_idx[cnt++] = flower.actions[0].police.index;
+            }
+        }
+    }
+
+    return 0;
+}
+
 int
 tc_del_filter(struct tcf_id *id)
 {
diff --git a/lib/tc.h b/lib/tc.h
index 96b9e6ccc..f6d1ed91c 100644
--- a/lib/tc.h
+++ b/lib/tc.h
@@ -382,5 +382,7 @@  int parse_netlink_to_tc_chain(struct ofpbuf *reply, uint32_t *chain);
 void tc_set_policy(const char *policy);
 int tc_parse_single_action(struct nlattr *action, struct tc_flower *flower,
                            bool terse);
+int tc_dump_tc_action_start(char *name, struct nl_dump *dump);
+int parse_netlink_to_tc_policer(struct ofpbuf *reply, uint32_t police_idx[]);
 
 #endif /* tc.h */