blob: bf19ee3713b8e3c22d86f8494b79716586e24135 [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 Guptabbe45792018-03-23 00:22:55 +053022constexpr auto DEFAULT_VALUE = -1;
23constexpr auto NONE = 0;
Ratan Guptaaac603e2018-03-23 00:25:54 +053024using CallBack = int(*)(struct nl_msg* msg, void* arg);
25
26namespace internal
27{
Ratan Guptabbe45792018-03-23 00:22:55 +053028
29using nlMsgPtr = std::unique_ptr<nl_msg, decltype(&::nlmsg_free)>;
30using nlSocketPtr = std::unique_ptr<nl_sock, decltype(&::nl_socket_free)>;
31
Ratan Guptaaac603e2018-03-23 00:25:54 +053032CallBack infoCallBack = [](struct nl_msg* msg, void* arg)
33{
34 using namespace phosphor::network::ncsi;
35 auto nlh = nlmsg_hdr(msg);
36
37 struct nlattr* tb[NCSI_ATTR_MAX + 1] = { nullptr };
38 struct nla_policy ncsiPolicy[NCSI_ATTR_MAX + 1] =
39 {
40 { type: NLA_UNSPEC },
41 { type: NLA_U32 },
42 { type: NLA_NESTED },
43 { type: NLA_U32 },
44 { type: NLA_U32 },
45 };
46
47 struct nlattr* packagetb[NCSI_PKG_ATTR_MAX + 1] = { nullptr };
48 struct nla_policy packagePolicy[NCSI_PKG_ATTR_MAX + 1] =
49 {
50 { type: NLA_UNSPEC },
51 { type: NLA_NESTED },
52 { type: NLA_U32 },
53 { type: NLA_FLAG },
54 { type: NLA_NESTED },
55 };
56
57 struct nlattr* channeltb[NCSI_CHANNEL_ATTR_MAX + 1] = { nullptr };
58 struct nla_policy channelPolicy[NCSI_CHANNEL_ATTR_MAX + 1] =
59 {
60 { type: NLA_UNSPEC },
61 { type: NLA_NESTED },
62 { type: NLA_U32 },
63 { type: NLA_FLAG },
64 { type: NLA_NESTED },
65 { type: NLA_UNSPEC},
66 };
67
68 auto ret = genlmsg_parse(nlh, 0, tb, NCSI_ATTR_MAX, ncsiPolicy);
69 if (!tb[NCSI_ATTR_PACKAGE_LIST])
70 {
71 log<level::ERR>("No Packages");
72 return -1;
73 }
74
75 auto attrTgt = static_cast<nlattr*>(nla_data(tb[NCSI_ATTR_PACKAGE_LIST]));
76 if (!attrTgt)
77 {
78 log<level::ERR>("Package list attribute is null");
79 return -1;
80 }
81
82 auto rem = nla_len(tb[NCSI_ATTR_PACKAGE_LIST]);
83 nla_for_each_nested(attrTgt, tb[NCSI_ATTR_PACKAGE_LIST], rem)
84 {
85 ret = nla_parse_nested(packagetb, NCSI_PKG_ATTR_MAX, attrTgt,
86 packagePolicy);
87 if (ret < 0)
88 {
89 log<level::ERR>("Failed to parse package nested");
90 return -1;
91 }
92
93 if (packagetb[NCSI_PKG_ATTR_ID])
94 {
95 auto attrID = nla_get_u32(packagetb[NCSI_PKG_ATTR_ID]);
96 log<level::DEBUG>("Package has id",
97 entry("ID=%x", attrID));
98 }
99 else
100 {
101 log<level::DEBUG>("Package with no id\n");
102 }
103
104 if (packagetb[NCSI_PKG_ATTR_FORCED])
105 {
106 log<level::DEBUG>("This package is forced\n");
107 }
108
109 auto channelListTarget = static_cast<nlattr*>(
110 nla_data(packagetb[NCSI_PKG_ATTR_CHANNEL_LIST]));
111
112 auto channelrem = nla_len(packagetb[NCSI_PKG_ATTR_CHANNEL_LIST]);
113 nla_for_each_nested(channelListTarget,
114 packagetb[NCSI_PKG_ATTR_CHANNEL_LIST], channelrem)
115 {
116 ret = nla_parse_nested(channeltb, NCSI_CHANNEL_ATTR_MAX,
117 channelListTarget, channelPolicy);
118 if (ret < 0)
119 {
120 log<level::ERR>("Failed to parse channel nested");
121 return -1;
122 }
123
124 if (channeltb[NCSI_CHANNEL_ATTR_ID])
125 {
126 auto channel = nla_get_u32(channeltb[NCSI_CHANNEL_ATTR_ID]);
127 if (channeltb[NCSI_CHANNEL_ATTR_ACTIVE])
128 {
129 log<level::DEBUG>("Channel Active",
130 entry("CHANNEL=%x", channel));
131 }
132 else
133 {
134 log<level::DEBUG>("Channel not Active",
135 entry("CHANNEL=%x", channel));
136
137 }
138
139 if (channeltb[NCSI_CHANNEL_ATTR_FORCED])
140 {
141 log<level::DEBUG>("Channel is forced");
142 }
143
144 }
145 else
146 {
147 log<level::DEBUG>("Channel with no ID");
148 }
149 if (channeltb[NCSI_CHANNEL_ATTR_VERSION_MAJOR])
150 {
151 auto major = nla_get_u32(channeltb[NCSI_CHANNEL_ATTR_VERSION_MAJOR]);
152 log<level::DEBUG>("Channel Major Version",
153 entry("VERSION=%x", major));
154 }
155 if (channeltb[NCSI_CHANNEL_ATTR_VERSION_MINOR])
156 {
157 auto minor = nla_get_u32(channeltb[NCSI_CHANNEL_ATTR_VERSION_MINOR]);
158 log<level::DEBUG>("Channel Minor Version",
159 entry("VERSION=%x", minor));
160 }
161 if (channeltb[NCSI_CHANNEL_ATTR_VERSION_STR])
162 {
163 auto str = nla_get_string(channeltb[NCSI_CHANNEL_ATTR_VERSION_STR]);
164 log<level::DEBUG>("Channel Version Str",
165 entry("VERSION=%s", str));
166 }
167 if (channeltb[NCSI_CHANNEL_ATTR_LINK_STATE])
168 {
169 auto link = nla_get_u32(channeltb[NCSI_CHANNEL_ATTR_LINK_STATE]);
170 log<level::DEBUG>("Channel Link State",
171 entry("STATE=%d", link));
172 }
173 if (channeltb[NCSI_CHANNEL_ATTR_VLAN_LIST])
174 {
175 log<level::DEBUG>("Active Vlan ids");
176 auto vids = channeltb[NCSI_CHANNEL_ATTR_VLAN_LIST];
177 auto vid = static_cast<nlattr*>(nla_data(vids));
178 auto len = nla_len(vids);
179 while (nla_ok(vid, len))
180 {
181 auto id = nla_get_u16(vid);
182 log<level::DEBUG>("VID",
183 entry("VID=%d", id));
184
185 vid = nla_next(vid, &len);
186 }
187 }
188
189 }
190
191 }
192 return (int)NL_SKIP;
193};
194
Ratan Guptabbe45792018-03-23 00:22:55 +0530195int applyCmd(int ifindex, int cmd, int package = DEFAULT_VALUE,
Ratan Guptaaac603e2018-03-23 00:25:54 +0530196 int channel = DEFAULT_VALUE, int flags = NONE,
197 CallBack function = nullptr)
Ratan Guptabbe45792018-03-23 00:22:55 +0530198{
199 nlSocketPtr socket(nl_socket_alloc(),&::nl_socket_free);
200 auto ret = genl_connect(socket.get());
201 if (ret < 0)
202 {
203 log<level::ERR>("Failed to open the socket",
204 entry("RC=%d", ret));
205 return ret;
206 }
207
208 auto driverID = genl_ctrl_resolve(socket.get(), "NCSI");
209 if (driverID < 0)
210 {
211 log<level::ERR>("Failed to resolve",
212 entry("RC=%d", ret));
213 return driverID;
214 }
215
216 nlMsgPtr msg(nlmsg_alloc(), &::nlmsg_free);
217
218 auto msgHdr = genlmsg_put(msg.get(), 0, 0, driverID, 0, flags,
219 cmd, 0);
220 if (!msgHdr)
221 {
222 log<level::ERR>("Unable to add the netlink headers",
223 entry("COMMAND=%d", cmd));
224 return -1;
225 }
226
227 if (package != DEFAULT_VALUE)
228 {
229 ret = nla_put_u32(msg.get(), ncsi_nl_attrs::NCSI_ATTR_PACKAGE_ID,
230 package);
231 if (ret < 0)
232 {
233 log<level::ERR>("Failed to set the attribute",
234 entry("RC=%d", ret),
235 entry("PACKAGE=%x", package));
236 return ret;
237 }
238 }
239
240 if (channel != DEFAULT_VALUE)
241 {
242 ret = nla_put_u32(msg.get(), ncsi_nl_attrs::NCSI_ATTR_CHANNEL_ID,
243 channel);
244 if (ret < 0)
245 {
246 log<level::ERR>("Failed to set the attribute",
247 entry("RC=%d", ret),
248 entry("CHANNEL=%x", channel));
249 return ret;
250 }
251 }
252
253 ret = nla_put_u32(msg.get(), ncsi_nl_attrs::NCSI_ATTR_IFINDEX, ifindex);
254 if (ret < 0)
255 {
256 log<level::ERR>("Failed to set the attribute",
257 entry("RC=%d", ret),
258 entry("INTERFACE=%x", ifindex));
259 return ret;
260 }
261
Ratan Guptaaac603e2018-03-23 00:25:54 +0530262 if (function)
263 {
264 // Add a callback function to the socket
265 nl_socket_modify_cb(socket.get(), NL_CB_VALID, NL_CB_CUSTOM,
266 function, nullptr);
267 }
Ratan Guptabbe45792018-03-23 00:22:55 +0530268
269 ret = nl_send_auto(socket.get(), msg.get());
270 if (ret < 0)
271 {
272 log<level::ERR>("Failed to send the message",
273 entry("RC=%d", ret));
274 return ret;
275 }
276
277 ret = nl_recvmsgs_default(socket.get());
278 if (ret < 0)
279 {
280 log<level::ERR>("Failed to recieve the message",
281 entry("RC=%d", ret));
282 }
283 return ret;
284}
285
286}//namespace internal
287
288int setChannel(int ifindex, int package, int channel)
289{
290 return internal::applyCmd(ifindex, ncsi_nl_commands::NCSI_CMD_SET_INTERFACE,
291 package, channel);
292}
293
294int clearInterface(int ifindex)
295{
296 return internal::applyCmd(ifindex,
297 ncsi_nl_commands::NCSI_CMD_CLEAR_INTERFACE);
298}
299
Ratan Guptaaac603e2018-03-23 00:25:54 +0530300int getInfo(int ifindex, int package)
301{
302 if (package == DEFAULT_VALUE)
303 {
304 return internal::applyCmd(ifindex, ncsi_nl_commands::NCSI_CMD_PKG_INFO,
305 package, DEFAULT_VALUE, NLM_F_DUMP,
306 internal::infoCallBack);
307 }
308 else
309 {
310 return internal::applyCmd(ifindex, ncsi_nl_commands::NCSI_CMD_PKG_INFO,
311 package, DEFAULT_VALUE, NONE,
312 internal::infoCallBack);
313 }
314}
315
Ratan Guptabbe45792018-03-23 00:22:55 +0530316}//namespace ncsi
317}//namespace network
318}//namespace phosphor