0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0015 #include <linux/module.h>
0016 #include <linux/netdevice.h>
0017 #include <linux/spinlock.h>
0018 #include <linux/netfilter/x_tables.h>
0019 #include <linux/netfilter_bridge/ebtables.h>
0020 #include <linux/netfilter_bridge/ebt_limit.h>
0021
0022 static DEFINE_SPINLOCK(limit_lock);
0023
0024 #define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24))
0025
0026 #define _POW2_BELOW2(x) ((x)|((x)>>1))
0027 #define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2))
0028 #define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4))
0029 #define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8))
0030 #define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16))
0031 #define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1)
0032
0033 #define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ)
0034
0035 static bool
0036 ebt_limit_mt(const struct sk_buff *skb, struct xt_action_param *par)
0037 {
0038 struct ebt_limit_info *info = (void *)par->matchinfo;
0039 unsigned long now = jiffies;
0040
0041 spin_lock_bh(&limit_lock);
0042 info->credit += (now - xchg(&info->prev, now)) * CREDITS_PER_JIFFY;
0043 if (info->credit > info->credit_cap)
0044 info->credit = info->credit_cap;
0045
0046 if (info->credit >= info->cost) {
0047
0048 info->credit -= info->cost;
0049 spin_unlock_bh(&limit_lock);
0050 return true;
0051 }
0052
0053 spin_unlock_bh(&limit_lock);
0054 return false;
0055 }
0056
0057
0058 static u_int32_t
0059 user2credits(u_int32_t user)
0060 {
0061
0062 if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
0063
0064 return (user / EBT_LIMIT_SCALE) * HZ * CREDITS_PER_JIFFY;
0065
0066 return (user * HZ * CREDITS_PER_JIFFY) / EBT_LIMIT_SCALE;
0067 }
0068
0069 static int ebt_limit_mt_check(const struct xt_mtchk_param *par)
0070 {
0071 struct ebt_limit_info *info = par->matchinfo;
0072
0073
0074 if (info->burst == 0 ||
0075 user2credits(info->avg * info->burst) < user2credits(info->avg)) {
0076 pr_info_ratelimited("overflow, try lower: %u/%u\n",
0077 info->avg, info->burst);
0078 return -EINVAL;
0079 }
0080
0081
0082 info->prev = jiffies;
0083 info->credit = user2credits(info->avg * info->burst);
0084 info->credit_cap = user2credits(info->avg * info->burst);
0085 info->cost = user2credits(info->avg);
0086 return 0;
0087 }
0088
0089
0090 #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
0091
0092
0093
0094
0095 struct ebt_compat_limit_info {
0096 compat_uint_t avg, burst;
0097 compat_ulong_t prev;
0098 compat_uint_t credit, credit_cap, cost;
0099 };
0100 #endif
0101
0102 static struct xt_match ebt_limit_mt_reg __read_mostly = {
0103 .name = "limit",
0104 .revision = 0,
0105 .family = NFPROTO_BRIDGE,
0106 .match = ebt_limit_mt,
0107 .checkentry = ebt_limit_mt_check,
0108 .matchsize = sizeof(struct ebt_limit_info),
0109 .usersize = offsetof(struct ebt_limit_info, prev),
0110 #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
0111 .compatsize = sizeof(struct ebt_compat_limit_info),
0112 #endif
0113 .me = THIS_MODULE,
0114 };
0115
0116 static int __init ebt_limit_init(void)
0117 {
0118 return xt_register_match(&ebt_limit_mt_reg);
0119 }
0120
0121 static void __exit ebt_limit_fini(void)
0122 {
0123 xt_unregister_match(&ebt_limit_mt_reg);
0124 }
0125
0126 module_init(ebt_limit_init);
0127 module_exit(ebt_limit_fini);
0128 MODULE_DESCRIPTION("Ebtables: Rate-limit match");
0129 MODULE_LICENSE("GPL");