]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/misc-progs/restartshaping.c
git-svn-id: http://svn.ipfire.org/svn/ipfire/IPFire/source@16 ea5c0bd1-69bd-2848...
[people/pmueller/ipfire-2.x.git] / src / misc-progs / restartshaping.c
1 /* IPCop helper program - restartshaping
2 *
3 * This program is distributed under the terms of the GNU General Public
4 * Licence. See the file COPYING for details.
5 *
6 * Copyright (C) 2002-04-09 Mark Wormgoor <mark@wormgoor.com>
7 *
8 * $Id: restartshaping.c,v 1.2.2.5 2005/01/28 13:11:40 riddles Exp $
9 *
10 */
11
12 #include "libsmooth.h"
13 #include "setuid.h"
14 #include <stdio.h>
15 #include <string.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
19 #include <stdlib.h>
20
21 int main(int argc, char *argv[])
22 {
23 FILE *file = NULL, *ifacefile = NULL;
24 struct keyvalue *kv = NULL;
25 int uplink, downlink, count = 0, r2q = 10;
26 char command[STRING_SIZE];
27 char iface[STRING_SIZE] = "";
28 char s[STRING_SIZE];
29 char *result;
30 char proto[STRING_SIZE];
31 char *protocol;
32 char *port;
33 char *prio;
34 char *enabled;
35
36 if (!(initsetuid())) {
37 fprintf(stderr, "Cannot run setuid\n");
38 exit(1);
39 }
40
41 /* Init the keyvalue structure */
42 kv=initkeyvalues();
43
44 /* Read in the current values */
45 if (!readkeyvalues(kv, CONFIG_ROOT "/shaping/settings"))
46 {
47 fprintf(stderr, "Cannot read shaping settings\n");
48 goto EXIT;
49 }
50
51 /* See what interface there is */
52 if ((ifacefile = fopen(CONFIG_ROOT "/red/iface", "r")))
53 {
54 fgets(iface, STRING_SIZE, ifacefile);
55 if (iface[strlen(iface) - 1] == '\n')
56 iface[strlen(iface) - 1] = '\0';
57 fclose (ifacefile);
58 } else {
59 fprintf(stderr, "Couldn't open iface file\n");
60 return(1);
61 }
62
63 if (strspn(iface, LETTERS_NUMBERS) != strlen(iface))
64 {
65 fprintf(stderr, "Bad iface: %s\n", iface);
66 goto EXIT;
67 }
68
69 /* Find the VALID value */
70 if (!findkey(kv, "VALID", s))
71 {
72 fprintf(stderr, "Cannot read VALID\n");
73 goto EXIT;
74 }
75
76 /* Check if config is VALID */
77 if (! strcmp(s, "yes")==0)
78 goto EXIT;
79
80 snprintf(command, STRING_SIZE-1, "/sbin/tc qdisc del dev %s root", iface);
81 safe_system(command);
82 snprintf(command, STRING_SIZE-1, "/sbin/tc qdisc del dev %s ingress", iface);
83 safe_system(command);
84
85 /* Find the ENABLE value */
86 if (!findkey(kv, "ENABLE", s))
87 {
88 fprintf(stderr, "Cannot read ENABLE\n");
89 goto EXIT;
90 }
91
92 /* Check if shaping is ENABLED */
93 if (! strcmp(s, "on")==0)
94 goto EXIT;
95
96 /* Find the UPLINK value */
97 if (!findkey(kv, "UPLINK", s))
98 {
99 fprintf(stderr, "Cannot read UPLINK\n");
100 goto EXIT;
101 }
102 uplink = atoi(s);
103 if (! uplink > 0) {
104 fprintf(stderr, "Invalid value for UPLINK\n");
105 goto EXIT;
106 }
107 /* In some limited testing, it was shown that
108 r2q = ( uplink * 1024 / 1500 );
109 * produced error messages from the kernel saying r2q needed to be
110 * changed. 1500 is taken as the MTU, but it seems that 16384 works
111 * better. -Alan.
112 */
113 r2q = ( uplink * 1024 / 16384 );
114 uplink = (uplink * 100) / 101;
115
116 /* Find the DOWNLINK value */
117 if (!findkey(kv, "DOWNLINK", s))
118 {
119 fprintf(stderr, "Cannot read DOWNLINK\n");
120 goto EXIT;
121 }
122 downlink = atoi(s);
123 if (! downlink > 0) {
124 fprintf(stderr, "Invalid value for DOWNLINK\n");
125 goto EXIT;
126 }
127 downlink = (downlink * 200) / 201;
128
129 /* Uplink classes */
130 snprintf(command, STRING_SIZE-1, "/sbin/tc qdisc add dev %s root handle 1: htb default 20 r2q %d", iface, r2q);
131 safe_system(command);
132 snprintf(command, STRING_SIZE-1, "/sbin/tc class add dev %s parent 1: classid 1:1 htb rate %dkbit", iface, uplink);
133 safe_system(command);
134 snprintf(command, STRING_SIZE-1, "/sbin/tc class add dev %s parent 1:1 classid 1:10 htb rate %dkbit ceil %dkbit prio 1", iface, (8 * uplink) / 10, uplink);
135 safe_system(command);
136 snprintf(command, STRING_SIZE-1, "/sbin/tc class add dev %s parent 1:1 classid 1:20 htb rate %dkbit ceil %dkbit prio 2", iface, (6 * uplink) / 10, uplink);
137 safe_system(command);
138 snprintf(command, STRING_SIZE-1, "/sbin/tc class add dev %s parent 1:1 classid 1:30 htb rate %dkbit ceil %dkbit prio 3", iface, (4 * uplink) / 10, uplink);
139 safe_system(command);
140
141 /* Uplink Stochastic fairness queue */
142 snprintf(command, STRING_SIZE-1, "/sbin/tc qdisc add dev %s parent 1:10 handle 10: sfq perturb 10", iface);
143 safe_system(command);
144 snprintf(command, STRING_SIZE-1, "/sbin/tc qdisc add dev %s parent 1:20 handle 20: sfq perturb 10", iface);
145 safe_system(command);
146 snprintf(command, STRING_SIZE-1, "/sbin/tc qdisc add dev %s parent 1:30 handle 30: sfq perturb 10", iface);
147 safe_system(command);
148
149 /* TOS Minimum Delay and ICMP traffic for high priority queue */
150 snprintf(command, STRING_SIZE-1, "/sbin/tc filter add dev %s parent 1:0 protocol ip prio 10 u32 match ip tos 0x10 0xff flowid 1:10", iface);
151 safe_system(command);
152 snprintf(command, STRING_SIZE-1, "/sbin/tc filter add dev %s parent 1:0 protocol ip prio 10 u32 match ip protocol 1 0xff flowid 1:10", iface);
153 safe_system(command);
154
155 /* ACK packets for high priority queue (to speed up downloads) */
156 snprintf(command, STRING_SIZE-1, "/sbin/tc filter add dev %s parent 1: protocol ip prio 10 u32 match ip protocol 6 0xff match u8 0x05 0x0f at 0 match u16 0x0000 0xffc0 at 2 match u8 0x10 0xff at 33 flowid 1:10", iface);
157 safe_system(command);
158
159 file = fopen(CONFIG_ROOT "/shaping/config", "r");
160 if (file)
161 {
162 while (fgets(s, STRING_SIZE, file) != NULL)
163 {
164 if (s[strlen(s) - 1] == '\n')
165 s[strlen(s) - 1] = '\0';
166 result = strtok(s, ",");
167
168 count = 0;
169 protocol = NULL;
170 port = NULL;
171 prio = NULL;
172 enabled = NULL;
173 while (result)
174 {
175 if (count == 0)
176 protocol = result;
177 else if (count == 1)
178 port = result;
179 else if (count == 2)
180 prio = result;
181 else if (count == 3)
182 enabled = result;
183 count++;
184 result = strtok(NULL, ",");
185 }
186 if (!(protocol && port && prio && enabled))
187 break;
188 if (strcmp(protocol, "tcp") == 0) {
189 strcpy(proto, "6");
190 } else if (strcmp(protocol, "udp") == 0) {
191 strcpy(proto, "17");
192 } else {
193 fprintf(stderr, "Bad protocol: %s\n", protocol);
194 goto EXIT;
195 }
196 if (strspn(port, PORT_NUMBERS) != strlen(port))
197 {
198 fprintf(stderr, "Bad port: %s\n", port);
199 goto EXIT;
200 }
201 if (strspn(prio, NUMBERS) != strlen(prio))
202 {
203 fprintf(stderr, "Bad priority: %s\n", prio);
204 goto EXIT;
205 }
206
207 if (strcmp(enabled, "on") == 0)
208 {
209 snprintf(command, STRING_SIZE-1, "/sbin/tc filter add dev %s parent 1: protocol ip prio 14 u32 match ip protocol %s 0xff match ip dport %s 0xffff flowid 1:%s", iface, proto, port, prio);
210
211 safe_system(command);
212
213 snprintf(command, STRING_SIZE-1, "/sbin/tc filter add dev %s parent 1: protocol ip prio 15 u32 match ip protocol %s 0xff match ip sport %s 0xffff flowid 1:%s", iface, proto, port, prio);
214
215 safe_system(command);
216 }
217 }
218 }
219
220 /* Setting everything else to the default queue */
221 snprintf(command, STRING_SIZE-1, "/sbin/tc filter add dev %s parent 1: protocol ip prio 18 u32 match ip dst 0.0.0.0/0 flowid 1:20", iface);
222 safe_system(command);
223
224 /* Downlink Section */
225 snprintf(command, STRING_SIZE-1, "/sbin/tc qdisc add dev %s handle ffff: ingress", iface);
226 safe_system(command);
227 snprintf(command, STRING_SIZE-1, "/sbin/tc filter add dev %s parent ffff: protocol ip prio 50 u32 match ip src 0.0.0.0/0 police rate %dkbit burst 10k drop flowid :1", iface, downlink);
228 safe_system(command);
229
230 EXIT:
231 if (kv) freekeyvalues(kv);
232 if (file) fclose(file);
233 return 0;
234 }