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