blob: 2b3fb54a132589362a5fa6b787717a86ee8f6629 [file] [log] [blame]
Patrick Venture189d44e2018-07-09 12:30:59 -07001#include "ncsi_util.hpp"
2
Ratan Guptabbe45792018-03-23 00:22:55 +05303#include <linux/ncsi.h>
Ratan Guptabbe45792018-03-23 00:22:55 +05304#include <netlink/genl/ctrl.h>
Gunnar Mills57d9c502018-09-14 14:42:34 -05005#include <netlink/genl/genl.h>
6#include <netlink/netlink.h>
Ratan Guptabbe45792018-03-23 00:22:55 +05307
Ratan Guptabbe45792018-03-23 00:22:55 +05308#include <phosphor-logging/elog-errors.hpp>
9#include <phosphor-logging/log.hpp>
Patrick Venture189d44e2018-07-09 12:30:59 -070010#include <xyz/openbmc_project/Common/error.hpp>
Ratan Guptabbe45792018-03-23 00:22:55 +053011
12namespace phosphor
13{
14namespace network
15{
16namespace ncsi
17{
18
19using namespace phosphor::logging;
20using namespace sdbusplus::xyz::openbmc_project::Common::Error;
21
Gunnar Mills57d9c502018-09-14 14:42:34 -050022using CallBack = int (*)(struct nl_msg* msg, void* arg);
Ratan Guptaaac603e2018-03-23 00:25:54 +053023
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
Gunnar Mills57d9c502018-09-14 14:42:34 -050030CallBack infoCallBack = [](struct nl_msg* msg, void* arg) {
Ratan Guptaaac603e2018-03-23 00:25:54 +053031 using namespace phosphor::network::ncsi;
32 auto nlh = nlmsg_hdr(msg);
33
Gunnar Mills57d9c502018-09-14 14:42:34 -050034 struct nlattr* tb[NCSI_ATTR_MAX + 1] = {nullptr};
35 struct nla_policy ncsiPolicy[NCSI_ATTR_MAX + 1] = {
36 {type : NLA_UNSPEC}, {type : NLA_U32}, {type : NLA_NESTED},
37 {type : NLA_U32}, {type : NLA_U32},
Ratan Guptaaac603e2018-03-23 00:25:54 +053038 };
39
Gunnar Mills57d9c502018-09-14 14:42:34 -050040 struct nlattr* packagetb[NCSI_PKG_ATTR_MAX + 1] = {nullptr};
41 struct nla_policy packagePolicy[NCSI_PKG_ATTR_MAX + 1] = {
42 {type : NLA_UNSPEC}, {type : NLA_NESTED}, {type : NLA_U32},
43 {type : NLA_FLAG}, {type : NLA_NESTED},
Ratan Guptaaac603e2018-03-23 00:25:54 +053044 };
45
Gunnar Mills57d9c502018-09-14 14:42:34 -050046 struct nlattr* channeltb[NCSI_CHANNEL_ATTR_MAX + 1] = {nullptr};
47 struct nla_policy channelPolicy[NCSI_CHANNEL_ATTR_MAX + 1] = {
48 {type : NLA_UNSPEC}, {type : NLA_NESTED}, {type : NLA_U32},
49 {type : NLA_FLAG}, {type : NLA_NESTED}, {type : NLA_UNSPEC},
Ratan Guptaaac603e2018-03-23 00:25:54 +053050 };
51
52 auto ret = genlmsg_parse(nlh, 0, tb, NCSI_ATTR_MAX, ncsiPolicy);
53 if (!tb[NCSI_ATTR_PACKAGE_LIST])
54 {
55 log<level::ERR>("No Packages");
56 return -1;
57 }
58
59 auto attrTgt = static_cast<nlattr*>(nla_data(tb[NCSI_ATTR_PACKAGE_LIST]));
60 if (!attrTgt)
61 {
62 log<level::ERR>("Package list attribute is null");
63 return -1;
64 }
65
66 auto rem = nla_len(tb[NCSI_ATTR_PACKAGE_LIST]);
67 nla_for_each_nested(attrTgt, tb[NCSI_ATTR_PACKAGE_LIST], rem)
68 {
69 ret = nla_parse_nested(packagetb, NCSI_PKG_ATTR_MAX, attrTgt,
70 packagePolicy);
71 if (ret < 0)
72 {
73 log<level::ERR>("Failed to parse package nested");
74 return -1;
75 }
76
77 if (packagetb[NCSI_PKG_ATTR_ID])
78 {
79 auto attrID = nla_get_u32(packagetb[NCSI_PKG_ATTR_ID]);
Gunnar Mills57d9c502018-09-14 14:42:34 -050080 log<level::DEBUG>("Package has id", entry("ID=%x", attrID));
Ratan Guptaaac603e2018-03-23 00:25:54 +053081 }
82 else
83 {
84 log<level::DEBUG>("Package with no id\n");
85 }
86
87 if (packagetb[NCSI_PKG_ATTR_FORCED])
88 {
89 log<level::DEBUG>("This package is forced\n");
90 }
91
92 auto channelListTarget = static_cast<nlattr*>(
Gunnar Mills57d9c502018-09-14 14:42:34 -050093 nla_data(packagetb[NCSI_PKG_ATTR_CHANNEL_LIST]));
Ratan Guptaaac603e2018-03-23 00:25:54 +053094
95 auto channelrem = nla_len(packagetb[NCSI_PKG_ATTR_CHANNEL_LIST]);
96 nla_for_each_nested(channelListTarget,
97 packagetb[NCSI_PKG_ATTR_CHANNEL_LIST], channelrem)
98 {
99 ret = nla_parse_nested(channeltb, NCSI_CHANNEL_ATTR_MAX,
100 channelListTarget, channelPolicy);
101 if (ret < 0)
102 {
103 log<level::ERR>("Failed to parse channel nested");
104 return -1;
105 }
106
107 if (channeltb[NCSI_CHANNEL_ATTR_ID])
108 {
109 auto channel = nla_get_u32(channeltb[NCSI_CHANNEL_ATTR_ID]);
110 if (channeltb[NCSI_CHANNEL_ATTR_ACTIVE])
111 {
112 log<level::DEBUG>("Channel Active",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500113 entry("CHANNEL=%x", channel));
Ratan Guptaaac603e2018-03-23 00:25:54 +0530114 }
115 else
116 {
Ratan Guptaed5d7ff2018-03-23 00:27:52 +0530117 log<level::DEBUG>("Channel Not Active",
118 entry("CHANNEL=%x", channel));
Ratan Guptaaac603e2018-03-23 00:25:54 +0530119 }
120
121 if (channeltb[NCSI_CHANNEL_ATTR_FORCED])
122 {
123 log<level::DEBUG>("Channel is forced");
124 }
Ratan Guptaaac603e2018-03-23 00:25:54 +0530125 }
126 else
127 {
128 log<level::DEBUG>("Channel with no ID");
129 }
Ratan Guptaed5d7ff2018-03-23 00:27:52 +0530130
Ratan Guptaaac603e2018-03-23 00:25:54 +0530131 if (channeltb[NCSI_CHANNEL_ATTR_VERSION_MAJOR])
132 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500133 auto major =
134 nla_get_u32(channeltb[NCSI_CHANNEL_ATTR_VERSION_MAJOR]);
Ratan Guptaaac603e2018-03-23 00:25:54 +0530135 log<level::DEBUG>("Channel Major Version",
136 entry("VERSION=%x", major));
137 }
138 if (channeltb[NCSI_CHANNEL_ATTR_VERSION_MINOR])
139 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500140 auto minor =
141 nla_get_u32(channeltb[NCSI_CHANNEL_ATTR_VERSION_MINOR]);
Ratan Guptaaac603e2018-03-23 00:25:54 +0530142 log<level::DEBUG>("Channel Minor Version",
143 entry("VERSION=%x", minor));
144 }
145 if (channeltb[NCSI_CHANNEL_ATTR_VERSION_STR])
146 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500147 auto str =
148 nla_get_string(channeltb[NCSI_CHANNEL_ATTR_VERSION_STR]);
Ratan Guptaaac603e2018-03-23 00:25:54 +0530149 log<level::DEBUG>("Channel Version Str",
150 entry("VERSION=%s", str));
151 }
152 if (channeltb[NCSI_CHANNEL_ATTR_LINK_STATE])
153 {
Ratan Guptaed5d7ff2018-03-23 00:27:52 +0530154
Gunnar Mills57d9c502018-09-14 14:42:34 -0500155 auto link =
156 nla_get_u32(channeltb[NCSI_CHANNEL_ATTR_LINK_STATE]);
Ratan Guptaaac603e2018-03-23 00:25:54 +0530157 log<level::DEBUG>("Channel Link State",
Ratan Guptaed5d7ff2018-03-23 00:27:52 +0530158 entry("STATE=%x", link));
Ratan Guptaaac603e2018-03-23 00:25:54 +0530159 }
160 if (channeltb[NCSI_CHANNEL_ATTR_VLAN_LIST])
161 {
162 log<level::DEBUG>("Active Vlan ids");
163 auto vids = channeltb[NCSI_CHANNEL_ATTR_VLAN_LIST];
164 auto vid = static_cast<nlattr*>(nla_data(vids));
165 auto len = nla_len(vids);
166 while (nla_ok(vid, len))
167 {
168 auto id = nla_get_u16(vid);
Gunnar Mills57d9c502018-09-14 14:42:34 -0500169 log<level::DEBUG>("VID", entry("VID=%d", id));
Ratan Guptaaac603e2018-03-23 00:25:54 +0530170 vid = nla_next(vid, &len);
171 }
172 }
Ratan Guptaaac603e2018-03-23 00:25:54 +0530173 }
Ratan Guptaaac603e2018-03-23 00:25:54 +0530174 }
175 return (int)NL_SKIP;
176};
177
Ratan Guptabbe45792018-03-23 00:22:55 +0530178int applyCmd(int ifindex, int cmd, int package = DEFAULT_VALUE,
Ratan Guptaaac603e2018-03-23 00:25:54 +0530179 int channel = DEFAULT_VALUE, int flags = NONE,
180 CallBack function = nullptr)
Ratan Guptabbe45792018-03-23 00:22:55 +0530181{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500182 nlSocketPtr socket(nl_socket_alloc(), &::nl_socket_free);
Ratan Guptabbe45792018-03-23 00:22:55 +0530183 auto ret = genl_connect(socket.get());
184 if (ret < 0)
185 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500186 log<level::ERR>("Failed to open the socket", entry("RC=%d", ret));
Ratan Guptabbe45792018-03-23 00:22:55 +0530187 return ret;
188 }
189
190 auto driverID = genl_ctrl_resolve(socket.get(), "NCSI");
191 if (driverID < 0)
192 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500193 log<level::ERR>("Failed to resolve", entry("RC=%d", ret));
Ratan Guptabbe45792018-03-23 00:22:55 +0530194 return driverID;
195 }
196
197 nlMsgPtr msg(nlmsg_alloc(), &::nlmsg_free);
198
Gunnar Mills57d9c502018-09-14 14:42:34 -0500199 auto msgHdr = genlmsg_put(msg.get(), 0, 0, driverID, 0, flags, cmd, 0);
Ratan Guptabbe45792018-03-23 00:22:55 +0530200 if (!msgHdr)
201 {
202 log<level::ERR>("Unable to add the netlink headers",
Gunnar Mills57d9c502018-09-14 14:42:34 -0500203 entry("COMMAND=%d", cmd));
Ratan Guptabbe45792018-03-23 00:22:55 +0530204 return -1;
205 }
206
207 if (package != DEFAULT_VALUE)
208 {
209 ret = nla_put_u32(msg.get(), ncsi_nl_attrs::NCSI_ATTR_PACKAGE_ID,
210 package);
211 if (ret < 0)
212 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500213 log<level::ERR>("Failed to set the attribute", entry("RC=%d", ret),
Ratan Guptabbe45792018-03-23 00:22:55 +0530214 entry("PACKAGE=%x", package));
215 return ret;
216 }
217 }
218
219 if (channel != DEFAULT_VALUE)
220 {
221 ret = nla_put_u32(msg.get(), ncsi_nl_attrs::NCSI_ATTR_CHANNEL_ID,
222 channel);
223 if (ret < 0)
224 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500225 log<level::ERR>("Failed to set the attribute", entry("RC=%d", ret),
Ratan Guptabbe45792018-03-23 00:22:55 +0530226 entry("CHANNEL=%x", channel));
227 return ret;
228 }
229 }
230
231 ret = nla_put_u32(msg.get(), ncsi_nl_attrs::NCSI_ATTR_IFINDEX, ifindex);
232 if (ret < 0)
233 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500234 log<level::ERR>("Failed to set the attribute", entry("RC=%d", ret),
Ratan Guptabbe45792018-03-23 00:22:55 +0530235 entry("INTERFACE=%x", ifindex));
236 return ret;
237 }
238
Ratan Guptaaac603e2018-03-23 00:25:54 +0530239 if (function)
240 {
241 // Add a callback function to the socket
Gunnar Mills57d9c502018-09-14 14:42:34 -0500242 nl_socket_modify_cb(socket.get(), NL_CB_VALID, NL_CB_CUSTOM, function,
243 nullptr);
Ratan Guptaaac603e2018-03-23 00:25:54 +0530244 }
Ratan Guptabbe45792018-03-23 00:22:55 +0530245
246 ret = nl_send_auto(socket.get(), msg.get());
247 if (ret < 0)
248 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500249 log<level::ERR>("Failed to send the message", entry("RC=%d", ret));
Ratan Guptabbe45792018-03-23 00:22:55 +0530250 return ret;
251 }
252
253 ret = nl_recvmsgs_default(socket.get());
254 if (ret < 0)
255 {
Gunnar Mills57d9c502018-09-14 14:42:34 -0500256 log<level::ERR>("Failed to receive the message", entry("RC=%d", ret));
Ratan Guptabbe45792018-03-23 00:22:55 +0530257 }
258 return ret;
259}
260
Gunnar Mills57d9c502018-09-14 14:42:34 -0500261} // namespace internal
Ratan Guptabbe45792018-03-23 00:22:55 +0530262
263int setChannel(int ifindex, int package, int channel)
264{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500265 log<level::DEBUG>("Set Channel", entry("CHANNEL=%x", channel),
Ratan Guptaed5d7ff2018-03-23 00:27:52 +0530266 entry("PACKAGE=%x", package),
267 entry("IFINDEX=%x", ifindex));
Ratan Guptabbe45792018-03-23 00:22:55 +0530268 return internal::applyCmd(ifindex, ncsi_nl_commands::NCSI_CMD_SET_INTERFACE,
269 package, channel);
270}
271
272int clearInterface(int ifindex)
273{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500274 log<level::DEBUG>("ClearInterface", entry("IFINDEX=%x", ifindex));
Ratan Guptabbe45792018-03-23 00:22:55 +0530275 return internal::applyCmd(ifindex,
276 ncsi_nl_commands::NCSI_CMD_CLEAR_INTERFACE);
277}
278
Ratan Guptaaac603e2018-03-23 00:25:54 +0530279int getInfo(int ifindex, int package)
280{
Gunnar Mills57d9c502018-09-14 14:42:34 -0500281 log<level::DEBUG>("Get Info", entry("PACKAGE=%x", package),
Ratan Guptaed5d7ff2018-03-23 00:27:52 +0530282 entry("IFINDEX=%x", ifindex));
Ratan Guptaaac603e2018-03-23 00:25:54 +0530283 if (package == DEFAULT_VALUE)
284 {
285 return internal::applyCmd(ifindex, ncsi_nl_commands::NCSI_CMD_PKG_INFO,
286 package, DEFAULT_VALUE, NLM_F_DUMP,
287 internal::infoCallBack);
288 }
289 else
290 {
291 return internal::applyCmd(ifindex, ncsi_nl_commands::NCSI_CMD_PKG_INFO,
292 package, DEFAULT_VALUE, NONE,
293 internal::infoCallBack);
294 }
295}
296
Gunnar Mills57d9c502018-09-14 14:42:34 -0500297} // namespace ncsi
298} // namespace network
299} // namespace phosphor