d5b4200bacf353e4b18ac0665e20972bdf99d36a
[public/netxms.git] / src / agent / subagents / xen / net.cpp
1 /*
2 ** NetXMS XEN hypervisor subagent
3 ** Copyright (C) 2017 Raden Solutions
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., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 ** File: net.cpp
20 **
21 **/
22
23 #include "xen.h"
24
25 /**
26 * Network device information
27 */
28 struct NetDevice
29 {
30 char name[64];
31 uint32_t domId;
32 uint32_t netId;
33 UINT64 rxBytes;
34 UINT64 txBytes;
35 UINT64 rxPackets;
36 UINT64 txPackets;
37 };
38
39 /**
40 * Get domaind and network ID from network device name
41 */
42 static bool NetDeviceToDomId(const char *dev, uint32_t *domId, uint32_t *netId)
43 {
44 if (sscanf(dev, "vif%u.%u", domId, netId) == 2)
45 return true;
46
47 char path[128];
48 snprintf(path, 128, "/sys/class/net/%s/device/nodename", dev);
49 FILE *f = fopen(path, "r");
50 if (path != NULL)
51 {
52 char line[256];
53 fgets(line, 256, f);
54 fclose(f);
55 if (sscanf(line, "backend/vif/%u/%u", domId, netId) == 2)
56 return true;
57 }
58
59 return false;
60 }
61
62 /**
63 * Scan network devices
64 */
65 ObjectArray<NetDevice> *ScanNetworkDevices()
66 {
67 FILE *f = fopen("/proc/net/dev", "r");
68 if (f == NULL)
69 return NULL;
70
71 char line[1024];
72 NetDevice dev;
73
74 ObjectArray<NetDevice> *devices = new ObjectArray<NetDevice>(32, 32, true);
75 while(!feof(f))
76 {
77 fgets(line, 1024, f);
78 if (sscanf(line, "%s: %llu %llu %*u %*u %*u %*u %*u %*u %llu %llu %*u %*u %*u %*u %*u %*u",
79 dev.name, &dev.rxBytes, &dev.rxPackets, &dev.txBytes, &dev.txPackets) == 5)
80 {
81 if (NetDeviceToDomId(dev.name, &dev.domId, &dev.netId))
82 {
83 devices->add(new NetDevice(dev));
84 }
85 }
86 }
87 fclose(f);
88 return devices;
89 }
90
91 /**
92 * Network device data cache
93 */
94 static ObjectArray<NetDevice> *s_cache = NULL;
95 static time_t s_cacheTimestamp = 0;
96 static Mutex s_cacheLock;
97
98 /**
99 * Acquire device data cache and update if needed
100 */
101 inline void AcquireNetDeviceCache()
102 {
103 s_cacheLock.lock();
104 time_t now = time(NULL);
105 if (now - s_cacheTimestamp > 1)
106 {
107 delete s_cache;
108 s_cache = ScanNetworkDevices();
109 if (s_cache != NULL)
110 s_cacheTimestamp = now;
111 }
112 }
113
114 /**
115 * Query network traffic for domain
116 */
117 bool XenQueryDomainNetworkTraffic(uint32_t domId, UINT64 *rxBytes, UINT64 *txBytes, UINT64 *rxPackets, UINT64 *txPackets)
118 {
119 bool success = false;
120
121 *rxBytes = 0;
122 *txBytes = 0;
123 *rxPackets = 0;
124 *txPackets = 0;
125
126 AcquireNetDeviceCache();
127 if (s_cache != NULL)
128 {
129 for(int i = 0; i < s_cache->size(); i++)
130 {
131 NetDevice *d = s_cache->get(i);
132 if (d->domId == domId)
133 {
134 *rxBytes += d->rxBytes;
135 *txBytes += d->txBytes;
136 *rxPackets += d->rxPackets;
137 *txPackets += d->txPackets;
138 }
139 }
140 success = true;
141 }
142 s_cacheLock.unlock();
143 return success;
144 }
145
146 /**
147 * Handler for XEN.Domain.Net.* parameters
148 */
149 LONG H_XenDomainNetStats(const TCHAR *param, const TCHAR *arg, TCHAR *value, AbstractCommSession *session)
150 {
151 char domName[256];
152 if (!AgentGetParameterArgA(param, 1, domName, 256))
153 return SYSINFO_RC_UNSUPPORTED;
154
155 char *eptr;
156 uint32_t domId = strtoul(domName, &eptr, 0);
157 if (*eptr != 0)
158 {
159 LONG rc = XenResolveDomainName(domName, &domId);
160 if (rc != SYSINFO_RC_SUCCESS)
161 return rc;
162 }
163
164 LONG rc = SYSINFO_RC_ERROR;
165 UINT64 rxBytes, txBytes, rxPackets, txPackets;
166 if (XenQueryDomainNetworkTraffic(domId, &rxBytes, &txBytes, &rxPackets, &txPackets))
167 {
168 if (arg[0] == 'R')
169 {
170 ret_uint64(value, arg[1] == 'B' ? rxBytes : rxPackets);
171 }
172 else
173 {
174 ret_uint64(value, arg[1] == 'B' ? txBytes : txPackets);
175 }
176 rc = SYSINFO_RC_SUCCESS;
177 }
178 return rc;
179 }