162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 262306a36Sopenharmony_ci/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/hash.h> 562306a36Sopenharmony_ci#include <linux/hashtable.h> 662306a36Sopenharmony_ci#include <linux/jhash.h> 762306a36Sopenharmony_ci#include <linux/math64.h> 862306a36Sopenharmony_ci#include <linux/vmalloc.h> 962306a36Sopenharmony_ci#include <net/pkt_cls.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "cmsg.h" 1262306a36Sopenharmony_ci#include "conntrack.h" 1362306a36Sopenharmony_ci#include "main.h" 1462306a36Sopenharmony_ci#include "../nfp_app.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistruct nfp_mask_id_table { 1762306a36Sopenharmony_ci struct hlist_node link; 1862306a36Sopenharmony_ci u32 hash_key; 1962306a36Sopenharmony_ci u32 ref_cnt; 2062306a36Sopenharmony_ci u8 mask_id; 2162306a36Sopenharmony_ci}; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistruct nfp_fl_flow_table_cmp_arg { 2462306a36Sopenharmony_ci struct net_device *netdev; 2562306a36Sopenharmony_ci unsigned long cookie; 2662306a36Sopenharmony_ci}; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistruct nfp_fl_stats_ctx_to_flow { 2962306a36Sopenharmony_ci struct rhash_head ht_node; 3062306a36Sopenharmony_ci u32 stats_cxt; 3162306a36Sopenharmony_ci struct nfp_fl_payload *flow; 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic const struct rhashtable_params stats_ctx_table_params = { 3562306a36Sopenharmony_ci .key_offset = offsetof(struct nfp_fl_stats_ctx_to_flow, stats_cxt), 3662306a36Sopenharmony_ci .head_offset = offsetof(struct nfp_fl_stats_ctx_to_flow, ht_node), 3762306a36Sopenharmony_ci .key_len = sizeof(u32), 3862306a36Sopenharmony_ci}; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic int nfp_release_stats_entry(struct nfp_app *app, u32 stats_context_id) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci struct nfp_flower_priv *priv = app->priv; 4362306a36Sopenharmony_ci struct circ_buf *ring; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci ring = &priv->stats_ids.free_list; 4662306a36Sopenharmony_ci /* Check if buffer is full, stats_ring_size must be power of 2 */ 4762306a36Sopenharmony_ci if (!CIRC_SPACE(ring->head, ring->tail, priv->stats_ring_size)) 4862306a36Sopenharmony_ci return -ENOBUFS; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci /* Each increment of head represents size of NFP_FL_STATS_ELEM_RS */ 5162306a36Sopenharmony_ci memcpy(&ring->buf[ring->head * NFP_FL_STATS_ELEM_RS], 5262306a36Sopenharmony_ci &stats_context_id, NFP_FL_STATS_ELEM_RS); 5362306a36Sopenharmony_ci ring->head = (ring->head + 1) & (priv->stats_ring_size - 1); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci return 0; 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic int nfp_get_stats_entry(struct nfp_app *app, u32 *stats_context_id) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci struct nfp_flower_priv *priv = app->priv; 6162306a36Sopenharmony_ci u32 freed_stats_id, temp_stats_id; 6262306a36Sopenharmony_ci struct circ_buf *ring; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci ring = &priv->stats_ids.free_list; 6562306a36Sopenharmony_ci freed_stats_id = priv->stats_ring_size; 6662306a36Sopenharmony_ci /* Check for unallocated entries first. */ 6762306a36Sopenharmony_ci if (priv->stats_ids.init_unalloc > 0) { 6862306a36Sopenharmony_ci *stats_context_id = 6962306a36Sopenharmony_ci FIELD_PREP(NFP_FL_STAT_ID_STAT, 7062306a36Sopenharmony_ci priv->stats_ids.init_unalloc - 1) | 7162306a36Sopenharmony_ci FIELD_PREP(NFP_FL_STAT_ID_MU_NUM, 7262306a36Sopenharmony_ci priv->active_mem_unit); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (++priv->active_mem_unit == priv->total_mem_units) { 7562306a36Sopenharmony_ci priv->stats_ids.init_unalloc--; 7662306a36Sopenharmony_ci priv->active_mem_unit = 0; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci return 0; 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci /* Check if buffer is empty. */ 8362306a36Sopenharmony_ci if (ring->head == ring->tail) { 8462306a36Sopenharmony_ci *stats_context_id = freed_stats_id; 8562306a36Sopenharmony_ci return -ENOENT; 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci /* Each increment of tail represents size of NFP_FL_STATS_ELEM_RS */ 8962306a36Sopenharmony_ci memcpy(&temp_stats_id, &ring->buf[ring->tail * NFP_FL_STATS_ELEM_RS], 9062306a36Sopenharmony_ci NFP_FL_STATS_ELEM_RS); 9162306a36Sopenharmony_ci *stats_context_id = temp_stats_id; 9262306a36Sopenharmony_ci memcpy(&ring->buf[ring->tail * NFP_FL_STATS_ELEM_RS], &freed_stats_id, 9362306a36Sopenharmony_ci NFP_FL_STATS_ELEM_RS); 9462306a36Sopenharmony_ci /* stats_ring_size must be power of 2 */ 9562306a36Sopenharmony_ci ring->tail = (ring->tail + 1) & (priv->stats_ring_size - 1); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci return 0; 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/* Must be called with either RTNL or rcu_read_lock */ 10162306a36Sopenharmony_cistruct nfp_fl_payload * 10262306a36Sopenharmony_cinfp_flower_search_fl_table(struct nfp_app *app, unsigned long tc_flower_cookie, 10362306a36Sopenharmony_ci struct net_device *netdev) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci struct nfp_fl_flow_table_cmp_arg flower_cmp_arg; 10662306a36Sopenharmony_ci struct nfp_flower_priv *priv = app->priv; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci flower_cmp_arg.netdev = netdev; 10962306a36Sopenharmony_ci flower_cmp_arg.cookie = tc_flower_cookie; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci return rhashtable_lookup_fast(&priv->flow_table, &flower_cmp_arg, 11262306a36Sopenharmony_ci nfp_flower_table_params); 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_civoid nfp_flower_rx_flow_stats(struct nfp_app *app, struct sk_buff *skb) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci unsigned int msg_len = nfp_flower_cmsg_get_data_len(skb); 11862306a36Sopenharmony_ci struct nfp_flower_priv *priv = app->priv; 11962306a36Sopenharmony_ci struct nfp_fl_stats_frame *stats; 12062306a36Sopenharmony_ci unsigned char *msg; 12162306a36Sopenharmony_ci u32 ctx_id; 12262306a36Sopenharmony_ci int i; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci msg = nfp_flower_cmsg_get_data(skb); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci spin_lock(&priv->stats_lock); 12762306a36Sopenharmony_ci for (i = 0; i < msg_len / sizeof(*stats); i++) { 12862306a36Sopenharmony_ci stats = (struct nfp_fl_stats_frame *)msg + i; 12962306a36Sopenharmony_ci ctx_id = be32_to_cpu(stats->stats_con_id); 13062306a36Sopenharmony_ci priv->stats[ctx_id].pkts += be32_to_cpu(stats->pkt_count); 13162306a36Sopenharmony_ci priv->stats[ctx_id].bytes += be64_to_cpu(stats->byte_count); 13262306a36Sopenharmony_ci priv->stats[ctx_id].used = jiffies; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci spin_unlock(&priv->stats_lock); 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic int nfp_release_mask_id(struct nfp_app *app, u8 mask_id) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci struct nfp_flower_priv *priv = app->priv; 14062306a36Sopenharmony_ci struct circ_buf *ring; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci ring = &priv->mask_ids.mask_id_free_list; 14362306a36Sopenharmony_ci /* Checking if buffer is full, 14462306a36Sopenharmony_ci * NFP_FLOWER_MASK_ENTRY_RS must be power of 2 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_ci if (CIRC_SPACE(ring->head, ring->tail, NFP_FLOWER_MASK_ENTRY_RS) == 0) 14762306a36Sopenharmony_ci return -ENOBUFS; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci /* Each increment of head represents size of 15062306a36Sopenharmony_ci * NFP_FLOWER_MASK_ELEMENT_RS 15162306a36Sopenharmony_ci */ 15262306a36Sopenharmony_ci memcpy(&ring->buf[ring->head * NFP_FLOWER_MASK_ELEMENT_RS], &mask_id, 15362306a36Sopenharmony_ci NFP_FLOWER_MASK_ELEMENT_RS); 15462306a36Sopenharmony_ci ring->head = (ring->head + 1) & (NFP_FLOWER_MASK_ENTRY_RS - 1); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci priv->mask_ids.last_used[mask_id] = ktime_get(); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci return 0; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic int nfp_mask_alloc(struct nfp_app *app, u8 *mask_id) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci struct nfp_flower_priv *priv = app->priv; 16462306a36Sopenharmony_ci ktime_t reuse_timeout; 16562306a36Sopenharmony_ci struct circ_buf *ring; 16662306a36Sopenharmony_ci u8 temp_id, freed_id; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci ring = &priv->mask_ids.mask_id_free_list; 16962306a36Sopenharmony_ci freed_id = NFP_FLOWER_MASK_ENTRY_RS - 1; 17062306a36Sopenharmony_ci /* Checking for unallocated entries first. */ 17162306a36Sopenharmony_ci if (priv->mask_ids.init_unallocated > 0) { 17262306a36Sopenharmony_ci *mask_id = priv->mask_ids.init_unallocated; 17362306a36Sopenharmony_ci priv->mask_ids.init_unallocated--; 17462306a36Sopenharmony_ci return 0; 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci /* Checking if buffer is empty. */ 17862306a36Sopenharmony_ci if (ring->head == ring->tail) 17962306a36Sopenharmony_ci goto err_not_found; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci /* Each increment of tail represents size of 18262306a36Sopenharmony_ci * NFP_FLOWER_MASK_ELEMENT_RS 18362306a36Sopenharmony_ci */ 18462306a36Sopenharmony_ci memcpy(&temp_id, &ring->buf[ring->tail * NFP_FLOWER_MASK_ELEMENT_RS], 18562306a36Sopenharmony_ci NFP_FLOWER_MASK_ELEMENT_RS); 18662306a36Sopenharmony_ci *mask_id = temp_id; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci reuse_timeout = ktime_add_ns(priv->mask_ids.last_used[*mask_id], 18962306a36Sopenharmony_ci NFP_FL_MASK_REUSE_TIME_NS); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci if (ktime_before(ktime_get(), reuse_timeout)) 19262306a36Sopenharmony_ci goto err_not_found; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci memcpy(&ring->buf[ring->tail * NFP_FLOWER_MASK_ELEMENT_RS], &freed_id, 19562306a36Sopenharmony_ci NFP_FLOWER_MASK_ELEMENT_RS); 19662306a36Sopenharmony_ci /* NFP_FLOWER_MASK_ENTRY_RS must be power of 2 */ 19762306a36Sopenharmony_ci ring->tail = (ring->tail + 1) & (NFP_FLOWER_MASK_ENTRY_RS - 1); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci return 0; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cierr_not_found: 20262306a36Sopenharmony_ci *mask_id = freed_id; 20362306a36Sopenharmony_ci return -ENOENT; 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic int 20762306a36Sopenharmony_cinfp_add_mask_table(struct nfp_app *app, char *mask_data, u32 mask_len) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci struct nfp_flower_priv *priv = app->priv; 21062306a36Sopenharmony_ci struct nfp_mask_id_table *mask_entry; 21162306a36Sopenharmony_ci unsigned long hash_key; 21262306a36Sopenharmony_ci u8 mask_id; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (nfp_mask_alloc(app, &mask_id)) 21562306a36Sopenharmony_ci return -ENOENT; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci mask_entry = kmalloc(sizeof(*mask_entry), GFP_KERNEL); 21862306a36Sopenharmony_ci if (!mask_entry) { 21962306a36Sopenharmony_ci nfp_release_mask_id(app, mask_id); 22062306a36Sopenharmony_ci return -ENOMEM; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci INIT_HLIST_NODE(&mask_entry->link); 22462306a36Sopenharmony_ci mask_entry->mask_id = mask_id; 22562306a36Sopenharmony_ci hash_key = jhash(mask_data, mask_len, priv->mask_id_seed); 22662306a36Sopenharmony_ci mask_entry->hash_key = hash_key; 22762306a36Sopenharmony_ci mask_entry->ref_cnt = 1; 22862306a36Sopenharmony_ci hash_add(priv->mask_table, &mask_entry->link, hash_key); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci return mask_id; 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic struct nfp_mask_id_table * 23462306a36Sopenharmony_cinfp_search_mask_table(struct nfp_app *app, char *mask_data, u32 mask_len) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci struct nfp_flower_priv *priv = app->priv; 23762306a36Sopenharmony_ci struct nfp_mask_id_table *mask_entry; 23862306a36Sopenharmony_ci unsigned long hash_key; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci hash_key = jhash(mask_data, mask_len, priv->mask_id_seed); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci hash_for_each_possible(priv->mask_table, mask_entry, link, hash_key) 24362306a36Sopenharmony_ci if (mask_entry->hash_key == hash_key) 24462306a36Sopenharmony_ci return mask_entry; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci return NULL; 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cistatic int 25062306a36Sopenharmony_cinfp_find_in_mask_table(struct nfp_app *app, char *mask_data, u32 mask_len) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci struct nfp_mask_id_table *mask_entry; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci mask_entry = nfp_search_mask_table(app, mask_data, mask_len); 25562306a36Sopenharmony_ci if (!mask_entry) 25662306a36Sopenharmony_ci return -ENOENT; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci mask_entry->ref_cnt++; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci /* Casting u8 to int for later use. */ 26162306a36Sopenharmony_ci return mask_entry->mask_id; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_cistatic bool 26562306a36Sopenharmony_cinfp_check_mask_add(struct nfp_app *app, char *mask_data, u32 mask_len, 26662306a36Sopenharmony_ci u8 *meta_flags, u8 *mask_id) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci int id; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci id = nfp_find_in_mask_table(app, mask_data, mask_len); 27162306a36Sopenharmony_ci if (id < 0) { 27262306a36Sopenharmony_ci id = nfp_add_mask_table(app, mask_data, mask_len); 27362306a36Sopenharmony_ci if (id < 0) 27462306a36Sopenharmony_ci return false; 27562306a36Sopenharmony_ci *meta_flags |= NFP_FL_META_FLAG_MANAGE_MASK; 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci *mask_id = id; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci return true; 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_cistatic bool 28362306a36Sopenharmony_cinfp_check_mask_remove(struct nfp_app *app, char *mask_data, u32 mask_len, 28462306a36Sopenharmony_ci u8 *meta_flags, u8 *mask_id) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci struct nfp_mask_id_table *mask_entry; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci mask_entry = nfp_search_mask_table(app, mask_data, mask_len); 28962306a36Sopenharmony_ci if (!mask_entry) 29062306a36Sopenharmony_ci return false; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci *mask_id = mask_entry->mask_id; 29362306a36Sopenharmony_ci mask_entry->ref_cnt--; 29462306a36Sopenharmony_ci if (!mask_entry->ref_cnt) { 29562306a36Sopenharmony_ci hash_del(&mask_entry->link); 29662306a36Sopenharmony_ci nfp_release_mask_id(app, *mask_id); 29762306a36Sopenharmony_ci kfree(mask_entry); 29862306a36Sopenharmony_ci if (meta_flags) 29962306a36Sopenharmony_ci *meta_flags |= NFP_FL_META_FLAG_MANAGE_MASK; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci return true; 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ciint nfp_compile_flow_metadata(struct nfp_app *app, u32 cookie, 30662306a36Sopenharmony_ci struct nfp_fl_payload *nfp_flow, 30762306a36Sopenharmony_ci struct net_device *netdev, 30862306a36Sopenharmony_ci struct netlink_ext_ack *extack) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci struct nfp_fl_stats_ctx_to_flow *ctx_entry; 31162306a36Sopenharmony_ci struct nfp_flower_priv *priv = app->priv; 31262306a36Sopenharmony_ci struct nfp_fl_payload *check_entry; 31362306a36Sopenharmony_ci u8 new_mask_id; 31462306a36Sopenharmony_ci u32 stats_cxt; 31562306a36Sopenharmony_ci int err; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci err = nfp_get_stats_entry(app, &stats_cxt); 31862306a36Sopenharmony_ci if (err) { 31962306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "invalid entry: cannot allocate new stats context"); 32062306a36Sopenharmony_ci return err; 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci nfp_flow->meta.host_ctx_id = cpu_to_be32(stats_cxt); 32462306a36Sopenharmony_ci nfp_flow->meta.host_cookie = cpu_to_be64(cookie); 32562306a36Sopenharmony_ci nfp_flow->ingress_dev = netdev; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci ctx_entry = kzalloc(sizeof(*ctx_entry), GFP_KERNEL); 32862306a36Sopenharmony_ci if (!ctx_entry) { 32962306a36Sopenharmony_ci err = -ENOMEM; 33062306a36Sopenharmony_ci goto err_release_stats; 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci ctx_entry->stats_cxt = stats_cxt; 33462306a36Sopenharmony_ci ctx_entry->flow = nfp_flow; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if (rhashtable_insert_fast(&priv->stats_ctx_table, &ctx_entry->ht_node, 33762306a36Sopenharmony_ci stats_ctx_table_params)) { 33862306a36Sopenharmony_ci err = -ENOMEM; 33962306a36Sopenharmony_ci goto err_free_ctx_entry; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci /* Do not allocate a mask-id for pre_tun_rules. These flows are used to 34362306a36Sopenharmony_ci * configure the pre_tun table and are never actually send to the 34462306a36Sopenharmony_ci * firmware as an add-flow message. This causes the mask-id allocation 34562306a36Sopenharmony_ci * on the firmware to get out of sync if allocated here. 34662306a36Sopenharmony_ci */ 34762306a36Sopenharmony_ci new_mask_id = 0; 34862306a36Sopenharmony_ci if (!nfp_flow->pre_tun_rule.dev && 34962306a36Sopenharmony_ci !nfp_check_mask_add(app, nfp_flow->mask_data, 35062306a36Sopenharmony_ci nfp_flow->meta.mask_len, 35162306a36Sopenharmony_ci &nfp_flow->meta.flags, &new_mask_id)) { 35262306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "invalid entry: cannot allocate a new mask id"); 35362306a36Sopenharmony_ci err = -ENOENT; 35462306a36Sopenharmony_ci goto err_remove_rhash; 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci nfp_flow->meta.flow_version = cpu_to_be64(priv->flower_version); 35862306a36Sopenharmony_ci priv->flower_version++; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci /* Update flow payload with mask ids. */ 36162306a36Sopenharmony_ci nfp_flow->unmasked_data[NFP_FL_MASK_ID_LOCATION] = new_mask_id; 36262306a36Sopenharmony_ci priv->stats[stats_cxt].pkts = 0; 36362306a36Sopenharmony_ci priv->stats[stats_cxt].bytes = 0; 36462306a36Sopenharmony_ci priv->stats[stats_cxt].used = jiffies; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci check_entry = nfp_flower_search_fl_table(app, cookie, netdev); 36762306a36Sopenharmony_ci if (check_entry) { 36862306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "invalid entry: cannot offload duplicate flow entry"); 36962306a36Sopenharmony_ci err = -EEXIST; 37062306a36Sopenharmony_ci goto err_remove_mask; 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci return 0; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_cierr_remove_mask: 37662306a36Sopenharmony_ci if (!nfp_flow->pre_tun_rule.dev) 37762306a36Sopenharmony_ci nfp_check_mask_remove(app, nfp_flow->mask_data, 37862306a36Sopenharmony_ci nfp_flow->meta.mask_len, 37962306a36Sopenharmony_ci NULL, &new_mask_id); 38062306a36Sopenharmony_cierr_remove_rhash: 38162306a36Sopenharmony_ci WARN_ON_ONCE(rhashtable_remove_fast(&priv->stats_ctx_table, 38262306a36Sopenharmony_ci &ctx_entry->ht_node, 38362306a36Sopenharmony_ci stats_ctx_table_params)); 38462306a36Sopenharmony_cierr_free_ctx_entry: 38562306a36Sopenharmony_ci kfree(ctx_entry); 38662306a36Sopenharmony_cierr_release_stats: 38762306a36Sopenharmony_ci nfp_release_stats_entry(app, stats_cxt); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci return err; 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_civoid __nfp_modify_flow_metadata(struct nfp_flower_priv *priv, 39362306a36Sopenharmony_ci struct nfp_fl_payload *nfp_flow) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci nfp_flow->meta.flags &= ~NFP_FL_META_FLAG_MANAGE_MASK; 39662306a36Sopenharmony_ci nfp_flow->meta.flow_version = cpu_to_be64(priv->flower_version); 39762306a36Sopenharmony_ci priv->flower_version++; 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ciint nfp_modify_flow_metadata(struct nfp_app *app, 40162306a36Sopenharmony_ci struct nfp_fl_payload *nfp_flow) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci struct nfp_fl_stats_ctx_to_flow *ctx_entry; 40462306a36Sopenharmony_ci struct nfp_flower_priv *priv = app->priv; 40562306a36Sopenharmony_ci u8 new_mask_id = 0; 40662306a36Sopenharmony_ci u32 temp_ctx_id; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci __nfp_modify_flow_metadata(priv, nfp_flow); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci if (!nfp_flow->pre_tun_rule.dev) 41162306a36Sopenharmony_ci nfp_check_mask_remove(app, nfp_flow->mask_data, 41262306a36Sopenharmony_ci nfp_flow->meta.mask_len, &nfp_flow->meta.flags, 41362306a36Sopenharmony_ci &new_mask_id); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci /* Update flow payload with mask ids. */ 41662306a36Sopenharmony_ci nfp_flow->unmasked_data[NFP_FL_MASK_ID_LOCATION] = new_mask_id; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci /* Release the stats ctx id and ctx to flow table entry. */ 41962306a36Sopenharmony_ci temp_ctx_id = be32_to_cpu(nfp_flow->meta.host_ctx_id); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci ctx_entry = rhashtable_lookup_fast(&priv->stats_ctx_table, &temp_ctx_id, 42262306a36Sopenharmony_ci stats_ctx_table_params); 42362306a36Sopenharmony_ci if (!ctx_entry) 42462306a36Sopenharmony_ci return -ENOENT; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci WARN_ON_ONCE(rhashtable_remove_fast(&priv->stats_ctx_table, 42762306a36Sopenharmony_ci &ctx_entry->ht_node, 42862306a36Sopenharmony_ci stats_ctx_table_params)); 42962306a36Sopenharmony_ci kfree(ctx_entry); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci return nfp_release_stats_entry(app, temp_ctx_id); 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cistruct nfp_fl_payload * 43562306a36Sopenharmony_cinfp_flower_get_fl_payload_from_ctx(struct nfp_app *app, u32 ctx_id) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci struct nfp_fl_stats_ctx_to_flow *ctx_entry; 43862306a36Sopenharmony_ci struct nfp_flower_priv *priv = app->priv; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci ctx_entry = rhashtable_lookup_fast(&priv->stats_ctx_table, &ctx_id, 44162306a36Sopenharmony_ci stats_ctx_table_params); 44262306a36Sopenharmony_ci if (!ctx_entry) 44362306a36Sopenharmony_ci return NULL; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci return ctx_entry->flow; 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic int nfp_fl_obj_cmpfn(struct rhashtable_compare_arg *arg, 44962306a36Sopenharmony_ci const void *obj) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci const struct nfp_fl_flow_table_cmp_arg *cmp_arg = arg->key; 45262306a36Sopenharmony_ci const struct nfp_fl_payload *flow_entry = obj; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci if (flow_entry->ingress_dev == cmp_arg->netdev) 45562306a36Sopenharmony_ci return flow_entry->tc_flower_cookie != cmp_arg->cookie; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci return 1; 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_cistatic u32 nfp_fl_obj_hashfn(const void *data, u32 len, u32 seed) 46162306a36Sopenharmony_ci{ 46262306a36Sopenharmony_ci const struct nfp_fl_payload *flower_entry = data; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci return jhash2((u32 *)&flower_entry->tc_flower_cookie, 46562306a36Sopenharmony_ci sizeof(flower_entry->tc_flower_cookie) / sizeof(u32), 46662306a36Sopenharmony_ci seed); 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic u32 nfp_fl_key_hashfn(const void *data, u32 len, u32 seed) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci const struct nfp_fl_flow_table_cmp_arg *cmp_arg = data; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci return jhash2((u32 *)&cmp_arg->cookie, 47462306a36Sopenharmony_ci sizeof(cmp_arg->cookie) / sizeof(u32), seed); 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ciconst struct rhashtable_params nfp_flower_table_params = { 47862306a36Sopenharmony_ci .head_offset = offsetof(struct nfp_fl_payload, fl_node), 47962306a36Sopenharmony_ci .hashfn = nfp_fl_key_hashfn, 48062306a36Sopenharmony_ci .obj_cmpfn = nfp_fl_obj_cmpfn, 48162306a36Sopenharmony_ci .obj_hashfn = nfp_fl_obj_hashfn, 48262306a36Sopenharmony_ci .automatic_shrinking = true, 48362306a36Sopenharmony_ci}; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ciconst struct rhashtable_params merge_table_params = { 48662306a36Sopenharmony_ci .key_offset = offsetof(struct nfp_merge_info, parent_ctx), 48762306a36Sopenharmony_ci .head_offset = offsetof(struct nfp_merge_info, ht_node), 48862306a36Sopenharmony_ci .key_len = sizeof(u64), 48962306a36Sopenharmony_ci}; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ciconst struct rhashtable_params nfp_zone_table_params = { 49262306a36Sopenharmony_ci .head_offset = offsetof(struct nfp_fl_ct_zone_entry, hash_node), 49362306a36Sopenharmony_ci .key_len = sizeof(u16), 49462306a36Sopenharmony_ci .key_offset = offsetof(struct nfp_fl_ct_zone_entry, zone), 49562306a36Sopenharmony_ci .automatic_shrinking = false, 49662306a36Sopenharmony_ci}; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ciconst struct rhashtable_params nfp_ct_map_params = { 49962306a36Sopenharmony_ci .head_offset = offsetof(struct nfp_fl_ct_map_entry, hash_node), 50062306a36Sopenharmony_ci .key_len = sizeof(unsigned long), 50162306a36Sopenharmony_ci .key_offset = offsetof(struct nfp_fl_ct_map_entry, cookie), 50262306a36Sopenharmony_ci .automatic_shrinking = true, 50362306a36Sopenharmony_ci}; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ciconst struct rhashtable_params neigh_table_params = { 50662306a36Sopenharmony_ci .key_offset = offsetof(struct nfp_neigh_entry, neigh_cookie), 50762306a36Sopenharmony_ci .head_offset = offsetof(struct nfp_neigh_entry, ht_node), 50862306a36Sopenharmony_ci .key_len = sizeof(unsigned long), 50962306a36Sopenharmony_ci}; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ciint nfp_flower_metadata_init(struct nfp_app *app, u64 host_ctx_count, 51262306a36Sopenharmony_ci unsigned int host_num_mems) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci struct nfp_flower_priv *priv = app->priv; 51562306a36Sopenharmony_ci int err, stats_size; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci hash_init(priv->mask_table); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci err = rhashtable_init(&priv->flow_table, &nfp_flower_table_params); 52062306a36Sopenharmony_ci if (err) 52162306a36Sopenharmony_ci return err; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci err = rhashtable_init(&priv->stats_ctx_table, &stats_ctx_table_params); 52462306a36Sopenharmony_ci if (err) 52562306a36Sopenharmony_ci goto err_free_flow_table; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci err = rhashtable_init(&priv->merge_table, &merge_table_params); 52862306a36Sopenharmony_ci if (err) 52962306a36Sopenharmony_ci goto err_free_stats_ctx_table; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci mutex_init(&priv->nfp_fl_lock); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci err = rhashtable_init(&priv->ct_zone_table, &nfp_zone_table_params); 53462306a36Sopenharmony_ci if (err) 53562306a36Sopenharmony_ci goto err_free_merge_table; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci err = rhashtable_init(&priv->ct_map_table, &nfp_ct_map_params); 53862306a36Sopenharmony_ci if (err) 53962306a36Sopenharmony_ci goto err_free_ct_zone_table; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci err = rhashtable_init(&priv->neigh_table, &neigh_table_params); 54262306a36Sopenharmony_ci if (err) 54362306a36Sopenharmony_ci goto err_free_ct_map_table; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci INIT_LIST_HEAD(&priv->predt_list); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci get_random_bytes(&priv->mask_id_seed, sizeof(priv->mask_id_seed)); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci /* Init ring buffer and unallocated mask_ids. */ 55062306a36Sopenharmony_ci priv->mask_ids.mask_id_free_list.buf = 55162306a36Sopenharmony_ci kmalloc_array(NFP_FLOWER_MASK_ENTRY_RS, 55262306a36Sopenharmony_ci NFP_FLOWER_MASK_ELEMENT_RS, GFP_KERNEL); 55362306a36Sopenharmony_ci if (!priv->mask_ids.mask_id_free_list.buf) 55462306a36Sopenharmony_ci goto err_free_neigh_table; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci priv->mask_ids.init_unallocated = NFP_FLOWER_MASK_ENTRY_RS - 1; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci /* Init timestamps for mask id*/ 55962306a36Sopenharmony_ci priv->mask_ids.last_used = 56062306a36Sopenharmony_ci kmalloc_array(NFP_FLOWER_MASK_ENTRY_RS, 56162306a36Sopenharmony_ci sizeof(*priv->mask_ids.last_used), GFP_KERNEL); 56262306a36Sopenharmony_ci if (!priv->mask_ids.last_used) 56362306a36Sopenharmony_ci goto err_free_mask_id; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci /* Init ring buffer and unallocated stats_ids. */ 56662306a36Sopenharmony_ci priv->stats_ids.free_list.buf = 56762306a36Sopenharmony_ci vmalloc(array_size(NFP_FL_STATS_ELEM_RS, 56862306a36Sopenharmony_ci priv->stats_ring_size)); 56962306a36Sopenharmony_ci if (!priv->stats_ids.free_list.buf) 57062306a36Sopenharmony_ci goto err_free_last_used; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci priv->stats_ids.init_unalloc = div_u64(host_ctx_count, host_num_mems); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci stats_size = FIELD_PREP(NFP_FL_STAT_ID_STAT, host_ctx_count) | 57562306a36Sopenharmony_ci FIELD_PREP(NFP_FL_STAT_ID_MU_NUM, host_num_mems - 1); 57662306a36Sopenharmony_ci priv->stats = kvmalloc_array(stats_size, sizeof(struct nfp_fl_stats), 57762306a36Sopenharmony_ci GFP_KERNEL); 57862306a36Sopenharmony_ci if (!priv->stats) 57962306a36Sopenharmony_ci goto err_free_ring_buf; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci spin_lock_init(&priv->stats_lock); 58262306a36Sopenharmony_ci spin_lock_init(&priv->predt_lock); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci return 0; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_cierr_free_ring_buf: 58762306a36Sopenharmony_ci vfree(priv->stats_ids.free_list.buf); 58862306a36Sopenharmony_cierr_free_last_used: 58962306a36Sopenharmony_ci kfree(priv->mask_ids.last_used); 59062306a36Sopenharmony_cierr_free_mask_id: 59162306a36Sopenharmony_ci kfree(priv->mask_ids.mask_id_free_list.buf); 59262306a36Sopenharmony_cierr_free_neigh_table: 59362306a36Sopenharmony_ci rhashtable_destroy(&priv->neigh_table); 59462306a36Sopenharmony_cierr_free_ct_map_table: 59562306a36Sopenharmony_ci rhashtable_destroy(&priv->ct_map_table); 59662306a36Sopenharmony_cierr_free_ct_zone_table: 59762306a36Sopenharmony_ci rhashtable_destroy(&priv->ct_zone_table); 59862306a36Sopenharmony_cierr_free_merge_table: 59962306a36Sopenharmony_ci rhashtable_destroy(&priv->merge_table); 60062306a36Sopenharmony_cierr_free_stats_ctx_table: 60162306a36Sopenharmony_ci rhashtable_destroy(&priv->stats_ctx_table); 60262306a36Sopenharmony_cierr_free_flow_table: 60362306a36Sopenharmony_ci rhashtable_destroy(&priv->flow_table); 60462306a36Sopenharmony_ci return -ENOMEM; 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_cistatic void nfp_zone_table_entry_destroy(struct nfp_fl_ct_zone_entry *zt) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci if (!zt) 61062306a36Sopenharmony_ci return; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci if (!list_empty(&zt->pre_ct_list)) { 61362306a36Sopenharmony_ci struct rhashtable *m_table = &zt->priv->ct_map_table; 61462306a36Sopenharmony_ci struct nfp_fl_ct_flow_entry *entry, *tmp; 61562306a36Sopenharmony_ci struct nfp_fl_ct_map_entry *map; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci WARN_ONCE(1, "pre_ct_list not empty as expected, cleaning up\n"); 61862306a36Sopenharmony_ci list_for_each_entry_safe(entry, tmp, &zt->pre_ct_list, 61962306a36Sopenharmony_ci list_node) { 62062306a36Sopenharmony_ci map = rhashtable_lookup_fast(m_table, 62162306a36Sopenharmony_ci &entry->cookie, 62262306a36Sopenharmony_ci nfp_ct_map_params); 62362306a36Sopenharmony_ci WARN_ON_ONCE(rhashtable_remove_fast(m_table, 62462306a36Sopenharmony_ci &map->hash_node, 62562306a36Sopenharmony_ci nfp_ct_map_params)); 62662306a36Sopenharmony_ci nfp_fl_ct_clean_flow_entry(entry); 62762306a36Sopenharmony_ci kfree(map); 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci } 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci if (!list_empty(&zt->post_ct_list)) { 63262306a36Sopenharmony_ci struct rhashtable *m_table = &zt->priv->ct_map_table; 63362306a36Sopenharmony_ci struct nfp_fl_ct_flow_entry *entry, *tmp; 63462306a36Sopenharmony_ci struct nfp_fl_ct_map_entry *map; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci WARN_ONCE(1, "post_ct_list not empty as expected, cleaning up\n"); 63762306a36Sopenharmony_ci list_for_each_entry_safe(entry, tmp, &zt->post_ct_list, 63862306a36Sopenharmony_ci list_node) { 63962306a36Sopenharmony_ci map = rhashtable_lookup_fast(m_table, 64062306a36Sopenharmony_ci &entry->cookie, 64162306a36Sopenharmony_ci nfp_ct_map_params); 64262306a36Sopenharmony_ci WARN_ON_ONCE(rhashtable_remove_fast(m_table, 64362306a36Sopenharmony_ci &map->hash_node, 64462306a36Sopenharmony_ci nfp_ct_map_params)); 64562306a36Sopenharmony_ci nfp_fl_ct_clean_flow_entry(entry); 64662306a36Sopenharmony_ci kfree(map); 64762306a36Sopenharmony_ci } 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci if (zt->nft) { 65162306a36Sopenharmony_ci nf_flow_table_offload_del_cb(zt->nft, 65262306a36Sopenharmony_ci nfp_fl_ct_handle_nft_flow, 65362306a36Sopenharmony_ci zt); 65462306a36Sopenharmony_ci zt->nft = NULL; 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci if (!list_empty(&zt->nft_flows_list)) { 65862306a36Sopenharmony_ci struct rhashtable *m_table = &zt->priv->ct_map_table; 65962306a36Sopenharmony_ci struct nfp_fl_ct_flow_entry *entry, *tmp; 66062306a36Sopenharmony_ci struct nfp_fl_ct_map_entry *map; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci WARN_ONCE(1, "nft_flows_list not empty as expected, cleaning up\n"); 66362306a36Sopenharmony_ci list_for_each_entry_safe(entry, tmp, &zt->nft_flows_list, 66462306a36Sopenharmony_ci list_node) { 66562306a36Sopenharmony_ci map = rhashtable_lookup_fast(m_table, 66662306a36Sopenharmony_ci &entry->cookie, 66762306a36Sopenharmony_ci nfp_ct_map_params); 66862306a36Sopenharmony_ci WARN_ON_ONCE(rhashtable_remove_fast(m_table, 66962306a36Sopenharmony_ci &map->hash_node, 67062306a36Sopenharmony_ci nfp_ct_map_params)); 67162306a36Sopenharmony_ci nfp_fl_ct_clean_flow_entry(entry); 67262306a36Sopenharmony_ci kfree(map); 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci rhashtable_free_and_destroy(&zt->tc_merge_tb, 67762306a36Sopenharmony_ci nfp_check_rhashtable_empty, NULL); 67862306a36Sopenharmony_ci rhashtable_free_and_destroy(&zt->nft_merge_tb, 67962306a36Sopenharmony_ci nfp_check_rhashtable_empty, NULL); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci kfree(zt); 68262306a36Sopenharmony_ci} 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_cistatic void nfp_free_zone_table_entry(void *ptr, void *arg) 68562306a36Sopenharmony_ci{ 68662306a36Sopenharmony_ci struct nfp_fl_ct_zone_entry *zt = ptr; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci nfp_zone_table_entry_destroy(zt); 68962306a36Sopenharmony_ci} 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_cistatic void nfp_free_map_table_entry(void *ptr, void *arg) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci struct nfp_fl_ct_map_entry *map = ptr; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci if (!map) 69662306a36Sopenharmony_ci return; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci kfree(map); 69962306a36Sopenharmony_ci} 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_civoid nfp_flower_metadata_cleanup(struct nfp_app *app) 70262306a36Sopenharmony_ci{ 70362306a36Sopenharmony_ci struct nfp_flower_priv *priv = app->priv; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci if (!priv) 70662306a36Sopenharmony_ci return; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci rhashtable_free_and_destroy(&priv->flow_table, 70962306a36Sopenharmony_ci nfp_check_rhashtable_empty, NULL); 71062306a36Sopenharmony_ci rhashtable_free_and_destroy(&priv->stats_ctx_table, 71162306a36Sopenharmony_ci nfp_check_rhashtable_empty, NULL); 71262306a36Sopenharmony_ci rhashtable_free_and_destroy(&priv->merge_table, 71362306a36Sopenharmony_ci nfp_check_rhashtable_empty, NULL); 71462306a36Sopenharmony_ci rhashtable_free_and_destroy(&priv->ct_zone_table, 71562306a36Sopenharmony_ci nfp_free_zone_table_entry, NULL); 71662306a36Sopenharmony_ci nfp_zone_table_entry_destroy(priv->ct_zone_wc); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci rhashtable_free_and_destroy(&priv->ct_map_table, 71962306a36Sopenharmony_ci nfp_free_map_table_entry, NULL); 72062306a36Sopenharmony_ci rhashtable_free_and_destroy(&priv->neigh_table, 72162306a36Sopenharmony_ci nfp_check_rhashtable_empty, NULL); 72262306a36Sopenharmony_ci kvfree(priv->stats); 72362306a36Sopenharmony_ci kfree(priv->mask_ids.mask_id_free_list.buf); 72462306a36Sopenharmony_ci kfree(priv->mask_ids.last_used); 72562306a36Sopenharmony_ci vfree(priv->stats_ids.free_list.buf); 72662306a36Sopenharmony_ci} 727