Home | History | Annotate | Download | only in extensions
      1 #include <stdbool.h>
      2 #include <stdio.h>
      3 #include <string.h>
      4 #include <stdlib.h>
      5 #include <stddef.h>
      6 #include <getopt.h>
      7 #include <math.h>
      8 
      9 #include <xtables.h>
     10 #include <linux/netfilter/x_tables.h>
     11 #include <linux/netfilter/xt_RATEEST.h>
     12 
     13 /* hack to pass raw values to final_check */
     14 static struct xt_rateest_target_info *RATEEST_info;
     15 static unsigned int interval;
     16 static unsigned int ewma_log;
     17 
     18 static void
     19 RATEEST_help(void)
     20 {
     21 	printf(
     22 "RATEEST target options:\n"
     23 "  --rateest-name name		Rate estimator name\n"
     24 "  --rateest-interval sec	Rate measurement interval in seconds\n"
     25 "  --rateest-ewmalog value	Rate measurement averaging time constant\n");
     26 }
     27 
     28 enum RATEEST_options {
     29 	RATEEST_OPT_NAME,
     30 	RATEEST_OPT_INTERVAL,
     31 	RATEEST_OPT_EWMALOG,
     32 };
     33 
     34 static const struct option RATEEST_opts[] = {
     35 	{.name = "rateest-name",     .has_arg = true, .val = RATEEST_OPT_NAME},
     36 	{.name = "rateest-interval", .has_arg = true, .val = RATEEST_OPT_INTERVAL},
     37 	{.name = "rateest-ewmalog",  .has_arg = true, .val = RATEEST_OPT_EWMALOG},
     38 	XT_GETOPT_TABLEEND,
     39 };
     40 
     41 /* Copied from iproute */
     42 #define TIME_UNITS_PER_SEC	1000000
     43 
     44 static int
     45 RATEEST_get_time(unsigned int *time, const char *str)
     46 {
     47 	double t;
     48 	char *p;
     49 
     50 	t = strtod(str, &p);
     51 	if (p == str)
     52 		return -1;
     53 
     54 	if (*p) {
     55 		if (strcasecmp(p, "s") == 0 || strcasecmp(p, "sec")==0 ||
     56 		    strcasecmp(p, "secs")==0)
     57 			t *= TIME_UNITS_PER_SEC;
     58 		else if (strcasecmp(p, "ms") == 0 || strcasecmp(p, "msec")==0 ||
     59 			 strcasecmp(p, "msecs") == 0)
     60 			t *= TIME_UNITS_PER_SEC/1000;
     61 		else if (strcasecmp(p, "us") == 0 || strcasecmp(p, "usec")==0 ||
     62 			 strcasecmp(p, "usecs") == 0)
     63 			t *= TIME_UNITS_PER_SEC/1000000;
     64 		else
     65 			return -1;
     66 	}
     67 
     68 	*time = t;
     69 	return 0;
     70 }
     71 
     72 static void
     73 RATEEST_print_time(unsigned int time)
     74 {
     75 	double tmp = time;
     76 
     77 	if (tmp >= TIME_UNITS_PER_SEC)
     78 		printf(" %.1fs", tmp / TIME_UNITS_PER_SEC);
     79 	else if (tmp >= TIME_UNITS_PER_SEC/1000)
     80 		printf(" %.1fms", tmp / (TIME_UNITS_PER_SEC / 1000));
     81 	else
     82 		printf(" %uus", time);
     83 }
     84 
     85 static int
     86 RATEEST_parse(int c, char **argv, int invert, unsigned int *flags,
     87 	      const void *entry, struct xt_entry_target **target)
     88 {
     89 	struct xt_rateest_target_info *info = (void *)(*target)->data;
     90 
     91 	RATEEST_info = info;
     92 
     93 	switch (c) {
     94 	case RATEEST_OPT_NAME:
     95 		if (*flags & (1 << c))
     96 			xtables_error(PARAMETER_PROBLEM,
     97 				   "RATEEST: can't specify --rateest-name twice");
     98 		*flags |= 1 << c;
     99 
    100 		strncpy(info->name, optarg, sizeof(info->name) - 1);
    101 		break;
    102 
    103 	case RATEEST_OPT_INTERVAL:
    104 		if (*flags & (1 << c))
    105 			xtables_error(PARAMETER_PROBLEM,
    106 				   "RATEEST: can't specify --rateest-interval twice");
    107 		*flags |= 1 << c;
    108 
    109 		if (RATEEST_get_time(&interval, optarg) < 0)
    110 			xtables_error(PARAMETER_PROBLEM,
    111 				   "RATEEST: bad interval value `%s'", optarg);
    112 
    113 		break;
    114 
    115 	case RATEEST_OPT_EWMALOG:
    116 		if (*flags & (1 << c))
    117 			xtables_error(PARAMETER_PROBLEM,
    118 				   "RATEEST: can't specify --rateest-ewmalog twice");
    119 		*flags |= 1 << c;
    120 
    121 		if (RATEEST_get_time(&ewma_log, optarg) < 0)
    122 			xtables_error(PARAMETER_PROBLEM,
    123 				   "RATEEST: bad ewmalog value `%s'", optarg);
    124 
    125 		break;
    126 	}
    127 
    128 	return 1;
    129 }
    130 
    131 static void
    132 RATEEST_final_check(unsigned int flags)
    133 {
    134 	struct xt_rateest_target_info *info = RATEEST_info;
    135 
    136 	if (!(flags & (1 << RATEEST_OPT_NAME)))
    137 		xtables_error(PARAMETER_PROBLEM, "RATEEST: no name specified");
    138 	if (!(flags & (1 << RATEEST_OPT_INTERVAL)))
    139 		xtables_error(PARAMETER_PROBLEM, "RATEEST: no interval specified");
    140 	if (!(flags & (1 << RATEEST_OPT_EWMALOG)))
    141 		xtables_error(PARAMETER_PROBLEM, "RATEEST: no ewmalog specified");
    142 
    143 	for (info->interval = 0; info->interval <= 5; info->interval++) {
    144 		if (interval <= (1 << info->interval) * (TIME_UNITS_PER_SEC / 4))
    145 			break;
    146 	}
    147 
    148 	if (info->interval > 5)
    149 		xtables_error(PARAMETER_PROBLEM,
    150 			   "RATEEST: interval value is too large");
    151 	info->interval -= 2;
    152 
    153 	for (info->ewma_log = 1; info->ewma_log < 32; info->ewma_log++) {
    154 		double w = 1.0 - 1.0 / (1 << info->ewma_log);
    155 		if (interval / (-log(w)) > ewma_log)
    156 			break;
    157 	}
    158 	info->ewma_log--;
    159 
    160 	if (info->ewma_log == 0 || info->ewma_log >= 31)
    161 		xtables_error(PARAMETER_PROBLEM,
    162 			   "RATEEST: ewmalog value is out of range");
    163 }
    164 
    165 static void
    166 __RATEEST_print(const struct xt_entry_target *target, const char *prefix)
    167 {
    168 	const struct xt_rateest_target_info *info = (const void *)target->data;
    169 	unsigned int local_interval;
    170 	unsigned int local_ewma_log;
    171 
    172 	local_interval = (TIME_UNITS_PER_SEC << (info->interval + 2)) / 4;
    173 	local_ewma_log = local_interval * (1 << (info->ewma_log));
    174 
    175 	printf(" %sname %s", prefix, info->name);
    176 	printf(" %sinterval", prefix);
    177 	RATEEST_print_time(local_interval);
    178 	printf(" %sewmalog", prefix);
    179 	RATEEST_print_time(local_ewma_log);
    180 }
    181 
    182 static void
    183 RATEEST_print(const void *ip, const struct xt_entry_target *target,
    184 	      int numeric)
    185 {
    186 	__RATEEST_print(target, "");
    187 }
    188 
    189 static void
    190 RATEEST_save(const void *ip, const struct xt_entry_target *target)
    191 {
    192 	__RATEEST_print(target, "--rateest-");
    193 }
    194 
    195 static struct xtables_target rateest_tg_reg = {
    196 	.family		= NFPROTO_UNSPEC,
    197 	.name		= "RATEEST",
    198 	.version	= XTABLES_VERSION,
    199 	.size		= XT_ALIGN(sizeof(struct xt_rateest_target_info)),
    200 	.userspacesize	= XT_ALIGN(sizeof(struct xt_rateest_target_info)),
    201 	.help		= RATEEST_help,
    202 	.parse		= RATEEST_parse,
    203 	.final_check	= RATEEST_final_check,
    204 	.print		= RATEEST_print,
    205 	.save		= RATEEST_save,
    206 	.extra_opts	= RATEEST_opts,
    207 };
    208 
    209 void _init(void)
    210 {
    211 	xtables_register_target(&rateest_tg_reg);
    212 }
    213