SwitchHeader.h 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  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. #ifndef SwitchHeader_H
  16. #define SwitchHeader_H
  17. #include "util/Assert.h"
  18. #include "util/Endian.h"
  19. #include "util/version/Version.h"
  20. #include <stdint.h>
  21. #include <stdbool.h>
  22. /**
  23. * The header which switches use to decide where to route traffic.
  24. *
  25. * 1 2 3
  26. * 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
  27. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  28. * 0 | |
  29. * + Switch Label +
  30. * 4 | |
  31. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  32. * 8 | Congest |S| V |labelShift | Penalty |
  33. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  34. *
  35. * Versions <= 7 byte number 8 is message type but the only 2 defined types were 0 (data)
  36. * and 1 (control).
  37. * Versions >= 8, byte number 8 is a congestion indicator but the lowest bit is a flag (S)
  38. * indicating that errors caused by this packet should be suppressed. Obviously an error message
  39. * should not trigger another error message so error messages will have the flag set.
  40. * Conveinently, all pre v8 versions will set the flag on every ctrl packet (including all errors).
  41. * Versions >= 8 will set congest to non-zero as a way to tell themselves apart from versions < 8
  42. * Versions < 8 are treating the byte as a number so all bits of congest will be zero.
  43. * Version >= 11 labelShift is the number of bits which the label has been shifted to the right
  44. * in the course of switching. Switches older than 11 will not update this value!
  45. * Penalty is used for QoS, see Penalty.h
  46. */
  47. #pragma pack(push)
  48. #pragma pack(4)
  49. struct SwitchHeader
  50. {
  51. /** The label, this is how the switch decides where to send the packet. Big Endian. */
  52. uint64_t label_be;
  53. /**
  54. * Top 7 bits: congest
  55. * Next bit: suppressErrors
  56. * In versions <= 7, this byte was set to 0 for data and 1 for ctrl packets.
  57. */
  58. uint8_t congestAndSuppressErrors;
  59. /**
  60. * High 2 bits: the version of the switch sending the packet.
  61. * Low 6 bits: the number of bits which the label has been shifted in the process of switching
  62. * the packet.
  63. */
  64. uint8_t versionAndLabelShift;
  65. /** QoS Penalty, see Penalty.h */
  66. uint16_t penalty_be;
  67. };
  68. #define SwitchHeader_SIZE 12
  69. Assert_compileTime(sizeof(struct SwitchHeader) == SwitchHeader_SIZE);
  70. #pragma pack(pop)
  71. #define SwitchHeader_MASK(x) ( (1 << (x)) - 1 )
  72. #define SwitchHeader_CURRENT_VERSION 1
  73. static inline uint32_t SwitchHeader_getVersion(const struct SwitchHeader* header)
  74. {
  75. return header->versionAndLabelShift >> 6;
  76. }
  77. static inline void SwitchHeader_setVersion(struct SwitchHeader* header, uint8_t version)
  78. {
  79. Assert_true(version < 4);
  80. header->versionAndLabelShift =
  81. (version << 6) | (header->versionAndLabelShift & SwitchHeader_MASK(6));
  82. }
  83. static inline uint32_t SwitchHeader_getLabelShift(const struct SwitchHeader* header)
  84. {
  85. return header->versionAndLabelShift & SwitchHeader_MASK(6);
  86. }
  87. static inline void SwitchHeader_setLabelShift(struct SwitchHeader* header, uint32_t shift)
  88. {
  89. Assert_true(shift < 64);
  90. header->versionAndLabelShift = header->versionAndLabelShift >> 6 << 6;
  91. header->versionAndLabelShift |= shift;
  92. }
  93. static inline uint32_t SwitchHeader_getCongestion(const struct SwitchHeader* header)
  94. {
  95. return header->congestAndSuppressErrors >> 1;
  96. }
  97. static inline void SwitchHeader_setCongestion(struct SwitchHeader* header, uint32_t cong)
  98. {
  99. Assert_true(cong <= 127);
  100. if (!cong) { cong++; }
  101. header->congestAndSuppressErrors = (header->congestAndSuppressErrors & 1) | (cong << 1);
  102. }
  103. static inline uint16_t SwitchHeader_getPenalty(const struct SwitchHeader* header)
  104. {
  105. return Endian_bigEndianToHost16(header->penalty_be);
  106. }
  107. static inline void SwitchHeader_setPenalty(struct SwitchHeader* header, uint16_t penalty)
  108. {
  109. header->penalty_be = Endian_hostToBigEndian16(penalty);
  110. }
  111. static inline bool SwitchHeader_getSuppressErrors(const struct SwitchHeader* header)
  112. {
  113. return header->congestAndSuppressErrors & 1;
  114. }
  115. static inline void SwitchHeader_setSuppressErrors(struct SwitchHeader* header, bool suppress)
  116. {
  117. header->congestAndSuppressErrors = header->congestAndSuppressErrors >> 1 << 1;
  118. header->congestAndSuppressErrors |= suppress;
  119. }
  120. #endif