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