1 #include "rtnetlink_server.hpp"
2 
3 #include "netlink.hpp"
4 #include "types.hpp"
5 
6 #include <linux/netlink.h>
7 #include <linux/rtnetlink.h>
8 #include <netinet/in.h>
9 
10 #include <memory>
11 #include <stdplus/fd/create.hpp>
12 #include <stdplus/fd/ops.hpp>
13 #include <string_view>
14 
15 namespace phosphor
16 {
17 namespace network
18 {
19 
20 extern std::unique_ptr<Timer> refreshObjectTimer;
21 
22 namespace netlink
23 {
24 
25 static bool shouldRefresh(const struct nlmsghdr& hdr,
26                           std::string_view data) noexcept
27 {
28     switch (hdr.nlmsg_type)
29     {
30         case RTM_NEWADDR:
31         case RTM_DELADDR:
32         case RTM_NEWROUTE:
33         case RTM_DELROUTE:
34             return true;
35         case RTM_NEWNEIGH:
36         case RTM_DELNEIGH:
37         {
38             if (data.size() < sizeof(ndmsg))
39             {
40                 return false;
41             }
42             const auto& ndm = *reinterpret_cast<const ndmsg*>(data.data());
43             // We only want to refresh for static neighbors
44             return ndm.ndm_state & NUD_PERMANENT;
45         }
46     }
47     return false;
48 }
49 
50 static void handler(const nlmsghdr& hdr, std::string_view data)
51 {
52     if (shouldRefresh(hdr, data) && !refreshObjectTimer->isEnabled())
53     {
54         refreshObjectTimer->restartOnce(refreshTimeout);
55     }
56 }
57 
58 static void eventHandler(sdeventplus::source::IO&, int fd, uint32_t)
59 {
60     while (receive(fd, handler) > 0)
61         ;
62 }
63 
64 static stdplus::ManagedFd makeSock()
65 {
66     using namespace stdplus::fd;
67 
68     auto sock = socket(SocketDomain::Netlink, SocketType::Raw,
69                        static_cast<stdplus::fd::SocketProto>(NETLINK_ROUTE));
70 
71     sock.fcntlSetfl(sock.fcntlGetfl().set(FileFlag::NonBlock));
72 
73     sockaddr_nl local{};
74     local.nl_family = AF_NETLINK;
75     local.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR |
76                       RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_NEIGH;
77     bind(sock, local);
78 
79     return sock;
80 }
81 
82 Server::Server(sdeventplus::Event& event) :
83     sock(makeSock()), io(event, sock.get(), EPOLLIN | EPOLLET, eventHandler)
84 {
85 }
86 
87 } // namespace netlink
88 } // namespace network
89 } // namespace phosphor
90