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 const char *__function_name = "ipmi_poller_process_value_request";
97 zbx_uint64_t itemid;
98 char *addr, *username, *password, *sensor, *value = NULL;
99 signed char authtype;
100 unsigned char privilege;
101 unsigned short port;
102 int errcode, command;
103
104 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
105
106 zbx_ipmi_deserialize_request(message->data, &itemid, &addr, &port, &authtype,
107 &privilege, &username, &password, &sensor, &command);
108
109 zabbix_log(LOG_LEVEL_TRACE, "%s() itemid:" ZBX_FS_UI64 " addr:%s port:%d authtype:%d privilege:%d username:%s"
110 " sensor:%s", __function_name, itemid, addr, (int)port, (int)authtype, (int)privilege,
111 username, sensor);
112
113 errcode = get_value_ipmi(itemid, addr, port, authtype, privilege, username, password, sensor, &value);
114 ipmi_poller_send_result(socket, ZBX_IPC_IPMI_VALUE_RESULT, errcode, value);
115
116 zbx_free(value);
117 zbx_free(addr);
118 zbx_free(username);
119 zbx_free(password);
120 zbx_free(sensor);
121
122 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
123 }
124
125 /******************************************************************************
126 * *
127 * Function: ipmi_poller_process_command_request *
128 * *
129 * Purpose:sets IPMI sensor value *
130 * *
131 * Parameters: socket - [IN] the connections socket *
132 * message - [IN] the command request message *
133 * *
134 ******************************************************************************/
ipmi_poller_process_command_request(zbx_ipc_async_socket_t * socket,zbx_ipc_message_t * message)135 static void ipmi_poller_process_command_request(zbx_ipc_async_socket_t *socket, zbx_ipc_message_t *message)
136 {
137 const char *__function_name = "ipmi_poller_process_command_request";
138 zbx_uint64_t itemid;
139 char *addr, *username, *password, *sensor, *error = NULL;
140 signed char authtype;
141 unsigned char privilege;
142 unsigned short port;
143 int errcode, command;
144
145 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
146
147 zbx_ipmi_deserialize_request(message->data, &itemid, &addr, &port, &authtype,
148 &privilege, &username, &password, &sensor, &command);
149
150 zabbix_log(LOG_LEVEL_TRACE, "%s() hostid:" ZBX_FS_UI64 " addr:%s port:%d authtype:%d privilege:%d username:%s"
151 " sensor:%s", __function_name, itemid, addr, (int)port, (int)authtype, (int)privilege,
152 username, sensor);
153
154 errcode = zbx_set_ipmi_control_value(itemid, addr, port, authtype, privilege, username, password, sensor,
155 command, &error);
156
157 ipmi_poller_send_result(socket, ZBX_IPC_IPMI_COMMAND_RESULT, errcode, error);
158
159 zbx_free(error);
160 zbx_free(addr);
161 zbx_free(username);
162 zbx_free(password);
163 zbx_free(sensor);
164
165 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
166 }
167
ZBX_THREAD_ENTRY(ipmi_poller_thread,args)168 ZBX_THREAD_ENTRY(ipmi_poller_thread, args)
169 {
170 char *error = NULL;
171 zbx_ipc_async_socket_t ipmi_socket;
172 int polled_num = 0;
173 double time_stat, time_idle = 0, time_now, time_read;
174
175 #define STAT_INTERVAL 5 /* if a process is busy and does not sleep then update status not faster than */
176 /* once in STAT_INTERVAL seconds */
177
178 process_type = ((zbx_thread_args_t *)args)->process_type;
179
180 server_num = ((zbx_thread_args_t *)args)->server_num;
181 process_num = ((zbx_thread_args_t *)args)->process_num;
182
183 zbx_setproctitle("%s #%d starting", get_process_type_string(process_type), process_num);
184
185 zabbix_log(LOG_LEVEL_INFORMATION, "%s #%d started [%s #%d]", get_program_type_string(program_type),
186 server_num, get_process_type_string(process_type), process_num);
187
188 update_selfmon_counter(ZBX_PROCESS_STATE_BUSY);
189
190 if (FAIL == zbx_ipc_async_socket_open(&ipmi_socket, ZBX_IPC_SERVICE_IPMI, SEC_PER_MIN, &error))
191 {
192 zabbix_log(LOG_LEVEL_CRIT, "cannot connect to IPMI service: %s", error);
193 zbx_free(error);
194 exit(EXIT_FAILURE);
195 }
196
197 zbx_init_ipmi_handler();
198
199 ipmi_poller_register(&ipmi_socket);
200
201 time_stat = zbx_time();
202
203 zbx_setproctitle("%s #%d started", get_process_type_string(process_type), process_num);
204
205 while (ZBX_IS_RUNNING())
206 {
207 zbx_ipc_message_t *message = NULL;
208
209 time_now = zbx_time();
210
211 if (STAT_INTERVAL < time_now - time_stat)
212 {
213 zbx_setproctitle("%s #%d [polled %d values, idle " ZBX_FS_DBL " sec during "
214 ZBX_FS_DBL " sec]", get_process_type_string(process_type), process_num,
215 polled_num, time_idle, time_now - time_stat);
216
217 time_stat = time_now;
218 time_idle = 0;
219 polled_num = 0;
220 }
221
222 update_selfmon_counter(ZBX_PROCESS_STATE_IDLE);
223
224 while (ZBX_IS_RUNNING())
225 {
226 const int ipc_timeout = 2;
227 const int ipmi_timeout = 1;
228
229 if (SUCCEED != zbx_ipc_async_socket_recv(&ipmi_socket, ipc_timeout, &message))
230 {
231 zabbix_log(LOG_LEVEL_CRIT, "cannot read IPMI service request");
232 exit(EXIT_FAILURE);
233 }
234
235 if (NULL != message)
236 break;
237
238 zbx_perform_all_openipmi_ops(ipmi_timeout);
239 }
240
241 update_selfmon_counter(ZBX_PROCESS_STATE_BUSY);
242
243 if (NULL == message)
244 break;
245
246 time_read = zbx_time();
247 time_idle += time_read - time_now;
248 zbx_update_env(time_read);
249
250 switch (message->code)
251 {
252 case ZBX_IPC_IPMI_VALUE_REQUEST:
253 ipmi_poller_process_value_request(&ipmi_socket, message);
254 polled_num++;
255 break;
256 case ZBX_IPC_IPMI_COMMAND_REQUEST:
257 ipmi_poller_process_command_request(&ipmi_socket, message);
258 break;
259 case ZBX_IPC_IPMI_CLEANUP_REQUEST:
260 zbx_delete_inactive_ipmi_hosts(time(NULL));
261 break;
262 }
263
264 zbx_ipc_message_free(message);
265 message = NULL;
266 }
267
268 zbx_setproctitle("%s #%d [terminated]", get_process_type_string(process_type), process_num);
269
270 while (1)
271 zbx_sleep(SEC_PER_MIN);
272
273 zbx_ipc_async_socket_close(&ipmi_socket);
274
275 zbx_free_ipmi_handler();
276 #undef STAT_INTERVAL
277 }
278
279 #endif
280