blob: 71be8e9d21ddfb7947fd187c765be84dd593b25f [file] [log] [blame]
William A. Kennington III862275a2019-04-22 20:37:08 -07001#include "mock_syscall.hpp"
William A. Kennington IIIc920bdb2019-04-19 14:23:06 -07002#include "netlink.hpp"
3#include "util.hpp"
4
5#include <linux/netlink.h>
6#include <linux/rtnetlink.h>
7
8#include <cstring>
9#include <stdexcept>
William A. Kennington III12beaad2020-06-13 19:30:41 -070010#include <stdplus/raw.hpp>
William A. Kennington IIIc920bdb2019-04-19 14:23:06 -070011#include <string_view>
12
13#include <gtest/gtest.h>
14
15namespace phosphor
16{
17namespace network
18{
19namespace netlink
20{
21namespace detail
22{
23
24TEST(ExtractMsgs, TooSmall)
25{
26 const char buf[] = {'1'};
27 static_assert(sizeof(buf) < sizeof(nlmsghdr));
28 std::string_view data(buf, sizeof(buf));
29
30 size_t cbCalls = 0;
31 auto cb = [&](const nlmsghdr&, std::string_view) { cbCalls++; };
32 bool done = true;
33 EXPECT_THROW(processMsg(data, done, cb), std::runtime_error);
34 EXPECT_EQ(1, data.size());
35 EXPECT_EQ(0, cbCalls);
36 EXPECT_TRUE(done);
37}
38
39TEST(ExtractMsgs, SmallAttrLen)
40{
41 nlmsghdr hdr{};
42 hdr.nlmsg_len = NLMSG_LENGTH(0) - 1;
43 std::string_view data(reinterpret_cast<char*>(&hdr), NLMSG_SPACE(0));
44
45 size_t cbCalls = 0;
46 auto cb = [&](const nlmsghdr&, std::string_view) { cbCalls++; };
47 bool done = true;
48 EXPECT_THROW(processMsg(data, done, cb), std::runtime_error);
49 EXPECT_EQ(NLMSG_SPACE(0), data.size());
50 EXPECT_EQ(0, cbCalls);
51 EXPECT_TRUE(done);
52}
53
54TEST(ExtractMsgs, LargeAttrLen)
55{
56 nlmsghdr hdr{};
57 hdr.nlmsg_len = NLMSG_LENGTH(0) + 1;
58 std::string_view data(reinterpret_cast<char*>(&hdr), NLMSG_SPACE(0));
59
60 size_t cbCalls = 0;
61 auto cb = [&](const nlmsghdr&, std::string_view) { cbCalls++; };
62 bool done = true;
63 EXPECT_THROW(processMsg(data, done, cb), std::runtime_error);
64 EXPECT_EQ(NLMSG_SPACE(0), data.size());
65 EXPECT_EQ(0, cbCalls);
66 EXPECT_TRUE(done);
67}
68
69TEST(ExtractMsgs, NoopMsg)
70{
71 nlmsghdr hdr{};
72 hdr.nlmsg_len = NLMSG_LENGTH(0);
73 hdr.nlmsg_type = NLMSG_NOOP;
74 std::string_view data(reinterpret_cast<char*>(&hdr), NLMSG_SPACE(0));
75
76 size_t cbCalls = 0;
77 auto cb = [&](const nlmsghdr&, std::string_view) { cbCalls++; };
78 bool done = true;
79 processMsg(data, done, cb);
80 EXPECT_EQ(0, data.size());
81 EXPECT_EQ(0, cbCalls);
82 EXPECT_TRUE(done);
83}
84
85TEST(ExtractMsgs, AckMsg)
86{
87 nlmsgerr ack{};
88 nlmsghdr hdr{};
William A. Kennington IIIa19558e2021-05-13 18:56:51 -070089 constexpr size_t len = NLMSG_LENGTH(sizeof(ack));
90 hdr.nlmsg_len = len;
William A. Kennington IIIc920bdb2019-04-19 14:23:06 -070091 hdr.nlmsg_type = NLMSG_ERROR;
William A. Kennington IIIa19558e2021-05-13 18:56:51 -070092 char buf[NLMSG_ALIGN(len)];
William A. Kennington IIIc920bdb2019-04-19 14:23:06 -070093 std::memcpy(buf, &hdr, sizeof(hdr));
94 std::memcpy(NLMSG_DATA(buf), &ack, sizeof(ack));
95 std::string_view data(reinterpret_cast<char*>(&buf), sizeof(buf));
96
97 size_t cbCalls = 0;
98 auto cb = [&](const nlmsghdr&, std::string_view) { cbCalls++; };
99 bool done = true;
100 processMsg(data, done, cb);
101 EXPECT_EQ(0, data.size());
102 EXPECT_EQ(0, cbCalls);
103 EXPECT_TRUE(done);
104}
105
106TEST(ExtractMsgs, ErrMsg)
107{
108 nlmsgerr err{};
109 err.error = EINVAL;
110 nlmsghdr hdr{};
William A. Kennington IIIa19558e2021-05-13 18:56:51 -0700111 constexpr size_t len = NLMSG_LENGTH(sizeof(err));
112 hdr.nlmsg_len = len;
William A. Kennington IIIc920bdb2019-04-19 14:23:06 -0700113 hdr.nlmsg_type = NLMSG_ERROR;
William A. Kennington IIIa19558e2021-05-13 18:56:51 -0700114 char buf[NLMSG_ALIGN(len)];
William A. Kennington IIIc920bdb2019-04-19 14:23:06 -0700115 std::memcpy(buf, &hdr, sizeof(hdr));
116 std::memcpy(NLMSG_DATA(buf), &err, sizeof(err));
117 std::string_view data(reinterpret_cast<char*>(&buf), sizeof(buf));
118
119 size_t cbCalls = 0;
120 nlmsghdr hdrOut;
121 std::string_view dataOut;
122 auto cb = [&](const nlmsghdr& hdr, std::string_view data) {
123 hdrOut = hdr;
124 dataOut = data;
125 cbCalls++;
126 };
127 bool done = true;
128 processMsg(data, done, cb);
129 EXPECT_EQ(0, data.size());
130 EXPECT_EQ(1, cbCalls);
William A. Kennington III12beaad2020-06-13 19:30:41 -0700131 EXPECT_TRUE(stdplus::raw::equal(hdr, hdrOut));
132 EXPECT_TRUE(
133 stdplus::raw::equal(err, stdplus::raw::extract<nlmsgerr>(dataOut)));
William A. Kennington IIIc920bdb2019-04-19 14:23:06 -0700134 EXPECT_EQ(0, dataOut.size());
135 EXPECT_TRUE(done);
136}
137
138TEST(ExtractMsgs, DoneNoMulti)
139{
140 nlmsghdr hdr{};
141 hdr.nlmsg_len = NLMSG_LENGTH(0);
142 hdr.nlmsg_type = NLMSG_DONE;
143 std::string_view data(reinterpret_cast<char*>(&hdr), NLMSG_SPACE(0));
144
145 size_t cbCalls = 0;
146 auto cb = [&](const nlmsghdr&, std::string_view) { cbCalls++; };
147 bool done = true;
148 EXPECT_THROW(processMsg(data, done, cb), std::runtime_error);
149 EXPECT_EQ(0, data.size());
150 EXPECT_EQ(0, cbCalls);
151 EXPECT_TRUE(done);
152}
153
154TEST(ExtractMsg, TwoMultiMsgs)
155{
156 nlmsghdr hdr{};
157 hdr.nlmsg_len = NLMSG_LENGTH(0);
158 hdr.nlmsg_type = RTM_NEWLINK;
159 hdr.nlmsg_flags = NLM_F_MULTI;
160 std::string buf;
161 buf.append(reinterpret_cast<char*>(&hdr), NLMSG_SPACE(0));
162 buf.append(reinterpret_cast<char*>(&hdr), NLMSG_SPACE(0));
163
164 std::string_view data = buf;
165 size_t cbCalls = 0;
166 auto cb = [&](const nlmsghdr&, std::string_view) { cbCalls++; };
167 bool done = true;
168 processMsg(data, done, cb);
169 EXPECT_EQ(NLMSG_SPACE(0), data.size());
170 EXPECT_EQ(1, cbCalls);
171 EXPECT_FALSE(done);
172
173 processMsg(data, done, cb);
174 EXPECT_EQ(0, data.size());
175 EXPECT_EQ(2, cbCalls);
176 EXPECT_FALSE(done);
177}
178
179TEST(ExtractMsgs, MultiMsgValid)
180{
181 nlmsghdr hdr{};
182 hdr.nlmsg_len = NLMSG_LENGTH(0);
183 hdr.nlmsg_type = RTM_NEWLINK;
184 hdr.nlmsg_flags = NLM_F_MULTI;
185 std::string_view data(reinterpret_cast<char*>(&hdr), NLMSG_SPACE(0));
186
187 size_t cbCalls = 0;
188 auto cb = [&](const nlmsghdr&, std::string_view) { cbCalls++; };
189 bool done = true;
190 processMsg(data, done, cb);
191 EXPECT_EQ(0, data.size());
192 EXPECT_EQ(1, cbCalls);
193 EXPECT_FALSE(done);
194
195 hdr.nlmsg_type = NLMSG_DONE;
196 hdr.nlmsg_flags = 0;
197 data = std::string_view(reinterpret_cast<char*>(&hdr), NLMSG_SPACE(0));
198 processMsg(data, done, cb);
199 EXPECT_EQ(0, data.size());
200 EXPECT_EQ(1, cbCalls);
201 EXPECT_TRUE(done);
202}
203
204TEST(ExtractMsgs, MultiMsgInvalid)
205{
206 nlmsghdr hdr{};
207 hdr.nlmsg_len = NLMSG_LENGTH(0);
208 hdr.nlmsg_type = RTM_NEWLINK;
209 hdr.nlmsg_flags = NLM_F_MULTI;
210 std::string_view data(reinterpret_cast<char*>(&hdr), NLMSG_SPACE(0));
211
212 size_t cbCalls = 0;
213 auto cb = [&](const nlmsghdr&, std::string_view) { cbCalls++; };
214 bool done = true;
215 processMsg(data, done, cb);
216 EXPECT_EQ(0, data.size());
217 EXPECT_EQ(1, cbCalls);
218 EXPECT_FALSE(done);
219
220 hdr.nlmsg_flags = 0;
221 data = std::string_view(reinterpret_cast<char*>(&hdr), NLMSG_SPACE(0));
222 EXPECT_THROW(processMsg(data, done, cb), std::runtime_error);
223 EXPECT_EQ(0, data.size());
224 EXPECT_EQ(1, cbCalls);
225 EXPECT_FALSE(done);
226}
227
228} // namespace detail
229
230TEST(ExtractRtAttr, TooSmall)
231{
232 const char buf[] = {'1'};
233 static_assert(sizeof(buf) < sizeof(rtattr));
234 std::string_view data(buf, sizeof(buf));
235
236 EXPECT_THROW(extractRtAttr(data), std::runtime_error);
237 EXPECT_EQ(1, data.size());
238}
239
240TEST(ExtractRtAttr, SmallAttrLen)
241{
242 rtattr rta{};
243 rta.rta_len = RTA_LENGTH(0) - 1;
244 std::string_view data(reinterpret_cast<char*>(&rta), RTA_SPACE(0));
245
246 EXPECT_THROW(extractRtAttr(data), std::runtime_error);
247 EXPECT_EQ(RTA_SPACE(0), data.size());
248}
249
250TEST(ExtractRtAttr, LargeAttrLen)
251{
252 rtattr rta{};
253 rta.rta_len = RTA_LENGTH(0) + 1;
254 std::string_view data(reinterpret_cast<char*>(&rta), RTA_SPACE(0));
255
256 EXPECT_THROW(extractRtAttr(data), std::runtime_error);
257 EXPECT_EQ(RTA_SPACE(0), data.size());
258}
259
260TEST(ExtractRtAttr, NoData)
261{
262 rtattr rta{};
263 rta.rta_len = RTA_LENGTH(0);
264 std::string_view data(reinterpret_cast<char*>(&rta), RTA_SPACE(0));
265
266 auto [hdr, attr] = extractRtAttr(data);
267 EXPECT_EQ(0, data.size());
268 EXPECT_EQ(0, attr.size());
269 EXPECT_EQ(0, std::memcmp(&rta, &hdr, sizeof(rta)));
270}
271
272TEST(ExtractRtAttr, SomeData)
273{
274 const char attrbuf[] = "abcd";
275 const char nextbuf[] = "efgh";
276 rtattr rta{};
277 rta.rta_len = RTA_LENGTH(sizeof(attrbuf));
278
279 char buf[RTA_SPACE(sizeof(attrbuf)) + sizeof(nextbuf)];
280 memcpy(buf, &rta, sizeof(rta));
281 memcpy(RTA_DATA(buf), &attrbuf, sizeof(attrbuf));
282 memcpy(buf + RTA_SPACE(sizeof(attrbuf)), &nextbuf, sizeof(nextbuf));
283 std::string_view data(buf, sizeof(buf));
284
285 auto [hdr, attr] = extractRtAttr(data);
286 EXPECT_EQ(0, memcmp(&rta, &hdr, sizeof(rta)));
287 EXPECT_EQ(sizeof(attrbuf), attr.size());
288 EXPECT_EQ(0, memcmp(&attrbuf, attr.data(), sizeof(attrbuf)));
289 EXPECT_EQ(sizeof(nextbuf), data.size());
290 EXPECT_EQ(0, memcmp(&nextbuf, data.data(), sizeof(nextbuf)));
291}
292
William A. Kennington III5bb7da92019-04-22 21:30:23 -0700293class PerformRequest : public testing::Test
294{
295 public:
296 void doLinkDump(size_t ifs)
297 {
298 mock_clear();
299 for (size_t i = 0; i < ifs; ++i)
300 {
William A. Kennington III9ecb90e2022-10-14 03:12:43 -0700301 mock_addIF(fmt::format("eth{}", i), /*idx=*/1 + i);
William A. Kennington III5bb7da92019-04-22 21:30:23 -0700302 }
303
304 size_t cbCalls = 0;
305 auto cb = [&](const nlmsghdr&, std::string_view) { cbCalls++; };
306 ifinfomsg msg{};
307 netlink::performRequest(NETLINK_ROUTE, RTM_GETLINK, NLM_F_DUMP, msg,
308 cb);
309 EXPECT_EQ(ifs, cbCalls);
310 }
311};
312
313TEST_F(PerformRequest, NoResponse)
314{
315 doLinkDump(0);
316}
317
318TEST_F(PerformRequest, SingleResponse)
319{
320 doLinkDump(1);
321}
322
323TEST_F(PerformRequest, MultiResponse)
324{
325 doLinkDump(3);
326}
327
328TEST_F(PerformRequest, MultiMsg)
329{
330 doLinkDump(1000);
331}
332
William A. Kennington IIIc920bdb2019-04-19 14:23:06 -0700333} // namespace netlink
334} // namespace network
335} // namespace phosphor