blob: 77224f72fa5a9e945d04275f4d7d53ffe7e00d3a [file] [log] [blame]
Ratan Guptabbe45792018-03-23 00:22:55 +05301#include <linux/ncsi.h>
2#include <netlink/netlink.h>
3#include <netlink/genl/genl.h>
4#include <netlink/genl/ctrl.h>
5
6#include "ncsi_util.hpp"
7#include "xyz/openbmc_project/Common/error.hpp"
8
9#include <phosphor-logging/elog-errors.hpp>
10#include <phosphor-logging/log.hpp>
11
12namespace phosphor
13{
14namespace network
15{
16namespace ncsi
17{
18
19using namespace phosphor::logging;
20using namespace sdbusplus::xyz::openbmc_project::Common::Error;
21
Ratan Guptaaac603e2018-03-23 00:25:54 +053022using CallBack = int(*)(struct nl_msg* msg, void* arg);
23
24namespace internal
25{
Ratan Guptabbe45792018-03-23 00:22:55 +053026
27using nlMsgPtr = std::unique_ptr<nl_msg, decltype(&::nlmsg_free)>;
28using nlSocketPtr = std::unique_ptr<nl_sock, decltype(&::nl_socket_free)>;
29
Ratan Guptaaac603e2018-03-23 00:25:54 +053030CallBack infoCallBack = [](struct nl_msg* msg, void* arg)
31{
32 using namespace phosphor::network::ncsi;
33 auto nlh = nlmsg_hdr(msg);
34
35 struct nlattr* tb[NCSI_ATTR_MAX + 1] = { nullptr };
36 struct nla_policy ncsiPolicy[NCSI_ATTR_MAX + 1] =
37 {
38 { type: NLA_UNSPEC },
39 { type: NLA_U32 },
40 { type: NLA_NESTED },
41 { type: NLA_U32 },
42 { type: NLA_U32 },
43 };
44
45 struct nlattr* packagetb[NCSI_PKG_ATTR_MAX + 1] = { nullptr };
46 struct nla_policy packagePolicy[NCSI_PKG_ATTR_MAX + 1] =
47 {
48 { type: NLA_UNSPEC },
49 { type: NLA_NESTED },
50 { type: NLA_U32 },
51 { type: NLA_FLAG },
52 { type: NLA_NESTED },
53 };
54
55 struct nlattr* channeltb[NCSI_CHANNEL_ATTR_MAX + 1] = { nullptr };
56 struct nla_policy channelPolicy[NCSI_CHANNEL_ATTR_MAX + 1] =
57 {
58 { type: NLA_UNSPEC },
59 { type: NLA_NESTED },
60 { type: NLA_U32 },
61 { type: NLA_FLAG },
62 { type: NLA_NESTED },
63 { type: NLA_UNSPEC},
64 };
65
66 auto ret = genlmsg_parse(nlh, 0, tb, NCSI_ATTR_MAX, ncsiPolicy);
67 if (!tb[NCSI_ATTR_PACKAGE_LIST])
68 {
69 log<level::ERR>("No Packages");
70 return -1;
71 }
72
73 auto attrTgt = static_cast<nlattr*>(nla_data(tb[NCSI_ATTR_PACKAGE_LIST]));
74 if (!attrTgt)
75 {
76 log<level::ERR>("Package list attribute is null");
77 return -1;
78 }
79
80 auto rem = nla_len(tb[NCSI_ATTR_PACKAGE_LIST]);
81 nla_for_each_nested(attrTgt, tb[NCSI_ATTR_PACKAGE_LIST], rem)
82 {
83 ret = nla_parse_nested(packagetb, NCSI_PKG_ATTR_MAX, attrTgt,
84 packagePolicy);
85 if (ret < 0)
86 {
87 log<level::ERR>("Failed to parse package nested");
88 return -1;
89 }
90
91 if (packagetb[NCSI_PKG_ATTR_ID])
92 {
93 auto attrID = nla_get_u32(packagetb[NCSI_PKG_ATTR_ID]);
94 log<level::DEBUG>("Package has id",
95 entry("ID=%x", attrID));
96 }
97 else
98 {
99 log<level::DEBUG>("Package with no id\n");
100 }
101
102 if (packagetb[NCSI_PKG_ATTR_FORCED])
103 {
104 log<level::DEBUG>("This package is forced\n");
105 }
106
107 auto channelListTarget = static_cast<nlattr*>(
108 nla_data(packagetb[NCSI_PKG_ATTR_CHANNEL_LIST]));
109
110 auto channelrem = nla_len(packagetb[NCSI_PKG_ATTR_CHANNEL_LIST]);
111 nla_for_each_nested(channelListTarget,
112 packagetb[NCSI_PKG_ATTR_CHANNEL_LIST], channelrem)
113 {
114 ret = nla_parse_nested(channeltb, NCSI_CHANNEL_ATTR_MAX,
115 channelListTarget, channelPolicy);
116 if (ret < 0)
117 {
118 log<level::ERR>("Failed to parse channel nested");
119 return -1;
120 }
121
122 if (channeltb[NCSI_CHANNEL_ATTR_ID])
123 {
124 auto channel = nla_get_u32(channeltb[NCSI_CHANNEL_ATTR_ID]);
125 if (channeltb[NCSI_CHANNEL_ATTR_ACTIVE])
126 {
127 log<level::DEBUG>("Channel Active",
128 entry("CHANNEL=%x", channel));
129 }
130 else
131 {
Ratan Guptaed5d7ff2018-03-23 00:27:52 +0530132 log<level::DEBUG>("Channel Not Active",
133 entry("CHANNEL=%x", channel));
Ratan Guptaaac603e2018-03-23 00:25:54 +0530134 }
135
136 if (channeltb[NCSI_CHANNEL_ATTR_FORCED])
137 {
138 log<level::DEBUG>("Channel is forced");
139 }
Ratan Guptaaac603e2018-03-23 00:25:54 +0530140 }
141 else
142 {
143 log<level::DEBUG>("Channel with no ID");
144 }
Ratan Guptaed5d7ff2018-03-23 00:27:52 +0530145
Ratan Guptaaac603e2018-03-23 00:25:54 +0530146 if (channeltb[NCSI_CHANNEL_ATTR_VERSION_MAJOR])
147 {
148 auto major = nla_get_u32(channeltb[NCSI_CHANNEL_ATTR_VERSION_MAJOR]);
149 log<level::DEBUG>("Channel Major Version",
150 entry("VERSION=%x", major));
151 }
152 if (channeltb[NCSI_CHANNEL_ATTR_VERSION_MINOR])
153 {
154 auto minor = nla_get_u32(channeltb[NCSI_CHANNEL_ATTR_VERSION_MINOR]);
155 log<level::DEBUG>("Channel Minor Version",
156 entry("VERSION=%x", minor));
157 }
158 if (channeltb[NCSI_CHANNEL_ATTR_VERSION_STR])
159 {
160 auto str = nla_get_string(channeltb[NCSI_CHANNEL_ATTR_VERSION_STR]);
161 log<level::DEBUG>("Channel Version Str",
162 entry("VERSION=%s", str));
163 }
164 if (channeltb[NCSI_CHANNEL_ATTR_LINK_STATE])
165 {
Ratan Guptaed5d7ff2018-03-23 00:27:52 +0530166
Ratan Guptaaac603e2018-03-23 00:25:54 +0530167 auto link = nla_get_u32(channeltb[NCSI_CHANNEL_ATTR_LINK_STATE]);
168 log<level::DEBUG>("Channel Link State",
Ratan Guptaed5d7ff2018-03-23 00:27:52 +0530169 entry("STATE=%x", link));
Ratan Guptaaac603e2018-03-23 00:25:54 +0530170 }
171 if (channeltb[NCSI_CHANNEL_ATTR_VLAN_LIST])
172 {
173 log<level::DEBUG>("Active Vlan ids");
174 auto vids = channeltb[NCSI_CHANNEL_ATTR_VLAN_LIST];
175 auto vid = static_cast<nlattr*>(nla_data(vids));
176 auto len = nla_len(vids);
177 while (nla_ok(vid, len))
178 {
179 auto id = nla_get_u16(vid);
180 log<level::DEBUG>("VID",
181 entry("VID=%d", id));
Ratan Guptaaac603e2018-03-23 00:25:54 +0530182 vid = nla_next(vid, &len);
183 }
184 }
185
186 }
187
188 }
189 return (int)NL_SKIP;
190};
191
Ratan Guptabbe45792018-03-23 00:22:55 +0530192int applyCmd(int ifindex, int cmd, int package = DEFAULT_VALUE,
Ratan Guptaaac603e2018-03-23 00:25:54 +0530193 int channel = DEFAULT_VALUE, int flags = NONE,
194 CallBack function = nullptr)
Ratan Guptabbe45792018-03-23 00:22:55 +0530195{
196 nlSocketPtr socket(nl_socket_alloc(),&::nl_socket_free);
197 auto ret = genl_connect(socket.get());
198 if (ret < 0)
199 {
200 log<level::ERR>("Failed to open the socket",
201 entry("RC=%d", ret));
202 return ret;
203 }
204
205 auto driverID = genl_ctrl_resolve(socket.get(), "NCSI");
206 if (driverID < 0)
207 {
208 log<level::ERR>("Failed to resolve",
209 entry("RC=%d", ret));
210 return driverID;
211 }
212
213 nlMsgPtr msg(nlmsg_alloc(), &::nlmsg_free);
214
215 auto msgHdr = genlmsg_put(msg.get(), 0, 0, driverID, 0, flags,
216 cmd, 0);
217 if (!msgHdr)
218 {
219 log<level::ERR>("Unable to add the netlink headers",
220 entry("COMMAND=%d", cmd));
221 return -1;
222 }
223
224 if (package != DEFAULT_VALUE)
225 {
226 ret = nla_put_u32(msg.get(), ncsi_nl_attrs::NCSI_ATTR_PACKAGE_ID,
227 package);
228 if (ret < 0)
229 {
230 log<level::ERR>("Failed to set the attribute",
231 entry("RC=%d", ret),
232 entry("PACKAGE=%x", package));
233 return ret;
234 }
235 }
236
237 if (channel != DEFAULT_VALUE)
238 {
239 ret = nla_put_u32(msg.get(), ncsi_nl_attrs::NCSI_ATTR_CHANNEL_ID,
240 channel);
241 if (ret < 0)
242 {
243 log<level::ERR>("Failed to set the attribute",
244 entry("RC=%d", ret),
245 entry("CHANNEL=%x", channel));
246 return ret;
247 }
248 }
249
250 ret = nla_put_u32(msg.get(), ncsi_nl_attrs::NCSI_ATTR_IFINDEX, ifindex);
251 if (ret < 0)
252 {
253 log<level::ERR>("Failed to set the attribute",
254 entry("RC=%d", ret),
255 entry("INTERFACE=%x", ifindex));
256 return ret;
257 }
258
Ratan Guptaaac603e2018-03-23 00:25:54 +0530259 if (function)
260 {
261 // Add a callback function to the socket
262 nl_socket_modify_cb(socket.get(), NL_CB_VALID, NL_CB_CUSTOM,
263 function, nullptr);
264 }
Ratan Guptabbe45792018-03-23 00:22:55 +0530265
266 ret = nl_send_auto(socket.get(), msg.get());
267 if (ret < 0)
268 {
269 log<level::ERR>("Failed to send the message",
270 entry("RC=%d", ret));
271 return ret;
272 }
273
274 ret = nl_recvmsgs_default(socket.get());
275 if (ret < 0)
276 {
277 log<level::ERR>("Failed to recieve the message",
278 entry("RC=%d", ret));
279 }
280 return ret;
281}
282
283}//namespace internal
284
285int setChannel(int ifindex, int package, int channel)
286{
Ratan Guptaed5d7ff2018-03-23 00:27:52 +0530287 log<level::DEBUG>("Set Channel",
288 entry("CHANNEL=%x", channel),
289 entry("PACKAGE=%x", package),
290 entry("IFINDEX=%x", ifindex));
Ratan Guptabbe45792018-03-23 00:22:55 +0530291 return internal::applyCmd(ifindex, ncsi_nl_commands::NCSI_CMD_SET_INTERFACE,
292 package, channel);
293}
294
295int clearInterface(int ifindex)
296{
Ratan Guptaed5d7ff2018-03-23 00:27:52 +0530297 log<level::DEBUG>("ClearInterface",
298 entry("IFINDEX=%x", ifindex));
Ratan Guptabbe45792018-03-23 00:22:55 +0530299 return internal::applyCmd(ifindex,
300 ncsi_nl_commands::NCSI_CMD_CLEAR_INTERFACE);
301}
302
Ratan Guptaaac603e2018-03-23 00:25:54 +0530303int getInfo(int ifindex, int package)
304{
Ratan Guptaed5d7ff2018-03-23 00:27:52 +0530305 log<level::DEBUG>("Get Info",
306 entry("PACKAGE=%x", package),
307 entry("IFINDEX=%x", ifindex));
Ratan Guptaaac603e2018-03-23 00:25:54 +0530308 if (package == DEFAULT_VALUE)
309 {
310 return internal::applyCmd(ifindex, ncsi_nl_commands::NCSI_CMD_PKG_INFO,
311 package, DEFAULT_VALUE, NLM_F_DUMP,
312 internal::infoCallBack);
313 }
314 else
315 {
316 return internal::applyCmd(ifindex, ncsi_nl_commands::NCSI_CMD_PKG_INFO,
317 package, DEFAULT_VALUE, NONE,
318 internal::infoCallBack);
319 }
320}
321
Ratan Guptabbe45792018-03-23 00:22:55 +0530322}//namespace ncsi
323}//namespace network
324}//namespace phosphor