1 #include "ncsi_util.hpp" 2 3 #include <linux/ncsi.h> 4 #include <netlink/genl/ctrl.h> 5 #include <netlink/genl/genl.h> 6 #include <netlink/netlink.h> 7 8 #include <iostream> 9 #include <phosphor-logging/elog-errors.hpp> 10 #include <phosphor-logging/log.hpp> 11 #include <xyz/openbmc_project/Common/error.hpp> 12 13 namespace phosphor 14 { 15 namespace network 16 { 17 namespace ncsi 18 { 19 20 using namespace phosphor::logging; 21 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 22 23 using CallBack = int (*)(struct nl_msg* msg, void* arg); 24 25 namespace internal 26 { 27 28 using nlMsgPtr = std::unique_ptr<nl_msg, decltype(&::nlmsg_free)>; 29 using nlSocketPtr = std::unique_ptr<nl_sock, decltype(&::nl_socket_free)>; 30 31 CallBack infoCallBack = [](struct nl_msg* msg, void* /*arg*/) { 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 {NLA_UNSPEC, 0, 0}, {NLA_U32, 0, 0}, {NLA_NESTED, 0, 0}, 38 {NLA_U32, 0, 0}, {NLA_U32, 0, 0}, 39 }; 40 41 struct nlattr* packagetb[NCSI_PKG_ATTR_MAX + 1] = {nullptr}; 42 struct nla_policy packagePolicy[NCSI_PKG_ATTR_MAX + 1] = { 43 {NLA_UNSPEC, 0, 0}, {NLA_NESTED, 0, 0}, {NLA_U32, 0, 0}, 44 {NLA_FLAG, 0, 0}, {NLA_NESTED, 0, 0}, 45 }; 46 47 struct nlattr* channeltb[NCSI_CHANNEL_ATTR_MAX + 1] = {nullptr}; 48 struct nla_policy channelPolicy[NCSI_CHANNEL_ATTR_MAX + 1] = { 49 {NLA_UNSPEC, 0, 0}, {NLA_NESTED, 0, 0}, {NLA_U32, 0, 0}, 50 {NLA_FLAG, 0, 0}, {NLA_NESTED, 0, 0}, {NLA_UNSPEC, 0, 0}, 51 }; 52 53 auto ret = genlmsg_parse(nlh, 0, tb, NCSI_ATTR_MAX, ncsiPolicy); 54 if (!tb[NCSI_ATTR_PACKAGE_LIST]) 55 { 56 std::cerr << "No Packages" << std::endl; 57 return -1; 58 } 59 60 auto attrTgt = static_cast<nlattr*>(nla_data(tb[NCSI_ATTR_PACKAGE_LIST])); 61 if (!attrTgt) 62 { 63 std::cerr << "Package list attribute is null" << std::endl; 64 return -1; 65 } 66 67 auto rem = nla_len(tb[NCSI_ATTR_PACKAGE_LIST]); 68 nla_for_each_nested(attrTgt, tb[NCSI_ATTR_PACKAGE_LIST], rem) 69 { 70 ret = nla_parse_nested(packagetb, NCSI_PKG_ATTR_MAX, attrTgt, 71 packagePolicy); 72 if (ret < 0) 73 { 74 std::cerr << "Failed to parse package nested" << std::endl; 75 return -1; 76 } 77 78 if (packagetb[NCSI_PKG_ATTR_ID]) 79 { 80 auto attrID = nla_get_u32(packagetb[NCSI_PKG_ATTR_ID]); 81 std::cout << "Package has id : " << std::hex << attrID << std::endl; 82 } 83 else 84 { 85 std::cout << "Package with no id" << std::endl; 86 } 87 88 if (packagetb[NCSI_PKG_ATTR_FORCED]) 89 { 90 std::cout << "This package is forced" << std::endl; 91 } 92 93 auto channelListTarget = static_cast<nlattr*>( 94 nla_data(packagetb[NCSI_PKG_ATTR_CHANNEL_LIST])); 95 96 auto channelrem = nla_len(packagetb[NCSI_PKG_ATTR_CHANNEL_LIST]); 97 nla_for_each_nested(channelListTarget, 98 packagetb[NCSI_PKG_ATTR_CHANNEL_LIST], channelrem) 99 { 100 ret = nla_parse_nested(channeltb, NCSI_CHANNEL_ATTR_MAX, 101 channelListTarget, channelPolicy); 102 if (ret < 0) 103 { 104 std::cerr << "Failed to parse channel nested" << std::endl; 105 return -1; 106 } 107 108 if (channeltb[NCSI_CHANNEL_ATTR_ID]) 109 { 110 auto channel = nla_get_u32(channeltb[NCSI_CHANNEL_ATTR_ID]); 111 if (channeltb[NCSI_CHANNEL_ATTR_ACTIVE]) 112 { 113 std::cout << "Channel Active : " << std::hex << channel 114 << std::endl; 115 } 116 else 117 { 118 std::cout << "Channel Not Active : " << std::hex << channel 119 << std::endl; 120 } 121 122 if (channeltb[NCSI_CHANNEL_ATTR_FORCED]) 123 { 124 std::cout << "Channel is forced" << std::endl; 125 } 126 } 127 else 128 { 129 std::cout << "Channel with no ID" << std::endl; 130 } 131 132 if (channeltb[NCSI_CHANNEL_ATTR_VERSION_MAJOR]) 133 { 134 auto major = 135 nla_get_u32(channeltb[NCSI_CHANNEL_ATTR_VERSION_MAJOR]); 136 std::cout << "Channel Major Version : " << std::hex << major 137 << std::endl; 138 } 139 if (channeltb[NCSI_CHANNEL_ATTR_VERSION_MINOR]) 140 { 141 auto minor = 142 nla_get_u32(channeltb[NCSI_CHANNEL_ATTR_VERSION_MINOR]); 143 std::cout << "Channel Minor Version : " << std::hex << minor 144 << std::endl; 145 } 146 if (channeltb[NCSI_CHANNEL_ATTR_VERSION_STR]) 147 { 148 auto str = 149 nla_get_string(channeltb[NCSI_CHANNEL_ATTR_VERSION_STR]); 150 std::cout << "Channel Version Str :" << str << std::endl; 151 } 152 if (channeltb[NCSI_CHANNEL_ATTR_LINK_STATE]) 153 { 154 155 auto link = 156 nla_get_u32(channeltb[NCSI_CHANNEL_ATTR_LINK_STATE]); 157 std::cout << "Channel Link State : " << std::hex << link 158 << std::endl; 159 } 160 if (channeltb[NCSI_CHANNEL_ATTR_VLAN_LIST]) 161 { 162 std::cout << "Active Vlan ids" << std::endl; 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); 169 std::cout << "VID : " << id << std::endl; 170 vid = nla_next(vid, &len); 171 } 172 } 173 } 174 } 175 return (int)NL_SKIP; 176 }; 177 178 int applyCmd(int ifindex, int cmd, int package = DEFAULT_VALUE, 179 int channel = DEFAULT_VALUE, int flags = NONE, 180 CallBack function = nullptr) 181 { 182 nlSocketPtr socket(nl_socket_alloc(), &::nl_socket_free); 183 auto ret = genl_connect(socket.get()); 184 if (ret < 0) 185 { 186 std::cerr << "Failed to open the socket , RC : " << ret << std::endl; 187 return ret; 188 } 189 190 auto driverID = genl_ctrl_resolve(socket.get(), "NCSI"); 191 if (driverID < 0) 192 { 193 std::cerr << "Failed to resolve, RC : " << ret << std::endl; 194 return driverID; 195 } 196 197 nlMsgPtr msg(nlmsg_alloc(), &::nlmsg_free); 198 199 auto msgHdr = genlmsg_put(msg.get(), 0, 0, driverID, 0, flags, cmd, 0); 200 if (!msgHdr) 201 { 202 std::cerr << "Unable to add the netlink headers , COMMAND : " << cmd 203 << std::endl; 204 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 { 213 std::cerr << "Failed to set the attribute , RC : " << ret 214 << "PACKAGE " << std::hex << package << std::endl; 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 { 225 std::cerr << "Failed to set the attribute , RC : " << ret 226 << "CHANNEL : " << std::hex << channel << std::endl; 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 { 234 std::cerr << "Failed to set the attribute , RC : " << ret 235 << "INTERFACE : " << std::hex << ifindex << std::endl; 236 return ret; 237 } 238 239 if (function) 240 { 241 // Add a callback function to the socket 242 nl_socket_modify_cb(socket.get(), NL_CB_VALID, NL_CB_CUSTOM, function, 243 nullptr); 244 } 245 246 ret = nl_send_auto(socket.get(), msg.get()); 247 if (ret < 0) 248 { 249 std::cerr << "Failed to send the message , RC : " << ret << std::endl; 250 return ret; 251 } 252 253 ret = nl_recvmsgs_default(socket.get()); 254 if (ret < 0) 255 { 256 std::cerr << "Failed to receive the message , RC : " << ret 257 << std::endl; 258 } 259 return ret; 260 } 261 262 } // namespace internal 263 264 int setChannel(int ifindex, int package, int channel) 265 { 266 std::cout << "Set Channel : " << std::hex << channel 267 << ", PACKAGE : " << std::hex << package 268 << ", IFINDEX : " << std::hex << ifindex << std::endl; 269 return internal::applyCmd(ifindex, ncsi_nl_commands::NCSI_CMD_SET_INTERFACE, 270 package, channel); 271 } 272 273 int clearInterface(int ifindex) 274 { 275 std::cout << "ClearInterface , IFINDEX :" << std::hex << ifindex 276 << std::endl; 277 return internal::applyCmd(ifindex, 278 ncsi_nl_commands::NCSI_CMD_CLEAR_INTERFACE); 279 } 280 281 int getInfo(int ifindex, int package) 282 { 283 std::cout << "Get Info , PACKAGE : " << std::hex << package 284 << ", IFINDEX : " << std::hex << ifindex << std::endl; 285 if (package == DEFAULT_VALUE) 286 { 287 return internal::applyCmd(ifindex, ncsi_nl_commands::NCSI_CMD_PKG_INFO, 288 package, DEFAULT_VALUE, NLM_F_DUMP, 289 internal::infoCallBack); 290 } 291 else 292 { 293 return internal::applyCmd(ifindex, ncsi_nl_commands::NCSI_CMD_PKG_INFO, 294 package, DEFAULT_VALUE, NONE, 295 internal::infoCallBack); 296 } 297 } 298 299 } // namespace ncsi 300 } // namespace network 301 } // namespace phosphor 302