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