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((IfAddr{in_addr{hton(0xc0a80114)}, 28}), ret.ifaddr);
95 }
96 
97 TEST(AddrFromRtm, ExtraFlags)
98 {
99     struct
100     {
101         alignas(NLMSG_ALIGNTO) ifaddrmsg ifa = {};
102         alignas(NLMSG_ALIGNTO) rtattr flags_hdr;
103         alignas(NLMSG_ALIGNTO) uint32_t flags = 0xff00ff00;
104         alignas(NLMSG_ALIGNTO) rtattr addr_hdr;
105         alignas(NLMSG_ALIGNTO) uint8_t addr[16] = {};
106     } msg;
107     msg.ifa.ifa_family = AF_INET6;
108     msg.flags_hdr.rta_type = IFA_FLAGS;
109     msg.flags_hdr.rta_len = RTA_LENGTH(sizeof(msg.flags));
110     msg.addr_hdr.rta_type = IFA_ADDRESS;
111     msg.addr_hdr.rta_len = RTA_LENGTH(sizeof(msg.addr));
112 
113     auto ret = addrFromRtm(stdplus::raw::asView<char>(msg));
114     EXPECT_EQ(0xff00ff00, ret.flags);
115 }
116 
117 TEST(NeighFromRtm, MissingAddr)
118 {
119     struct
120     {
121         alignas(NLMSG_ALIGNTO) ndmsg ndm = {};
122     } msg;
123 
124     EXPECT_EQ((NeighborInfo{}), neighFromRtm(stdplus::raw::asView<char>(msg)));
125 }
126 
127 TEST(NeighFromRtm, NoMac)
128 {
129     struct
130     {
131         alignas(NLMSG_ALIGNTO) ndmsg ndm;
132         alignas(NLMSG_ALIGNTO) rtattr addr_hdr;
133         alignas(NLMSG_ALIGNTO) uint8_t addr[4] = {192, 168, 1, 20};
134     } msg;
135     msg.ndm.ndm_family = AF_INET;
136     msg.ndm.ndm_state = 4;
137     msg.addr_hdr.rta_type = NDA_DST;
138     msg.addr_hdr.rta_len = RTA_LENGTH(sizeof(msg.addr));
139 
140     auto ret = neighFromRtm(stdplus::raw::asView<char>(msg));
141     EXPECT_EQ(msg.ndm.ndm_state, ret.state);
142     EXPECT_EQ((in_addr{hton(0xc0a80114)}), ret.addr);
143     EXPECT_FALSE(ret.mac);
144 }
145 
146 TEST(NeighFromRtm, Full)
147 {
148     struct
149     {
150         alignas(NLMSG_ALIGNTO) ndmsg ndm;
151         alignas(NLMSG_ALIGNTO) rtattr addr_hdr;
152         alignas(NLMSG_ALIGNTO) uint8_t addr[4] = {192, 168, 1, 20};
153         alignas(NLMSG_ALIGNTO) rtattr mac_hdr;
154         alignas(NLMSG_ALIGNTO) uint8_t mac[6] = {1, 2, 3, 4, 5, 6};
155     } msg;
156     msg.ndm.ndm_family = AF_INET;
157     msg.addr_hdr.rta_type = NDA_DST;
158     msg.addr_hdr.rta_len = RTA_LENGTH(sizeof(msg.addr));
159     msg.mac_hdr.rta_type = NDA_LLADDR;
160     msg.mac_hdr.rta_len = RTA_LENGTH(sizeof(msg.mac));
161 
162     auto ret = neighFromRtm(stdplus::raw::asView<char>(msg));
163     EXPECT_EQ((in_addr{hton(0xc0a80114)}), ret.addr);
164     EXPECT_EQ((ether_addr{1, 2, 3, 4, 5, 6}), ret.mac);
165 }
166 
167 } // namespace phosphor::network::netlink
168