27450751a3153575df7cc7dd6df05074b17a1b7a
[folly.git] / folly / MacAddress.h
1 /*
2  * Copyright 2017 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #pragma once
18
19 #include <iosfwd>
20
21 #include <folly/Bits.h>
22 #include <folly/Range.h>
23
24 namespace folly {
25
26 class IPAddressV6;
27
28 /*
29  * MacAddress represents an IEEE 802 MAC address.
30  */
31 class MacAddress {
32  public:
33   static constexpr size_t SIZE = 6;
34   static const MacAddress BROADCAST;
35   static const MacAddress ZERO;
36
37   /*
38    * Construct a zero-initialized MacAddress.
39    */
40   MacAddress() {
41     memset(&bytes_, 0, 8);
42   }
43
44   /*
45    * Parse a MacAddress from a human-readable string.
46    * The string must contain 6 one- or two-digit hexadecimal
47    * numbers, separated by dashes or colons.
48    * Examples: 00:02:C9:C8:F9:68 or 0-2-c9-c8-f9-68
49    */
50   explicit MacAddress(StringPiece str);
51
52   /*
53    * Construct a MAC address from its 6-byte binary value
54    */
55   static MacAddress fromBinary(ByteRange value) {
56     MacAddress ret;
57     ret.setFromBinary(value);
58     return ret;
59   }
60
61   /*
62    * Construct a MacAddress from a uint64_t in network byte order.
63    *
64    * The first two bytes are ignored, and the MAC address is taken from the
65    * latter 6 bytes.
66    *
67    * This is a static method rather than a constructor to avoid confusion
68    * between host and network byte order constructors.
69    */
70   static MacAddress fromNBO(uint64_t value) {
71     return MacAddress(value);
72   }
73
74   /*
75    * Construct a MacAddress from a uint64_t in host byte order.
76    *
77    * The most significant two bytes are ignored, and the MAC address is taken
78    * from the least significant 6 bytes.
79    *
80    * This is a static method rather than a constructor to avoid confusion
81    * between host and network byte order constructors.
82    */
83   static MacAddress fromHBO(uint64_t value) {
84     return MacAddress(Endian::big(value));
85   }
86
87   /*
88    * Construct the multicast MacAddress for the specified multicast IPv6
89    * address.
90    */
91   static MacAddress createMulticast(IPAddressV6 addr);
92
93   /*
94    * Get a pointer to the MAC address' binary value.
95    *
96    * The returned value points to internal storage inside the MacAddress
97    * object.  It is only valid as long as the MacAddress, and its contents may
98    * change if the MacAddress is updated.
99    */
100   const uint8_t* bytes() const {
101     return bytes_ + 2;
102   }
103
104   /*
105    * Return the address as a uint64_t, in network byte order.
106    *
107    * The first two bytes will be 0, and the subsequent 6 bytes will contain
108    * the address in network byte order.
109    */
110   uint64_t u64NBO() const {
111     return packedBytes();
112   }
113
114   /*
115    * Return the address as a uint64_t, in host byte order.
116    *
117    * The two most significant bytes will be 0, and the remaining 6 bytes will
118    * contain the address.  The most significant of these 6 bytes will contain
119    * the first byte that appear on the wire, and the least significant byte
120    * will contain the last byte.
121    */
122   uint64_t u64HBO() const {
123     // Endian::big() does what we want here, even though we are converting
124     // from big-endian to host byte order.  This swaps if and only if
125     // the host byte order is little endian.
126     return Endian::big(packedBytes());
127   }
128
129   /*
130    * Return a human-readable representation of the MAC address.
131    */
132   std::string toString() const;
133
134   /*
135    * Update the current MacAddress object from a human-readable string.
136    */
137   void parse(StringPiece str);
138
139   /*
140    * Update the current MacAddress object from a 6-byte binary representation.
141    */
142   void setFromBinary(ByteRange value);
143
144   bool isBroadcast() const {
145     return *this == BROADCAST;
146   }
147   bool isMulticast() const {
148     return getByte(0) & 0x1;
149   }
150   bool isUnicast() const {
151     return !isMulticast();
152   }
153
154   /*
155    * Return true if this MAC address is locally administered.
156    *
157    * Locally administered addresses are assigned by the local network
158    * administrator, and are not guaranteed to be globally unique.  (It is
159    * similar to IPv4's private address space.)
160    *
161    * Note that isLocallyAdministered() will return true for the broadcast
162    * address, since it has the locally administered bit set.
163    */
164   bool isLocallyAdministered() const {
165     return getByte(0) & 0x2;
166   }
167
168   // Comparison operators.
169
170   bool operator==(const MacAddress& other) const {
171     // All constructors and modifying methods make sure padding is 0,
172     // so we don't need to mask these bytes out when comparing here.
173     return packedBytes() == other.packedBytes();
174   }
175
176   bool operator<(const MacAddress& other) const {
177     return u64HBO() < other.u64HBO();
178   }
179
180   bool operator!=(const MacAddress& other) const {
181     return !(*this == other);
182   }
183
184   bool operator>(const MacAddress& other) const {
185     return other < *this;
186   }
187
188   bool operator>=(const MacAddress& other) const {
189     return !(*this < other);
190   }
191
192   bool operator<=(const MacAddress& other) const {
193     return !(*this > other);
194   }
195
196  private:
197   explicit MacAddress(uint64_t valueNBO) {
198     memcpy(&bytes_, &valueNBO, 8);
199     // Set the pad bytes to 0.
200     // This allows us to easily compare two MacAddresses,
201     // without having to worry about differences in the padding.
202     bytes_[0] = 0;
203     bytes_[1] = 0;
204   }
205
206   /* We store the 6 bytes starting at bytes_[2] (most significant)
207      through bytes_[7] (least).
208      bytes_[0] and bytes_[1] are always equal to 0 to simplify comparisons.
209   */
210   unsigned char bytes_[8];
211
212   inline uint64_t getByte(size_t index) const {
213     return bytes_[index + 2];
214   }
215
216   uint64_t packedBytes() const {
217     uint64_t u64;
218     memcpy(&u64, bytes_, 8);
219     return u64;
220   }
221 };
222
223 /* Define toAppend() so to<string> will work */
224 template <class Tgt>
225 typename std::enable_if<IsSomeString<Tgt>::value>::type
226 toAppend(MacAddress address, Tgt* result) {
227   toAppend(address.toString(), result);
228 }
229
230 std::ostream& operator<<(std::ostream& os, MacAddress address);
231
232 } // namespace folly