fixed HTB quantum 1514 instead of r2q
[svn/Prometheus-QoS/.git] / prometheus.c
... / ...
CommitLineData
1/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
2/* Prometheus QoS - you can "steal fire" from your ISP */\r
3/* "fair-per-IP" quality of service (QoS) utility */\r
4/* requires Linux 2.4.x or 2.6.x with HTB support */\r
5/* Copyright(C) 2005-2020 Michael Polak, Arachne Aerospace */\r
6/* iptables-restore support Copyright(C) 2007-2008 ludva */\r
7/* Credit: CZFree.Net,Martin Devera,Netdave,Aquarius,Gandalf */\r
8/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
9\r
10/* Modified by: xChaos, 20220327\r
11 ludva, 20080415\r
12 \r
13 Prometheus QoS is free software; you can redistribute it and/or\r
14 modify it under the terms of the GNU General Public License as \r
15 published by the Free Software Foundation; either version 2.1 of \r
16 the License, or (at your option) any later version.\r
17\r
18 Prometheus QoS is distributed in the hope that it will be useful,\r
19 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
21 General Public License for more details.\r
22\r
23 You should have received a copy of the GNU General Public License\r
24 along with Prometheus Qos; if not, write to the Free Software\r
25 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA \r
26 \r
27 GNU General Public License is located in file COPYING */\r
28\r
29#include "cll1-0.6.2.h"\r
30#include "ipstruct.h"\r
31\r
32const char *version = "1.0.0-b";\r
33\r
34/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
35/* Versions: 0.9.0 is development release, 1.0 will be "stable" */\r
36/* Official Trac URL: https://dev.arachne.cz/svn/prometheus */\r
37/* Official SVN URL: https://dev.arachne.cz/repos/prometheus */\r
38/* BTC donations account: 19rriLx8vR19wGefPaMhakqnCYNYwjLvxq */\r
39/* CZK donations account: 2900242944/2010 (transparent account) */\r
40/* Warning: unofficial Github mirror is not supported by author! */\r
41/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
42\r
43const char *stats_html_signature = "<span class=\"small\">Statistics generated by Prometheus QoS version %s<br />GPL+Copyright(C)2005-2020 Michael Polak, <a target=\"_blank\" href=\"http://www.arachne.cz/\">Arachne Labs</a></span>\n";\r
44\r
45#define STRLEN 512\r
46#undef DEBUG\r
47\r
48/* ======= All path names are defined here (for RPM patch) ======= */\r
49\r
50const char *tc = "/sbin/tc"; /* requires tc with HTB support */\r
51const char *iptables = "/sbin/iptables"; /* requires iptables utility */\r
52const char *ip6tables = "/sbin/ip6tables"; /* requires iptables utility */\r
53const char *iptablessave = "/sbin/iptables-save"; /* not yet required */\r
54const char *iptablesrestore = "/sbin/iptables-restore"; /* requires iptables-restore */\r
55const char *ip6tablessave = "/sbin/ip6tables-save"; /* not yet required */\r
56const char *ip6tablesrestore = "/sbin/ip6tables-restore"; /* requires iptables-restore */\r
57const char *ls = "/bin/ls"; /* this is not user configurable :-) */\r
58\r
59char *config = "/etc/prometheus/prometheus.conf"; /* main configuration file */\r
60char *hosts = "/etc/prometheus/hosts"; /* per-IP bandwidth definition file */\r
61char *macrosfile = "/etc/prometheus/prometheus.macros"; /* rewrite rules for most common tariffs */\r
62char *upstreamfile = "/etc/prometheus/upstream.interfaces"; /* list of interfaces to manage */\r
63char *downstreamfile = "/etc/prometheus/downstream.interfaces"; /* list of interfaces to manage */\r
64char *qosfreefile = "/etc/prometheus/qosfree.interfaces"; /* list of interfaces to manage */\r
65char *iptablesfile = "/var/spool/prometheus.iptables"; /* temporary file for iptables-restore*/\r
66char *iptablesdump = "/var/spool/prometheus.iptables-dump"; /* temporary file for iptables -L -v -x -n -t mangle */\r
67char *ip6tablesfile = "/var/spool/prometheus.ip6tables"; /* temporary file for ip6tables-restore*/\r
68char *credit = "/var/lib/misc/prometheus.credit"; /* credit log file */\r
69char *classmap = "/var/lib/misc/prometheus.classes"; /* credit log file */\r
70char *html = "/var/www/traffic.html"; /* hall of fame - html version */\r
71char *preview = "/var/www/preview.html"; /* hall of fame preview - html version */\r
72char *json_traffic = "/var/www/logs/traffic.json"; /* hall of fame - json version */\r
73char *json_preview = "/var/www/logs/preview.json"; /* hall of fame preview - json version */\r
74char *cmdlog = "/var/log/prometheuslog"; /* command log filename */\r
75char *log_dir = "/var/www/logs/"; /* log directory pathname, ended with slash */\r
76char *log_url = "/logs/"; /* log directory relative URI prefix (partial URL) */\r
77char *html_log_dir = "/var/www/logs/html/";\r
78\r
79char *jquery_url = "http://code.jquery.com/jquery-latest.js";\r
80char *lms_url = "/lms/?m=customerinfo&amp;id=";\r
81int use_jquery_popups = TRUE;\r
82int row_odd_even = 0; /*<tr class="odd/even"> */\r
83 \r
84/* === Configuraration file values defaults - stored in global variables ==== */\r
85\r
86int filter_type = 1; /*1 mark, 2 classify*/\r
87char *final_chain = "DROP"; /* REJECT would be better, but it is impossible in mangle */\r
88char *mark = "MARK";\r
89char *mark_iptables = "MARK --set-mark ";\r
90int dry_run = FALSE; /* preview - use puts() instead of system() */\r
91char *iptablespreamble = "*mangle\n:PREROUTING ACCEPT [0:0]\n:POSTROUTING ACCEPT [0:0]\n:INPUT ACCEPT [0:0]\n:OUTPUT ACCEPT [0:0]\n:FORWARD ACCEPT [0:0]";\r
92char *ip6preamble = "-A FORWARD -p ipv6-icmp -j ACCEPT\n-A POSTROUTING -p ipv6-icmp -j ACCEPT\n-A FORWARD -s fe80::/10 -j ACCEPT\n-A FORWARD -d ff00::/8 -j ACCEPT\n-A POSTROUTING -s fe80::/10 -j ACCEPT\n-A POSTROUTING -d ff00::/8 -j ACCEPT";\r
93FILE *iptables_file = NULL;\r
94FILE *ip6tables_file = NULL;\r
95int enable_credit = TRUE; /* enable credit file */\r
96int use_credit = FALSE; /* use credit file (if enabled)*/\r
97char *title = "Hall of Fame - Greatest Suckers"; /* hall of fame title */\r
98int hall_of_fame = TRUE; /* enable hall of fame */\r
99char *medium = "1000Mbit"; /* 10Mbit/100Mbit ethernet */\r
100//obsolete: char *lan = "eth0"; /* LAN interface */\r
101//obsolete: char *lan_medium = "1000Mbit"; /* 10Mbit/100Mbit ethernet */\r
102char *ip6prefix = NULL; /* Prefix for global /48 IPv6 subnet */\r
103char *qos_leaf = "sfq perturb 5"; /* leaf discipline */\r
104char *qos_free_zone = NULL; /* QoS free zone */\r
105char *qos_free_dst_ipset = NULL; /* QoS free zone - dst match ipset name, must be prepared outside prometheus */\r
106char *qos_free_src_ipset = NULL; /* QoS free zone - src match ipset name, must be prepared outside prometheus */\r
107/* int qos_proxy = TRUE; include proxy port to QoS */\r
108int found_lmsid = FALSE; /* show links to users in LMS information system */\r
109int include_upload = TRUE; /* upload+download=total traffic */\r
110/* char *proxy_ip = "192.168.1.1/32"; our IP with proxy port */\r
111/* int proxy_port = 3128; proxy port number */\r
112//obsolete: long long int line = 1024; /* WAN/ISP download in kbps */\r
113//obsolete: long long int up = 1024; /* WAN/ISP upload in kbps */\r
114int free_min = 256; /* minimum guaranted bandwidth for all undefined hosts */\r
115int free_max = 512; /* maximum allowed bandwidth for all undefined hosts */\r
116int overlimit_min = 256; /* minimum guaranted bandwidth for all undefined hosts */\r
117int overlimit_max = 512; /* maximum allowed bandwidth for all undefined hosts */\r
118int qos_free_delay = 0; /* seconds to sleep before applying new QoS rules */\r
119int digital_divide = 2; /* controls digital divide weirdness ratio, 1...3 */ \r
120int max_nesting = 5; /* /include/uapi/linux/pkt_sched.h: #define TC_HTB_MAXDEPTH 8 [... - 3 parent classes] */\r
121//obsolete: int htb_r2q = 256; /* should work for leaf values 512 kbps to 8 Mbps */\r
122int htb_quantum = 1514; /* MTU + ethernet header */\r
123int burst = 8; /* HTB burst (in kbits) */\r
124int burst_main = 64;\r
125int burst_group = 32;\r
126int magic_treshold = 8; /* reduce ceil by X*magic_treshhold kbps (hard shaping) */\r
127int keywordcount = 0;\r
128int class_count = 0;\r
129int ip_count = 0;\r
130FILE *log_file = NULL;\r
131char *kwd = "via-prometheus"; /* /etc/hosts comment, eg. #qos-64-128 */\r
132\r
133const int highest_priority = 0; /* highest HTB priority (HTB built-in value is 0) */\r
134const int lowest_priority = 7; /* lowest HTB priority /include/uapi/linux/pkt_sched.h: #define TC_HTB_NUMPRIO 8 */\r
135const int idxtable_treshold1 = 24; /* this is no longer configurable */\r
136const int idxtable_treshold2 = 12; /* this is no longer configurable */\r
137const int idxtable_bitmask1 = 3; /* this is no longer configurable */\r
138const int idxtable_bitmask2 = 3; /* this is no longer configurable */\r
139\r
140struct IP *ips = NULL, *networks = NULL, *ip, *sharedip;\r
141struct Group *groups = NULL, *group;\r
142struct Keyword *keyword, *defaultkeyword=NULL, *keywords = NULL;\r
143struct Macro *macro, *macros = NULL;\r
144struct Index *idxs = NULL, *idx, *metaindex;\r
145struct Interface *interfaces = NULL, *interface;\r
146struct QosFreeInterface *qosfreeinterfaces = NULL, *qosfreeinterface;\r
147\r
148#define FREE_CLASS 3\r
149#define OVERLIMIT_CLASS 4\r
150\r
151void help(void);\r
152/* implemented in help.c */
153\r
154void get_traffic_statistics(const char *whichiptables, int ipv6);\r
155/* implemented in parseiptables.c */\r
156\r
157void parse_ip_log(int argc, char **argv);\r
158/* implemented in parselog.c */\r
159\r
160void parse_hosts(char *hosts);\r
161/* implemented in parsehosts.c */\r
162\r
163void write_json_traffic(char *json);\r
164/* implemented in json.c */\r
165\r
166void write_htmlandlogs(char *html, char *d, int total, int just_preview);\r
167/* implemented in htmlandlogs.c */\r
168\r
169void analyse_topology(char *traceroute);\r
170/* implemented in networks.c */\r
171\r
172char *parse_datafile_line(char *str);\r
173/* implemented in utils.c */\r
174\r
175time_t get_mtime(const char *path);\r
176/* implemented in utils.c */\r
177\r
178const char *tr_odd_even(void)\r
179{\r
180 row_odd_even = 1 - row_odd_even;\r
181 if(row_odd_even)\r
182 {\r
183 return "<tr class=\"even\">\n";\r
184 }\r
185 else\r
186 {\r
187 return "<tr class=\"odd\">\n";\r
188 }\r
189}\r
190\r
191\r
192/* ====== iptables indexes are used to reduce complexity to log8(N) ===== */\r
193\r
194char *index_id(char *ip, int bitmask);\r
195/* function implemented in ipv4subnets.c */\r
196\r
197char *subnet_id(char *ip, int bitmask);\r
198/* function implemented in ipv4subnets.c */\r
199\r
200char *index6_id(char *ip, int bitmask);\r
201/* function implemented in ipv6subnets.c */\r
202\r
203char *subnet6_id(char *ip, int bitmask);\r
204/* function implemented in ipv6subnets.c */\r
205\r
206/* ================= Let's parse configuration file here ================ */\r
207\r
208void reject_config_and_exit(char *filename)\r
209{\r
210 printf("Configuration file %s rejected - abnormal exit.",filename);\r
211 exit(-1);\r
212}\r
213\r
214void get_config(char *config_filename)\r
215{\r
216 char *cnf="mark";\r
217 \r
218 printf("Configured keywords: ");\r
219 parse(config_filename)\r
220 {\r
221 option("keyword",kwd);\r
222 if(kwd)\r
223 {\r
224 printf("%s ",kwd);\r
225\r
226 create(keyword,Keyword);\r
227 keyword->key = kwd;\r
228 keyword->asymetry_ratio = 1; /* ratio for ADSL-like upload */\r
229 keyword->asymetry_fixed = 0; /* fixed treshold for ADSL-like upload */\r
230 keyword->data_limit = 8; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */\r
231 keyword->data_prio = 4; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */\r
232 keyword->fixed_limit = 0; /* fixed data limit for setting lower HTB ceil */\r
233 keyword->fixed_prio = 0; /* fixed data limit for setting lower HTB prio */\r
234 keyword->reserve_min = 8; /* bonus for nominal HTB rate bandwidth (in kbps) */\r
235 keyword->reserve_max = 0; /* malus for nominal HTB ceil (in kbps) */\r
236 keyword->default_prio = highest_priority+1;\r
237 keyword->download_aggregation = keyword->upload_aggregation = 0; /* disable by default */\r
238 keyword->html_color = "000000";\r
239 keyword->ip_count = 0;\r
240 keyword->leaf_discipline = "";\r
241 keyword->allowed_avgmtu = 0;\r
242\r
243 push(keyword, keywords);\r
244 if(!defaultkeyword)\r
245 {\r
246 defaultkeyword = keyword;\r
247 }\r
248 keywordcount++;\r
249 \r
250 kwd=NULL;\r
251 }\r
252 else\r
253 {\r
254 for_each(keyword,keywords)\r
255 {\r
256 int l=strlen(keyword->key);\r
257\r
258 if(!strncmp(keyword->key,_,l) && strlen(_)>l+2)\r
259 {\r
260 char *tmptr=_; /* <---- l+1 ----> */\r
261 _+=l+1; /* via-prometheus-asymetry-ratio, etc. */\r
262 foption("asymetry-ratio", keyword->asymetry_ratio);\r
263 ioption("asymetry-treshold", keyword->asymetry_fixed);\r
264 ioption("magic-relative-limit", keyword->data_limit);\r
265 ioption("magic-relative-prio", keyword->data_prio);\r
266 loption("magic-fixed-limit", keyword->fixed_limit);\r
267 loption("magic-fixed-prio", keyword->fixed_prio);\r
268 ioption("htb-default-prio", keyword->default_prio);\r
269 ioption("htb-rate-bonus", keyword->reserve_min);\r
270 ioption("htb-ceil-malus", keyword->reserve_max);\r
271 ioption("download-aggregation", keyword->download_aggregation);\r
272 ioption("upload-aggregation", keyword->upload_aggregation);\r
273 option("leaf-discipline", keyword->leaf_discipline);\r
274 option("html-color", keyword->html_color);\r
275 ioption("allowed-avgmtu" ,keyword->allowed_avgmtu);\r
276 _=tmptr;\r
277 \r
278 if(keyword->data_limit || keyword->fixed_limit || \r
279 keyword->data_prio || keyword->fixed_prio)\r
280 {\r
281 use_credit=1; \r
282 }\r
283 }\r
284 }\r
285 }\r
286\r
287 option("tc",tc);\r
288 option("iptables",iptables);\r
289 option("iptables-save",iptablessave);\r
290 option("iptables-restore",iptablesrestore);\r
291 option("ip6tables",ip6tables);\r
292 option("ip6tables-save",ip6tablessave);\r
293 option("ip6tables-restore",ip6tablesrestore);\r
294 option("iptables-in-filename",iptablesfile);\r
295 option("iptables-dump-filename",iptablesdump);\r
296 option("ip6tables-in-filename",ip6tablesfile);\r
297 option("hosts",hosts);\r
298 option("downstream-interfaces-list-filename",downstreamfile);\r
299 option("upstream-interfaces-list-filename",upstreamfile);\r
300 option("qos-free-interfaces-list-filename",qosfreefile);\r
301 option("macros-filename",macrosfile);\r
302 option("ip6-prefix",ip6prefix);\r
303 option("medium",medium);\r
304 ioption("hall-of-fame-enable",hall_of_fame);\r
305 ioption("digital-divide-weirdness-ratio",digital_divide);\r
306 option("hall-of-fame-title",title);\r
307 option("hall-of-fame-filename",html);\r
308 option("json-filename",json_traffic);\r
309 option("hall-of-fame-preview",preview);\r
310 option("json-preview",json_preview);\r
311 option("log-filename",cmdlog);\r
312 option("credit-filename",credit);\r
313 option("classmap-filename",classmap);\r
314 ioption("credit-enable",enable_credit);\r
315 option("log-traffic-directory",log_dir);\r
316 option("log-traffic-html-directory",html_log_dir);\r
317 option("log-traffic-url-path",log_url);\r
318 option("jquery-url",jquery_url);\r
319 option("lms-url",lms_url);\r
320 ioption("use-jquery-popups",use_jquery_popups);\r
321 option("qos-free-zone",qos_free_zone);\r
322 option("qos-free-dst-ipset",qos_free_dst_ipset);\r
323 option("qos-free-src-ipset",qos_free_src_ipset);\r
324 ioption("qos-free-delay",qos_free_delay);\r
325/* ioption("qos-proxy-enable",qos_proxy); */\r
326/* option("qos-proxy-ip",proxy_ip);*/\r
327 option("htb-leaf-discipline",qos_leaf);\r
328/* ioption("qos-proxy-port",proxy_port); */\r
329 ioption("free-rate",free_min);\r
330 ioption("free-ceil",free_max);\r
331 ioption("overlimit-rate",overlimit_min);\r
332 ioption("overlimit-ceil",overlimit_max);\r
333 ioption("htb-burst",burst);\r
334 ioption("htb-burst-main",burst_main);\r
335 ioption("htb-burst-group",burst_group);\r
336 ioption("htb-nesting-limit",max_nesting);\r
337 ioption("htb-quantum",htb_quantum);\r
338 ioption("magic-include-upload",include_upload);\r
339 ioption("magic-treshold",magic_treshold); \r
340 option("filter-type", cnf); \r
341/* not yet implemented:\r
342 ioption("magic-fixed-packets",fixed_packets);\r
343 ioption("magic-relative-packets",packet_limit);\r
344*/\r
345 }\r
346 fail\r
347 { \r
348 perror(config_filename);\r
349 puts("Warning - using built-in defaults instead ...");\r
350 }\r
351 done; /* ugly macro end */\r
352 printf("\n");\r
353 \r
354 /* leaf discipline for keywords */\r
355 for_each(keyword,keywords)\r
356 {\r
357 if(!strcmpi(keyword->leaf_discipline, ""))\r
358 {\r
359 keyword->leaf_discipline = qos_leaf;\r
360 }\r
361 }\r
362\r
363 if(strcmpi(cnf, "mark"))\r
364 {\r
365 filter_type = 2;\r
366 mark = "CLASSIFY";\r
367 mark_iptables = "CLASSIFY --set-class 1:";\r
368 }\r
369 else\r
370 {\r
371 filter_type = 1;\r
372 mark = "MARK";\r
373 mark_iptables = "MARK --set-mark ";\r
374 }\r
375}\r
376\r
377 \r
378/* ========== This function executes, logs or also prints command ========== */\r
379\r
380void safe_run(char *cmd)\r
381{\r
382 if(dry_run)\r
383 {\r
384 printf("\n=>%s\n",cmd);\r
385 }\r
386 else\r
387 {\r
388 system(cmd);\r
389 }\r
390 if(log_file)\r
391 {\r
392 fprintf(log_file,"%s\n",cmd);\r
393 }\r
394}\r
395\r
396void iptables_save_line(char *line, int ipv6)\r
397{\r
398 if(ipv6)\r
399 {\r
400 fprintf(ip6tables_file,"%s\n",line);\r
401 }\r
402 else\r
403 {\r
404 fprintf(iptables_file,"%s\n",line);\r
405 }\r
406}\r
407\r
408#define IPv4 FALSE\r
409#define IPv6 TRUE\r
410\r
411\r
412void run_iptables_restore(void)\r
413{\r
414 char *restor;\r
415 string(restor, STRLEN);\r
416\r
417 /*-----------------------------------------------------------------*/\r
418 printf("Running %s <%s ...\n", iptablesrestore, iptablesfile);\r
419 /*-----------------------------------------------------------------*/\r
420\r
421 iptables_save_line("COMMIT", IPv4);\r
422 fclose(iptables_file);\r
423 if(dry_run) \r
424 {\r
425 parse(iptablesfile)\r
426 {\r
427 printf("%s\n",_);\r
428 }\r
429 done; /* ugly macro end */\r
430 }\r
431\r
432 sprintf(restor,"%s <%s",iptablesrestore, iptablesfile);\r
433 safe_run(restor);\r
434\r
435 if(ip6prefix)\r
436 {\r
437 /*-----------------------------------------------------------------*/\r
438 printf("Running %s <%s ...\n", ip6tablesrestore, ip6tablesfile);\r
439 /*-----------------------------------------------------------------*/\r
440 iptables_save_line("COMMIT", IPv6);\r
441 fclose(ip6tables_file);\r
442 if(dry_run) \r
443 {\r
444 parse(ip6tablesfile)\r
445 {\r
446 printf("%s\n",_);\r
447 }\r
448 done; /* ugly macro end */\r
449 }\r
450 sprintf(restor,"%s <%s",ip6tablesrestore, ip6tablesfile);\r
451 safe_run(restor);\r
452 }\r
453 free(restor);\r
454}\r
455\r
456/**/\r
457\r
458char *parse_datafile_line(char *str);\r
459time_t get_mtime(const char *path);\r
460\r
461/*-----------------------------------------------------------------*/\r
462/* Are you looking for int main(int argc, char **argv) ? :-)) */\r
463/*-----------------------------------------------------------------*/\r
464\r
465program\r
466{\r
467 int i=0; /* just plain old Fortran style integer :-) */\r
468 FILE *f=NULL; /* everything is just stream of bytes... */\r
469 char *str, *ptr, *d; /* LET A$=B$ :-) */\r
470 char *substring, *limit_pkts;\r
471\r
472 int parent = 1;\r
473 int just_networks = FALSE; \r
474 int just_flush = FALSE; /* deactivates all previous actions */\r
475 int nodelay = FALSE;\r
476 int just_preview = FALSE; /* preview - generate just stats */\r
477 int start_shaping = FALSE; /* apply FUP - requires classmap file */\r
478 int stop_shaping = FALSE; /* lift FUP - requires classmap file */\r
479 int reduce_ceil = 0; /* allow only rate+(ceil-rate)/2, /4, etc. */\r
480 int just_logs = FALSE; /* just parse logs */\r
481 int run = FALSE;\r
482 int total = 0;\r
483 \r
484 char *althosts=NULL;\r
485 \r
486 printf("\n\\r
487Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\\r
488Version %s - Copyright (C)2005-2017 Michael Polak, Arachne Labs\n\\r
489iptables-restore & burst tunning & classify modification by Ludva\n\\r
490Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version);\r
491\r
492 /*----- Boring... we have to check command line options first: ----*/ \r
493 arguments\r
494 {\r
495 argument("-c") { nextargument(config); }\r
496 argument("-h") { nextargument(althosts);}\r
497 argument("-d") { run=TRUE; dry_run=TRUE; }\r
498 argument("-f") { run=TRUE; just_flush=TRUE; }\r
499 argument("-9") { run=TRUE; just_flush=9; }\r
500 argument("-p") { run=TRUE; just_preview=TRUE; }\r
501 argument("-q") { run=TRUE; just_preview=TRUE; stop_shaping=TRUE; }\r
502 argument("-2") { run=TRUE; just_preview=TRUE; reduce_ceil=2; }\r
503 argument("-4") { run=TRUE; just_preview=TRUE; reduce_ceil=4; }\r
504 argument("-s") { run=TRUE; just_preview=TRUE; start_shaping=TRUE; }\r
505 argument("-r") { run=TRUE; }\r
506 argument("-n") { run=TRUE; nodelay=TRUE; }\r
507 argument("-a") { run=TRUE; just_networks=TRUE; }\r
508 argument("-l") { just_logs=TRUE; }\r
509 argument("-m") { just_logs=TRUE; }\r
510 argument("-y") { just_logs=TRUE; }\r
511 argument("-?") { help(); exit(0); }\r
512 argument("--help") { help(); exit(0); }\r
513 argument("-v") { exit(0); } \r
514 argument("--version") { exit(0); } \r
515 }\r
516 \r
517 if(dry_run)\r
518 {\r
519 puts("*** THIS IS JUST DRY RUN ! ***\n");\r
520 }\r
521\r
522 date(d); /* this is typical cll1.h macro - prints current date */\r
523\r
524 /*-----------------------------------------------------------------*/\r
525 printf("Parsing configuration file %s ...\n", config);\r
526 /*-----------------------------------------------------------------*/\r
527 get_config(config);\r
528 /*-----------------------------------------------------------------*/\r
529 printf("Parsing upstream interfaces list %s ...\n", upstreamfile);\r
530 /*-----------------------------------------------------------------*/\r
531 parse(upstreamfile)\r
532 {\r
533 ptr = parse_datafile_line(_);\r
534 if(ptr)\r
535 {\r
536 create(interface, Interface);\r
537 interface->name = _;\r
538 interface->speed = (long long)atol(ptr);\r
539 /* is supplied value meaningful ?*/\r
540 if(interface->speed <= 0)\r
541 {\r
542 printf("Illegal value of %s interface bandwidth.\n", interface->name);\r
543 reject_config_and_exit(upstreamfile);\r
544 }\r
545 interface->is_upstream = TRUE;\r
546 interface->chain = "FORWARD";\r
547 interface->idxprefix = "forw";\r
548 push(interface, interfaces);\r
549 printf("Upstream interface %s: medium %s capacity %ld kbps\n", interface->name, medium, interface->speed);\r
550 }\r
551 }\r
552 done; /* ugly macro end */\r
553\r
554 /*-----------------------------------------------------------------*/\r
555 printf("Parsing downstream interfaces list %s ...\n", downstreamfile);\r
556 /*-----------------------------------------------------------------*/\r
557 parse(downstreamfile)\r
558 {\r
559 ptr = parse_datafile_line(_);\r
560 if(ptr)\r
561 {\r
562 create(interface, Interface);\r
563 interface->name = _;\r
564 interface->speed = (long long)atol(ptr);\r
565 /* is supplied value meaningful ?*/\r
566 if(interface->speed <= 0)\r
567 {\r
568 printf("Illegal value of %s interface bandwidth.\n", interface->name);\r
569 reject_config_and_exit(downstreamfile);\r
570 }\r
571 interface->is_upstream = FALSE;\r
572 interface->chain = "POSTROUTING";\r
573 interface->idxprefix = "post";\r
574 push(interface, interfaces);\r
575 printf("Downstream interface %s: medium %s capacity %ld kbps\n", interface->name, medium, interface->speed);\r
576 }\r
577 }\r
578 done; /* ugly macro end */\r
579 \r
580 if(just_logs)\r
581 {\r
582 parse_ip_log(argc,argv);\r
583 exit(0);\r
584 }\r
585 else if(not run)\r
586 {\r
587 help();\r
588 exit(0);\r
589 }\r
590\r
591 if(althosts)\r
592 {\r
593 hosts = althosts;\r
594 }\r
595\r
596 if(just_flush<9)\r
597 {\r
598 /*-----------------------------------------------------------------*/\r
599 puts("Parsing iptables verbose output ...");\r
600 /*-----------------------------------------------------------------*/\r
601 get_traffic_statistics(iptables, FALSE);\r
602 if(ip6prefix)\r
603 {\r
604 /*-----------------------------------------------------------------*/\r
605 puts("Parsing ip6tables verbose output ...");\r
606 /*-----------------------------------------------------------------*/ \r
607 get_traffic_statistics(ip6tables, TRUE);\r
608 }\r
609 }\r
610\r
611 /*-----------------------------------------------------------------*/\r
612 /* cll1.h - let's allocate brand new character buffer... */\r
613 /*-----------------------------------------------------------------*/\r
614 string(str, STRLEN); \r
615 string(limit_pkts, STRLEN);\r
616\r
617 /*-----------------------------------------------------------------*/\r
618 printf("Parsing qos free interfaces file %s ...\n", qosfreefile);\r
619 /*-----------------------------------------------------------------*/\r
620 load(qosfreeinterface, qosfreeinterfaces,\r
621 qosfreefile, QosFreeInterface, name);\r
622\r
623 /*-----------------------------------------------------------------*/\r
624 printf("Parsing macro definition file %s ...\n", macrosfile);\r
625 /*-----------------------------------------------------------------*/\r
626 parse(macrosfile)\r
627 {\r
628 ptr = parse_datafile_line(_);\r
629 if(ptr)\r
630 {\r
631 create(macro, Macro);\r
632 macro->rewrite_from = _;\r
633 macro->rewrite_to = ptr;\r
634 push(macro, macros);\r
635 printf("%s -> %s\n", macro->rewrite_from, macro->rewrite_to);\r
636 }\r
637 }\r
638 done; /* ugly macro end */\r
639\r
640\r
641\r
642 /*-----------------------------------------------------------------*/\r
643 printf("Parsing class defintion file %s ...\n", hosts);\r
644 /*-----------------------------------------------------------------*/\r
645 parse_hosts(hosts);\r
646\r
647#ifdef MONITORINGTRHU_CTU\r
648//special hack only to generate certain required CSV statistics for www.ctu.cz (regulation body)\r
649//not required for everyday use, requires special syntax sugar in hosts file, see parsehosts.c\r
650 for_each(technology, technologies)\r
651 {\r
652 char *filename;\r
653 FILE *f;\r
654 string(filename, strlen(log_dir) + strlen(technology->filename) + 5);\r
655 strcpy(filename, log_dir);\r
656 strcat(filename, technology->filename); \r
657 strcat(filename, ".csv");\r
658 /*-----------------------------------------------------------------*/\r
659 printf("Writing report file %s ...\n", filename);\r
660 /*-----------------------------------------------------------------*/\r
661 f = fopen(filename, "w");\r
662 if(f)\r
663 {\r
664 for_each(ip, ips) if(eq(technology->filename, ip->technology_str))\r
665 {\r
666 fprintf(f,"%d,%s,%d\n", ip->lmsid, ip->ruian_id_str, ip->max);\r
667 }\r
668 fclose(f);\r
669 }\r
670 else\r
671 perror(filename); \r
672 } \r
673#endif\r
674\r
675 /*-----------------------------------------------------------------*/\r
676 puts("Resolving shared connections ...");\r
677 /*-----------------------------------------------------------------*/\r
678 for_each(ip, ips) if(ip->sharing)\r
679 {\r
680 for_each(sharedip, ips) if(eq(sharedip->name, ip->sharing))\r
681 {\r
682 sharedip->traffic += ip->traffic;\r
683 sharedip->traffic_down += ip->direct;\r
684 sharedip->traffic_up += ip->upload;\r
685 ip->traffic = 0;\r
686 ip->mark = sharedip->mark; \r
687 ip->lmsid = sharedip->lmsid;\r
688 ip->pps_limit = sharedip->pps_limit; /* no other way to do this */\r
689\r
690 /* Ugly hack: append IPv4 addresses of sharedip to IPv6 uplinks */\r
691 ptr = strchr(ip->addr, '+');\r
692 if(ptr && ptr-ip->addr > 1 && !sharedip->v6)\r
693 {\r
694 *(--ptr) = 0;\r
695 concatenate(ip->addr, sharedip->addr, ptr);\r
696 ip->name = ip->addr = ptr;\r
697 ptr = strchr(ip->addr, '.');\r
698 while(ptr && *ptr)\r
699 {\r
700 *ptr = ':';\r
701 ptr = strchr(ptr, '.');\r
702 }\r
703 ip->mask += 64;\r
704 }\r
705\r
706 break;\r
707 }\r
708 if(not sharedip)\r
709 {\r
710 printf("Unresolved shared connection: %s %s sharing-%s\n",\r
711 ip->addr, ip->name, ip->sharing);\r
712 }\r
713 }\r
714\r
715 if(enable_credit && just_flush<9)\r
716 {\r
717 /*-----------------------------------------------------------------*/\r
718 printf("Parsing credit file %s ...\n", credit);\r
719 /*-----------------------------------------------------------------*/\r
720 parse(credit)\r
721 {\r
722 ptr = parse_datafile_line(_);\r
723 if(ptr)\r
724 {\r
725 if_exists(ip,ips,eq(ip->addr,_))\r
726 {\r
727 sscanf(ptr,"%Lu",&(ip->credit));\r
728 }\r
729 }\r
730 }\r
731 done; /* ugly macro end */\r
732 }\r
733\r
734\r
735 if(!just_preview)\r
736 {\r
737 /*-----------------------------------------------------------------*/\r
738 puts("Initializing iptables and tc classes ...");\r
739 /*-----------------------------------------------------------------*/\r
740 \r
741 iptables_file = fopen(iptablesfile, "w");\r
742 if(iptables_file == NULL)\r
743 {\r
744 perror(iptablesfile);\r
745 exit(-1);\r
746 }\r
747 iptables_save_line(iptablespreamble, IPv4);\r
748\r
749 if(ip6prefix)\r
750 {\r
751 ip6tables_file = fopen(ip6tablesfile, "w");\r
752 if(ip6tables_file == NULL)\r
753 {\r
754 perror(ip6tablesfile);\r
755 exit(-1);\r
756 }\r
757 iptables_save_line(iptablespreamble, IPv6);\r
758 iptables_save_line(ip6preamble, IPv6);\r
759 }\r
760\r
761 run_iptables_restore();\r
762 \r
763 log_file = fopen(cmdlog, "w");\r
764 if(log_file == NULL) \r
765 {\r
766 perror(cmdlog);\r
767 exit(-1);\r
768 } \r
769 \r
770 for_each(interface, interfaces)\r
771 {\r
772 sprintf(str,"%s qdisc del dev %s root 2>/dev/null", tc, interface->name);\r
773 safe_run(str);\r
774 }\r
775 \r
776 iptables_file=fopen(iptablesfile,"w");\r
777 iptables_save_line(iptablespreamble, IPv4);\r
778 if(ip6prefix)\r
779 {\r
780 ip6tables_file=fopen(ip6tablesfile,"w");\r
781 iptables_save_line(iptablespreamble, IPv6);\r
782 iptables_save_line(ip6preamble, IPv6);\r
783 }\r
784\r
785 if(qos_free_zone && *qos_free_zone != '0') /* this is currently supported only for IPv4 */\r
786 {\r
787 for_each(interface, interfaces)\r
788 {\r
789 sprintf(str,"-A %s -%c %s -o %s -j ACCEPT", interface->chain, (interface->is_upstream?'d':'s'), qos_free_zone, interface->name);\r
790 iptables_save_line(str, IPv4);\r
791 }\r
792 }\r
793\r
794 if(qos_free_dst_ipset && *qos_free_dst_ipset != '0') /* this is currently supported only for IPv4 */\r
795 {\r
796 for_each(interface, interfaces)\r
797 {\r
798 sprintf(str,"-A %s -m set --match-set %s %s -o %s -j ACCEPT", interface->chain, qos_free_dst_ipset, (interface->is_upstream?"dst":"src"), interface->name);\r
799 iptables_save_line(str, IPv4);\r
800 }\r
801 }\r
802\r
803 if(qos_free_src_ipset && *qos_free_src_ipset != '0') /* this is currently supported only for IPv4 */\r
804 {\r
805 for_each(interface, interfaces)\r
806 {\r
807 sprintf(str,"-A %s -m set --match-set %s %s -o %s -j ACCEPT", interface->chain, qos_free_src_ipset, (interface->is_upstream?"src":"dst"), interface->name);\r
808 iptables_save_line(str, IPv4);\r
809 }\r
810 }\r
811 \r
812 for_each(qosfreeinterface, qosfreeinterfaces)\r
813 {\r
814 sprintf(str,"-A FORWARD -i %s -j ACCEPT", qosfreeinterface->name);\r
815 iptables_save_line(str, IPv4); \r
816 iptables_save_line(str, IPv6);\r
817 sprintf(str,"-A POSTROUTING -o %s -j ACCEPT", qosfreeinterface->name);\r
818 iptables_save_line(str, IPv4);\r
819 iptables_save_line(str, IPv6);\r
820 }\r
821 \r
822 if(ip_count > idxtable_treshold1 && !just_flush)\r
823 {\r
824 int idxcount=0, bitmask=32-idxtable_bitmask1;\r
825 char *subnet, *buf;\r
826 /*-----------------------------------------------------------------*/\r
827 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count);\r
828 /*-----------------------------------------------------------------*/\r
829\r
830 iptables_save_line(":post_common - [0:0]", IPv4);\r
831 iptables_save_line(":forw_common - [0:0]", IPv4);\r
832 if(ip6prefix)\r
833 {\r
834 iptables_save_line(":post_common - [0:0]", IPv6);\r
835 iptables_save_line(":forw_common - [0:0]", IPv6);\r
836 }\r
837\r
838 for_each(ip,ips) if(ip->addr && *(ip->addr) && !eq(ip->addr,"0.0.0.0/0")) \r
839 {\r
840 if(ip->v6)\r
841 {\r
842 buf=index6_id(ip->addr,bitmask+32);\r
843 }\r
844 else\r
845 {\r
846 buf=index_id(ip->addr, bitmask);\r
847 }\r
848 \r
849 if_exists(idx,idxs,eq(idx->id,buf))\r
850 {\r
851 idx->children++;\r
852 }\r
853 else\r
854 {\r
855 create(idx,Index);\r
856 idx->addr = ip->addr;\r
857 idx->id = buf;\r
858 idx->bitmask = bitmask+32*ip->v6;\r
859 idx->parent = NULL;\r
860 idx->children = 0;\r
861 idx->ipv6 = ip->v6;\r
862 idxcount++;\r
863 push(idx,idxs);\r
864 }\r
865 }\r
866\r
867 /* brutal perfomance optimalization */\r
868 while(idxcount > idxtable_treshold2 && bitmask > 2*idxtable_bitmask2)\r
869 {\r
870 bitmask -= idxtable_bitmask2;\r
871 idxcount = 0;\r
872\r
873 for_each(idx,idxs) if(idx->parent == NULL)\r
874 {\r
875 if(idx->ipv6)\r
876 {\r
877 buf = index6_id(idx->addr, bitmask+32);\r
878 }\r
879 else\r
880 {\r
881 buf = index_id(idx->addr, bitmask);\r
882 }\r
883 if_exists(metaindex,idxs,eq(metaindex->id,buf))\r
884 {\r
885 metaindex->children++;\r
886 }\r
887 else\r
888 {\r
889 create(metaindex,Index);\r
890 metaindex->addr = idx->addr;\r
891 metaindex->id = buf;\r
892 metaindex->bitmask = bitmask+32*idx->ipv6;\r
893 metaindex->parent = NULL;\r
894 metaindex->children = 0;\r
895 metaindex->ipv6 = idx->ipv6;\r
896 idxcount++;\r
897 push(metaindex,idxs);\r
898 }\r
899 idx->parent=metaindex;\r
900 }\r
901 }\r
902\r
903 /* this should slightly optimize throughput ... */\r
904 sort(idx,idxs,desc_order_by,children);\r
905 sort(idx,idxs,order_by,bitmask);\r
906\r
907 i=0;\r
908 for_each(idx, idxs)\r
909 {\r
910 if(idx->ipv6)\r
911 {\r
912 subnet=subnet6_id(idx->addr, idx->bitmask);\r
913 }\r
914 else\r
915 {\r
916 subnet=subnet_id(idx->addr, idx->bitmask);\r
917 }\r
918 printf("%d: %s/%d\n", ++i, subnet, idx->bitmask);\r
919 \r
920 sprintf(str,":post_%s - [0:0]", idx->id);\r
921 iptables_save_line(str, idx->ipv6);\r
922\r
923 sprintf(str,":forw_%s - [0:0]", idx->id);\r
924 iptables_save_line(str, idx->ipv6);\r
925\r
926 for_each(interface, interfaces)\r
927 {\r
928 if(idx->parent)\r
929 {\r
930 string(buf, strlen(idx->parent->id)+6);\r
931 sprintf(buf, "%s_%s", interface->idxprefix, idx->parent->id);\r
932 }\r
933 else\r
934 {\r
935 buf = interface->chain;\r
936 }\r
937\r
938 sprintf(str, "-A %s -%c %s/%d -o %s -j %s_%s", \r
939 buf, (interface->is_upstream?'s':'d'), subnet, idx->bitmask, interface->name, interface->idxprefix, idx->id);\r
940 iptables_save_line(str, idx->ipv6);\r
941\r
942 sprintf(str, "-A %s -%c %s/%d -o %s -j %s_common",\r
943 buf, (interface->is_upstream?'s':'d'), subnet, idx->bitmask, interface->name, interface->idxprefix);\r
944 iptables_save_line(str, idx->ipv6);\r
945 }\r
946 }\r
947 printf("Total indexed iptables chains created: %d\n", i);\r
948\r
949 for_each(interface, interfaces)\r
950 {\r
951 sprintf(str,"-A %s -o %s -j %s_common", interface->chain, interface->name, interface->idxprefix);\r
952 iptables_save_line(str, IPv4);\r
953 if(ip6prefix)\r
954 {\r
955 sprintf(str,"-A %s -o %s -j %s_common", interface->chain, interface->name, interface->idxprefix);\r
956 iptables_save_line(str, IPv6);\r
957 }\r
958 }\r
959 }\r
960 }\r
961\r
962 if(just_flush)\r
963 {\r
964 fclose(iptables_file);\r
965 if(log_file)\r
966 { \r
967 fclose(log_file);\r
968 }\r
969 puts("Just flushed iptables and tc classes - now exiting ...");\r
970 exit(0);\r
971 }\r
972\r
973 if(!just_preview)\r
974 {\r
975 if(!dry_run && !nodelay && qos_free_delay)\r
976 {\r
977 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n", qos_free_delay);\r
978 sleep(qos_free_delay);\r
979 }\r
980\r
981 for_each(interface, interfaces)\r
982 {\r
983 sprintf(str, "%s qdisc add dev %s root handle 1: htb default 1",\r
984 tc, interface->name);\r
985 safe_run(str);\r
986\r
987 sprintf(str, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d quantum %d",\r
988 tc, interface->name, medium, medium, burst_main, highest_priority, htb_quantum);\r
989 safe_run(str);\r
990\r
991 sprintf(str, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d quantum %d",\r
992 tc, interface->name, interface->speed, interface->speed, burst_main, highest_priority, htb_quantum);\r
993 safe_run(str);\r
994 }\r
995 }\r
996\r
997 /*-----------------------------------------------------------------*/\r
998 puts("Locating heavy downloaders and generating root classes ...");\r
999 /*-----------------------------------------------------------------*/\r
1000 sort(ip,ips,desc_order_by,traffic); \r
1001\r
1002 /*-----------------------------------------------------------------*/\r
1003 for_each(interface, interfaces)\r
1004 {\r
1005 long long int rate = interface->speed;\r
1006 long long int max = interface->speed;\r
1007 int group_count = 0;\r
1008 //obsolete: FILE *credit_file = NULL;\r
1009 \r
1010 //obsolete: if(!just_preview && !dry_run && enable_credit)\r
1011 //obsolete: {\r
1012 //obsolete: credit_file = fopen(credit,"w");\r
1013 //obsolete: }\r
1014\r
1015 for_each(group,groups)\r
1016 {\r
1017 if(!just_preview)\r
1018 {\r
1019 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d quantum %d #down desired %d", \r
1020 tc, interface->name, parent, group->id, rate, max, burst_group, highest_priority+1, htb_quantum, group->desired);\r
1021 safe_run(str);\r
1022 }\r
1023\r
1024 if(group_count++ < max_nesting)\r
1025 {\r
1026 parent = group->id;\r
1027 }\r
1028\r
1029 rate -= digital_divide*group->min;\r
1030 if(rate < group->min)\r
1031 {\r
1032 rate = group->min;\r
1033 }\r
1034 \r
1035 /*shaping of aggresive downloaders, with credit file support */\r
1036 /* obsolete\r
1037 if(use_credit)\r
1038 {\r
1039 int group_rate = group->min, priority_sequence = lowest_priority;\r
1040 \r
1041 for_each(ip, ips) if(ip->min == group->min && ip->max > ip->min)\r
1042 {\r
1043 ip->realquota=ip->credit+(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20));\r
1044 if( ip->keyword->data_limit \r
1045 and not ip->fixedprio \r
1046 and ip->traffic > ip->realquota )\r
1047 {\r
1048 if(group_rate < ip->max)\r
1049 {\r
1050 ip->max = group_rate;\r
1051 }\r
1052 group_rate+=magic_treshold;\r
1053 ip->prio=lowest_priority;\r
1054 if(ip->prio<highest_priority+2)\r
1055 {\r
1056 ip->prio=highest_priority+2;\r
1057 }\r
1058 }\r
1059 else\r
1060 {\r
1061 if( ip->keyword->data_prio \r
1062 && !ip->fixedprio \r
1063 && ( ip->traffic > ip->credit + (ip->min*ip->keyword->data_prio+(ip->keyword->fixed_prio<<20))) )\r
1064 {\r
1065 ip->prio=priority_sequence--;\r
1066 if(ip->prio<highest_priority+1)\r
1067 {\r
1068 ip->prio=highest_priority+1;\r
1069 }\r
1070 }\r
1071 \r
1072 if(credit_file)\r
1073 {\r
1074 unsigned long long lcredit=0;\r
1075 \r
1076 if((ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))>ip->traffic)\r
1077 {\r
1078 lcredit=(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))-ip->traffic;\r
1079 }\r
1080 fprintf(credit_file,"%s %Lu\n",ip->addr,lcredit);\r
1081 }\r
1082 }\r
1083 } \r
1084 } obsolete */\r
1085 }\r
1086 /* obsolete \r
1087 if(credit_file)\r
1088 {\r
1089 fclose(credit_file);\r
1090 } obsolete */\r
1091 }\r
1092\r
1093 if(just_preview)\r
1094 {\r
1095 if(start_shaping || stop_shaping || reduce_ceil)\r
1096 {\r
1097 time_t how_much_seconds = time(NULL) - get_mtime(classmap); /* sice start of daily aggregation session */\r
1098 printf("Reading %s (%ld seconds old) and applying Fair Use Policy and Aggregation rules... \n", classmap, how_much_seconds);\r
1099 \r
1100 parse(classmap)\r
1101 {\r
1102 ptr=strchr(_,' ');\r
1103 if(ptr)\r
1104 {\r
1105 *ptr=0;\r
1106 ptr++;\r
1107 if_exists(ip,ips,eq(ip->addr,_))\r
1108 {\r
1109 int unshape_this_ip = 0;\r
1110 long avg_mbps_down = ip->traffic_down * 8 / how_much_seconds; \r
1111 long avg_mbps_up = ip->traffic_up * 8 / how_much_seconds;\r
1112 int agreg = 1, print_stats = 1;\r
1113 \r
1114 if(ip->keyword->download_aggregation)\r
1115 {\r
1116 int min_mbps = (ip->min/ip->keyword->download_aggregation)>>10;\r
1117 if(min_mbps < 1)\r
1118 {\r
1119 min_mbps = 1;\r
1120 }\r
1121 \r
1122 if(min_mbps <= avg_mbps_down)\r
1123 {\r
1124 unshape_this_ip = 0;\r
1125 agreg = (int)((float)(avg_mbps_down+1)/min_mbps+.5);\r
1126 ip->max /= agreg;\r
1127 ip->pps_limit /= agreg;\r
1128 printf("Download aggregation 1:%d for %s (min: %lu Mbps avg: %ld Mbps)\n", agreg, ip->name, min_mbps, avg_mbps_down);\r
1129 }\r
1130 else\r
1131 {\r
1132 unshape_this_ip = 1;\r
1133 }\r
1134 }\r
1135 else if(ip->keyword->upload_aggregation)\r
1136 {\r
1137 int min_mbps = (ip->min/ip->keyword->upload_aggregation)>>10;\r
1138 if(min_mbps < 1)\r
1139 {\r
1140 min_mbps = 1;\r
1141 }\r
1142\r
1143 if(min_mbps <= avg_mbps_up)\r
1144 {\r
1145 unshape_this_ip = 0;\r
1146 agreg = (int)((float)(avg_mbps_up+1)/min_mbps+.5);\r
1147 ip->max /= agreg;\r
1148 printf("Upload aggregation 1:%d for %s: (min: %lu Mbps avg: %ld Mbps)\n", agreg, ip->name, min_mbps, avg_mbps_up);\r
1149 }\r
1150 else\r
1151 {\r
1152 unshape_this_ip = 1;\r
1153 }\r
1154 }\r
1155 if(stop_shaping)\r
1156 {\r
1157 unshape_this_ip = 1;\r
1158 }\r
1159 ip->aggregated = agreg; \r
1160 ip->mark = atoi(ptr);\r
1161 if(ip->max < ip->desired || unshape_this_ip || reduce_ceil) /* apply or disable FUP limit immediately.... */\r
1162 {\r
1163 if(unshape_this_ip)\r
1164 {\r
1165 ip->max = ip->desired;\r
1166 if(stop_shaping) /* all limits removed, but not printed with -s (start_shaping) switch */\r
1167 {\r
1168 printf("Removing limit for %s (%s) ", ip->name, ip->addr);\r
1169 }\r
1170 else\r
1171 {\r
1172 print_stats = 0;\r
1173 }\r
1174 }\r
1175 else\r
1176 {\r
1177 printf("Updating %s (%s) ", ip->name, ip->addr);\r
1178 if(reduce_ceil)\r
1179 {\r
1180 ip->max = ip->min + (ip->desired-ip->min)/reduce_ceil;\r
1181 }\r
1182 else if(ip->max < ip->min)\r
1183 {\r
1184 ip->max = ip->min;\r
1185 } \r
1186 }\r
1187 for_each(interface, interfaces)\r
1188 {\r
1189 if(!interface->is_upstream)\r
1190 {\r
1191 if(print_stats)\r
1192 {\r
1193 printf("[down %s: %dk-%dk wants %d]", interface->name, ip->min, ip->max, ip->desired);\r
1194 }\r
1195 sprintf(str, "%s class change dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d quantum %d", \r
1196 tc, interface->name, ip->group, ip->mark, ip->min, ip->max, burst, ip->prio, htb_quantum);\r
1197 safe_run(str);\r
1198 }\r
1199 else\r
1200 {\r
1201 if(print_stats)\r
1202 {\r
1203 printf("[up %s: %dk-%dk wants %dk]", interface->name, (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), \r
1204 (int)((ip->desired/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),\r
1205 (int)((ip->desired/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed));\r
1206 }\r
1207 sprintf(str,"%s class change dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d quantum %d",\r
1208 tc, interface->name, ip->group, ip->mark,\r
1209 (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),\r
1210 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), burst, ip->prio, htb_quantum);\r
1211 safe_run(str);\r
1212 }\r
1213 }\r
1214 if(print_stats)\r
1215 {\r
1216 printf("\n");\r
1217 }\r
1218 }\r
1219 }\r
1220 }\r
1221 }\r
1222 fail\r
1223 { \r
1224 perror(classmap);\r
1225 puts("Warning - classmap file not fund, just generating preview ...");\r
1226 start_shaping=FALSE;\r
1227 stop_shaping=FALSE;\r
1228 }\r
1229 done; /* ugly macro end */\r
1230 }\r
1231 html=preview;\r
1232 json_traffic=json_preview;\r
1233 }\r
1234\r
1235 if(!dry_run && !just_flush)\r
1236 {\r
1237 /*-----------------------------------------------------------------*/\r
1238 printf("Writing json traffic overview %s ... ", json_traffic);\r
1239 /*-----------------------------------------------------------------*/\r
1240 write_json_traffic(json_traffic);\r
1241\r
1242 /*-----------------------------------------------------------------*/\r
1243 printf("Writing statistics into HTML page %s ...\n", html);\r
1244 /*-----------------------------------------------------------------*/\r
1245 write_htmlandlogs(html, d, total, just_preview);\r
1246 printf("\n");\r
1247 }\r
1248\r
1249 if(just_preview)\r
1250 {\r
1251 char swchar='p';\r
1252 if(start_shaping)\r
1253 {\r
1254 swchar='s';\r
1255 }\r
1256 else if(reduce_ceil)\r
1257 {\r
1258 swchar='0'+reduce_ceil; /* -2, -4 */\r
1259 }\r
1260 else if(stop_shaping)\r
1261 {\r
1262 swchar='q';\r
1263 }\r
1264\r
1265 printf("Statistics preview generated (-%c switch) - now exiting ...\n", swchar);\r
1266 exit(0);\r
1267 } \r
1268\r
1269 i=0;\r
1270#ifdef DEBUG\r
1271 printf("%-22s %-15s mark\n","name","ip");\r
1272#endif\r
1273\r
1274 printf("Writing %s", classmap); \r
1275 f = fopen(classmap, "w"); \r
1276 if(f < 0)\r
1277 {\r
1278 perror(classmap);\r
1279 }\r
1280\r
1281 /*-----------------------------------------------------------------*/\r
1282 printf(" + generating iptables and tc classes ... ");\r
1283 /*-----------------------------------------------------------------*/\r
1284\r
1285 for_each(ip, ips) if(ip->mark > 0)\r
1286 {\r
1287 for_each(interface, interfaces)\r
1288 {\r
1289 char *chain;\r
1290 if(idxs)\r
1291 {\r
1292 char *buf;\r
1293 duplicate(ip->addr,buf);\r
1294 if(ip->v6)\r
1295 {\r
1296 buf=index6_id(ip->addr,64-idxtable_bitmask1);\r
1297 }\r
1298 else\r
1299 {\r
1300 buf=index_id(ip->addr,32-idxtable_bitmask1);\r
1301 }\r
1302 \r
1303 string(chain, 6+strlen(buf));\r
1304 sprintf(chain, "%s_", interface->idxprefix);\r
1305 strcat(chain, buf);\r
1306\r
1307 free(buf);\r
1308 }\r
1309 else\r
1310 {\r
1311 chain = interface->chain;\r
1312 }\r
1313\r
1314 /* packet limits - this will be optional in future */\r
1315 if(ip->pps_limit)\r
1316 {\r
1317 sprintf(limit_pkts, "-m limit --limit %d/s --limit-burst %d ", \r
1318 ip->pps_limit, ip->pps_limit);\r
1319 }\r
1320 else\r
1321 {\r
1322 *limit_pkts = 0;\r
1323 } \r
1324\r
1325 #ifdef DEBUG\r
1326 printf("%-22s %-16s %04d %d/s\n", ip->name, ip->addr, ip->mark, ip->pps_limit); \r
1327 #endif\r
1328\r
1329 /* ------------------------------------------------ iptables classify */\r
1330 sprintf(str, "-A %s -%c %s/%d -o %s -j %s%d",\r
1331 chain, (interface->is_upstream?'s':'d'), ip->addr, ip->mask,\r
1332 interface->name, mark_iptables, ip->mark);\r
1333 iptables_save_line(str, ip->v6);\r
1334\r
1335 sprintf(str, "-A %s -%c %s/%d -o %s %s-j ACCEPT",\r
1336 chain, (interface->is_upstream?'s':'d'),ip->addr, ip->mask,\r
1337 interface->name, limit_pkts);\r
1338 iptables_save_line(str, ip->v6);\r
1339\r
1340 if(*limit_pkts) /* non-empty string?*/\r
1341 {\r
1342 /* classify overlimit packets to separate overlimit class */\r
1343 sprintf(str, "-A %s -%c %s/%d -o %s -j %s%d",\r
1344 chain, (interface->is_upstream?'s':'d'), ip->addr, ip->mask,\r
1345 interface->name, mark_iptables, OVERLIMIT_CLASS);\r
1346 iptables_save_line(str, ip->v6);\r
1347\r
1348 sprintf(str, "-A %s -%c %s/%d -o %s -j ACCEPT",\r
1349 chain, (interface->is_upstream?'s':'d'), ip->addr, ip->mask,\r
1350 interface->name);\r
1351 iptables_save_line(str, ip->v6);\r
1352 }\r
1353\r
1354 if(ip->min)\r
1355 {\r
1356 //TODO - min and max should not exceed interface->speed\r
1357 \r
1358 /* -------------------------------------------------------- tc class */\r
1359 #ifdef DEBUG\r
1360 printf("[down: %dk-%dk]", ip->min, ip->max);\r
1361 #endif\r
1362\r
1363 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d quantum %d", \r
1364 tc, interface->name, ip->group, ip->mark, ip->min, ip->max, burst, ip->prio, htb_quantum);\r
1365 safe_run(str);\r
1366\r
1367 if(strcmpi(ip->keyword->leaf_discipline, "none"))\r
1368 {\r
1369 sprintf(str, "%s qdisc add dev %s parent 1:%d handle %d %s", \r
1370 tc, interface->name, ip->mark, ip->mark, ip->keyword->leaf_discipline); /*qos_leaf*/\r
1371 safe_run(str);\r
1372 }\r
1373\r
1374 if(filter_type == 1)\r
1375 {\r
1376 sprintf(str, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",\r
1377 tc, interface->name, ip->mark, ip->mark);\r
1378 safe_run(str);\r
1379 }\r
1380 }\r
1381 else\r
1382 {\r
1383 #ifdef DEBUG\r
1384 printf("(sharing %s)\n", ip->sharing);\r
1385 #endif\r
1386 }\r
1387 i++;\r
1388 }\r
1389 if(ip->min && f > 0)\r
1390 {\r
1391 fprintf(f, "%s %d\n", ip->addr, ip->mark);\r
1392 }\r
1393 }\r
1394 if(f > 0)\r
1395 {\r
1396 puts("done.");\r
1397 fclose(f);\r
1398 }\r
1399\r
1400 for_each(interface, interfaces)\r
1401 {\r
1402 char *chain;\r
1403 if(idxs)\r
1404 {\r
1405 string(chain, STRLEN);\r
1406 sprintf(chain, "%s_common", interface->idxprefix);\r
1407 }\r
1408 else\r
1409 {\r
1410 chain = interface->chain;\r
1411 }\r
1412\r
1413 if(free_min)\r
1414 {\r
1415 final_chain = "ACCEPT";\r
1416\r
1417 sprintf(str, "-A %s -o %s -j %s%d",\r
1418 chain, interface->name, mark_iptables, FREE_CLASS);\r
1419 iptables_save_line(str, IPv4); /* only for IPv4 */\r
1420 }\r
1421\r
1422 sprintf(str,"-A %s -o %s -j %s", chain, interface->name, final_chain);\r
1423 iptables_save_line(str, IPv4);\r
1424 if(ip6prefix)\r
1425 {\r
1426 sprintf(str,"-A %s -o %s -j %s", chain, interface->name, final_chain);\r
1427 iptables_save_line(str, IPv6);\r
1428 }\r
1429\r
1430 if(free_min) /* allocate free bandwith if it is not zero... */ \r
1431 {\r
1432 /*-----------------------------------------------------------------*/\r
1433 puts("Generating free bandwith class ...");\r
1434 /*-----------------------------------------------------------------*/\r
1435 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d quantum %d",\r
1436 tc, interface->name, parent, FREE_CLASS, free_min, free_max,burst, lowest_priority, htb_quantum);\r
1437 safe_run(str);\r
1438 /* tc SFQ */\r
1439 if(strcmpi(qos_leaf, "none"))\r
1440 {\r
1441 sprintf(str,"%s qdisc add dev %s parent 1:%d handle %d %s", tc, interface->name, FREE_CLASS, FREE_CLASS, qos_leaf);\r
1442 safe_run(str);\r
1443 } \r
1444 /* tc handle 1 fw flowid */\r
1445 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d", tc, interface->name, FREE_CLASS, FREE_CLASS);\r
1446 safe_run(str);\r
1447 }\r
1448 /*-----------------------------------------------------------------*/\r
1449 puts("Generating bandwith class for overlimit packets...");\r
1450 /*-----------------------------------------------------------------*/\r
1451 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d quantum %d",\r
1452 tc, interface->name, parent, OVERLIMIT_CLASS, overlimit_min, overlimit_max, burst, lowest_priority, htb_quantum);\r
1453 safe_run(str);\r
1454 } \r
1455 printf("Total IP count: %d\n", i);\r
1456 run_iptables_restore();\r
1457 if(log_file)\r
1458 {\r
1459 fclose(log_file);\r
1460 }\r
1461 return 0;\r
1462 /* that's all folks, thank you for reading it all the way up to this point ;-) */\r
1463 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */\r
1464}\r
This page took 0.245724 seconds and 4 git commands to generate.