diff mbox series

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

Message ID 20220407091603.31995-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 success test: success

Commit Message

Jianbo Liu April 7, 2022, 9:16 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(+)
diff mbox series

Patch

diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c
index 9364cb530..d6ef5159c 100644
--- a/lib/netdev-offload-tc.c
+++ b/lib/netdev-offload-tc.c
@@ -2511,12 +2511,87 @@  meter_tc_del_policer(ofproto_meter_id meter_id,
     return err;
 }
 
+struct policer_node {
+    struct hmap_node node;
+    uint32_t police_idx;
+};
+
+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
 meter_tc_init_policer(void)
 {
     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);
     return 0;
 }
 
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 */