libxt_RATEEST.c revision 32b8e61e4e5bd405d9ad07bf9468498dfbb19f9e
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 */ 14static struct xt_rateest_target_info *RATEEST_info; 15static unsigned int interval; 16static unsigned int ewma_log; 17 18static void 19RATEEST_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 28enum RATEEST_options { 29 RATEEST_OPT_NAME, 30 RATEEST_OPT_INTERVAL, 31 RATEEST_OPT_EWMALOG, 32}; 33 34static 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 44static int 45RATEEST_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 72static void 73RATEEST_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 85static void 86RATEEST_init(struct xt_entry_target *target) 87{ 88 interval = 0; 89 ewma_log = 0; 90} 91 92static int 93RATEEST_parse(int c, char **argv, int invert, unsigned int *flags, 94 const void *entry, struct xt_entry_target **target) 95{ 96 struct xt_rateest_target_info *info = (void *)(*target)->data; 97 98 RATEEST_info = info; 99 100 switch (c) { 101 case RATEEST_OPT_NAME: 102 if (*flags & (1 << c)) 103 xtables_error(PARAMETER_PROBLEM, 104 "RATEEST: can't specify --rateest-name twice"); 105 *flags |= 1 << c; 106 107 strncpy(info->name, optarg, sizeof(info->name) - 1); 108 break; 109 110 case RATEEST_OPT_INTERVAL: 111 if (*flags & (1 << c)) 112 xtables_error(PARAMETER_PROBLEM, 113 "RATEEST: can't specify --rateest-interval twice"); 114 *flags |= 1 << c; 115 116 if (RATEEST_get_time(&interval, optarg) < 0) 117 xtables_error(PARAMETER_PROBLEM, 118 "RATEEST: bad interval value `%s'", optarg); 119 120 break; 121 122 case RATEEST_OPT_EWMALOG: 123 if (*flags & (1 << c)) 124 xtables_error(PARAMETER_PROBLEM, 125 "RATEEST: can't specify --rateest-ewmalog twice"); 126 *flags |= 1 << c; 127 128 if (RATEEST_get_time(&ewma_log, optarg) < 0) 129 xtables_error(PARAMETER_PROBLEM, 130 "RATEEST: bad ewmalog value `%s'", optarg); 131 132 break; 133 134 default: 135 return 0; 136 } 137 138 return 1; 139} 140 141static void 142RATEEST_final_check(unsigned int flags) 143{ 144 struct xt_rateest_target_info *info = RATEEST_info; 145 146 if (!(flags & (1 << RATEEST_OPT_NAME))) 147 xtables_error(PARAMETER_PROBLEM, "RATEEST: no name specified"); 148 if (!(flags & (1 << RATEEST_OPT_INTERVAL))) 149 xtables_error(PARAMETER_PROBLEM, "RATEEST: no interval specified"); 150 if (!(flags & (1 << RATEEST_OPT_EWMALOG))) 151 xtables_error(PARAMETER_PROBLEM, "RATEEST: no ewmalog specified"); 152 153 for (info->interval = 0; info->interval <= 5; info->interval++) { 154 if (interval <= (1 << info->interval) * (TIME_UNITS_PER_SEC / 4)) 155 break; 156 } 157 158 if (info->interval > 5) 159 xtables_error(PARAMETER_PROBLEM, 160 "RATEEST: interval value is too large"); 161 info->interval -= 2; 162 163 for (info->ewma_log = 1; info->ewma_log < 32; info->ewma_log++) { 164 double w = 1.0 - 1.0 / (1 << info->ewma_log); 165 if (interval / (-log(w)) > ewma_log) 166 break; 167 } 168 info->ewma_log--; 169 170 if (info->ewma_log == 0 || info->ewma_log >= 31) 171 xtables_error(PARAMETER_PROBLEM, 172 "RATEEST: ewmalog value is out of range"); 173} 174 175static void 176__RATEEST_print(const struct xt_entry_target *target, const char *prefix) 177{ 178 const struct xt_rateest_target_info *info = (const void *)target->data; 179 unsigned int local_interval; 180 unsigned int local_ewma_log; 181 182 local_interval = (TIME_UNITS_PER_SEC << (info->interval + 2)) / 4; 183 local_ewma_log = local_interval * (1 << (info->ewma_log)); 184 185 printf("%sname %s ", prefix, info->name); 186 printf("%sinterval ", prefix); 187 RATEEST_print_time(local_interval); 188 printf("%sewmalog ", prefix); 189 RATEEST_print_time(local_ewma_log); 190} 191 192static void 193RATEEST_print(const void *ip, const struct xt_entry_target *target, 194 int numeric) 195{ 196 __RATEEST_print(target, ""); 197} 198 199static void 200RATEEST_save(const void *ip, const struct xt_entry_target *target) 201{ 202 __RATEEST_print(target, "--rateest-"); 203} 204 205static struct xtables_target rateest_tg_reg = { 206 .family = NFPROTO_UNSPEC, 207 .name = "RATEEST", 208 .version = XTABLES_VERSION, 209 .size = XT_ALIGN(sizeof(struct xt_rateest_target_info)), 210 .userspacesize = XT_ALIGN(sizeof(struct xt_rateest_target_info)), 211 .help = RATEEST_help, 212 .init = RATEEST_init, 213 .parse = RATEEST_parse, 214 .final_check = RATEEST_final_check, 215 .print = RATEEST_print, 216 .save = RATEEST_save, 217 .extra_opts = RATEEST_opts, 218}; 219 220void _init(void) 221{ 222 xtables_register_target(&rateest_tg_reg); 223} 224