1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 **/
19
20 #include "common.h"
21
22 #ifdef HAVE_OPENIPMI
23
24 #include "dbcache.h"
25 #include "daemon.h"
26 #include "zbxself.h"
27 #include "log.h"
28 #include "zbxipcservice.h"
29
30 #include "ipmi_manager.h"
31 #include "ipmi_protocol.h"
32 #include "checks_ipmi.h"
33 #include "ipmi_poller.h"
34
35 #define ZBX_IPMI_MANAGER_CLEANUP_DELAY SEC_PER_DAY
36
37 extern unsigned char process_type, program_type;
38 extern int server_num, process_num;
39
40 /******************************************************************************
41 * *
42 * Function: ipmi_poller_register *
43 * *
44 * Purpose: registers IPMI poller with IPMI manager *
45 * *
46 * Parameters: socket - [IN] the connections socket *
47 * *
48 ******************************************************************************/
ipmi_poller_register(zbx_ipc_async_socket_t * socket)49 static void ipmi_poller_register(zbx_ipc_async_socket_t *socket)
50 {
51 pid_t ppid;
52
53 ppid = getppid();
54
55 zbx_ipc_async_socket_send(socket, ZBX_IPC_IPMI_REGISTER, (unsigned char *)&ppid, sizeof(ppid));
56 }
57
58 /******************************************************************************
59 * *
60 * Function: ipmi_poller_send_result *
61 * *
62 * Purpose: sends IPMI poll result to manager *
63 * *
64 * Parameters: socket - [IN] the connections socket *
65 * itemid - [IN] the item identifier *
66 * errcode - [IN] the result error code *
67 * value - [IN] the resulting value/error message *
68 * *
69 ******************************************************************************/
ipmi_poller_send_result(zbx_ipc_async_socket_t * socket,zbx_uint32_t code,int errcode,const char * value)70 static void ipmi_poller_send_result(zbx_ipc_async_socket_t *socket, zbx_uint32_t code, int errcode,
71 const char *value)
72 {
73 unsigned char *data;
74 zbx_uint32_t data_len;
75 zbx_timespec_t ts;
76
77 zbx_timespec(&ts);
78 data_len = zbx_ipmi_serialize_result(&data, &ts, errcode, value);
79 zbx_ipc_async_socket_send(socket, code, data, data_len);
80
81 zbx_free(data);
82 }
83
84 /******************************************************************************
85 * *
86 * Function: ipmi_poller_process_value_request *
87 * *
88 * Purpose: gets IPMI sensor value from the specified host *
89 * *
90 * Parameters: socket - [IN] the connections socket *
91 * message - [IN] the value request message *
92 * *
93 ******************************************************************************/
ipmi_poller_process_value_request(zbx_ipc_async_socket_t * socket,zbx_ipc_message_t * message)94 static void ipmi_poller_process_value_request(zbx_ipc_async_socket_t *socket, zbx_ipc_message_t *message)
95 {
96 zbx_uint64_t itemid;
97 char *addr, *username, *password, *sensor, *value = NULL, *key;
98 signed char authtype;
99 unsigned char privilege;
100 unsigned short port;
101 int errcode, command;
102
103 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
104
105 zbx_ipmi_deserialize_request(message->data, &itemid, &addr, &port, &authtype, &privilege, &username, &password,
106 &sensor, &command, &key);
107
108 if (0 == strcmp(key, "ipmi.get") || 0 == strncmp(key, "ipmi.get[", ZBX_CONST_STRLEN("ipmi.get[")))
109 {
110 zabbix_log(LOG_LEVEL_TRACE, "%s() for discovery itemid:" ZBX_FS_UI64 " addr:%s port:%d authtype:%d"
111 " privilege:%d username:%s", __func__, itemid, addr, (int)port, (int)authtype,
112 (int)privilege, username);
113 errcode = get_discovery_ipmi(itemid, addr, port, authtype, privilege, username, password, &value);
114 ipmi_poller_send_result(socket, ZBX_IPC_IPMI_VALUE_RESULT, errcode, value);
115 }
116 else
117 {
118 zabbix_log(LOG_LEVEL_TRACE, "%s() itemid:" ZBX_FS_UI64 " addr:%s port:%d authtype:%d privilege:%d"
119 " username:%s sensor:%s", __func__, itemid, addr, (int)port, (int)authtype,
120 (int)privilege, username, sensor);
121 errcode = get_value_ipmi(itemid, addr, port, authtype, privilege, username, password, sensor, &value);
122 ipmi_poller_send_result(socket, ZBX_IPC_IPMI_VALUE_RESULT, errcode, value);
123 }
124
125 zbx_free(value);
126 zbx_free(addr);
127 zbx_free(username);
128 zbx_free(password);
129 zbx_free(sensor);
130 zbx_free(key);
131
132 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
133 }
134
135 /******************************************************************************
136 * *
137 * Function: ipmi_poller_process_command_request *
138 * *
139 * Purpose:sets IPMI sensor value *
140 * *
141 * Parameters: socket - [IN] the connections socket *
142 * message - [IN] the command request message *
143 * *
144 ******************************************************************************/
ipmi_poller_process_command_request(zbx_ipc_async_socket_t * socket,zbx_ipc_message_t * message)145 static void ipmi_poller_process_command_request(zbx_ipc_async_socket_t *socket, zbx_ipc_message_t *message)
146 {
147 zbx_uint64_t itemid;
148 char *addr, *username, *password, *sensor, *error = NULL, *key;
149 signed char authtype;
150 unsigned char privilege;
151 unsigned short port;
152 int errcode, command;
153
154 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
155
156 zbx_ipmi_deserialize_request(message->data, &itemid, &addr, &port, &authtype, &privilege, &username, &password,
157 &sensor, &command, &key);
158
159 zabbix_log(LOG_LEVEL_TRACE, "%s() hostid:" ZBX_FS_UI64 " addr:%s port:%d authtype:%d privilege:%d username:%s"
160 " sensor:%s", __func__, itemid, addr, (int)port, (int)authtype, (int)privilege,
161 username, sensor);
162
163 errcode = zbx_set_ipmi_control_value(itemid, addr, port, authtype, privilege, username, password, sensor,
164 command, &error);
165
166 ipmi_poller_send_result(socket, ZBX_IPC_IPMI_COMMAND_RESULT, errcode, error);
167
168 zbx_free(error);
169 zbx_free(addr);
170 zbx_free(username);
171 zbx_free(password);
172 zbx_free(sensor);
173 zbx_free(key);
174
175 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
176 }
177
ZBX_THREAD_ENTRY(ipmi_poller_thread,args)178 ZBX_THREAD_ENTRY(ipmi_poller_thread, args)
179 {
180 char *error = NULL;
181 zbx_ipc_async_socket_t ipmi_socket;
182 int polled_num = 0;
183 double time_stat, time_idle = 0, time_now, time_read;
184
185 #define STAT_INTERVAL 5 /* if a process is busy and does not sleep then update status not faster than */
186 /* once in STAT_INTERVAL seconds */
187
188 process_type = ((zbx_thread_args_t *)args)->process_type;
189
190 server_num = ((zbx_thread_args_t *)args)->server_num;
191 process_num = ((zbx_thread_args_t *)args)->process_num;
192
193 zbx_setproctitle("%s #%d starting", get_process_type_string(process_type), process_num);
194
195 zabbix_log(LOG_LEVEL_INFORMATION, "%s #%d started [%s #%d]", get_program_type_string(program_type),
196 server_num, get_process_type_string(process_type), process_num);
197
198 update_selfmon_counter(ZBX_PROCESS_STATE_BUSY);
199
200 if (FAIL == zbx_ipc_async_socket_open(&ipmi_socket, ZBX_IPC_SERVICE_IPMI, SEC_PER_MIN, &error))
201 {
202 zabbix_log(LOG_LEVEL_CRIT, "cannot connect to IPMI service: %s", error);
203 zbx_free(error);
204 exit(EXIT_FAILURE);
205 }
206
207 zbx_init_ipmi_handler();
208
209 ipmi_poller_register(&ipmi_socket);
210
211 time_stat = zbx_time();
212
213 zbx_setproctitle("%s #%d started", get_process_type_string(process_type), process_num);
214
215 while (ZBX_IS_RUNNING())
216 {
217 zbx_ipc_message_t *message = NULL;
218
219 time_now = zbx_time();
220
221 if (STAT_INTERVAL < time_now - time_stat)
222 {
223 zbx_setproctitle("%s #%d [polled %d values, idle " ZBX_FS_DBL " sec during "
224 ZBX_FS_DBL " sec]", get_process_type_string(process_type), process_num,
225 polled_num, time_idle, time_now - time_stat);
226
227 time_stat = time_now;
228 time_idle = 0;
229 polled_num = 0;
230 }
231
232 update_selfmon_counter(ZBX_PROCESS_STATE_IDLE);
233
234 while (ZBX_IS_RUNNING())
235 {
236 const int ipc_timeout = 2;
237 const int ipmi_timeout = 1;
238
239 if (SUCCEED != zbx_ipc_async_socket_recv(&ipmi_socket, ipc_timeout, &message))
240 {
241 zabbix_log(LOG_LEVEL_CRIT, "cannot read IPMI service request");
242 exit(EXIT_FAILURE);
243 }
244
245 if (NULL != message)
246 break;
247
248 zbx_perform_all_openipmi_ops(ipmi_timeout);
249 }
250
251 update_selfmon_counter(ZBX_PROCESS_STATE_BUSY);
252
253 if (NULL == message)
254 break;
255
256 time_read = zbx_time();
257 time_idle += time_read - time_now;
258 zbx_update_env(time_read);
259
260 switch (message->code)
261 {
262 case ZBX_IPC_IPMI_VALUE_REQUEST:
263 ipmi_poller_process_value_request(&ipmi_socket, message);
264 polled_num++;
265 break;
266 case ZBX_IPC_IPMI_COMMAND_REQUEST:
267 ipmi_poller_process_command_request(&ipmi_socket, message);
268 break;
269 case ZBX_IPC_IPMI_CLEANUP_REQUEST:
270 zbx_delete_inactive_ipmi_hosts(time(NULL));
271 break;
272 }
273
274 zbx_ipc_message_free(message);
275 message = NULL;
276 }
277
278 zbx_setproctitle("%s #%d [terminated]", get_process_type_string(process_type), process_num);
279
280 while (1)
281 zbx_sleep(SEC_PER_MIN);
282
283 zbx_ipc_async_socket_close(&ipmi_socket);
284
285 zbx_free_ipmi_handler();
286 #undef STAT_INTERVAL
287 }
288
289 #endif
290