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