/* vim: set expandtab ts=4 sw=4: */ /* * You may redistribute this program and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SwitchHeader_H #define SwitchHeader_H #include "util/Assert.h" #include "util/Endian.h" #include "util/version/Version.h" #include #include /** * The header which switches use to decide where to route traffic. * * 1 2 3 * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * 0 | | * + Switch Label + * 4 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * 8 | Congest |S| V |labelShift | Traffic Class | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * Versions <= 7 byte number 8 is message type but the only 2 defined types were 0 (data) * and 1 (control). * Versions >= 8, byte number 8 is a congestion indicator but the lowest bit is a flag (S) * indicating that errors caused by this packet should be suppressed. Obviously an error message * should not trigger another error message so error messages will have the flag set. * Conveinently, all pre v8 versions will set the flag on every ctrl packet (including all errors). * Versions >= 8 will set congest to non-zero as a way to tell themselves apart from versions < 8 * Versions < 8 are treating the byte as a number so all bits of congest will be zero. * Version >= 11 labelShift is the number of bits which the label has been shifted to the right * in the course of switching. Switches older than 11 will not update this value! */ #pragma pack(push) #pragma pack(4) struct SwitchHeader { /** The label, this is how the switch decides where to send the packet. Big Endian. */ uint64_t label_be; /** * Top 7 bits: congest * Next bit: suppressErrors * In versions <= 7, this byte was set to 0 for data and 1 for ctrl packets. */ uint8_t congestAndSuppressErrors; /** * High 2 bits: the version of the switch sending the packet. * Low 6 bits: the number of bits which the label has been shifted in the process of switching * the packet. */ uint8_t versionAndLabelShift; /** * Number of the traffic class, if this is 0xffff then it's "unclassed". * As of this writing, the code is not written but the plan is to allow traffic classifications * with different bandwidth allotments. All bandwidth shall remain burstable but a bandwidth * allotment will be guaranteed up to it's limit when deciding which packets must be dropped * in an over-capacity link. */ uint16_t trafficClass_be; }; #define SwitchHeader_SIZE 12 Assert_compileTime(sizeof(struct SwitchHeader) == SwitchHeader_SIZE); #pragma pack(pop) #define SwitchHeader_MASK(x) ( (1 << (x)) - 1 ) #define SwitchHeader_CURRENT_VERSION 1 static inline uint32_t SwitchHeader_getVersion(const struct SwitchHeader* header) { return header->versionAndLabelShift >> 6; } static inline void SwitchHeader_setVersion(struct SwitchHeader* header, uint8_t version) { Assert_true(version < 4); header->versionAndLabelShift = (version << 6) | (header->versionAndLabelShift & SwitchHeader_MASK(6)); } static inline uint32_t SwitchHeader_getLabelShift(const struct SwitchHeader* header) { return header->versionAndLabelShift & SwitchHeader_MASK(6); } static inline void SwitchHeader_setLabelShift(struct SwitchHeader* header, uint32_t shift) { Assert_true(shift < 64); header->versionAndLabelShift = header->versionAndLabelShift >> 6 << 6; header->versionAndLabelShift |= shift; } static inline uint32_t SwitchHeader_getCongestion(const struct SwitchHeader* header) { return header->congestAndSuppressErrors >> 1; } static inline void SwitchHeader_setCongestion(struct SwitchHeader* header, uint32_t cong) { Assert_true(cong <= 127); if (!cong) { cong++; } header->congestAndSuppressErrors = (header->congestAndSuppressErrors & 1) | (cong << 1); } static inline uint16_t SwitchHeader_getTrafficClass(const struct SwitchHeader* header) { return Endian_bigEndianToHost16(header->trafficClass_be); } static inline void SwitchHeader_setTrafficClass(struct SwitchHeader* header, uint16_t tc) { header->trafficClass_be = Endian_hostToBigEndian16(tc); } static inline bool SwitchHeader_getSuppressErrors(const struct SwitchHeader* header) { return header->congestAndSuppressErrors & 1; } static inline void SwitchHeader_setSuppressErrors(struct SwitchHeader* header, bool suppress) { header->congestAndSuppressErrors = header->congestAndSuppressErrors >> 1 << 1; header->congestAndSuppressErrors |= suppress; } #endif