1 #include "rtnetlink.hpp"
2 
3 #include <linux/netlink.h>
4 #include <linux/rtnetlink.h>
5 
6 #include <stdplus/raw.hpp>
7 
8 #include <gtest/gtest.h>
9 
10 namespace phosphor::network::netlink
11 {
12 
13 TEST(IntfFromRtm, SmallMsg)
14 {
15     EXPECT_THROW(intfFromRtm("1"), std::runtime_error);
16 }
17 
18 TEST(IntfFromRtm, NoAttrs)
19 {
20     struct
21     {
22         ifinfomsg hdr __attribute__((aligned(NLMSG_ALIGNTO)));
23     } msg;
24     msg.hdr.ifi_index = 1;
25     msg.hdr.ifi_flags = 2;
26     EXPECT_EQ(intfFromRtm(stdplus::raw::asView<char>(msg)),
27               (InterfaceInfo{.idx = 1, .flags = 2}));
28 }
29 
30 TEST(IntfFromRtm, AllAttrs)
31 {
32     struct
33     {
34         ifinfomsg hdr __attribute__((aligned(NLMSG_ALIGNTO)));
35         rtattr addr_hdr __attribute__((aligned((RTA_ALIGNTO))));
36         char addr[6]
37             __attribute__((aligned((RTA_ALIGNTO)))) = {0, 1, 2, 3, 4, 5};
38         rtattr name_hdr __attribute__((aligned((RTA_ALIGNTO))));
39         char name[5] __attribute__((aligned((RTA_ALIGNTO)))) = "eth0";
40         rtattr mtu_hdr __attribute__((aligned((RTA_ALIGNTO))));
41         unsigned mtu __attribute__((aligned((RTA_ALIGNTO)))) = 50;
42     } msg;
43     msg.hdr.ifi_index = 1;
44     msg.hdr.ifi_flags = 2;
45     msg.addr_hdr.rta_type = IFLA_ADDRESS;
46     msg.addr_hdr.rta_len = RTA_LENGTH(sizeof(msg.addr));
47     msg.name_hdr.rta_type = IFLA_IFNAME;
48     msg.name_hdr.rta_len = RTA_LENGTH(sizeof(msg.name));
49     msg.mtu_hdr.rta_type = IFLA_MTU;
50     msg.mtu_hdr.rta_len = RTA_LENGTH(sizeof(msg.mtu));
51 
52     auto info = intfFromRtm(stdplus::raw::asView<char>(msg));
53     auto expected = InterfaceInfo{.idx = 1,
54                                   .flags = 2,
55                                   .name = "eth0",
56                                   .mac = ether_addr{0, 1, 2, 3, 4, 5},
57                                   .mtu = 50};
58     EXPECT_EQ(info, expected);
59 }
60 
61 TEST(AddrFromRtm, MissingAddr)
62 {
63     struct
64     {
65         alignas(NLMSG_ALIGNTO) ifaddrmsg ifa = {};
66     } msg;
67     EXPECT_THROW(addrFromRtm(stdplus::raw::asView<char>(msg)),
68                  std::runtime_error);
69 }
70 
71 TEST(AddrFromRtm, Regular)
72 {
73     struct
74     {
75         alignas(NLMSG_ALIGNTO) ifaddrmsg ifa;
76         alignas(NLMSG_ALIGNTO) rtattr addr_hdr;
77         alignas(NLMSG_ALIGNTO) uint8_t addr[4] = {192, 168, 1, 20};
78     } msg;
79     msg.ifa.ifa_family = AF_INET;
80     msg.ifa.ifa_prefixlen = 28;
81     msg.ifa.ifa_flags = 4;
82     msg.ifa.ifa_scope = 3;
83     msg.ifa.ifa_index = 10;
84     msg.addr_hdr.rta_type = IFA_ADDRESS;
85     msg.addr_hdr.rta_len = RTA_LENGTH(sizeof(msg.addr));
86 
87     auto ret = addrFromRtm(stdplus::raw::asView<char>(msg));
88     EXPECT_EQ(msg.ifa.ifa_flags, ret.flags);
89     EXPECT_EQ(msg.ifa.ifa_scope, ret.scope);
90     EXPECT_EQ(msg.ifa.ifa_index, ret.ifidx);
91     EXPECT_EQ((IfAddr{in_addr{hton(0xc0a80114)}, 28}), ret.ifaddr);
92 }
93 
94 TEST(AddrFromRtm, ExtraFlags)
95 {
96     struct
97     {
98         alignas(NLMSG_ALIGNTO) ifaddrmsg ifa = {};
99         alignas(NLMSG_ALIGNTO) rtattr flags_hdr;
100         alignas(NLMSG_ALIGNTO) uint32_t flags = 0xff00ff00;
101         alignas(NLMSG_ALIGNTO) rtattr addr_hdr;
102         alignas(NLMSG_ALIGNTO) uint8_t addr[16] = {};
103     } msg;
104     msg.ifa.ifa_family = AF_INET6;
105     msg.flags_hdr.rta_type = IFA_FLAGS;
106     msg.flags_hdr.rta_len = RTA_LENGTH(sizeof(msg.flags));
107     msg.addr_hdr.rta_type = IFA_ADDRESS;
108     msg.addr_hdr.rta_len = RTA_LENGTH(sizeof(msg.addr));
109 
110     auto ret = addrFromRtm(stdplus::raw::asView<char>(msg));
111     EXPECT_EQ(0xff00ff00, ret.flags);
112 }
113 
114 TEST(NeighFromRtm, MissingAddr)
115 {
116     struct
117     {
118         alignas(NLMSG_ALIGNTO) ndmsg ndm = {};
119     } msg;
120 
121     EXPECT_EQ((NeighborInfo{}), neighFromRtm(stdplus::raw::asView<char>(msg)));
122 }
123 
124 TEST(NeighFromRtm, NoMac)
125 {
126     struct
127     {
128         alignas(NLMSG_ALIGNTO) ndmsg ndm;
129         alignas(NLMSG_ALIGNTO) rtattr addr_hdr;
130         alignas(NLMSG_ALIGNTO) uint8_t addr[4] = {192, 168, 1, 20};
131     } msg;
132     msg.ndm.ndm_family = AF_INET;
133     msg.ndm.ndm_state = 4;
134     msg.addr_hdr.rta_type = NDA_DST;
135     msg.addr_hdr.rta_len = RTA_LENGTH(sizeof(msg.addr));
136 
137     auto ret = neighFromRtm(stdplus::raw::asView<char>(msg));
138     EXPECT_EQ(msg.ndm.ndm_state, ret.state);
139     EXPECT_EQ((in_addr{hton(0xc0a80114)}), ret.addr);
140     EXPECT_FALSE(ret.mac);
141 }
142 
143 TEST(NeighFromRtm, Full)
144 {
145     struct
146     {
147         alignas(NLMSG_ALIGNTO) ndmsg ndm;
148         alignas(NLMSG_ALIGNTO) rtattr addr_hdr;
149         alignas(NLMSG_ALIGNTO) uint8_t addr[4] = {192, 168, 1, 20};
150         alignas(NLMSG_ALIGNTO) rtattr mac_hdr;
151         alignas(NLMSG_ALIGNTO) uint8_t mac[6] = {1, 2, 3, 4, 5, 6};
152     } msg;
153     msg.ndm.ndm_family = AF_INET;
154     msg.addr_hdr.rta_type = NDA_DST;
155     msg.addr_hdr.rta_len = RTA_LENGTH(sizeof(msg.addr));
156     msg.mac_hdr.rta_type = NDA_LLADDR;
157     msg.mac_hdr.rta_len = RTA_LENGTH(sizeof(msg.mac));
158 
159     auto ret = neighFromRtm(stdplus::raw::asView<char>(msg));
160     EXPECT_EQ((in_addr{hton(0xc0a80114)}), ret.addr);
161     EXPECT_EQ((ether_addr{1, 2, 3, 4, 5, 6}), ret.mac);
162 }
163 
164 } // namespace phosphor::network::netlink
165