libxt_hashlimit: Create revision 2 of xt_hashlimit to support higher pps rates
Subsystems (3)
PATCH v4 2/2 libxt_hashlimit: Create revision 2 of xt_hashlimit to support higher pps rates
v2:
* Added two tests for 1000000pps support to libxt_hashlimit.t
* cfg_copy returns -EINVAL and all callers of cfg_copy will look
for the error value
v3:
Reorder mode, avg and burst in hashlimit_cfg2 to avoid padding
v4:XT_HASHLIMIT_SCALE for rev2 is now XT_HASHLIMIT_SCALE_v2
--
libxt_hashlimit: Create revision 2 of xt_hashlimit to support higher pps rates
Create a new revision for the hashlimit iptables extension module. Rev 2 will support higher pps of upto 1 million, Version 1 supports only 10k.
To support this we have to increase the size of the variables avg and burst in hashlimit_cfg to 64-bit. Create two new structs hashlimit_cfg2 and xt_hashlimit_mtinfo2 and also create newer versions of all the functions for match, checkentry and destory.
--- extensions/libxt_hashlimit.c | 457 ++++++++++++++++++++++++++------- extensions/libxt_hashlimit.t | 2 + include/linux/netfilter/xt_hashlimit.h | 26 +- 3 files changed, 394 insertions(+), 91 deletions(-)
extensions/libxt_hashlimit.c +367 -90
@@ -18,12 +18,14 @@#include <stdio.h> #include <string.h> #include <stdlib.h> +#include <errno.h> #include <xtables.h> #include <linux/netfilter/x_tables.h> #include <linux/netfilter/xt_hashlimit.h> #define XT_HASHLIMIT_BURST 5#define XT_HASHLIMIT_BURST_MAX_v1 10000 +#define XT_HASHLIMIT_BURST_MAX 1000000#define XT_HASHLIMIT_BYTE_EXPIRE 15#define XT_HASHLIMIT_BYTE_EXPIRE_BURST 60
@@ -150,16 +152,70 @@ static const struct xt_option_entry hashlimit_mt_opts_v1[] = { };#undef s -static uint32_t cost_to_bytes (uint32_t cost) +#define s struct xt_hashlimit_mtinfo2 +static const struct xt_option_entry hashlimit_mt_opts[] = { + {.name ="hashlimit-upto" , .id =O_UPTO , .excl =F_ABOVE , + .type =XTTYPE_STRING , .flags =XTOPT_INVERT }, + {.name ="hashlimit-above" , .id =O_ABOVE , .excl =F_UPTO , + .type =XTTYPE_STRING , .flags =XTOPT_INVERT }, + {.name ="hashlimit" , .id =O_UPTO , .excl =F_ABOVE , + .type =XTTYPE_STRING , .flags =XTOPT_INVERT },/* old name */ + {.name ="hashlimit-srcmask" , .id =O_SRCMASK , .type =XTTYPE_PLEN }, + {.name ="hashlimit-dstmask" , .id =O_DSTMASK , .type =XTTYPE_PLEN }, + {.name ="hashlimit-burst" , .id =O_BURST , .type =XTTYPE_STRING }, + {.name ="hashlimit-htable-size" , .id =O_HTABLE_SIZE , + .type =XTTYPE_UINT32 , .flags =XTOPT_PUT , +XTOPT_POINTER (s, cfg.size)}, + {.name ="hashlimit-htable-max" , .id =O_HTABLE_MAX , + .type =XTTYPE_UINT32 , .flags =XTOPT_PUT , +XTOPT_POINTER (s, cfg.max)}, + {.name ="hashlimit-htable-gcinterval" , .id =O_HTABLE_GCINT , + .type =XTTYPE_UINT32 , .flags =XTOPT_PUT , +XTOPT_POINTER (s, cfg.gc_interval)}, + {.name ="hashlimit-htable-expire" , .id =O_HTABLE_EXPIRE , + .type =XTTYPE_UINT32 , .flags =XTOPT_PUT , +XTOPT_POINTER (s, cfg.expire)}, + {.name ="hashlimit-mode" , .id =O_MODE , .type =XTTYPE_STRING }, + {.name ="hashlimit-name" , .id =O_NAME , .type =XTTYPE_STRING , + .flags =XTOPT_MAND |XTOPT_PUT ,XTOPT_POINTER (s, name), .min =1 }, +XTOPT_TABLEEND , +}; +#undef s + +static int +cfg_copy (struct hashlimit_cfg2 *to,const void *from,int revision) +{ +if (revision ==1 ) { +struct hashlimit_cfg1 *cfg = (struct hashlimit_cfg1 *)from; + + to->mode = cfg->mode; + to->avg = cfg->avg; + to->burst = cfg->burst; + to->size = cfg->size; + to->max = cfg->max; + to->gc_interval = cfg->gc_interval; + to->expire = cfg->expire; + to->srcmask = cfg->srcmask; + to->dstmask = cfg->dstmask; + }else if (revision ==2 ) { +memcpy (to, from,sizeof (struct hashlimit_cfg2 )); + }else { +return -EINVAL ; + } + +return 0 ; +} + +static uint64_t cost_to_bytes (uint64_t cost) { -uint32_t r; +uint64_t r; r = cost ?UINT32_MAX / cost :UINT32_MAX ; r = (r -1 ) <<XT_HASHLIMIT_BYTE_SHIFT ;return r; } -static uint64_t bytes_to_cost (uint32_t bytes) +static uint64_t bytes_to_cost (uint64_t bytes) {uint32_t r = bytes >>XT_HASHLIMIT_BYTE_SHIFT ;return UINT32_MAX / (r+1 );
@@ -180,57 +236,78 @@ static void burst_error_v1(void) "\"--hashlimit-burst\", or out of range (1-%u).", XT_HASHLIMIT_BURST_MAX_v1); } -static uint32_t parse_burst (const char *burst,struct xt_hashlimit_mtinfo1 *info) +static void burst_error (void ) +{ +xtables_error (PARAMETER_PROBLEM ,"bad value for option " +"\"--hashlimit-burst\", or out of range (1-%u)." ,XT_HASHLIMIT_BURST_MAX ); +} + +static uint64_t parse_burst (const char *burst,int revision) {uintmax_t v;char *end; - -if (!xtables_strtoul (burst, &end, &v,1 ,UINT32_MAX ) || - (*end ==0 && v > XT_HASHLIMIT_BURST_MAX_v1)) -burst_error_v1 (); +uint64_t max = (revision ==1 ) ?UINT32_MAX :UINT64_MAX ; +uint64_t burst_max = (revision ==1 ) ? + XT_HASHLIMIT_BURST_MAX_v1 :XT_HASHLIMIT_BURST_MAX ; + +if (!xtables_strtoul (burst, &end, &v,1 , max) || + (*end ==0 && v > burst_max)) { +if (revision ==1 ) +burst_error_v1 (); +else +burst_error (); + } v *=get_factor (*end); -if (v >UINT32_MAX ) +if (v > max)xtables_error (PARAMETER_PROBLEM ,"bad value for option " "\"--hashlimit-burst\", value \"%s\" too large " -"(max %umb)." , burst,UINT32_MAX /1024 /1024 ); +"(max %lumb)." , burst, max/1024 /1024 );return v; } -static bool parse_bytes (const char *rate,uint32_t *val,struct hashlimit_mt_udata *ud) +static bool parse_bytes (const char *rate,void *val,struct hashlimit_mt_udata *ud,int revision) {unsigned int factor =1 ; -uint64_t tmp; -int r; +uint64_t tmp, r;const char *mode =strstr (rate,"b/s" ); +uint64_t max = (revision ==1 ) ?UINT32_MAX :UINT64_MAX ; +if (!mode || mode == rate)return false; mode--; - r =atoi (rate); + r =atoll (rate);if (r ==0 )return false; factor =get_factor (*mode); tmp = (uint64_t ) r * factor; -if (tmp >UINT32_MAX ) +if (tmp > max)xtables_error (PARAMETER_PROBLEM , -"Rate value too large \"%llu\" (max %u)\n" , - (unsigned long long )tmp,UINT32_MAX ); +"Rate value too large \"%llu\" (max %lu)\n" , + (unsigned long long )tmp, max); - *val =bytes_to_cost (tmp); -if (*val ==0 ) + tmp =bytes_to_cost (tmp); +if (tmp ==0 )xtables_error (PARAMETER_PROBLEM ,"Rate too high \"%s\"\n" , rate); ud->mult =XT_HASHLIMIT_BYTE_EXPIRE ; + +if (revision ==1 ) + *((uint32_t *)val) = tmp; +else + *((uint64_t *)val) = tmp; +return true; }static -int parse_rate (const char *rate,uint32_t *val,struct hashlimit_mt_udata *ud) +int parse_rate (const char *rate,void *val,struct hashlimit_mt_udata *ud,int revision) {const char *delim; -uint32_t r; +uint64_t tmp, r; +uint64_t scale = (revision ==1 ) ?XT_HASHLIMIT_SCALE : XT_HASHLIMIT_SCALE_v2; ud->mult =1 ;/* Seconds by default. */ delim =strchr (rate,'/' );
@@ -249,17 +326,23 @@ int parse_rate(const char *rate, uint32_t *val, struct hashlimit_mt_udata *ud)else return 0 ; } - r =atoi (rate); + r =atoll (rate);if (!r)return 0 ; - *val =XT_HASHLIMIT_SCALE * ud->mult / r; -if (*val ==0 ) + tmp = scale * ud->mult / r; +if (tmp ==0 )/* * The rate maps to infinity. (1/day is the minimum they can * specify, so we are ok at that end). */ xtables_error (PARAMETER_PROBLEM ,"Rate too fast \"%s\"\n" , rate); + +if (revision ==1 ) + *((uint32_t *)val) = tmp; +else + *((uint64_t *)val) = tmp; +return 1 ; }
@@ -294,6 +377,28 @@ static void hashlimit_mt6_init_v1(struct xt_entry_match *match) info->cfg.dstmask =128 ; } +static void hashlimit_mt4_init (struct xt_entry_match *match) +{ +struct xt_hashlimit_mtinfo2 *info = (void *)match->data; + + info->cfg.mode =0 ; + info->cfg.burst =XT_HASHLIMIT_BURST ; + info->cfg.gc_interval =XT_HASHLIMIT_GCINTERVAL ; + info->cfg.srcmask =32 ; + info->cfg.dstmask =32 ; +} + +static void hashlimit_mt6_init (struct xt_entry_match *match) +{ +struct xt_hashlimit_mtinfo2 *info = (void *)match->data; + + info->cfg.mode =0 ; + info->cfg.burst =XT_HASHLIMIT_BURST ; + info->cfg.gc_interval =XT_HASHLIMIT_GCINTERVAL ; + info->cfg.srcmask =128 ; + info->cfg.dstmask =128 ; +} +/* Parse a 'mode' parameter into the required bitmask */ static int parse_mode (uint32_t *mode,const char *option_arg) {
@@ -330,7 +435,7 @@ static void hashlimit_parse(struct xt_option_call *cb)xtables_option_parse (cb);switch (cb->entry->id) {case O_UPTO : -if (!parse_rate (cb->arg, &info->cfg.avg, cb->udata)) +if (!parse_rate (cb->arg, &info->cfg.avg, cb->udata,1 ))xtables_param_act (XTF_BAD_VALUE ,"hashlimit" ,"--hashlimit-upto" , cb->arg);break ;
@@ -349,23 +454,64 @@ static void hashlimit_mt_parse_v1(struct xt_option_call *cb)xtables_option_parse (cb);switch (cb->entry->id) {case O_BURST : - info->cfg.burst =parse_burst (cb->arg, info); + info->cfg.burst =parse_burst (cb->arg,1 );break ;case O_UPTO :if (cb->invert) info->cfg.mode |=XT_HASHLIMIT_INVERT ; -if (parse_bytes (cb->arg, &info->cfg.avg, cb->udata)) +if (parse_bytes (cb->arg, &info->cfg.avg, cb->udata,1 )) info->cfg.mode |=XT_HASHLIMIT_BYTES ; -else if (!parse_rate (cb->arg, &info->cfg.avg, cb->udata)) +else if (!parse_rate (cb->arg, &info->cfg.avg, cb->udata,1 ))xtables_param_act (XTF_BAD_VALUE ,"hashlimit" ,"--hashlimit-upto" , cb->arg);break ;case O_ABOVE :if (!cb->invert) info->cfg.mode |=XT_HASHLIMIT_INVERT ; -if (parse_bytes (cb->arg, &info->cfg.avg, cb->udata)) +if (parse_bytes (cb->arg, &info->cfg.avg, cb->udata,1 )) info->cfg.mode |=XT_HASHLIMIT_BYTES ; -else if (!parse_rate (cb->arg, &info->cfg.avg, cb->udata)) +else if (!parse_rate (cb->arg, &info->cfg.avg, cb->udata,1 )) +xtables_param_act (XTF_BAD_VALUE ,"hashlimit" , +"--hashlimit-above" , cb->arg); +break ; +case O_MODE : +if (parse_mode (&info->cfg.mode, cb->arg) <0 ) +xtables_param_act (XTF_BAD_VALUE ,"hashlimit" , +"--hashlimit-mode" , cb->arg); +break ; +case O_SRCMASK : + info->cfg.srcmask = cb->val.hlen; +break ; +case O_DSTMASK : + info->cfg.dstmask = cb->val.hlen; +break ; + } +} + +static void hashlimit_mt_parse (struct xt_option_call *cb) +{ +struct xt_hashlimit_mtinfo2 *info = cb->data; + +xtables_option_parse (cb); +switch (cb->entry->id) { +case O_BURST : + info->cfg.burst =parse_burst (cb->arg,2 ); +break ; +case O_UPTO : +if (cb->invert) + info->cfg.mode |=XT_HASHLIMIT_INVERT ; +if (parse_bytes (cb->arg, &info->cfg.avg, cb->udata,2 )) + info->cfg.mode |=XT_HASHLIMIT_BYTES ; +else if (!parse_rate (cb->arg, &info->cfg.avg, cb->udata,2 )) +xtables_param_act (XTF_BAD_VALUE ,"hashlimit" , +"--hashlimit-upto" , cb->arg); +break ; +case O_ABOVE : +if (!cb->invert) + info->cfg.mode |=XT_HASHLIMIT_INVERT ; +if (parse_bytes (cb->arg, &info->cfg.avg, cb->udata,2 )) + info->cfg.mode |=XT_HASHLIMIT_BYTES ; +else if (!parse_rate (cb->arg, &info->cfg.avg, cb->udata,2 ))xtables_param_act (XTF_BAD_VALUE ,"hashlimit" ,"--hashlimit-above" , cb->arg);break ;
@@ -411,7 +557,7 @@ static void hashlimit_mt_check_v1(struct xt_fcheck_call *cb)if (cb->xflags &F_BURST ) {if (info->cfg.burst <cost_to_bytes (info->cfg.avg))xtables_error (PARAMETER_PROBLEM , -"burst cannot be smaller than %ub" ,cost_to_bytes (info->cfg.avg)); +"burst cannot be smaller than %lub" ,cost_to_bytes (info->cfg.avg)); burst = info->cfg.burst; burst /=cost_to_bytes (info->cfg.avg);
@@ -425,32 +571,69 @@ static void hashlimit_mt_check_v1(struct xt_fcheck_call *cb)burst_error_v1 (); } -static const struct rates_v1 +static void hashlimit_mt_check (struct xt_fcheck_call *cb) { +const struct hashlimit_mt_udata *udata = cb->udata; +struct xt_hashlimit_mtinfo2 *info = cb->data; + +if (!(cb->xflags & (F_UPTO |F_ABOVE ))) +xtables_error (PARAMETER_PROBLEM , +"You have to specify --hashlimit" ); +if (!(cb->xflags &F_HTABLE_EXPIRE )) + info->cfg.expire = udata->mult *1000 ;/* from s to msec */ + +if (info->cfg.mode &XT_HASHLIMIT_BYTES ) { +uint32_t burst =0 ; +if (cb->xflags &F_BURST ) { +if (info->cfg.burst <cost_to_bytes (info->cfg.avg)) +xtables_error (PARAMETER_PROBLEM , +"burst cannot be smaller than %lub" ,cost_to_bytes (info->cfg.avg)); + + burst = info->cfg.burst; + burst /=cost_to_bytes (info->cfg.avg); +if (info->cfg.burst %cost_to_bytes (info->cfg.avg)) + burst++; +if (!(cb->xflags &F_HTABLE_EXPIRE )) + info->cfg.expire =XT_HASHLIMIT_BYTE_EXPIRE_BURST *1000 ; + } + info->cfg.burst = burst; + }else if (info->cfg.burst >XT_HASHLIMIT_BURST_MAX ) +burst_error (); +} + +struct rates {const char *name; -uint32_t mult; +uint64_t mult; } rates_v1[] = { {"day" ,XT_HASHLIMIT_SCALE *24 *60 *60 }, {"hour" ,XT_HASHLIMIT_SCALE *60 *60 }, {"min" ,XT_HASHLIMIT_SCALE *60 }, {"sec" ,XT_HASHLIMIT_SCALE } }; -static uint32_t print_rate (uint32_t period) +static const struct rates rates[] = { + {"day" , XT_HASHLIMIT_SCALE_v2*24 *60 *60 }, + {"hour" , XT_HASHLIMIT_SCALE_v2*60 *60 }, + {"min" , XT_HASHLIMIT_SCALE_v2*60 }, + {"sec" , XT_HASHLIMIT_SCALE_v2 } }; + +static uint32_t print_rate (uint32_t period,int revision) {unsigned int i; +const struct rates *_rates = (revision ==1 ) ? rates_v1 : rates; +uint64_t scale = (revision ==1 ) ?XT_HASHLIMIT_SCALE : XT_HASHLIMIT_SCALE_v2;if (period ==0 ) {printf (" %f" ,INFINITY );return 0 ; } -for (i =1 ; i <ARRAY_SIZE (rates_v1); ++i) -if (period > rates_v1[i].mult - || rates_v1[i].mult/period < rates_v1[i].mult%period) +for (i =1 ; i <ARRAY_SIZE (rates); ++i) +if (period > _rates[i].mult + || _rates[i].mult/period < _rates[i].mult%period)break ; -printf (" %u/%s" , rates_v1[i-1 ].mult / period, rates_v1[i-1 ].name); +printf (" %lu/%s" , _rates[i-1 ].mult / period, _rates[i-1 ].name);/* return in msec */ -return rates_v1[i-1 ].mult /XT_HASHLIMIT_SCALE *1000 ; +return _rates[i-1 ].mult / scale *1000 ; } static const struct {
@@ -462,7 +645,7 @@ static const struct { { "", 1 }, }; -static uint32_t print_bytes (uint32_t avg,uint32_t burst,const char *prefix) +static uint32_t print_bytes (uint64_t avg,uint64_t burst,const char *prefix) {unsigned int i;unsigned long long r;
@@ -523,7 +706,7 @@ static void hashlimit_print(const void *ip,uint32_t quantum;fputs (" limit: avg" , stdout); - quantum =print_rate (r->cfg.avg); + quantum =print_rate (r->cfg.avg,1 );printf (" burst %u" , r->cfg.burst);fputs (" mode" , stdout);print_mode (r->cfg.mode,'-' );
@@ -538,39 +721,39 @@ static void hashlimit_print(const void *ip, }static void -hashlimit_mt_print (const struct xt_hashlimit_mtinfo1 *info,unsigned int dmask) +hashlimit_mt_print (const struct hashlimit_cfg2 *cfg,unsigned int dmask,int revision) {uint32_t quantum; -if (info->cfg.mode &XT_HASHLIMIT_INVERT ) +if (cfg->mode &XT_HASHLIMIT_INVERT )fputs (" limit: above" , stdout);else fputs (" limit: up to" , stdout); -if (info->cfg.mode &XT_HASHLIMIT_BYTES ) { - quantum =print_bytes (info->cfg.avg, info->cfg.burst,"" ); +if (cfg->mode &XT_HASHLIMIT_BYTES ) { + quantum =print_bytes (cfg->avg, cfg->burst,"" ); }else { - quantum =print_rate (info->cfg.avg); -printf (" burst %u" , info->cfg.burst); + quantum =print_rate (cfg->avg, revision); +printf (" burst %llu" , cfg->burst); } -if (info->cfg.mode & (XT_HASHLIMIT_HASH_SIP |XT_HASHLIMIT_HASH_SPT | +if (cfg->mode & (XT_HASHLIMIT_HASH_SIP |XT_HASHLIMIT_HASH_SPT |XT_HASHLIMIT_HASH_DIP |XT_HASHLIMIT_HASH_DPT )) {fputs (" mode" , stdout); -print_mode (info->cfg.mode,'-' ); +print_mode (cfg->mode,'-' ); } -if (info->cfg.size !=0 ) -printf (" htable-size %u" , info->cfg.size); -if (info->cfg.max !=0 ) -printf (" htable-max %u" , info->cfg.max); -if (info->cfg.gc_interval !=XT_HASHLIMIT_GCINTERVAL ) -printf (" htable-gcinterval %u" , info->cfg.gc_interval); -if (info->cfg.expire != quantum) -printf (" htable-expire %u" , info->cfg.expire); - -if (info->cfg.srcmask != dmask) -printf (" srcmask %u" , info->cfg.srcmask); -if (info->cfg.dstmask != dmask) -printf (" dstmask %u" , info->cfg.dstmask); +if (cfg->size !=0 ) +printf (" htable-size %u" , cfg->size); +if (cfg->max !=0 ) +printf (" htable-max %u" , cfg->max); +if (cfg->gc_interval !=XT_HASHLIMIT_GCINTERVAL ) +printf (" htable-gcinterval %u" , cfg->gc_interval); +if (cfg->expire != quantum) +printf (" htable-expire %u" , cfg->expire); + +if (cfg->srcmask != dmask) +printf (" srcmask %u" , cfg->srcmask); +if (cfg->dstmask != dmask) +printf (" dstmask %u" , cfg->dstmask); } static void
@@ -578,8 +761,15 @@ hashlimit_mt4_print_v1(const void *ip, const struct xt_entry_match *match, int numeric) {const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data; +struct hashlimit_cfg2 cfg; +int ret; + + ret =cfg_copy (&cfg, (const void *)&info->cfg,1 ); -hashlimit_mt_print (info,32 ); +if (ret) +xtables_error (OTHER_PROBLEM ,"unknown revision" ); + +hashlimit_mt_print (&cfg,32 ,1 ); } static void
@@ -587,8 +777,33 @@ hashlimit_mt6_print_v1(const void *ip, const struct xt_entry_match *match, int numeric) {const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data; +struct hashlimit_cfg2 cfg; +int ret; + + ret =cfg_copy (&cfg, (const void *)&info->cfg,1 ); -hashlimit_mt_print (info,128 ); +if (ret) +xtables_error (OTHER_PROBLEM ,"unknown revision" ); + +hashlimit_mt_print (&cfg,128 ,1 ); +} + +static void +hashlimit_mt4_print (const void *ip,const struct xt_entry_match *match, +int numeric) +{ +const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data; + +hashlimit_mt_print (&info->cfg,32 ,2 ); +} + +static void +hashlimit_mt6_print (const void *ip,const struct xt_entry_match *match, +int numeric) +{ +const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data; + +hashlimit_mt_print (&info->cfg,128 ,2 ); }static void hashlimit_save (const void *ip,const struct xt_entry_match *match)
@@ -597,7 +812,7 @@ static void hashlimit_save(const void *ip, const struct xt_entry_match *match)uint32_t quantum;fputs (" --hashlimit" , stdout); - quantum =print_rate (r->cfg.avg); + quantum =print_rate (r->cfg.avg,1 );printf (" --hashlimit-burst %u" , r->cfg.burst);fputs (" --hashlimit-mode" , stdout);
@@ -616,59 +831,89 @@ static void hashlimit_save(const void *ip, const struct xt_entry_match *match) }static void -hashlimit_mt_save (const struct xt_hashlimit_mtinfo1 *info,unsigned int dmask) +hashlimit_mt_save (const struct hashlimit_cfg2 *cfg,const char * name,unsigned int dmask,int revision) {uint32_t quantum; -if (info->cfg.mode &XT_HASHLIMIT_INVERT ) +if (cfg->mode &XT_HASHLIMIT_INVERT )fputs (" --hashlimit-above" , stdout);else fputs (" --hashlimit-upto" , stdout); -if (info->cfg.mode &XT_HASHLIMIT_BYTES ) { - quantum =print_bytes (info->cfg.avg, info->cfg.burst,"--hashlimit-" ); +if (cfg->mode &XT_HASHLIMIT_BYTES ) { + quantum =print_bytes (cfg->avg, cfg->burst,"--hashlimit-" ); }else { - quantum =print_rate (info->cfg.avg); -printf (" --hashlimit-burst %u" , info->cfg.burst); + quantum =print_rate (cfg->avg, revision); +printf (" --hashlimit-burst %llu" , cfg->burst); } -if (info->cfg.mode & (XT_HASHLIMIT_HASH_SIP |XT_HASHLIMIT_HASH_SPT | +if (cfg->mode & (XT_HASHLIMIT_HASH_SIP |XT_HASHLIMIT_HASH_SPT |XT_HASHLIMIT_HASH_DIP |XT_HASHLIMIT_HASH_DPT )) {fputs (" --hashlimit-mode" , stdout); -print_mode (info->cfg.mode,',' ); +print_mode (cfg->mode,',' ); } -printf (" --hashlimit-name %s" , info->name); - -if (info->cfg.size !=0 ) -printf (" --hashlimit-htable-size %u" , info->cfg.size); -if (info->cfg.max !=0 ) -printf (" --hashlimit-htable-max %u" , info->cfg.max); -if (info->cfg.gc_interval !=XT_HASHLIMIT_GCINTERVAL ) -printf (" --hashlimit-htable-gcinterval %u" , info->cfg.gc_interval); -if (info->cfg.expire != quantum) -printf (" --hashlimit-htable-expire %u" , info->cfg.expire); - -if (info->cfg.srcmask != dmask) -printf (" --hashlimit-srcmask %u" , info->cfg.srcmask); -if (info->cfg.dstmask != dmask) -printf (" --hashlimit-dstmask %u" , info->cfg.dstmask); +printf (" --hashlimit-name %s" , name); + +if (cfg->size !=0 ) +printf (" --hashlimit-htable-size %u" , cfg->size); +if (cfg->max !=0 ) +printf (" --hashlimit-htable-max %u" , cfg->max); +if (cfg->gc_interval !=XT_HASHLIMIT_GCINTERVAL ) +printf (" --hashlimit-htable-gcinterval %u" , cfg->gc_interval); +if (cfg->expire != quantum) +printf (" --hashlimit-htable-expire %u" , cfg->expire); + +if (cfg->srcmask != dmask) +printf (" --hashlimit-srcmask %u" , cfg->srcmask); +if (cfg->dstmask != dmask) +printf (" --hashlimit-dstmask %u" , cfg->dstmask); }static void hashlimit_mt4_save_v1 (const void *ip,const struct xt_entry_match *match) {const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data; +struct hashlimit_cfg2 cfg; +int ret; + + ret =cfg_copy (&cfg, (const void *)&info->cfg,1 ); -hashlimit_mt_save (info,32 ); +if (ret) +xtables_error (OTHER_PROBLEM ,"unknown revision" ); + +hashlimit_mt_save (&cfg, info->name,32 ,1 ); }static void hashlimit_mt6_save_v1 (const void *ip,const struct xt_entry_match *match) {const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data; +struct hashlimit_cfg2 cfg; +int ret; + + ret =cfg_copy (&cfg, (const void *)&info->cfg,1 ); + +if (ret) +xtables_error (OTHER_PROBLEM ,"unknown revision" ); + +hashlimit_mt_save (&cfg, info->name,128 ,1 ); +} -hashlimit_mt_save (info,128 ); +static void +hashlimit_mt4_save (const void *ip,const struct xt_entry_match *match) +{ +const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data; + +hashlimit_mt_save (&info->cfg, info->name,32 ,2 ); +} + +static void +hashlimit_mt6_save (const void *ip,const struct xt_entry_match *match) +{ +const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data; + +hashlimit_mt_save (&info->cfg, info->name,128 ,2 ); }static struct xtables_match hashlimit_mt_reg[] = {
@@ -720,6 +965,38 @@ static struct xtables_match hashlimit_mt_reg[] = { .x6_options = hashlimit_mt_opts_v1, .udata_size = sizeof(struct hashlimit_mt_udata), }, + { + .version = XTABLES_VERSION, + .name = "hashlimit", + .revision = 2, + .family = NFPROTO_IPV4, + .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo2)), + .userspacesize = offsetof(struct xt_hashlimit_mtinfo2, hinfo), + .help = hashlimit_mt_help, + .init = hashlimit_mt4_init, + .x6_parse = hashlimit_mt_parse, + .x6_fcheck = hashlimit_mt_check, + .print = hashlimit_mt4_print, + .save = hashlimit_mt4_save, + .x6_options = hashlimit_mt_opts, + .udata_size = sizeof(struct hashlimit_mt_udata), + }, + { + .version = XTABLES_VERSION, + .name = "hashlimit", + .revision = 2, + .family = NFPROTO_IPV6, + .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo2)), + .userspacesize = offsetof(struct xt_hashlimit_mtinfo2, hinfo), + .help = hashlimit_mt_help, + .init = hashlimit_mt6_init, + .x6_parse = hashlimit_mt_parse, + .x6_fcheck = hashlimit_mt_check, + .print = hashlimit_mt6_print, + .save = hashlimit_mt6_save, + .x6_options = hashlimit_mt_opts, + .udata_size = sizeof(struct hashlimit_mt_udata), + }, };void _init (void )
extensions/libxt_hashlimit.t +2 -0
@@ -1,10 +1,12 @@ :INPUT,FORWARD,OUTPUT -m hashlimit --hashlimit-above 1/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK +-m hashlimit --hashlimit-above 1000000/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK -m hashlimit --hashlimit-above 1/min --hashlimit-burst 5 --hashlimit-name mini1;=;OK -m hashlimit --hashlimit-above 1/hour --hashlimit-burst 5 --hashlimit-name mini1;=;OK # kernel says "xt_hashlimit: overflow, try lower: 864000000/5" -m hashlimit --hashlimit-above 1/day --hashlimit-burst 5 --hashlimit-name mini1;;FAIL -m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK +-m hashlimit --hashlimit-upto 1000000/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK -m hashlimit --hashlimit-upto 1/min --hashlimit-burst 5 --hashlimit-name mini1;=;OK -m hashlimit --hashlimit-upto 1/hour --hashlimit-burst 5 --hashlimit-name mini1;=;OK # kernel says "xt_hashlimit: overflow, try lower: 864000000/5"
include/linux/netfilter/xt_hashlimit.h +25 -1
@@ -5,8 +5,10 @@/* timings are in milliseconds. */ #define XT_HASHLIMIT_SCALE 10000 +#define XT_HASHLIMIT_SCALE_v2 1000000llu/* 1/10,000 sec period => max of 10,000/sec. Min rate is then 429490 -seconds, or one packet every 59 hours. */ +* seconds, or one packet every 59 hours. +*/ /* packet length accounting is done in 16-byte steps */ #define XT_HASHLIMIT_BYTE_SHIFT 4
@@ -61,6 +63,20 @@ struct hashlimit_cfg1 {__u8 srcmask, dstmask; }; +struct hashlimit_cfg2 { +__u64 avg;/* Average secs between packets * scale */ +__u64 burst;/* Period multiplier for upper limit. */ +__u32 mode;/* bitmask of XT_HASHLIMIT_HASH_* */ + +/* user specified */ +__u32 size;/* how many buckets */ +__u32 max;/* max number of entries */ +__u32 gc_interval;/* gc interval */ +__u32 expire;/* when do entries expire? */ + +__u8 srcmask, dstmask; +}; +struct xt_hashlimit_mtinfo1 {char name[IFNAMSIZ ];struct hashlimit_cfg1 cfg;
@@ -69,4 +85,12 @@ struct xt_hashlimit_mtinfo1 { struct xt_hashlimit_htable *hinfo __attribute__((aligned(8))); }; +struct xt_hashlimit_mtinfo2 { +char name[NAME_MAX ]; +struct hashlimit_cfg2 cfg; + +/* Used internally by the kernel */ +struct xt_hashlimit_htable *hinfo __attribute__((aligned (8 ))); +}; +#endif /*_XT_HASHLIMIT_H*/
Signature · 1 line
1.9.1
Pablo Neira Ayuso
maintainerQuoted 10 lines · Vishwanath Pai
libxt_hashlimit: Create revision 2 ofxt_hashlimitto support higher pps ratesCreate a new revision for the hashlimit iptables extension module. Rev 2 will support higher pps of upto 1 million, Version 1 supports only 10k.
To support this we have to increase the size of the variables avg and burst in
hashlimit_cfgto 64-bit. Create two new structshashlimit_cfg2andxt_hashlimit_mtinfo2and also create newer versions of all the functions for match, checkentry and destory.
Also applied, thanks.