blob: f1f217975e6a0b222bb4895a7c91f9ecc2fe1098 [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{
187
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700188template <typename T>
189constexpr bool vcontains() noexcept
190{
191 return false;
192}
193
194template <typename T, typename V, typename... Vs>
195constexpr bool vcontains() noexcept
196{
197 return vcontains<T, Vs...>() || std::is_same_v<T, V>;
198}
199
200template <typename T, typename... Types>
201constexpr std::enable_if_t<vcontains<T, Types...>(), bool>
202 veq(T t, std::variant<Types...> v) noexcept
203{
204 return std::visit(
205 [t](auto v) {
206 if constexpr (std::is_same_v<T, decltype(v)>)
207 {
208 return v == t;
209 }
210 else
211 {
212 return false;
213 }
214 },
215 v);
216}
217
218template <typename T>
219struct AddrBufMaker
220{
221};
222
223template <>
224struct AddrBufMaker<ether_addr>
225{
226 public:
227 std::string_view operator()(ether_addr val) noexcept;
228
229 private:
230 std::array<char, /*octet*/ 2 * /*octets*/ 6 + /*seps*/ 5> buf;
231};
232
233template <>
234struct AddrBufMaker<in_addr>
235{
236 public:
237 std::string_view operator()(in_addr val) noexcept;
238
239 private:
240 std::array<char, /*octet*/ 3 * /*octets*/ 4 + /*seps*/ 3> buf;
241};
242
243template <>
244struct AddrBufMaker<in6_addr>
245{
246 public:
247 std::string_view operator()(in6_addr val) noexcept;
248
249 private:
250 std::array<char, /*hextet*/ 4 * /*hextets*/ 8 + /*seps*/ 7> buf;
251};
252
253template <typename BufMaker>
254struct FormatFromBuf
255{
256 private:
257 fmt::formatter<std::string_view> formatter;
258
259 public:
260 template <typename ParseContext>
261 constexpr auto parse(ParseContext& ctx)
262 {
263 return ctx.begin();
264 }
265
266 template <typename FormatContext>
267 auto format(auto v, FormatContext& ctx) const
268 {
269 return formatter.format(BufMaker{}(v), ctx);
270 }
271};
272} // namespace detail
Gunnar Mills57d9c502018-09-14 14:42:34 -0500273} // namespace network
274} // namespace phosphor
William A. Kennington III3e471c52022-10-27 19:46:07 -0700275
276template <typename... Ts>
277struct std::hash<std::tuple<Ts...>>
278{
279 constexpr auto operator()(const std::tuple<Ts...>& t) const noexcept
280 {
281 return std::apply(phosphor::network::hash_multi<Ts...>, t);
282 }
283};
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700284
William A. Kennington III653114f2022-11-01 22:34:04 -0700285template <>
286struct std::hash<in_addr>
287{
288 std::size_t operator()(in_addr addr) const noexcept;
289};
290
291template <>
292struct std::hash<in6_addr>
293{
294 std::size_t operator()(in6_addr addr) const noexcept;
295};
296
William A. Kennington IIIb9d7cba2022-11-08 10:54:11 -0800297template <>
298struct std::hash<phosphor::network::IfAddr>
299{
300 std::size_t operator()(phosphor::network::IfAddr addr) const noexcept;
301};
302
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700303namespace fmt
304{
305template <>
306struct formatter<ether_addr>
307 : phosphor::network::detail::FormatFromBuf<
308 phosphor::network::detail::AddrBufMaker<ether_addr>>
309{
310};
311template <>
312struct formatter<in_addr>
313 : phosphor::network::detail::FormatFromBuf<
314 phosphor::network::detail::AddrBufMaker<in_addr>>
315{
316};
317template <>
318struct formatter<in6_addr>
319 : phosphor::network::detail::FormatFromBuf<
320 phosphor::network::detail::AddrBufMaker<in6_addr>>
321{
322};
323template <>
324struct formatter<phosphor::network::InAddrAny>
325{
326 private:
327 fmt::formatter<std::string_view> formatter;
328
329 public:
330 template <typename ParseContext>
331 constexpr auto parse(ParseContext& ctx)
332 {
333 return ctx.begin();
334 }
335
336 template <typename FormatContext>
337 auto format(auto v, FormatContext& ctx) const
338 {
339 return std::visit(
340 [&](auto v) {
341 auto abm =
342 phosphor::network::detail::AddrBufMaker<decltype(v)>{};
343 return formatter.format(abm(v), ctx);
344 },
345 v);
346 }
347};
William A. Kennington IIIb9d7cba2022-11-08 10:54:11 -0800348template <>
349struct formatter<phosphor::network::IfAddr>
350{
351 private:
352 fmt::formatter<phosphor::network::InAddrAny> addrF;
353 fmt::formatter<char> strF;
354 fmt::formatter<uint8_t> numF;
355
356 public:
357 template <typename ParseContext>
358 constexpr auto parse(ParseContext& ctx)
359 {
360 return ctx.begin();
361 }
362
363 template <typename FormatContext>
364 auto format(auto v, FormatContext& ctx) const
365 {
366 addrF.format(v.getAddr(), ctx);
367 strF.format('/', ctx);
368 return numF.format(v.getPfx(), ctx);
369 }
370};
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700371} // namespace fmt
372
373namespace std
374{
375string to_string(ether_addr value);
376string to_string(in_addr value);
377string to_string(in6_addr value);
378string to_string(phosphor::network::InAddrAny value);
William A. Kennington IIIb9d7cba2022-11-08 10:54:11 -0800379string to_string(phosphor::network::IfAddr value);
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700380} // namespace std
381
382constexpr bool operator==(ether_addr lhs, ether_addr rhs) noexcept
383{
384 return std::equal(lhs.ether_addr_octet, lhs.ether_addr_octet + 6,
385 rhs.ether_addr_octet);
386}
387
388constexpr bool operator==(in_addr lhs, in_addr rhs) noexcept
389{
390 return lhs.s_addr == rhs.s_addr;
391}
392
393constexpr bool operator==(in6_addr lhs, in6_addr rhs) noexcept
394{
395 return std::equal(lhs.s6_addr32, lhs.s6_addr32 + 4, rhs.s6_addr32);
396}
397
398template <typename T>
399constexpr std::enable_if_t<!std::is_same_v<phosphor::network::InAddrAny, T>,
400 bool>
401 operator==(phosphor::network::InAddrAny lhs, T rhs) noexcept
402{
403 return phosphor::network::detail::veq(rhs, lhs);
404}
405
William A. Kennington III86eb8b72022-11-01 22:35:04 -0700406auto& operator<<(auto& os, ether_addr v)
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700407{
408 return os << phosphor::network::detail::AddrBufMaker<ether_addr>{}(v);
409}
410
William A. Kennington III86eb8b72022-11-01 22:35:04 -0700411auto& operator<<(auto& os, in_addr v)
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700412{
413 return os << phosphor::network::detail::AddrBufMaker<in_addr>{}(v);
414}
415
William A. Kennington III86eb8b72022-11-01 22:35:04 -0700416auto& operator<<(auto& os, in6_addr v)
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700417{
418 return os << phosphor::network::detail::AddrBufMaker<in6_addr>{}(v);
419}
420
William A. Kennington III86eb8b72022-11-01 22:35:04 -0700421auto& operator<<(auto& os, phosphor::network::InAddrAny v)
William A. Kennington IIIbb0eacc2022-10-21 15:22:06 -0700422{
423 return os << std::visit(
424 [](auto v) {
425 return phosphor::network::detail::AddrBufMaker<
426 decltype(v)>{}(v);
427 },
428 v);
429}
William A. Kennington IIIb9d7cba2022-11-08 10:54:11 -0800430
431auto& operator<<(auto& os, phosphor::network::IfAddr v)
432{
433 return os << v.getAddr() << "/" << std::dec << int{v.getPfx()};
434}