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