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