blob: 9262623102237fa6c4d88f63190caaabb13d0ae3 [file] [log] [blame]
Ratan Gupta82549cc2017-04-21 08:45:23 +05301#pragma once
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -07002#include <fmt/core.h>
3#include <net/ethernet.h>
William A. Kennington III0d7ce482019-01-30 17:14:23 -08004#include <netinet/in.h>
Ratan Gupta3681a502017-06-17 19:20:04 +05305
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -07006#include <algorithm>
7#include <array>
Patrick Venture189d44e2018-07-09 12:30:59 -07008#include <chrono>
William A. Kennington III71de63a2022-11-08 10:50:54 -08009#include <numeric>
William A. Kennington III3a70fa22018-09-20 18:48:20 -070010#include <sdeventplus/clock.hpp>
11#include <sdeventplus/utility/timer.hpp>
Patrick Venture189d44e2018-07-09 12:30:59 -070012#include <string>
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -070013#include <string_view>
14#include <type_traits>
William A. Kennington IIIdd9ef812022-10-05 02:08:02 -070015#include <unordered_map>
Willy Tuf7dce2e2022-10-07 05:48:08 +000016#include <unordered_set>
William A. Kennington III0d7ce482019-01-30 17:14:23 -080017#include <variant>
Ratan Gupta0f9dc1b2017-09-03 17:57:50 +053018
William A. Kennington III454a0de2022-11-12 01:01:04 -080019constexpr bool operator==(ether_addr lhs, ether_addr rhs) noexcept
20{
21 return std::equal(lhs.ether_addr_octet, lhs.ether_addr_octet + 6,
22 rhs.ether_addr_octet);
23}
24
25constexpr bool operator==(in_addr lhs, in_addr rhs) noexcept
26{
27 return lhs.s_addr == rhs.s_addr;
28}
29
30constexpr bool operator==(in6_addr lhs, in6_addr rhs) noexcept
31{
32 return std::equal(lhs.s6_addr32, lhs.s6_addr32 + 4, rhs.s6_addr32);
33}
34
Ratan Gupta82549cc2017-04-21 08:45:23 +053035namespace phosphor
36{
37namespace network
38{
Ratan Guptae05083a2017-09-16 07:12:11 +053039
40using namespace std::chrono_literals;
Ratan Gupta16f12882017-09-22 18:26:11 +053041
William A. Kennington IIIc7cf25f2021-11-09 16:16:59 -080042// wait for three seconds before reloading systemd-networkd
43constexpr auto reloadTimeout = 3s;
Ratan Gupta16f12882017-09-22 18:26:11 +053044
William A. Kennington IIId41db382021-11-09 20:42:29 -080045// refresh the objets after four seconds as network
46// configuration takes 3-4 sec to reconfigure at most.
47constexpr auto refreshTimeout = 4s;
Ratan Guptae05083a2017-09-16 07:12:11 +053048
William A. Kennington III0d7ce482019-01-30 17:14:23 -080049// Byte representations for common address types in network byte order
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -070050using InAddrAny = std::variant<in_addr, in6_addr>;
William A. Kennington IIIb9d7cba2022-11-08 10:54:11 -080051class IfAddr
52{
53 private:
54 InAddrAny addr;
55 uint8_t pfx;
56
57 static void invalidPfx(uint8_t pfx);
58
59 public:
60 constexpr IfAddr() : addr({}), pfx(0)
61 {
62 }
63
64 constexpr IfAddr(InAddrAny addr, uint8_t pfx) : addr(addr), pfx(pfx)
65 {
66 std::visit(
67 [pfx](auto v) {
68 if (sizeof(v) * 8 < pfx)
69 {
70 invalidPfx(pfx);
71 }
72 },
73 addr);
74 }
75
76 constexpr auto getAddr() const
77 {
78 return addr;
79 }
80
81 constexpr auto getPfx() const
82 {
83 return pfx;
84 }
85
86 constexpr bool operator==(phosphor::network::IfAddr rhs) const noexcept
87 {
88 return addr == rhs.addr && pfx == rhs.pfx;
89 }
90};
William A. Kennington III0d7ce482019-01-30 17:14:23 -080091
William A. Kennington III3a70fa22018-09-20 18:48:20 -070092using Timer = sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>;
93
William A. Kennington III454a0de2022-11-12 01:01:04 -080094/** @class InterfaceInfo
95 * @brief Information about interfaces from the kernel
96 */
97struct InterfaceInfo
98{
99 unsigned idx;
100 unsigned flags;
101 std::optional<std::string> name = std::nullopt;
102 std::optional<ether_addr> mac = std::nullopt;
103 std::optional<unsigned> mtu = std::nullopt;
104 std::optional<unsigned> parent_idx = std::nullopt;
105 std::optional<std::string> kind = std::nullopt;
106 std::optional<uint16_t> vlan_id = std::nullopt;
107
108 constexpr bool operator==(const InterfaceInfo& rhs) const noexcept
109 {
110 return idx == rhs.idx && flags == rhs.flags && name == rhs.name &&
111 mac == rhs.mac && mtu == rhs.mtu &&
112 parent_idx == rhs.parent_idx && kind == rhs.kind &&
113 vlan_id == rhs.vlan_id;
114 }
115};
116
William A. Kennington III6a923632022-11-06 18:17:33 -0800117/** @class AddressInfo
118 * @brief Information about a addresses from the kernel
119 */
120struct AddressInfo
121{
122 unsigned ifidx;
123 IfAddr ifaddr;
124 uint8_t scope;
125 uint32_t flags;
William A. Kennington III454a0de2022-11-12 01:01:04 -0800126
127 constexpr bool operator==(const AddressInfo& rhs) const noexcept
128 {
129 return ifidx == rhs.ifidx && ifaddr == rhs.ifaddr &&
130 scope == rhs.scope && flags == rhs.flags;
131 }
William A. Kennington III6a923632022-11-06 18:17:33 -0800132};
133
William A. Kennington IIIa8426902022-11-07 15:37:41 -0800134/** @class NeighborInfo
135 * @brief Information about a neighbor from the kernel
136 */
137struct NeighborInfo
138{
139 unsigned ifidx;
William A. Kennington III454a0de2022-11-12 01:01:04 -0800140 uint16_t state;
William A. Kennington IIIa8426902022-11-07 15:37:41 -0800141 InAddrAny addr;
142 std::optional<ether_addr> mac;
William A. Kennington III454a0de2022-11-12 01:01:04 -0800143
144 constexpr bool operator==(const NeighborInfo& rhs) const noexcept
145 {
146 return ifidx == rhs.ifidx && state == rhs.state && addr == rhs.addr &&
147 mac == rhs.mac;
148 }
William A. Kennington IIIa8426902022-11-07 15:37:41 -0800149};
150
William A. Kennington IIIdd9ef812022-10-05 02:08:02 -0700151struct string_hash : public std::hash<std::string_view>
152{
153 using is_transparent = void;
154};
155template <typename V>
156using string_umap =
157 std::unordered_map<std::string, V, string_hash, std::equal_to<>>;
William A. Kennington III96444792022-10-05 15:16:22 -0700158using string_uset =
159 std::unordered_set<std::string, string_hash, std::equal_to<>>;
William A. Kennington IIIdd9ef812022-10-05 02:08:02 -0700160
William A. Kennington III3e471c52022-10-27 19:46:07 -0700161constexpr std::size_t hash_multi() noexcept
William A. Kennington III991a8e82022-10-11 15:02:47 -0700162{
163 return 0;
164}
165
166template <typename T, typename... Args>
William A. Kennington IIIbecda1a2022-11-03 12:44:59 -0700167constexpr std::size_t hash_multi(const T& v, const Args&... args) noexcept
William A. Kennington III991a8e82022-10-11 15:02:47 -0700168{
169 const std::size_t seed = hash_multi(args...);
170 return seed ^ (std::hash<T>{}(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2));
171}
172
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700173namespace detail
174{
175
William A. Kennington III71de63a2022-11-08 10:50:54 -0800176template <typename T, uint8_t size = sizeof(T)>
177struct BswapAlign
178{
179 using type = T;
180};
181
182template <typename T>
183struct BswapAlign<T, 2>
184{
185 using type alignas(uint16_t) = T;
186};
187
188template <typename T>
189struct BswapAlign<T, 4>
190{
191 using type alignas(uint32_t) = T;
192};
193
194template <typename T>
195struct BswapAlign<T, 8>
196{
197 using type alignas(uint64_t) = T;
198};
199
200template <typename T>
201constexpr T bswapInt(typename BswapAlign<T>::type n) noexcept
202{
203 static_assert(std::is_trivially_copyable_v<T>);
204 if constexpr (sizeof(T) == 2)
205 {
206 reinterpret_cast<uint16_t&>(n) =
207 __builtin_bswap16(reinterpret_cast<uint16_t&>(n));
208 }
209 else if constexpr (sizeof(T) == 4)
210 {
211 reinterpret_cast<uint32_t&>(n) =
212 __builtin_bswap32(reinterpret_cast<uint32_t&>(n));
213 }
214 else if constexpr (sizeof(T) == 8)
215 {
216 reinterpret_cast<uint64_t&>(n) =
217 __builtin_bswap64(reinterpret_cast<uint64_t&>(n));
218 }
219 else
220 {
221 auto b = reinterpret_cast<std::byte*>(&n);
222 std::reverse(b, b + sizeof(n));
223 }
224 return n;
225}
226
227} // namespace detail
228
229template <typename T>
230constexpr T bswap(T n) noexcept
231{
232 return detail::bswapInt<T>(n);
233}
234
235template <typename T>
236constexpr T hton(T n) noexcept
237{
238 if constexpr (std::endian::native == std::endian::big)
239 {
240 return n;
241 }
242 else if constexpr (std::endian::native == std::endian::little)
243 {
244 return bswap(n);
245 }
246 else
247 {
248 static_assert(std::is_same_v<T, void>);
249 }
250}
251
252template <typename T>
253constexpr T ntoh(T n) noexcept
254{
255 return hton(n);
256}
257
258namespace detail
259{
William A. Kennington III238ef992022-11-03 12:47:49 -0700260inline constexpr auto charLookup = []() {
261 std::array<int8_t, 256> ret;
262 std::fill(ret.begin(), ret.end(), -1);
263 for (int8_t i = 0; i < 10; ++i)
264 {
265 ret[i + '0'] = i;
266 }
267 for (int8_t i = 0; i < 26; ++i)
268 {
269 ret[i + 'A'] = i + 10;
270 ret[i + 'a'] = i + 10;
271 }
272 return ret;
273}();
William A. Kennington IIIdd7c7b32022-11-04 15:19:36 -0700274inline constexpr auto intLookup = []() {
275 std::array<char, 36> ret;
276 for (int8_t i = 0; i < 10; ++i)
277 {
278 ret[i] = i + '0';
279 }
280 for (int8_t i = 0; i < 26; ++i)
281 {
282 ret[i + 10] = i + 'a';
283 }
284 return ret;
285}();
286} // namespace detail
William A. Kennington III238ef992022-11-03 12:47:49 -0700287
288template <typename T, uint8_t base>
289struct DecodeInt
290{
291 static_assert(base > 1 && base <= 36);
292 static_assert(std::is_unsigned_v<T>);
293
294 constexpr T operator()(std::string_view str) const
295 {
296 if (str.empty())
297 {
298 throw std::invalid_argument("Empty Str");
299 }
300 constexpr auto max = std::numeric_limits<T>::max();
301 auto ret =
302 std::accumulate(str.begin(), str.end(), T{}, [&](T r, char c) {
303 auto v = detail::charLookup[c];
304 if (v < 0 || v >= base)
305 {
306 throw std::invalid_argument("Invalid numeral");
307 }
308 if constexpr (std::popcount(base) == 1)
309 {
310 constexpr auto shift = std::countr_zero(base);
311 constexpr auto maxshift = max >> shift;
312 if (r > maxshift)
313 {
314 throw std::overflow_error("Integer Decode");
315 }
316 return (r << shift) | v;
317 }
318 else
319 {
320 constexpr auto maxbase = max / base;
321 if (r > maxbase)
322 {
323 throw std::overflow_error("Integer Decode");
324 }
325 r *= base;
326 if (max - v < r)
327 {
328 throw std::overflow_error("Integer Decode");
329 }
330 return r + v;
331 }
332 });
333 return ret;
334 }
335};
336
William A. Kennington IIIdd7c7b32022-11-04 15:19:36 -0700337template <typename T, uint8_t base>
338struct EncodeInt
339{
340 static_assert(base > 1 && base <= 36);
341 static_assert(std::is_unsigned_v<T>);
342
343 static constexpr uint8_t buf_size = []() {
344 T v = std::numeric_limits<T>::max();
345 uint8_t i = 0;
346 for (; v != 0; ++i)
347 {
348 v /= base;
349 }
350 return i;
351 }();
352 using buf_type = std::array<char, buf_size>;
353
354 constexpr uint8_t reverseFill(char* buf, T v) const noexcept
355 {
356 uint8_t i = 0;
357 do
358 {
359 if constexpr (std::popcount(base) == 1)
360 {
361 buf[i++] = detail::intLookup[v & 0xf];
362 v >>= 4;
363 }
364 else
365 {
366 buf[i++] = detail::intLookup[v % base];
367 v /= base;
368 }
369 } while (v > 0);
370 return i;
371 }
372
373 constexpr char* operator()(char* buf, T v) const noexcept
374 {
375 uint8_t i = reverseFill(buf, v);
376 std::reverse(buf, buf + i);
377 return buf + i;
378 }
379
380 constexpr char* operator()(char* buf, T v, uint8_t min_width) const noexcept
381 {
382 uint8_t i = reverseFill(buf, v);
383 auto end = buf + std::max(i, min_width);
384 std::fill(buf + i, end, '0');
385 std::reverse(buf, end);
386 return end;
387 }
388};
389
William A. Kennington IIIb01d08f2022-11-03 12:50:00 -0700390template <typename T>
391struct ToAddr
392{
393};
394
395template <>
396struct ToAddr<ether_addr>
397{
398 constexpr ether_addr operator()(std::string_view str) const
399 {
400 constexpr DecodeInt<uint8_t, 16> di;
401 ether_addr ret;
402 if (str.size() == 12 && str.find(":") == str.npos)
403 {
404 for (size_t i = 0; i < 6; ++i)
405 {
406 ret.ether_addr_octet[i] = di(str.substr(i * 2, 2));
407 }
408 }
409 else
410 {
411 for (size_t i = 0; i < 5; ++i)
412 {
413 auto loc = str.find(":");
414 ret.ether_addr_octet[i] = di(str.substr(0, loc));
415 str.remove_prefix(loc == str.npos ? str.size() : loc + 1);
416 if (str.empty())
417 {
418 throw std::invalid_argument("Missing mac data");
419 }
420 }
421 ret.ether_addr_octet[5] = di(str);
422 }
423 return ret;
424 }
425};
426
William A. Kennington IIIdf1178e2022-11-03 12:56:33 -0700427template <>
428struct ToAddr<in_addr>
429{
430 constexpr in_addr operator()(std::string_view str) const
431 {
432 constexpr DecodeInt<uint8_t, 10> di;
433 uint32_t addr = {};
434 for (size_t i = 0; i < 3; ++i)
435 {
436 auto loc = str.find(".");
437 addr |= di(str.substr(0, loc));
438 addr <<= 8;
439 str.remove_prefix(loc == str.npos ? str.size() : loc + 1);
440 if (str.empty())
441 {
442 throw std::invalid_argument("Missing addr data");
443 }
444 }
445 addr |= di(str);
446 return {hton(addr)};
447 }
448};
449
William A. Kennington IIIec496a82022-11-04 02:17:20 -0700450template <>
451struct ToAddr<in6_addr>
452{
453 constexpr in6_addr operator()(std::string_view str) const
454 {
455 constexpr DecodeInt<uint16_t, 16> di;
456 in6_addr ret = {};
457 size_t i = 0;
458 while (i < 8)
459 {
460 auto loc = str.find(':');
461 if (i == 6 && loc == str.npos)
462 {
463 ret.s6_addr32[3] = ToAddr<in_addr>{}(str).s_addr;
464 return ret;
465 }
466 if (loc != 0 && !str.empty())
467 {
468 ret.s6_addr16[i++] = hton(di(str.substr(0, loc)));
469 }
470 if (i < 8 && str.size() > loc + 1 && str[loc + 1] == ':')
471 {
472 str.remove_prefix(loc + 2);
473 break;
474 }
475 else if (str.empty())
476 {
477 throw std::invalid_argument("IPv6 Data");
478 }
479 str.remove_prefix(loc == str.npos ? str.size() : loc + 1);
480 }
481 if (str.starts_with(':'))
482 {
483 throw std::invalid_argument("Extra separator");
484 }
485 size_t j = 7;
486 if (!str.empty() && i < 6 && str.find('.') != str.npos)
487 {
488 auto loc = str.rfind(':');
489 ret.s6_addr32[3] =
490 ToAddr<in_addr>{}(str.substr(loc == str.npos ? 0 : loc + 1))
491 .s_addr;
492 str.remove_suffix(loc == str.npos ? str.size() : str.size() - loc);
493 j -= 2;
494 }
495 while (!str.empty() && j > i)
496 {
497 auto loc = str.rfind(':');
498 ret.s6_addr16[j--] =
499 hton(di(str.substr(loc == str.npos ? 0 : loc + 1)));
500 str.remove_suffix(loc == str.npos ? str.size() : str.size() - loc);
501 }
502 if (!str.empty())
503 {
504 throw std::invalid_argument("Too much data");
505 }
506 return ret;
507 }
508};
509
William A. Kennington IIIead71982022-11-04 02:18:10 -0700510template <>
511struct ToAddr<InAddrAny>
512{
513 constexpr InAddrAny operator()(std::string_view str) const
514 {
515 if (str.find(':') == str.npos)
516 {
517 return ToAddr<in_addr>{}(str);
518 }
519 return ToAddr<in6_addr>{}(str);
520 }
521};
522
523template <>
524struct ToAddr<IfAddr>
525{
526 constexpr IfAddr operator()(std::string_view str) const
527 {
528 auto pos = str.rfind('/');
529 if (pos == str.npos)
530 {
531 throw std::invalid_argument("Invalid IfAddr");
532 }
533 return {ToAddr<InAddrAny>{}(str.substr(0, pos)),
534 DecodeInt<uint8_t, 10>{}(str.substr(pos + 1))};
535 }
536};
537
William A. Kennington III55bdc362022-11-04 17:57:21 -0700538template <typename T>
539struct ToStr
540{
541};
542
543template <>
544struct ToStr<char>
545{
546 static constexpr uint8_t buf_size = 1;
547 using buf_type = std::array<char, buf_size>;
548
549 constexpr char* operator()(char* buf, char v) const noexcept
550 {
551 buf[0] = v;
552 return buf + 1;
553 }
554};
555
556template <>
557struct ToStr<ether_addr>
558{
559 // 6 octets * 2 hex chars + 5 separators
560 static constexpr uint8_t buf_size = 17;
561 using buf_type = std::array<char, buf_size>;
562
563 constexpr char* operator()(char* buf, ether_addr v) const noexcept
564 {
565 for (char* ptr = buf + 2; ptr < buf + buf_size; ptr += 3)
566 {
567 *ptr = ':';
568 }
569 for (size_t i = 0; i < 6; ++i)
570 {
571 char* tmp = buf + i * 3;
572 uint8_t byte = v.ether_addr_octet[i];
573 EncodeInt<uint8_t, 16>{}(tmp, byte, 2);
574 }
575 return buf + buf_size;
576 }
577};
578
579template <>
580struct ToStr<in_addr>
581{
582 // 4 octets * 3 dec chars + 3 separators
583 static constexpr uint8_t buf_size = 15;
584 using buf_type = std::array<char, buf_size>;
585
586 constexpr char* operator()(char* buf, in_addr v) const noexcept
587 {
588 auto n = bswap(ntoh(v.s_addr));
589 for (size_t i = 0; i < 3; ++i)
590 {
591 buf = ToStr<char>{}(EncodeInt<uint8_t, 10>{}(buf, n & 0xff), '.');
592 n >>= 8;
593 }
594 return EncodeInt<uint8_t, 10>{}(buf, n & 0xff);
595 }
596};
597
598template <>
599struct ToStr<in6_addr>
600{
601 // 8 hextets * 4 hex chars + 7 separators
602 static constexpr uint8_t buf_size = 39;
603 using buf_type = std::array<char, buf_size>;
604
605 constexpr char* operator()(char* buf, in6_addr v) const noexcept
606 {
607 // IPv4 in IPv6 Addr
608 if (v.s6_addr32[0] == 0 && v.s6_addr32[1] == 0 &&
609 v.s6_addr32[2] == hton(uint32_t(0xffff)))
610 {
611 constexpr auto prefix = std::string_view("::ffff:");
612 return ToStr<in_addr>{}(
613 std::copy(prefix.begin(), prefix.end(), buf), {v.s6_addr32[3]});
614 }
615
616 size_t skip_start = 0;
617 size_t skip_size = 0;
618 {
619 size_t new_start = 0;
620 size_t new_size = 0;
621 for (size_t i = 0; i < 9; ++i)
622 {
623 if (i < 8 && v.s6_addr16[i] == 0)
624 {
625 if (new_start + new_size == i)
626 {
627 new_size++;
628 }
629 else
630 {
631 new_start = i;
632 new_size = 1;
633 }
634 }
635 else if (new_start + new_size == i && new_size > skip_size)
636 {
637 skip_start = new_start;
638 skip_size = new_size;
639 }
640 }
641 }
642 for (size_t i = 0; i < 8; ++i)
643 {
644 if (i == skip_start && skip_size > 1)
645 {
646 if (i == 0)
647 {
648 *(buf++) = ':';
649 }
650 *(buf++) = ':';
651 i += skip_size - 1;
652 continue;
653 }
654 buf = EncodeInt<uint16_t, 16>{}(buf, ntoh(v.s6_addr16[i]));
655 if (i < 7)
656 {
657 *(buf++) = ':';
658 }
659 }
660 return buf;
661 }
662};
663
664template <>
665struct ToStr<InAddrAny>
666{
667 // IPv6 is the bigger of the addrs
668 static constexpr uint8_t buf_size = ToStr<in6_addr>::buf_size;
669 using buf_type = std::array<char, buf_size>;
670
671 constexpr char* operator()(char* buf, InAddrAny v) const noexcept
672 {
673 return std::visit([=](auto v) { return ToStr<decltype(v)>{}(buf, v); },
674 v);
675 }
676};
677
678template <>
679struct ToStr<IfAddr>
680{
681 // InAddrAny + sep + 3 prefix chars
682 static constexpr uint8_t buf_size = ToStr<InAddrAny>::buf_size + 4;
683 using buf_type = std::array<char, buf_size>;
684
685 constexpr char* operator()(char* buf, IfAddr v) const noexcept
686 {
687 buf = ToStr<InAddrAny>{}(buf, v.getAddr());
688 buf = ToStr<char>{}(buf, '/');
689 return EncodeInt<uint8_t, 10>{}(buf, v.getPfx());
690 }
691};
692
William A. Kennington III238ef992022-11-03 12:47:49 -0700693namespace detail
694{
William A. Kennington III71de63a2022-11-08 10:50:54 -0800695
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700696template <typename T>
697constexpr bool vcontains() noexcept
698{
699 return false;
700}
701
702template <typename T, typename V, typename... Vs>
703constexpr bool vcontains() noexcept
704{
705 return vcontains<T, Vs...>() || std::is_same_v<T, V>;
706}
707
708template <typename T, typename... Types>
709constexpr std::enable_if_t<vcontains<T, Types...>(), bool>
710 veq(T t, std::variant<Types...> v) noexcept
711{
712 return std::visit(
713 [t](auto v) {
714 if constexpr (std::is_same_v<T, decltype(v)>)
715 {
716 return v == t;
717 }
718 else
719 {
720 return false;
721 }
722 },
723 v);
724}
725
726template <typename T>
William A. Kennington III55bdc362022-11-04 17:57:21 -0700727struct ToStrBuf
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700728{
729 public:
William A. Kennington III55bdc362022-11-04 17:57:21 -0700730 constexpr std::string_view operator()(T v) noexcept
731 {
732 return {buf.data(), ToStr<T>{}(buf.data(), v)};
733 }
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700734
735 private:
William A. Kennington III55bdc362022-11-04 17:57:21 -0700736 typename ToStr<T>::buf_type buf;
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700737};
738
William A. Kennington III55bdc362022-11-04 17:57:21 -0700739template <typename T>
740struct Format
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700741{
742 private:
743 fmt::formatter<std::string_view> formatter;
744
745 public:
746 template <typename ParseContext>
747 constexpr auto parse(ParseContext& ctx)
748 {
749 return ctx.begin();
750 }
751
752 template <typename FormatContext>
753 auto format(auto v, FormatContext& ctx) const
754 {
William A. Kennington III55bdc362022-11-04 17:57:21 -0700755 return formatter.format(ToStrBuf<T>{}(v), ctx);
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700756 }
757};
758} // namespace detail
Gunnar Mills57d9c502018-09-14 14:42:34 -0500759} // namespace network
760} // namespace phosphor
William A. Kennington III3e471c52022-10-27 19:46:07 -0700761
762template <typename... Ts>
763struct std::hash<std::tuple<Ts...>>
764{
765 constexpr auto operator()(const std::tuple<Ts...>& t) const noexcept
766 {
767 return std::apply(phosphor::network::hash_multi<Ts...>, t);
768 }
769};
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700770
William A. Kennington III653114f2022-11-01 22:34:04 -0700771template <>
772struct std::hash<in_addr>
773{
774 std::size_t operator()(in_addr addr) const noexcept;
775};
776
777template <>
778struct std::hash<in6_addr>
779{
780 std::size_t operator()(in6_addr addr) const noexcept;
781};
782
William A. Kennington IIIb9d7cba2022-11-08 10:54:11 -0800783template <>
784struct std::hash<phosphor::network::IfAddr>
785{
786 std::size_t operator()(phosphor::network::IfAddr addr) const noexcept;
787};
788
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700789namespace fmt
790{
791template <>
William A. Kennington III55bdc362022-11-04 17:57:21 -0700792struct formatter<ether_addr> : phosphor::network::detail::Format<ether_addr>
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700793{
794};
795template <>
William A. Kennington III55bdc362022-11-04 17:57:21 -0700796struct formatter<in_addr> : phosphor::network::detail::Format<in_addr>
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700797{
798};
799template <>
William A. Kennington III55bdc362022-11-04 17:57:21 -0700800struct formatter<in6_addr> : phosphor::network::detail::Format<in6_addr>
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700801{
802};
803template <>
804struct formatter<phosphor::network::InAddrAny>
William A. Kennington III55bdc362022-11-04 17:57:21 -0700805 : phosphor::network::detail::Format<phosphor::network::InAddrAny>
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700806{
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700807};
William A. Kennington IIIb9d7cba2022-11-08 10:54:11 -0800808template <>
809struct formatter<phosphor::network::IfAddr>
William A. Kennington III55bdc362022-11-04 17:57:21 -0700810 : phosphor::network::detail::Format<phosphor::network::IfAddr>
William A. Kennington IIIb9d7cba2022-11-08 10:54:11 -0800811{
William A. Kennington IIIb9d7cba2022-11-08 10:54:11 -0800812};
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700813} // namespace fmt
814
815namespace std
816{
817string to_string(ether_addr value);
818string to_string(in_addr value);
819string to_string(in6_addr value);
820string to_string(phosphor::network::InAddrAny value);
William A. Kennington IIIb9d7cba2022-11-08 10:54:11 -0800821string to_string(phosphor::network::IfAddr value);
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700822} // namespace std
823
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700824template <typename T>
825constexpr std::enable_if_t<!std::is_same_v<phosphor::network::InAddrAny, T>,
826 bool>
827 operator==(phosphor::network::InAddrAny lhs, T rhs) noexcept
828{
829 return phosphor::network::detail::veq(rhs, lhs);
830}
831
William A. Kennington III86eb8b72022-11-01 22:35:04 -0700832auto& operator<<(auto& os, ether_addr v)
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700833{
William A. Kennington III55bdc362022-11-04 17:57:21 -0700834 return os << phosphor::network::detail::ToStrBuf<ether_addr>{}(v);
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700835}
836
William A. Kennington III86eb8b72022-11-01 22:35:04 -0700837auto& operator<<(auto& os, in_addr v)
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700838{
William A. Kennington III55bdc362022-11-04 17:57:21 -0700839 return os << phosphor::network::detail::ToStrBuf<in_addr>{}(v);
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700840}
841
William A. Kennington III86eb8b72022-11-01 22:35:04 -0700842auto& operator<<(auto& os, in6_addr v)
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700843{
William A. Kennington III55bdc362022-11-04 17:57:21 -0700844 return os << phosphor::network::detail::ToStrBuf<in6_addr>{}(v);
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700845}
846
William A. Kennington III86eb8b72022-11-01 22:35:04 -0700847auto& operator<<(auto& os, phosphor::network::InAddrAny v)
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700848{
William A. Kennington III55bdc362022-11-04 17:57:21 -0700849 phosphor::network::detail::ToStrBuf<phosphor::network::InAddrAny> tsb;
850 return os << tsb(v);
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700851}
William A. Kennington IIIb9d7cba2022-11-08 10:54:11 -0800852
853auto& operator<<(auto& os, phosphor::network::IfAddr v)
854{
William A. Kennington III55bdc362022-11-04 17:57:21 -0700855 phosphor::network::detail::ToStrBuf<phosphor::network::IfAddr> tsb;
856 return os << tsb(v);
William A. Kennington IIIb9d7cba2022-11-08 10:54:11 -0800857}