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