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
22 DEFINE_SPINLOCK(credits_list_lock
);
23 LIST_HEAD(credit_refresh_conns
);
24 static struct delayed_work credit_refresh_work
;
25 static int refresh_running
= 0;
27 static __u64
decay_credits(__u64 credits
)
29 int decay_rate
= (CREDIT_DECAYTIME_HOURS
* 3) / 2;
30 if (unlikely(decay_rate
== 0))
32 return credits
- credits
/decay_rate
;
35 __u32
creditrate_initial(void)
37 __u64 rate
= (CREDITS_TOTAL
- decay_credits(CREDITS_TOTAL
)) / 3600;
38 if (unlikely((rate
>> 32) > 0))
43 /* credit_lock must be held while calling this */
44 static void refresh_credits_state(struct neighbor
*nb
, ktime_t now
)
49 if (ktime_before_eq(now
, nb
->ktime_credit_update
))
52 creditrate_add
= nb
->creditrate_earning
;
53 if (unlikely(creditrate_add
+ nb
->creditrate_initial
< creditrate_add
))
56 creditrate_add
+= nb
->creditrate_initial
;
58 creditrate_sub
= multiply_div(nb
->creditrate_spending
,
59 1000 - CREDIT_EXCHANGETAX_PERMILLE
, 1000);
61 if (creditrate_sub
> creditrate_add
) {
64 __u64 adj
= multiply_div2(creditrate_sub
- creditrate_add
,
65 0 - nb
->credits_rem
, ktime_to_ns(now
) -
66 ktime_to_ns(nb
->ktime_credit_update
),
69 BUG_ON(rem
>= 1000000000);
71 if (unlikely(nb
->credits
< adj
)) {
76 nb
->credits_rem
= 0 - rem
;
78 } else if (creditrate_sub
< creditrate_add
) {
81 __u64 adj
= multiply_div2(creditrate_add
- creditrate_sub
,
82 nb
->credits_rem
, ktime_to_ns(now
) -
83 ktime_to_ns(nb
->ktime_credit_update
),
86 BUG_ON(rem
>= 1000000000);
88 if (unlikely(nb
->credits
+ adj
< nb
->credits
)) {
93 nb
->credits_rem
= rem
;
97 nb
->ktime_credit_update
= now
;
99 if (unlikely(ktime_after(ktime_add_us(nb
->ktime_credit_decay
,
100 3600LL * 1000000), now
))) {
101 nb
->credits
= decay_credits(nb
->credits
);
103 nb
->ktime_credit_decay
= ktime_add_us(
104 nb
->ktime_credit_decay
, 3600LL * 1000000);
106 if (unlikely(ktime_after(ktime_add_us(nb
->ktime_credit_decay
,
107 3600LL * 1000000), now
))) {
108 nb
->ktime_credit_decay
= ktime_sub_us(now
,
114 void set_creditrate_initial(struct neighbor
*nb
, __u32 creditrate
, ktime_t now
)
116 unsigned long iflags
;
118 spin_lock_irqsave(&(nb
->credits_lock
), iflags
);
119 refresh_credits_state(nb
, now
);
120 nb
->creditrate_initial
= creditrate
;
121 spin_unlock_irqrestore(&(nb
->credits_lock
), iflags
);
124 static __u64
decay_time_to_crate(struct neighbor
*nb
, __u16 decay_time_raw
)
126 __u64 decay_time
= dec_log_300_24(decay_time_raw
);
129 return nb
->credits
/ (decay_time
* 3 / 2);
132 static __u16
crate_to_decay_time(struct neighbor
*nb
, __u64 crate_out
)
135 return enc_log_300_24(0);
136 return enc_log_300_24(nb
->credits
/ multiply_div(crate_out
,
137 2*(1000 - CREDIT_EXCHANGETAX_PERMILLE
), 3 * 1000));
140 static void refresh_crate_forward(struct conn
*cn_lc
, __u64 timediff_ns
)
142 __u8 last_bufferstate
= cn_lc
->last_bufferstate
;
146 if (cn_lc
->tos
== TOS_NORMAL
)
148 else if (cn_lc
->tos
== TOS_LATENCY
)
150 else if (cn_lc
->tos
== TOS_THROUGHPUT
)
152 else if (cn_lc
->tos
== TOS_PRIVACY
)
158 * buffer full shifts 1 bit more so only about 1/3rd if there is no
162 BUG_ON(cn_lc
->crate_forward
> (1 << 31));
164 while (timediff_ns
> 0) {
165 __u64 currdiff
= timediff_ns
;
166 if (currdiff
> 1000000)
169 if (last_bufferstate
== 0)
170 cn_lc
->crate_forward
= ( ((__u64
)cn_lc
->crate_forward
) *
171 (currdiff
<< (shift_base
- 2))) /
172 (currdiff
<< shift_base
);
174 cn_lc
->crate_forward
= ( ((__u64
)cn_lc
->crate_forward
) *
175 (currdiff
<< shift_base
)) /
176 (currdiff
<< (shift_base
- 1));
178 if (cn_lc
->crate_forward
> (1 << 31)) {
179 cn_lc
->crate_forward
= (1 << 31);
183 if (cn_lc
->crate_forward
< (1 << 16)) {
184 cn_lc
->crate_forward
= (1 << 16);
188 timediff_ns
-= currdiff
;
191 cn_lc
->crate_out
= multiply_div(cn_lc
->crate_in
, cn_lc
->crate_forward
,
195 static int decaytime_send_needed(struct conn
*trgt_out_lc
, __u16
*decaytime
)
199 if (trgt_out_lc
->target
.out
.decaytime_send_allowed
== 0)
202 *decaytime
= crate_to_decay_time(trgt_out_lc
->target
.out
.nb
,
203 trgt_out_lc
->crate_out
);
205 if (unlikely(trgt_out_lc
->target
.out
.conn_id
== 0)) {
206 trgt_out_lc
->reversedir
->source
.in
.decaytime
= *decaytime
;
207 trgt_out_lc
->target
.out
.decaytime_last
= *decaytime
;
208 trgt_out_lc
->target
.out
.decaytime_send_allowed
= 0;
212 if (*decaytime
> trgt_out_lc
->target
.out
.decaytime_last
)
213 diff
= *decaytime
- trgt_out_lc
->target
.out
.decaytime_last
;
214 if (*decaytime
< trgt_out_lc
->target
.out
.decaytime_last
)
215 diff
= trgt_out_lc
->target
.out
.decaytime_last
- *decaytime
;
217 if (diff
!= 0 && (*decaytime
== 0 ||
218 trgt_out_lc
->target
.out
.decaytime_last
== 0))
221 if (trgt_out_lc
->tos
== TOS_PRIVACY
) {
237 static __u64
newnbrate(__u64 nbrate
, __u64 oldconnrate
, __u64 newconnrate
)
239 if (unlikely(nbrate
< oldconnrate
))
242 nbrate
-= oldconnrate
;
244 if (unlikely(nbrate
+ newconnrate
< nbrate
))
247 nbrate
+= newconnrate
;
252 static void refresh_conn_crate_out(struct conn
*trgt_out_lc
, ktime_t now
,
255 unsigned long iflags
;
262 if (likely(trgt_out_lc
->target
.out
.conn_id
!= 0)) {
263 refresh_crate_forward(trgt_out_lc
, timediff_ns
);
265 if (((__s32
) (trgt_out_lc
->target
.out
.seqno_nextsend
-
266 trgt_out_lc
->target
.out
.seqno_windowlimit
)) <=0)
267 trgt_out_lc
->last_bufferstate
= 1;
269 trgt_out_lc
->last_bufferstate
= 0;
272 spin_lock_irqsave(&(trgt_out_lc
->target
.out
.nb
->credits_lock
), iflags
);
274 oldrate
= trgt_out_lc
->crate_out
;
275 refresh_credits_state(trgt_out_lc
->target
.out
.nb
, now
);
276 trgt_out_lc
->target
.out
.nb
->creditrate_spending
= newnbrate(
277 trgt_out_lc
->target
.out
.nb
->creditrate_spending
,
278 oldrate
, trgt_out_lc
->crate_out
);
280 send
= decaytime_send_needed(trgt_out_lc
, &crate
);
282 spin_unlock_irqrestore(&(trgt_out_lc
->target
.out
.nb
->credits_lock
),
285 if (unlikely(send
!= 0)) {
286 send_decaytime(trgt_out_lc
, (send
== 2), crate
);
291 static void refresh_conn_crate_in(struct conn
*src_in_lc
, ktime_t now
)
293 unsigned long iflags
;
295 __u64 oldrate
= src_in_lc
->crate_in
;
297 spin_lock_irqsave(&(src_in_lc
->source
.in
.nb
->credits_lock
), iflags
);
299 refresh_credits_state(src_in_lc
->source
.in
.nb
, now
);
301 src_in_lc
->crate_in
= decay_time_to_crate(src_in_lc
->source
.in
.nb
,
302 src_in_lc
->source
.in
.decaytime
);
303 src_in_lc
->source
.in
.nb
->creditrate_earning
= newnbrate(
304 src_in_lc
->source
.in
.nb
->creditrate_earning
, oldrate
,
305 src_in_lc
->crate_in
);
307 spin_unlock_irqrestore(&(src_in_lc
->source
.in
.nb
->credits_lock
),
311 static void refresh_conn_crates(struct conn
*cn_lc
, ktime_t now
,
314 /* set conn->crate_in */
315 if (cn_lc
->sourcetype
== SOURCE_NONE
) {
316 cn_lc
->crate_in
= cn_lc
->reversedir
->crate_out
;
317 } else if (cn_lc
->sourcetype
== SOURCE_IN
) {
318 refresh_conn_crate_in(cn_lc
, now
);
319 } else if (cn_lc
->sourcetype
== SOURCE_SOCK
) {
320 if (cn_lc
->reversedir
->target
.sock
.credituser
== 1)
321 cn_lc
->crate_in
= cn_lc
->reversedir
->crate_out
;
322 else if ((cn_lc
->source
.sock
.crate
+
323 cn_lc
->reversedir
->crate_out
) <
324 cn_lc
->reversedir
->crate_out
)
325 cn_lc
->crate_in
= -1;
327 cn_lc
->crate_in
= cn_lc
->reversedir
->crate_out
+
328 cn_lc
->source
.sock
.crate
;
333 /* set conn->crate_forward + conn->crate_out */
334 if (cn_lc
->targettype
== TARGET_UNCONNECTED
||
335 cn_lc
->targettype
== TARGET_DISCARD
) {
336 cn_lc
->crate_out
= cn_lc
->crate_in
;
337 } else if (cn_lc
->targettype
== TARGET_SOCK
) {
338 if (cn_lc
->target
.sock
.credituser
== 0) {
339 cn_lc
->crate_out
= cn_lc
->crate_in
;
341 refresh_crate_forward(cn_lc
, timediff_ns
);
342 cn_lc
->last_bufferstate
= (
343 cn_lc
->reversedir
->source
.sock
.wait_len
346 } else if (cn_lc
->targettype
== TARGET_OUT
) {
347 refresh_conn_crate_out(cn_lc
, now
, timediff_ns
);
353 static void _refresh_conn_credits(struct conn
*cn_lc
, ktime_t now
)
355 __u64 timediff_ns
= ktime_to_ns(now
) -
356 ktime_to_ns(cn_lc
->ktime_credit_update
);
358 if (ktime_before_eq(now
, cn_lc
->ktime_credit_update
)) {
363 if (unlikely(cn_lc
->crate_out
> cn_lc
->crate_in
)) {
366 __u64 adj
= multiply_div2(cn_lc
->crate_out
- cn_lc
->crate_in
,
367 0 - cn_lc
->credits_rem
, timediff_ns
,
370 BUG_ON(rem
>= 1000000000);
372 if (unlikely(cn_lc
->credits
< adj
)) {
374 cn_lc
->credits_rem
= 0;
376 cn_lc
->credits
-= adj
;
377 cn_lc
->credits_rem
= 0 - rem
;
382 __u64 adj
= multiply_div2(cn_lc
->crate_in
- cn_lc
->crate_out
,
383 cn_lc
->credits_rem
, timediff_ns
,
386 BUG_ON(rem
>= 1000000000);
388 if (unlikely(cn_lc
->credits
+ adj
< cn_lc
->credits
)) {
390 cn_lc
->credits_rem
= 0;
392 cn_lc
->credits
+= adj
;
393 cn_lc
->credits_rem
= rem
;
398 refresh_conn_crates(cn_lc
, now
, timediff_ns
);
400 if (timediff_ns
!= 0)
401 cn_lc
->ktime_credit_update
= now
;
404 static void credits_unlock_conn(struct conn
*cn
, __u32 hints
)
406 if ((hints
& 1) != 0)
407 mutex_unlock(&(cn
->rcv_lock
));
408 if ((hints
& 2) != 0)
409 mutex_unlock(&(cn
->reversedir
->rcv_lock
));
410 if ((hints
& 4) != 0)
411 mutex_unlock(&(cn
->rcv_lock
));
414 static __u32
credits_lock_conn(struct conn
*cn
)
416 mutex_lock(&(cn
->rcv_lock
));
417 if (cn
->sourcetype
== SOURCE_IN
&& cn
->targettype
== TARGET_OUT
) {
418 if (likely(cn
->target
.out
.conn_id
!= 0))
423 mutex_lock(&(cn
->reversedir
->rcv_lock
));
426 mutex_unlock(&(cn
->rcv_lock
));
428 mutex_lock(&(cn
->reversedir
->rcv_lock
));
429 mutex_lock(&(cn
->rcv_lock
));
435 int refresh_conn_credits(struct conn
*cn
, int fromperiodic
, int locked
)
437 unsigned long iflags
;
438 __u32 unlockhints
= 0;
443 if (likely(locked
== 0))
444 unlockhints
= credits_lock_conn(cn
);
446 if (unlikely(cn
->isreset
!= 0)) {
455 /* quit if not time for refresh yet */
456 if (ktime_after(ktime_add_us(cn
->ktime_credit_update
,
457 CREDIT_REFRESHINTERVAL_SEC
* 1000000), now
)) {
458 int alreadyrefreshed
;
460 spin_lock_irqsave(&credits_list_lock
, iflags
);
461 alreadyrefreshed
= &(cn
->credit_list
) !=
462 credit_refresh_conns
.next
;
463 spin_unlock_irqrestore(&credits_list_lock
, iflags
);
465 if (unlikely(alreadyrefreshed
))
468 rc
= usecs_to_jiffies(ktime_us_delta(ktime_add_us(
469 cn
->ktime_credit_update
,
470 CREDIT_REFRESHINTERVAL_SEC
* 1000000),
474 if (unlikely(rc
> HZ
* CREDIT_REFRESHINTERVAL_SEC
))
475 rc
= HZ
* CREDIT_REFRESHINTERVAL_SEC
;
480 if (cn
->targettype
== TARGET_UNCONNECTED
||
481 cn
->targettype
== TARGET_DISCARD
|| (
482 cn
->targettype
== TARGET_SOCK
&&
483 cn
->target
.sock
.credituser
== 0)) {
484 if (unlikely(cn
->in_credit_list
)) {
485 spin_lock_irqsave(&credits_list_lock
, iflags
);
486 list_del(&(cn
->credit_list
));
487 cn
->in_credit_list
= 0;
488 spin_unlock_irqrestore(&credits_list_lock
, iflags
);
492 if (cn
->sourcetype
== SOURCE_NONE
|| (
493 cn
->sourcetype
== SOURCE_SOCK
&&
494 cn
->reversedir
->target
.sock
.credituser
== 0))
500 spin_lock_irqsave(&credits_list_lock
, iflags
);
502 if (unlikely(cn
->in_credit_list
== 0)) {
503 cn
->in_credit_list
= 1;
504 kref_get(&(cn
->ref
));
505 if (refresh_running
== 0) {
506 schedule_delayed_work(&credit_refresh_work
, HZ
*
507 CREDIT_REFRESHINTERVAL_SEC
);
511 list_del(&(cn
->credit_list
));
513 list_add_tail(&(cn
->credit_list
), &credit_refresh_conns
);
516 spin_unlock_irqrestore(&credits_list_lock
, iflags
);
519 if (cn
->sourcetype
== SOURCE_NONE
|| (
520 cn
->sourcetype
== SOURCE_SOCK
&&
521 cn
->reversedir
->target
.sock
.credituser
== 0))
522 _refresh_conn_credits(cn
->reversedir
, now
);
523 _refresh_conn_credits(cn
, now
);
524 if (cn
->targettype
== TARGET_UNCONNECTED
||
525 cn
->targettype
== TARGET_DISCARD
|| (
526 cn
->targettype
== TARGET_OUT
&&
527 cn
->target
.out
.conn_id
== 0) || (
528 cn
->targettype
== TARGET_SOCK
&&
529 cn
->target
.sock
.credituser
== 0))
530 _refresh_conn_credits(cn
->reversedir
, now
);
533 if (likely(locked
== 0))
534 credits_unlock_conn(cn
, unlockhints
);
537 kref_put(&(cn
->ref
), free_conn
);
542 void connreset_credits(struct conn
*cn
)
544 unsigned long iflags
;
546 __u32 unlockhints
= credits_lock_conn(cn
);
547 if (cn
->in_credit_list
) {
548 spin_lock_irqsave(&credits_list_lock
, iflags
);
549 list_del(&(cn
->credit_list
));
550 cn
->in_credit_list
= 0;
551 spin_unlock_irqrestore(&credits_list_lock
, iflags
);
552 kref_put(&(cn
->ref
), free_conn
);
555 if (cn
->sourcetype
== SOURCE_IN
) {
556 struct neighbor
*nb
= cn
->source
.in
.nb
;
557 spin_lock_irqsave(&(nb
->credits_lock
), iflags
);
558 refresh_credits_state(nb
, ktime_get());
559 nb
->creditrate_earning
= newnbrate(nb
->creditrate_earning
,
561 spin_unlock_irqrestore(&(nb
->credits_lock
), iflags
);
564 if (cn
->targettype
== TARGET_OUT
) {
565 struct neighbor
*nb
= cn
->target
.out
.nb
;
566 spin_lock_irqsave(&(nb
->credits_lock
), iflags
);
567 refresh_credits_state(nb
, ktime_get());
568 nb
->creditrate_spending
= newnbrate(nb
->creditrate_spending
,
570 spin_unlock_irqrestore(&(nb
->credits_lock
), iflags
);
572 credits_unlock_conn(cn
, unlockhints
);
575 void set_conn_in_decaytime(struct neighbor
*nb
, __u32 conn_id
,
576 struct conn
*src_in
, __u8 decaytime_seqno
, __u16 decaytime
)
578 __u32 unlockhints
= credits_lock_conn(src_in
);
580 if (unlikely(is_conn_in(src_in
, nb
, conn_id
) == 0))
583 if (unlikely(src_in
->source
.in
.decaytime_seqno
== 255)) {
584 src_in
->source
.in
.decaytime_seqno
= decaytime_seqno
;
588 if (src_in
->source
.in
.decaytime_seqno
!= decaytime_seqno
)
590 src_in
->source
.in
.decaytime_seqno
= (src_in
->source
.in
.decaytime_seqno
+
594 src_in
->source
.in
.decaytime
= decaytime
;
595 refresh_conn_credits(src_in
, 0, 1);
598 credits_unlock_conn(src_in
, unlockhints
);
601 static void background_refresh_credits(struct work_struct
*work
)
603 unsigned long iflags
;
608 spin_lock_irqsave(&credits_list_lock
, iflags
);
609 if (unlikely(list_empty(&(credit_refresh_conns
)))) {
614 cn
= container_of(credit_refresh_conns
.next
,
615 struct conn
, credit_list
);
617 spin_unlock_irqrestore(&credits_list_lock
, iflags
);
620 rc
= refresh_conn_credits(cn
, 1, 0);
623 if (likely(rc
> 0)) {
624 schedule_delayed_work(&credit_refresh_work
, rc
);
628 void __init
credits_init(void)
630 INIT_DELAYED_WORK(&credit_refresh_work
, background_refresh_credits
);
633 MODULE_LICENSE("GPL");