Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 79e6d46a authored by Kumar Sanghvi's avatar Kumar Sanghvi Committed by David S. Miller
Browse files

cxgb4: convert flower table to use rhashtable



T6 supports ~500K hash filters and can theoretically climb up to
~1 million hash filters. Preallocated hash table is not efficient
in terms of memory usage. So, use rhashtable instead which gives
the flexibility to grow based on usage.

Signed-off-by: default avatarKumar Sanghvi <kumaras@chelsio.com>
Signed-off-by: default avatarRahul Lakkireddy <rahul.lakkireddy@chelsio.com>
Signed-off-by: default avatarGanesh Goudar <ganeshgr@chelsio.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9d922d4b
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -918,8 +918,10 @@ struct adapter {
	struct chcr_stats_debug chcr_stats;

	/* TC flower offload */
	DECLARE_HASHTABLE(flower_anymatch_tbl, 9);
	struct rhashtable flower_tbl;
	struct rhashtable_params flower_ht_params;
	struct timer_list flower_stats_timer;
	struct work_struct flower_stats_work;

	/* Ethtool Dump */
	struct ethtool_dump eth_dump;
+3 −1
Original line number Diff line number Diff line
@@ -5182,7 +5182,9 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
			dev_warn(&pdev->dev,
				 "could not offload tc u32, continuing\n");

		cxgb4_init_tc_flower(adapter);
		if (cxgb4_init_tc_flower(adapter))
			dev_warn(&pdev->dev,
				 "could not offload tc flower, continuing\n");
	}

	if (is_offload(adapter) || is_hashfilter(adapter)) {
+74 −32
Original line number Diff line number Diff line
@@ -74,13 +74,8 @@ static struct ch_tc_flower_entry *allocate_flower_entry(void)
static struct ch_tc_flower_entry *ch_flower_lookup(struct adapter *adap,
						   unsigned long flower_cookie)
{
	struct ch_tc_flower_entry *flower_entry;

	hash_for_each_possible_rcu(adap->flower_anymatch_tbl, flower_entry,
				   link, flower_cookie)
		if (flower_entry->tc_flower_cookie == flower_cookie)
			return flower_entry;
	return NULL;
	return rhashtable_lookup_fast(&adap->flower_tbl, &flower_cookie,
				      adap->flower_ht_params);
}

static void cxgb4_process_flow_match(struct net_device *dev,
@@ -707,12 +702,17 @@ int cxgb4_tc_flower_replace(struct net_device *dev,
		goto free_entry;
	}

	INIT_HLIST_NODE(&ch_flower->link);
	ch_flower->tc_flower_cookie = cls->cookie;
	ch_flower->filter_id = ctx.tid;
	hash_add_rcu(adap->flower_anymatch_tbl, &ch_flower->link, cls->cookie);
	ret = rhashtable_insert_fast(&adap->flower_tbl, &ch_flower->node,
				     adap->flower_ht_params);
	if (ret)
		goto del_filter;

	return ret;
	return 0;

del_filter:
	cxgb4_del_filter(dev, ch_flower->filter_id, &ch_flower->fs);

free_entry:
	kfree(ch_flower);
@@ -734,25 +734,37 @@ int cxgb4_tc_flower_destroy(struct net_device *dev,
	if (ret)
		goto err;

	hash_del_rcu(&ch_flower->link);
	ret = rhashtable_remove_fast(&adap->flower_tbl, &ch_flower->node,
				     adap->flower_ht_params);
	if (ret) {
		netdev_err(dev, "Flow remove from rhashtable failed");
		goto err;
	}
	kfree_rcu(ch_flower, rcu);

err:
	return ret;
}

static void ch_flower_stats_cb(struct timer_list *t)
static void ch_flower_stats_handler(struct work_struct *work)
{
	struct adapter *adap = from_timer(adap, t, flower_stats_timer);
	struct adapter *adap = container_of(work, struct adapter,
					    flower_stats_work);
	struct ch_tc_flower_entry *flower_entry;
	struct ch_tc_flower_stats *ofld_stats;
	unsigned int i;
	struct rhashtable_iter iter;
	u64 packets;
	u64 bytes;
	int ret;

	rcu_read_lock();
	hash_for_each_rcu(adap->flower_anymatch_tbl, i, flower_entry, link) {
	rhashtable_walk_enter(&adap->flower_tbl, &iter);
	do {
		flower_entry = ERR_PTR(rhashtable_walk_start(&iter));
		if (IS_ERR(flower_entry))
			goto walk_stop;

		while ((flower_entry = rhashtable_walk_next(&iter)) &&
		       !IS_ERR(flower_entry)) {
			ret = cxgb4_get_filter_counters(adap->port[0],
							flower_entry->filter_id,
							&packets, &bytes,
@@ -768,10 +780,20 @@ static void ch_flower_stats_cb(struct timer_list *t)
				spin_unlock(&flower_entry->lock);
			}
		}
	rcu_read_unlock();
walk_stop:
		rhashtable_walk_stop(&iter);
	} while (flower_entry == ERR_PTR(-EAGAIN));
	rhashtable_walk_exit(&iter);
	mod_timer(&adap->flower_stats_timer, jiffies + STATS_CHECK_PERIOD);
}

static void ch_flower_stats_cb(struct timer_list *t)
{
	struct adapter *adap = from_timer(adap, t, flower_stats_timer);

	schedule_work(&adap->flower_stats_work);
}

int cxgb4_tc_flower_stats(struct net_device *dev,
			  struct tc_cls_flower_offload *cls)
{
@@ -814,15 +836,35 @@ int cxgb4_tc_flower_stats(struct net_device *dev,
	return ret;
}

void cxgb4_init_tc_flower(struct adapter *adap)
static const struct rhashtable_params cxgb4_tc_flower_ht_params = {
	.nelem_hint = 384,
	.head_offset = offsetof(struct ch_tc_flower_entry, node),
	.key_offset = offsetof(struct ch_tc_flower_entry, tc_flower_cookie),
	.key_len = sizeof(((struct ch_tc_flower_entry *)0)->tc_flower_cookie),
	.max_size = 524288,
	.min_size = 512,
	.automatic_shrinking = true
};

int cxgb4_init_tc_flower(struct adapter *adap)
{
	hash_init(adap->flower_anymatch_tbl);
	int ret;

	adap->flower_ht_params = cxgb4_tc_flower_ht_params;
	ret = rhashtable_init(&adap->flower_tbl, &adap->flower_ht_params);
	if (ret)
		return ret;

	INIT_WORK(&adap->flower_stats_work, ch_flower_stats_handler);
	timer_setup(&adap->flower_stats_timer, ch_flower_stats_cb, 0);
	mod_timer(&adap->flower_stats_timer, jiffies + STATS_CHECK_PERIOD);
	return 0;
}

void cxgb4_cleanup_tc_flower(struct adapter *adap)
{
	if (adap->flower_stats_timer.function)
		del_timer_sync(&adap->flower_stats_timer);
	cancel_work_sync(&adap->flower_stats_work);
	rhashtable_destroy(&adap->flower_tbl);
}
+2 −2
Original line number Diff line number Diff line
@@ -48,7 +48,7 @@ struct ch_tc_flower_entry {
	struct ch_filter_specification fs;
	struct ch_tc_flower_stats stats;
	unsigned long tc_flower_cookie;
	struct hlist_node link;
	struct rhash_head node;
	struct rcu_head rcu;
	spinlock_t lock; /* lock for stats */
	u32 filter_id;
@@ -115,6 +115,6 @@ int cxgb4_tc_flower_destroy(struct net_device *dev,
int cxgb4_tc_flower_stats(struct net_device *dev,
			  struct tc_cls_flower_offload *cls);

void cxgb4_init_tc_flower(struct adapter *adap);
int cxgb4_init_tc_flower(struct adapter *adap);
void cxgb4_cleanup_tc_flower(struct adapter *adap);
#endif /* __CXGB4_TC_FLOWER_H */