blob: 73d27789552fa42d2b99170daa0519b21f48f888 [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
Ratan Gupta82549cc2017-04-21 08:45:23 +053019namespace phosphor
20{
21namespace network
22{
Ratan Guptae05083a2017-09-16 07:12:11 +053023
24using namespace std::chrono_literals;
Ratan Gupta16f12882017-09-22 18:26:11 +053025
William A. Kennington IIIc7cf25f2021-11-09 16:16:59 -080026// wait for three seconds before reloading systemd-networkd
27constexpr auto reloadTimeout = 3s;
Ratan Gupta16f12882017-09-22 18:26:11 +053028
William A. Kennington IIId41db382021-11-09 20:42:29 -080029// refresh the objets after four seconds as network
30// configuration takes 3-4 sec to reconfigure at most.
31constexpr auto refreshTimeout = 4s;
Ratan Guptae05083a2017-09-16 07:12:11 +053032
William A. Kennington III0d7ce482019-01-30 17:14:23 -080033// Byte representations for common address types in network byte order
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -070034using InAddrAny = std::variant<in_addr, in6_addr>;
William A. Kennington IIIb9d7cba2022-11-08 10:54:11 -080035class IfAddr
36{
37 private:
38 InAddrAny addr;
39 uint8_t pfx;
40
41 static void invalidPfx(uint8_t pfx);
42
43 public:
44 constexpr IfAddr() : addr({}), pfx(0)
45 {
46 }
47
48 constexpr IfAddr(InAddrAny addr, uint8_t pfx) : addr(addr), pfx(pfx)
49 {
50 std::visit(
51 [pfx](auto v) {
52 if (sizeof(v) * 8 < pfx)
53 {
54 invalidPfx(pfx);
55 }
56 },
57 addr);
58 }
59
60 constexpr auto getAddr() const
61 {
62 return addr;
63 }
64
65 constexpr auto getPfx() const
66 {
67 return pfx;
68 }
69
70 constexpr bool operator==(phosphor::network::IfAddr rhs) const noexcept
71 {
72 return addr == rhs.addr && pfx == rhs.pfx;
73 }
74};
William A. Kennington III0d7ce482019-01-30 17:14:23 -080075
William A. Kennington III3a70fa22018-09-20 18:48:20 -070076using Timer = sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>;
77
William A. Kennington IIIdd9ef812022-10-05 02:08:02 -070078struct string_hash : public std::hash<std::string_view>
79{
80 using is_transparent = void;
81};
82template <typename V>
83using string_umap =
84 std::unordered_map<std::string, V, string_hash, std::equal_to<>>;
William A. Kennington III96444792022-10-05 15:16:22 -070085using string_uset =
86 std::unordered_set<std::string, string_hash, std::equal_to<>>;
William A. Kennington IIIdd9ef812022-10-05 02:08:02 -070087
William A. Kennington III3e471c52022-10-27 19:46:07 -070088constexpr std::size_t hash_multi() noexcept
William A. Kennington III991a8e82022-10-11 15:02:47 -070089{
90 return 0;
91}
92
93template <typename T, typename... Args>
William A. Kennington IIIbecda1a2022-11-03 12:44:59 -070094constexpr std::size_t hash_multi(const T& v, const Args&... args) noexcept
William A. Kennington III991a8e82022-10-11 15:02:47 -070095{
96 const std::size_t seed = hash_multi(args...);
97 return seed ^ (std::hash<T>{}(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2));
98}
99
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700100namespace detail
101{
102
William A. Kennington III71de63a2022-11-08 10:50:54 -0800103template <typename T, uint8_t size = sizeof(T)>
104struct BswapAlign
105{
106 using type = T;
107};
108
109template <typename T>
110struct BswapAlign<T, 2>
111{
112 using type alignas(uint16_t) = T;
113};
114
115template <typename T>
116struct BswapAlign<T, 4>
117{
118 using type alignas(uint32_t) = T;
119};
120
121template <typename T>
122struct BswapAlign<T, 8>
123{
124 using type alignas(uint64_t) = T;
125};
126
127template <typename T>
128constexpr T bswapInt(typename BswapAlign<T>::type n) noexcept
129{
130 static_assert(std::is_trivially_copyable_v<T>);
131 if constexpr (sizeof(T) == 2)
132 {
133 reinterpret_cast<uint16_t&>(n) =
134 __builtin_bswap16(reinterpret_cast<uint16_t&>(n));
135 }
136 else if constexpr (sizeof(T) == 4)
137 {
138 reinterpret_cast<uint32_t&>(n) =
139 __builtin_bswap32(reinterpret_cast<uint32_t&>(n));
140 }
141 else if constexpr (sizeof(T) == 8)
142 {
143 reinterpret_cast<uint64_t&>(n) =
144 __builtin_bswap64(reinterpret_cast<uint64_t&>(n));
145 }
146 else
147 {
148 auto b = reinterpret_cast<std::byte*>(&n);
149 std::reverse(b, b + sizeof(n));
150 }
151 return n;
152}
153
154} // namespace detail
155
156template <typename T>
157constexpr T bswap(T n) noexcept
158{
159 return detail::bswapInt<T>(n);
160}
161
162template <typename T>
163constexpr T hton(T n) noexcept
164{
165 if constexpr (std::endian::native == std::endian::big)
166 {
167 return n;
168 }
169 else if constexpr (std::endian::native == std::endian::little)
170 {
171 return bswap(n);
172 }
173 else
174 {
175 static_assert(std::is_same_v<T, void>);
176 }
177}
178
179template <typename T>
180constexpr T ntoh(T n) noexcept
181{
182 return hton(n);
183}
184
185namespace detail
186{
William A. Kennington III238ef992022-11-03 12:47:49 -0700187inline constexpr auto charLookup = []() {
188 std::array<int8_t, 256> ret;
189 std::fill(ret.begin(), ret.end(), -1);
190 for (int8_t i = 0; i < 10; ++i)
191 {
192 ret[i + '0'] = i;
193 }
194 for (int8_t i = 0; i < 26; ++i)
195 {
196 ret[i + 'A'] = i + 10;
197 ret[i + 'a'] = i + 10;
198 }
199 return ret;
200}();
201}
202
203template <typename T, uint8_t base>
204struct DecodeInt
205{
206 static_assert(base > 1 && base <= 36);
207 static_assert(std::is_unsigned_v<T>);
208
209 constexpr T operator()(std::string_view str) const
210 {
211 if (str.empty())
212 {
213 throw std::invalid_argument("Empty Str");
214 }
215 constexpr auto max = std::numeric_limits<T>::max();
216 auto ret =
217 std::accumulate(str.begin(), str.end(), T{}, [&](T r, char c) {
218 auto v = detail::charLookup[c];
219 if (v < 0 || v >= base)
220 {
221 throw std::invalid_argument("Invalid numeral");
222 }
223 if constexpr (std::popcount(base) == 1)
224 {
225 constexpr auto shift = std::countr_zero(base);
226 constexpr auto maxshift = max >> shift;
227 if (r > maxshift)
228 {
229 throw std::overflow_error("Integer Decode");
230 }
231 return (r << shift) | v;
232 }
233 else
234 {
235 constexpr auto maxbase = max / base;
236 if (r > maxbase)
237 {
238 throw std::overflow_error("Integer Decode");
239 }
240 r *= base;
241 if (max - v < r)
242 {
243 throw std::overflow_error("Integer Decode");
244 }
245 return r + v;
246 }
247 });
248 return ret;
249 }
250};
251
William A. Kennington IIIb01d08f2022-11-03 12:50:00 -0700252template <typename T>
253struct ToAddr
254{
255};
256
257template <>
258struct ToAddr<ether_addr>
259{
260 constexpr ether_addr operator()(std::string_view str) const
261 {
262 constexpr DecodeInt<uint8_t, 16> di;
263 ether_addr ret;
264 if (str.size() == 12 && str.find(":") == str.npos)
265 {
266 for (size_t i = 0; i < 6; ++i)
267 {
268 ret.ether_addr_octet[i] = di(str.substr(i * 2, 2));
269 }
270 }
271 else
272 {
273 for (size_t i = 0; i < 5; ++i)
274 {
275 auto loc = str.find(":");
276 ret.ether_addr_octet[i] = di(str.substr(0, loc));
277 str.remove_prefix(loc == str.npos ? str.size() : loc + 1);
278 if (str.empty())
279 {
280 throw std::invalid_argument("Missing mac data");
281 }
282 }
283 ret.ether_addr_octet[5] = di(str);
284 }
285 return ret;
286 }
287};
288
William A. Kennington IIIdf1178e2022-11-03 12:56:33 -0700289template <>
290struct ToAddr<in_addr>
291{
292 constexpr in_addr operator()(std::string_view str) const
293 {
294 constexpr DecodeInt<uint8_t, 10> di;
295 uint32_t addr = {};
296 for (size_t i = 0; i < 3; ++i)
297 {
298 auto loc = str.find(".");
299 addr |= di(str.substr(0, loc));
300 addr <<= 8;
301 str.remove_prefix(loc == str.npos ? str.size() : loc + 1);
302 if (str.empty())
303 {
304 throw std::invalid_argument("Missing addr data");
305 }
306 }
307 addr |= di(str);
308 return {hton(addr)};
309 }
310};
311
William A. Kennington IIIec496a82022-11-04 02:17:20 -0700312template <>
313struct ToAddr<in6_addr>
314{
315 constexpr in6_addr operator()(std::string_view str) const
316 {
317 constexpr DecodeInt<uint16_t, 16> di;
318 in6_addr ret = {};
319 size_t i = 0;
320 while (i < 8)
321 {
322 auto loc = str.find(':');
323 if (i == 6 && loc == str.npos)
324 {
325 ret.s6_addr32[3] = ToAddr<in_addr>{}(str).s_addr;
326 return ret;
327 }
328 if (loc != 0 && !str.empty())
329 {
330 ret.s6_addr16[i++] = hton(di(str.substr(0, loc)));
331 }
332 if (i < 8 && str.size() > loc + 1 && str[loc + 1] == ':')
333 {
334 str.remove_prefix(loc + 2);
335 break;
336 }
337 else if (str.empty())
338 {
339 throw std::invalid_argument("IPv6 Data");
340 }
341 str.remove_prefix(loc == str.npos ? str.size() : loc + 1);
342 }
343 if (str.starts_with(':'))
344 {
345 throw std::invalid_argument("Extra separator");
346 }
347 size_t j = 7;
348 if (!str.empty() && i < 6 && str.find('.') != str.npos)
349 {
350 auto loc = str.rfind(':');
351 ret.s6_addr32[3] =
352 ToAddr<in_addr>{}(str.substr(loc == str.npos ? 0 : loc + 1))
353 .s_addr;
354 str.remove_suffix(loc == str.npos ? str.size() : str.size() - loc);
355 j -= 2;
356 }
357 while (!str.empty() && j > i)
358 {
359 auto loc = str.rfind(':');
360 ret.s6_addr16[j--] =
361 hton(di(str.substr(loc == str.npos ? 0 : loc + 1)));
362 str.remove_suffix(loc == str.npos ? str.size() : str.size() - loc);
363 }
364 if (!str.empty())
365 {
366 throw std::invalid_argument("Too much data");
367 }
368 return ret;
369 }
370};
371
William A. Kennington IIIead71982022-11-04 02:18:10 -0700372template <>
373struct ToAddr<InAddrAny>
374{
375 constexpr InAddrAny operator()(std::string_view str) const
376 {
377 if (str.find(':') == str.npos)
378 {
379 return ToAddr<in_addr>{}(str);
380 }
381 return ToAddr<in6_addr>{}(str);
382 }
383};
384
385template <>
386struct ToAddr<IfAddr>
387{
388 constexpr IfAddr operator()(std::string_view str) const
389 {
390 auto pos = str.rfind('/');
391 if (pos == str.npos)
392 {
393 throw std::invalid_argument("Invalid IfAddr");
394 }
395 return {ToAddr<InAddrAny>{}(str.substr(0, pos)),
396 DecodeInt<uint8_t, 10>{}(str.substr(pos + 1))};
397 }
398};
399
William A. Kennington III238ef992022-11-03 12:47:49 -0700400namespace detail
401{
William A. Kennington III71de63a2022-11-08 10:50:54 -0800402
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700403template <typename T>
404constexpr bool vcontains() noexcept
405{
406 return false;
407}
408
409template <typename T, typename V, typename... Vs>
410constexpr bool vcontains() noexcept
411{
412 return vcontains<T, Vs...>() || std::is_same_v<T, V>;
413}
414
415template <typename T, typename... Types>
416constexpr std::enable_if_t<vcontains<T, Types...>(), bool>
417 veq(T t, std::variant<Types...> v) noexcept
418{
419 return std::visit(
420 [t](auto v) {
421 if constexpr (std::is_same_v<T, decltype(v)>)
422 {
423 return v == t;
424 }
425 else
426 {
427 return false;
428 }
429 },
430 v);
431}
432
433template <typename T>
434struct AddrBufMaker
435{
436};
437
438template <>
439struct AddrBufMaker<ether_addr>
440{
441 public:
442 std::string_view operator()(ether_addr val) noexcept;
443
444 private:
445 std::array<char, /*octet*/ 2 * /*octets*/ 6 + /*seps*/ 5> buf;
446};
447
448template <>
449struct AddrBufMaker<in_addr>
450{
451 public:
452 std::string_view operator()(in_addr val) noexcept;
453
454 private:
455 std::array<char, /*octet*/ 3 * /*octets*/ 4 + /*seps*/ 3> buf;
456};
457
458template <>
459struct AddrBufMaker<in6_addr>
460{
461 public:
462 std::string_view operator()(in6_addr val) noexcept;
463
464 private:
465 std::array<char, /*hextet*/ 4 * /*hextets*/ 8 + /*seps*/ 7> buf;
466};
467
468template <typename BufMaker>
469struct FormatFromBuf
470{
471 private:
472 fmt::formatter<std::string_view> formatter;
473
474 public:
475 template <typename ParseContext>
476 constexpr auto parse(ParseContext& ctx)
477 {
478 return ctx.begin();
479 }
480
481 template <typename FormatContext>
482 auto format(auto v, FormatContext& ctx) const
483 {
484 return formatter.format(BufMaker{}(v), ctx);
485 }
486};
487} // namespace detail
Gunnar Mills57d9c502018-09-14 14:42:34 -0500488} // namespace network
489} // namespace phosphor
William A. Kennington III3e471c52022-10-27 19:46:07 -0700490
491template <typename... Ts>
492struct std::hash<std::tuple<Ts...>>
493{
494 constexpr auto operator()(const std::tuple<Ts...>& t) const noexcept
495 {
496 return std::apply(phosphor::network::hash_multi<Ts...>, t);
497 }
498};
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700499
William A. Kennington III653114f2022-11-01 22:34:04 -0700500template <>
501struct std::hash<in_addr>
502{
503 std::size_t operator()(in_addr addr) const noexcept;
504};
505
506template <>
507struct std::hash<in6_addr>
508{
509 std::size_t operator()(in6_addr addr) const noexcept;
510};
511
William A. Kennington IIIb9d7cba2022-11-08 10:54:11 -0800512template <>
513struct std::hash<phosphor::network::IfAddr>
514{
515 std::size_t operator()(phosphor::network::IfAddr addr) const noexcept;
516};
517
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700518namespace fmt
519{
520template <>
521struct formatter<ether_addr>
522 : phosphor::network::detail::FormatFromBuf<
523 phosphor::network::detail::AddrBufMaker<ether_addr>>
524{
525};
526template <>
527struct formatter<in_addr>
528 : phosphor::network::detail::FormatFromBuf<
529 phosphor::network::detail::AddrBufMaker<in_addr>>
530{
531};
532template <>
533struct formatter<in6_addr>
534 : phosphor::network::detail::FormatFromBuf<
535 phosphor::network::detail::AddrBufMaker<in6_addr>>
536{
537};
538template <>
539struct formatter<phosphor::network::InAddrAny>
540{
541 private:
542 fmt::formatter<std::string_view> formatter;
543
544 public:
545 template <typename ParseContext>
546 constexpr auto parse(ParseContext& ctx)
547 {
548 return ctx.begin();
549 }
550
551 template <typename FormatContext>
552 auto format(auto v, FormatContext& ctx) const
553 {
554 return std::visit(
555 [&](auto v) {
556 auto abm =
557 phosphor::network::detail::AddrBufMaker<decltype(v)>{};
558 return formatter.format(abm(v), ctx);
559 },
560 v);
561 }
562};
William A. Kennington IIIb9d7cba2022-11-08 10:54:11 -0800563template <>
564struct formatter<phosphor::network::IfAddr>
565{
566 private:
567 fmt::formatter<phosphor::network::InAddrAny> addrF;
568 fmt::formatter<char> strF;
569 fmt::formatter<uint8_t> numF;
570
571 public:
572 template <typename ParseContext>
573 constexpr auto parse(ParseContext& ctx)
574 {
575 return ctx.begin();
576 }
577
578 template <typename FormatContext>
579 auto format(auto v, FormatContext& ctx) const
580 {
581 addrF.format(v.getAddr(), ctx);
582 strF.format('/', ctx);
583 return numF.format(v.getPfx(), ctx);
584 }
585};
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700586} // namespace fmt
587
588namespace std
589{
590string to_string(ether_addr value);
591string to_string(in_addr value);
592string to_string(in6_addr value);
593string to_string(phosphor::network::InAddrAny value);
William A. Kennington IIIb9d7cba2022-11-08 10:54:11 -0800594string to_string(phosphor::network::IfAddr value);
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700595} // namespace std
596
597constexpr bool operator==(ether_addr lhs, ether_addr rhs) noexcept
598{
599 return std::equal(lhs.ether_addr_octet, lhs.ether_addr_octet + 6,
600 rhs.ether_addr_octet);
601}
602
603constexpr bool operator==(in_addr lhs, in_addr rhs) noexcept
604{
605 return lhs.s_addr == rhs.s_addr;
606}
607
608constexpr bool operator==(in6_addr lhs, in6_addr rhs) noexcept
609{
610 return std::equal(lhs.s6_addr32, lhs.s6_addr32 + 4, rhs.s6_addr32);
611}
612
613template <typename T>
614constexpr std::enable_if_t<!std::is_same_v<phosphor::network::InAddrAny, T>,
615 bool>
616 operator==(phosphor::network::InAddrAny lhs, T rhs) noexcept
617{
618 return phosphor::network::detail::veq(rhs, lhs);
619}
620
William A. Kennington III86eb8b72022-11-01 22:35:04 -0700621auto& operator<<(auto& os, ether_addr v)
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700622{
623 return os << phosphor::network::detail::AddrBufMaker<ether_addr>{}(v);
624}
625
William A. Kennington III86eb8b72022-11-01 22:35:04 -0700626auto& operator<<(auto& os, in_addr v)
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700627{
628 return os << phosphor::network::detail::AddrBufMaker<in_addr>{}(v);
629}
630
William A. Kennington III86eb8b72022-11-01 22:35:04 -0700631auto& operator<<(auto& os, in6_addr v)
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700632{
633 return os << phosphor::network::detail::AddrBufMaker<in6_addr>{}(v);
634}
635
William A. Kennington III86eb8b72022-11-01 22:35:04 -0700636auto& operator<<(auto& os, phosphor::network::InAddrAny v)
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700637{
638 return os << std::visit(
639 [](auto v) {
640 return phosphor::network::detail::AddrBufMaker<
641 decltype(v)>{}(v);
642 },
643 v);
644}
William A. Kennington IIIb9d7cba2022-11-08 10:54:11 -0800645
646auto& operator<<(auto& os, phosphor::network::IfAddr v)
647{
648 return os << v.getAddr() << "/" << std::dec << int{v.getPfx()};
649}