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