From 3602c72baeee6a3c5884c20c92a5f37adbccd095 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Patrick McHardy/emailAddress=kaber@trash.net" Date: Tue, 15 Jan 2008 17:25:39 +0000 Subject: Add RATEEST target extension Signed-off-by: Patrick McHardy --- Makefile | 4 +- extensions/Makefile | 2 +- extensions/libxt_RATEEST.c | 240 +++++++++++++++++++++++++++++++++++ include/linux/netfilter/xt_RATEEST.h | 11 ++ 4 files changed, 254 insertions(+), 3 deletions(-) create mode 100644 extensions/libxt_RATEEST.c create mode 100644 include/linux/netfilter/xt_RATEEST.h diff --git a/Makefile b/Makefile index a7dc929..516cead 100644 --- a/Makefile +++ b/Makefile @@ -80,7 +80,7 @@ SH_CFLAGS:=$(CFLAGS) -fPIC STATIC_LIBS = STATIC6_LIBS = LDFLAGS = -rdynamic -LDLIBS = -ldl +LDLIBS = -ldl -lm ifeq ($(DO_SELINUX), 1) LDLIBS += -lselinux endif @@ -89,7 +89,7 @@ DEPFILES = $(EXT_OBJS:%.o=%.d) STATIC_LIBS = extensions/libext.a STATIC6_LIBS = extensions/libext6.a LDFLAGS = -static -LDLIBS = +LDLIBS = -lm ifeq ($(DO_SELINUX), 1) LDLIBS += -lselinux endif diff --git a/extensions/Makefile b/extensions/Makefile index 0750415..dcb6c5d 100644 --- a/extensions/Makefile +++ b/extensions/Makefile @@ -7,7 +7,7 @@ # PF_EXT_SLIB:=ah addrtype conntrack ecn icmp iprange owner policy realm recent tos ttl unclean CLUSTERIP DNAT ECN LOG MASQUERADE MIRROR NETMAP REDIRECT REJECT SAME SNAT TOS TTL ULOG PF6_EXT_SLIB:=ah dst eui64 frag hbh hl icmp6 ipv6header mh owner policy rt HL LOG REJECT -PFX_EXT_SLIB:=connbytes connmark connlimit comment dccp dscp esp hashlimit helper length limit mac mark multiport physdev pkttype quota sctp state statistic standard string tcp tcpmss time u32 udp CLASSIFY CONNMARK DSCP MARK NFLOG NFQUEUE NOTRACK TCPMSS TRACE +PFX_EXT_SLIB:=connbytes connmark connlimit comment dccp dscp esp hashlimit helper length limit mac mark multiport physdev pkttype quota sctp state statistic standard string tcp tcpmss time u32 udp CLASSIFY CONNMARK DSCP MARK NFLOG NFQUEUE NOTRACK RATEEST TCPMSS TRACE PF_EXT_SELINUX_SLIB:= PF6_EXT_SELINUX_SLIB:= diff --git a/extensions/libxt_RATEEST.c b/extensions/libxt_RATEEST.c new file mode 100644 index 0000000..8445cdf --- /dev/null +++ b/extensions/libxt_RATEEST.c @@ -0,0 +1,240 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* hack to pass raw values to final_check */ +static struct xt_rateest_target_info *RATEEST_info; +static unsigned int interval; +static unsigned int ewma_log; + +static void +RATEEST_help(void) +{ + printf( +"RATEST target v%s options:\n" +" --rateest-name name Rate estimator name\n" +" --rateest-interval sec Rate measurement interval in seconds\n" +" --rateest-ewmalog value Rate measurement averaging time constant\n" +"\n", + IPTABLES_VERSION); +} + +enum RATEEST_options { + RATEEST_OPT_NAME, + RATEEST_OPT_INTERVAL, + RATEEST_OPT_EWMALOG, +}; + +static const struct option RATEEST_opts[] = { + { "rateest-name", 1, NULL, RATEEST_OPT_NAME }, + { "rateest-interval", 1, NULL, RATEEST_OPT_INTERVAL }, + { "rateest-ewmalog", 1, NULL, RATEEST_OPT_EWMALOG }, + { }, +}; + +/* Copied from iproute */ +#define TIME_UNITS_PER_SEC 1000000 + +static int +RATEEST_get_time(unsigned int *time, const char *str) +{ + double t; + char *p; + + t = strtod(str, &p); + if (p == str) + return -1; + + if (*p) { + if (strcasecmp(p, "s") == 0 || strcasecmp(p, "sec")==0 || + strcasecmp(p, "secs")==0) + t *= TIME_UNITS_PER_SEC; + else if (strcasecmp(p, "ms") == 0 || strcasecmp(p, "msec")==0 || + strcasecmp(p, "msecs") == 0) + t *= TIME_UNITS_PER_SEC/1000; + else if (strcasecmp(p, "us") == 0 || strcasecmp(p, "usec")==0 || + strcasecmp(p, "usecs") == 0) + t *= TIME_UNITS_PER_SEC/1000000; + else + return -1; + } + + *time = t; + return 0; +} + +static void +RATEEST_print_time(unsigned int time) +{ + double tmp = time; + + if (tmp >= TIME_UNITS_PER_SEC) + printf("%.1fs ", tmp/TIME_UNITS_PER_SEC); + else if (tmp >= TIME_UNITS_PER_SEC/1000) + printf("%.1fms ", tmp/(TIME_UNITS_PER_SEC/1000)); + else + printf("%uus ", time); +} + +static void +RATEEST_init(struct xt_entry_target *target) +{ + interval = 0; + ewma_log = 0; +} + +static int +RATEEST_parse(int c, char **argv, int invert, unsigned int *flags, + const void *entry, struct xt_entry_target **target) +{ + struct xt_rateest_target_info *info = (void *)(*target)->data; + + RATEEST_info = info; + + switch (c) { + case RATEEST_OPT_NAME: + if (*flags & (1 << c)) + exit_error(PARAMETER_PROBLEM, + "RATEEST: can't specify --rateest-name twice"); + *flags |= 1 << c; + + strncpy(info->name, optarg, sizeof(info->name) - 1); + break; + + case RATEEST_OPT_INTERVAL: + if (*flags & (1 << c)) + exit_error(PARAMETER_PROBLEM, + "RATEEST: can't specify --rateest-interval twice"); + *flags |= 1 << c; + + if (RATEEST_get_time(&interval, optarg) < 0) + exit_error(PARAMETER_PROBLEM, + "RATEEST: bad interval value `%s'", optarg); + + break; + + case RATEEST_OPT_EWMALOG: + if (*flags & (1 << c)) + exit_error(PARAMETER_PROBLEM, + "RATEEST: can't specify --rateest-ewmalog twice"); + *flags |= 1 << c; + + if (RATEEST_get_time(&ewma_log, optarg) < 0) + exit_error(PARAMETER_PROBLEM, + "RATEEST: bad ewmalog value `%s'", optarg); + + break; + + default: + return 0; + } + + return 1; +} + +static void +RATEEST_final_check(unsigned int flags) +{ + struct xt_rateest_target_info *info = RATEEST_info; + + if (!(flags & (1 << RATEEST_OPT_NAME))) + exit_error(PARAMETER_PROBLEM, "RATEEST: no name specified"); + if (!(flags & (1 << RATEEST_OPT_INTERVAL))) + exit_error(PARAMETER_PROBLEM, "RATEEST: no interval specified"); + if (!(flags & (1 << RATEEST_OPT_EWMALOG))) + exit_error(PARAMETER_PROBLEM, "RATEEST: no ewmalog specified"); + + for (info->interval = 0; info->interval <= 5; info->interval++) { + if (interval <= (1 << info->interval) * (TIME_UNITS_PER_SEC / 4)) + break; + } + + if (info->interval > 5) + exit_error(PARAMETER_PROBLEM, + "RATEEST: interval value is too large"); + info->interval -= 2; + + for (info->ewma_log = 1; info->ewma_log < 32; info->ewma_log++) { + double w = 1.0 - 1.0 / (1 << info->ewma_log); + if (interval / (-log(w)) > ewma_log) + break; + } + info->ewma_log--; + + if (info->ewma_log == 0 || info->ewma_log >= 31) + exit_error(PARAMETER_PROBLEM, + "RATEEST: ewmalog value is out of range"); +} + +static void +__RATEEST_print(const struct xt_entry_target *target, const char *prefix) +{ + struct xt_rateest_target_info *info = (void *)target->data; + unsigned int interval; + unsigned int ewma_log; + + interval = (TIME_UNITS_PER_SEC << (info->interval + 2)) / 4; + ewma_log = interval * (1 << (info->ewma_log)); + + printf("%sname %s ", prefix, info->name); + printf("%sinterval ", prefix); + RATEEST_print_time(interval); + printf("%sewmalog ", prefix); + RATEEST_print_time(ewma_log); +} + +static void +RATEEST_print(const void *ip, const struct xt_entry_target *target, + int numeric) +{ + __RATEEST_print(target, ""); +} + +static void +RATEEST_save(const void *ip, const struct xt_entry_target *target) +{ + __RATEEST_print(target, "--rateest-"); +} + +static struct xtables_target rateest_target4 = { + .family = AF_INET, + .name = "RATEEST", + .version = IPTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_rateest_target_info)), + .userspacesize = XT_ALIGN(sizeof(struct xt_rateest_target_info)), + .help = RATEEST_help, + .init = RATEEST_init, + .parse = RATEEST_parse, + .final_check = RATEEST_final_check, + .print = RATEEST_print, + .save = RATEEST_save, + .extra_opts = RATEEST_opts, +}; + +static struct xtables_target rateest_target6 = { + .family = AF_INET6, + .name = "RATEEST", + .version = IPTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_rateest_target_info)), + .userspacesize = XT_ALIGN(sizeof(struct xt_rateest_target_info)), + .help = RATEEST_help, + .init = RATEEST_init, + .parse = RATEEST_parse, + .final_check = RATEEST_final_check, + .print = RATEEST_print, + .save = RATEEST_save, + .extra_opts = RATEEST_opts, +}; + +void _init(void) +{ + xtables_register_target(&rateest_target4); + xtables_register_target(&rateest_target6); +} diff --git a/include/linux/netfilter/xt_RATEEST.h b/include/linux/netfilter/xt_RATEEST.h new file mode 100644 index 0000000..ed9665f --- /dev/null +++ b/include/linux/netfilter/xt_RATEEST.h @@ -0,0 +1,11 @@ +#ifndef _XT_RATEEST_TARGET_H +#define _XT_RATEEST_TARGET_H + +struct xt_rateest_target_info { + char name[IFNAMSIZ]; + signed char interval; + unsigned char ewma_log; + struct xt_rateest *est __attribute__((aligned(8))); +}; + +#endif /* _XT_RATEEST_TARGET_H */ -- cgit v1.2.3