2 * Connection oriented routing
3 * Copyright (C) 2007-2011 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(credits_list_lock
);
24 LIST_HEAD(credit_refresh_conns
);
25 static struct delayed_work credit_refresh_work
;
26 static int refresh_running
= 0;
28 static inline __s64
mul_saturated_signed(__s64 a
, __u64 b
)
31 if (unlikely(res
/ a
!= b
)) {
40 static __u64
decay_credits(__u64 credits
)
42 int decay_rate
= (CREDIT_DECAYTIME_HOURS
* 3) / 2;
43 if (unlikely(decay_rate
== 0))
45 return credits
- credits
/decay_rate
;
48 __u32
creditrate_initial(void)
50 __u64 rate
= (CREDITS_TOTAL
- decay_credits(CREDITS_TOTAL
)) / 3600;
51 if (unlikely((rate
>> 32) > 0))
56 /* credit_lock must be held while calling this */
57 static void refresh_credits_state(struct neighbor
*nb
)
59 unsigned long jiffies_tmp
= jiffies
;
64 if (jiffies_tmp
== nb
->jiffies_credit_update
)
67 if (unlikely(nb
->creditrate_earning
>= (1LL << 63)))
70 creditrate
= nb
->creditrate_earning
;
72 if (unlikely(creditrate
- nb
->creditrate_spending
> creditrate
))
75 creditrate
-= nb
->creditrate_spending
;
77 if (unlikely(creditrate
+ nb
->creditrate_initial
< creditrate
))
80 creditrate
+= nb
->creditrate_initial
;
82 credits_adj
= mul_saturated_signed(creditrate
, jiffies_tmp
-
83 nb
->jiffies_credit_update
);
85 if (unlikely(credits_adj
+ nb
->credits_fract
< credits_adj
)) {
86 credits_adj
= S64_MAX
;
88 credits_adj
+= nb
->credits_fract
;
91 if (unlikely((credits_adj
< 0 && (nb
->credits
< -(credits_adj
/HZ
))) ||
92 credits_adj
== S64_MIN
)) {
94 nb
->credits_fract
= 0;
95 } else if (unlikely(credits_adj
> 0 && (nb
->credits
+ credits_adj
/HZ
) <
98 nb
->credits_fract
= 0;
100 nb
->credits
+= credits_adj
/ HZ
;
101 nb
->credits_fract
= credits_adj
% HZ
;
104 nb
->jiffies_credit_update
= jiffies_tmp
;
106 if (unlikely(time_after(nb
->jiffies_credit_decay
+ 3600*HZ
,
108 nb
->credits
= decay_credits(nb
->credits
);
110 nb
->jiffies_credit_decay
+= 3600*HZ
;
111 if (unlikely(time_after(nb
->jiffies_credit_decay
+ 3600*HZ
,
113 nb
->jiffies_credit_decay
= jiffies_tmp
- 3600*HZ
;
117 void set_creditrate_initial(struct neighbor
*nb
, __u32 creditrate
)
119 unsigned long iflags
;
121 spin_lock_irqsave(&(nb
->credits_lock
), iflags
);
122 refresh_credits_state(nb
);
123 nb
->creditrate_initial
= creditrate
;
124 spin_unlock_irqrestore(&(nb
->credits_lock
), iflags
);
127 static __u64
decay_time_to_crate(struct neighbor
*nb
, __u16 decay_time_raw
)
129 __u64 decay_time
= dec_log_300_24(decay_time_raw
);
132 return nb
->credits
/ (decay_time
* 3 / 2);
135 #warning todo exchange tax
136 static __u16
crate_to_decay_time(struct neighbor
*nb
, __u64 crate_out
)
139 return enc_log_300_24(0);
140 return enc_log_300_24(nb
->credits
/ (crate_out
/ 3 * 2));
143 static void refresh_crate_forward(struct conn
*cn_lc
, long jiffies_diff
)
145 __u8 last_bufferstate
= cn_lc
->last_bufferstate
;
149 if (cn_lc
->tos
== TOS_NORMAL
)
151 else if (cn_lc
->tos
== TOS_LATENCY
)
153 else if (cn_lc
->tos
== TOS_THROUGHPUT
)
155 else if (cn_lc
->tos
== TOS_PRIVACY
)
161 * buffer full shifts 1 bit more so only about 1/3rd if there is no
165 BUG_ON(cn_lc
->crate_forward
> (1 << 31));
167 for (;jiffies_diff
< 0;jiffies_diff
--) {
168 if (last_bufferstate
== 0)
169 cn_lc
->crate_forward
= ( ((__u64
) cn_lc
->crate_forward
) *
170 (HZ
<< (shift_base
- 2))) /
173 cn_lc
->crate_forward
= ( ((__u64
) cn_lc
->crate_forward
) *
174 (HZ
<< shift_base
)) /
175 (HZ
<< (shift_base
- 1));
177 if (cn_lc
->crate_forward
> (1 << 31)) {
178 cn_lc
->crate_forward
= (1 << 31);
182 if (cn_lc
->crate_forward
< (1 << 16)) {
183 cn_lc
->crate_forward
= (1 << 16);
188 cn_lc
->crate_out
= multiply_div(cn_lc
->crate_in
, cn_lc
->crate_forward
,
192 static int decaytime_send_needed(struct conn
*trgt_out_lc
, __u16
*decaytime
)
196 if (trgt_out_lc
->target
.out
.decaytime_send_allowed
== 0)
199 *decaytime
= crate_to_decay_time(trgt_out_lc
->target
.out
.nb
,
200 trgt_out_lc
->crate_out
);
202 if (unlikely(trgt_out_lc
->target
.out
.conn_id
== 0)) {
203 trgt_out_lc
->reversedir
->source
.in
.decaytime
= *decaytime
;
204 trgt_out_lc
->target
.out
.decaytime_last
= *decaytime
;
205 trgt_out_lc
->target
.out
.decaytime_send_allowed
= 0;
209 if (*decaytime
> trgt_out_lc
->target
.out
.decaytime_last
)
210 diff
= *decaytime
- trgt_out_lc
->target
.out
.decaytime_last
;
211 if (*decaytime
< trgt_out_lc
->target
.out
.decaytime_last
)
212 diff
= trgt_out_lc
->target
.out
.decaytime_last
- *decaytime
;
214 if (diff
!= 0 && (*decaytime
== 0 ||
215 trgt_out_lc
->target
.out
.decaytime_last
== 0))
218 if (trgt_out_lc
->tos
== TOS_PRIVACY
) {
234 static __u64
newnbrate(__u64 nbrate
, __u64 oldconnrate
, __u64 newconnrate
)
236 if (unlikely(nbrate
< oldconnrate
))
239 nbrate
-= oldconnrate
;
241 if (unlikely(nbrate
+ newconnrate
< nbrate
))
244 nbrate
+= newconnrate
;
249 static void refresh_conn_crate_out(struct conn
*trgt_out_lc
,
250 unsigned long jiffies_diff
)
252 unsigned long iflags
;
259 if (likely(trgt_out_lc
->target
.out
.conn_id
!= 0)) {
260 refresh_crate_forward(trgt_out_lc
, jiffies_diff
);
262 if (((__s32
) (trgt_out_lc
->target
.out
.seqno_nextsend
-
263 trgt_out_lc
->target
.out
.seqno_windowlimit
)) <=0)
264 trgt_out_lc
->last_bufferstate
= 1;
266 trgt_out_lc
->last_bufferstate
= 0;
269 spin_lock_irqsave(&(trgt_out_lc
->target
.out
.nb
->credits_lock
), iflags
);
271 oldrate
= trgt_out_lc
->crate_out
;
272 refresh_credits_state(trgt_out_lc
->target
.out
.nb
);
273 trgt_out_lc
->target
.out
.nb
->creditrate_spending
= newnbrate(
274 trgt_out_lc
->target
.out
.nb
->creditrate_spending
,
275 oldrate
, trgt_out_lc
->crate_out
);
277 send
= decaytime_send_needed(trgt_out_lc
, &crate
);
279 spin_unlock_irqrestore(&(trgt_out_lc
->target
.out
.nb
->credits_lock
),
282 if (unlikely(send
!= 0)) {
283 send_decaytime(trgt_out_lc
, (send
== 2), crate
);
288 static void refresh_conn_crate_in(struct conn
*src_in_lc
)
290 unsigned long iflags
;
292 __u64 oldrate
= src_in_lc
->crate_in
;
294 spin_lock_irqsave(&(src_in_lc
->source
.in
.nb
->credits_lock
), iflags
);
296 refresh_credits_state(src_in_lc
->source
.in
.nb
);
298 src_in_lc
->crate_in
= decay_time_to_crate(src_in_lc
->source
.in
.nb
,
299 src_in_lc
->source
.in
.decaytime
);
300 src_in_lc
->source
.in
.nb
->creditrate_earning
= newnbrate(
301 src_in_lc
->source
.in
.nb
->creditrate_earning
, oldrate
,
302 src_in_lc
->crate_in
);
304 spin_unlock_irqrestore(&(src_in_lc
->source
.in
.nb
->credits_lock
),
308 static void refresh_conn_crates(struct conn
*cn_lc
, unsigned long jiffies_diff
)
310 /* set conn->crate_in */
311 if (cn_lc
->sourcetype
== SOURCE_NONE
) {
312 cn_lc
->crate_in
= cn_lc
->reversedir
->crate_out
;
313 } else if (cn_lc
->sourcetype
== SOURCE_IN
) {
314 refresh_conn_crate_in(cn_lc
);
315 } else if (cn_lc
->sourcetype
== SOURCE_SOCK
) {
316 if (cn_lc
->reversedir
->target
.sock
.credituser
== 1)
317 cn_lc
->crate_in
= cn_lc
->reversedir
->crate_out
;
318 else if ((cn_lc
->source
.sock
.crate
+
319 cn_lc
->reversedir
->crate_out
) <
320 cn_lc
->reversedir
->crate_out
)
321 cn_lc
->crate_in
= -1;
323 cn_lc
->crate_in
= cn_lc
->reversedir
->crate_out
+
324 cn_lc
->source
.sock
.crate
;
329 /* set conn->crate_forward + conn->crate_out */
330 if (cn_lc
->targettype
== TARGET_UNCONNECTED
) {
331 cn_lc
->crate_out
= cn_lc
->crate_in
;
332 } else if (cn_lc
->targettype
== TARGET_SOCK
) {
333 if (cn_lc
->target
.sock
.credituser
== 0) {
334 cn_lc
->crate_out
= cn_lc
->crate_in
;
336 refresh_crate_forward(cn_lc
, jiffies_diff
);
337 cn_lc
->last_bufferstate
= (
338 cn_lc
->reversedir
->source
.sock
.wait_len
341 } else if (cn_lc
->targettype
== TARGET_OUT
) {
342 refresh_conn_crate_out(cn_lc
, jiffies_diff
);
348 static void _refresh_conn_credits(struct conn
*cn_lc
)
350 unsigned long jiffies_tmp
= jiffies
;
351 unsigned long jiffies_diff
= jiffies_tmp
- cn_lc
->jiffies_credit_update
;
353 if (jiffies_diff
== 0)
356 #warning todo rates in in secs
358 if (unlikely(cn_lc
->crate_out
> cn_lc
->crate_in
)) {
359 __u64 diff
= cn_lc
->crate_out
- cn_lc
->crate_in
;
360 if (unlikely((diff
* jiffies_diff
) / jiffies_diff
!= diff
))
363 diff
*= jiffies_diff
;
365 if (unlikely(cn_lc
->credits
- diff
> cn_lc
->credits
))
368 cn_lc
->credits
-= diff
;
370 __u64 diff
= cn_lc
->crate_in
- cn_lc
->crate_out
;
371 if (unlikely((diff
* jiffies_diff
) / jiffies_diff
!= diff
))
374 diff
*= jiffies_diff
;
376 if (unlikely(cn_lc
->credits
+ diff
< cn_lc
->credits
))
379 cn_lc
->credits
+= diff
;
383 refresh_conn_crates(cn_lc
, jiffies_tmp
- cn_lc
->jiffies_credit_update
);
385 cn_lc
->jiffies_credit_update
= jiffies_tmp
;
388 static void credits_unlock_conn(struct conn
*cn
, __u32 hints
)
390 if ((hints
& 1) != 0)
391 mutex_unlock(&(cn
->rcv_lock
));
392 if ((hints
& 2) != 0)
393 mutex_unlock(&(cn
->reversedir
->rcv_lock
));
394 if ((hints
& 4) != 0)
395 mutex_unlock(&(cn
->rcv_lock
));
398 static __u32
credits_lock_conn(struct conn
*cn
)
400 mutex_lock(&(cn
->rcv_lock
));
401 if (cn
->sourcetype
== SOURCE_IN
&& cn
->targettype
== TARGET_OUT
) {
402 if (likely(cn
->target
.out
.conn_id
!= 0))
407 mutex_lock(&(cn
->reversedir
->rcv_lock
));
410 mutex_unlock(&(cn
->rcv_lock
));
412 mutex_lock(&(cn
->reversedir
->rcv_lock
));
413 mutex_lock(&(cn
->rcv_lock
));
419 int refresh_conn_credits(struct conn
*cn
, int fromperiodic
, int locked
)
421 unsigned long iflags
;
422 __u32 unlockhints
= 0;
426 if (likely(locked
== 0))
427 unlockhints
= credits_lock_conn(cn
);
429 if (atomic_read(&(cn
->isreset
)) != 0) {
436 /* quit if not time for refresh yet */
437 unsigned long jiffies_tmp
= jiffies
;
438 if (time_after(cn
->jiffies_credit_update
+
439 HZ
*CREDIT_REFRESHINTERVAL_SEC
, jiffies_tmp
)) {
440 int alreadyrefreshed
;
442 spin_lock_irqsave(&credits_list_lock
, iflags
);
443 alreadyrefreshed
= &(cn
->credit_list
) !=
444 credit_refresh_conns
.next
;
445 spin_unlock_irqrestore(&credits_list_lock
, iflags
);
447 if (unlikely(alreadyrefreshed
))
450 rc
= cn
->jiffies_credit_update
- jiffies_tmp
;
453 if (rc
> HZ
* CREDIT_REFRESHINTERVAL_SEC
)
454 rc
= HZ
* CREDIT_REFRESHINTERVAL_SEC
;
459 if (cn
->targettype
== TARGET_UNCONNECTED
|| (
460 cn
->targettype
== TARGET_SOCK
&&
461 cn
->target
.sock
.credituser
== 0)) {
462 if (unlikely(cn
->in_credit_list
)) {
463 spin_lock_irqsave(&credits_list_lock
, iflags
);
464 list_del(&(cn
->credit_list
));
465 cn
->in_credit_list
= 0;
466 spin_unlock_irqrestore(&credits_list_lock
, iflags
);
470 if (cn
->sourcetype
== SOURCE_NONE
|| (
471 cn
->sourcetype
== SOURCE_SOCK
&&
472 cn
->reversedir
->target
.sock
.credituser
== 0))
478 spin_lock_irqsave(&credits_list_lock
, iflags
);
480 if (unlikely(cn
->in_credit_list
== 0)) {
481 cn
->in_credit_list
= 1;
482 kref_get(&(cn
->ref
));
483 if (refresh_running
== 0) {
484 schedule_delayed_work(&credit_refresh_work
, HZ
*
485 CREDIT_REFRESHINTERVAL_SEC
);
489 list_del(&(cn
->credit_list
));
491 list_add_tail(&(cn
->credit_list
), &credit_refresh_conns
);
494 spin_unlock_irqrestore(&credits_list_lock
, iflags
);
497 if (cn
->sourcetype
== SOURCE_NONE
|| (
498 cn
->sourcetype
== SOURCE_SOCK
&&
499 cn
->reversedir
->target
.sock
.credituser
== 0))
500 _refresh_conn_credits(cn
->reversedir
);
501 _refresh_conn_credits(cn
);
502 if (cn
->targettype
== TARGET_UNCONNECTED
|| (
503 cn
->targettype
== TARGET_OUT
&&
504 cn
->target
.out
.conn_id
== 0) || (
505 cn
->targettype
== TARGET_SOCK
&&
506 cn
->target
.sock
.credituser
== 0))
507 _refresh_conn_credits(cn
->reversedir
);
510 if (likely(locked
== 0))
511 credits_unlock_conn(cn
, unlockhints
);
514 kref_put(&(cn
->ref
), free_conn
);
519 void connreset_credits(struct conn
*cn
)
521 unsigned long iflags
;
523 __u32 unlockhints
= credits_lock_conn(cn
);
524 if (cn
->in_credit_list
) {
525 spin_lock_irqsave(&credits_list_lock
, iflags
);
526 list_del(&(cn
->credit_list
));
527 cn
->in_credit_list
= 0;
528 spin_unlock_irqrestore(&credits_list_lock
, iflags
);
529 kref_put(&(cn
->ref
), free_conn
);
532 if (cn
->sourcetype
== SOURCE_IN
) {
533 struct neighbor
*nb
= cn
->source
.in
.nb
;
534 spin_lock_irqsave(&(nb
->credits_lock
), iflags
);
535 refresh_credits_state(nb
);
536 nb
->creditrate_earning
= newnbrate(nb
->creditrate_earning
,
538 spin_unlock_irqrestore(&(nb
->credits_lock
), iflags
);
541 if (cn
->targettype
== TARGET_OUT
) {
542 struct neighbor
*nb
= cn
->target
.out
.nb
;
543 spin_lock_irqsave(&(nb
->credits_lock
), iflags
);
544 refresh_credits_state(nb
);
545 nb
->creditrate_spending
= newnbrate(nb
->creditrate_spending
,
547 spin_unlock_irqrestore(&(nb
->credits_lock
), iflags
);
549 credits_unlock_conn(cn
, unlockhints
);
552 void set_conn_in_decaytime(struct neighbor
*nb
, __u32 conn_id
,
553 struct conn
*src_in
, __u8 decaytime_seqno
, __u16 decaytime
)
555 __u32 unlockhints
= credits_lock_conn(src_in
);
557 if (unlikely(is_conn_in(src_in
, nb
, conn_id
) == 0))
560 if (unlikely(src_in
->source
.in
.decaytime_seqno
== 255)) {
561 src_in
->source
.in
.decaytime_seqno
= decaytime_seqno
;
565 if (src_in
->source
.in
.decaytime_seqno
!= decaytime_seqno
)
567 src_in
->source
.in
.decaytime_seqno
= (src_in
->source
.in
.decaytime_seqno
+
571 src_in
->source
.in
.decaytime
= decaytime
;
572 refresh_conn_credits(src_in
, 0, 1);
575 credits_unlock_conn(src_in
, unlockhints
);
578 static void background_refresh_credits(struct work_struct
*work
)
580 unsigned long iflags
;
585 spin_lock_irqsave(&credits_list_lock
, iflags
);
586 if (unlikely(list_empty(&(credit_refresh_conns
)))) {
591 cn
= container_of(credit_refresh_conns
.next
,
592 struct conn
, credit_list
);
594 spin_unlock_irqrestore(&credits_list_lock
, iflags
);
597 rc
= refresh_conn_credits(cn
, 1, 0);
600 if (likely(rc
> 0)) {
601 schedule_delayed_work(&credit_refresh_work
, rc
);
605 void __init
credits_init(void)
607 INIT_DELAYED_WORK(&credit_refresh_work
, background_refresh_credits
);
610 MODULE_LICENSE("GPL");