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