Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * ebt_limit | |
3 | * | |
4 | * Authors: | |
5 | * Tom Marshall <tommy@home.tig-grr.com> | |
6 | * | |
7 | * Mostly copied from netfilter's ipt_limit.c, see that file for | |
8 | * more explanation | |
9 | * | |
10 | * September, 2003 | |
11 | * | |
12 | */ | |
ff67e4e4 | 13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
1da177e4 | 14 | #include <linux/module.h> |
1da177e4 LT |
15 | #include <linux/netdevice.h> |
16 | #include <linux/spinlock.h> | |
18219d3f JE |
17 | #include <linux/netfilter/x_tables.h> |
18 | #include <linux/netfilter_bridge/ebtables.h> | |
19 | #include <linux/netfilter_bridge/ebt_limit.h> | |
1da177e4 LT |
20 | |
21 | static DEFINE_SPINLOCK(limit_lock); | |
22 | ||
23 | #define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24)) | |
24 | ||
25 | #define _POW2_BELOW2(x) ((x)|((x)>>1)) | |
26 | #define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2)) | |
27 | #define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4)) | |
28 | #define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8)) | |
29 | #define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16)) | |
30 | #define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1) | |
31 | ||
32 | #define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ) | |
33 | ||
2d06d4a5 | 34 | static bool |
62fc8051 | 35 | ebt_limit_mt(const struct sk_buff *skb, struct xt_action_param *par) |
1da177e4 | 36 | { |
f7108a20 | 37 | struct ebt_limit_info *info = (void *)par->matchinfo; |
1da177e4 LT |
38 | unsigned long now = jiffies; |
39 | ||
40 | spin_lock_bh(&limit_lock); | |
41 | info->credit += (now - xchg(&info->prev, now)) * CREDITS_PER_JIFFY; | |
42 | if (info->credit > info->credit_cap) | |
43 | info->credit = info->credit_cap; | |
44 | ||
45 | if (info->credit >= info->cost) { | |
46 | /* We're not limited. */ | |
47 | info->credit -= info->cost; | |
48 | spin_unlock_bh(&limit_lock); | |
8cc784ee | 49 | return true; |
1da177e4 LT |
50 | } |
51 | ||
52 | spin_unlock_bh(&limit_lock); | |
8cc784ee | 53 | return false; |
1da177e4 LT |
54 | } |
55 | ||
56 | /* Precision saver. */ | |
57 | static u_int32_t | |
58 | user2credits(u_int32_t user) | |
59 | { | |
60 | /* If multiplying would overflow... */ | |
61 | if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY)) | |
62 | /* Divide first. */ | |
63 | return (user / EBT_LIMIT_SCALE) * HZ * CREDITS_PER_JIFFY; | |
64 | ||
65 | return (user * HZ * CREDITS_PER_JIFFY) / EBT_LIMIT_SCALE; | |
66 | } | |
67 | ||
b0f38452 | 68 | static int ebt_limit_mt_check(const struct xt_mtchk_param *par) |
1da177e4 | 69 | { |
9b4fce7a | 70 | struct ebt_limit_info *info = par->matchinfo; |
1da177e4 | 71 | |
1da177e4 LT |
72 | /* Check for overflow. */ |
73 | if (info->burst == 0 || | |
74 | user2credits(info->avg * info->burst) < user2credits(info->avg)) { | |
ff67e4e4 | 75 | pr_info("overflow, try lower: %u/%u\n", |
1da177e4 | 76 | info->avg, info->burst); |
bd414ee6 | 77 | return -EINVAL; |
1da177e4 LT |
78 | } |
79 | ||
80 | /* User avg in seconds * EBT_LIMIT_SCALE: convert to jiffies * 128. */ | |
81 | info->prev = jiffies; | |
82 | info->credit = user2credits(info->avg * info->burst); | |
83 | info->credit_cap = user2credits(info->avg * info->burst); | |
84 | info->cost = user2credits(info->avg); | |
bd414ee6 | 85 | return 0; |
1da177e4 LT |
86 | } |
87 | ||
314ddca3 FW |
88 | |
89 | #ifdef CONFIG_COMPAT | |
90 | /* | |
91 | * no conversion function needed -- | |
92 | * only avg/burst have meaningful values in userspace. | |
93 | */ | |
94 | struct ebt_compat_limit_info { | |
95 | compat_uint_t avg, burst; | |
96 | compat_ulong_t prev; | |
97 | compat_uint_t credit, credit_cap, cost; | |
98 | }; | |
99 | #endif | |
100 | ||
043ef46c JE |
101 | static struct xt_match ebt_limit_mt_reg __read_mostly = { |
102 | .name = "limit", | |
001a18d3 JE |
103 | .revision = 0, |
104 | .family = NFPROTO_BRIDGE, | |
2d06d4a5 JE |
105 | .match = ebt_limit_mt, |
106 | .checkentry = ebt_limit_mt_check, | |
fc0e3df4 | 107 | .matchsize = sizeof(struct ebt_limit_info), |
314ddca3 FW |
108 | #ifdef CONFIG_COMPAT |
109 | .compatsize = sizeof(struct ebt_compat_limit_info), | |
110 | #endif | |
1da177e4 LT |
111 | .me = THIS_MODULE, |
112 | }; | |
113 | ||
65b4b4e8 | 114 | static int __init ebt_limit_init(void) |
1da177e4 | 115 | { |
043ef46c | 116 | return xt_register_match(&ebt_limit_mt_reg); |
1da177e4 LT |
117 | } |
118 | ||
65b4b4e8 | 119 | static void __exit ebt_limit_fini(void) |
1da177e4 | 120 | { |
043ef46c | 121 | xt_unregister_match(&ebt_limit_mt_reg); |
1da177e4 LT |
122 | } |
123 | ||
65b4b4e8 AM |
124 | module_init(ebt_limit_init); |
125 | module_exit(ebt_limit_fini); | |
f776c4cd | 126 | MODULE_DESCRIPTION("Ebtables: Rate-limit match"); |
1da177e4 | 127 | MODULE_LICENSE("GPL"); |