cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

xt_RATEEST.c (5706B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * (C) 2007 Patrick McHardy <kaber@trash.net>
      4 */
      5#include <linux/module.h>
      6#include <linux/skbuff.h>
      7#include <linux/gen_stats.h>
      8#include <linux/jhash.h>
      9#include <linux/rtnetlink.h>
     10#include <linux/random.h>
     11#include <linux/slab.h>
     12#include <net/gen_stats.h>
     13#include <net/netlink.h>
     14#include <net/netns/generic.h>
     15
     16#include <linux/netfilter/x_tables.h>
     17#include <linux/netfilter/xt_RATEEST.h>
     18#include <net/netfilter/xt_rateest.h>
     19
     20#define RATEEST_HSIZE	16
     21
     22struct xt_rateest_net {
     23	struct mutex hash_lock;
     24	struct hlist_head hash[RATEEST_HSIZE];
     25};
     26
     27static unsigned int xt_rateest_id;
     28
     29static unsigned int jhash_rnd __read_mostly;
     30
     31static unsigned int xt_rateest_hash(const char *name)
     32{
     33	return jhash(name, sizeof_field(struct xt_rateest, name), jhash_rnd) &
     34	       (RATEEST_HSIZE - 1);
     35}
     36
     37static void xt_rateest_hash_insert(struct xt_rateest_net *xn,
     38				   struct xt_rateest *est)
     39{
     40	unsigned int h;
     41
     42	h = xt_rateest_hash(est->name);
     43	hlist_add_head(&est->list, &xn->hash[h]);
     44}
     45
     46static struct xt_rateest *__xt_rateest_lookup(struct xt_rateest_net *xn,
     47					      const char *name)
     48{
     49	struct xt_rateest *est;
     50	unsigned int h;
     51
     52	h = xt_rateest_hash(name);
     53	hlist_for_each_entry(est, &xn->hash[h], list) {
     54		if (strcmp(est->name, name) == 0) {
     55			est->refcnt++;
     56			return est;
     57		}
     58	}
     59
     60	return NULL;
     61}
     62
     63struct xt_rateest *xt_rateest_lookup(struct net *net, const char *name)
     64{
     65	struct xt_rateest_net *xn = net_generic(net, xt_rateest_id);
     66	struct xt_rateest *est;
     67
     68	mutex_lock(&xn->hash_lock);
     69	est = __xt_rateest_lookup(xn, name);
     70	mutex_unlock(&xn->hash_lock);
     71	return est;
     72}
     73EXPORT_SYMBOL_GPL(xt_rateest_lookup);
     74
     75void xt_rateest_put(struct net *net, struct xt_rateest *est)
     76{
     77	struct xt_rateest_net *xn = net_generic(net, xt_rateest_id);
     78
     79	mutex_lock(&xn->hash_lock);
     80	if (--est->refcnt == 0) {
     81		hlist_del(&est->list);
     82		gen_kill_estimator(&est->rate_est);
     83		/*
     84		 * gen_estimator est_timer() might access est->lock or bstats,
     85		 * wait a RCU grace period before freeing 'est'
     86		 */
     87		kfree_rcu(est, rcu);
     88	}
     89	mutex_unlock(&xn->hash_lock);
     90}
     91EXPORT_SYMBOL_GPL(xt_rateest_put);
     92
     93static unsigned int
     94xt_rateest_tg(struct sk_buff *skb, const struct xt_action_param *par)
     95{
     96	const struct xt_rateest_target_info *info = par->targinfo;
     97	struct gnet_stats_basic_sync *stats = &info->est->bstats;
     98
     99	spin_lock_bh(&info->est->lock);
    100	u64_stats_add(&stats->bytes, skb->len);
    101	u64_stats_inc(&stats->packets);
    102	spin_unlock_bh(&info->est->lock);
    103
    104	return XT_CONTINUE;
    105}
    106
    107static int xt_rateest_tg_checkentry(const struct xt_tgchk_param *par)
    108{
    109	struct xt_rateest_net *xn = net_generic(par->net, xt_rateest_id);
    110	struct xt_rateest_target_info *info = par->targinfo;
    111	struct xt_rateest *est;
    112	struct {
    113		struct nlattr		opt;
    114		struct gnet_estimator	est;
    115	} cfg;
    116	int ret;
    117
    118	if (strnlen(info->name, sizeof(est->name)) >= sizeof(est->name))
    119		return -ENAMETOOLONG;
    120
    121	net_get_random_once(&jhash_rnd, sizeof(jhash_rnd));
    122
    123	mutex_lock(&xn->hash_lock);
    124	est = __xt_rateest_lookup(xn, info->name);
    125	if (est) {
    126		mutex_unlock(&xn->hash_lock);
    127		/*
    128		 * If estimator parameters are specified, they must match the
    129		 * existing estimator.
    130		 */
    131		if ((!info->interval && !info->ewma_log) ||
    132		    (info->interval != est->params.interval ||
    133		     info->ewma_log != est->params.ewma_log)) {
    134			xt_rateest_put(par->net, est);
    135			return -EINVAL;
    136		}
    137		info->est = est;
    138		return 0;
    139	}
    140
    141	ret = -ENOMEM;
    142	est = kzalloc(sizeof(*est), GFP_KERNEL);
    143	if (!est)
    144		goto err1;
    145
    146	gnet_stats_basic_sync_init(&est->bstats);
    147	strlcpy(est->name, info->name, sizeof(est->name));
    148	spin_lock_init(&est->lock);
    149	est->refcnt		= 1;
    150	est->params.interval	= info->interval;
    151	est->params.ewma_log	= info->ewma_log;
    152
    153	cfg.opt.nla_len		= nla_attr_size(sizeof(cfg.est));
    154	cfg.opt.nla_type	= TCA_STATS_RATE_EST;
    155	cfg.est.interval	= info->interval;
    156	cfg.est.ewma_log	= info->ewma_log;
    157
    158	ret = gen_new_estimator(&est->bstats, NULL, &est->rate_est,
    159				&est->lock, NULL, &cfg.opt);
    160	if (ret < 0)
    161		goto err2;
    162
    163	info->est = est;
    164	xt_rateest_hash_insert(xn, est);
    165	mutex_unlock(&xn->hash_lock);
    166	return 0;
    167
    168err2:
    169	kfree(est);
    170err1:
    171	mutex_unlock(&xn->hash_lock);
    172	return ret;
    173}
    174
    175static void xt_rateest_tg_destroy(const struct xt_tgdtor_param *par)
    176{
    177	struct xt_rateest_target_info *info = par->targinfo;
    178
    179	xt_rateest_put(par->net, info->est);
    180}
    181
    182static struct xt_target xt_rateest_tg_reg __read_mostly = {
    183	.name       = "RATEEST",
    184	.revision   = 0,
    185	.family     = NFPROTO_UNSPEC,
    186	.target     = xt_rateest_tg,
    187	.checkentry = xt_rateest_tg_checkentry,
    188	.destroy    = xt_rateest_tg_destroy,
    189	.targetsize = sizeof(struct xt_rateest_target_info),
    190	.usersize   = offsetof(struct xt_rateest_target_info, est),
    191	.me         = THIS_MODULE,
    192};
    193
    194static __net_init int xt_rateest_net_init(struct net *net)
    195{
    196	struct xt_rateest_net *xn = net_generic(net, xt_rateest_id);
    197	int i;
    198
    199	mutex_init(&xn->hash_lock);
    200	for (i = 0; i < ARRAY_SIZE(xn->hash); i++)
    201		INIT_HLIST_HEAD(&xn->hash[i]);
    202	return 0;
    203}
    204
    205static struct pernet_operations xt_rateest_net_ops = {
    206	.init = xt_rateest_net_init,
    207	.id   = &xt_rateest_id,
    208	.size = sizeof(struct xt_rateest_net),
    209};
    210
    211static int __init xt_rateest_tg_init(void)
    212{
    213	int err = register_pernet_subsys(&xt_rateest_net_ops);
    214
    215	if (err)
    216		return err;
    217	return xt_register_target(&xt_rateest_tg_reg);
    218}
    219
    220static void __exit xt_rateest_tg_fini(void)
    221{
    222	xt_unregister_target(&xt_rateest_tg_reg);
    223	unregister_pernet_subsys(&xt_rateest_net_ops);
    224}
    225
    226
    227MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
    228MODULE_LICENSE("GPL");
    229MODULE_DESCRIPTION("Xtables: packet rate estimator");
    230MODULE_ALIAS("ipt_RATEEST");
    231MODULE_ALIAS("ip6t_RATEEST");
    232module_init(xt_rateest_tg_init);
    233module_exit(xt_rateest_tg_fini);