247 lines
6.5 KiB
C
247 lines
6.5 KiB
C
|
/*
|
||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
#pragma once
|
||
|
|
||
|
#include <iosfwd>
|
||
|
|
||
|
#include <folly/Conv.h>
|
||
|
#include <folly/Range.h>
|
||
|
#include <folly/lang/Bits.h>
|
||
|
|
||
|
namespace folly {
|
||
|
|
||
|
class IPAddressV6;
|
||
|
|
||
|
/*
|
||
|
* MacAddress represents an IEEE 802 MAC address.
|
||
|
*/
|
||
|
class MacAddress {
|
||
|
public:
|
||
|
static constexpr size_t SIZE = 6;
|
||
|
static const MacAddress BROADCAST;
|
||
|
static const MacAddress ZERO;
|
||
|
|
||
|
/*
|
||
|
* Construct a zero-initialized MacAddress.
|
||
|
*/
|
||
|
MacAddress() {
|
||
|
memset(&bytes_, 0, 8);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Parse a MacAddress from a human-readable string.
|
||
|
* The string must contain 6 one- or two-digit hexadecimal
|
||
|
* numbers, separated by dashes or colons.
|
||
|
* Examples: 00:02:C9:C8:F9:68 or 0-2-c9-c8-f9-68
|
||
|
*/
|
||
|
explicit MacAddress(StringPiece str);
|
||
|
|
||
|
/*
|
||
|
* Construct a MAC address from its 6-byte binary value
|
||
|
*/
|
||
|
static MacAddress fromBinary(ByteRange value) {
|
||
|
MacAddress ret;
|
||
|
ret.setFromBinary(value);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Construct a MacAddress from a uint64_t in network byte order.
|
||
|
*
|
||
|
* The first two bytes are ignored, and the MAC address is taken from the
|
||
|
* latter 6 bytes.
|
||
|
*
|
||
|
* This is a static method rather than a constructor to avoid confusion
|
||
|
* between host and network byte order constructors.
|
||
|
*/
|
||
|
static MacAddress fromNBO(uint64_t value) {
|
||
|
return MacAddress(value);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Construct a MacAddress from a uint64_t in host byte order.
|
||
|
*
|
||
|
* The most significant two bytes are ignored, and the MAC address is taken
|
||
|
* from the least significant 6 bytes.
|
||
|
*
|
||
|
* This is a static method rather than a constructor to avoid confusion
|
||
|
* between host and network byte order constructors.
|
||
|
*/
|
||
|
static MacAddress fromHBO(uint64_t value) {
|
||
|
return MacAddress(Endian::big(value));
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Construct the multicast MacAddress for the specified multicast IPv6
|
||
|
* address.
|
||
|
*/
|
||
|
static MacAddress createMulticast(IPAddressV6 addr);
|
||
|
|
||
|
/*
|
||
|
* Get a pointer to the MAC address' binary value.
|
||
|
*
|
||
|
* The returned value points to internal storage inside the MacAddress
|
||
|
* object. It is only valid as long as the MacAddress, and its contents may
|
||
|
* change if the MacAddress is updated.
|
||
|
*/
|
||
|
const uint8_t* bytes() const {
|
||
|
return bytes_ + 2;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Return the address as a uint64_t, in network byte order.
|
||
|
*
|
||
|
* The first two bytes will be 0, and the subsequent 6 bytes will contain
|
||
|
* the address in network byte order.
|
||
|
*/
|
||
|
uint64_t u64NBO() const {
|
||
|
return packedBytes();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Return the address as a uint64_t, in host byte order.
|
||
|
*
|
||
|
* The two most significant bytes will be 0, and the remaining 6 bytes will
|
||
|
* contain the address. The most significant of these 6 bytes will contain
|
||
|
* the first byte that appear on the wire, and the least significant byte
|
||
|
* will contain the last byte.
|
||
|
*/
|
||
|
uint64_t u64HBO() const {
|
||
|
// Endian::big() does what we want here, even though we are converting
|
||
|
// from big-endian to host byte order. This swaps if and only if
|
||
|
// the host byte order is little endian.
|
||
|
return Endian::big(packedBytes());
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Return a human-readable representation of the MAC address.
|
||
|
*/
|
||
|
std::string toString() const;
|
||
|
|
||
|
/*
|
||
|
* Update the current MacAddress object from a human-readable string.
|
||
|
*/
|
||
|
void parse(StringPiece str);
|
||
|
|
||
|
/*
|
||
|
* Update the current MacAddress object from a 6-byte binary representation.
|
||
|
*/
|
||
|
void setFromBinary(ByteRange value);
|
||
|
|
||
|
bool isBroadcast() const {
|
||
|
return *this == BROADCAST;
|
||
|
}
|
||
|
bool isMulticast() const {
|
||
|
return getByte(0) & 0x1;
|
||
|
}
|
||
|
bool isUnicast() const {
|
||
|
return !isMulticast();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Return true if this MAC address is locally administered.
|
||
|
*
|
||
|
* Locally administered addresses are assigned by the local network
|
||
|
* administrator, and are not guaranteed to be globally unique. (It is
|
||
|
* similar to IPv4's private address space.)
|
||
|
*
|
||
|
* Note that isLocallyAdministered() will return true for the broadcast
|
||
|
* address, since it has the locally administered bit set.
|
||
|
*/
|
||
|
bool isLocallyAdministered() const {
|
||
|
return getByte(0) & 0x2;
|
||
|
}
|
||
|
|
||
|
// Comparison operators.
|
||
|
|
||
|
bool operator==(const MacAddress& other) const {
|
||
|
// All constructors and modifying methods make sure padding is 0,
|
||
|
// so we don't need to mask these bytes out when comparing here.
|
||
|
return packedBytes() == other.packedBytes();
|
||
|
}
|
||
|
|
||
|
bool operator<(const MacAddress& other) const {
|
||
|
return u64HBO() < other.u64HBO();
|
||
|
}
|
||
|
|
||
|
bool operator!=(const MacAddress& other) const {
|
||
|
return !(*this == other);
|
||
|
}
|
||
|
|
||
|
bool operator>(const MacAddress& other) const {
|
||
|
return other < *this;
|
||
|
}
|
||
|
|
||
|
bool operator>=(const MacAddress& other) const {
|
||
|
return !(*this < other);
|
||
|
}
|
||
|
|
||
|
bool operator<=(const MacAddress& other) const {
|
||
|
return !(*this > other);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
explicit MacAddress(uint64_t valueNBO) {
|
||
|
memcpy(&bytes_, &valueNBO, 8);
|
||
|
// Set the pad bytes to 0.
|
||
|
// This allows us to easily compare two MacAddresses,
|
||
|
// without having to worry about differences in the padding.
|
||
|
bytes_[0] = 0;
|
||
|
bytes_[1] = 0;
|
||
|
}
|
||
|
|
||
|
/* We store the 6 bytes starting at bytes_[2] (most significant)
|
||
|
through bytes_[7] (least).
|
||
|
bytes_[0] and bytes_[1] are always equal to 0 to simplify comparisons.
|
||
|
*/
|
||
|
unsigned char bytes_[8];
|
||
|
|
||
|
inline uint64_t getByte(size_t index) const {
|
||
|
return bytes_[index + 2];
|
||
|
}
|
||
|
|
||
|
uint64_t packedBytes() const {
|
||
|
uint64_t u64;
|
||
|
memcpy(&u64, bytes_, 8);
|
||
|
return u64;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/* Define toAppend() so to<string> will work */
|
||
|
template <class Tgt>
|
||
|
typename std::enable_if<IsSomeString<Tgt>::value>::type toAppend(
|
||
|
MacAddress address,
|
||
|
Tgt* result) {
|
||
|
toAppend(address.toString(), result);
|
||
|
}
|
||
|
|
||
|
std::ostream& operator<<(std::ostream& os, MacAddress address);
|
||
|
|
||
|
} // namespace folly
|
||
|
|
||
|
namespace std {
|
||
|
|
||
|
// Provide an implementation for std::hash<MacAddress>
|
||
|
template <>
|
||
|
struct hash<folly::MacAddress> {
|
||
|
size_t operator()(const folly::MacAddress& address) const {
|
||
|
return std::hash<uint64_t>()(address.u64HBO());
|
||
|
}
|
||
|
};
|
||
|
|
||
|
} // namespace std
|