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 #include "sysinfo.h"
22 #include "zbxjson.h"
23 #include "log.h"
24
25 typedef struct
26 {
27 zbx_uint64_t ibytes;
28 zbx_uint64_t ipackets;
29 zbx_uint64_t ierr;
30 zbx_uint64_t obytes;
31 zbx_uint64_t opackets;
32 zbx_uint64_t oerr;
33 zbx_uint64_t colls;
34 }
35 net_stat_t;
36
get_net_stat(const char * if_name,net_stat_t * ns,char ** error)37 static int get_net_stat(const char *if_name, net_stat_t *ns, char **error)
38 {
39 #if defined(HAVE_LIBPERFSTAT)
40 perfstat_id_t ps_id;
41 perfstat_netinterface_t ps_netif;
42
43 if (NULL == if_name || '\0' == *if_name)
44 {
45 *error = zbx_strdup(NULL, "Network interface name cannot be empty.");
46 return SYSINFO_RET_FAIL;
47 }
48
49 strscpy(ps_id.name, if_name);
50
51 if (-1 == perfstat_netinterface(&ps_id, &ps_netif, sizeof(ps_netif), 1))
52 {
53 *error = zbx_dsprintf(NULL, "Cannot obtain system information: %s", zbx_strerror(errno));
54 return SYSINFO_RET_FAIL;
55 }
56
57 ns->ibytes = (zbx_uint64_t)ps_netif.ibytes;
58 ns->ipackets = (zbx_uint64_t)ps_netif.ipackets;
59 ns->ierr = (zbx_uint64_t)ps_netif.ierrors;
60
61 ns->obytes = (zbx_uint64_t)ps_netif.obytes;
62 ns->opackets = (zbx_uint64_t)ps_netif.opackets;
63 ns->oerr = (zbx_uint64_t)ps_netif.oerrors;
64
65 ns->colls = (zbx_uint64_t)ps_netif.collisions;
66
67 return SYSINFO_RET_OK;
68 #else
69 SET_MSG_RESULT(result, zbx_strdup(NULL, "Agent was compiled without support for Perfstat API."));
70 return SYSINFO_RET_FAIL;
71 #endif
72 }
73
NET_IF_IN(AGENT_REQUEST * request,AGENT_RESULT * result)74 int NET_IF_IN(AGENT_REQUEST *request, AGENT_RESULT *result)
75 {
76 char *if_name, *mode, *error;
77 net_stat_t ns;
78
79 if (2 < request->nparam)
80 {
81 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
82 return SYSINFO_RET_FAIL;
83 }
84
85 if_name = get_rparam(request, 0);
86 mode = get_rparam(request, 1);
87
88 if (SYSINFO_RET_FAIL == get_net_stat(if_name, &ns, &error))
89 {
90 SET_MSG_RESULT(result, error);
91 return SYSINFO_RET_FAIL;
92 }
93
94 if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "bytes"))
95 SET_UI64_RESULT(result, ns.ibytes);
96 else if (0 == strcmp(mode, "packets"))
97 SET_UI64_RESULT(result, ns.ipackets);
98 else if (0 == strcmp(mode, "errors"))
99 SET_UI64_RESULT(result, ns.ierr);
100 else
101 {
102 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
103 return SYSINFO_RET_FAIL;
104 }
105
106 return SYSINFO_RET_OK;
107 }
108
NET_IF_OUT(AGENT_REQUEST * request,AGENT_RESULT * result)109 int NET_IF_OUT(AGENT_REQUEST *request, AGENT_RESULT *result)
110 {
111 char *if_name, *mode, *error;
112 net_stat_t ns;
113
114 if (2 < request->nparam)
115 {
116 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
117 return SYSINFO_RET_FAIL;
118 }
119
120 if_name = get_rparam(request, 0);
121 mode = get_rparam(request, 1);
122
123 if (SYSINFO_RET_FAIL == get_net_stat(if_name, &ns, &error))
124 {
125 SET_MSG_RESULT(result, error);
126 return SYSINFO_RET_FAIL;
127 }
128
129 if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "bytes"))
130 SET_UI64_RESULT(result, ns.obytes);
131 else if (0 == strcmp(mode, "packets"))
132 SET_UI64_RESULT(result, ns.opackets);
133 else if (0 == strcmp(mode, "errors"))
134 SET_UI64_RESULT(result, ns.oerr);
135 else
136 {
137 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
138 return SYSINFO_RET_FAIL;
139 }
140
141 return SYSINFO_RET_OK;
142 }
143
NET_IF_TOTAL(AGENT_REQUEST * request,AGENT_RESULT * result)144 int NET_IF_TOTAL(AGENT_REQUEST *request, AGENT_RESULT *result)
145 {
146 char *if_name, *mode, *error;
147 net_stat_t ns;
148
149 if (2 < request->nparam)
150 {
151 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
152 return SYSINFO_RET_FAIL;
153 }
154
155 if_name = get_rparam(request, 0);
156 mode = get_rparam(request, 1);
157
158 if (SYSINFO_RET_FAIL == get_net_stat(if_name, &ns, &error))
159 {
160 SET_MSG_RESULT(result, error);
161 return SYSINFO_RET_FAIL;
162 }
163
164 if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "bytes"))
165 SET_UI64_RESULT(result, ns.ibytes + ns.obytes);
166 else if (0 == strcmp(mode, "packets"))
167 SET_UI64_RESULT(result, ns.ipackets + ns.opackets);
168 else if (0 == strcmp(mode, "errors"))
169 SET_UI64_RESULT(result, ns.ierr + ns.oerr);
170 else
171 {
172 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
173 return SYSINFO_RET_FAIL;
174 }
175
176 return SYSINFO_RET_OK;
177 }
178
NET_IF_COLLISIONS(AGENT_REQUEST * request,AGENT_RESULT * result)179 int NET_IF_COLLISIONS(AGENT_REQUEST *request, AGENT_RESULT *result)
180 {
181 char *if_name, *error;
182 net_stat_t ns;
183
184 if (1 < request->nparam)
185 {
186 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
187 return SYSINFO_RET_FAIL;
188 }
189
190 if_name = get_rparam(request, 0);
191
192 if (SYSINFO_RET_FAIL == get_net_stat(if_name, &ns, &error))
193 {
194 SET_MSG_RESULT(result, error);
195 return SYSINFO_RET_FAIL;
196 }
197
198 SET_UI64_RESULT(result, ns.colls);
199
200 return SYSINFO_RET_OK;
201 }
202
NET_IF_DISCOVERY(AGENT_REQUEST * request,AGENT_RESULT * result)203 int NET_IF_DISCOVERY(AGENT_REQUEST *request, AGENT_RESULT *result)
204 {
205 #if defined(HAVE_LIBPERFSTAT)
206 int rc, i, ret = SYSINFO_RET_FAIL;
207 perfstat_id_t ps_id;
208 perfstat_netinterface_t *ps_netif = NULL;
209 struct zbx_json j;
210
211 /* check how many perfstat_netinterface_t structures are available */
212 if (-1 == (rc = perfstat_netinterface(NULL, NULL, sizeof(perfstat_netinterface_t), 0)))
213 {
214 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain system information: %s", zbx_strerror(errno)));
215 return SYSINFO_RET_FAIL;
216 }
217
218 zbx_json_initarray(&j, ZBX_JSON_STAT_BUF_LEN);
219
220 if (0 == rc) /* no network interfaces found */
221 {
222 ret = SYSINFO_RET_OK;
223 goto end;
224 }
225
226 ps_netif = zbx_malloc(ps_netif, rc * sizeof(perfstat_netinterface_t));
227
228 /* set name to first interface */
229 strscpy(ps_id.name, FIRST_NETINTERFACE); /* pseudo-name for the first network interface */
230
231 /* ask to get all the structures available in one call */
232 /* return code is number of structures returned */
233 if (-1 != (rc = perfstat_netinterface(&ps_id, ps_netif, sizeof(perfstat_netinterface_t), rc)))
234 ret = SYSINFO_RET_OK;
235
236 /* collecting of the information for each of the interfaces */
237 for (i = 0; i < rc; i++)
238 {
239 zbx_json_addobject(&j, NULL);
240 zbx_json_addstring(&j, "{#IFNAME}", ps_netif[i].name, ZBX_JSON_TYPE_STRING);
241 zbx_json_close(&j);
242 }
243
244 zbx_free(ps_netif);
245 end:
246 zbx_json_close(&j);
247
248 SET_STR_RESULT(result, strdup(j.buffer));
249
250 zbx_json_free(&j);
251
252 return ret;
253 #else
254 SET_MSG_RESULT(result, zbx_strdup(NULL, "Agent was compiled without support for Perfstat API."));
255 return SYSINFO_RET_FAIL;
256 #endif
257 }
258