11bbe3d1eSWilliam A. Kennington III #pragma once 2bb0eaccbSWilliam A. Kennington III #include <fmt/core.h> 3bb0eaccbSWilliam A. Kennington III #include <net/ethernet.h> 41bbe3d1eSWilliam A. Kennington III #include <netinet/in.h> 51bbe3d1eSWilliam A. Kennington III 6bb0eaccbSWilliam A. Kennington III #include <algorithm> 7bb0eaccbSWilliam A. Kennington III #include <array> 81bbe3d1eSWilliam A. Kennington III #include <chrono> 971de63a2SWilliam A. Kennington III #include <numeric> 101bbe3d1eSWilliam A. Kennington III #include <sdeventplus/clock.hpp> 111bbe3d1eSWilliam A. Kennington III #include <sdeventplus/utility/timer.hpp> 121bbe3d1eSWilliam A. Kennington III #include <string> 13bb0eaccbSWilliam A. Kennington III #include <string_view> 14bb0eaccbSWilliam A. Kennington III #include <type_traits> 15dd9ef815SWilliam A. Kennington III #include <unordered_map> 16f7dce2e8SWilly Tu #include <unordered_set> 171bbe3d1eSWilliam A. Kennington III #include <variant> 181bbe3d1eSWilliam A. Kennington III 191bbe3d1eSWilliam A. Kennington III namespace phosphor 201bbe3d1eSWilliam A. Kennington III { 211bbe3d1eSWilliam A. Kennington III namespace network 221bbe3d1eSWilliam A. Kennington III { 231bbe3d1eSWilliam A. Kennington III 241bbe3d1eSWilliam A. Kennington III using namespace std::chrono_literals; 251bbe3d1eSWilliam A. Kennington III 26c7cf25f7SWilliam A. Kennington III // wait for three seconds before reloading systemd-networkd 27c7cf25f7SWilliam A. Kennington III constexpr auto reloadTimeout = 3s; 281bbe3d1eSWilliam A. Kennington III 29d41db383SWilliam A. Kennington III // refresh the objets after four seconds as network 30d41db383SWilliam A. Kennington III // configuration takes 3-4 sec to reconfigure at most. 31d41db383SWilliam A. Kennington III constexpr auto refreshTimeout = 4s; 321bbe3d1eSWilliam A. Kennington III 331bbe3d1eSWilliam A. Kennington III // Byte representations for common address types in network byte order 34bb0eaccbSWilliam A. Kennington III using InAddrAny = std::variant<in_addr, in6_addr>; 35b9d7cbacSWilliam A. Kennington III class IfAddr 36b9d7cbacSWilliam A. Kennington III { 37b9d7cbacSWilliam A. Kennington III private: 38b9d7cbacSWilliam A. Kennington III InAddrAny addr; 39b9d7cbacSWilliam A. Kennington III uint8_t pfx; 40b9d7cbacSWilliam A. Kennington III 41b9d7cbacSWilliam A. Kennington III static void invalidPfx(uint8_t pfx); 42b9d7cbacSWilliam A. Kennington III 43b9d7cbacSWilliam A. Kennington III public: 44b9d7cbacSWilliam A. Kennington III constexpr IfAddr() : addr({}), pfx(0) 45b9d7cbacSWilliam A. Kennington III { 46b9d7cbacSWilliam A. Kennington III } 47b9d7cbacSWilliam A. Kennington III 48b9d7cbacSWilliam A. Kennington III constexpr IfAddr(InAddrAny addr, uint8_t pfx) : addr(addr), pfx(pfx) 49b9d7cbacSWilliam A. Kennington III { 50b9d7cbacSWilliam A. Kennington III std::visit( 51b9d7cbacSWilliam A. Kennington III [pfx](auto v) { 52b9d7cbacSWilliam A. Kennington III if (sizeof(v) * 8 < pfx) 53b9d7cbacSWilliam A. Kennington III { 54b9d7cbacSWilliam A. Kennington III invalidPfx(pfx); 55b9d7cbacSWilliam A. Kennington III } 56b9d7cbacSWilliam A. Kennington III }, 57b9d7cbacSWilliam A. Kennington III addr); 58b9d7cbacSWilliam A. Kennington III } 59b9d7cbacSWilliam A. Kennington III 60b9d7cbacSWilliam A. Kennington III constexpr auto getAddr() const 61b9d7cbacSWilliam A. Kennington III { 62b9d7cbacSWilliam A. Kennington III return addr; 63b9d7cbacSWilliam A. Kennington III } 64b9d7cbacSWilliam A. Kennington III 65b9d7cbacSWilliam A. Kennington III constexpr auto getPfx() const 66b9d7cbacSWilliam A. Kennington III { 67b9d7cbacSWilliam A. Kennington III return pfx; 68b9d7cbacSWilliam A. Kennington III } 69b9d7cbacSWilliam A. Kennington III 70b9d7cbacSWilliam A. Kennington III constexpr bool operator==(phosphor::network::IfAddr rhs) const noexcept 71b9d7cbacSWilliam A. Kennington III { 72b9d7cbacSWilliam A. Kennington III return addr == rhs.addr && pfx == rhs.pfx; 73b9d7cbacSWilliam A. Kennington III } 74b9d7cbacSWilliam A. Kennington III }; 751bbe3d1eSWilliam A. Kennington III 761bbe3d1eSWilliam A. Kennington III using Timer = sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>; 771bbe3d1eSWilliam A. Kennington III 78dd9ef815SWilliam A. Kennington III struct string_hash : public std::hash<std::string_view> 79dd9ef815SWilliam A. Kennington III { 80dd9ef815SWilliam A. Kennington III using is_transparent = void; 81dd9ef815SWilliam A. Kennington III }; 82dd9ef815SWilliam A. Kennington III template <typename V> 83dd9ef815SWilliam A. Kennington III using string_umap = 84dd9ef815SWilliam A. Kennington III std::unordered_map<std::string, V, string_hash, std::equal_to<>>; 8596444795SWilliam A. Kennington III using string_uset = 8696444795SWilliam A. Kennington III std::unordered_set<std::string, string_hash, std::equal_to<>>; 87dd9ef815SWilliam A. Kennington III 883e471c5fSWilliam A. Kennington III constexpr std::size_t hash_multi() noexcept 89991a8e81SWilliam A. Kennington III { 90991a8e81SWilliam A. Kennington III return 0; 91991a8e81SWilliam A. Kennington III } 92991a8e81SWilliam A. Kennington III 93991a8e81SWilliam A. Kennington III template <typename T, typename... Args> 94becda1aaSWilliam A. Kennington III constexpr std::size_t hash_multi(const T& v, const Args&... args) noexcept 95991a8e81SWilliam A. Kennington III { 96991a8e81SWilliam A. Kennington III const std::size_t seed = hash_multi(args...); 97991a8e81SWilliam A. Kennington III return seed ^ (std::hash<T>{}(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2)); 98991a8e81SWilliam A. Kennington III } 99991a8e81SWilliam A. Kennington III 100bb0eaccbSWilliam A. Kennington III namespace detail 101bb0eaccbSWilliam A. Kennington III { 102bb0eaccbSWilliam A. Kennington III 10371de63a2SWilliam A. Kennington III template <typename T, uint8_t size = sizeof(T)> 10471de63a2SWilliam A. Kennington III struct BswapAlign 10571de63a2SWilliam A. Kennington III { 10671de63a2SWilliam A. Kennington III using type = T; 10771de63a2SWilliam A. Kennington III }; 10871de63a2SWilliam A. Kennington III 10971de63a2SWilliam A. Kennington III template <typename T> 11071de63a2SWilliam A. Kennington III struct BswapAlign<T, 2> 11171de63a2SWilliam A. Kennington III { 11271de63a2SWilliam A. Kennington III using type alignas(uint16_t) = T; 11371de63a2SWilliam A. Kennington III }; 11471de63a2SWilliam A. Kennington III 11571de63a2SWilliam A. Kennington III template <typename T> 11671de63a2SWilliam A. Kennington III struct BswapAlign<T, 4> 11771de63a2SWilliam A. Kennington III { 11871de63a2SWilliam A. Kennington III using type alignas(uint32_t) = T; 11971de63a2SWilliam A. Kennington III }; 12071de63a2SWilliam A. Kennington III 12171de63a2SWilliam A. Kennington III template <typename T> 12271de63a2SWilliam A. Kennington III struct BswapAlign<T, 8> 12371de63a2SWilliam A. Kennington III { 12471de63a2SWilliam A. Kennington III using type alignas(uint64_t) = T; 12571de63a2SWilliam A. Kennington III }; 12671de63a2SWilliam A. Kennington III 12771de63a2SWilliam A. Kennington III template <typename T> 12871de63a2SWilliam A. Kennington III constexpr T bswapInt(typename BswapAlign<T>::type n) noexcept 12971de63a2SWilliam A. Kennington III { 13071de63a2SWilliam A. Kennington III static_assert(std::is_trivially_copyable_v<T>); 13171de63a2SWilliam A. Kennington III if constexpr (sizeof(T) == 2) 13271de63a2SWilliam A. Kennington III { 13371de63a2SWilliam A. Kennington III reinterpret_cast<uint16_t&>(n) = 13471de63a2SWilliam A. Kennington III __builtin_bswap16(reinterpret_cast<uint16_t&>(n)); 13571de63a2SWilliam A. Kennington III } 13671de63a2SWilliam A. Kennington III else if constexpr (sizeof(T) == 4) 13771de63a2SWilliam A. Kennington III { 13871de63a2SWilliam A. Kennington III reinterpret_cast<uint32_t&>(n) = 13971de63a2SWilliam A. Kennington III __builtin_bswap32(reinterpret_cast<uint32_t&>(n)); 14071de63a2SWilliam A. Kennington III } 14171de63a2SWilliam A. Kennington III else if constexpr (sizeof(T) == 8) 14271de63a2SWilliam A. Kennington III { 14371de63a2SWilliam A. Kennington III reinterpret_cast<uint64_t&>(n) = 14471de63a2SWilliam A. Kennington III __builtin_bswap64(reinterpret_cast<uint64_t&>(n)); 14571de63a2SWilliam A. Kennington III } 14671de63a2SWilliam A. Kennington III else 14771de63a2SWilliam A. Kennington III { 14871de63a2SWilliam A. Kennington III auto b = reinterpret_cast<std::byte*>(&n); 14971de63a2SWilliam A. Kennington III std::reverse(b, b + sizeof(n)); 15071de63a2SWilliam A. Kennington III } 15171de63a2SWilliam A. Kennington III return n; 15271de63a2SWilliam A. Kennington III } 15371de63a2SWilliam A. Kennington III 15471de63a2SWilliam A. Kennington III } // namespace detail 15571de63a2SWilliam A. Kennington III 15671de63a2SWilliam A. Kennington III template <typename T> 15771de63a2SWilliam A. Kennington III constexpr T bswap(T n) noexcept 15871de63a2SWilliam A. Kennington III { 15971de63a2SWilliam A. Kennington III return detail::bswapInt<T>(n); 16071de63a2SWilliam A. Kennington III } 16171de63a2SWilliam A. Kennington III 16271de63a2SWilliam A. Kennington III template <typename T> 16371de63a2SWilliam A. Kennington III constexpr T hton(T n) noexcept 16471de63a2SWilliam A. Kennington III { 16571de63a2SWilliam A. Kennington III if constexpr (std::endian::native == std::endian::big) 16671de63a2SWilliam A. Kennington III { 16771de63a2SWilliam A. Kennington III return n; 16871de63a2SWilliam A. Kennington III } 16971de63a2SWilliam A. Kennington III else if constexpr (std::endian::native == std::endian::little) 17071de63a2SWilliam A. Kennington III { 17171de63a2SWilliam A. Kennington III return bswap(n); 17271de63a2SWilliam A. Kennington III } 17371de63a2SWilliam A. Kennington III else 17471de63a2SWilliam A. Kennington III { 17571de63a2SWilliam A. Kennington III static_assert(std::is_same_v<T, void>); 17671de63a2SWilliam A. Kennington III } 17771de63a2SWilliam A. Kennington III } 17871de63a2SWilliam A. Kennington III 17971de63a2SWilliam A. Kennington III template <typename T> 18071de63a2SWilliam A. Kennington III constexpr T ntoh(T n) noexcept 18171de63a2SWilliam A. Kennington III { 18271de63a2SWilliam A. Kennington III return hton(n); 18371de63a2SWilliam A. Kennington III } 18471de63a2SWilliam A. Kennington III 18571de63a2SWilliam A. Kennington III namespace detail 18671de63a2SWilliam A. Kennington III { 187238ef992SWilliam A. Kennington III inline constexpr auto charLookup = []() { 188238ef992SWilliam A. Kennington III std::array<int8_t, 256> ret; 189238ef992SWilliam A. Kennington III std::fill(ret.begin(), ret.end(), -1); 190238ef992SWilliam A. Kennington III for (int8_t i = 0; i < 10; ++i) 191238ef992SWilliam A. Kennington III { 192238ef992SWilliam A. Kennington III ret[i + '0'] = i; 193238ef992SWilliam A. Kennington III } 194238ef992SWilliam A. Kennington III for (int8_t i = 0; i < 26; ++i) 195238ef992SWilliam A. Kennington III { 196238ef992SWilliam A. Kennington III ret[i + 'A'] = i + 10; 197238ef992SWilliam A. Kennington III ret[i + 'a'] = i + 10; 198238ef992SWilliam A. Kennington III } 199238ef992SWilliam A. Kennington III return ret; 200238ef992SWilliam A. Kennington III }(); 201*dd7c7b34SWilliam A. Kennington III inline constexpr auto intLookup = []() { 202*dd7c7b34SWilliam A. Kennington III std::array<char, 36> ret; 203*dd7c7b34SWilliam A. Kennington III for (int8_t i = 0; i < 10; ++i) 204*dd7c7b34SWilliam A. Kennington III { 205*dd7c7b34SWilliam A. Kennington III ret[i] = i + '0'; 206238ef992SWilliam A. Kennington III } 207*dd7c7b34SWilliam A. Kennington III for (int8_t i = 0; i < 26; ++i) 208*dd7c7b34SWilliam A. Kennington III { 209*dd7c7b34SWilliam A. Kennington III ret[i + 10] = i + 'a'; 210*dd7c7b34SWilliam A. Kennington III } 211*dd7c7b34SWilliam A. Kennington III return ret; 212*dd7c7b34SWilliam A. Kennington III }(); 213*dd7c7b34SWilliam A. Kennington III } // namespace detail 214238ef992SWilliam A. Kennington III 215238ef992SWilliam A. Kennington III template <typename T, uint8_t base> 216238ef992SWilliam A. Kennington III struct DecodeInt 217238ef992SWilliam A. Kennington III { 218238ef992SWilliam A. Kennington III static_assert(base > 1 && base <= 36); 219238ef992SWilliam A. Kennington III static_assert(std::is_unsigned_v<T>); 220238ef992SWilliam A. Kennington III 221238ef992SWilliam A. Kennington III constexpr T operator()(std::string_view str) const 222238ef992SWilliam A. Kennington III { 223238ef992SWilliam A. Kennington III if (str.empty()) 224238ef992SWilliam A. Kennington III { 225238ef992SWilliam A. Kennington III throw std::invalid_argument("Empty Str"); 226238ef992SWilliam A. Kennington III } 227238ef992SWilliam A. Kennington III constexpr auto max = std::numeric_limits<T>::max(); 228238ef992SWilliam A. Kennington III auto ret = 229238ef992SWilliam A. Kennington III std::accumulate(str.begin(), str.end(), T{}, [&](T r, char c) { 230238ef992SWilliam A. Kennington III auto v = detail::charLookup[c]; 231238ef992SWilliam A. Kennington III if (v < 0 || v >= base) 232238ef992SWilliam A. Kennington III { 233238ef992SWilliam A. Kennington III throw std::invalid_argument("Invalid numeral"); 234238ef992SWilliam A. Kennington III } 235238ef992SWilliam A. Kennington III if constexpr (std::popcount(base) == 1) 236238ef992SWilliam A. Kennington III { 237238ef992SWilliam A. Kennington III constexpr auto shift = std::countr_zero(base); 238238ef992SWilliam A. Kennington III constexpr auto maxshift = max >> shift; 239238ef992SWilliam A. Kennington III if (r > maxshift) 240238ef992SWilliam A. Kennington III { 241238ef992SWilliam A. Kennington III throw std::overflow_error("Integer Decode"); 242238ef992SWilliam A. Kennington III } 243238ef992SWilliam A. Kennington III return (r << shift) | v; 244238ef992SWilliam A. Kennington III } 245238ef992SWilliam A. Kennington III else 246238ef992SWilliam A. Kennington III { 247238ef992SWilliam A. Kennington III constexpr auto maxbase = max / base; 248238ef992SWilliam A. Kennington III if (r > maxbase) 249238ef992SWilliam A. Kennington III { 250238ef992SWilliam A. Kennington III throw std::overflow_error("Integer Decode"); 251238ef992SWilliam A. Kennington III } 252238ef992SWilliam A. Kennington III r *= base; 253238ef992SWilliam A. Kennington III if (max - v < r) 254238ef992SWilliam A. Kennington III { 255238ef992SWilliam A. Kennington III throw std::overflow_error("Integer Decode"); 256238ef992SWilliam A. Kennington III } 257238ef992SWilliam A. Kennington III return r + v; 258238ef992SWilliam A. Kennington III } 259238ef992SWilliam A. Kennington III }); 260238ef992SWilliam A. Kennington III return ret; 261238ef992SWilliam A. Kennington III } 262238ef992SWilliam A. Kennington III }; 263238ef992SWilliam A. Kennington III 264*dd7c7b34SWilliam A. Kennington III template <typename T, uint8_t base> 265*dd7c7b34SWilliam A. Kennington III struct EncodeInt 266*dd7c7b34SWilliam A. Kennington III { 267*dd7c7b34SWilliam A. Kennington III static_assert(base > 1 && base <= 36); 268*dd7c7b34SWilliam A. Kennington III static_assert(std::is_unsigned_v<T>); 269*dd7c7b34SWilliam A. Kennington III 270*dd7c7b34SWilliam A. Kennington III static constexpr uint8_t buf_size = []() { 271*dd7c7b34SWilliam A. Kennington III T v = std::numeric_limits<T>::max(); 272*dd7c7b34SWilliam A. Kennington III uint8_t i = 0; 273*dd7c7b34SWilliam A. Kennington III for (; v != 0; ++i) 274*dd7c7b34SWilliam A. Kennington III { 275*dd7c7b34SWilliam A. Kennington III v /= base; 276*dd7c7b34SWilliam A. Kennington III } 277*dd7c7b34SWilliam A. Kennington III return i; 278*dd7c7b34SWilliam A. Kennington III }(); 279*dd7c7b34SWilliam A. Kennington III using buf_type = std::array<char, buf_size>; 280*dd7c7b34SWilliam A. Kennington III 281*dd7c7b34SWilliam A. Kennington III constexpr uint8_t reverseFill(char* buf, T v) const noexcept 282*dd7c7b34SWilliam A. Kennington III { 283*dd7c7b34SWilliam A. Kennington III uint8_t i = 0; 284*dd7c7b34SWilliam A. Kennington III do 285*dd7c7b34SWilliam A. Kennington III { 286*dd7c7b34SWilliam A. Kennington III if constexpr (std::popcount(base) == 1) 287*dd7c7b34SWilliam A. Kennington III { 288*dd7c7b34SWilliam A. Kennington III buf[i++] = detail::intLookup[v & 0xf]; 289*dd7c7b34SWilliam A. Kennington III v >>= 4; 290*dd7c7b34SWilliam A. Kennington III } 291*dd7c7b34SWilliam A. Kennington III else 292*dd7c7b34SWilliam A. Kennington III { 293*dd7c7b34SWilliam A. Kennington III buf[i++] = detail::intLookup[v % base]; 294*dd7c7b34SWilliam A. Kennington III v /= base; 295*dd7c7b34SWilliam A. Kennington III } 296*dd7c7b34SWilliam A. Kennington III } while (v > 0); 297*dd7c7b34SWilliam A. Kennington III return i; 298*dd7c7b34SWilliam A. Kennington III } 299*dd7c7b34SWilliam A. Kennington III 300*dd7c7b34SWilliam A. Kennington III constexpr char* operator()(char* buf, T v) const noexcept 301*dd7c7b34SWilliam A. Kennington III { 302*dd7c7b34SWilliam A. Kennington III uint8_t i = reverseFill(buf, v); 303*dd7c7b34SWilliam A. Kennington III std::reverse(buf, buf + i); 304*dd7c7b34SWilliam A. Kennington III return buf + i; 305*dd7c7b34SWilliam A. Kennington III } 306*dd7c7b34SWilliam A. Kennington III 307*dd7c7b34SWilliam A. Kennington III constexpr char* operator()(char* buf, T v, uint8_t min_width) const noexcept 308*dd7c7b34SWilliam A. Kennington III { 309*dd7c7b34SWilliam A. Kennington III uint8_t i = reverseFill(buf, v); 310*dd7c7b34SWilliam A. Kennington III auto end = buf + std::max(i, min_width); 311*dd7c7b34SWilliam A. Kennington III std::fill(buf + i, end, '0'); 312*dd7c7b34SWilliam A. Kennington III std::reverse(buf, end); 313*dd7c7b34SWilliam A. Kennington III return end; 314*dd7c7b34SWilliam A. Kennington III } 315*dd7c7b34SWilliam A. Kennington III }; 316*dd7c7b34SWilliam A. Kennington III 317b01d08fdSWilliam A. Kennington III template <typename T> 318b01d08fdSWilliam A. Kennington III struct ToAddr 319b01d08fdSWilliam A. Kennington III { 320b01d08fdSWilliam A. Kennington III }; 321b01d08fdSWilliam A. Kennington III 322b01d08fdSWilliam A. Kennington III template <> 323b01d08fdSWilliam A. Kennington III struct ToAddr<ether_addr> 324b01d08fdSWilliam A. Kennington III { 325b01d08fdSWilliam A. Kennington III constexpr ether_addr operator()(std::string_view str) const 326b01d08fdSWilliam A. Kennington III { 327b01d08fdSWilliam A. Kennington III constexpr DecodeInt<uint8_t, 16> di; 328b01d08fdSWilliam A. Kennington III ether_addr ret; 329b01d08fdSWilliam A. Kennington III if (str.size() == 12 && str.find(":") == str.npos) 330b01d08fdSWilliam A. Kennington III { 331b01d08fdSWilliam A. Kennington III for (size_t i = 0; i < 6; ++i) 332b01d08fdSWilliam A. Kennington III { 333b01d08fdSWilliam A. Kennington III ret.ether_addr_octet[i] = di(str.substr(i * 2, 2)); 334b01d08fdSWilliam A. Kennington III } 335b01d08fdSWilliam A. Kennington III } 336b01d08fdSWilliam A. Kennington III else 337b01d08fdSWilliam A. Kennington III { 338b01d08fdSWilliam A. Kennington III for (size_t i = 0; i < 5; ++i) 339b01d08fdSWilliam A. Kennington III { 340b01d08fdSWilliam A. Kennington III auto loc = str.find(":"); 341b01d08fdSWilliam A. Kennington III ret.ether_addr_octet[i] = di(str.substr(0, loc)); 342b01d08fdSWilliam A. Kennington III str.remove_prefix(loc == str.npos ? str.size() : loc + 1); 343b01d08fdSWilliam A. Kennington III if (str.empty()) 344b01d08fdSWilliam A. Kennington III { 345b01d08fdSWilliam A. Kennington III throw std::invalid_argument("Missing mac data"); 346b01d08fdSWilliam A. Kennington III } 347b01d08fdSWilliam A. Kennington III } 348b01d08fdSWilliam A. Kennington III ret.ether_addr_octet[5] = di(str); 349b01d08fdSWilliam A. Kennington III } 350b01d08fdSWilliam A. Kennington III return ret; 351b01d08fdSWilliam A. Kennington III } 352b01d08fdSWilliam A. Kennington III }; 353b01d08fdSWilliam A. Kennington III 354df1178e0SWilliam A. Kennington III template <> 355df1178e0SWilliam A. Kennington III struct ToAddr<in_addr> 356df1178e0SWilliam A. Kennington III { 357df1178e0SWilliam A. Kennington III constexpr in_addr operator()(std::string_view str) const 358df1178e0SWilliam A. Kennington III { 359df1178e0SWilliam A. Kennington III constexpr DecodeInt<uint8_t, 10> di; 360df1178e0SWilliam A. Kennington III uint32_t addr = {}; 361df1178e0SWilliam A. Kennington III for (size_t i = 0; i < 3; ++i) 362df1178e0SWilliam A. Kennington III { 363df1178e0SWilliam A. Kennington III auto loc = str.find("."); 364df1178e0SWilliam A. Kennington III addr |= di(str.substr(0, loc)); 365df1178e0SWilliam A. Kennington III addr <<= 8; 366df1178e0SWilliam A. Kennington III str.remove_prefix(loc == str.npos ? str.size() : loc + 1); 367df1178e0SWilliam A. Kennington III if (str.empty()) 368df1178e0SWilliam A. Kennington III { 369df1178e0SWilliam A. Kennington III throw std::invalid_argument("Missing addr data"); 370df1178e0SWilliam A. Kennington III } 371df1178e0SWilliam A. Kennington III } 372df1178e0SWilliam A. Kennington III addr |= di(str); 373df1178e0SWilliam A. Kennington III return {hton(addr)}; 374df1178e0SWilliam A. Kennington III } 375df1178e0SWilliam A. Kennington III }; 376df1178e0SWilliam A. Kennington III 377ec496a86SWilliam A. Kennington III template <> 378ec496a86SWilliam A. Kennington III struct ToAddr<in6_addr> 379ec496a86SWilliam A. Kennington III { 380ec496a86SWilliam A. Kennington III constexpr in6_addr operator()(std::string_view str) const 381ec496a86SWilliam A. Kennington III { 382ec496a86SWilliam A. Kennington III constexpr DecodeInt<uint16_t, 16> di; 383ec496a86SWilliam A. Kennington III in6_addr ret = {}; 384ec496a86SWilliam A. Kennington III size_t i = 0; 385ec496a86SWilliam A. Kennington III while (i < 8) 386ec496a86SWilliam A. Kennington III { 387ec496a86SWilliam A. Kennington III auto loc = str.find(':'); 388ec496a86SWilliam A. Kennington III if (i == 6 && loc == str.npos) 389ec496a86SWilliam A. Kennington III { 390ec496a86SWilliam A. Kennington III ret.s6_addr32[3] = ToAddr<in_addr>{}(str).s_addr; 391ec496a86SWilliam A. Kennington III return ret; 392ec496a86SWilliam A. Kennington III } 393ec496a86SWilliam A. Kennington III if (loc != 0 && !str.empty()) 394ec496a86SWilliam A. Kennington III { 395ec496a86SWilliam A. Kennington III ret.s6_addr16[i++] = hton(di(str.substr(0, loc))); 396ec496a86SWilliam A. Kennington III } 397ec496a86SWilliam A. Kennington III if (i < 8 && str.size() > loc + 1 && str[loc + 1] == ':') 398ec496a86SWilliam A. Kennington III { 399ec496a86SWilliam A. Kennington III str.remove_prefix(loc + 2); 400ec496a86SWilliam A. Kennington III break; 401ec496a86SWilliam A. Kennington III } 402ec496a86SWilliam A. Kennington III else if (str.empty()) 403ec496a86SWilliam A. Kennington III { 404ec496a86SWilliam A. Kennington III throw std::invalid_argument("IPv6 Data"); 405ec496a86SWilliam A. Kennington III } 406ec496a86SWilliam A. Kennington III str.remove_prefix(loc == str.npos ? str.size() : loc + 1); 407ec496a86SWilliam A. Kennington III } 408ec496a86SWilliam A. Kennington III if (str.starts_with(':')) 409ec496a86SWilliam A. Kennington III { 410ec496a86SWilliam A. Kennington III throw std::invalid_argument("Extra separator"); 411ec496a86SWilliam A. Kennington III } 412ec496a86SWilliam A. Kennington III size_t j = 7; 413ec496a86SWilliam A. Kennington III if (!str.empty() && i < 6 && str.find('.') != str.npos) 414ec496a86SWilliam A. Kennington III { 415ec496a86SWilliam A. Kennington III auto loc = str.rfind(':'); 416ec496a86SWilliam A. Kennington III ret.s6_addr32[3] = 417ec496a86SWilliam A. Kennington III ToAddr<in_addr>{}(str.substr(loc == str.npos ? 0 : loc + 1)) 418ec496a86SWilliam A. Kennington III .s_addr; 419ec496a86SWilliam A. Kennington III str.remove_suffix(loc == str.npos ? str.size() : str.size() - loc); 420ec496a86SWilliam A. Kennington III j -= 2; 421ec496a86SWilliam A. Kennington III } 422ec496a86SWilliam A. Kennington III while (!str.empty() && j > i) 423ec496a86SWilliam A. Kennington III { 424ec496a86SWilliam A. Kennington III auto loc = str.rfind(':'); 425ec496a86SWilliam A. Kennington III ret.s6_addr16[j--] = 426ec496a86SWilliam A. Kennington III hton(di(str.substr(loc == str.npos ? 0 : loc + 1))); 427ec496a86SWilliam A. Kennington III str.remove_suffix(loc == str.npos ? str.size() : str.size() - loc); 428ec496a86SWilliam A. Kennington III } 429ec496a86SWilliam A. Kennington III if (!str.empty()) 430ec496a86SWilliam A. Kennington III { 431ec496a86SWilliam A. Kennington III throw std::invalid_argument("Too much data"); 432ec496a86SWilliam A. Kennington III } 433ec496a86SWilliam A. Kennington III return ret; 434ec496a86SWilliam A. Kennington III } 435ec496a86SWilliam A. Kennington III }; 436ec496a86SWilliam A. Kennington III 437ead7198cSWilliam A. Kennington III template <> 438ead7198cSWilliam A. Kennington III struct ToAddr<InAddrAny> 439ead7198cSWilliam A. Kennington III { 440ead7198cSWilliam A. Kennington III constexpr InAddrAny operator()(std::string_view str) const 441ead7198cSWilliam A. Kennington III { 442ead7198cSWilliam A. Kennington III if (str.find(':') == str.npos) 443ead7198cSWilliam A. Kennington III { 444ead7198cSWilliam A. Kennington III return ToAddr<in_addr>{}(str); 445ead7198cSWilliam A. Kennington III } 446ead7198cSWilliam A. Kennington III return ToAddr<in6_addr>{}(str); 447ead7198cSWilliam A. Kennington III } 448ead7198cSWilliam A. Kennington III }; 449ead7198cSWilliam A. Kennington III 450ead7198cSWilliam A. Kennington III template <> 451ead7198cSWilliam A. Kennington III struct ToAddr<IfAddr> 452ead7198cSWilliam A. Kennington III { 453ead7198cSWilliam A. Kennington III constexpr IfAddr operator()(std::string_view str) const 454ead7198cSWilliam A. Kennington III { 455ead7198cSWilliam A. Kennington III auto pos = str.rfind('/'); 456ead7198cSWilliam A. Kennington III if (pos == str.npos) 457ead7198cSWilliam A. Kennington III { 458ead7198cSWilliam A. Kennington III throw std::invalid_argument("Invalid IfAddr"); 459ead7198cSWilliam A. Kennington III } 460ead7198cSWilliam A. Kennington III return {ToAddr<InAddrAny>{}(str.substr(0, pos)), 461ead7198cSWilliam A. Kennington III DecodeInt<uint8_t, 10>{}(str.substr(pos + 1))}; 462ead7198cSWilliam A. Kennington III } 463ead7198cSWilliam A. Kennington III }; 464ead7198cSWilliam A. Kennington III 465238ef992SWilliam A. Kennington III namespace detail 466238ef992SWilliam A. Kennington III { 46771de63a2SWilliam A. Kennington III 468bb0eaccbSWilliam A. Kennington III template <typename T> 469bb0eaccbSWilliam A. Kennington III constexpr bool vcontains() noexcept 470bb0eaccbSWilliam A. Kennington III { 471bb0eaccbSWilliam A. Kennington III return false; 472bb0eaccbSWilliam A. Kennington III } 473bb0eaccbSWilliam A. Kennington III 474bb0eaccbSWilliam A. Kennington III template <typename T, typename V, typename... Vs> 475bb0eaccbSWilliam A. Kennington III constexpr bool vcontains() noexcept 476bb0eaccbSWilliam A. Kennington III { 477bb0eaccbSWilliam A. Kennington III return vcontains<T, Vs...>() || std::is_same_v<T, V>; 478bb0eaccbSWilliam A. Kennington III } 479bb0eaccbSWilliam A. Kennington III 480bb0eaccbSWilliam A. Kennington III template <typename T, typename... Types> 481bb0eaccbSWilliam A. Kennington III constexpr std::enable_if_t<vcontains<T, Types...>(), bool> 482bb0eaccbSWilliam A. Kennington III veq(T t, std::variant<Types...> v) noexcept 483bb0eaccbSWilliam A. Kennington III { 484bb0eaccbSWilliam A. Kennington III return std::visit( 485bb0eaccbSWilliam A. Kennington III [t](auto v) { 486bb0eaccbSWilliam A. Kennington III if constexpr (std::is_same_v<T, decltype(v)>) 487bb0eaccbSWilliam A. Kennington III { 488bb0eaccbSWilliam A. Kennington III return v == t; 489bb0eaccbSWilliam A. Kennington III } 490bb0eaccbSWilliam A. Kennington III else 491bb0eaccbSWilliam A. Kennington III { 492bb0eaccbSWilliam A. Kennington III return false; 493bb0eaccbSWilliam A. Kennington III } 494bb0eaccbSWilliam A. Kennington III }, 495bb0eaccbSWilliam A. Kennington III v); 496bb0eaccbSWilliam A. Kennington III } 497bb0eaccbSWilliam A. Kennington III 498bb0eaccbSWilliam A. Kennington III template <typename T> 499bb0eaccbSWilliam A. Kennington III struct AddrBufMaker 500bb0eaccbSWilliam A. Kennington III { 501bb0eaccbSWilliam A. Kennington III }; 502bb0eaccbSWilliam A. Kennington III 503bb0eaccbSWilliam A. Kennington III template <> 504bb0eaccbSWilliam A. Kennington III struct AddrBufMaker<ether_addr> 505bb0eaccbSWilliam A. Kennington III { 506bb0eaccbSWilliam A. Kennington III public: 507bb0eaccbSWilliam A. Kennington III std::string_view operator()(ether_addr val) noexcept; 508bb0eaccbSWilliam A. Kennington III 509bb0eaccbSWilliam A. Kennington III private: 510bb0eaccbSWilliam A. Kennington III std::array<char, /*octet*/ 2 * /*octets*/ 6 + /*seps*/ 5> buf; 511bb0eaccbSWilliam A. Kennington III }; 512bb0eaccbSWilliam A. Kennington III 513bb0eaccbSWilliam A. Kennington III template <> 514bb0eaccbSWilliam A. Kennington III struct AddrBufMaker<in_addr> 515bb0eaccbSWilliam A. Kennington III { 516bb0eaccbSWilliam A. Kennington III public: 517bb0eaccbSWilliam A. Kennington III std::string_view operator()(in_addr val) noexcept; 518bb0eaccbSWilliam A. Kennington III 519bb0eaccbSWilliam A. Kennington III private: 520bb0eaccbSWilliam A. Kennington III std::array<char, /*octet*/ 3 * /*octets*/ 4 + /*seps*/ 3> buf; 521bb0eaccbSWilliam A. Kennington III }; 522bb0eaccbSWilliam A. Kennington III 523bb0eaccbSWilliam A. Kennington III template <> 524bb0eaccbSWilliam A. Kennington III struct AddrBufMaker<in6_addr> 525bb0eaccbSWilliam A. Kennington III { 526bb0eaccbSWilliam A. Kennington III public: 527bb0eaccbSWilliam A. Kennington III std::string_view operator()(in6_addr val) noexcept; 528bb0eaccbSWilliam A. Kennington III 529bb0eaccbSWilliam A. Kennington III private: 530bb0eaccbSWilliam A. Kennington III std::array<char, /*hextet*/ 4 * /*hextets*/ 8 + /*seps*/ 7> buf; 531bb0eaccbSWilliam A. Kennington III }; 532bb0eaccbSWilliam A. Kennington III 533bb0eaccbSWilliam A. Kennington III template <typename BufMaker> 534bb0eaccbSWilliam A. Kennington III struct FormatFromBuf 535bb0eaccbSWilliam A. Kennington III { 536bb0eaccbSWilliam A. Kennington III private: 537bb0eaccbSWilliam A. Kennington III fmt::formatter<std::string_view> formatter; 538bb0eaccbSWilliam A. Kennington III 539bb0eaccbSWilliam A. Kennington III public: 540bb0eaccbSWilliam A. Kennington III template <typename ParseContext> 541bb0eaccbSWilliam A. Kennington III constexpr auto parse(ParseContext& ctx) 542bb0eaccbSWilliam A. Kennington III { 543bb0eaccbSWilliam A. Kennington III return ctx.begin(); 544bb0eaccbSWilliam A. Kennington III } 545bb0eaccbSWilliam A. Kennington III 546bb0eaccbSWilliam A. Kennington III template <typename FormatContext> 547bb0eaccbSWilliam A. Kennington III auto format(auto v, FormatContext& ctx) const 548bb0eaccbSWilliam A. Kennington III { 549bb0eaccbSWilliam A. Kennington III return formatter.format(BufMaker{}(v), ctx); 550bb0eaccbSWilliam A. Kennington III } 551bb0eaccbSWilliam A. Kennington III }; 552bb0eaccbSWilliam A. Kennington III } // namespace detail 5531bbe3d1eSWilliam A. Kennington III } // namespace network 5541bbe3d1eSWilliam A. Kennington III } // namespace phosphor 5553e471c5fSWilliam A. Kennington III 5563e471c5fSWilliam A. Kennington III template <typename... Ts> 5573e471c5fSWilliam A. Kennington III struct std::hash<std::tuple<Ts...>> 5583e471c5fSWilliam A. Kennington III { 5593e471c5fSWilliam A. Kennington III constexpr auto operator()(const std::tuple<Ts...>& t) const noexcept 5603e471c5fSWilliam A. Kennington III { 5613e471c5fSWilliam A. Kennington III return std::apply(phosphor::network::hash_multi<Ts...>, t); 5623e471c5fSWilliam A. Kennington III } 5633e471c5fSWilliam A. Kennington III }; 564bb0eaccbSWilliam A. Kennington III 565653114fcSWilliam A. Kennington III template <> 566653114fcSWilliam A. Kennington III struct std::hash<in_addr> 567653114fcSWilliam A. Kennington III { 568653114fcSWilliam A. Kennington III std::size_t operator()(in_addr addr) const noexcept; 569653114fcSWilliam A. Kennington III }; 570653114fcSWilliam A. Kennington III 571653114fcSWilliam A. Kennington III template <> 572653114fcSWilliam A. Kennington III struct std::hash<in6_addr> 573653114fcSWilliam A. Kennington III { 574653114fcSWilliam A. Kennington III std::size_t operator()(in6_addr addr) const noexcept; 575653114fcSWilliam A. Kennington III }; 576653114fcSWilliam A. Kennington III 577b9d7cbacSWilliam A. Kennington III template <> 578b9d7cbacSWilliam A. Kennington III struct std::hash<phosphor::network::IfAddr> 579b9d7cbacSWilliam A. Kennington III { 580b9d7cbacSWilliam A. Kennington III std::size_t operator()(phosphor::network::IfAddr addr) const noexcept; 581b9d7cbacSWilliam A. Kennington III }; 582b9d7cbacSWilliam A. Kennington III 583bb0eaccbSWilliam A. Kennington III namespace fmt 584bb0eaccbSWilliam A. Kennington III { 585bb0eaccbSWilliam A. Kennington III template <> 586bb0eaccbSWilliam A. Kennington III struct formatter<ether_addr> 587bb0eaccbSWilliam A. Kennington III : phosphor::network::detail::FormatFromBuf< 588bb0eaccbSWilliam A. Kennington III phosphor::network::detail::AddrBufMaker<ether_addr>> 589bb0eaccbSWilliam A. Kennington III { 590bb0eaccbSWilliam A. Kennington III }; 591bb0eaccbSWilliam A. Kennington III template <> 592bb0eaccbSWilliam A. Kennington III struct formatter<in_addr> 593bb0eaccbSWilliam A. Kennington III : phosphor::network::detail::FormatFromBuf< 594bb0eaccbSWilliam A. Kennington III phosphor::network::detail::AddrBufMaker<in_addr>> 595bb0eaccbSWilliam A. Kennington III { 596bb0eaccbSWilliam A. Kennington III }; 597bb0eaccbSWilliam A. Kennington III template <> 598bb0eaccbSWilliam A. Kennington III struct formatter<in6_addr> 599bb0eaccbSWilliam A. Kennington III : phosphor::network::detail::FormatFromBuf< 600bb0eaccbSWilliam A. Kennington III phosphor::network::detail::AddrBufMaker<in6_addr>> 601bb0eaccbSWilliam A. Kennington III { 602bb0eaccbSWilliam A. Kennington III }; 603bb0eaccbSWilliam A. Kennington III template <> 604bb0eaccbSWilliam A. Kennington III struct formatter<phosphor::network::InAddrAny> 605bb0eaccbSWilliam A. Kennington III { 606bb0eaccbSWilliam A. Kennington III private: 607bb0eaccbSWilliam A. Kennington III fmt::formatter<std::string_view> formatter; 608bb0eaccbSWilliam A. Kennington III 609bb0eaccbSWilliam A. Kennington III public: 610bb0eaccbSWilliam A. Kennington III template <typename ParseContext> 611bb0eaccbSWilliam A. Kennington III constexpr auto parse(ParseContext& ctx) 612bb0eaccbSWilliam A. Kennington III { 613bb0eaccbSWilliam A. Kennington III return ctx.begin(); 614bb0eaccbSWilliam A. Kennington III } 615bb0eaccbSWilliam A. Kennington III 616bb0eaccbSWilliam A. Kennington III template <typename FormatContext> 617bb0eaccbSWilliam A. Kennington III auto format(auto v, FormatContext& ctx) const 618bb0eaccbSWilliam A. Kennington III { 619bb0eaccbSWilliam A. Kennington III return std::visit( 620bb0eaccbSWilliam A. Kennington III [&](auto v) { 621bb0eaccbSWilliam A. Kennington III auto abm = 622bb0eaccbSWilliam A. Kennington III phosphor::network::detail::AddrBufMaker<decltype(v)>{}; 623bb0eaccbSWilliam A. Kennington III return formatter.format(abm(v), ctx); 624bb0eaccbSWilliam A. Kennington III }, 625bb0eaccbSWilliam A. Kennington III v); 626bb0eaccbSWilliam A. Kennington III } 627bb0eaccbSWilliam A. Kennington III }; 628b9d7cbacSWilliam A. Kennington III template <> 629b9d7cbacSWilliam A. Kennington III struct formatter<phosphor::network::IfAddr> 630b9d7cbacSWilliam A. Kennington III { 631b9d7cbacSWilliam A. Kennington III private: 632b9d7cbacSWilliam A. Kennington III fmt::formatter<phosphor::network::InAddrAny> addrF; 633b9d7cbacSWilliam A. Kennington III fmt::formatter<char> strF; 634b9d7cbacSWilliam A. Kennington III fmt::formatter<uint8_t> numF; 635b9d7cbacSWilliam A. Kennington III 636b9d7cbacSWilliam A. Kennington III public: 637b9d7cbacSWilliam A. Kennington III template <typename ParseContext> 638b9d7cbacSWilliam A. Kennington III constexpr auto parse(ParseContext& ctx) 639b9d7cbacSWilliam A. Kennington III { 640b9d7cbacSWilliam A. Kennington III return ctx.begin(); 641b9d7cbacSWilliam A. Kennington III } 642b9d7cbacSWilliam A. Kennington III 643b9d7cbacSWilliam A. Kennington III template <typename FormatContext> 644b9d7cbacSWilliam A. Kennington III auto format(auto v, FormatContext& ctx) const 645b9d7cbacSWilliam A. Kennington III { 646b9d7cbacSWilliam A. Kennington III addrF.format(v.getAddr(), ctx); 647b9d7cbacSWilliam A. Kennington III strF.format('/', ctx); 648b9d7cbacSWilliam A. Kennington III return numF.format(v.getPfx(), ctx); 649b9d7cbacSWilliam A. Kennington III } 650b9d7cbacSWilliam A. Kennington III }; 651bb0eaccbSWilliam A. Kennington III } // namespace fmt 652bb0eaccbSWilliam A. Kennington III 653bb0eaccbSWilliam A. Kennington III namespace std 654bb0eaccbSWilliam A. Kennington III { 655bb0eaccbSWilliam A. Kennington III string to_string(ether_addr value); 656bb0eaccbSWilliam A. Kennington III string to_string(in_addr value); 657bb0eaccbSWilliam A. Kennington III string to_string(in6_addr value); 658bb0eaccbSWilliam A. Kennington III string to_string(phosphor::network::InAddrAny value); 659b9d7cbacSWilliam A. Kennington III string to_string(phosphor::network::IfAddr value); 660bb0eaccbSWilliam A. Kennington III } // namespace std 661bb0eaccbSWilliam A. Kennington III 662bb0eaccbSWilliam A. Kennington III constexpr bool operator==(ether_addr lhs, ether_addr rhs) noexcept 663bb0eaccbSWilliam A. Kennington III { 664bb0eaccbSWilliam A. Kennington III return std::equal(lhs.ether_addr_octet, lhs.ether_addr_octet + 6, 665bb0eaccbSWilliam A. Kennington III rhs.ether_addr_octet); 666bb0eaccbSWilliam A. Kennington III } 667bb0eaccbSWilliam A. Kennington III 668bb0eaccbSWilliam A. Kennington III constexpr bool operator==(in_addr lhs, in_addr rhs) noexcept 669bb0eaccbSWilliam A. Kennington III { 670bb0eaccbSWilliam A. Kennington III return lhs.s_addr == rhs.s_addr; 671bb0eaccbSWilliam A. Kennington III } 672bb0eaccbSWilliam A. Kennington III 673bb0eaccbSWilliam A. Kennington III constexpr bool operator==(in6_addr lhs, in6_addr rhs) noexcept 674bb0eaccbSWilliam A. Kennington III { 675bb0eaccbSWilliam A. Kennington III return std::equal(lhs.s6_addr32, lhs.s6_addr32 + 4, rhs.s6_addr32); 676bb0eaccbSWilliam A. Kennington III } 677bb0eaccbSWilliam A. Kennington III 678bb0eaccbSWilliam A. Kennington III template <typename T> 679bb0eaccbSWilliam A. Kennington III constexpr std::enable_if_t<!std::is_same_v<phosphor::network::InAddrAny, T>, 680bb0eaccbSWilliam A. Kennington III bool> 681bb0eaccbSWilliam A. Kennington III operator==(phosphor::network::InAddrAny lhs, T rhs) noexcept 682bb0eaccbSWilliam A. Kennington III { 683bb0eaccbSWilliam A. Kennington III return phosphor::network::detail::veq(rhs, lhs); 684bb0eaccbSWilliam A. Kennington III } 685bb0eaccbSWilliam A. Kennington III 68686eb8b70SWilliam A. Kennington III auto& operator<<(auto& os, ether_addr v) 687bb0eaccbSWilliam A. Kennington III { 688bb0eaccbSWilliam A. Kennington III return os << phosphor::network::detail::AddrBufMaker<ether_addr>{}(v); 689bb0eaccbSWilliam A. Kennington III } 690bb0eaccbSWilliam A. Kennington III 69186eb8b70SWilliam A. Kennington III auto& operator<<(auto& os, in_addr v) 692bb0eaccbSWilliam A. Kennington III { 693bb0eaccbSWilliam A. Kennington III return os << phosphor::network::detail::AddrBufMaker<in_addr>{}(v); 694bb0eaccbSWilliam A. Kennington III } 695bb0eaccbSWilliam A. Kennington III 69686eb8b70SWilliam A. Kennington III auto& operator<<(auto& os, in6_addr v) 697bb0eaccbSWilliam A. Kennington III { 698bb0eaccbSWilliam A. Kennington III return os << phosphor::network::detail::AddrBufMaker<in6_addr>{}(v); 699bb0eaccbSWilliam A. Kennington III } 700bb0eaccbSWilliam A. Kennington III 70186eb8b70SWilliam A. Kennington III auto& operator<<(auto& os, phosphor::network::InAddrAny v) 702bb0eaccbSWilliam A. Kennington III { 703bb0eaccbSWilliam A. Kennington III return os << std::visit( 704bb0eaccbSWilliam A. Kennington III [](auto v) { 705bb0eaccbSWilliam A. Kennington III return phosphor::network::detail::AddrBufMaker< 706bb0eaccbSWilliam A. Kennington III decltype(v)>{}(v); 707bb0eaccbSWilliam A. Kennington III }, 708bb0eaccbSWilliam A. Kennington III v); 709bb0eaccbSWilliam A. Kennington III } 710b9d7cbacSWilliam A. Kennington III 711b9d7cbacSWilliam A. Kennington III auto& operator<<(auto& os, phosphor::network::IfAddr v) 712b9d7cbacSWilliam A. Kennington III { 713b9d7cbacSWilliam A. Kennington III return os << v.getAddr() << "/" << std::dec << int{v.getPfx()}; 714b9d7cbacSWilliam A. Kennington III } 715