Penalty.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. /* vim: set expandtab ts=4 sw=4: */
  2. /*
  3. * You may redistribute this program and/or modify it under the terms of
  4. * the GNU General Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. */
  15. #include "switch/Penalty.h"
  16. #include "switch/PenaltyFloat.h"
  17. #include "util/events/Time.h"
  18. #include "util/events/Timeout.h"
  19. #include "util/log/Log.h"
  20. /**
  21. * Penalty entry
  22. *
  23. * 1 2 3
  24. * 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
  25. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  26. * 0 | Packed Penalty (host order) | size | timeMilliseconds |
  27. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  28. */
  29. #define ENTRY_COUNT 1024
  30. struct Penalty_pvt
  31. {
  32. struct Penalty pub;
  33. struct Timeout* maintanenceTimeout;
  34. struct EventBase* eventBase;
  35. struct Log* log;
  36. int lastReplaced;
  37. uint32_t entries[ENTRY_COUNT];
  38. Identity
  39. };
  40. #define EXPIRE_AFTER_MILLISECONDS 1024
  41. #define PENALTY_TIME(penaltyEntry) ((penaltyEntry) << 21 >> 21)
  42. static uint16_t handlePacket(struct Penalty_pvt* p,
  43. uint32_t currentPackedPenalty,
  44. int messageLength)
  45. {
  46. uint32_t now = Time_currentTimeMilliseconds(p->eventBase);
  47. uint64_t unpackedPenalty = PenaltyFloat_unpack((uint16_t)currentPackedPenalty);
  48. uint32_t newPenaltyEntry =
  49. (PenaltyFloat_pack(unpackedPenalty) << 16) |
  50. (((messageLength / 128) & ((1<<5)-1)) << 11) |
  51. (now & ((1<<11)-1));
  52. // normalize currentPackedPenalty
  53. currentPackedPenalty = newPenaltyEntry >> 16;
  54. for (int i = 0; i < ENTRY_COUNT; i++) {
  55. // Non-branching comparison: 30% - 60% better perf for whole switching process (no crypto)
  56. uint32_t e = p->entries[i];
  57. //if (e > newPenaltyEntry) { unpackedPenalty += (e << 16 >> 11); }
  58. unpackedPenalty += ( ((((e - newPenaltyEntry - 1) >> 31) << 31) - 1) & (e << 16 >> 11) );
  59. }
  60. p->lastReplaced = (p->lastReplaced + 1) % ENTRY_COUNT;
  61. p->entries[p->lastReplaced] = newPenaltyEntry;
  62. uint16_t newPackedPenalty = PenaltyFloat_pack(unpackedPenalty);
  63. if (newPackedPenalty > currentPackedPenalty) {
  64. /* Per packet logging...
  65. Log_debug(p->log, "Adjusting penalty [%016llx] -> [%016llx]",
  66. (long long)PenaltyFloat_unpack((uint16_t)currentPackedPenalty),
  67. (long long)unpackedPenalty);
  68. */
  69. return newPackedPenalty;
  70. }
  71. return (uint16_t)currentPackedPenalty;
  72. }
  73. void Penalty_apply(struct Penalty* penalty, struct SwitchHeader* switchHeader, int messageLen)
  74. {
  75. struct Penalty_pvt* p = Identity_check((struct Penalty_pvt*) penalty);
  76. uint16_t currentPenalty = SwitchHeader_getPenalty(switchHeader);
  77. SwitchHeader_setPenalty(switchHeader, handlePacket(p, currentPenalty, messageLen));
  78. }
  79. static void maintanence(void* vPenalty)
  80. {
  81. struct Penalty_pvt* p = Identity_check((struct Penalty_pvt*) vPenalty);
  82. uint32_t now = Time_currentTimeMilliseconds(p->eventBase);
  83. uint32_t tooOld = PENALTY_TIME(now - EXPIRE_AFTER_MILLISECONDS);
  84. now = PENALTY_TIME(now);
  85. for (int i = 0; i < ENTRY_COUNT; i++) {
  86. if (PENALTY_TIME(p->entries[i]) < tooOld) {
  87. // set to max penalty.
  88. p->entries[i] = (PenaltyFloat_MAX << 16) | now;
  89. }
  90. }
  91. }
  92. struct Penalty* Penalty_new(struct Allocator* alloc, struct EventBase* base, struct Log* log)
  93. {
  94. struct Penalty_pvt* p = Allocator_calloc(alloc, sizeof(struct Penalty_pvt), 1);
  95. p->eventBase = base;
  96. p->maintanenceTimeout = Timeout_setInterval(maintanence, p, 1024, base, alloc);
  97. p->log = log;
  98. Identity_set(p);
  99. uint32_t now = Time_currentTimeMilliseconds(p->eventBase);
  100. for (int i = 0; i < ENTRY_COUNT; i++) {
  101. p->entries[i] = (PenaltyFloat_MAX << 16) | now;
  102. }
  103. return &p->pub;
  104. }