2 * Connection oriented routing
3 * Copyright (C) 2007-2010 Michael Blizek
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 DEFINE_SPINLOCK(conn_credits_lock
);
25 /* credit_lock must be held while calling this */
26 int refresh_credits_state(struct neighbor
*nb
)
28 long jiffies_tmp
= jiffies
;
30 __s64 creditrate
= 1000 * ((__s64
)(nb
->creditrate_initial
+
31 nb
->creditrate_earning
- nb
->creditrate_spending
));
33 __s64 crediterrorrate
= 1000 * ((__s64
)(nb
->creditrate_spending
-
34 nb
->creditrate_spending_expected
)) -
36 * tolerance is 50% of creditsrate_initial + 2.5% of
37 * both spending+earning
39 500 * ((__s64
)(nb
->creditrate_initial
)) -
40 25 * ((__s64
)(nb
->creditrate_spending_expected
)) -
41 25 * ((__s64
)(nb
->creditrate_earning
));
43 __s64 debitrate
= 1000 * ((__s64
)(nb
->debitrate_initial
+
44 nb
->debitrate_initial_adj
+ nb
->debitrate_earning
-
45 nb
->debitrate_spending
));
48 __s64 credits_adj
= (jiffies_tmp
- nb
->jiffies_credit_update
) *
49 creditrate
+ nb
->credits_fract
;
51 __s64 creditsd_adj
= (jiffies_tmp
- nb
->jiffies_credit_update
) *
52 crediterrorrate
+ nb
->credits_diff_fract
;
54 __s64 debits_adj
= (jiffies_tmp
- nb
->jiffies_credit_update
) *
55 debitrate
+ nb
->debits_fract
;
58 nb
->jiffies_credit_update
= jiffies_tmp
;
61 if (unlikely(credits_adj
< 0 && (nb
->credits
< -(credits_adj
/HZ
)))) {
63 nb
->credits_fract
= 0;
65 nb
->credits
+= credits_adj
/ HZ
;
66 nb
->credits_fract
= credits_adj
% HZ
;
69 if (unlikely(creditsd_adj
< 0 && (nb
->credits_diff
<
70 -(creditsd_adj
/HZ
)))) {
72 nb
->credits_diff_fract
= 0;
74 nb
->credits_diff
+= creditsd_adj
/ HZ
;
75 nb
->credits_diff_fract
= creditsd_adj
% HZ
;
78 if (unlikely(debits_adj
< 0 && (nb
->debits
< -(debits_adj
/HZ
)))) {
84 nb
->debits
+= debits_adj
/ HZ
;
85 nb
->debits_fract
= debits_adj
% HZ
;
91 void check_credit_state(struct neighbor
*nb
)
96 struct list_head
*currlh
;
99 spin_lock_irqsave( &(nb
->credits_lock
), iflags
);
100 refresh_credits_state(nb
);
101 resetconns
= (nb
->debits
== 0 && ((
102 (__s64
) nb
->debitrate_initial_adj
+
103 (__s64
) nb
->debitrate_earning
-
104 (__s64
) nb
->debitrate_spending
) < 0));
105 spin_unlock_irqrestore( &(nb
->credits_lock
), iflags
);
107 if (likely(resetconns
== 0)) {
108 if (unlikely(sendcredits
))
115 mutex_lock(&(nb
->conn_list_lock
));
116 BUG_ON(list_empty(&(nb
->snd_conn_list
)) && nb
->num_send_conns
!= 0);
117 currlh
= nb
->snd_conn_list
.next
;
119 while (currlh
!= &(nb
->snd_conn_list
)) {
121 struct conn
*sconn
= container_of(currlh
, struct conn
,
123 struct conn
*rconn
= sconn
->reversedir
;
125 mutex_lock(&(rconn
->rcv_lock
));
126 BUG_ON(sconn
->targettype
!= TARGET_OUT
);
127 BUG_ON(rconn
->sourcetype
!= SOURCE_IN
);
129 spin_lock_irqsave(&conn_credits_lock
, iflags
);
130 if (rconn
->targettype
== TARGET_UNCONNECTED
||
131 (rconn
->targettype
== TARGET_SOCK
&&
132 rconn
->target
.sock
.credituser
!= 0))
135 ispaying
= (sconn
->recp_crate
> rconn
->sender_crate
);
136 spin_unlock_irqrestore(&conn_credits_lock
, iflags
);
138 mutex_unlock(&(rconn
->rcv_lock
));
142 * reset_conn must not be called with conn_list_lock
145 mutex_unlock(&(nb
->conn_list_lock
));
149 currlh
= currlh
->next
;
155 int debit_adj_needed(struct neighbor
*nb
)
158 unsigned long iflags
;
160 spin_lock_irqsave( &(nb
->credits_lock
), iflags
);
162 refresh_credits_state(nb
);
164 expected_adj
= nb
->creditrate_initial
- nb
->credits_diff
/10000;
165 if (unlikely((expected_adj
< 0 || nb
->debitrate_initial_adj
< 0) &&
166 ( (expected_adj
* 2 < nb
->debitrate_initial_adj
) ||
167 (expected_adj
> nb
->debitrate_initial_adj
* 2) ))) {
168 nb
->debitrate_initial_adj
= (nb
->debitrate_initial_adj
* 15 +
173 spin_unlock_irqrestore( &(nb
->credits_lock
), iflags
);
178 void set_credits(struct neighbor
*nb
, __u64 credits
, __s32 creditrate_initial
,
179 __u32 creditrate_earning
, __u32 creditrate_spending
)
181 unsigned long iflags
;
183 spin_lock_irqsave( &(nb
->credits_lock
), iflags
);
185 refresh_credits_state(nb
);
187 if (nb
->credits_diff
+ nb
->credits
< credits
)
188 nb
->credits_diff
= 0;
190 nb
->credits_diff
+= nb
->credits
- credits
;
191 nb
->credits
= credits
;
192 nb
->creditrate_initial
= creditrate_initial
;
193 nb
->creditrate_earning
= creditrate_earning
;
194 nb
->creditrate_spending
= creditrate_spending
;
196 spin_unlock_irqrestore( &(nb
->credits_lock
), iflags
);
199 void set_debitrate_initial(struct neighbor
*nb
, __u32 debitrate
)
201 unsigned long iflags
;
203 spin_lock_irqsave( &(nb
->credits_lock
), iflags
);
205 refresh_credits_state(nb
);
206 nb
->debitrate_initial
= debitrate
;
208 spin_unlock_irqrestore( &(nb
->credits_lock
), iflags
);
213 static __u32
credit_exchange_in(struct neighbor
*nb
, __u32 crate_in_raw
)
215 unsigned long iflags
;
217 spin_lock_irqsave( &(nb
->credits_lock
), iflags
);
218 if (unlikely(nb
->debits
== 0))
221 ret
= multiply_div(nb
->credits
, crate_in_raw
, nb
->debits
);
222 spin_unlock_irqrestore( &(nb
->credits_lock
), iflags
);
224 if ((ret
>> 32) != 0)
229 static void refresh_crate_forward(struct conn
*conn
, long jiffies_diff
)
231 __u8 last_bufferstate
= conn
->last_bufferstate
;
235 if (conn
->tos
== TOS_NORMAL
)
237 else if (conn
->tos
== TOS_LATENCY
)
239 else if (conn
->tos
== TOS_THROUGHPUT
)
241 else if (conn
->tos
== TOS_PRIVACY
)
246 /* buffer full shifts 1 bit more so that */
248 BUG_ON(conn
->crate_forward
> (1 << 31));
250 for (;jiffies_diff
< 0;jiffies_diff
--) {
251 if (last_bufferstate
== 0)
252 conn
->crate_forward
= ( ((__u64
) conn
->crate_forward
) *
253 (HZ
<< (shift_base
- 2))) /
256 conn
->crate_forward
= ( ((__u64
) conn
->crate_forward
) *
257 (HZ
<< shift_base
)) /
258 (HZ
<< (shift_base
- 1));
260 if (conn
->crate_forward
> (1 << 31)) {
261 conn
->crate_forward
= (1 << 31);
265 if (conn
->crate_forward
< (1 << 16)) {
266 conn
->crate_forward
= (1 << 16);
272 static int get_crate_forward_grace_period(struct conn
*conn
)
274 if (conn
->tos
== TOS_NORMAL
)
276 if (conn
->tos
== TOS_LATENCY
)
278 if (conn
->tos
== TOS_THROUGHPUT
)
280 if (conn
->tos
== TOS_PRIVACY
)
286 static void refresh_conn_crates(struct conn
*conn
, long jiffies_diff
)
288 if (conn
->sourcetype
== SOURCE_NONE
) {
289 conn
->sender_crate
= conn
->reversedir
->recp_crate
;
290 } else if (conn
->sourcetype
== SOURCE_IN
) {
291 conn
->sender_crate
= credit_exchange_in(conn
->source
.in
.nb
,
292 conn
->source
.in
.crate_in_raw
);
293 } else if (conn
->sourcetype
== SOURCE_SOCK
) {
294 BUG_ON(conn
->reversedir
->target
.sock
.credituser
== 0 &&
295 conn
->targettype
== TARGET_SOCK
&&
296 conn
->reversedir
->recp_crate
!= 0);
299 if ((conn
->source
.sock
.crate
+ conn
->reversedir
->recp_crate
) <
300 conn
->reversedir
->recp_crate
|| (
301 conn
->reversedir
->recp_crate
+
302 conn
->source
.sock
.crate
) > MAX_CREDITRATE_SOCK
)
303 conn
->sender_crate
= MAX_CREDITRATE_SOCK
;
305 conn
->sender_crate
= conn
->reversedir
->recp_crate
+
306 conn
->source
.sock
.crate
;
311 if (conn
->targettype
== TARGET_UNCONNECTED
) {
312 conn
->recp_crate
= conn
->sender_crate
;
313 conn
->reversedir
->sender_crate
= conn
->recp_crate
;
314 } else if (conn
->targettype
== TARGET_SOCK
) {
315 if (conn
->target
.sock
.credituser
== 0) {
316 conn
->recp_crate
= conn
->sender_crate
;
318 refresh_crate_forward(conn
, jiffies_diff
);
319 conn
->recp_crate
= (((__u64
) conn
->sender_crate
) *
320 conn
->crate_forward
) / (1 << 31);
322 conn
->reversedir
->sender_crate
= conn
->recp_crate
+
323 conn
->reversedir
->source
.sock
.crate
;
324 if ((conn
->reversedir
->source
.sock
.crate
+ conn
->recp_crate
) <
325 conn
->recp_crate
|| (conn
->recp_crate
+
326 conn
->reversedir
->source
.sock
.crate
) >
328 conn
->reversedir
->sender_crate
= MAX_CREDITRATE_SOCK
;
329 #warning todo last bufferstate
330 conn
->last_bufferstate
= 0;
331 } else if (conn
->targettype
== TARGET_OUT
) {
332 int grace
= get_crate_forward_grace_period(conn
);
333 if (conn
->target
.out
.jiffies_crate_send
+ grace
>
334 conn
->jiffies_credit_update
) {
335 jiffies_diff
+= conn
->jiffies_credit_update
;
336 jiffies_diff
-= conn
->target
.out
.jiffies_crate_send
;
337 jiffies_diff
-= grace
;
339 if (jiffies_diff
< 0)
342 refresh_crate_forward(conn
, jiffies_diff
);
343 if (((__s32
) (conn
->target
.out
.seqno_nextsend
-
344 conn
->target
.out
.seqno_windowlimit
)) <= 0)
345 conn
->last_bufferstate
= 1;
347 conn
->last_bufferstate
= 0;
348 #warning todo send credits
354 static void _refresh_conn_credits(struct conn
*conn
, long jiffies_diff
)
356 __s64 diff
= 1000 * ((__s64
) conn
->sender_crate
-
357 (__s64
) conn
->recp_crate
) * jiffies_diff
+
360 conn
->credits
+= diff
/ HZ
;
361 conn
->credits_fract
= diff
% HZ
;
365 * locked for access to credits + source.* + target.*
366 * lock both sides, if either source or target is not out/in
368 static __u32
credits_lock_conn(struct conn
*conn
)
371 mutex_lock(&(conn
->rcv_lock
));
372 if (conn
->sourcetype
!= SOURCE_IN
) {
373 mutex_unlock(&(conn
->rcv_lock
));
375 mutex_lock(&(conn
->reversedir
->rcv_lock
));
376 mutex_lock(&(conn
->rcv_lock
));
379 } else if (conn
->targettype
!= TARGET_OUT
) {
380 mutex_lock(&(conn
->reversedir
->rcv_lock
));
387 static void credits_unlock_conn(struct conn
*conn
, __u32 hints
)
389 if ((hints
& 1) != 0)
390 mutex_unlock(&(conn
->rcv_lock
));
391 if ((hints
& 2) != 0)
392 mutex_unlock(&(conn
->reversedir
->rcv_lock
));
393 if ((hints
& 4) != 0)
394 mutex_unlock(&(conn
->rcv_lock
));
397 #warning todo call periodically
398 void refresh_conn_credits(struct conn
*conn
)
400 unsigned long iflags
;
402 __u32 unlockhints
= credits_lock_conn(conn
);
404 if (unlikely(conn
->targettype
== TARGET_SOCK
&&
405 conn
->reversedir
->targettype
== TARGET_SOCK
&&
406 conn
->target
.sock
.credituser
== 0 &&
407 conn
->reversedir
->target
.sock
.credituser
== 0))
409 spin_lock_irqsave(&conn_credits_lock
, iflags
);
411 jiffies_tmp
= jiffies
;
412 _refresh_conn_credits(conn
, jiffies_tmp
- conn
->jiffies_credit_update
);
413 refresh_conn_crates(conn
, jiffies_tmp
- conn
->jiffies_credit_update
);
414 conn
->jiffies_credit_update
= jiffies_tmp
;
416 spin_unlock_irqrestore(&conn_credits_lock
, iflags
);
418 credits_unlock_conn(conn
, unlockhints
);
421 void set_conn_in_crate(struct conn
*rconn
, __u32 crate_in
)
423 unsigned long iflags
;
426 __u32 unlockhints
= credits_lock_conn(rconn
);
427 spin_lock_irqsave(&conn_credits_lock
, iflags
);
429 BUG_ON(rconn
->sourcetype
!= SOURCE_IN
);
431 jiffies_tmp
= jiffies
;
432 _refresh_conn_credits(rconn
, jiffies_tmp
-rconn
->jiffies_credit_update
);
433 rconn
->source
.in
.crate_in_raw
= crate_in
;
434 refresh_conn_crates(rconn
, jiffies_tmp
- rconn
->jiffies_credit_update
);
435 rconn
->jiffies_credit_update
= jiffies_tmp
;
437 spin_unlock_irqrestore(&conn_credits_lock
, iflags
);
438 credits_unlock_conn(rconn
, unlockhints
);
441 MODULE_LICENSE("GPL");