SwitchHeader.h 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  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 | Traffic Class |
  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. */
  46. #pragma pack(push)
  47. #pragma pack(4)
  48. struct SwitchHeader
  49. {
  50. /** The label, this is how the switch decides where to send the packet. Big Endian. */
  51. uint64_t label_be;
  52. /**
  53. * Top 7 bits: congest
  54. * Next bit: suppressErrors
  55. * In versions <= 7, this byte was set to 0 for data and 1 for ctrl packets.
  56. */
  57. uint8_t congestAndSuppressErrors;
  58. /**
  59. * High 2 bits: the version of the switch sending the packet.
  60. * Low 6 bits: the number of bits which the label has been shifted in the process of switching
  61. * the packet.
  62. */
  63. uint8_t versionAndLabelShift;
  64. /**
  65. * Number of the traffic class, if this is 0xffff then it's "unclassed".
  66. * As of this writing, the code is not written but the plan is to allow traffic classifications
  67. * with different bandwidth allotments. All bandwidth shall remain burstable but a bandwidth
  68. * allotment will be guaranteed up to it's limit when deciding which packets must be dropped
  69. * in an over-capacity link.
  70. */
  71. uint16_t trafficClass_be;
  72. };
  73. #define SwitchHeader_SIZE 12
  74. Assert_compileTime(sizeof(struct SwitchHeader) == SwitchHeader_SIZE);
  75. #pragma pack(pop)
  76. #define SwitchHeader_MASK(x) ( (1 << (x)) - 1 )
  77. #define SwitchHeader_CURRENT_VERSION 1
  78. static inline uint32_t SwitchHeader_getVersion(const struct SwitchHeader* header)
  79. {
  80. return header->versionAndLabelShift >> 6;
  81. }
  82. static inline void SwitchHeader_setVersion(struct SwitchHeader* header, uint8_t version)
  83. {
  84. Assert_true(version < 4);
  85. header->versionAndLabelShift =
  86. (version << 6) | (header->versionAndLabelShift & SwitchHeader_MASK(6));
  87. }
  88. static inline uint32_t SwitchHeader_getLabelShift(const struct SwitchHeader* header)
  89. {
  90. return header->versionAndLabelShift & SwitchHeader_MASK(6);
  91. }
  92. static inline void SwitchHeader_setLabelShift(struct SwitchHeader* header, uint32_t shift)
  93. {
  94. Assert_true(shift < 64);
  95. header->versionAndLabelShift = header->versionAndLabelShift >> 6 << 6;
  96. header->versionAndLabelShift |= shift;
  97. }
  98. static inline uint32_t SwitchHeader_getCongestion(const struct SwitchHeader* header)
  99. {
  100. return header->congestAndSuppressErrors >> 1;
  101. }
  102. static inline void SwitchHeader_setCongestion(struct SwitchHeader* header, uint32_t cong)
  103. {
  104. Assert_true(cong <= 127);
  105. if (!cong) { cong++; }
  106. header->congestAndSuppressErrors = (header->congestAndSuppressErrors & 1) | (cong << 1);
  107. }
  108. static inline uint16_t SwitchHeader_getTrafficClass(const struct SwitchHeader* header)
  109. {
  110. return Endian_bigEndianToHost16(header->trafficClass_be);
  111. }
  112. static inline void SwitchHeader_setTrafficClass(struct SwitchHeader* header, uint16_t tc)
  113. {
  114. header->trafficClass_be = Endian_hostToBigEndian16(tc);
  115. }
  116. static inline bool SwitchHeader_getSuppressErrors(const struct SwitchHeader* header)
  117. {
  118. return header->congestAndSuppressErrors & 1;
  119. }
  120. static inline void SwitchHeader_setSuppressErrors(struct SwitchHeader* header, bool suppress)
  121. {
  122. header->congestAndSuppressErrors = header->congestAndSuppressErrors >> 1 << 1;
  123. header->congestAndSuppressErrors |= suppress;
  124. }
  125. #endif