]>
Commit | Line | Data |
---|---|---|
aba5acdf SH |
1 | /* |
2 | * tc_core.c TC core library. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or | |
5 | * modify it under the terms of the GNU General Public License | |
6 | * as published by the Free Software Foundation; either version | |
7 | * 2 of the License, or (at your option) any later version. | |
8 | * | |
9 | * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> | |
10 | * | |
11 | */ | |
12 | ||
13 | #include <stdio.h> | |
14 | #include <stdlib.h> | |
ae717baf | 15 | #include <stdint.h> |
aba5acdf | 16 | #include <unistd.h> |
aba5acdf SH |
17 | #include <fcntl.h> |
18 | #include <math.h> | |
19 | #include <sys/socket.h> | |
20 | #include <netinet/in.h> | |
21 | #include <arpa/inet.h> | |
22 | #include <string.h> | |
23 | ||
abf70ef4 | 24 | #include "utils.h" |
aba5acdf | 25 | #include "tc_core.h" |
292f29b4 | 26 | #include <linux/atm.h> |
aba5acdf | 27 | |
aba5acdf | 28 | static double tick_in_usec = 1; |
147e1d4b | 29 | static double clock_factor = 1; |
aba5acdf | 30 | |
32a121cb | 31 | int tc_core_time2big(unsigned int time) |
fa565130 | 32 | { |
8f34caaf | 33 | __u64 t = time; |
fa565130 SH |
34 | |
35 | t *= tick_in_usec; | |
36 | return (t >> 32) != 0; | |
37 | } | |
38 | ||
39 | ||
32a121cb | 40 | unsigned int tc_core_time2tick(unsigned int time) |
aba5acdf | 41 | { |
8f34caaf | 42 | return time*tick_in_usec; |
aba5acdf SH |
43 | } |
44 | ||
32a121cb | 45 | unsigned int tc_core_tick2time(unsigned int tick) |
aba5acdf SH |
46 | { |
47 | return tick/tick_in_usec; | |
48 | } | |
49 | ||
32a121cb | 50 | unsigned int tc_core_time2ktime(unsigned int time) |
f0bda7e5 | 51 | { |
147e1d4b | 52 | return time * clock_factor; |
f0bda7e5 PM |
53 | } |
54 | ||
32a121cb | 55 | unsigned int tc_core_ktime2time(unsigned int ktime) |
f0bda7e5 | 56 | { |
147e1d4b | 57 | return ktime / clock_factor; |
f0bda7e5 PM |
58 | } |
59 | ||
32a121cb | 60 | unsigned int tc_calc_xmittime(__u64 rate, unsigned int size) |
aba5acdf | 61 | { |
8334bb32 | 62 | return tc_core_time2tick(TIME_UNITS_PER_SEC*((double)size/(double)rate)); |
aba5acdf SH |
63 | } |
64 | ||
32a121cb | 65 | unsigned int tc_calc_xmitsize(__u64 rate, unsigned int ticks) |
76dc0aa2 | 66 | { |
8f34caaf | 67 | return ((double)rate*tc_core_tick2time(ticks))/TIME_UNITS_PER_SEC; |
76dc0aa2 PM |
68 | } |
69 | ||
292f29b4 JDB |
70 | /* |
71 | * The align to ATM cells is used for determining the (ATM) SAR | |
72 | * alignment overhead at the ATM layer. (SAR = Segmentation And | |
73 | * Reassembly). This is for example needed when scheduling packet on | |
74 | * an ADSL connection. Note that the extra ATM-AAL overhead is _not_ | |
75 | * included in this calculation. This overhead is added in the kernel | |
76 | * before doing the rate table lookup, as this gives better precision | |
77 | * (as the table will always be aligned for 48 bytes). | |
78 | * --Hawk, d.7/11-2004. <hawk@diku.dk> | |
79 | */ | |
32a121cb | 80 | static unsigned int tc_align_to_atm(unsigned int size) |
292f29b4 JDB |
81 | { |
82 | int linksize, cells; | |
32a121cb | 83 | |
292f29b4 JDB |
84 | cells = size / ATM_CELL_PAYLOAD; |
85 | if ((size % ATM_CELL_PAYLOAD) > 0) | |
86 | cells++; | |
87 | ||
88 | linksize = cells * ATM_CELL_SIZE; /* Use full cell size to add ATM tax */ | |
89 | return linksize; | |
90 | } | |
91 | ||
32a121cb | 92 | static unsigned int tc_adjust_size(unsigned int sz, unsigned int mpu, enum link_layer linklayer) |
839c8456 JK |
93 | { |
94 | if (sz < mpu) | |
95 | sz = mpu; | |
96 | ||
97 | switch (linklayer) { | |
98 | case LINKLAYER_ATM: | |
99 | return tc_align_to_atm(sz); | |
100 | case LINKLAYER_ETHERNET: | |
101 | default: | |
32a121cb | 102 | /* No size adjustments on Ethernet */ |
839c8456 JK |
103 | return sz; |
104 | } | |
105 | } | |
106 | ||
3e92ff52 JDB |
107 | /* Notice, the rate table calculated here, have gotten replaced in the |
108 | * kernel and is no-longer used for lookups. | |
109 | * | |
110 | * This happened in kernel release v3.8 caused by kernel | |
111 | * - commit 56b765b79 ("htb: improved accuracy at high rates"). | |
112 | * This change unfortunately caused breakage of tc overhead and | |
113 | * linklayer parameters. | |
114 | * | |
115 | * Kernel overhead handling got fixed in kernel v3.10 by | |
116 | * - commit 01cb71d2d47 (net_sched: restore "overhead xxx" handling) | |
117 | * | |
118 | * Kernel linklayer handling got fixed in kernel v3.11 by | |
119 | * - commit 8a8e3d84b17 (net_sched: restore "linklayer atm" handling) | |
120 | */ | |
121 | ||
aba5acdf SH |
122 | /* |
123 | rtab[pkt_len>>cell_log] = pkt_xmit_time | |
124 | */ | |
125 | ||
292f29b4 | 126 | int tc_calc_rtable(struct tc_ratespec *r, __u32 *rtab, |
32a121cb | 127 | int cell_log, unsigned int mtu, |
292f29b4 | 128 | enum link_layer linklayer) |
aba5acdf SH |
129 | { |
130 | int i; | |
32a121cb SH |
131 | unsigned int sz; |
132 | unsigned int bps = r->rate; | |
133 | unsigned int mpu = r->mpu; | |
aba5acdf SH |
134 | |
135 | if (mtu == 0) | |
136 | mtu = 2047; | |
137 | ||
138 | if (cell_log < 0) { | |
139 | cell_log = 0; | |
292f29b4 | 140 | while ((mtu >> cell_log) > 255) |
aba5acdf SH |
141 | cell_log++; |
142 | } | |
292f29b4 | 143 | |
32a121cb | 144 | for (i = 0; i < 256; i++) { |
839c8456 | 145 | sz = tc_adjust_size((i + 1) << cell_log, mpu, linklayer); |
476daa72 | 146 | rtab[i] = tc_calc_xmittime(bps, sz); |
aba5acdf | 147 | } |
292f29b4 | 148 | |
e9e9365b | 149 | r->cell_align = -1; |
32a121cb | 150 | r->cell_log = cell_log; |
3e92ff52 | 151 | r->linklayer = (linklayer & TC_LINKLAYER_MASK); |
aba5acdf SH |
152 | return cell_log; |
153 | } | |
154 | ||
839c8456 JK |
155 | /* |
156 | stab[pkt_len>>cell_log] = pkt_xmit_size>>size_log | |
157 | */ | |
158 | ||
159 | int tc_calc_size_table(struct tc_sizespec *s, __u16 **stab) | |
160 | { | |
161 | int i; | |
162 | enum link_layer linklayer = s->linklayer; | |
163 | unsigned int sz; | |
164 | ||
165 | if (linklayer <= LINKLAYER_ETHERNET && s->mpu == 0) { | |
166 | /* don't need data table in this case (only overhead set) */ | |
167 | s->mtu = 0; | |
168 | s->tsize = 0; | |
169 | s->cell_log = 0; | |
170 | s->cell_align = 0; | |
171 | *stab = NULL; | |
172 | return 0; | |
173 | } | |
174 | ||
175 | if (s->mtu == 0) | |
176 | s->mtu = 2047; | |
177 | if (s->tsize == 0) | |
178 | s->tsize = 512; | |
179 | ||
180 | s->cell_log = 0; | |
181 | while ((s->mtu >> s->cell_log) > s->tsize - 1) | |
182 | s->cell_log++; | |
183 | ||
184 | *stab = malloc(s->tsize * sizeof(__u16)); | |
185 | if (!*stab) | |
186 | return -1; | |
187 | ||
188 | again: | |
189 | for (i = s->tsize - 1; i >= 0; i--) { | |
190 | sz = tc_adjust_size((i + 1) << s->cell_log, s->mpu, linklayer); | |
191 | if ((sz >> s->size_log) > UINT16_MAX) { | |
192 | s->size_log++; | |
193 | goto again; | |
194 | } | |
195 | (*stab)[i] = sz >> s->size_log; | |
196 | } | |
197 | ||
32a121cb | 198 | s->cell_align = -1; /* Due to the sz calc */ |
839c8456 JK |
199 | return 0; |
200 | } | |
201 | ||
d1f28cf1 | 202 | int tc_core_init(void) |
aba5acdf | 203 | { |
147e1d4b PM |
204 | FILE *fp; |
205 | __u32 clock_res; | |
206 | __u32 t2us; | |
207 | __u32 us2t; | |
aba5acdf | 208 | |
147e1d4b | 209 | fp = fopen("/proc/net/psched", "r"); |
aba5acdf SH |
210 | if (fp == NULL) |
211 | return -1; | |
212 | ||
147e1d4b | 213 | if (fscanf(fp, "%08x%08x%08x", &t2us, &us2t, &clock_res) != 3) { |
aba5acdf SH |
214 | fclose(fp); |
215 | return -1; | |
216 | } | |
217 | fclose(fp); | |
147e1d4b PM |
218 | |
219 | /* compatibility hack: for old iproute binaries (ignoring | |
220 | * the kernel clock resolution) the kernel advertises a | |
221 | * tick multiplier of 1000 in case of nano-second resolution, | |
222 | * which really is 1. */ | |
223 | if (clock_res == 1000000000) | |
224 | t2us = us2t; | |
225 | ||
226 | clock_factor = (double)clock_res / TIME_UNITS_PER_SEC; | |
227 | tick_in_usec = (double)t2us / us2t * clock_factor; | |
aba5acdf SH |
228 | return 0; |
229 | } |