2
0

MulticastGroup.hpp 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
  4. *
  5. * (c) ZeroTier, Inc.
  6. * https://www.zerotier.com/
  7. */
  8. #ifndef ZT_MULTICASTGROUP_HPP
  9. #define ZT_MULTICASTGROUP_HPP
  10. #include "InetAddress.hpp"
  11. #include "MAC.hpp"
  12. #include <stdint.h>
  13. namespace ZeroTier {
  14. /**
  15. * A multicast group composed of a multicast MAC and a 32-bit ADI field
  16. *
  17. * ADI stands for additional distinguishing information. ADI is primarily for
  18. * adding additional information to broadcast (ff:ff:ff:ff:ff:ff) memberships,
  19. * since straight-up broadcast won't scale. Right now it's zero except for
  20. * IPv4 ARP, where it holds the IPv4 address itself to make ARP into a
  21. * selective multicast query that can scale.
  22. *
  23. * In the future we might add some kind of plugin architecture that can add
  24. * ADI for things like mDNS (multicast DNS) to improve the selectivity of
  25. * those protocols.
  26. *
  27. * MulticastGroup behaves as an immutable value object.
  28. */
  29. class MulticastGroup {
  30. public:
  31. MulticastGroup() : _mac(), _adi(0)
  32. {
  33. }
  34. MulticastGroup(const MAC& m, uint32_t a) : _mac(m), _adi(a)
  35. {
  36. }
  37. /**
  38. * Derive the multicast group used for address resolution (ARP/NDP) for an IP
  39. *
  40. * @param ip IP address (port field is ignored)
  41. * @return Multicast group for ARP/NDP
  42. */
  43. static inline MulticastGroup deriveMulticastGroupForAddressResolution(const InetAddress& ip)
  44. {
  45. if (ip.isV4()) {
  46. // IPv4 wants broadcast MACs, so we shove the V4 address itself into
  47. // the Multicast Group ADI field. Making V4 ARP work is basically why
  48. // ADI was added, as well as handling other things that want mindless
  49. // Ethernet broadcast to all.
  50. return MulticastGroup(MAC(0xffffffffffffULL), Utils::ntoh(*((const uint32_t*)ip.rawIpData())));
  51. }
  52. else if (ip.isV6()) {
  53. // IPv6 is better designed in this respect. We can compute the IPv6
  54. // multicast address directly from the IP address, and it gives us
  55. // 24 bits of uniqueness. Collisions aren't likely to be common enough
  56. // to care about.
  57. const unsigned char* a = (const unsigned char*)ip.rawIpData();
  58. return MulticastGroup(MAC(0x33, 0x33, 0xff, a[13], a[14], a[15]), 0);
  59. }
  60. return MulticastGroup();
  61. }
  62. /**
  63. * @return Multicast address
  64. */
  65. inline const MAC& mac() const
  66. {
  67. return _mac;
  68. }
  69. /**
  70. * @return Additional distinguishing information
  71. */
  72. inline uint32_t adi() const
  73. {
  74. return _adi;
  75. }
  76. inline unsigned long hashCode() const
  77. {
  78. return (_mac.hashCode() ^ (unsigned long)_adi);
  79. }
  80. inline bool operator==(const MulticastGroup& g) const
  81. {
  82. return ((_mac == g._mac) && (_adi == g._adi));
  83. }
  84. inline bool operator!=(const MulticastGroup& g) const
  85. {
  86. return ((_mac != g._mac) || (_adi != g._adi));
  87. }
  88. inline bool operator<(const MulticastGroup& g) const
  89. {
  90. if (_mac < g._mac) {
  91. return true;
  92. }
  93. else if (_mac == g._mac) {
  94. return (_adi < g._adi);
  95. }
  96. return false;
  97. }
  98. inline bool operator>(const MulticastGroup& g) const
  99. {
  100. return (g < *this);
  101. }
  102. inline bool operator<=(const MulticastGroup& g) const
  103. {
  104. return ! (g < *this);
  105. }
  106. inline bool operator>=(const MulticastGroup& g) const
  107. {
  108. return ! (*this < g);
  109. }
  110. private:
  111. MAC _mac;
  112. uint32_t _adi;
  113. };
  114. } // namespace ZeroTier
  115. #endif