suricata
source-pcap.c
Go to the documentation of this file.
1 /* Copyright (C) 2020 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 #include "../suricata-common.h"
19 #include "../util-unittest.h"
20 
21 static uint32_t Upper32(uint64_t value)
22 {
23  /* uint64_t -> uint32_t is defined behaviour. It slices lower 32bits. */
24  return value >> 32;
25 }
26 static uint32_t Lower32(uint64_t value)
27 {
28  /* uint64_t -> uint32_t is defined behaviour. It slices lower 32bits. */
29  return value;
30 }
31 
32 /* Structured test data to make it easier on my eyes */
33 typedef struct TestData_ {
34  uint64_t last; /* internal 64bit counter to drag along */
35  u_int current; /* 32bit pcap stat */
37 
38 static int UpdatePcapStatsValue64NoChange01(void)
39 {
40  /*
41  * No change in counter values.
42  * Last count is within first 32bit range, i.e. same as pcap_stat range.
43  */
44  TestData data[] = {{.last = 0, .current = 0},
45  {.last = 12345, .current = 12345},
46  {.last = (uint64_t)UINT32_MAX, .current = UINT_MAX}};
47 
48  for (size_t i = 0; i < ARRAY_SIZE(data); ++i) {
49  FAIL_IF_NOT(data[i].last == data[i].current);
50 
51  UpdatePcapStatsValue64(&data[i].last, data[i].current);
52  FAIL_IF_NOT(data[i].last == data[i].current);
53  }
54 
55  PASS;
56 }
57 
58 static int UpdatePcapStatsValue64NoChange02(void)
59 {
60  /*
61  * No change in counter values.
62  * Last count is outside 32bits range.
63  */
64  TestData data[] = {{.last = (2ull << 32) + 0, .current = 0},
65  {.last = (3ull << 32) + 12345, .current = 12345},
66  {.last = (3ull << 32) + (uint64_t)UINT32_MAX, .current = UINT_MAX},
67  {.last = UINT64_MAX, .current = UINT_MAX}};
68 
69  for (size_t i = 0; i < ARRAY_SIZE(data); ++i) {
70  uint32_t upper = Upper32(data[i].last);
71  FAIL_IF_NOT(Lower32(data[i].last) == data[i].current);
72 
73  UpdatePcapStatsValue64(&data[i].last, data[i].current);
74  FAIL_IF_NOT(Lower32(data[i].last) == data[i].current);
75  FAIL_IF_NOT(Upper32(data[i].last) == upper);
76  }
77 
78  PASS;
79 }
80 
81 static int UpdatePcapStatsValue64NoOverflow01(void)
82 {
83  /*
84  * Non-overflowing counter value is simply taken over in lower 32bits.
85  * Last count is within first 32bit range, i.e. same as pcap_stat range.
86  * Also test edges and simple +1.
87  */
88  TestData data[] = {{.last = 0, .current = 1},
89  {.last = 12345, .current = 34567},
90  {.last = (uint64_t)UINT32_MAX - 1, .current = UINT_MAX}};
91 
92  for (size_t i = 0; i < ARRAY_SIZE(data); ++i) {
93  FAIL_IF_NOT(data[i].last < data[i].current);
94 
95  UpdatePcapStatsValue64(&data[i].last, data[i].current);
96  FAIL_IF_NOT(data[i].last == data[i].current);
97  }
98 
99  PASS;
100 }
101 
102 static int UpdatePcapStatsValue64NoOverflow02(void)
103 {
104  /*
105  * Non-overflowing counter value is simply taken over in lower 32bits.
106  * Last count is outside 32bits range.
107  */
108  TestData data[] = {{.last = (2ull << 32) + 0, .current = 1},
109  {.last = (3ull << 32) + 12345, .current = 34567},
110  {.last = UINT64_MAX - 1, .current = UINT_MAX}};
111 
112  for (size_t i = 0; i < ARRAY_SIZE(data); ++i) {
113  uint32_t upper = Upper32(data[i].last);
114  FAIL_IF_NOT(Lower32(data[i].last) < data[i].current);
115 
116  UpdatePcapStatsValue64(&data[i].last, data[i].current);
117  FAIL_IF_NOT(Lower32(data[i].last) == data[i].current);
118  FAIL_IF_NOT(Upper32(data[i].last) == upper);
119  }
120 
121  PASS;
122 }
123 
124 static int UpdatePcapStatsValue64Overflow01(void)
125 {
126  /*
127  * Overflowing counter value is simply taken over in lower 32bits.
128  * Last count is within first 32bit range, i.e. same as pcap_stat range.
129  */
130  TestData data[] = {{.last = 1, .current = 0},
131  {.last = 12345, .current = 22}, {.last = 12345, .current = 12344},
132  {.last = (uint64_t)UINT32_MAX, .current = UINT_MAX - 1}};
133 
134  for (size_t i = 0; i < ARRAY_SIZE(data); ++i) {
135  FAIL_IF_NOT(data[i].last > data[i].current);
136 
137  UpdatePcapStatsValue64(&data[i].last, data[i].current);
138  FAIL_IF_NOT(Lower32(data[i].last) == data[i].current);
139  FAIL_IF_NOT(Upper32(data[i].last) == 1); /* wrap around */
140  }
141 
142  PASS;
143 }
144 
145 static int UpdatePcapStatsValue64Overflow02(void)
146 {
147  /*
148  * Overflowing counter value is simply taken over in lower 32bits.
149  * Last count is outside 32bits range.
150  */
151  TestData data[] = {{.last = (2ull << 32) + 1, .current = 0},
152  {.last = (3ull << 32) + 12345, .current = 22},
153  {.last = (3ull << 32) + 12345, .current = 12344},
154  {.last = UINT64_MAX, .current = UINT_MAX - 1}};
155 
156  for (size_t i = 0; i < ARRAY_SIZE(data); ++i) {
157  uint32_t upper = Upper32(data[i].last);
158  FAIL_IF_NOT(Lower32(data[i].last) > data[i].current);
159 
160  UpdatePcapStatsValue64(&data[i].last, data[i].current);
161  FAIL_IF_NOT(Lower32(data[i].last) == data[i].current);
162  FAIL_IF_NOT(Upper32(data[i].last) == upper + 1); /* wrap around */
163  }
164 
165  PASS;
166 }
167 
168 static int UpdatePcapStatsValue64Overflow03(void)
169 {
170  /*
171  * Overflowing counter value is simply taken over in lower 32bits.
172  * Edge cases where upper32 bit wrap around to 0.
173  */
174  TestData data[] = {{.last = UINT64_MAX, .current = 0},
175  {.last = UINT64_MAX, .current = 3333}};
176 
177  for (size_t i = 0; i < ARRAY_SIZE(data); ++i) {
178  FAIL_IF_NOT(Lower32(data[i].last) > data[i].current);
179 
180  UpdatePcapStatsValue64(&data[i].last, data[i].current);
181  FAIL_IF_NOT(Lower32(data[i].last) == data[i].current);
182  FAIL_IF_NOT(Upper32(data[i].last) == 0); /* wrap around */
183  }
184 
185  PASS;
186 }
187 
188 static int UpdatePcapStats64Assorted01(void)
189 {
190  /*
191  * Test that all fields of the struct are correctly updated.
192  *
193  * Full testing of value behaviour is done in UpdatePcapStatsValue64...()
194  * tests.
195  */
196  PcapStats64 last = {.ps_recv = 0, .ps_drop = 1234, .ps_ifdrop = 8765};
197  struct pcap_stat current = {
198  .ps_recv = 12, .ps_drop = 2345, .ps_ifdrop = 9876};
199 
200  // test setup sanity check
201  FAIL_IF_NOT(last.ps_recv < current.ps_recv);
202  FAIL_IF_NOT(last.ps_drop < current.ps_drop);
203  FAIL_IF_NOT(last.ps_ifdrop < current.ps_ifdrop);
204 
205  UpdatePcapStats64(&last, &current);
206 
207  FAIL_IF_NOT(last.ps_recv == current.ps_recv);
208  FAIL_IF_NOT(last.ps_drop == current.ps_drop);
209  FAIL_IF_NOT(last.ps_ifdrop == current.ps_ifdrop);
210 
211  PASS;
212 }
213 
214 static void SourcePcapRegisterStatsTests(void)
215 {
216  UtRegisterTest("UpdatePcapStatsValue64NoChange01",
217  UpdatePcapStatsValue64NoChange01);
218  UtRegisterTest("UpdatePcapStatsValue64NoChange02",
219  UpdatePcapStatsValue64NoChange02);
220  UtRegisterTest("UpdatePcapStatsValue64NoOverflow01",
221  UpdatePcapStatsValue64NoOverflow01);
222  UtRegisterTest("UpdatePcapStatsValue64NoOverflow02",
223  UpdatePcapStatsValue64NoOverflow02);
224  UtRegisterTest("UpdatePcapStatsValue64Overflow01",
225  UpdatePcapStatsValue64Overflow01);
226  UtRegisterTest("UpdatePcapStatsValue64Overflow02",
227  UpdatePcapStatsValue64Overflow02);
228  UtRegisterTest("UpdatePcapStatsValue64Overflow03",
229  UpdatePcapStatsValue64Overflow03);
230 
231  UtRegisterTest("UpdatePcapStats64Assorted01", UpdatePcapStats64Assorted01);
232 }
TestData_::last
uint64_t last
Definition: source-pcap.c:34
TestData_::current
u_int current
Definition: source-pcap.c:35
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
PcapStats64_::ps_drop
uint64_t ps_drop
Definition: source-pcap.c:65
FAIL_IF_NOT
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:82
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
PcapStats64_::ps_recv
uint64_t ps_recv
Definition: source-pcap.c:64
ARRAY_SIZE
#define ARRAY_SIZE(arr)
Definition: suricata-common.h:547
PcapStats64_
64bit pcap stats counters.
Definition: source-pcap.c:63
TestData_
Definition: source-pcap.c:33
PcapStats64_::ps_ifdrop
uint64_t ps_ifdrop
Definition: source-pcap.c:66
TestData
struct TestData_ TestData