diff mbox series

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

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

Checks

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

Commit Message

Jianbo Liu July 2, 2022, 3:18 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 | 85 +++++++++++++++++++++++++++++++++++++++++
 lib/tc.c                | 61 +++++++++++++++++++++++++++++
 lib/tc.h                |  2 +
 3 files changed, 148 insertions(+)

Comments

Eelco Chaudron July 7, 2022, 11:52 a.m. UTC | #1
On 2 Jul 2022, at 5:18, Jianbo Liu 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>

Changes look good to me.

Acked-by: Eelco Chaudron <echaudro@redhat.com>
diff mbox series

Patch

diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c
index 2d3206fb6..7de51a6e0 100644
--- a/lib/netdev-offload-tc.c
+++ b/lib/netdev-offload-tc.c
@@ -70,6 +70,11 @@  struct meter_police_mapping_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 police ids pool. */
@@ -2255,6 +2260,84 @@  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)) {
+        memset(police_idx, 0, sizeof police_idx);
+        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);
+        }
+    }
+
+    err = nl_dump_done(dump->nl_dump);
+    ofpbuf_uninit(&rbuffer);
+    free(dump->nl_dump);
+    free(dump);
+
+    return err;
+}
+
+static void
+tc_cleanup_policer_actions(struct id_pool *police_ids,
+                          uint32_t id_min, uint32_t id_max)
+{
+    struct policer_node *policer_node;
+    unsigned int unusable_ids = 0;
+    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 && err != ENOENT) {
+                /* Don't use this police any more. */
+                id_pool_add(police_ids, police_idx);
+
+                unusable_ids++;
+                VLOG_DBG("Policer index %u could not be freed for OVS, "
+                         "error %d", police_idx, err);
+            }
+        }
+        free(policer_node);
+    }
+
+    if (unusable_ids) {
+        VLOG_WARN("Full policer index pool allocation failed, "
+                  "%u indexes are unavailable", unusable_ids);
+    }
+
+    hmap_destroy(&map);
+}
+
 static int
 netdev_tc_init_flow_api(struct netdev *netdev)
 {
@@ -2308,6 +2391,8 @@  netdev_tc_init_flow_api(struct netdev *netdev)
         ovs_mutex_lock(&meter_police_ids_mutex);
         meter_police_ids = id_pool_create(METER_POLICE_IDS_BASE,
                             METER_POLICE_IDS_MAX - METER_POLICE_IDS_BASE + 1);
+        tc_cleanup_policer_actions(meter_police_ids, METER_POLICE_IDS_BASE,
+                                   METER_POLICE_IDS_MAX);
         ovs_mutex_unlock(&meter_police_ids_mutex);
 
         ovsthread_once_done(&once);
diff --git a/lib/tc.c b/lib/tc.c
index bd107a588..74e2d6caf 100644
--- a/lib/tc.c
+++ b/lib/tc.c
@@ -2090,6 +2090,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;
+
+    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, 1);
+    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 actions in netlink to policer");
+        return EPROTO;
+    }
+
+    for (i = 0; i < TCA_ACT_MAX_PRIO; i++) {
+        if (actions_orders[i]) {
+            memset(&flower, 0, sizeof(struct tc_flower));
+            err = nl_parse_single_action(actions_orders[i], &flower, false);
+            if (err || flower.actions[0].type != TC_ACT_POLICE) {
+                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 30cd2f7ff..4690dce4f 100644
--- a/lib/tc.h
+++ b/lib/tc.h
@@ -382,5 +382,7 @@  int tc_parse_action_stats(struct nlattr *action,
                           struct ovs_flow_stats *stats_sw,
                           struct ovs_flow_stats *stats_hw,
                           struct ovs_flow_stats *stats_dropped);
+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 */