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         {
35             return true;
36         }
37         case RTM_NEWNEIGH:
38         case RTM_DELNEIGH:
39         {
40             struct ndmsg ndm;
41             if (data.size() < sizeof(ndm))
42             {
43                 return false;
44             }
45             memcpy(&ndm, data.data(), sizeof(ndm));
46             // We only want to refresh for static neighbors
47             return ndm.ndm_state & NUD_PERMANENT;
48         }
49     }
50 
51     return false;
52 }
53 
54 static void handler(const nlmsghdr& hdr, std::string_view data)
55 {
56     if (shouldRefresh(hdr, data) && !refreshObjectTimer->isEnabled())
57     {
58         refreshObjectTimer->restartOnce(refreshTimeout);
59     }
60 }
61 
62 static void eventHandler(sdeventplus::source::IO&, int fd, uint32_t)
63 {
64     receive(fd, handler);
65 }
66 
67 static stdplus::ManagedFd makeSock()
68 {
69     using namespace stdplus::fd;
70 
71     auto sock = socket(SocketDomain::Netlink, SocketType::Raw,
72                        static_cast<stdplus::fd::SocketProto>(NETLINK_ROUTE));
73 
74     sock.fcntlSetfl(sock.fcntlGetfl().set(FileFlag::NonBlock));
75 
76     sockaddr_nl local{};
77     local.nl_family = AF_NETLINK;
78     local.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR |
79                       RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_NEIGH;
80     bind(sock, local);
81 
82     return sock;
83 }
84 
85 Server::Server(sdeventplus::Event& event) :
86     sock(makeSock()), io(event, sock.get(), EPOLLIN | EPOLLET, eventHandler)
87 {
88 }
89 
90 } // namespace netlink
91 } // namespace network
92 } // namespace phosphor
93