1#include <stdio.h> 2#include <string.h> 3#include <stdlib.h> 4#include <math.h> 5 6#include <xtables.h> 7#include <linux/netfilter/x_tables.h> 8#include <linux/netfilter/xt_RATEEST.h> 9 10struct rateest_tg_udata { 11 unsigned int interval; 12 unsigned int ewma_log; 13}; 14 15static void 16RATEEST_help(void) 17{ 18 printf( 19"RATEEST target options:\n" 20" --rateest-name name Rate estimator name\n" 21" --rateest-interval sec Rate measurement interval in seconds\n" 22" --rateest-ewmalog value Rate measurement averaging time constant\n"); 23} 24 25enum { 26 O_NAME = 0, 27 O_INTERVAL, 28 O_EWMALOG, 29}; 30 31#define s struct xt_rateest_target_info 32static const struct xt_option_entry RATEEST_opts[] = { 33 {.name = "rateest-name", .id = O_NAME, .type = XTTYPE_STRING, 34 .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name)}, 35 {.name = "rateest-interval", .id = O_INTERVAL, .type = XTTYPE_STRING, 36 .flags = XTOPT_MAND}, 37 {.name = "rateest-ewmalog", .id = O_EWMALOG, .type = XTTYPE_STRING, 38 .flags = XTOPT_MAND}, 39 XTOPT_TABLEEND, 40}; 41#undef s 42 43/* Copied from iproute */ 44#define TIME_UNITS_PER_SEC 1000000 45 46static int 47RATEEST_get_time(unsigned int *time, const char *str) 48{ 49 double t; 50 char *p; 51 52 t = strtod(str, &p); 53 if (p == str) 54 return -1; 55 56 if (*p) { 57 if (strcasecmp(p, "s") == 0 || strcasecmp(p, "sec")==0 || 58 strcasecmp(p, "secs")==0) 59 t *= TIME_UNITS_PER_SEC; 60 else if (strcasecmp(p, "ms") == 0 || strcasecmp(p, "msec")==0 || 61 strcasecmp(p, "msecs") == 0) 62 t *= TIME_UNITS_PER_SEC/1000; 63 else if (strcasecmp(p, "us") == 0 || strcasecmp(p, "usec")==0 || 64 strcasecmp(p, "usecs") == 0) 65 t *= TIME_UNITS_PER_SEC/1000000; 66 else 67 return -1; 68 } 69 70 *time = t; 71 return 0; 72} 73 74static void 75RATEEST_print_time(unsigned int time) 76{ 77 double tmp = time; 78 79 if (tmp >= TIME_UNITS_PER_SEC) 80 printf(" %.1fs", tmp / TIME_UNITS_PER_SEC); 81 else if (tmp >= TIME_UNITS_PER_SEC/1000) 82 printf(" %.1fms", tmp / (TIME_UNITS_PER_SEC / 1000)); 83 else 84 printf(" %uus", time); 85} 86 87static void RATEEST_parse(struct xt_option_call *cb) 88{ 89 struct rateest_tg_udata *udata = cb->udata; 90 91 xtables_option_parse(cb); 92 switch (cb->entry->id) { 93 case O_INTERVAL: 94 if (RATEEST_get_time(&udata->interval, cb->arg) < 0) 95 xtables_error(PARAMETER_PROBLEM, 96 "RATEEST: bad interval value \"%s\"", 97 cb->arg); 98 break; 99 case O_EWMALOG: 100 if (RATEEST_get_time(&udata->ewma_log, cb->arg) < 0) 101 xtables_error(PARAMETER_PROBLEM, 102 "RATEEST: bad ewmalog value \"%s\"", 103 cb->arg); 104 break; 105 } 106} 107 108static void RATEEST_final_check(struct xt_fcheck_call *cb) 109{ 110 struct xt_rateest_target_info *info = cb->data; 111 struct rateest_tg_udata *udata = cb->udata; 112 113 for (info->interval = 0; info->interval <= 5; info->interval++) { 114 if (udata->interval <= (1 << info->interval) * (TIME_UNITS_PER_SEC / 4)) 115 break; 116 } 117 118 if (info->interval > 5) 119 xtables_error(PARAMETER_PROBLEM, 120 "RATEEST: interval value is too large"); 121 info->interval -= 2; 122 123 for (info->ewma_log = 1; info->ewma_log < 32; info->ewma_log++) { 124 double w = 1.0 - 1.0 / (1 << info->ewma_log); 125 if (udata->interval / (-log(w)) > udata->ewma_log) 126 break; 127 } 128 info->ewma_log--; 129 130 if (info->ewma_log == 0 || info->ewma_log >= 31) 131 xtables_error(PARAMETER_PROBLEM, 132 "RATEEST: ewmalog value is out of range"); 133} 134 135static void 136__RATEEST_print(const struct xt_entry_target *target, const char *prefix) 137{ 138 const struct xt_rateest_target_info *info = (const void *)target->data; 139 unsigned int local_interval; 140 unsigned int local_ewma_log; 141 142 local_interval = (TIME_UNITS_PER_SEC << (info->interval + 2)) / 4; 143 local_ewma_log = local_interval * (1 << (info->ewma_log)); 144 145 printf(" %sname %s", prefix, info->name); 146 printf(" %sinterval", prefix); 147 RATEEST_print_time(local_interval); 148 printf(" %sewmalog", prefix); 149 RATEEST_print_time(local_ewma_log); 150} 151 152static void 153RATEEST_print(const void *ip, const struct xt_entry_target *target, 154 int numeric) 155{ 156 __RATEEST_print(target, ""); 157} 158 159static void 160RATEEST_save(const void *ip, const struct xt_entry_target *target) 161{ 162 __RATEEST_print(target, "--rateest-"); 163} 164 165static struct xtables_target rateest_tg_reg = { 166 .family = NFPROTO_UNSPEC, 167 .name = "RATEEST", 168 .version = XTABLES_VERSION, 169 .size = XT_ALIGN(sizeof(struct xt_rateest_target_info)), 170 .userspacesize = offsetof(struct xt_rateest_target_info, est), 171 .help = RATEEST_help, 172 .x6_parse = RATEEST_parse, 173 .x6_fcheck = RATEEST_final_check, 174 .print = RATEEST_print, 175 .save = RATEEST_save, 176 .x6_options = RATEEST_opts, 177 .udata_size = sizeof(struct rateest_tg_udata), 178}; 179 180void _init(void) 181{ 182 xtables_register_target(&rateest_tg_reg); 183} 184