Coverage Report

Created: 2024-02-25 06:37

/src/ntopng/src/InterfaceStatsHash.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *
3
 * (C) 2013-24 - ntop.org
4
 *
5
 *
6
 * This program is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software Foundation,
18
 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
 *
20
 */
21
22
#include "ntop_includes.h"
23
24
/* ************************************ */
25
26
0
InterfaceStatsHash::InterfaceStatsHash(u_int _max_hash_size) {
27
0
  if(trace_new_delete) ntop->getTrace()->traceEvent(TRACE_NORMAL, "[new] %s", __FILE__);
28
  
29
0
  max_hash_size = _max_hash_size;
30
0
  buckets = (sFlowInterfaceStats **)calloc(sizeof(sFlowInterfaceStats *),
31
0
                                           max_hash_size);
32
33
0
  if (buckets == NULL) throw "Not enough memory";
34
0
}
35
36
/* ************************************ */
37
38
0
InterfaceStatsHash::~InterfaceStatsHash() {
39
0
  for (u_int i = 0; i < max_hash_size; i++) {
40
0
    if (buckets[i] != NULL) {
41
0
      if (buckets[i]->ifName) free(buckets[i]->ifName);
42
43
0
      if (buckets[i]->container_info_set) {
44
0
        if (buckets[i]->container_info.id) free(buckets[i]->container_info.id);
45
0
        if (buckets[i]->container_info.name)
46
0
          free(buckets[i]->container_info.name);
47
48
0
        if (buckets[i]->container_info.data_type ==
49
0
            container_info_data_type_k8s) {
50
0
          if (buckets[i]->container_info.data.k8s.pod)
51
0
            free(buckets[i]->container_info.data.k8s.pod);
52
0
          if (buckets[i]->container_info.data.k8s.ns)
53
0
            free(buckets[i]->container_info.data.k8s.ns);
54
0
        } else if (buckets[i]->container_info.data_type ==
55
0
                   container_info_data_type_docker)
56
0
          ;
57
0
      }
58
59
0
      free(buckets[i]);
60
0
    }
61
0
  }
62
63
0
  free(buckets);
64
0
}
65
/* ************************************ */
66
67
0
bool InterfaceStatsHash::set(const sFlowInterfaceStats *const stats) {
68
0
  sFlowInterfaceStats *head;
69
0
  u_int32_t ifIndex = stats->ifIndex, deviceIP = stats->deviceIP;
70
0
  const char *ifName = stats->ifName;
71
0
  u_int32_t hash = (deviceIP + ifIndex + Utils::hashString(ifName)) %
72
0
                   max_hash_size,
73
0
            num_runs = 0;
74
0
  bool ret = true;
75
76
0
  m.lock(__FILE__, __LINE__);
77
78
0
  if (!buckets[hash]) goto new_bucket;
79
80
0
  head = (sFlowInterfaceStats *)buckets[hash];
81
82
0
  while (head != NULL) {
83
0
    if (head->deviceIP == deviceIP && head->ifIndex == ifIndex &&
84
0
        ((!head->ifName && !ifName) ||
85
0
         (head->ifName && ifName && strcmp(head->ifName, ifName) == 0))) {
86
0
      break;
87
0
    } else {
88
      /* Inplace hash */
89
0
      hash = (hash + 1) % max_hash_size, num_runs++;
90
91
0
      if (num_runs >= max_hash_size) {
92
0
        ntop->getTrace()->traceEvent(
93
0
            TRACE_WARNING, "Internal error: too many loops=%u", max_hash_size);
94
0
        ret = false;
95
0
        goto unlock;
96
0
      }
97
98
0
      head = buckets[hash];
99
0
    }
100
0
  }
101
102
0
  if (head) {
103
    /* Update values */
104
0
    head->ifType = stats->ifType, head->ifSpeed = stats->ifSpeed,
105
0
    head->ifFullDuplex = stats->ifFullDuplex,
106
0
    head->ifAdminStatus = stats->ifAdminStatus,
107
0
    head->ifOperStatus = stats->ifOperStatus,
108
0
    head->ifPromiscuousMode = stats->ifPromiscuousMode;
109
110
0
    if (stats->samplesGenerated > 0 &&
111
0
        stats->samplesGenerated == head->samplesGenerated) {
112
      /*
113
        This is an update as `samplesGenerated`.
114
        Ubiquiti routers when generating sFlow send two counters samples in two
115
        different packets with the same value for `samplesGenerated`. The first
116
        counter sample has data for the IN direction and the second counter
117
        sample has data for the OUT direction. In this case, we need to check
118
        and update values rather than overwriting them.
119
       */
120
0
      head->ifInOctets += stats->ifInOctets,
121
0
          head->ifInPackets += stats->ifInPackets,
122
0
          head->ifInErrors += stats->ifInErrors,
123
0
          head->ifOutOctets += stats->ifOutOctets,
124
0
          head->ifOutPackets += stats->ifOutPackets,
125
0
          head->ifOutErrors += stats->ifOutErrors;
126
0
    } else {
127
0
      head->ifInOctets = stats->ifInOctets,
128
0
      head->ifInPackets = stats->ifInPackets,
129
0
      head->ifInErrors = stats->ifInErrors,
130
0
      head->ifOutOctets = stats->ifOutOctets,
131
0
      head->ifOutPackets = stats->ifOutPackets,
132
0
      head->ifOutErrors = stats->ifOutErrors;
133
0
    }
134
135
0
    head->samplesGenerated = stats->samplesGenerated;
136
0
  } else {
137
0
  new_bucket:
138
0
    buckets[hash] = (sFlowInterfaceStats *)malloc(sizeof(sFlowInterfaceStats));
139
140
0
    if (!buckets[hash]) {
141
0
      ret = false;
142
0
      goto unlock;
143
0
    }
144
145
0
    memcpy(buckets[hash], stats, sizeof(sFlowInterfaceStats));
146
147
0
    if (buckets[hash]->ifName)
148
0
      buckets[hash]->ifName = strdup(buckets[hash]->ifName);
149
150
0
    if (buckets[hash]->container_info_set) {
151
0
      if (buckets[hash]->container_info.id)
152
0
        buckets[hash]->container_info.id =
153
0
            strdup(buckets[hash]->container_info.id);
154
0
      if (buckets[hash]->container_info.name)
155
0
        buckets[hash]->container_info.name =
156
0
            strdup(buckets[hash]->container_info.name);
157
158
0
      if (buckets[hash]->container_info.data_type ==
159
0
          container_info_data_type_k8s) {
160
0
        if (buckets[hash]->container_info.data.k8s.pod)
161
0
          buckets[hash]->container_info.data.k8s.pod =
162
0
              strdup(buckets[hash]->container_info.data.k8s.pod);
163
0
        if (buckets[hash]->container_info.data.k8s.ns)
164
0
          buckets[hash]->container_info.data.k8s.ns =
165
0
              strdup(buckets[hash]->container_info.data.k8s.ns);
166
0
      } else if (buckets[hash]->container_info.data_type ==
167
0
                 container_info_data_type_docker) {
168
0
      }
169
0
    }
170
0
  }
171
172
0
unlock:
173
0
  m.unlock(__FILE__, __LINE__);
174
175
0
  return (ret);
176
0
}
177
178
/* ************************************ */
179
180
0
void InterfaceStatsHash::luaDeviceList(lua_State *vm) {
181
0
  std::set<u_int32_t>
182
0
      flowDevices; /* Set size automatically limited by max_hash_size */
183
0
  std::set<u_int32_t>::const_iterator it;
184
185
0
  lua_newtable(vm);
186
187
0
  m.lock(__FILE__, __LINE__);
188
189
0
  for (u_int i = 0; i < max_hash_size; i++) {
190
0
    sFlowInterfaceStats *head = (sFlowInterfaceStats *)buckets[i];
191
192
0
    if (head) {
193
0
      bool found = false;
194
195
0
      if (flowDevices.find(head->deviceIP) != flowDevices.end()) found = true;
196
197
0
      if (!found) {
198
0
        char a[64];
199
200
0
        flowDevices.insert(head->deviceIP);
201
202
0
        lua_push_uint64_table_entry(
203
0
            vm, Utils::intoaV4(head->deviceIP, a, sizeof(a)), head->deviceIP);
204
0
      }
205
0
    }
206
0
  }
207
208
0
  m.unlock(__FILE__, __LINE__);
209
0
}
210
211
/* ************************************ */
212
213
0
void InterfaceStatsHash::luaDeviceInfo(lua_State *vm, u_int32_t deviceIP) {
214
0
  lua_newtable(vm);
215
216
0
  m.lock(__FILE__, __LINE__);
217
218
0
  for (u_int i = 0; i < max_hash_size; i++) {
219
0
    sFlowInterfaceStats *head = (sFlowInterfaceStats *)buckets[i];
220
221
0
    if (head && (head->deviceIP == deviceIP)) {
222
0
      lua_newtable(vm);
223
224
0
      lua_push_uint64_table_entry(vm, "ifType", head->ifType);
225
0
      if (head->ifName) lua_push_str_table_entry(vm, "ifName", head->ifName);
226
0
      if (head->container_info_set) {
227
0
        Utils::containerInfoLua(vm, &head->container_info);
228
229
0
        lua_pushstring(vm, "container");
230
0
        lua_insert(vm, -2);
231
0
        lua_settable(vm, -3);
232
0
      }
233
0
      lua_push_uint64_table_entry(vm, "ifSpeed", head->ifSpeed);
234
0
      lua_push_bool_table_entry(vm, "ifFullDuplex", head->ifFullDuplex);
235
0
      lua_push_bool_table_entry(vm, "ifAdminStatus", head->ifAdminStatus);
236
0
      lua_push_bool_table_entry(vm, "ifOperStatus", head->ifOperStatus);
237
0
      lua_push_bool_table_entry(vm, "ifPromiscuousMode",
238
0
                                head->ifPromiscuousMode);
239
0
      lua_push_uint64_table_entry(vm, "ifInOctets", head->ifInOctets);
240
0
      lua_push_uint64_table_entry(vm, "ifInPackets", head->ifInPackets);
241
0
      lua_push_uint64_table_entry(vm, "ifInErrors", head->ifInErrors);
242
0
      lua_push_uint64_table_entry(vm, "ifOutOctets", head->ifOutOctets);
243
0
      lua_push_uint64_table_entry(vm, "ifOutPackets", head->ifOutPackets);
244
0
      lua_push_uint64_table_entry(vm, "ifOutErrors", head->ifOutErrors);
245
246
0
      lua_pushinteger(vm, head->ifIndex);
247
0
      lua_insert(vm, -2);
248
0
      lua_settable(vm, -3);
249
0
    }
250
0
  }
251
252
0
  m.unlock(__FILE__, __LINE__);
253
0
}