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