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