├── .travis.yml
├── CREDITS
├── IPT-NETFLOW-MIB.my
├── Makefile.in
├── NEWS
├── README
├── README.promisc
├── compat.h
├── configure
├── dkms.conf
├── gen_compat_def
├── install-dkms.sh
├── ipt_NETFLOW.c
├── ipt_NETFLOW.h
├── irqtop
├── libipt_NETFLOW.c
├── murmur3.h
├── openwrt
├── Makefile
├── Readme.md
└── patches
│ └── 310-Makefile_crosscompile.patch
├── raw_promisc.patch
├── raw_promisc_debian_squeeze6.patch
├── snmp_NETFLOW.c
├── test_update_config.sh
├── testing.sh
├── travis
└── Dockerfile.centos
└── version.sh
/.travis.yml:
--------------------------------------------------------------------------------
1 | # .travis.yml for ipt-netflow
2 |
3 | language: c
4 | dist: xenial
5 | services:
6 | - docker
7 |
8 | addons:
9 | apt:
10 | update: true
11 | packages:
12 | - pkg-config
13 | - module-assistant
14 | - iptables-dev
15 | - snmpd
16 | - libsnmp-dev
17 |
18 | matrix:
19 | include:
20 | - name: x86_64 Ubuntu 16.04.5 LTS Xenial
21 | os: linux
22 | - name: ppc64le Ubuntu 16.04.4 LTS Xenial
23 | os: linux-ppc64le
24 | - name: x86_64 CentOS 7.6.1810
25 | env: OS_NAME=centos OS_VERSION=7.6.1810
26 | - name: x86_64 CentOS 7.4.1708
27 | env: OS_NAME=centos OS_VERSION=7.4.1708
28 | - name: x86_64 CentOS 7.3.1611
29 | env: OS_NAME=centos OS_VERSION=7.3.1611
30 | - name: x86_64 CentOS 6.10
31 | env: OS_NAME=centos OS_VERSION=6.10
32 | - name: x86_64 CentOS 6.9
33 | env: OS_NAME=centos OS_VERSION=6.9
34 | - name: x86_64 CentOS 6.8
35 | env: OS_NAME=centos OS_VERSION=6.8
36 |
37 |
38 | install:
39 | - if [ -z "$OS_NAME" ]; then
40 | ( set -x; sudo m-a prepare );
41 | else
42 | ( set -x;
43 | sudo docker pull ${OS_NAME}:${OS_VERSION};
44 | sudo docker build --no-cache --rm --file=travis/Dockerfile.${OS_NAME} --build-arg=OS_VERSION=${OS_VERSION} --tag=${OS_NAME}-${OS_VERSION}:test .;
45 | );
46 | fi
47 |
48 | script:
49 | - if [ -z "$OS_NAME" ]; then
50 | ( set -x; ./configure && make all && sudo make install );
51 | else
52 | ( set -x; sudo docker run -v $PWD:$PWD -w $PWD ${OS_NAME}-${OS_VERSION}:test );
53 | fi
54 |
55 |
--------------------------------------------------------------------------------
/CREDITS:
--------------------------------------------------------------------------------
1 | License is GPL-2.0-only, is the same as of Linux kernel:
2 |
3 | This program is free software: you can redistribute it and/or modify
4 | it under the terms of the GNU General Public License as published by
5 | the Free Software Foundation, either version 2 of the License, or
6 | (at your option) any later version.
7 |
8 | This program is distributed in the hope that it will be useful,
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | GNU General Public License for more details.
12 |
13 | You should have received a copy of the GNU General Public License
14 | along with this program. If not, see .
15 |
16 |
17 | Sign-off rule is that of the Linux kernel:
18 |
19 | Developer's Certificate of Origin 1.1
20 |
21 | By making a contribution to this project, I certify that:
22 |
23 | (a) The contribution was created in whole or in part by me and I
24 | have the right to submit it under the open source license
25 | indicated in the file; or
26 |
27 | (b) The contribution is based upon previous work that, to the best
28 | of my knowledge, is covered under an appropriate open source
29 | license and I have the right under that license to submit that
30 | work with modifications, whether created in whole or in part
31 | by me, under the same open source license (unless I am
32 | permitted to submit under a different license), as indicated
33 | in the file; or
34 |
35 | (c) The contribution was provided directly to me by some other
36 | person who certified (a), (b) or (c) and I have not modified
37 | it.
38 |
39 | (d) I understand and agree that this project and the contribution
40 | are public and that a record of the contribution (including all
41 | personal information I submit with it, including my sign-off) is
42 | maintained indefinitely and may be redistributed consistent with
43 | this project or the open source license(s) involved.
44 |
45 |
46 | Principal author and project maintainer:
47 |
48 | ABC [2008-2021]
49 |
50 |
51 | Compatibility layer is using code from Linux Kernel and should be
52 | attributed to respective Linux developers.
53 |
54 | MurmurHash3 is based on smhasher (2012) of Austin Appleby.
55 |
56 |
57 | Patch authors and submitters:
58 |
59 | Ilya Evseev [2010]
60 | spizer [2010]
61 | Eric W. Biederman [2010]
62 | Giedrius Liubavičius [2010]
63 | Igor Alov [2010]
64 | Valentin V. Yankin [2011] prototype for SNMP-index
65 | Alexey Osipov [2011]
66 | Pavel Boldin [2012]
67 | Alexander Demenshin [2013]
68 | uropek [2013]
69 | shaman [2013]
70 | Jeremy Drake [2013]
71 | Matthew Martin [2016] DKMS fixes
72 | alex-eri [2016, 2017] OpenWRT compatibility
73 | xtaran [2018]
74 | Thadeu Lima de Souza Cascardo @ Canonical [2019]
75 | dbugnar [2019]
76 | Vadim Fedorenko [2019]
77 | Paolo Pisati @ Canonical [2020]
78 | Jeroen Roovers @ Gentoo [2020]
79 | Michael Hu [2020]
80 | Sven Hartge [2020]
81 | Simon Chopin [2021]
82 |
83 |
84 | Project supporters:
85 |
86 | Summa Telecom [2014]
87 | Starlink [2014]
88 | Anonymous
89 |
90 |
91 | Extensive testing and other help:
92 |
93 | Alexander (shulik) [2013]
94 | Igor Diakonov @ Summa Telecom [2014]
95 | Yuriy Dolgoruk @ Summa Telecom [2014]
96 | Andrew Savin @ Starlink [2014]
97 | Alexander Zakharov @ WAW Technologies [2015]
98 | Ivanov Eduard [2015]
99 | Maciej Zdeb [2015]
100 |
101 |
102 | (Send your names, emails, or nicks to add to the list.)
103 |
104 |
--------------------------------------------------------------------------------
/IPT-NETFLOW-MIB.my:
--------------------------------------------------------------------------------
1 | -- IPT-NETFLOW-MIB.my
2 |
3 | IPT-NETFLOW-MIB DEFINITIONS ::= BEGIN
4 |
5 | IMPORTS
6 | MODULE-IDENTITY, OBJECT-TYPE, Counter64,
7 | Gauge32, Integer32, Counter32, enterprises
8 | FROM SNMPv2-SMI
9 | OBJECT-GROUP, MODULE-COMPLIANCE
10 | FROM SNMPv2-CONF
11 | CounterBasedGauge64
12 | FROM HCNUM-TC
13 | TEXTUAL-CONVENTION, DisplayString, DateAndTime
14 | FROM SNMPv2-TC;
15 |
16 | iptNetflowMIB MODULE-IDENTITY
17 | LAST-UPDATED "201409120000Z"
18 | ORGANIZATION "ABC"
19 | CONTACT-INFO
20 | "Author's email: abc at telekom.ru
21 |
22 | Latest version should be obtained from
23 | https://raw.githubusercontent.com/aabc/ipt-netflow/master/IPT-NETFLOW-MIB.my"
24 |
25 | DESCRIPTION
26 | "The IPT-NETFLOW-MIB defines managed objects
27 | for ipt_NETFLOW kernel module, which is high
28 | performance NetFlow/IPFIX probe for Linux.
29 |
30 | Copyright (c) 2014 .
31 |
32 | License: GPL-2.0-only"
33 |
34 | REVISION "201409110000Z"
35 | DESCRIPTION "Initial revision."
36 |
37 | ::= { enterprises 37476 9000 10 1 }
38 |
39 | -- Top Level --
40 | iptNetflowObjects OBJECT IDENTIFIER ::= { iptNetflowMIB 1 }
41 | iptNetflowStatistics OBJECT IDENTIFIER ::= { iptNetflowMIB 2 }
42 | iptNetflowConformance OBJECT IDENTIFIER ::= { iptNetflowMIB 3 }
43 |
44 | -- Objects --
45 |
46 | -- modinfo
47 | iptNetflowModule OBJECT IDENTIFIER ::= { iptNetflowObjects 1 }
48 | -- sysctl net.netflow
49 | iptNetflowSysctl OBJECT IDENTIFIER ::= { iptNetflowObjects 2 }
50 |
51 | -- Modinfo Objects --
52 |
53 | name OBJECT-TYPE
54 | SYNTAX DisplayString
55 | MAX-ACCESS read-only
56 | STATUS current
57 | DESCRIPTION
58 | "Module name."
59 | ::= { iptNetflowModule 1 }
60 |
61 | version OBJECT-TYPE
62 | SYNTAX DisplayString
63 | MAX-ACCESS read-only
64 | STATUS current
65 | DESCRIPTION
66 | "Software version of the module."
67 | ::= { iptNetflowModule 2 }
68 |
69 | srcversion OBJECT-TYPE
70 | SYNTAX DisplayString
71 | MAX-ACCESS read-only
72 | STATUS current
73 | DESCRIPTION
74 | "Binary version of the module."
75 | ::= { iptNetflowModule 3 }
76 |
77 | loadTime OBJECT-TYPE
78 | SYNTAX DateAndTime
79 | MAX-ACCESS read-only
80 | STATUS current
81 | DESCRIPTION
82 | "Module load date-time."
83 | ::= { iptNetflowModule 4 }
84 |
85 | refcnt OBJECT-TYPE
86 | SYNTAX Integer32
87 | MAX-ACCESS read-only
88 | STATUS current
89 | DESCRIPTION
90 | "Module usage by other kernel objects."
91 | ::= { iptNetflowModule 5 }
92 |
93 | -- RW Sysctl objects --
94 |
95 | protocol OBJECT-TYPE
96 | SYNTAX INTEGER {
97 | netflow5(5),
98 | netflow9(9),
99 | ipfix(10)
100 | }
101 | MAX-ACCESS read-write
102 | STATUS current
103 | DESCRIPTION
104 | "Protocol version (5, 9, 10=IPFIX)."
105 | ::= { iptNetflowSysctl 1 }
106 |
107 | hashsize OBJECT-TYPE
108 | SYNTAX Integer32
109 | UNITS "buckets"
110 | MAX-ACCESS read-write
111 | STATUS current
112 | DESCRIPTION
113 | "Hash table size of flows cache."
114 | ::= { iptNetflowSysctl 2 }
115 |
116 | maxflows OBJECT-TYPE
117 | SYNTAX Integer32
118 | UNITS "flows"
119 | MAX-ACCESS read-write
120 | STATUS current
121 | DESCRIPTION
122 | "Max flows limit. This limit is used for DoS protection."
123 | ::= { iptNetflowSysctl 3 }
124 |
125 | active-timeout OBJECT-TYPE
126 | SYNTAX Integer32
127 | UNITS "minutes"
128 | MAX-ACCESS read-write
129 | STATUS current
130 | DESCRIPTION
131 | "Active flows timeout value."
132 | ::= { iptNetflowSysctl 4 }
133 |
134 | inactive-timeout OBJECT-TYPE
135 | SYNTAX Integer32
136 | UNITS "minutes"
137 | MAX-ACCESS read-write
138 | STATUS current
139 | DESCRIPTION
140 | "Inactive flows timeout value."
141 | ::= { iptNetflowSysctl 5 }
142 |
143 | sndbuf OBJECT-TYPE
144 | SYNTAX Integer32
145 | UNITS "bytes"
146 | MAX-ACCESS read-write
147 | STATUS current
148 | DESCRIPTION
149 | "Sockets SNDBUF size."
150 | ::= { iptNetflowSysctl 6 }
151 |
152 | destination OBJECT-TYPE
153 | SYNTAX DisplayString
154 | MAX-ACCESS read-write
155 | STATUS current
156 | DESCRIPTION
157 | "Export destination parameter."
158 | ::= { iptNetflowSysctl 7 }
159 |
160 | aggregation OBJECT-TYPE
161 | SYNTAX DisplayString
162 | MAX-ACCESS read-write
163 | STATUS current
164 | DESCRIPTION
165 | "Aggregation parameters."
166 | ::= { iptNetflowSysctl 8 }
167 |
168 | sampler OBJECT-TYPE
169 | SYNTAX DisplayString
170 | MAX-ACCESS read-write
171 | STATUS current
172 | DESCRIPTION
173 | "Sampler parameters: sampling mode:sampling interval.
174 | Where samplign modes: deterministic, random, hash."
175 | ::= { iptNetflowSysctl 9 }
176 |
177 | natevents OBJECT-TYPE
178 | SYNTAX INTEGER {
179 | disabled(0),
180 | enabled(1)
181 | }
182 | MAX-ACCESS read-write
183 | STATUS current
184 | DESCRIPTION
185 | "Natevents (NEL) controlling parameter."
186 | ::= { iptNetflowSysctl 10 }
187 |
188 | promisc OBJECT-TYPE
189 | SYNTAX INTEGER {
190 | disabled(0),
191 | enabled(1)
192 | }
193 | MAX-ACCESS read-write
194 | STATUS current
195 | DESCRIPTION
196 | "Promisc hack controlling parameter."
197 | ::= { iptNetflowSysctl 11 }
198 |
199 | snmp-rules OBJECT-TYPE
200 | SYNTAX DisplayString
201 | MAX-ACCESS read-write
202 | STATUS current
203 | DESCRIPTION
204 | "SNMP-index translation rules."
205 | ::= { iptNetflowSysctl 12 }
206 |
207 | scan-min OBJECT-TYPE
208 | SYNTAX Integer32
209 | MAX-ACCESS read-write
210 | STATUS current
211 | DESCRIPTION
212 | "scan-min parameter."
213 | ::= { iptNetflowSysctl 13 }
214 |
215 | -- Statistics Objects --
216 |
217 | iptNetflowTotals OBJECT IDENTIFIER ::= { iptNetflowStatistics 1 }
218 |
219 | inBitRate OBJECT-TYPE
220 | SYNTAX CounterBasedGauge64
221 | UNITS "bits/second"
222 | MAX-ACCESS read-only
223 | STATUS current
224 | DESCRIPTION
225 | "Total incoming bits per second."
226 | ::= { iptNetflowTotals 1 }
227 |
228 | inPacketRate OBJECT-TYPE
229 | SYNTAX Gauge32
230 | UNITS "packets/second"
231 | MAX-ACCESS read-only
232 | STATUS current
233 | DESCRIPTION
234 | "Total incoming packets per second."
235 | ::= { iptNetflowTotals 2 }
236 |
237 | inFlows OBJECT-TYPE
238 | SYNTAX Counter64
239 | UNITS "flows"
240 | MAX-ACCESS read-only
241 | STATUS current
242 | DESCRIPTION
243 | "Total observed (metered) flows."
244 | ::= { iptNetflowTotals 3 }
245 |
246 | inPackets OBJECT-TYPE
247 | SYNTAX Counter64
248 | UNITS "packets"
249 | MAX-ACCESS read-only
250 | STATUS current
251 | DESCRIPTION
252 | "Total metered packets. Not couning dropped packets."
253 | ::= { iptNetflowTotals 4 }
254 |
255 | inBytes OBJECT-TYPE
256 | SYNTAX Counter64
257 | UNITS "bytes"
258 | MAX-ACCESS read-only
259 | STATUS current
260 | DESCRIPTION
261 | "Total metered bytes in inPackets."
262 | ::= { iptNetflowTotals 5 }
263 |
264 | FixedDiv100 ::= TEXTUAL-CONVENTION
265 | DISPLAY-HINT "d-2"
266 | STATUS current
267 | DESCRIPTION "Fixed point, two decimals."
268 | SYNTAX Gauge32
269 |
270 | hashMetric OBJECT-TYPE
271 | SYNTAX FixedDiv100
272 | MAX-ACCESS read-only
273 | STATUS current
274 | DESCRIPTION
275 | "Measure of performance of hash table. When optimal should
276 | attract to 1.0, when non-optimal will be highly above of 1."
277 | ::= { iptNetflowTotals 6 }
278 |
279 | hashMemory OBJECT-TYPE
280 | SYNTAX Gauge32
281 | UNITS "bytes"
282 | MAX-ACCESS read-only
283 | STATUS current
284 | DESCRIPTION
285 | "How much system memory is used by the hash table."
286 | ::= { iptNetflowTotals 7 }
287 |
288 | hashFlows OBJECT-TYPE
289 | SYNTAX Gauge32
290 | UNITS "flows"
291 | MAX-ACCESS read-only
292 | STATUS current
293 | DESCRIPTION
294 | "Flows currently residing in the hash table and not
295 | exported yet."
296 | ::= { iptNetflowTotals 8 }
297 |
298 | hashPackets OBJECT-TYPE
299 | SYNTAX Gauge32
300 | UNITS "packets"
301 | MAX-ACCESS read-only
302 | STATUS current
303 | DESCRIPTION
304 | "Packets in flows currently residing in the hash table."
305 | ::= { iptNetflowTotals 9 }
306 |
307 | hashBytes OBJECT-TYPE
308 | SYNTAX CounterBasedGauge64
309 | UNITS "bytes"
310 | MAX-ACCESS read-only
311 | STATUS current
312 | DESCRIPTION
313 | "Bytes in flows currently residing in the hash table."
314 | ::= { iptNetflowTotals 10 }
315 |
316 | dropPackets OBJECT-TYPE
317 | SYNTAX Counter64
318 | UNITS "packets"
319 | MAX-ACCESS read-only
320 | STATUS current
321 | DESCRIPTION
322 | "Total packets dropped by metering process."
323 | ::= { iptNetflowTotals 11 }
324 |
325 | dropBytes OBJECT-TYPE
326 | SYNTAX Counter64
327 | UNITS "bytes"
328 | MAX-ACCESS read-only
329 | STATUS current
330 | DESCRIPTION
331 | "Total bytes in packets dropped by metering process."
332 | ::= { iptNetflowTotals 12 }
333 |
334 | outByteRate OBJECT-TYPE
335 | SYNTAX Gauge32
336 | UNITS "bytes/second"
337 | MAX-ACCESS read-only
338 | STATUS current
339 | DESCRIPTION
340 | "Total exporter output bytes per second."
341 | ::= { iptNetflowTotals 13 }
342 |
343 | outFlows OBJECT-TYPE
344 | SYNTAX Counter64
345 | UNITS "flows"
346 | MAX-ACCESS read-only
347 | STATUS current
348 | DESCRIPTION
349 | "Total exported flow data records."
350 | ::= { iptNetflowTotals 14 }
351 |
352 | outPackets OBJECT-TYPE
353 | SYNTAX Counter64
354 | UNITS "packets"
355 | MAX-ACCESS read-only
356 | STATUS current
357 | DESCRIPTION
358 | "Total exported packets of netflow stream itself."
359 | ::= { iptNetflowTotals 15 }
360 |
361 | outBytes OBJECT-TYPE
362 | SYNTAX Counter64
363 | UNITS "bytes"
364 | MAX-ACCESS read-only
365 | STATUS current
366 | DESCRIPTION
367 | "Total exported bytes of netflow stream itself."
368 | ::= { iptNetflowTotals 16 }
369 |
370 | lostFlows OBJECT-TYPE
371 | SYNTAX Counter64
372 | UNITS "flows"
373 | MAX-ACCESS read-only
374 | STATUS current
375 | DESCRIPTION
376 | "Total of accounted flows that are lost by exporting process
377 | due to socket errors. This value will not include asynchronous
378 | errors (cberr), these will be counted in errTotal."
379 | ::= { iptNetflowTotals 17 }
380 |
381 | lostPackets OBJECT-TYPE
382 | SYNTAX Counter64
383 | UNITS "packets"
384 | MAX-ACCESS read-only
385 | STATUS current
386 | DESCRIPTION
387 | "Total metered packets lost by exporting process.
388 | See lostFlows for details."
389 | ::= { iptNetflowTotals 18 }
390 |
391 | lostBytes OBJECT-TYPE
392 | SYNTAX Counter64
393 | UNITS "bytes"
394 | MAX-ACCESS read-only
395 | STATUS current
396 | DESCRIPTION
397 | "Total bytes in packets lost by exporting process.
398 | See lostFlows for details."
399 | ::= { iptNetflowTotals 19 }
400 |
401 | errTotal OBJECT-TYPE
402 | SYNTAX Counter32
403 | MAX-ACCESS read-only
404 | STATUS current
405 | DESCRIPTION
406 | "Total exporting sockets errors (including cberr)."
407 | ::= { iptNetflowTotals 20 }
408 |
409 | sndbufPeak OBJECT-TYPE
410 | SYNTAX Counter32
411 | UNITS "bytes"
412 | MAX-ACCESS read-only
413 | STATUS current
414 | DESCRIPTION
415 | "Global maximum value of socket sndbuf. Sort of output
416 | queue length."
417 | ::= { iptNetflowTotals 21 }
418 |
419 | -- Per CPU statistics --
420 |
421 | iptNetflowCpuTable OBJECT-TYPE
422 | SYNTAX SEQUENCE OF IptNetflowCpuEntry
423 | MAX-ACCESS not-accessible
424 | STATUS current
425 | DESCRIPTION
426 | "Per-CPU statistics."
427 | ::= { iptNetflowStatistics 2 }
428 |
429 | iptNetflowCpuEntry OBJECT-TYPE
430 | SYNTAX IptNetflowCpuEntry
431 | MAX-ACCESS not-accessible
432 | STATUS current
433 | DESCRIPTION
434 | "Defines an entry in the iptNetflowCpuTable."
435 | INDEX { cpuIndex }
436 | ::= { iptNetflowCpuTable 1 }
437 |
438 | IptNetflowCpuEntry ::=
439 | SEQUENCE {
440 | cpuIndex INTEGER,
441 | cpuInPacketRate Gauge32,
442 | cpuInFlows Counter64,
443 | cpuInPackets Counter64,
444 | cpuInBytes Counter64,
445 | cpuHashMetric FixedDiv100,
446 | cpuDropPackets Counter64,
447 | cpuDropBytes Counter64,
448 | cpuErrTrunc Counter32,
449 | cpuErrFrag Counter32,
450 | cpuErrAlloc Counter32,
451 | cpuErrMaxflows Counter32
452 | }
453 |
454 | cpuIndex OBJECT-TYPE
455 | SYNTAX Integer32 (0..4096)
456 | MAX-ACCESS read-only
457 | STATUS current
458 | DESCRIPTION
459 | "Index of this cpu."
460 | ::= { iptNetflowCpuEntry 1 }
461 |
462 | cpuInPacketRate OBJECT-TYPE
463 | SYNTAX Gauge32
464 | UNITS "packets/second"
465 | MAX-ACCESS read-only
466 | STATUS current
467 | DESCRIPTION
468 | "Incoming packets per second for this cpu."
469 | ::= { iptNetflowCpuEntry 2 }
470 |
471 | cpuInFlows OBJECT-TYPE
472 | SYNTAX Counter64
473 | UNITS "flows"
474 | MAX-ACCESS read-only
475 | STATUS current
476 | DESCRIPTION
477 | "Flows metered on this cpu."
478 | ::= { iptNetflowCpuEntry 3 }
479 |
480 | cpuInPackets OBJECT-TYPE
481 | SYNTAX Counter64
482 | UNITS "packets"
483 | MAX-ACCESS read-only
484 | STATUS current
485 | DESCRIPTION
486 | "Packets metered for cpuIndex."
487 | ::= { iptNetflowCpuEntry 4 }
488 |
489 | cpuInBytes OBJECT-TYPE
490 | SYNTAX Counter64
491 | UNITS "bytes"
492 | MAX-ACCESS read-only
493 | STATUS current
494 | DESCRIPTION
495 | "Bytes metered on this cpu."
496 | ::= { iptNetflowCpuEntry 5 }
497 |
498 | cpuHashMetric OBJECT-TYPE
499 | SYNTAX FixedDiv100
500 | MAX-ACCESS read-only
501 | STATUS current
502 | DESCRIPTION
503 | "Measure of performance of hash table on this cpu."
504 | ::= { iptNetflowCpuEntry 6 }
505 |
506 | cpuDropPackets OBJECT-TYPE
507 | SYNTAX Counter64
508 | UNITS "packets"
509 | MAX-ACCESS read-only
510 | STATUS current
511 | DESCRIPTION
512 | "Packets dropped by metering process on this cpu."
513 | ::= { iptNetflowCpuEntry 7 }
514 |
515 | cpuDropBytes OBJECT-TYPE
516 | SYNTAX Counter64
517 | UNITS "bytes"
518 | MAX-ACCESS read-only
519 | STATUS current
520 | DESCRIPTION
521 | "Bytes in cpuDropPackets for this cpu."
522 | ::= { iptNetflowCpuEntry 8 }
523 |
524 | cpuErrTrunc OBJECT-TYPE
525 | SYNTAX Counter32
526 | MAX-ACCESS read-only
527 | STATUS current
528 | DESCRIPTION
529 | "Truncated packets dropped for this cpu."
530 | ::= { iptNetflowCpuEntry 9 }
531 |
532 | cpuErrFrag OBJECT-TYPE
533 | SYNTAX Counter32
534 | MAX-ACCESS read-only
535 | STATUS current
536 | DESCRIPTION
537 | "Fragmented packets dropped for this cpu."
538 | ::= { iptNetflowCpuEntry 10 }
539 |
540 | cpuErrAlloc OBJECT-TYPE
541 | SYNTAX Counter32
542 | MAX-ACCESS read-only
543 | STATUS current
544 | DESCRIPTION
545 | "Packets dropped due to memory allocation errors."
546 | ::= { iptNetflowCpuEntry 11 }
547 |
548 | cpuErrMaxflows OBJECT-TYPE
549 | SYNTAX Counter32
550 | MAX-ACCESS read-only
551 | STATUS current
552 | DESCRIPTION
553 | "Packets dropped due to maxflows limit being reached."
554 | ::= { iptNetflowCpuEntry 12 }
555 |
556 | -- Per Socket statistics --
557 |
558 | iptNetflowSockTable OBJECT-TYPE
559 | SYNTAX SEQUENCE OF IptNetflowSockEntry
560 | MAX-ACCESS not-accessible
561 | STATUS current
562 | DESCRIPTION
563 | "Per socket statistics."
564 | ::= { iptNetflowStatistics 3 }
565 |
566 | iptNetflowSockEntry OBJECT-TYPE
567 | SYNTAX IptNetflowSockEntry
568 | MAX-ACCESS not-accessible
569 | STATUS current
570 | DESCRIPTION
571 | "Defines an entry in the iptNetflowSockTable."
572 | INDEX { sockIndex }
573 | ::= { iptNetflowSockTable 1 }
574 |
575 | IptNetflowSockEntry ::=
576 | SEQUENCE {
577 | sockIndex INTEGER,
578 | sockDestination DisplayString,
579 | sockActive INTEGER,
580 | sockErrConnect Counter32,
581 | sockErrFull Counter32,
582 | sockErrCberr Counter32,
583 | sockErrOther Counter32,
584 | sockSndbuf Gauge32,
585 | sockSndbufFill Gauge32,
586 | sockSndbufPeak Gauge32
587 | }
588 |
589 | sockIndex OBJECT-TYPE
590 | SYNTAX Integer32 (0..4096)
591 | MAX-ACCESS not-accessible
592 | STATUS current
593 | DESCRIPTION
594 | "Exporting socket index."
595 | ::= { iptNetflowSockEntry 1 }
596 |
597 | sockDestination OBJECT-TYPE
598 | SYNTAX DisplayString
599 | MAX-ACCESS read-only
600 | STATUS current
601 | DESCRIPTION
602 | "Exporting connection destination of this socket."
603 | ::= { iptNetflowSockEntry 2 }
604 |
605 | sockActive OBJECT-TYPE
606 | SYNTAX INTEGER {
607 | inactive(0),
608 | active(1)
609 | }
610 | MAX-ACCESS read-only
611 | STATUS current
612 | DESCRIPTION
613 | "Connection state of this socket."
614 | ::= { iptNetflowSockEntry 3 }
615 |
616 | sockErrConnect OBJECT-TYPE
617 | SYNTAX Counter32
618 | MAX-ACCESS read-only
619 | STATUS current
620 | DESCRIPTION
621 | "Connections attempt count. High value usually mean
622 | that network is not set up properly, or module is loaded
623 | before network is up, in this case it is not dangerous
624 | and should be ignored."
625 | ::= { iptNetflowSockEntry 4 }
626 |
627 | sockErrFull OBJECT-TYPE
628 | SYNTAX Counter32
629 | MAX-ACCESS read-only
630 | STATUS current
631 | DESCRIPTION
632 | "Socket full errors on this socket. Usually mean sndbuf
633 | value is too small."
634 | ::= { iptNetflowSockEntry 5 }
635 |
636 | sockErrCberr OBJECT-TYPE
637 | SYNTAX Counter32
638 | MAX-ACCESS read-only
639 | STATUS current
640 | DESCRIPTION
641 | "Asynchronous callback errors on this socket. Usually mean
642 | that there is 'connection refused' errors on UDP socket
643 | reported via ICMP messages."
644 | ::= { iptNetflowSockEntry 6 }
645 |
646 | sockErrOther OBJECT-TYPE
647 | SYNTAX Counter32
648 | MAX-ACCESS read-only
649 | STATUS current
650 | DESCRIPTION
651 | "All other possible errors on this socket."
652 | ::= { iptNetflowSockEntry 7 }
653 |
654 | sockSndbuf OBJECT-TYPE
655 | SYNTAX Gauge32
656 | UNITS "bytes"
657 | MAX-ACCESS read-only
658 | STATUS current
659 | DESCRIPTION
660 | "Sndbuf value for this socket. Higher value allows accommodate
661 | (exporting) traffic bursts."
662 | ::= { iptNetflowSockEntry 8 }
663 |
664 | sockSndbufFill OBJECT-TYPE
665 | SYNTAX Gauge32
666 | UNITS "bytes"
667 | MAX-ACCESS read-only
668 | STATUS current
669 | DESCRIPTION
670 | "Amount of data currently in socket buffers. When this value
671 | will reach size sndbuf, packet loss will occur."
672 | ::= { iptNetflowSockEntry 9 }
673 |
674 | sockSndbufPeak OBJECT-TYPE
675 | SYNTAX Gauge32
676 | UNITS "bytes"
677 | MAX-ACCESS read-only
678 | STATUS current
679 | DESCRIPTION
680 | "Historical peak amount of data in socket buffers. Useful to
681 | evaluate sndbuf size, because sockSndbufFill is transient."
682 | ::= { iptNetflowSockEntry 10 }
683 |
684 | -- Conformance Information --
685 |
686 | iptNetflowCompliances OBJECT IDENTIFIER ::= { iptNetflowConformance 1 }
687 | iptNetflowGroups OBJECT IDENTIFIER ::= { iptNetflowConformance 2 }
688 |
689 | iptNetflowCompliance MODULE-COMPLIANCE
690 | STATUS current
691 | DESCRIPTION "iptNetflowCompliance"
692 | MODULE
693 | MANDATORY-GROUPS {
694 | iptNetflowModuleGroup,
695 | iptNetflowSysctlGroup,
696 | iptNetflowTotalsGroup,
697 | iptNetflowCpuGroup,
698 | iptNetflowSockGroup
699 | }
700 | ::= { iptNetflowCompliances 1 }
701 |
702 | iptNetflowModuleGroup OBJECT-GROUP
703 | OBJECTS {
704 | name,
705 | version,
706 | srcversion,
707 | loadTime,
708 | refcnt
709 | }
710 | STATUS current
711 | DESCRIPTION "Modinfo."
712 | ::= { iptNetflowGroups 1 }
713 |
714 | iptNetflowSysctlGroup OBJECT-GROUP
715 | OBJECTS {
716 | hashsize,
717 | maxflows,
718 | protocol,
719 | active-timeout,
720 | inactive-timeout,
721 | sndbuf,
722 | destination,
723 | aggregation,
724 | sampler,
725 | natevents,
726 | promisc,
727 | snmp-rules,
728 | scan-min
729 | }
730 | STATUS current
731 | DESCRIPTION "Read-write objects accessed via sysctl"
732 | ::= { iptNetflowGroups 2 }
733 |
734 | iptNetflowTotalsGroup OBJECT-GROUP
735 | OBJECTS {
736 | inBitRate,
737 | inPacketRate,
738 | inFlows,
739 | inPackets,
740 | inBytes,
741 | hashMetric,
742 | hashMemory,
743 | hashFlows,
744 | hashPackets,
745 | hashBytes,
746 | dropPackets,
747 | dropBytes,
748 | outByteRate,
749 | outFlows,
750 | outPackets,
751 | outBytes,
752 | lostFlows,
753 | lostPackets,
754 | lostBytes,
755 | errTotal,
756 | sndbufPeak
757 | }
758 | STATUS current
759 | DESCRIPTION "Statistics totals."
760 | ::= { iptNetflowGroups 3 }
761 |
762 | iptNetflowCpuGroup OBJECT-GROUP
763 | OBJECTS {
764 | cpuIndex,
765 | cpuInPacketRate,
766 | cpuInFlows,
767 | cpuInPackets,
768 | cpuInBytes,
769 | cpuHashMetric,
770 | cpuDropPackets,
771 | cpuDropBytes,
772 | cpuErrTrunc,
773 | cpuErrFrag,
774 | cpuErrAlloc,
775 | cpuErrMaxflows
776 | }
777 | STATUS current
778 | DESCRIPTION "Per CPU statistics."
779 | ::= { iptNetflowGroups 4 }
780 |
781 | iptNetflowSockGroup OBJECT-GROUP
782 | OBJECTS {
783 | sockDestination,
784 | sockActive,
785 | sockErrConnect,
786 | sockErrFull,
787 | sockErrCberr,
788 | sockErrOther,
789 | sockSndbuf,
790 | sockSndbufFill,
791 | sockSndbufPeak
792 | }
793 | STATUS current
794 | DESCRIPTION "Per socket statistics."
795 | ::= { iptNetflowGroups 5 }
796 |
797 | END
798 |
--------------------------------------------------------------------------------
/Makefile.in:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: GPL-2.0-only
2 | #
3 | # Edit Makefile.in and run ./configure
4 |
5 | KVERSION = @KVERSION@
6 | KDIR = @KDIR@
7 | KINSTDIR = $(shell dirname @KDIR@)
8 | KOPTS = @KOPTS@
9 | IPTABLES_CFLAGS = @IPTABLES_CFLAGS@
10 | IPTABLES_MODULES = @IPTABLES_MODULES@
11 | DEPMOD = /sbin/depmod -a
12 | CARGS = @CARGS@
13 | SNMPTGSO = /usr/lib/snmp/dlmod/snmp_NETFLOW.so
14 | SNMPCONF = /etc/snmp/snmpd.conf
15 | SNMPLINE = dlmod netflow $(SNMPTGSO)
16 | CC = gcc
17 |
18 | # https://www.kernel.org/doc/Documentation/kbuild/modules.txt
19 | # https://www.kernel.org/doc/Documentation/kbuild/makefiles.txt
20 | obj-m = ipt_NETFLOW.o
21 | ccflags-y = @KOPTS@
22 |
23 | all: ipt_NETFLOW.ko libipt_NETFLOW.so libip6t_NETFLOW.so @SNMPTARGET@
24 |
25 | ipt_NETFLOW.ko: version.h ipt_NETFLOW.c ipt_NETFLOW.h compat_def.h compat.h Makefile
26 | @echo Compiling $(shell ./version.sh) for kernel $(KVERSION)
27 | make -C $(KDIR) M=$(CURDIR) modules
28 | @touch $@
29 | compat_def.h: gen_compat_def
30 | ./gen_compat_def > $@-
31 | mv $@- $@
32 | sparse: | version.h ipt_NETFLOW.c ipt_NETFLOW.h compat.h Makefile
33 | @rm -f ipt_NETFLOW.ko ipt_NETFLOW.o
34 | @echo Compiling for kernel $(KVERSION)
35 | make -C $(KDIR) M=$(CURDIR) modules C=1
36 | @touch ipt_NETFLOW.ko
37 | coverity:
38 | coverity-submit -v
39 |
40 | minstall: | ipt_NETFLOW.ko
41 | @echo " *"
42 | make -C $(KDIR) M=$(CURDIR) modules_install INSTALL_MOD_PATH=$(DESTDIR)
43 | $(DEPMOD)
44 | mclean:
45 | make -C $(KDIR) M=$(CURDIR) clean
46 | lclean:
47 | -rm -f *.so *_sh.o
48 | clean: mclean lclean
49 | -rm -f *.so *.o modules.order version.h compat_def.h
50 |
51 | snmp_NETFLOW.so: snmp_NETFLOW.c
52 | $(CC) -fPIC -shared -o $@ $< -lnetsnmp
53 |
54 | sinstall: | snmp_NETFLOW.so IPT-NETFLOW-MIB.my
55 | @echo " *"
56 | install -D IPT-NETFLOW-MIB.my $(DESTDIR)/usr/share/snmp/mibs/IPT-NETFLOW-MIB.my
57 | install -D snmp_NETFLOW.so $(DESTDIR)$(SNMPTGSO)
58 | @if ! grep -E -qs "^ *$(SNMPLINE)" $(SNMPCONF); then \
59 | echo " *"; \
60 | echo " * Add this line to $(SNMPCONF) to enable IPT-NETFLOW-MIB:"; \
61 | echo " *"; \
62 | echo " * $(SNMPLINE)"; \
63 | echo " *"; \
64 | fi
65 | @if killall -0 snmpd >/dev/null 2>&1; then \
66 | echo " * (snmpd needs restart for changes to take effect.)"; \
67 | else \
68 | echo " * (snmpd is not started.)"; \
69 | fi
70 |
71 | %_sh.o: libipt_NETFLOW.c
72 | $(CC) $(CFLAGS) -O2 -Wall -Wunused $(IPTABLES_CFLAGS) -fPIC -o $@ -c libipt_NETFLOW.c
73 |
74 | %.so: %_sh.o
75 | $(CC) -shared -o $@ $<
76 |
77 | version.h: ipt_NETFLOW.c ipt_NETFLOW.h compat.h Makefile
78 | @./version.sh --define > version.h
79 |
80 | linstall: | libipt_NETFLOW.so libip6t_NETFLOW.so
81 | @echo " *"
82 | install -D libipt_NETFLOW.so $(DESTDIR)$(IPTABLES_MODULES)/libipt_NETFLOW.so
83 | install -D libip6t_NETFLOW.so $(DESTDIR)$(IPTABLES_MODULES)/libip6t_NETFLOW.so
84 |
85 | dinstall:
86 | @echo " *"
87 | @./install-dkms.sh --install
88 |
89 | install: minstall linstall @DKMSINSTALL@ @SNMPINSTALL@
90 |
91 | uninstall:
92 | -rm -f $(DESTDIR)$(IPTABLES_MODULES)/libipt_NETFLOW.so
93 | -rm -f $(DESTDIR)$(IPTABLES_MODULES)/libip6t_NETFLOW.so
94 | -rm -f $(DESTDIR)/usr/share/snmp/mibs/IPT-NETFLOW-MIB.my
95 | -rm -f $(DESTDIR)$(SNMPTGSO)
96 | @if grep -E -qs "^ *$(SNMPLINE)" $(SNMPCONF); then \
97 | echo " *"; \
98 | echo " * Remove this line from $(SNMPCONF):"; \
99 | echo " *"; \
100 | echo " * "`grep -E "^ *$(SNMPLINE)" $(SNMPCONF)`; \
101 | echo " *"; \
102 | fi
103 | @if [ "@DKMSINSTALL@" = dinstall ]; then ./install-dkms.sh --uninstall; fi
104 | -rm -f $(DESTDIR)$(KINSTDIR)/extra/ipt_NETFLOW.ko
105 |
106 | Makefile: Makefile.in configure
107 | ./configure --make ${CARGS}
108 |
109 | load: all
110 | -insmod ipt_NETFLOW.ko active_timeout=5 protocol=9
111 | -iptables -I OUTPUT -j NETFLOW
112 | -iptables -I INPUT -j NETFLOW
113 | -ip6tables -I OUTPUT -j NETFLOW
114 | -ip6tables -I INPUT -j NETFLOW
115 |
116 | unload:
117 | -iptables -D OUTPUT -j NETFLOW
118 | -iptables -D INPUT -j NETFLOW
119 | -ip6tables -D OUTPUT -j NETFLOW
120 | -ip6tables -D INPUT -j NETFLOW
121 | -rmmod ipt_NETFLOW.ko
122 |
123 | reload: unload load
124 |
125 | ChangeLog:
126 | gitlog-to-changelog > ChangeLog
127 | .PHONY: ChangeLog
128 |
129 |
--------------------------------------------------------------------------------
/NEWS:
--------------------------------------------------------------------------------
1 | ipt-netflow NEWS
2 | ================
3 |
4 | 2.6 (2021-05-15)
5 | * Minor feature and maintenance release.
6 | - Compilation compatibility with kernel 5.12.
7 | - Add ipVersion (60) support.
8 | - Optionally seed initial template ID from PRNG.
9 | - Compilation improvements.
10 |
11 | 2.5.1 (2020-08-12)
12 | * Maintenance release.
13 | - Fix soft lockup on kernels with xtables targets used via nftables.
14 | - Fix compilation with Linux 5.8 and with CentOS 8.
15 |
16 | 2.5 (2020-04-24)
17 | * Minor maintenance release.
18 | - Compilation compatibility with kernels up to 5.6.
19 | - Performance improvements by Vadim Fedorenko.
20 | - Small code fixes and typo corrections.
21 |
22 | 2.4 (2019-06-23)
23 | * Minor maintenance release.
24 | - Compilation compatibility with kernels up to 5.2.
25 | - README, CREDITS update.
26 |
27 | 2.3 (2018-03-19)
28 |
29 | * Minor feature and Maintenance release.
30 | - Compatibility with latest kernels.
31 | - Allow to set engine_id (observationDomainId).
32 | - Cross-compilation support.
33 | - OpenWRT support.
34 | - Allow binding destination socket to IP and interface.
35 |
36 | 2.2 (2016-02-21)
37 |
38 | * Minor feature and Maintenance release.
39 | - Decapsulate MPLS in promisc mode and MPLS-aware NetFlow feature.
40 | - Export flowEndReason for IPFIX.
41 | - Promics mode improvements.
42 | - Allow export destination to be IPv6 address.
43 | - Move flows list from debugfs to proc.
44 | - Compilation compatibility with latest kernels.
45 | - Code is Coverity scanned.
46 |
47 | 2.1 (2014-02-08)
48 |
49 | * Options Templates support (V9 and IPFIX). Which let to implement:
50 | - Flow Sampling (random, deterministic, and hash modes) for all types
51 | of NetFlow protocols (V5, V9, IPFIX).
52 | - Export Statistics (metering, exporting, sampling) and Configuration.
53 | - Export Interface list (ifName, ifDescr).
54 | * Promisc hack (no need to patch kernel anymore).
55 | * SNMP monitoring interface and agent (via net-snmp dlmod).
56 | * More compilation compatibility with recent kernels, grsecurity kernels,
57 | Gentoo, Debian, Centos. DKMS install support.
58 | * Minor features: IPSec flows, Direction Element. Removed support for
59 | CONNMARK. Bug fixes and improvements.
60 | * irqtop tool (ruby).
61 |
62 | 2.0.1 (2014-09-04)
63 |
64 | * Minor fixes for 2.0 release.
65 |
66 | 2.0 (2014-08-07)
67 |
68 | * This is major release with a lot of new features and improvements, such
69 | as:
70 | - Support of NetFlow v9 and IPFIX.
71 | - IPv6 support.
72 | - NAT translation events (NEL).
73 | - Additional options is SNMP-index translation rules, Ethernet Type,
74 | VLAN, and MAC addresses exporting.
75 | - Performance improvements (tested to work well on 10Gbit load).
76 | - Stability improvements and bug fixes.
77 |
78 | 1.8 (2012-07-02)
79 |
80 | * This is minor bug fix release with small improvements.
81 |
82 | 1.7.1 (2011-04-04)
83 |
84 | * This is minor release with improved compilation compatibility and small
85 | improvements.
86 |
87 | 1.7 (2011-01-30)
88 |
89 | * This version have improved compilation compatibility with latest Linux
90 | kernels (2.6.36.3 and 2.6.27) and bunch of small improvements.
91 |
92 | * Since version 1.7 ipt-netflow's repository moved to Git SCM. Use of CVS
93 | repository is deprecated.
94 |
95 | 1.5.1 (2009-03-14)
96 |
97 | * This version have improved compliance to NetFlow standard and
98 | compatibility with iptables/xtables 1.4.x. Added options to configure
99 | script for manual customization.
100 |
101 | 1.4 (2008-12-23)
102 |
103 | * This version have restored compatibility with popular kernel 2.6.18,
104 | added configure script, statistics improvements, some fixes for 64-bit
105 | platforms, and minor performance tune up.
106 |
107 | 1.2 (2008-11-15)
108 |
109 | * This version have stability enhancements, documentation improvements, IP
110 | frag support, better statistics.
111 |
112 | 1.1 (2008-08-06)
113 |
114 | * This version updated compatibility with latest (2.6.26) Linux kernel, have
115 | more support for promisc patch, and minor fixes.
116 |
117 | 1.0 (2008-07-12)
118 |
119 | * First release tested in production environment.
120 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | ipt_NETFLOW linux 2.6.x-5.x kernel module by -- 2008-2021.
2 |
3 | High performance NetFlow v5, v9, IPFIX flow data export module for Linux
4 | kernel. Created to be useful for linux routers in high-throughput networks.
5 | It should be used as iptables target.
6 |
7 |
8 | =========================
9 | = Detailed Feature List =
10 | =========================
11 |
12 | * High performance and scalability. For highest performance module could be
13 | run without conntrack being enabled in kernel. Reported to be able to
14 | handle 10Gbit traffic with more than 1500000 pps with negligible server
15 | load (on S5500BC).
16 |
17 | * NetFlow v5, v9, and IPFIX are fully supported.
18 |
19 | Support of v9/IPFIX is adding flexibility to exporting of flow data
20 | plus greater visibility of traffic, letting export many additional fields
21 | besides what was possible in v5 era. Such as
22 |
23 | * IPv6 option headers, IPv4 options, TCP options, ethernet type, dot1q
24 | service and customer VLAN ids, MAC addresses, and
25 |
26 | * Full IPv6 support,
27 |
28 | * NAT translations events (from conntrack) using NetFlow Event Logging (NEL).
29 | This is standardized way for v9/IPFIXr, but module export such events even
30 | for v5 collectors via specially crafted pseudo-records.
31 |
32 | * Deterministic (systematic count-based), random and hash Flow Sampling.
33 | With appropriate differences in support of v5, v9, and IPFIX.
34 |
35 | * SNMP agent (for net-snmp) for remote management and monitoring.
36 |
37 | * Options Templates (v9/IPFIX) let export useful statistical,
38 | configurational, and informational records to collector.
39 | Such as metering, exporting, sampling stat and reliability stat, sampling
40 | configuration, network devices ifName, ifDescr list.
41 |
42 | * Tested to compile and work out of the box on Centos 6, 7, Debian and
43 | * Ubuntu. Many vanilla Linux kernels since 2.6.18 up to the latest (as of
44 | * writing is 3.19) are supported and tested.
45 |
46 | * Module load time and run-time (via sysctl) configuration.
47 |
48 | * Flexibility in enabling features via ./configure script. This will let you
49 | disable features you don't need, which increase compatibility with custom
50 | kernels and performance.
51 |
52 | * SNMP-index translation rules, let convert meaningless and unstable
53 | interface indexes (ifIndex) to more meaningful numbering scheme.
54 |
55 | * Easy support for catching mirrored traffic with promisc option. Which is
56 | also supporting optional MPLS decapsulation and MPLS-aware NetFlow.
57 |
58 |
59 | ============================
60 | = OBTAINING LATEST VERSION =
61 | ============================
62 |
63 | $ git clone git://github.com/aabc/ipt-netflow.git ipt-netflow
64 | $ cd ipt-netflow
65 |
66 |
67 | ================
68 | = INSTALLATION =
69 | ================
70 |
71 | Five easy steps.
72 |
73 | ** 1. Prepare Kernel source
74 |
75 | If you have package system install kernel-devel package, otherwise install
76 | raw kernel source from http://kernel.org matching _exactly_ version of your
77 | installed kernel.
78 |
79 | a) What to do for Centos:
80 |
81 | ~# yum install kernel-devel
82 |
83 | b) What to do for Debian and Ubuntu:
84 |
85 | ~# apt-get install module-assistant
86 | ~# m-a prepare
87 |
88 | c) Otherwise, if you downloaded raw kernel sources don't forget to create
89 | .config by copying it from your distribution's kernel. Its copy could reside
90 | in /boot or sometimes in /proc, examples:
91 |
92 | kernel-src-dir/# cp /boot/config-`uname -r` .config
93 | or
94 | kernel-src-dir/# zcat /proc/config.gz > .config
95 |
96 | Assuming you unpacked kernel source into `kernel-src-dir/' directory.
97 | Then run:
98 |
99 | kernel-src-dir/# make oldconfig
100 |
101 | After that you'll need to prepare kernel for modules build:
102 |
103 | kernel-src-dir/# make prepare modules_prepare
104 |
105 | Note: Don't try to `make prepare' in Centos kernel-devel package directory
106 | (which is usually something like /usr/src/kernels/2.6.32-431.el6.x86_64)
107 | as this is wrong and meaningless.
108 |
109 | ** 2. Prepare Iptables
110 |
111 | Before this step it also would be useful to install pkg-config if don't
112 | already have.
113 |
114 | If you have package system just install iptables-devel (or on Debian, Ubuntu
115 | and derivatives libxtables-dev if available, otherwise iptables-dev)
116 | package, otherwise install iptables source matching version of your
117 | installation from ftp://ftp.netfilter.org/pub/iptables/
118 |
119 | a) What to do for Centos:
120 |
121 | # yum install iptables-devel
122 |
123 | b) What to do for Debian or Ubuntu:
124 |
125 | # apt-get install iptables-dev pkg-config
126 |
127 | c) Otherwise, for raw iptables source build it and make install.
128 |
129 | ** 3. Prepare net-snmp (optional)
130 |
131 | In case you want to manage or monitor module performance via SNMP you
132 | may install net-snmp. If you want to skip this step run configure
133 | with --disable-snmp-agent option.
134 |
135 | a) For Centos:
136 |
137 | # yum install net-snmp net-snmp-devel
138 |
139 | b) For Debian or Ubuntu:
140 |
141 | # apt-get install snmpd libsnmp-dev
142 |
143 | c) Otherwise install net-snmp from www.net-snmp.org
144 |
145 | ** 4. Now, to actually build the module run:
146 |
147 | ~/ipt-netflow# ./configure
148 | ~/ipt-netflow# make all install
149 | ~/ipt-netflow# depmod
150 |
151 | This will install kernel module and iptables specific library.
152 |
153 | Troubleshooting:
154 |
155 | a) Sometimes you will want to add CC=gcc-3 to make command.
156 | Example: make CC=gcc-3.3
157 |
158 | b) Compile module with actual kernel source compiled.
159 | I.e. first compile kernel and boot into it, and then compile module.
160 | If you are using kernel-devel package check that its version matches
161 | your kernel package.
162 |
163 | c) If you have sources in non-standard places or configure isn't able to
164 | find something run ./configure --help to see how to specify paths manually.
165 |
166 | d) To run irqtop on Debian 8 you may need to install:
167 |
168 | # apt-get install ruby ruby-dev ncurses-dev
169 | # gem install curses
170 |
171 | z) If all fails create ticket at
172 | https://github.com/aabc/ipt-netflow/issues
173 |
174 | ** 5. After this point you should be able to load module and
175 | use -j NETFLOW target in your iptables. See next section.
176 |
177 |
178 | =====================
179 | = Configure Options =
180 | =====================
181 |
182 | Configure script allows to enable or disable optional features:
183 |
184 | --enable-natevents
185 | enables natevents (NEL) support, (this and option will require
186 | conntrack support to be enabled into kernel and conntack
187 | module (nf_conntrack) loaded before ipt_NETFLOW. Usually this is
188 | done automatically because of `depmod', but if you don't do `make
189 | install' you'll need to load nf_conntrack manually.
190 | Read below for explanation of natevents.
191 |
192 | --enable-sampler
193 | enables flow sampler. Read below for explanation of its configuration
194 | option.
195 |
196 | --enable-sampler=hash
197 | additionally enables 'hash' sampler.
198 |
199 | --disable-snmp-agent
200 | disables building net-snmp agent module, which is enabled by default.
201 |
202 | --enable-snmp-rules
203 | enables SNMP-index conversion rules. Read below for explanation
204 | of snmp-rules.
205 |
206 | --enable-macaddress
207 | enables exporting of src and dst MAC addresses for every flow
208 | in v9/IPFIX. Difference in any of MAC address will be accounted
209 | as different flow. I.e. MAC addresses will be part of flow key.
210 |
211 | --enable-vlan
212 | enables exporting of dot1q VLAN Ids and Priorities for every flow
213 | in v9/IPFIX. It supports outer and second dot1q tags if present.
214 |
215 | Any of two previous options will enable exporting of Ethernet Packet
216 | Type, ethernetType(256).
217 |
218 | --enable-direction
219 | enables exporting of flowDirection(61) Element for v9/IPFIX.
220 |
221 | Packets captured in PREROUTING and INPUT chains will be accounted as
222 | ingress flows(0), in OUTPUT and POSTROUTING as egress flows(1), and
223 | in FORWARD will have flowDirection set to undefined value 255.
224 |
225 | --enable-aggregation
226 | enables aggregation rules. Read below for explanation of aggregation.
227 |
228 | --disable-dkms
229 | disable creating dkms.conf and auto-install module into DKMS tree.
230 |
231 | --disable-dkms-install
232 | only disable auto-install into DKMS, but still create dkms.conf, in
233 | case you will want to install it manually.
234 |
235 | --enable-physdev
236 | Export ingressPhysicalInterface(252) and egressPhysicalInterface(253)
237 | (relevant for bridges) in V9 and IPFIX. If your collector does not
238 | support these Elements but you still need physdevs then use
239 | --enable-physdev-override, in that case physdevs will override normal
240 | interface numbers ingressInterface(10) and egressInterface(14).
241 |
242 | --enable-promisc
243 | Enables capturing of promiscuous packets into raw/PREROUTING chain.
244 | See README.promisc Solution 1 for usage details and example.
245 |
246 | --promisc-mpls
247 | Enables MPLS label stack decapsulation for promiscuous packets. (For
248 | IPv4 and IPv6 packets only). This also enables MPLS-aware NetFlow (v9
249 | and IPFIX), you may wish to specify with --promisc-mpls=n how much MPLS
250 | labels you want to be recorded and exported (default is 3, maximum is
251 | 10, set to 0 to not report anything).
252 |
253 |
254 | ===========
255 | = RUNNING =
256 | ===========
257 |
258 | 1. You can load module directly by insmod like this:
259 |
260 | # insmod ipt_NETFLOW.ko destination=127.0.0.1:2055 debug=1
261 |
262 | Or if properly installed (make install; depmod) by this:
263 |
264 | # modprobe ipt_NETFLOW destination=127.0.0.1:2055
265 |
266 | See, you may add options in insmod/modprobe command line, or add
267 | them in /etc/modprobe.conf or /etc/modprobe.d/ipt_NETFLOW.conf
268 | like thus:
269 |
270 | options ipt_NETFLOW destination=127.0.0.1:2055 protocol=9 natevents=1
271 |
272 | 2. Statistics is in /proc/net/stat/ipt_netflow
273 | Machine readable statistics is in /proc/net/stat/ipt_netflow_snmp
274 | To view boring slab statistics: grep ipt_netflow /proc/slabinfo
275 | Dump of all flows is in /proc/net/stat/ipt_netflow_flows
276 |
277 | 3. You can view parameters and control them via sysctl, example:
278 |
279 | # sysctl net.netflow
280 | # sysctl net.netflow.hashsize=32768
281 |
282 | Note: For after-reboot configuration I recommend to store module parameters
283 | in modprobe configs instead of storing them in /etc/sysctl.conf, as it's
284 | less clear when init process will apply sysctl.conf, before of after
285 | module's load.
286 |
287 | 4. Example of directing all IPv4 traffic into the module:
288 |
289 | # iptables -I FORWARD -j NETFLOW
290 | # iptables -I INPUT -j NETFLOW
291 | # iptables -I OUTPUT -j NETFLOW
292 |
293 | Note: It is preferable (because easier to understand) to _insert_
294 | NETFLOW target at the top of the chain, otherwise not all traffic may
295 | reach NETFLOW if your iptables configuration is complicated and some
296 | other rule inadvertently consume the traffic (dropping or acepting before
297 | NETFLOW is reached). It's always good to test your configuration.
298 | Use iptables -L -nvx to check pkts/bytes counters on the rules.
299 |
300 | 5. If you want to account IPv6 traffic you should use protocol 9 or 10.
301 | Example of directing all IPv6 traffic into the module:
302 |
303 | # sysctl net.netflow.protocol=10
304 | # ip6tables -I FORWARD -j NETFLOW
305 | # ip6tables -I INPUT -j NETFLOW
306 | # ip6tables -I OUTPUT -j NETFLOW
307 |
308 | Note: First enable right version of protocol and after that add ip6tables
309 | rules, otherwise you will get errors in dmesg.
310 |
311 | 6. If you want to account NAT events (NEL):
312 |
313 | # sysctl net.netflow.natevents=1
314 |
315 | Note that natevents feature is completely independent from traffic accounting
316 | (it's using so called conntrack events), thus you don't need to set or change
317 | any iptables rules to use that. You may need to enable kernel config option
318 | CONFIG_NF_CONNTRACK_EVENTS though (if it isn't already enabled).
319 | For details on how they are exported for different protocol versions see
320 | below.
321 |
322 | 7. For SNMP support you will need to add this command into snmpd.conf to
323 | enable IPT-NETFLOW-MIB in SNMP agent:
324 |
325 | dlmod netflow /usr/lib/snmp/dlmod/snmp_NETFLOW.so
326 |
327 | Restart snmpd for changes to take effect. Don't forget to properly configure
328 | access control. Example simplest configuration may looks like (note that this
329 | is whole /etc/snmp/snmpd.conf):
330 |
331 | rocommunity public 127.0.0.1
332 | dlmod netflow /usr/lib/snmp/dlmod/snmp_NETFLOW.so
333 |
334 | Note, that this config will also allow _full_ read-only access to the whole
335 | linux MIB. To install IPT-NETFLOW-MIB locally, copy file IPT-NETFLOW-MIB.my
336 | into ~/.snmp/mibs/
337 |
338 | * Detailed example of SNMP configuration is there:
339 | * https://github.com/aabc/ipt-netflow/wiki/Configuring-SNMP-access
340 |
341 | To check that MIB is installed well you may issue:
342 |
343 | $ snmptranslate -m IPT-NETFLOW-MIB -IR -Tp iptNetflowMIB
344 |
345 | This should output IPT-NETFLOW-MIB in tree form.
346 |
347 | To check that snmp agent is working well issue:
348 |
349 | $ snmpwalk -v 1 -c public 127.0.0.1 -m IPT-NETFLOW-MIB iptNetflowMIB
350 |
351 | Should output full MIB. If MIB is not installed try:
352 |
353 | $ snmpget -v 1 -c public 127.0.0.1 .1.3.6.1.4.1.37476.9000.10.1.1.1.1.0
354 |
355 | Which should output STRING: "ipt_NETFLOW".
356 |
357 | MIB provides access to very similar statistics that you have in
358 | /proc/net/stat/ipt_netflow, you can read description of objects in
359 | text file IPT-NETFLOW-MIB.my
360 |
361 | If you want to access to SNMP stat in machine readable form for your
362 | scripts there is file /proc/net/stat/ipt_netflow_snmp
363 |
364 | Note: Using of SNMP v2c or v3 is mandatory for most tables, because
365 | this MIB uses 64-bit counters (Counter64) which is not supported in old
366 | SNMP v1. You should understand that 32-bit counter will wrap on 10Gbit
367 | traffic in just 3.4 seconds! So, always pass option `-v2c' or `-v3'
368 | to net-snmp utils. Or, for example, configure option `defVersion 2c'
369 | in ~/.snmp/snmp.conf You can also have `defCommunity public' ov v3
370 | auth parameters (defSecurityName, defSecurityLevel, defPassphrase)
371 | set there (man snmp.conf).
372 |
373 | Examples for dumping typical IPT-NETFLOW-MIB objects:
374 |
375 | - Module info (similar to modinfo, SNMPv1 is ok for following two objects):
376 |
377 | $ snmpwalk -v 1 -c public 127.0.0.1 -m IPT-NETFLOW-MIB iptNetflowModule
378 |
379 | - Read-write sysctl-like parameters (yes, they are writable via snmpset, you
380 | may need to configure write access to snmpd, though):
381 |
382 | $ snmpwalk -v 1 -c public 127.0.0.1 -m IPT-NETFLOW-MIB iptNetflowSysctl
383 |
384 | - Global performance stat of the module (note -v2c, because rest of the
385 | objects require SNMP v2c or SNMP v3):
386 |
387 | $ snmpwalk -v2c -c public 127.0.0.1 -m IPT-NETFLOW-MIB iptNetflowTotals
388 |
389 | - Per-CPU (metering) and per-socket (exporting) statistics in table format:
390 |
391 | $ snmptable -v2c -c public 127.0.0.1 -m IPT-NETFLOW-MIB iptNetflowCpuTable
392 | $ snmptable -v2c -c public 127.0.0.1 -m IPT-NETFLOW-MIB iptNetflowSockTable
393 |
394 |
395 | ===========
396 | = OPTIONS =
397 | ===========
398 |
399 | Options can be passed as parameters to module or changed dynamically
400 | via sysctl net.netflow or IPT-NETFLOW-MIB::iptNetflowSysctl
401 |
402 | protocol=5
403 | - what version of NetFlow protocol to use. Default is 5.
404 | You can choose from 5, 9, or 10 (where 10 is IPFIX). If you plan
405 | to account IPv6 traffic you should use protocol 9 or 10 (IPFIX),
406 | because NetFlow v5 isn't compatible with IPv6.
407 |
408 | destination=127.0.0.1:2055
409 | - where to export netflow, to this ip address. Port is optional, default
410 | is 2055. You will see this connection in netstat like this:
411 |
412 | udp 0 0 127.0.0.1:32772 127.0.0.1:2055 ESTABLISHED
413 |
414 | destination=[2001:db8::1]:2055
415 | - export target using IPv6 address. Brackets are optional, but otherwise
416 | you should delimit port with 'p' or '#' character.
417 |
418 | destination=127.0.0.1:2055,192.0.0.1:2055
419 | - mirror flows to two (can be more) addresses, separate addresses
420 | with comma.
421 |
422 | destination=127.0.0.1:2055@127.0.0.2
423 | - bind socket to address (127.0.0.2).
424 |
425 | destination=127.0.0.1:2055%eth0
426 | - bind socket to interface (eth0). May be useful for multi-homed boxes.
427 |
428 | sampler=deterministic:123
429 | sampler=random:123
430 | sampler=hash:123
431 | - enables Flow Sampling. To disable set to the empty value or to `0'.
432 | Note, that this is flow sampling (as of RFC 7014), not packet
433 | sampling (PSAMP).
434 |
435 | There is three sampling modes:
436 |
437 | deterministic: select each N-th observed flow; in IPFIX this mode
438 | is called Systematic count-based Sampling;
439 | random: select randomly one out of N flows.
440 | hash: select hash-randomly one out of N flows.
441 |
442 | Number after colon is population size N, with valid values 2-16383.
443 | (This 16383 limit is for compatibility with NetFlow v5.)
444 | Using 'deterministic' and 'random' sampling will not reduce resource
445 | usage caused by the module, because flows are sampled late in exporting
446 | process. This will reduces amount of flows which go to the collector,
447 | thus, reducing load on the collector.
448 | On the other hand, using 'hash' sampling will reduce CPU and memory
449 | load caused by the module, because flows are discarded early in the
450 | processing chain. They are discarded almost like in random sampler,
451 | except that pseudo-random value is depend on the Flow Key hash for each
452 | packet.
453 | All required NetFlow/IPFIX information to signal use of sampling is
454 | also sent to the collector. 'Hash' sampling will be presented as 'random'
455 | sampling to the collector, because of their similarity.
456 | Note, that Flow Sampling is compatible with NetFlow v5, v9, and IPFIX.
457 |
458 | natevents=1
459 | - Collect and send NAT translation events as NetFlow Event Logging (NEL)
460 | for NetFlow v9/IPFIX, or as dummy flows compatible with NetFlow v5.
461 | Default is 0 (don't send).
462 |
463 | For NetFlow v5 protocol meaning of fields in dummy flows are such:
464 | Src IP, Src Port is Pre-nat source address.
465 | Dst IP, Dst Port is Post-nat destination address.
466 | - These two fields made equal to data flows caught in FORWARD chain.
467 | Nexthop, Src AS is Post-nat source address for SNAT. Or,
468 | Nexthop, Dst AS is Pre-nat destination address for DNAT.
469 | TCP Flags is SYN+SCK for start event, RST+FIN for stop event.
470 | Pkt/Traffic size is 0 (zero), so it won't interfere with accounting.
471 |
472 | Natevents are compilation disabled by default, to enable you will need to
473 | add --enable-natevents option to ./configure script.
474 |
475 | For technical description of NAT Events see:
476 | http://tools.ietf.org/html/draft-ietf-behave-ipfix-nat-logging-04
477 |
478 | inactive_timeout=15
479 | - export flow after it's inactive for 15 seconds. Default value is 15.
480 |
481 | active_timeout=1800
482 | - export flow after it's active for 1800 seconds (30 minutes). Default
483 | value is 1800.
484 |
485 | refresh-rate=20
486 | - for NetFlow v9 and IPFIX it's rate how frequently to re-send templates
487 | (per packets). You probably don't need to change default (which is 20).
488 |
489 | timeout-rate=30
490 | - for NetFlow v9 and IPFIX it's rate when to re-send old templates (in
491 | minutes). No need to change it.
492 |
493 | debug=0
494 | - debug level (none).
495 |
496 | sndbuf=number
497 | - size of output socket buffer in bytes. I recommend you to put higher
498 | value if you experience netflow packet drops (can be seen in statistics
499 | as 'sock: fail' number.)
500 | Default value is system default.
501 |
502 | hashsize=number
503 | - Hash table bucket size. Used for performance tuning.
504 | Abstractly speaking, it should be minimum two times bigger than flows
505 | you usually have, but not need to.
506 | Default is system memory dependent small enough value.
507 |
508 | maxflows=2000000
509 | - Maximum number of flows to account. It's here to prevent DOS attacks.
510 | After this limit is reached new flows will not be accounted. Default is
511 | 2000000, zero is unlimited.
512 |
513 | aggregation=string..
514 | - Few aggregation rules (or some say they are rule.)
515 |
516 | Buffer for aggregation string 1024 bytes, and sysctl limit it
517 | to ~700 bytes, so don't write there a lot.
518 | Rules worked in definition order for each packet, so don't
519 | write them a lot again.
520 | Rules applied to both directions (dst and src).
521 | Rules tried until first match, but for netmask and port
522 | aggregations separately.
523 | Delimit them with commas.
524 |
525 | Rules are of two kinds: for netmask aggregation
526 | and port aggregation:
527 |
528 | a) Netmask aggregation example: 192.0.0.0/8=16
529 | Which mean to strip addresses matching subnet 192.0.0.0/8 to /16.
530 |
531 | b) Port aggregation example: 80-89=80
532 | Which mean to replace ports from 80 to 89 with 80.
533 |
534 | Full example:
535 | aggregation=192.0.0.0/8=16,10.0.0.0/8=16,80-89=80,3128=80
536 |
537 | Aggregation rules are enabled by default, if you feel you don't need them
538 | you may add --disable-aggregation to ./configure script.
539 |
540 | snmp-rules=string...
541 | - Few SNMP-index conversion rules similar to fproble-ulog.
542 |
543 | Quoting man fprobe-ulog:
544 |
545 | "Comma separated list of interface name to SNMP-index conversion
546 | rules. Each rule consists of interface base name and SNMP-index
547 | base separated by colon (e.g. ppp:200). Final SNMP-index is sum
548 | of corresponding SNMP-index base and interface number.
549 | In the above example SNMP-index of interface ppp11 is 211.
550 |
551 | If interface name did not fit to any of conversion rules then
552 | SNMP-index will be taken from kernel."
553 |
554 | This implementation isn't optimized for performance (no rule caching
555 | or hashing), but should be fast if rules list are short.
556 |
557 | Rules are parsed in order from first to last until first match.
558 |
559 | snmp-rules are compilation disabled by default, to enable you will need
560 | to add --enable-snmp option to ./configure script.
561 |
562 | scan-min=1
563 | - Minimal interval between flow export scans. Sometimes could be useful
564 | to reduce load on exporting CPU by increasing this interval. Value are
565 | in kernel jiffies units (which is x/HZ seconds).
566 |
567 | promisc=1
568 | - Enables promisc hack. See README.promisc Solution 1 for details.
569 |
570 | exportcpu=number
571 | - Lock exporter to single CPU. This may be useful to fine control CPU
572 | load. Common use case: with smp_affinity and RSS you spread packet
573 | processing to all CPUs except one, and lock it to the exporter. While
574 | exporter CPU load generally is not high, for someone it may be not
575 | desirable to combine it with packet processing on very highly loaded
576 | routers.
577 |
578 | This option could be changed at runtime with:
579 |
580 | # echo number > /sys/module/ipt_NETFLOW/parameters/exportcpu
581 |
582 | engine_id=number
583 | - Observation Domain ID (on IPFIX, Source Id on NetFlow v9, or Engine Id
584 | on NetFlow v5) value to be exported. This may help your collector to
585 | distinguish between multiple exporters. On Netflow v9 and IPFIX this
586 | value is 32-bit on NetFlow v5 only 8 low bits are significant.
587 | Default value is 0.
588 |
589 | This option could be changed at runtime with:
590 |
591 | # echo number > /sys/module/ipt_NETFLOW/parameters/engine_id
592 |
593 |
594 | ====================
595 | = HOW TO READ STAT =
596 | ====================
597 |
598 | Statistics is your friend to fine tune and understand netflow module
599 | performance.
600 |
601 | To see stat in human readable form:
602 | # cat /proc/net/stat/ipt_netflow
603 |
604 | How to interpret the data:
605 |
606 | > ipt_NETFLOW version v1.8-122-gfae9d59-dirty, srcversion 6141961152BE0DFA6A21EF4; aggr mac vlan
607 |
608 | This line helps to identify actual source that your module is build on.
609 | Please always supply it in all bug reports.
610 |
611 | v1.8-122: 1.8 is release, 122 is commit number after release;
612 | -gfae9d59: fae9d59 is short git commit id;
613 | -dirty: if present, meaning that git detected that sources are changed since
614 | last git commit, you may wish to do `git diff' to view changes;
615 | srcversion 6141961152BE0DFA6A21EF4: binary version of module, you can
616 | compare this with data from `modinfo ./ipt_NETFLOW.ko' to identify
617 | actual binary loaded;
618 | aggr mac vlan: tags to identify compile time options that are enabled.
619 |
620 | > Protocol version 10 (ipfix), refresh-rate 20, timeout-rate 30, (templates 2, active 2). Timeouts: active 5, inactive 15. Maxflows 2000000
621 |
622 | Protocol version currently in use. Refresh-rate and timeout-rate
623 | for v9 and IPFIX. Total templates generated and currently active.
624 | Timeout: active X: how much seconds to wait before exporting active flow.
625 | - same as sysctl net.netflow.active_timeout variable.
626 | inactive X: how much seconds to wait before exporting inactive flow.
627 | - same as sysctl net.netflow.inactive_timeout variable.
628 | Maxflows 2000000: maxflows limit.
629 | - all flows above maxflows limit must be dropped.
630 | - you can control maxflows limit by sysctl net.netflow.maxflows variable.
631 |
632 | > Promisc hack is disabled (observed 0 packets, discarded 0).
633 |
634 | observed n: To see that promisc hack is really working.
635 |
636 | > Natevents disabled, count start 0, stop 0.
637 |
638 | - Natevents mode disabled or enabled, and how much start or stop events
639 | are reported.
640 |
641 | > Flows: active 5187 (peak 83905 reached 0d0h1m ago), mem 283K, worker delay 100/1000 (37 ms, 0 us, 4:0 0 [3]).
642 |
643 | active X: currently active flows in memory cache.
644 | - for optimum CPU performance it is recommended to set hash table size to
645 | at least twice of average of this value, or higher.
646 | peak X reached Y ago: peak value of active flows.
647 | mem XK: how much kilobytes of memory currently taken by active flows.
648 | - one active flow taking 56 bytes of memory.
649 | - there is system limit on cache size too.
650 | worker delay X/HZ: how frequently exporter scan flows table per second.
651 | Rest is boring debug info.
652 |
653 | > Hash: size 8192 (mem 32K), metric 1.00, [1.00, 1.00, 1.00]. InHash: 1420 pkt, 364 K, InPDU 28, 6716.
654 |
655 | Hash: size X: current hash size/limit.
656 | - you can control this by sysctl net.netflow.hashsize variable.
657 | - increasing this value can significantly reduce CPU load.
658 | - default value is not optimal for performance.
659 | - optimal value is twice of average of active flows.
660 | mem XK: how much memory occupied by hash table.
661 | - hash table is fixed size by nature, taking 4 bytes per entry.
662 | metric X, [X, X, X]: how optimal is your hash table being used.
663 | - lesser value mean more optimal hash table use, min is 1.0.
664 | - last three numbers in squares is moving average (EWMA) of hash table
665 | access divided by match rate (searches / matches) for 4sec, and 1, 5, and
666 | 15 minutes. Sort of hash table load average. First value is instantaneous.
667 | You can try to increase hashsize if averages more than 1 (increase
668 | certainly if >= 2).
669 | InHash: X pkt, X K: how much traffic accounted for flows in the hash table.
670 | InPDU X, X: how much traffic in flows preparing to be exported.
671 |
672 | > Rate: 202448 bits/sec, 83 packets/sec; 1 min: 668463 bps, 930 pps; 5 min: 329039 bps, 483 pps
673 |
674 | - Module throughput values for 1 second, 1 minute, and 5 minutes.
675 |
676 | > cpu# pps; , traffic: , drop:
677 | > cpu0 123; 980540 10473 180600 [1.03], 0 0 0 0, traffic: 188765, 14 MB, drop: 27863, 1142 K
678 |
679 | cpu#: this is Total and per CPU statistics for:
680 | pps: packets per second on this CPU. It's useful to debug load imbalance.
681 | : internal stat for:
682 | search found new: hash table searched, found, and not found counters.
683 | [metric]: one minute (ewma) average hash metric per cpu.
684 | trunc: how much truncated packets are ignored
685 | - for example if packets don't have valid IP header.
686 | - it's also accounted in drop packets counter, but not in drop bytes.
687 | frag: how much fragmented packets have seen.
688 | - kernel defragments INPUT/OUTPUT chains for us if nf_defrag_ipv[46]
689 | module is loaded.
690 | - these packets are not ignored but not reassembled either, so:
691 | - if there is no enough data in fragment (ex. tcp ports) it is considered
692 | to be zero.
693 | alloc: how much cache memory allocations are failed.
694 | - packets ignored and accounted in traffic drop stat.
695 | - probably increase system memory if this ever happen.
696 | maxflows: how much packets ignored on maxflows (maximum active flows reached).
697 | - packets ignored and accounted in traffic drop stat.
698 | - you can control maxflows limit by sysctl net.netflow.maxflows variable.
699 |
700 | traffic: : how much traffic is accounted.
701 | pkt, bytes: sum of packets/megabytes accounted by module.
702 | - flows that failed to be exported (on socket error) is accounted here too.
703 |
704 | drop: : how much of traffic is not accounted.
705 | pkt, bytes: sum of packets/kilobytes that are dropped by metering process.
706 | - reasons these drops are accounted here:
707 | truncated/fragmented packets,
708 | packet is for new flow but failed to allocate memory for it,
709 | packet is for new flow but maxflows is already reached.
710 | Traffic lost due to socket errors is not accounted here. Look below
711 | about export and socket errors.
712 |
713 | > Export: Rate 0 bytes/s; Total 2 pkts, 0 MB, 18 flows; Errors 0 pkts; Traffic lost 0 pkts, 0 Kbytes, 0 flows.
714 |
715 | Rate X bytes/s: traffic rate generated by exporter itself.
716 | Total X pkts, X MB: total amount of traffic generated by exporter.
717 | X flows: how much data flows are exported.
718 | Errors X pkts: how much packets not sent due to socket errors.
719 | Traffic lost 0 pkts, 0 Kbytes, 0 flows: how much metered traffic is lost
720 | due to socket errors.
721 | Note that `cberr' errors are not accounted here due to their asynchronous
722 | nature. Read below about `cberr' errors.
723 |
724 | > sock0: 10.0.0.2:2055 unconnected (1 attempts).
725 |
726 | If socket is unconnected (for example if module loaded before interfaces is
727 | up) it shows now much connection attempts was failed. It will try to connect
728 | until success.
729 |
730 | > sock0: 10.0.0.2:2055, sndbuf 106496, filled 0, peak 106848; err: sndbuf reached 928, connect 0, cberr 0, other 0
731 |
732 | sockX: per destination stats for:
733 | X.X.X.X:Y: destination ip address and port.
734 | - controlled by sysctl net.netflow.destination variable.
735 | sndbuf X: how much data socket can hold in buffers.
736 | - controlled by sysctl net.netflow.sndbuf variable.
737 | - if you have packet drops due to sndbuf reached (error -11) increase this
738 | value.
739 | filled X: how much data in socket buffers right now.
740 | peak X: peak value of how much data in socket buffers was.
741 | - you will be interested to keep it below sndbuf value.
742 | err: how much packets are dropped due to errors.
743 | - all flows from them will be accounted in drop stat.
744 | sndbuf reached X: how much packets dropped due to sndbuf being too small
745 | (error -11).
746 | connect X: how much connection attempts was failed.
747 | cberr X: how much connection refused ICMP errors we got from export target.
748 | - probably you are not launched collector software on destination,
749 | - or specified wrong destination address.
750 | - flows lost in this fashion is not possible to account in drop stat.
751 | - these are ICMP errors, and would look like this in tcpdump:
752 | 05:04:09.281247 IP alice.19440 > bob.2055: UDP, length 120
753 | 05:04:09.281405 IP bob > alice: ICMP bob udp port 2055 unreachable, length 156
754 | other X: dropped due to other possible errors.
755 |
756 | > aggr0: ...
757 | aggrX: aggregation rulesets.
758 | - controlled by sysctl net.netflow.aggregation variable.
759 |
760 |
761 | ==========================
762 | = NetFlow considerations =
763 | ==========================
764 |
765 | List of all IPFIX Elements http://www.iana.org/assignments/ipfix/ipfix.xhtml
766 |
767 | Flow Keys are Elements that distinguish flows. Quoting RFC: "If a Flow
768 | Record for a specific Flow Key value already exists, the Flow Record is
769 | updated; otherwise, a new Flow Record is created."
770 |
771 | In this implementation following Elements are treated as Flow Keys:
772 |
773 | IPv4 source address: sourceIPv4Address(8),
774 | IPv6 source address: sourceIPv6Address(27),
775 | IPv4 destination address: destinationIPv4Address(12),
776 | IPv6 destination address: destinationIPv6Address(28),
777 | TCP/UDP source port: sourceTransportPort(7),
778 | TCP/UDP destination port: destinationTransportPort(11),
779 | input interface: ingressInterface(10),
780 | IP protocol: protocolIdentifier(4),
781 | IP TOS: ipClassOfService(5),
782 | and address family (IP or IPv6).
783 |
784 | Additional Flow Keys if VLAN exporting is enabled:
785 |
786 | First (outer) dot1q VLAN tag: dot1qVlanId(243) and
787 | dot1qPriority(244) for IPFIX,
788 | or vlanId(243) for NetFlow v9.
789 | Second (customer) dot1q VLAN tag: dot1qCustomerVlanId(245)
790 | and dot1qCustomerPriority(246).
791 |
792 | Additional Flow Keys if MAC address exporting is enabled:
793 |
794 | Destination MAC address: destinationMacAddress(80),
795 | Source MAC address: sourceMacAddress(56).
796 |
797 | Additional Flow Keys if MPLS-aware NetFlow is enabled:
798 |
799 | Captured MPLS stack is fully treated as flow key (including TTL values),
800 | which is Elements from mplsTopLabelStackSection(70) to
801 | mplsLabelStackSection10(79), and, if present, mplsTopLabelTTL(200).
802 |
803 |
804 | Other Elements are not Flow Keys. Note that outer interface, which is
805 | egressInterface(14), is not regarded as Flow Key. Quoting RFC 7012: "For
806 | Information Elements ... for which the value may change from packet to packet
807 | within a single Flow, the exported value of an Information Element is by
808 | default determined by the first packet observed for the corresponding Flow".
809 |
810 | Note that NetFlow and IPFIX modes of operation may have slightly different
811 | Elements being used and different statistics sent via Options Templates.
812 |
813 |
814 | =========
815 | = VOILA =
816 | =========
817 |
--------------------------------------------------------------------------------
/README.promisc:
--------------------------------------------------------------------------------
1 | Hello,
2 |
3 | If you wish to account with ipt-netflow module traffic mirrored on switch you may follow
4 | one of these examples:
5 |
6 |
7 | Solution 1: Promisc-hack module option. [2014]
8 | Solution 2: General kernel patch. [2008]
9 | Solution 3: Alternative w/o kernel patch, using bridges. [2010]
10 |
11 |
12 | **************
13 | * Solution 1 *
14 | **************
15 |
16 | No kernel patching is need anymore! (As in easy.)
17 |
18 | Compile module with `./configure --enable-promisc' option. This will enable
19 | `promisc=' module parameter and sysctl parameter `net.netflow.promisc'.
20 | Set any of these to `1' to enable promisc hack, you will see dmesg message
21 | that it's enabled, set to `0' to disable (default).
22 |
23 | This option turned on will pass promisc traffic into `PREROUTING' chain
24 | of `raw' table (same as with promisc patches). Briefly it's like this:
25 |
26 | # cd ipt-netflow/
27 | # ./configure --enable-promisc
28 | # make all install
29 | # iptables -A PREROUTING -t raw -i eth2 -j NETFLOW
30 | # sysctl net.netflow.promisc=1
31 | # ifconfig eth2 promisc
32 | # grep Promisc /proc/net/stat/ipt_netflow
33 |
34 | Now you should be able to see promisc observed packets count increasing.
35 |
36 | Note, that enabling module's parameter promisc=1 will not enable promiscuous
37 | mode on network cards, these are completely different things. This option will
38 | let iptables to see promisc traffic. That traffic will not be routed anywhere
39 | and discarded just after passing PREROUTING chain.
40 |
41 | Do not enable this option if you have kernel already patched with promisc
42 | patch, as this may cause double accounting. Just keep it disabled or remove
43 | the patch. Promisc patching is completely custom and non-standard, so if you
44 | did not apply it - you are most probably safe to use promisc option. But, if
45 | in doubt - measure if module seeing traffic in raw/PREROUTING, if it isn't - you
46 | don't have the patch applied and certainly safe to use the option.
47 |
48 |
49 |
50 | **************
51 | * Solution 2 *
52 | **************
53 |
54 | 1. Patch your kernel with `raw_promisc.patch' to enable raw table to see promisc traffic.
55 |
56 | # cd /usr/src/linux
57 | # patch -p1 < ~/ipt_netflow/raw_promisc.patch
58 |
59 | Then recompile and reinstall patched kernel.
60 |
61 | 2. For example you mirroring traffic on your Cisco switch to 47th vlan:
62 |
63 | # interface FastEthernet0/32
64 | # description this port with vlan 47
65 | # switchport trunk encapsulation dot1q
66 | # switchport mode trunk
67 | # !
68 | # interface FastEthernet0/33
69 | # port monitor FastEthernet0/32
70 | # !
71 |
72 | 3. Enable promisc mode on interface to actually see the packets:
73 |
74 | # /sbin/ifconfig eth1 promisc
75 |
76 | 4. Configure vlan on your linux box:
77 |
78 | # /sbin/vconfig add eth1 47
79 | # /sbin/ifconfig eth1.47 up
80 |
81 | 5. Compile module:
82 |
83 | # make clean all install
84 |
85 | 6. Load ipt_netflow module:
86 |
87 | # /sbin/modprobe ipt_NETFLOW hashsize=160000 destination=127.0.0.1:9800
88 |
89 | 7. Direct all packets from 47th vlan to ipt_netflow module:
90 |
91 | # /sbin/iptables -A PREROUTING -t raw -i eth1.47 -j NETFLOW
92 |
93 | Voila.
94 |
95 | ps. For Debian Squeeze instructions look at raw_promisc_debian_squeeze6.patch
96 |
97 |
98 |
99 | **************
100 | * Solution 3 *
101 | **************
102 |
103 | By Anonymous.
104 |
105 | > raw promisc hack is not needed
106 | > there is a more elegant way to capture port mirrored traffic:
107 | >
108 | > 1. create a bridge of eth0 and dummy0
109 | > 2. put eth0 to promisc
110 | > 3. add a "-i br0 -j NETFLOW" rule to FORWARD (possibly also -j DROP after that)
111 | >
112 | > ...for some reason it works when ipt_netflow is attached to a bridge, but
113 | > requires the promisc hack when attached to a real promisc interface.
114 |
115 | Sometimes you may need to run:
116 |
117 | # brctl setageing br0 0
118 |
119 | for this scheme to work.
120 |
121 |
--------------------------------------------------------------------------------
/compat.h:
--------------------------------------------------------------------------------
1 | /* SPDX-License-Identifier: GPL-2.0-only
2 | *
3 | * This code is derived from the Linux Kernel sources intended
4 | * to maintain compatibility with different Kernel versions.
5 | * Copyright of original source is of respective Linux Kernel authors.
6 | */
7 |
8 | #ifndef COMPAT_NETFLOW_H
9 | #define COMPAT_NETFLOW_H
10 | #include "compat_def.h"
11 |
12 | #ifndef NIPQUAD
13 | # define NIPQUAD(addr) \
14 | ((unsigned char *)&addr)[0], \
15 | ((unsigned char *)&addr)[1], \
16 | ((unsigned char *)&addr)[2], \
17 | ((unsigned char *)&addr)[3]
18 | #endif
19 | #ifndef HIPQUAD
20 | # if defined(__LITTLE_ENDIAN)
21 | # define HIPQUAD(addr) \
22 | ((unsigned char *)&addr)[3], \
23 | ((unsigned char *)&addr)[2], \
24 | ((unsigned char *)&addr)[1], \
25 | ((unsigned char *)&addr)[0]
26 | # elif defined(__BIG_ENDIAN)
27 | # define HIPQUAD NIPQUAD
28 | # else
29 | # error "Please fix asm/byteorder.h"
30 | # endif /* __LITTLE_ENDIAN */
31 | #endif
32 |
33 | #ifndef IPT_CONTINUE
34 | # define IPT_CONTINUE XT_CONTINUE
35 | # define ipt_target xt_target
36 | #endif
37 |
38 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
39 | union nf_inet_addr {
40 | __be32 ip;
41 | __be32 ip6[4];
42 | struct in_addr in;
43 | struct in6_addr in6;
44 | };
45 | #endif
46 |
47 | #ifndef list_first_entry
48 | #define list_first_entry(ptr, type, member) \
49 | list_entry((ptr)->next, type, member)
50 | #endif
51 |
52 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
53 | # define INIT_NET(x) x
54 | #else
55 | # define INIT_NET(x) init_net.x
56 | #endif
57 |
58 | #ifndef ETH_P_8021AD
59 | # define ETH_P_8021AD 0x88A8 /* 802.1ad Service VLAN */
60 | #endif
61 |
62 | #ifndef ETH_P_QINQ1
63 | # define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN */
64 | # define ETH_P_QINQ2 0x9200 /* deprecated QinQ VLAN */
65 | # define ETH_P_QINQ3 0x9300 /* deprecated QinQ VLAN */
66 | #endif
67 |
68 | #ifndef IPPROTO_MH
69 | # define IPPROTO_MH 135
70 | #endif
71 |
72 | #ifdef CONFIG_SYSCTL
73 | # if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
74 | # define BEFORE2632(x,y) x,y
75 | # else /* since 2.6.32 */
76 | # define BEFORE2632(x,y)
77 | # endif
78 |
79 | # if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)
80 | # define ctl_table struct ctl_table
81 | # endif
82 |
83 | # ifndef HAVE_GRSECURITY_H
84 | # define ctl_table_no_const ctl_table
85 | # endif
86 | #endif
87 |
88 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0)
89 | # define compat_hlist_for_each_entry hlist_for_each_entry
90 | # define compat_hlist_for_each_entry_safe hlist_for_each_entry_safe
91 | #else /* since 3.9.0 */
92 | # define compat_hlist_for_each_entry(a,pos,c,d) hlist_for_each_entry(a,c,d)
93 | # define compat_hlist_for_each_entry_safe(a,pos,c,d,e) hlist_for_each_entry_safe(a,c,d,e)
94 | #endif
95 |
96 | #ifndef WARN_ONCE
97 | #define WARN_ONCE(x,fmt...) ({ if (x) printk(KERN_WARNING fmt); })
98 | #endif
99 |
100 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
101 | # define IPPROTO_UDPLITE 136
102 | #endif
103 |
104 | #ifndef time_is_before_jiffies
105 | # define time_is_before_jiffies(a) time_after(jiffies, a)
106 | #endif
107 | #ifndef time_is_after_jiffies
108 | # define time_is_after_jiffies(a) time_before(jiffies, a)
109 | #endif
110 |
111 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
112 | # if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
113 | # define prandom_u32 get_random_int
114 | # elif LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)
115 | # define prandom_u32 random32
116 | #endif
117 | #define prandom_u32_max compat_prandom_u32_max
118 | static inline u32 prandom_u32_max(u32 ep_ro)
119 | {
120 | return (u32)(((u64) prandom_u32() * ep_ro) >> 32);
121 | }
122 | #endif
123 |
124 | #ifndef min_not_zero
125 | # define min_not_zero(x, y) ({ \
126 | typeof(x) __x = (x); \
127 | typeof(y) __y = (y); \
128 | __x == 0 ? __y : ((__y == 0) ? __x : min(__x, __y)); })
129 | #endif
130 |
131 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0)
132 | static int __ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
133 | {
134 | ASSERT_RTNL();
135 |
136 | if (!dev->ethtool_ops->get_settings)
137 | return -EOPNOTSUPP;
138 |
139 | memset(cmd, 0, sizeof(struct ethtool_cmd));
140 | cmd->cmd = ETHTOOL_GSET;
141 | return dev->ethtool_ops->get_settings(dev, cmd);
142 | }
143 | #endif
144 |
145 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
146 | # define ethtool_cmd_speed(x) (x)->speed
147 | #endif
148 |
149 | #ifndef ARPHRD_PHONET
150 | # define ARPHRD_PHONET 820
151 | # define ARPHRD_PHONET_PIPE 821
152 | #endif
153 | #ifndef ARPHRD_IEEE802154
154 | # define ARPHRD_IEEE802154 804
155 | #endif
156 |
157 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
158 | # define for_each_netdev_ns(net, dev) for (dev = dev_base; dev; dev = dev->next)
159 | #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
160 | # define for_each_netdev_ns(net, d) for_each_netdev(d)
161 | #else
162 | # define for_each_netdev_ns(net, d) for_each_netdev(net, d)
163 | #endif
164 |
165 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
166 | # define CHECK_FAIL 0
167 | # define CHECK_OK 1
168 | #else
169 | # define CHECK_FAIL -EINVAL
170 | # define CHECK_OK 0
171 | #endif
172 |
173 | #ifndef NF_IP_LOCAL_IN /* 2.6.25 */
174 | # define NF_IP_PRE_ROUTING NF_INET_PRE_ROUTING
175 | # define NF_IP_LOCAL_IN NF_INET_LOCAL_IN
176 | # define NF_IP_FORWARD NF_INET_FORWARD
177 | # define NF_IP_LOCAL_OUT NF_INET_LOCAL_OUT
178 | # define NF_IP_POST_ROUTING NF_INET_POST_ROUTING
179 | #endif
180 |
181 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
182 | /* net/netfilter/x_tables.c */
183 | static void xt_unregister_targets(struct xt_target *target, unsigned int n)
184 | {
185 | unsigned int i;
186 |
187 | for (i = 0; i < n; i++)
188 | xt_unregister_target(&target[i]);
189 | }
190 | static int xt_register_targets(struct xt_target *target, unsigned int n)
191 | {
192 | unsigned int i;
193 |
194 | int err = 0;
195 | for (i = 0; i < n; i++)
196 | if ((err = xt_register_target(&target[i])))
197 | goto err;
198 | return err;
199 | err:
200 | if (i > 0)
201 | xt_unregister_targets(target, i);
202 | return err;
203 | }
204 | #endif
205 |
206 | #ifdef HAVE_TOTALRAM_PAGES
207 | #define num_physpages totalram_pages()
208 | #elif defined HAVE_TOTALRAM_PAGES_REF
209 | #define num_physpages totalram_pages
210 | #endif
211 |
212 | #ifndef HAVE_TIMEVAL
213 | /* timeval is only used internally, so we can use anything for it. */
214 | struct timeval {
215 | long tv_sec;
216 | long tv_usec; /* microseconds */
217 | };
218 |
219 | unsigned long timeval_to_jiffies(const struct timeval *tv)
220 | {
221 | return timespec64_to_jiffies(&(struct timespec64){
222 | tv->tv_sec,
223 | tv->tv_usec * NSEC_PER_USEC
224 | });
225 | }
226 | #endif
227 |
228 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
229 | # ifdef ktime_to_timeval
230 | /* ktime_to_timeval is defined on 64bit and inline on 32bit cpu */
231 | /* when it's defined it calls ns_to_timeval, which is not exported */
232 | struct timeval portable_ns_to_timeval(const s64 nsec)
233 | {
234 | struct timespec ts = ns_to_timespec(nsec);
235 | struct timeval tv;
236 |
237 | tv.tv_sec = ts.tv_sec;
238 | tv.tv_usec = (suseconds_t) ts.tv_nsec / 1000;
239 |
240 | return tv;
241 | }
242 | # define ns_to_timeval portable_ns_to_timeval
243 | # endif
244 |
245 | static inline s64 portable_ktime_to_ms(const ktime_t kt)
246 | {
247 | struct timeval tv = ktime_to_timeval(kt);
248 | return (s64) tv.tv_sec * MSEC_PER_SEC + tv.tv_usec / USEC_PER_MSEC;
249 | }
250 | # define ktime_to_ms portable_ktime_to_ms
251 | #endif /* before 2.6.35 */
252 |
253 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
254 | static inline s64 portable_ktime_to_us(const ktime_t kt)
255 | {
256 | struct timeval tv = ktime_to_timeval(kt);
257 | return (s64) tv.tv_sec * USEC_PER_SEC + tv.tv_usec;
258 | }
259 | #define ktime_to_us portable_ktime_to_us
260 | #endif
261 |
262 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
263 | static inline void put_unaligned_be16(u16 val, void *p)
264 | {
265 | put_unaligned(cpu_to_be16(val), (__be16 *)p);
266 | }
267 | static inline void put_unaligned_be32(u32 val, void *p)
268 | {
269 | put_unaligned(cpu_to_be32(val), (__be32 *)p);
270 | }
271 | static inline void put_unaligned_be64(u64 val, void *p)
272 | {
273 | put_unaligned(cpu_to_be64(val), (__be64 *)p);
274 | }
275 | #endif
276 |
277 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24) && !defined(RHEL_MAJOR)
278 | static void *__seq_open_private(struct file *f, struct seq_operations *ops,
279 | int psize)
280 | {
281 | int rc;
282 | void *private;
283 | struct seq_file *seq;
284 |
285 | private = kzalloc(psize, GFP_KERNEL);
286 | if (private == NULL)
287 | goto out;
288 |
289 | rc = seq_open(f, ops);
290 | if (rc < 0)
291 | goto out_free;
292 |
293 | seq = f->private_data;
294 | seq->private = private;
295 | return private;
296 |
297 | out_free:
298 | kfree(private);
299 | out:
300 | return NULL;
301 | }
302 | #endif
303 |
304 | /* disappeared in v3.19 */
305 | #ifndef __get_cpu_var
306 | #define __get_cpu_var(var) (*this_cpu_ptr(&(var)))
307 | #endif
308 |
309 | #ifndef MPLS_HLEN
310 | #define MPLS_HLEN 4
311 | static inline int eth_p_mpls(__be16 eth_type)
312 | {
313 | return eth_type == htons(ETH_P_MPLS_UC) ||
314 | eth_type == htons(ETH_P_MPLS_MC);
315 | }
316 | #endif
317 | #ifndef MPLS_LS_S_MASK
318 | struct mpls_label {
319 | __be32 entry;
320 | };
321 | #define MPLS_LS_S_MASK 0x00000100
322 |
323 | #endif
324 |
325 | /* sockaddr comparison functions is from fs/nfs/client.c */
326 | static int sockaddr_match_ipaddr6(const struct sockaddr *sa1, const struct sockaddr *sa2)
327 | {
328 | const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1;
329 | const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2;
330 |
331 | if (!ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr))
332 | return 0;
333 | #if 0
334 | else if (ipv6_addr_type(&sin1->sin6_addr) & IPV6_ADDR_LINKLOCAL)
335 | return sin1->sin6_scope_id == sin2->sin6_scope_id;
336 | #endif
337 | return 1;
338 | }
339 |
340 | static int sockaddr_match_ipaddr4(const struct sockaddr *sa1, const struct sockaddr *sa2)
341 | {
342 | const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1;
343 | const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2;
344 |
345 | return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
346 | }
347 |
348 | static int sockaddr_cmp_ip6(const struct sockaddr *sa1, const struct sockaddr *sa2)
349 | {
350 | const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1;
351 | const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2;
352 |
353 | return sockaddr_match_ipaddr6(sa1, sa2) &&
354 | (sin1->sin6_port == sin2->sin6_port);
355 | }
356 |
357 | static int sockaddr_cmp_ip4(const struct sockaddr *sa1, const struct sockaddr *sa2)
358 | {
359 | const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1;
360 | const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2;
361 |
362 | return sockaddr_match_ipaddr4(sa1, sa2) &&
363 | (sin1->sin_port == sin2->sin_port);
364 | }
365 |
366 | static int sockaddr_cmp(const struct sockaddr_storage *sa1, const struct sockaddr_storage *sa2)
367 | {
368 | const struct sockaddr *s1 = (const struct sockaddr *)sa1;
369 | const struct sockaddr *s2 = (const struct sockaddr *)sa2;
370 |
371 | if (sa1->ss_family != sa2->ss_family)
372 | return 0;
373 |
374 | switch (sa1->ss_family) {
375 | case AF_INET:
376 | return sockaddr_cmp_ip4(s1, s2);
377 | case AF_INET6:
378 | return sockaddr_cmp_ip6(s1, s2);
379 | }
380 | return 0;
381 | }
382 |
383 | #ifndef IN6PTON_XDIGIT
384 | #define hex_to_bin compat_hex_to_bin
385 | /* lib/hexdump.c */
386 | int hex_to_bin(char ch)
387 | {
388 | if ((ch >= '0') && (ch <= '9'))
389 | return ch - '0';
390 | ch = tolower(ch);
391 | if ((ch >= 'a') && (ch <= 'f'))
392 | return ch - 'a' + 10;
393 | return -1;
394 | }
395 |
396 | /* net/core/utils.c */
397 | #define IN6PTON_XDIGIT 0x00010000
398 | #define IN6PTON_DIGIT 0x00020000
399 | #define IN6PTON_COLON_MASK 0x00700000
400 | #define IN6PTON_COLON_1 0x00100000 /* single : requested */
401 | #define IN6PTON_COLON_2 0x00200000 /* second : requested */
402 | #define IN6PTON_COLON_1_2 0x00400000 /* :: requested */
403 | #define IN6PTON_DOT 0x00800000 /* . */
404 | #define IN6PTON_DELIM 0x10000000
405 | #define IN6PTON_NULL 0x20000000 /* first/tail */
406 | #define IN6PTON_UNKNOWN 0x40000000
407 |
408 | static inline int xdigit2bin(char c, int delim)
409 | {
410 | int val;
411 |
412 | if (c == delim || c == '\0')
413 | return IN6PTON_DELIM;
414 | if (c == ':')
415 | return IN6PTON_COLON_MASK;
416 | if (c == '.')
417 | return IN6PTON_DOT;
418 |
419 | val = hex_to_bin(c);
420 | if (val >= 0)
421 | return val | IN6PTON_XDIGIT | (val < 10 ? IN6PTON_DIGIT : 0);
422 |
423 | if (delim == -1)
424 | return IN6PTON_DELIM;
425 | return IN6PTON_UNKNOWN;
426 | }
427 |
428 | int in4_pton(const char *src, int srclen,
429 | u8 *dst,
430 | int delim, const char **end)
431 | {
432 | const char *s;
433 | u8 *d;
434 | u8 dbuf[4];
435 | int ret = 0;
436 | int i;
437 | int w = 0;
438 |
439 | if (srclen < 0)
440 | srclen = strlen(src);
441 | s = src;
442 | d = dbuf;
443 | i = 0;
444 | while(1) {
445 | int c;
446 | c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
447 | if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK))) {
448 | goto out;
449 | }
450 | if (c & (IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
451 | if (w == 0)
452 | goto out;
453 | *d++ = w & 0xff;
454 | w = 0;
455 | i++;
456 | if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
457 | if (i != 4)
458 | goto out;
459 | break;
460 | }
461 | goto cont;
462 | }
463 | w = (w * 10) + c;
464 | if ((w & 0xffff) > 255) {
465 | goto out;
466 | }
467 | cont:
468 | if (i >= 4)
469 | goto out;
470 | s++;
471 | srclen--;
472 | }
473 | ret = 1;
474 | memcpy(dst, dbuf, sizeof(dbuf));
475 | out:
476 | if (end)
477 | *end = s;
478 | return ret;
479 | }
480 |
481 | int in6_pton(const char *src, int srclen,
482 | u8 *dst,
483 | int delim, const char **end)
484 | {
485 | const char *s, *tok = NULL;
486 | u8 *d, *dc = NULL;
487 | u8 dbuf[16];
488 | int ret = 0;
489 | int i;
490 | int state = IN6PTON_COLON_1_2 | IN6PTON_XDIGIT | IN6PTON_NULL;
491 | int w = 0;
492 |
493 | memset(dbuf, 0, sizeof(dbuf));
494 |
495 | s = src;
496 | d = dbuf;
497 | if (srclen < 0)
498 | srclen = strlen(src);
499 |
500 | while (1) {
501 | int c;
502 |
503 | c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
504 | if (!(c & state))
505 | goto out;
506 | if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
507 | /* process one 16-bit word */
508 | if (!(state & IN6PTON_NULL)) {
509 | *d++ = (w >> 8) & 0xff;
510 | *d++ = w & 0xff;
511 | }
512 | w = 0;
513 | if (c & IN6PTON_DELIM) {
514 | /* We've processed last word */
515 | break;
516 | }
517 | /*
518 | * COLON_1 => XDIGIT
519 | * COLON_2 => XDIGIT|DELIM
520 | * COLON_1_2 => COLON_2
521 | */
522 | switch (state & IN6PTON_COLON_MASK) {
523 | case IN6PTON_COLON_2:
524 | dc = d;
525 | state = IN6PTON_XDIGIT | IN6PTON_DELIM;
526 | if (dc - dbuf >= sizeof(dbuf))
527 | state |= IN6PTON_NULL;
528 | break;
529 | case IN6PTON_COLON_1|IN6PTON_COLON_1_2:
530 | state = IN6PTON_XDIGIT | IN6PTON_COLON_2;
531 | break;
532 | case IN6PTON_COLON_1:
533 | state = IN6PTON_XDIGIT;
534 | break;
535 | case IN6PTON_COLON_1_2:
536 | state = IN6PTON_COLON_2;
537 | break;
538 | default:
539 | state = 0;
540 | }
541 | tok = s + 1;
542 | goto cont;
543 | }
544 |
545 | if (c & IN6PTON_DOT) {
546 | ret = in4_pton(tok ? tok : s, srclen + (int)(s - tok), d, delim, &s);
547 | if (ret > 0) {
548 | d += 4;
549 | break;
550 | }
551 | goto out;
552 | }
553 |
554 | w = (w << 4) | (0xff & c);
555 | state = IN6PTON_COLON_1 | IN6PTON_DELIM;
556 | if (!(w & 0xf000)) {
557 | state |= IN6PTON_XDIGIT;
558 | }
559 | if (!dc && d + 2 < dbuf + sizeof(dbuf)) {
560 | state |= IN6PTON_COLON_1_2;
561 | state &= ~IN6PTON_DELIM;
562 | }
563 | if (d + 2 >= dbuf + sizeof(dbuf)) {
564 | state &= ~(IN6PTON_COLON_1|IN6PTON_COLON_1_2);
565 | }
566 | cont:
567 | if ((dc && d + 4 < dbuf + sizeof(dbuf)) ||
568 | d + 4 == dbuf + sizeof(dbuf)) {
569 | state |= IN6PTON_DOT;
570 | }
571 | if (d >= dbuf + sizeof(dbuf)) {
572 | state &= ~(IN6PTON_XDIGIT|IN6PTON_COLON_MASK);
573 | }
574 | s++;
575 | srclen--;
576 | }
577 |
578 | i = 15; d--;
579 |
580 | if (dc) {
581 | while(d >= dc)
582 | dst[i--] = *d--;
583 | while(i >= dc - dbuf)
584 | dst[i--] = 0;
585 | while(i >= 0)
586 | dst[i--] = *d--;
587 | } else
588 | memcpy(dst, dbuf, sizeof(dbuf));
589 |
590 | ret = 1;
591 | out:
592 | if (end)
593 | *end = s;
594 | return ret;
595 | }
596 | #endif /* IN6PTON_XDIGIT */
597 |
598 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,2,0)
599 | # define sock_create_kern(f, t, p, s) sock_create_kern(&init_net, f, t, p, s)
600 | #endif
601 |
602 | #if !defined(vlan_tx_tag_get) && defined(skb_vlan_tag_get)
603 | # define vlan_tx_tag_get skb_vlan_tag_get
604 | # define vlan_tx_tag_present skb_vlan_tag_present
605 | #endif
606 |
607 | #ifndef SPEED_UNKNOWN
608 | # define SPEED_UNKNOWN -1
609 | #endif
610 |
611 | #if !defined __GNUC_PREREQ && defined __GNUC__ && defined __GNUC_MINOR__
612 | # define __GNUC_PREREQ(maj, min) \
613 | ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
614 | #else
615 | # define __GNUC_PREREQ(maj, min) 0
616 | #endif
617 |
618 | /* ktime is not union anymore, since 2456e855354415bfaeb7badaa14e11b3e02c8466 */
619 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0)
620 | # define first_tv64 first.tv64
621 | # define last_tv64 last.tv64
622 | #else
623 | # define first_tv64 first
624 | # define last_tv64 last
625 | #endif
626 |
627 | /* Offset changes made in 613dbd95723aee7abd16860745691b6c7bda20dc */
628 | #ifndef HAVE_XT_FAMILY
629 | # if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
630 | # define xt_action_param xt_target_param
631 | # endif
632 | static inline u_int8_t xt_family(const struct xt_action_param *par)
633 | {
634 | return par->family;
635 | }
636 | static inline const struct net_device *xt_in(const struct xt_action_param *par)
637 | {
638 | return par->in;
639 | }
640 | static inline const struct net_device *xt_out(const struct xt_action_param *par)
641 | {
642 | return par->out;
643 | }
644 | static inline unsigned int xt_hooknum(const struct xt_action_param *par)
645 | {
646 | return par->hooknum;
647 | }
648 | #endif
649 |
650 | #ifndef SK_CAN_REUSE
651 | # define SK_CAN_REUSE 1
652 | #endif
653 |
654 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,13,0)
655 | # define compat_refcount_read atomic_read
656 | #else
657 | # define compat_refcount_read refcount_read
658 | #endif
659 |
660 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0)
661 | # define timer_setup setup_timer
662 | #endif
663 |
664 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0)
665 | static int dev_get_alias(const struct net_device *dev, char *name, size_t len)
666 | {
667 | return snprintf(name, len, "%s", dev->ifalias);
668 | }
669 | #else
670 | /* no static because defined in include/linux/netdevice.h,
671 | * but forgot to create EXPORT_SYMBOL,
672 | * probably will collide with some future kernel */
673 | int dev_get_alias(const struct net_device *dev, char *name, size_t len)
674 | {
675 | const struct dev_ifalias *alias;
676 | int ret = 0;
677 |
678 | rcu_read_lock();
679 | alias = rcu_dereference(dev->ifalias);
680 | if (alias)
681 | ret = snprintf(name, len, "%s", alias->ifalias);
682 | rcu_read_unlock();
683 |
684 | return ret;
685 | }
686 | #endif
687 |
688 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,39) && !defined(RHEL_MAJOR)
689 | static inline int is_vlan_dev(struct net_device *dev)
690 | {
691 | return dev->priv_flags & IFF_802_1Q_VLAN;
692 | }
693 | #endif
694 |
695 | #ifdef CONFIG_BRIDGE_NETFILTER
696 | # ifndef HAVE_NF_BRIDGE_INFO_GET
697 | static inline struct nf_bridge_info *
698 | nf_bridge_info_get(const struct sk_buff *skb)
699 | {
700 | return skb->nf_bridge;
701 | }
702 | # endif
703 | #endif
704 |
705 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0)
706 | static inline void do_gettimeofday(struct timeval *tv)
707 | {
708 | struct timespec64 ts64;
709 | ktime_get_real_ts64(&ts64);
710 | tv->tv_sec = ts64.tv_sec;
711 | tv->tv_usec = ts64.tv_nsec/1000;
712 | }
713 | #endif
714 |
715 | #define TOLOWER(x) ((x) | 0x20)
716 | unsigned long long strtoul(const char *cp, char **endp, unsigned int base)
717 | {
718 | unsigned long long result = 0;
719 |
720 | if (!base) {
721 | if (cp[0] == '0') {
722 | if (TOLOWER(cp[1]) == 'x' && isxdigit(cp[2]))
723 | base = 16;
724 | else
725 | base = 8;
726 | } else {
727 | base = 10;
728 | }
729 | }
730 |
731 | if (base == 16 && cp[0] == '0' && TOLOWER(cp[1]) == 'x')
732 | cp += 2;
733 |
734 | while (isxdigit(*cp)) {
735 | unsigned int value;
736 |
737 | value = isdigit(*cp) ? *cp - '0' : TOLOWER(*cp) - 'a' + 10;
738 | if (value >= base)
739 | break;
740 | result = result * base + value;
741 | cp++;
742 | }
743 | if (endp)
744 | *endp = (char *)cp;
745 |
746 | return result;
747 | }
748 |
749 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,12,0)
750 | /*
751 | * find_module() is unexported in v5.12:
752 | * 089049f6c9956 ("module: unexport find_module and module_mutex")
753 | * and module_mutex is replaced with RCU in
754 | * a006050575745 ("module: use RCU to synchronize find_module")
755 | */
756 | #include
757 | struct module *find_module(const char *name)
758 | {
759 | struct module *mod;
760 |
761 | rcu_read_lock_sched();
762 | /* Yes this is crazy, but should work. */
763 | list_for_each_entry_rcu(mod, &THIS_MODULE->list, list) {
764 | if (!strcmp(mod->name, name)) {
765 | rcu_read_unlock_sched();
766 | return mod;
767 | }
768 | }
769 | rcu_read_unlock_sched();
770 | return NULL;
771 | }
772 | #endif
773 |
774 | /* Copy from 294f69e662d1 ("compiler_attributes.h: Add 'fallthrough' pseudo
775 | * keyword for switch/case use") */
776 | #ifndef fallthrough
777 | # if defined __has_attribute && __has_attribute(__fallthrough__)
778 | # define fallthrough __attribute__((__fallthrough__))
779 | # else
780 | # define fallthrough do {} while (0) /* fallthrough */
781 | # endif
782 | #endif
783 |
784 | #ifndef HAVE_NF_CT_EVENT_NOTIFIER_CT_EVENT
785 | /*
786 | * nat event callback parameter is constified in 5.15+
787 | * but it prevents module building with previous kernel versions
788 | */
789 | # define NF_CT_EVENT struct nf_ct_event
790 | # define ct_event fcn
791 | #else
792 | # define NF_CT_EVENT const struct nf_ct_event
793 | #endif
794 |
795 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,4,0)
796 | static inline bool netif_is_bridge_port(const struct net_device *dev)
797 | {
798 | return dev->priv_flags & IFF_BRIDGE_PORT;
799 | }
800 | #endif
801 |
802 | #endif /* COMPAT_NETFLOW_H */
803 |
--------------------------------------------------------------------------------
/configure:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # SPDX-License-Identifier: GPL-2.0-only
3 |
4 | PATH=$PATH:/bin:/usr/bin:/usr/sbin:/sbin:/usr/local/sbin
5 |
6 | case "$1" in
7 | --from-dkms-conf*)
8 | KDKMS=`echo "$1" | sed 's/[^=]*.//'`
9 | # restore options from existing Makefile, if present
10 | if [ -e Makefile ]; then
11 | set -- `sed -n 's/^CARGS = \(.*\)/\1/p' Makefile`
12 | FROMDKMSCONF=1
13 | fi
14 | ;;
15 | esac
16 |
17 | error() {
18 | printf "! Error: $*\n"
19 | exit 1
20 | }
21 |
22 | iptables_src_version() {
23 | test "$IPTSRC" || return 1
24 |
25 | echo -n "Checking iptables sources version: "
26 | SRC="$IPTSRC/Makefile"
27 | test -s "$SRC" || error "Please build iptables first."
28 | VER=`sed -n 's/^\(IPTABLES_\)\?VERSION[ :]= \?//p' "$SRC"`
29 | test "$VER" || error "Unknown version of iptables."
30 | if [ "$VER" = "$IPTVER" ]; then
31 | echo "$VER (ok)"
32 | else
33 | echo "$VER"
34 | error "Source version ($VER) doesn't match binary ($IPTVER)"
35 | fi
36 | }
37 |
38 | get_lib_dir() {
39 | test -s "$1" && LIB=`sed -n 's/.*_LIB_DIR "\(.*\)"/\1/p' "$1"`
40 | if [ "$LIB" ]; then
41 | IPTLIB=$LIB
42 | echo "$IPTLIB (from sources)"
43 | return 0
44 | fi
45 | return 1
46 | }
47 |
48 | get_lib_from_bin() {
49 | LIB=`strings $IPTBIN | grep ^/.*lib.*/.*tables`
50 | if [ "$LIB" ]; then
51 | IPTLIB=$LIB
52 | echo "$IPTLIB (from binary)"
53 | return 0
54 | fi
55 | return 1
56 | }
57 |
58 | get_lib_from_lib() {
59 | XLIB=`/usr/bin/ldd $IPTBIN | grep libxtables | sed -n 's!.* \(/[^ ]\+\).*!\1!p'`
60 | test "$XLIB" || return 1
61 | LIB=`strings $XLIB | grep ^/.*lib.*/.*tables`
62 | if [ "$LIB" ]; then
63 | IPTLIB=$LIB
64 | echo "$IPTLIB (from libxtables.so, from binary)"
65 | return 0
66 | fi
67 | return 1
68 | }
69 |
70 | iptables_inc() {
71 | echo -n "Iptables include flags: "
72 | if [ "$IPTINC" ]; then
73 | echo "$IPTINC (user specified)"
74 | elif [ "$PKGVER" ]; then
75 | IPTINC="$PKGINC"
76 | echo "$IPTINC (pkg-config)"
77 | elif [ "$NOIPTSRC" ]; then
78 | IPTINC=
79 | echo "none (default)"
80 | else
81 | IPTINC="$IPTSRC/include"
82 | IPTINC="-I$IPTINC"
83 | echo "$IPTINC (from source)"
84 | fi
85 | }
86 |
87 | iptables_modules() {
88 | echo -n "Iptables module path: "
89 | if [ "$IPTLIB" ]; then
90 | echo "$IPTLIB (user specified)"
91 | else
92 | if [ "$PKGLIB" ]; then
93 | IPTLIB="$PKGLIB"
94 | echo "$IPTLIB (pkg-config)"
95 | else
96 | get_lib_dir "$IPTSRC/include/iptables.h" && return 0
97 | get_lib_dir "$IPTSRC/include/xtables.h" && return 0
98 | get_lib_dir "$IPTSRC/xtables/internal.h" && return 0
99 | get_lib_from_bin && return 0
100 | get_lib_from_lib && return 0
101 | error "can not find, try setting it with --ipt-lib="
102 | fi
103 | fi
104 | }
105 |
106 | try_dir() {
107 | if [ -d "$1/include" ]; then
108 | echo "Found iptables sources at $1"
109 | IPTSRC=$1
110 | return 0
111 | fi
112 | return 1
113 | }
114 |
115 | try_dirg() {
116 | try_dir "$1" && return 0
117 | try_dir "$1.git" && return 0
118 | }
119 |
120 | try_dir2() {
121 | test -d "$1" && try_dir `dirname $1` && return 0
122 | }
123 |
124 | check_pkg_config() {
125 | test "$PKGWARN" && return 1
126 | if ! which pkg-config >/dev/null 2>&1; then
127 | echo "! You don't have pkg-config, it may be useful to install it."
128 | PKGWARN=1
129 | return 1
130 | fi
131 | return 0
132 | }
133 | iptables_find_version() {
134 | echo -n "Iptables binary version: "
135 | if [ "$IPTVER" ]; then
136 | echo "$IPTVER (user specified)"
137 | else
138 | IPTVER=`$IPTBIN -V 2>/dev/null | sed -n s/iptables.v//p`
139 | if [ "$IPTVER" ]; then
140 | echo "$IPTVER (detected from $IPTBIN)"
141 | return
142 | else
143 | echo "no iptables binary found"
144 | fi
145 | check_pkg_config
146 | PKGVER=`pkg-config --modversion xtables 2>/dev/null`
147 | if [ "$PKGVER" ]; then
148 | IPTVER="$PKGVER"
149 | echo "Xtables version: $IPTVER (detected from `which pkg-config`)"
150 | return
151 | fi
152 | error "Can not find iptables version, try setting it with --ipt-ver="
153 | fi
154 | }
155 |
156 | compiler_presence_test() {
157 | echo -n "Check for working gcc: "
158 | $CC -v >/dev/null 2>&1
159 | if [ $? = 0 ]; then
160 | echo Yes "($CC)"
161 | else
162 | echo No
163 |
164 | echo "! You need gcc to install module from source"
165 | if [ -s /etc/debian_version ]; then
166 | NAME=Debian
167 | if [ -e /etc/os-release ]; then
168 | . /etc/os-release >/dev/null 2>&1
169 | fi
170 | echo "! "
171 | echo "! Under $NAME try to run this:"
172 | echo "! root# apt-get install gcc"
173 | echo "! "
174 | elif [ -s /etc/redhat-release ]; then
175 | echo "! "
176 | echo "! Under Centos try to run this:"
177 | echo "! root# yum install gcc"
178 | echo "! "
179 | fi
180 | exit 1
181 | fi
182 | }
183 |
184 | compile_libitp_test() {
185 | local FLAGS
186 | local MSG
187 | echo -n "Checking for presence of $@... "
188 | if [ "$IPTINC" ]; then
189 | FLAGS=$IPTINC
190 | MSG="(using ipt-inc)"
191 | elif [ "$PKGINC" ]; then
192 | FLAGS=$PKGINC
193 | MSG="(using pkg-config)"
194 | else
195 | FLAGS=
196 | MSG=
197 | fi
198 | echo "
199 | #define __EXPORTED_HEADERS__
200 | #include <$*>" > test.c
201 | $CC -c test.c $FLAGS >/dev/null 2>&1
202 | RET=$?
203 | if [ $RET = 0 ]; then
204 | echo Yes $MSG;
205 | else
206 | echo No;
207 | fi
208 | rm -f test.c test.o
209 | return $RET
210 | }
211 |
212 | iptables_try_pkgconfig() {
213 | if [ ! "$PKGVER" ]; then
214 | check_pkg_config
215 | PKGVER=`pkg-config --modversion xtables 2>/dev/null`
216 | TRYPKGVER=`pkg-config --modversion xtables 2>/dev/null`
217 | echo -n "pkg-config for version $IPTVER exists: "
218 | pkg-config --exact-version=$IPTVER xtables 2>/dev/null
219 | if [ $? = 0 ]; then
220 | echo "Yes"
221 | PKGVER=$TRYPKGVER
222 | else
223 | if [ "$TRYPKGVER" ]; then
224 | echo "No (reported: $TRYPKGVER)"
225 | else
226 | echo "No"
227 | fi
228 | PKGVER=
229 | fi
230 | fi
231 | if [ "$PKGVER" ]; then
232 | check_pkg_config
233 | PKGVER=`pkg-config --modversion xtables 2>/dev/null`
234 | PKGINC=`pkg-config --cflags xtables`
235 | PKGLIB=`pkg-config --variable=xtlibdir xtables`
236 | elif expr "$IPTVER" : '^1\.3' >/dev/null; then
237 | echo "! This version of iptables ($IPTVER) will be treated as old version."
238 | # Newer versions of iptables should not have -I/kernel/include!
239 | # So I assume that newer version will have correct pkg-config set up
240 | # and if not, then it's older who need it.
241 | IPTCFLAGS="-I$KDIR/include -DIPTABLES_VERSION=\\\\\"$IPTVER\\\\\""
242 | fi
243 | compiler_presence_test
244 | if compile_libitp_test xtables.h; then
245 | IPTCFLAGS="-DXTABLES $IPTCFLAGS"
246 | elif ! compile_libitp_test iptables.h; then
247 | echo "! Iptables headers not found. You may need to specify --ipt-inc=..."
248 | if [ -s /etc/debian_version ]; then
249 | echo "! "
250 | echo "! Under Debian simply run this:"
251 | if apt-cache policy libxtables-dev 2>&1 | grep -F -q "Candidate:"; then
252 | echo "! root# apt-get install libxtables-dev pkg-config"
253 | else
254 | echo "! root# apt-get install iptables-dev pkg-config"
255 | fi
256 | elif [ -s /etc/redhat-release ]; then
257 | echo "! "
258 | arch=.`uname -m`
259 | echo "! Under Centos simply run this:"
260 | echo "! root# yum install iptables-devel$arch pkgconfig"
261 | fi
262 | exit 1
263 | fi
264 |
265 | }
266 |
267 | iptables_find_src() {
268 | test "$IPTINC" && return 1
269 | test "$PKGVER" && return 1
270 |
271 | VER="iptables-$IPTVER"
272 | if [ "$IPTSRC" ]; then
273 | echo "User specified source directory: $IPTSRC"
274 | try_dir $IPTSRC || error "Specified directory is not iptables source.."
275 | else
276 | echo "Searching for $VER sources.."
277 | try_dir "./$VER" && return 0
278 | try_dir "../$VER" && return 0
279 | try_dir "/usr/src/$VER" && return 0
280 | try_dirg "iptables" && return 0
281 | try_dirg "../iptables" && return 0
282 | try_dirg "/usr/src/iptables" && return 0
283 | try_dir2 `locate $VER/extensions 2>/dev/null | head -1` && return 0
284 | echo "! Can not find iptables source directory, you may try setting it with --ipt-src="
285 | echo "! This is not fatal error, yet. Will be just using default include dir."
286 | NOIPTSRC=1
287 | fi
288 | }
289 |
290 | show_help() {
291 | echo "Possible options:"
292 | echo " --ipt-ver=.. iptables version (ex.: 1.4.2)"
293 | echo " --ipt-bin=.. iptables binary to use (ex.: /usr/sbin/iptables)"
294 | echo " --ipt-src=.. directory for iptable source (ex.: ../iptables-1.4.2)"
295 | echo " --ipt-lib=.. iptable modules path (ex.: /usr/libexec/xtables)"
296 | echo " --ipt-inc=.. directory for iptable headers (ex.: /usr/include)"
297 | echo " --kver=.. kernel version (ex.: 2.6.30-std-def-alt15)"
298 | echo " --kdir=.. directory for kernel source (ex.: /usr/src/kernel)"
299 | echo " --enable-natevents enables natevents support"
300 | echo " --enable-snmp-rules enables SNMP-index conversion rules"
301 | echo " --enable-macaddress enables MAC address for v9/IPFIX"
302 | echo " --enable-vlan enables VLAN Ids for v9/IPFIX"
303 | echo " --enable-direction enables flowDirection(61) Element"
304 | echo " --enable-sampler enables Flow Sampling"
305 | echo " --enable-sampler=hash enables Hash sampler"
306 | echo " --enable-rand-tpl-id enables seeding the template IDs from a random number"
307 | echo " --enable-aggregation enables aggregation rules"
308 | echo " --enable-promisc enables promisc hack mode"
309 | echo " --promisc-mpls decapsulate MPLS in promisc mode"
310 | echo " --promisc-mpls=N -- and record N labels (default 3)"
311 | echo " --enable-physdev enables physdev reporting"
312 | echo " --enable-physdev-override to override interfaces"
313 | echo " --disable-snmp-agent disables net-snmp agent"
314 | echo " --disable-dkms disables DKMS support completely"
315 | echo " --disable-dkms-install no DKMS install but still create dkms.conf"
316 | exit 0
317 | }
318 |
319 | CARGS="$@"
320 | for ac_option
321 | do
322 | case "$ac_option" in
323 | -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
324 | *) ac_optarg= ;;
325 | esac
326 |
327 | case "$ac_option" in
328 | --ipt-bin=*) IPTBIN="$ac_optarg" ;;
329 | --ipt-lib=*) IPTLIB="$ac_optarg" ;;
330 | --ipt-src=*) IPTSRC="$ac_optarg" ;;
331 | --ipt-ver=*) IPTVER="$ac_optarg" ;;
332 | --ipt-inc=*) IPTINC="-I$ac_optarg" ;;
333 | --kver=*) KVERSION="$ac_optarg" ;;
334 | --kdir=*) KDIR="$ac_optarg" ;;
335 | --enable-nat*) KOPTS="$KOPTS -DENABLE_NAT" ;;
336 | --enable-mac*) KOPTS="$KOPTS -DENABLE_MAC" ;;
337 | --enable-vlan*) KOPTS="$KOPTS -DENABLE_VLAN" ;;
338 | --enable-direc*) KOPTS="$KOPTS -DENABLE_DIRECTION" ;;
339 | --enable-sampl*hash) KOPTS="$KOPTS -DENABLE_SAMPLER -DSAMPLING_HASH" ;;
340 | --enable-sampl*) KOPTS="$KOPTS -DENABLE_SAMPLER" ;;
341 | --enable-aggr*) KOPTS="$KOPTS -DENABLE_AGGR" ;;
342 | --enable-rand-tpl*) KOPTS="$KOPTS -DENABLE_RANDOM_TEMPLATE_IDS" ;;
343 | --enable-promi*) ENABLE_PROMISC=1 ;;
344 | --promisc-mpls*) ENABLE_PROMISC=1; PROMISC_MPLS=1; MPLS_DEPTH=${ac_optarg:-3} ;;
345 | --enable-snmp-r*) KOPTS="$KOPTS -DSNMP_RULES" ;;
346 | --enable-physdev) KOPTS="$KOPTS -DENABLE_PHYSDEV" ;;
347 | --enable-physdev-over*) KOPTS="$KOPTS -DENABLE_PHYSDEV_OVER" ;;
348 | --disable-snmp-a*) SKIPSNMP=1 ;;
349 | --disable-net-snmp*) SKIPSNMP=1 ;;
350 | --disable-dkms*) SKIPDKMS=1 ;;
351 | --from-dkms-conf*) ;;
352 | --make) echo called from make; CARGS=`echo $CARGS | sed s/--make//g` ;;
353 | -Werror) KOPTS="$KOPTS -Werror" ;;
354 | --help|-h) show_help ;;
355 | -*) echo Invalid option: $ac_option; exit 1 ;;
356 | # *) ni="$ni $ac_option" ;;
357 | esac
358 | done
359 |
360 | if [ "$ENABLE_PROMISC" = 1 ]; then KOPTS="$KOPTS -DENABLE_PROMISC"; fi
361 | if [ "$PROMISC_MPLS" = 1 ]; then
362 | KOPTS="$KOPTS -DPROMISC_MPLS"
363 | case "$MPLS_DEPTH" in (*[!0-9]*|"") MPLS_DEPTH=1 ;; esac
364 | if [ "$MPLS_DEPTH" -lt 1 ]; then
365 | echo "! Requested MPLS stack depth is too small, limiting to 1."
366 | elif [ "$MPLS_DEPTH" -gt 10 ]; then
367 | echo "! Requested MPLS stack depth is too big, limiting to 10."
368 | MPLS_DEPTH=10;
369 | fi
370 | if [ "$MPLS_DEPTH" -ge 1 ]; then KOPTS="$KOPTS -DMPLS_DEPTH=$MPLS_DEPTH"; fi
371 | fi
372 |
373 | kernel_find_version() {
374 | KHOW=requested
375 | test "$KVERSION" && return 0
376 |
377 | if grep -q '#.*Debian' /proc/version; then
378 | KHOW=proc
379 | KVERSION=`sed -n 's/.*#.*Debian \([0-9\.]\+\)-.*/\1/p' /proc/version`
380 | KLIBMOD=`uname -r`
381 | else
382 | KHOW=uname
383 | KVERSION=`uname -r`
384 | fi
385 | test "$KDIR" || return 0
386 |
387 | test -s $KDIR/Makefile || return 1
388 | test -s $KDIR/include/config/kernel.release || return 1
389 | KVERSION=`cat $KDIR/include/config/kernel.release`
390 | KHOW=sources
391 | }
392 |
393 | kernel_check_src() {
394 | if [ -s "$1/Makefile" ]; then
395 | KDIR="$1"
396 | return 0
397 | fi
398 | return 1
399 | }
400 |
401 | kernel_check_src2() {
402 | if kernel_check_src $1/source; then
403 | KSRC=$KDIR
404 | fi
405 | kernel_check_src $1/build
406 | }
407 |
408 | kernel_find_source() {
409 | if [ "$KDKMS" ]; then
410 | # dkms args is highest priority
411 | KDIR=$KDKMS
412 | KSHOW=dkms
413 | return 0
414 | fi
415 | KSHOW=requested
416 | test "$KDIR" && return 0
417 | KSHOW=found
418 | kernel_check_src2 /lib/modules/$KLIBMOD && return 0
419 | kernel_check_src2 /lib/modules/$KVERSION && return 0
420 | kernel_check_src /usr/src/kernels/$KVERSION && return 0
421 | kernel_check_src /usr/src/linux-$KVERSION && return 0
422 | echo "! Linux source not found. Don't panic. You may specify kernel source"
423 | echo "! directory with --kdir=..., or try to install kernel-devel package,"
424 | echo "! or just raw sources for linux-$KVERSION from kernel.org."
425 | if grep -q -i centos /proc/version 2>/dev/null; then
426 | echo "! "
427 | arch=.`uname -m`
428 | echo "! Under Centos simply run this:"
429 | echo "! root# yum install kernel-devel iptables-devel$arch pkgconfig"
430 | fi
431 | if grep -q -i debian /proc/version 2>/dev/null; then
432 | echo "! "
433 | echo "! Under Debian simply run this:"
434 | echo "! root# apt-get install module-assistant iptables-dev pkg-config"
435 | echo "! root# m-a prepare"
436 | fi
437 | exit 1
438 | }
439 |
440 | kernel_check_consistency() {
441 | if [ -s $KDIR/include/config/kernel.release ]; then
442 | SRCVER=`cat $KDIR/include/config/kernel.release`
443 | if [ "$KVERSION" != "$SRCVER" ]; then
444 | echo "! Warning: $KHOW kernel version ($KVERSION) and $KSHOW version of kernel source ($SRCVER) doesn't match!"
445 | echo "! You may try to specify only kernel source tree with --kdir=$KDIR"
446 | echo "! and configure will pick up version properly."
447 | echo "! Assuming you want to build for $SRCVER"
448 | KVERSION=$SRCVER
449 | fi
450 | fi
451 | test -e "$KDIR/.config" || error ".config in kernel source not found, run make menuconfig in $KDIR"
452 | test -d "$KDIR/include/config" || error "kernel is not prepared, run make prepare modules_prepare in $KDIR"
453 | }
454 |
455 | kconfig() {
456 | KCONFIG=$KDIR/.config
457 | if ! grep -q "^$1=" $KCONFIG 2>/dev/null; then
458 | if [ "$KCONFIGREPORTED" != true ]; then
459 | KCONFIGREPORTED=true
460 | echo Kernel config file checked: $KCONFIG
461 | echo
462 | fi
463 | echo "! Attention: $1 is undefined in your kernel configuration"
464 | echo "! Without this option enabled $2 will not work."
465 | echo
466 | return 1
467 | fi
468 | return 0
469 | }
470 |
471 | # Respond to change in https://github.com/torvalds/linux/commit/4806e975729f99
472 | nf_nat_needed() {
473 | local INC=include/linux/netfilter.h
474 |
475 | echo -n "Checking for presence of $INC... "
476 | if [ "$KSRC" -a -e $KSRC/$INC ]; then
477 | echo Yes
478 | INC=$KSRC/$INC
479 | elif [ -e $KDIR/$INC ]; then
480 | echo Yes
481 | INC=$KDIR/$INC
482 | else
483 | echo No
484 | return 1
485 | fi
486 | echo -n "netfilter.h uses CONFIG_NF_NAT_NEEDED... "
487 | if grep -q CONFIG_NF_NAT_NEEDED $INC; then
488 | echo Yes
489 | else
490 | echo No
491 | return 1
492 | fi
493 | }
494 |
495 | kernel_check_config() {
496 | kconfig CONFIG_SYSCTL "sysctl interface"
497 | kconfig CONFIG_PROC_FS "proc interface"
498 | if nf_nat_needed; then
499 | kconfig CONFIG_NF_NAT_NEEDED "natevents"
500 | else
501 | kconfig CONFIG_NF_NAT "natevents" && KOPTS="$KOPTS -DCONFIG_NF_NAT_NEEDED"
502 | fi
503 | kconfig CONFIG_NF_CONNTRACK_EVENTS "natevents"
504 | kconfig CONFIG_IPV6 "IPv6"
505 | kconfig CONFIG_IP6_NF_IPTABLES "ip6tables target"
506 | kconfig CONFIG_BRIDGE_NETFILTER "physdev override"
507 | }
508 |
509 | kernel_check_include() {
510 | echo -n "Checking for presence of $1... "
511 | if [ "$KSRC" -a -e $KSRC/$1 ]; then
512 | echo Yes
513 | KOPTS="$KOPTS $2"
514 | elif [ -e $KDIR/$1 ]; then
515 | echo Yes
516 | KOPTS="$KOPTS $2"
517 | else
518 | echo No
519 | fi
520 | }
521 |
522 | kernel_check_features() {
523 | kernel_check_include include/linux/llist.h -DHAVE_LLIST
524 | kernel_check_include include/linux/grsecurity.h -DHAVE_GRSECURITY_H
525 | }
526 |
527 | snmp_check() {
528 | SNMPTARGET=
529 | SNMPINSTALL=
530 | test "$SKIPSNMP" && return
531 |
532 | echo -n "Searching for net-snmp-config... "
533 | if which net-snmp-config >/dev/null 2>&1; then
534 | echo Yes `which net-snmp-config`
535 | else
536 | echo No.
537 | SNMPCONFIG=no
538 | fi
539 |
540 | echo -n "Searching for net-snmp agent... "
541 | if [ -s /etc/redhat-release ]; then
542 | if ! rpm --quiet -q net-snmp; then
543 | echo No.
544 | SNMPADD="do: yum install net-snmp"
545 | if [ "$SNMPCONFIG" ]; then
546 | SNMPADD="$SNMPADD net-snmp-devel"
547 | fi
548 | else
549 | echo Yes.
550 | fi
551 | if [ "$SNMPCONFIG" ]; then
552 | SNMPCONFIG="run: yum install net-snmp-devel"
553 | fi
554 | elif [ -s /etc/debian_version ]; then
555 | if ! dpkg -s snmpd >/dev/null 2>&1; then
556 | echo No.
557 | SNMPADD="do: apt-get install snmpd"
558 | if [ "$SNMPCONFIG" ]; then
559 | SNMPADD="$SNMPADD libsnmp-dev"
560 | fi
561 | else
562 | echo Yes.
563 | fi
564 | if [ "$SNMPCONFIG" ]; then
565 | SNMPCONFIG="run: apt-get install libsnmp-dev"
566 | fi
567 | elif [ -s /etc/snmp/snmpd.conf ]; then
568 | echo Yes.
569 | else
570 | echo No.
571 | SNMPADD="install net-snmp (www.net-snmp.org)"
572 | SNMPCONFIG="reinstall net-snmp with agent support."
573 | fi
574 |
575 | if [ "$SNMPADD" ]; then
576 | echo " Assuming you don't want net-snmp agent support".
577 | echo " Otherwise $SNMPADD"
578 | return
579 | elif [ "$SNMPCONFIG" ]; then
580 | echo "! You have net-snmp agent but not development package."
581 | echo "! net-snmp agent will not be built, to fix:"
582 | echo "! $SNMPCONFIG"
583 | return
584 | fi
585 |
586 | SNMPTARGET=snmp_NETFLOW.so
587 | SNMPINSTALL=sinstall
588 | }
589 |
590 | dkms_check() {
591 | DKMSINSTALL=
592 | test "$SKIPDKMS" && return
593 |
594 | echo -n "Checking for DKMS... "
595 | if ! which dkms >/dev/null 2>&1; then
596 | echo "No. (It may be useful to install it.)"
597 | echo "! "
598 | echo "! DKMS is method of installing kernel modules, that will"
599 | echo "! automatically recompile module after kernel upgrade."
600 | if [ -s /etc/debian_version ]; then
601 | echo "! "
602 | echo "! To install it under Debian simply run this:"
603 | echo "! root# apt-get install dkms"
604 | echo "! "
605 | elif [ -s /etc/redhat-release ]; then
606 | echo "! "
607 | echo "! To install it under Centos enable EPEL or RPMforge repository,"
608 | echo "! then run this:"
609 | echo "! root# yum install dkms"
610 | echo "! "
611 | fi
612 | return
613 | fi
614 | echo Yes.
615 | DKMSINSTALL=dinstall
616 | test "$FROMDKMSCONF" && return
617 | if dkms status | grep ^ipt-netflow, >/dev/null; then
618 | echo "! You are already have module installed via DKMS"
619 | echo "! it will be uninstalled on 'make install' and"
620 | echo "! current version of module installed afterwards."
621 | echo "! Use --disable-dkms option if don't want this."
622 | fi
623 | }
624 |
625 | echo "Module version: $(./version.sh)"
626 |
627 | kernel_find_version #KVERSION
628 | test "$KLIBMOD" || KLIBMOD=$KVERSION
629 | echo "Kernel version: $KVERSION ($KHOW)"
630 | kernel_find_source #KDIR
631 | echo "Kernel sources: $KDIR ($KSHOW)"
632 | kernel_check_consistency
633 | kernel_check_config
634 | kernel_check_features
635 |
636 | CC=${CC:-gcc}
637 | test "$IPTBIN" || IPTBIN=`which iptables`
638 |
639 | iptables_find_version #IPTVER
640 | iptables_try_pkgconfig #try to configure from pkg-config
641 | iptables_find_src #IPTSRC
642 | iptables_src_version #check that IPTSRC match to IPTVER
643 | iptables_inc #IPTINC
644 | iptables_modules #IPTLIB
645 |
646 | snmp_check
647 | dkms_check
648 |
649 | rm -f compat_def.h
650 |
651 | REPLACE="\
652 | s!@CARGS@!$CARGS!;\
653 | s!@KVERSION@!$KVERSION!;\
654 | s!@KDIR@!$KDIR!;\
655 | s!@KOPTS@!$KOPTS!;\
656 | s!@SNMPTARGET@!$SNMPTARGET!;\
657 | s!@SNMPINSTALL@!$SNMPINSTALL!;\
658 | s!@DKMSINSTALL@!$DKMSINSTALL!;\
659 | s!@IPTABLES_VERSION@!$IPTVER!;\
660 | s!@IPTABLES_CFLAGS@!$IPTCFLAGS $IPTINC!;\
661 | s!@IPTABLES_MODULES@!$IPTLIB!"
662 |
663 | echo -n "Creating Makefile.. "
664 | sed "$REPLACE" Makefile.in > Makefile
665 | echo done.
666 | echo
667 | echo " If you need some options enabled run ./configure --help"
668 | echo " Now run: make all install"
669 | echo
670 |
671 |
--------------------------------------------------------------------------------
/dkms.conf:
--------------------------------------------------------------------------------
1 | PACKAGE_NAME="ipt-netflow"
2 | pushd `dirname $BASH_SOURCE`
3 | PACKAGE_VERSION=`./version.sh`
4 | popd
5 | BUILT_MODULE_NAME[0]=ipt_NETFLOW
6 | DEST_MODULE_LOCATION[0]=/kernel/extra
7 | STRIP[0]=no
8 | MAKE[0]="make ipt_NETFLOW.ko"
9 | PRE_BUILD="./configure --from-dkms-conf=$kernel_source_dir"
10 | AUTOINSTALL=yes
11 |
--------------------------------------------------------------------------------
/gen_compat_def:
--------------------------------------------------------------------------------
1 | #!/bin/bash -efu
2 | # SPDX-License-Identifier: GPL-2.0-only
3 | #
4 | # Generate defines based on kernel having some symbols declared.
5 | # Tests should work without linking, because kernel may not be
6 | # completely compiled (only prepared).
7 | #
8 | # Copyright (C) 2019-2021
9 | #
10 |
11 | export LANG=C LC_ALL=C LC_MESSAGES=C LC_CTYPE=C
12 | fatal() {
13 | echo "Error: $*" >&2
14 | exit 1
15 | }
16 |
17 | eval $(grep ^KDIR Makefile | tr -d ' ')
18 | [ "$KDIR" ] || fatal "KDIR is not found"
19 |
20 | WD=cc-test-build
21 | mkdir -p $WD
22 | cd ./$WD || fatal "cannot cd to $WD"
23 |
24 | # args: HAVE_SUMBOL symbol include
25 | kbuild_test_compile() {
26 | local cmd
27 |
28 | cat > test.c
29 | echo obj-m = test.o > Makefile
30 | cmd="make -s -B -C $KDIR M=$PWD modules"
31 | echo "$cmd" > log
32 | if $cmd >> log 2>&1; then
33 | echo " declared" >&2
34 | [ "$2" ] && echo "// $2 is declared ${3:+in <$3>}"
35 | echo "#define HAVE_$1"
36 | echo
37 | else
38 | echo " undeclared" >&2
39 | echo "#undef HAVE_$1"
40 | echo "// ${2:-symbol} is undeclared${3:+ in <$3>}. Compile:"
41 | sed "s/^/\/\/ /" test.c
42 | echo "// Output:"
43 | sed "s/^/\/\/ /" log
44 | echo
45 | if ! grep -E -q \
46 | -e 'has no member named' \
47 | -e 'undeclared' \
48 | -e 'storage size of .* isn.t known' \
49 | -e 'No such file or directory' \
50 | -e 'incompatible types when initializing' \
51 | -e 'initializer element is not constant' \
52 | -e 'dereferencing pointer to incomplete type' \
53 | log; then
54 | echo "Error: unexpected error from compiler" >&2
55 | cat log >&2
56 | echo >&2
57 | exit 3
58 | fi
59 | fi
60 | }
61 |
62 | # Test that symbol is defined (will catch functions mostly).
63 | kbuild_test_symbol() {
64 | echo -n "Test function $* " >&2
65 | kbuild_test_compile ${1^^} $1 ${2-} <<-EOF
66 | #include
67 | ${2:+#include <$2>}
68 | MODULE_LICENSE("GPL");
69 | void *test = $1;
70 | EOF
71 | }
72 |
73 | # Test that symbol is defined (functions and globals).
74 | kbuild_test_ref() {
75 | echo -n "Test symbol $* " >&2
76 | kbuild_test_compile ${1^^}_REF $1 ${2-} <<-EOF
77 | #include
78 | ${2:+#include <$2>}
79 | MODULE_LICENSE("GPL");
80 | void *test = &$1;
81 | EOF
82 | }
83 | # Test that struct is defined.
84 | kbuild_test_struct() {
85 | echo -n "Test struct $* " >&2
86 | kbuild_test_compile ${1^^} "struct $1" ${2-} <<-EOF
87 | #include
88 | ${2:+#include <$2>}
89 | MODULE_LICENSE("GPL");
90 | struct $1 test;
91 | EOF
92 | }
93 |
94 | # Test that struct have member
95 | kbuild_test_member() {
96 | echo -n "Test member $* " >&2
97 | structname=${1%.*}
98 | member=${1#*.}
99 | def=${1^^}
100 | def=${def//./_}
101 | kbuild_test_compile $def "struct $1" ${2-} <<-EOF
102 | #include
103 | ${2:+#include <$2>}
104 | MODULE_LICENSE("GPL");
105 | typeof(((struct $structname*)0)->$member) test;
106 | EOF
107 | }
108 | echo "// Autogenerated for $KDIR"
109 | echo
110 |
111 | # helpers introduced in 613dbd95723aee7abd16860745691b6c7bda20dc
112 | kbuild_test_symbol xt_family linux/netfilter_ipv4/ip_tables.h
113 | kbuild_test_struct timeval linux/ktime.h
114 | # 97a32539b9568 proc: convert everything to "struct proc_ops"
115 | # d56c0d45f0e27 proc: decouple proc from VFS with "struct proc_ops"
116 | kbuild_test_struct proc_ops linux/proc_fs.h
117 | # No since v5.1, but present in CentOS-8's 4.18.0-227
118 | kbuild_test_symbol synchronize_sched linux/rcupdate.h
119 | # Fails on 3.10.0-957.10.1.el7.x86_64
120 | kbuild_test_symbol nf_bridge_info_get linux/netfilter_bridge.h
121 | # Stumbled on 5.9
122 | kbuild_test_struct vlan_dev_priv linux/if_vlan.h
123 | # Kernel version check broken by centos8
124 | kbuild_test_symbol put_unaligned_be24 asm/unaligned.h
125 | # totalram_pages changed from atomic to inline function.
126 | kbuild_test_symbol totalram_pages linux/mm.h
127 | kbuild_test_ref totalram_pages linux/mm.h
128 | # b86c0e6429da ("netfilter: ecache: prepare for event notifier merge")
129 | kbuild_test_member nf_ct_event_notifier.ct_event net/netfilter/nf_conntrack_ecache.h
130 | # 6.4: 0199849acd07 ("sysctl: remove register_sysctl_paths()")
131 | kbuild_test_symbol register_sysctl_paths linux/sysctl.h
132 |
133 | echo "// End of compat_def.h"
134 |
135 | cd $OLDPWD
136 | rm -rf $WD
137 |
138 | # debug output for Travis
139 | if [ -z "${PWD/*travis*}" ]; then
140 | cat compat_def.h >&2
141 | fi
142 |
--------------------------------------------------------------------------------
/install-dkms.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # SPDX-License-Identifier: GPL-2.0-only
3 | #
4 | # This script cleanly re-install module into DKMS tree.
5 |
6 | PATH=$PATH:/bin:/usr/bin:/usr/sbin:/sbin:/usr/local/sbin
7 |
8 | if [ "$1" = --uninstall ]; then
9 | echo "Uninstalling from DKMS..."
10 | elif [ "$1" = --install ]; then
11 | echo "Installing into DKMS..."
12 | else
13 | exit 1
14 | fi
15 |
16 | if ! which dkms >/dev/null 2>&1; then
17 | echo "! You don't have DKMS accessible in system."
18 | exit 1
19 | fi
20 |
21 | if [ ! -e dkms.conf ]; then
22 | echo "! You don't have DKMS configured for this module."
23 | exit 1
24 | fi
25 |
26 | MVERSION=`./version.sh`
27 |
28 | contains() { for e in "${@:2}"; do [[ "$e" = "$1" ]] && return 0; done; return 1; }
29 |
30 | D=() # to be list of installed versions
31 | OLDIFS="$IFS"
32 | IFS=$'\n' A=(`dkms status | grep ^ipt-netflow`)
33 | IFS="$OLDIFS"
34 |
35 | for i in "${A[@]}"; do
36 | z=($i)
37 | v=${z[1]}
38 | v=${v%,}
39 | v=${v%:}
40 | if ! contains "$v" "${D[@]}"; then
41 | D+=($v)
42 | fi
43 | done
44 |
45 | if [ ${#D[@]} -eq 1 ]; then
46 | # single version is already installed.
47 | if [ $D = "$MVERSION" ]; then
48 | echo "! You have same version of module already installed into DKMS."
49 | else
50 | echo "! You have different version of module installed into DKMS."
51 | fi
52 | if [ ! -d /usr/src/ipt-netflow-$D ]; then
53 | echo "! Can not find DKMS dir for it, that's plain weird."
54 | elif [ -e /usr/src/ipt-netflow-$D/.automatic ]; then
55 | echo "! That version was automatically installed by this script,"
56 | echo "! thus, is safe to remove. No worries."
57 | else
58 | echo "! That version was manually installed by you."
59 | fi
60 |
61 | nodepmod=
62 | if grep -qs no-depmod `which dkms`; then
63 | nodepmod=--no-depmod
64 | fi
65 | echo "! Removing from dkms..."
66 | dkms $nodepmod remove ipt-netflow/$D --all
67 |
68 | if [ -d "/usr/src/ipt-netflow-$D" ]; then
69 | echo "! Removing source tree from /usr/src/ipt-netflow-$D"
70 | rm -rf "/usr/src/ipt-netflow-$D"
71 | fi
72 |
73 | elif [ ${#D[@]} -gt 1 ]; then
74 | # multiple versions are installed.
75 | echo "! You have multiple versions of module already installed in DKMS."
76 | echo "! Please remove them manually to avoid conflict."
77 | echo "! 'dkms status' output:"
78 | dkms status
79 | echo "! Suggested commands to remove them:"
80 | for i in ${D[@]}; do
81 | echo "! root# dkms remove ipt-netflow/$i --all"
82 | done
83 | exit 1
84 | fi
85 |
86 | if [ "$1" = --uninstall ]; then
87 | exit 0
88 | fi
89 |
90 | if [ "$PWD" = "/usr/src/ipt-netflow-$MVERSION" ]; then
91 | echo "! You are already in DKMS dir."
92 | dkms add -m ipt-netflow -v $MVERSION
93 | exit $?
94 | fi
95 |
96 | echo "! Installing $MVERSION into DKMS..."
97 | rm -rf /usr/src/ipt-netflow-$MVERSION
98 |
99 | mkdir -p /usr/src/ipt-netflow-$MVERSION
100 | cp -p *.[ch] Make* READ* conf* gen* irq* *.sh *.conf /usr/src/ipt-netflow-$MVERSION/
101 | if [ -d .git ]; then
102 | cp -pr .git /usr/src/ipt-netflow-$MVERSION/
103 | fi
104 | touch /usr/src/ipt-netflow-$MVERSION/.automatic
105 |
106 | dkms add -m ipt-netflow -v $MVERSION
107 | exit $?
108 |
109 |
--------------------------------------------------------------------------------
/ipt_NETFLOW.h:
--------------------------------------------------------------------------------
1 | /* SPDX-License-Identifier: GPL-2.0-only
2 | *
3 | * This file is part of NetFlow exporting module.
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, see .
17 | *
18 | */
19 |
20 | #ifndef _IPT_NETFLOW_H
21 | #define _IPT_NETFLOW_H
22 |
23 | /*
24 | * Some tech info:
25 | * http://www.cisco.com/en/US/products/ps6601/prod_white_papers_list.html
26 | * http://www.cisco.com/en/US/products/sw/netmgtsw/ps1964/products_implementation_design_guide09186a00800d6a11.html
27 | */
28 |
29 | #define NETFLOW5_RECORDS_MAX 30
30 |
31 | struct netflow5_record {
32 | __be32 s_addr;
33 | __be32 d_addr;
34 | __be32 nexthop;
35 | __be16 i_ifc;
36 | __be16 o_ifc;
37 | __be32 nr_packets;
38 | __be32 nr_octets;
39 | __be32 first_ms;
40 | __be32 last_ms;
41 | __be16 s_port;
42 | __be16 d_port;
43 | __u8 reserved;
44 | __u8 tcp_flags;
45 | __u8 protocol;
46 | __u8 tos;
47 | __be16 s_as;
48 | __be16 d_as;
49 | __u8 s_mask;
50 | __u8 d_mask;
51 | __u16 padding;
52 | } __attribute__ ((packed));
53 |
54 | /* NetFlow v5 packet */
55 | struct netflow5_pdu {
56 | __be16 version;
57 | __be16 nr_records;
58 | __be32 ts_uptime; /* ms */
59 | __be32 ts_usecs; /* s */
60 | __be32 ts_unsecs; /* ns */
61 | __be32 seq;
62 | __u8 eng_type;
63 | __u8 eng_id;
64 | __u16 sampling;
65 | struct netflow5_record flow[NETFLOW5_RECORDS_MAX];
66 | } __attribute__ ((packed));
67 | #define NETFLOW5_HEADER_SIZE (sizeof(struct netflow5_pdu) - NETFLOW5_RECORDS_MAX * sizeof(struct netflow5_record))
68 |
69 | #define IF_NAME_SZ IFNAMSIZ
70 | #define IF_DESC_SZ 32
71 |
72 | /* NetFlow v9 http://www.ietf.org/rfc/rfc3954.txt */
73 | /* IPFIX http://www.iana.org/assignments/ipfix/ipfix.xhtml */
74 | /* v9 elements are uppercased, IPFIX camel cased. */
75 | #define one(id, name, len) name = id,
76 | #define two(id, a, b, len) \
77 | one(id, a, len) \
78 | one(id, b, len)
79 | #define Elements \
80 | two(1, IN_BYTES, octetDeltaCount, 4) \
81 | two(2, IN_PKTS, packetDeltaCount, 4) \
82 | two(4, PROTOCOL, protocolIdentifier, 1) \
83 | two(5, TOS, ipClassOfService, 1) \
84 | two(6, TCP_FLAGS, tcpControlBits, 1) \
85 | two(7, L4_SRC_PORT, sourceTransportPort, 2) \
86 | two(8, IPV4_SRC_ADDR, sourceIPv4Address, 4) \
87 | two(9, SRC_MASK, sourceIPv4PrefixLength, 1) \
88 | two(10, INPUT_SNMP, ingressInterface, 2) \
89 | two(11, L4_DST_PORT, destinationTransportPort, 2) \
90 | two(12, IPV4_DST_ADDR, destinationIPv4Address, 4) \
91 | two(13, DST_MASK, destinationIPv4PrefixLength, 1) \
92 | two(14, OUTPUT_SNMP, egressInterface, 2) \
93 | two(15, IPV4_NEXT_HOP, ipNextHopIPv4Address, 4) \
94 | two(21, LAST_SWITCHED, flowEndSysUpTime, 4) \
95 | two(22, FIRST_SWITCHED, flowStartSysUpTime, 4) \
96 | one(25, minimumIpTotalLength, 2) \
97 | one(26, maximumIpTotalLength, 2) \
98 | two(27, IPV6_SRC_ADDR, sourceIPv6Address, 16) \
99 | two(28, IPV6_DST_ADDR, destinationIPv6Address, 16) \
100 | two(31, IPV6_FLOW_LABEL, flowLabelIPv6, 3) \
101 | two(32, ICMP_TYPE, icmpTypeCodeIPv4, 2) \
102 | two(33, MUL_IGMP_TYPE, igmpType, 1) \
103 | two(40, TOTAL_BYTES_EXP, exportedOctetTotalCount, 8) \
104 | two(41, TOTAL_PKTS_EXP, exportedMessageTotalCount, 8) \
105 | two(42, TOTAL_FLOWS_EXP, exportedFlowRecordTotalCount, 8) \
106 | two(48, FLOW_SAMPLER_ID, samplerId, 1) \
107 | two(49, FLOW_SAMPLER_MODE, samplerMode, 1) \
108 | two(50, FLOW_SAMPLER_RANDOM_INTERVAL, samplerRandomInterval, 2) \
109 | one(52, minimumTTL, 1) \
110 | one(53, maximumTTL, 1) \
111 | two(56, SRC_MAC, sourceMacAddress, 6) \
112 | two(57, DST_MAC, postDestinationMacAddress, 6) \
113 | two(58, SRC_VLAN, vlanId, 2) \
114 | two(60, IP_VERSION, ipVersion, 1) \
115 | two(61, DIRECTION, flowDirection, 1) \
116 | two(62, IPV6_NEXT_HOP, ipNextHopIPv6Address, 16) \
117 | two(64, IPV6_OPTION_HEADERS, ipv6ExtensionHeaders, 2) \
118 | two(70, MPLS_LABEL_1, mplsTopLabelStackSection, 3) \
119 | two(71, MPLS_LABEL_2, mplsLabelStackSection2, 3) \
120 | two(72, MPLS_LABEL_3, mplsLabelStackSection3, 3) \
121 | two(73, MPLS_LABEL_4, mplsLabelStackSection4, 3) \
122 | two(74, MPLS_LABEL_5, mplsLabelStackSection5, 3) \
123 | two(75, MPLS_LABEL_6, mplsLabelStackSection6, 3) \
124 | two(76, MPLS_LABEL_7, mplsLabelStackSection7, 3) \
125 | two(77, MPLS_LABEL_8, mplsLabelStackSection8, 3) \
126 | two(78, MPLS_LABEL_9, mplsLabelStackSection9, 3) \
127 | two(79, MPLS_LABEL_10, mplsLabelStackSection10, 3) \
128 | one(80, destinationMacAddress, 6) \
129 | two(82, IF_NAME, interfaceName, IF_NAME_SZ) \
130 | two(83, IF_DESC, interfaceDescription, IF_DESC_SZ) \
131 | one(136, flowEndReason, 1) \
132 | one(138, observationPointId, 4) \
133 | one(139, icmpTypeCodeIPv6, 2) \
134 | one(141, LineCardId, 4) \
135 | one(142, portId, 4) \
136 | one(143, meteringProcessId, 4) \
137 | one(144, exportingProcessId, 4) \
138 | one(145, TemplateId, 2) \
139 | one(149, observationDomainId, 4) \
140 | one(152, flowStartMilliseconds, 8) \
141 | one(153, flowEndMilliseconds, 8) \
142 | one(154, flowStartMicroseconds, 8) \
143 | one(155, flowEndMicroseconds, 8) \
144 | one(160, systemInitTimeMilliseconds, 8) \
145 | one(163, observedFlowTotalCount, 8) \
146 | one(164, ignoredPacketTotalCount, 8) \
147 | one(165, ignoredOctetTotalCount, 8) \
148 | one(166, notSentFlowTotalCount, 8) \
149 | one(167, notSentPacketTotalCount, 8) \
150 | one(168, notSentOctetTotalCount, 8) \
151 | one(200, mplsTopLabelTTL, 1) \
152 | one(201, mplsLabelStackLength, 1) \
153 | one(202, mplsLabelStackDepth, 1) \
154 | one(208, ipv4Options, 4) \
155 | one(209, tcpOptions, 4) \
156 | one(225, postNATSourceIPv4Address, 4) \
157 | one(226, postNATDestinationIPv4Address, 4) \
158 | one(227, postNAPTSourceTransportPort, 2) \
159 | one(228, postNAPTDestinationTransportPort, 2) \
160 | one(230, natEvent, 1) \
161 | one(243, dot1qVlanId, 2) \
162 | one(244, dot1qPriority, 1) \
163 | one(245, dot1qCustomerVlanId, 2) \
164 | one(246, dot1qCustomerPriority, 1) \
165 | one(252, ingressPhysicalInterface, 2) \
166 | one(253, egressPhysicalInterface, 2) \
167 | one(256, ethernetType, 2) \
168 | one(295, IPSecSPI, 4) \
169 | one(300, observationDomainName, 128) \
170 | one(302, selectorId, 1) \
171 | one(309, samplingSize, 1) \
172 | one(310, samplingPopulation, 2) \
173 | one(318, selectorIdTotalPktsObserved, 8) \
174 | one(319, selectorIdTotalPktsSelected, 8) \
175 | one(323, observationTimeMilliseconds, 8) \
176 | one(324, observationTimeMicroseconds, 8) \
177 | one(325, observationTimeNanoseconds, 8) \
178 | one(390, flowSelectorAlgorithm, 1) \
179 | one(394, selectorIDTotalFlowsObserved, 8) \
180 | one(395, selectorIDTotalFlowsSelected, 8) \
181 | one(396, samplingFlowInterval, 1) \
182 | one(397, samplingFlowSpacing, 2)
183 |
184 | enum {
185 | Elements
186 | };
187 | #undef one
188 | #undef two
189 |
190 | enum {
191 | FLOWSET_TEMPLATE = 0,
192 | FLOWSET_OPTIONS = 1,
193 | IPFIX_TEMPLATE = 2,
194 | IPFIX_OPTIONS = 3,
195 | FLOWSET_DATA_FIRST = 256,
196 | };
197 |
198 | enum { /* v9 scopes */
199 | V9_SCOPE_SYSTEM = 1,
200 | V9_SCOPE_INTERFACE = 2,
201 | V9_SCOPE_LINECARD = 3,
202 | V9_SCOPE_CACHE = 4,
203 | V9_SCOPE_TEMPLATE = 5,
204 | };
205 |
206 | struct flowset_template {
207 | __be16 flowset_id;
208 | __be16 length; /* (bytes) */
209 | __be16 template_id;
210 | __be16 field_count; /* (items) */
211 | } __attribute__ ((packed));
212 |
213 | struct flowset_data {
214 | __be16 flowset_id; /* corresponds to template_id */
215 | __be16 length; /* (bytes) */
216 | } __attribute__ ((packed));
217 |
218 | /* http://tools.ietf.org/html/rfc3954#section-6.1 */
219 | struct flowset_opt_tpl_v9 {
220 | __be16 flowset_id;
221 | __be16 length;
222 | __be16 template_id;
223 | __be16 scope_len; /* (bytes) */
224 | __be16 opt_len; /* (bytes) */
225 | } __attribute__ ((packed));
226 |
227 | /* http://tools.ietf.org/html/rfc5101#section-3.4.2.2 */
228 | struct flowset_opt_tpl_ipfix {
229 | __be16 flowset_id;
230 | __be16 length;
231 | __be16 template_id;
232 | __be16 field_count; /* total (items) */
233 | __be16 scope_count; /* (items) must not be zero */
234 | } __attribute__ ((packed));
235 |
236 | /* NetFlow v9 packet. */
237 | struct netflow9_pdu {
238 | __be16 version;
239 | __be16 nr_records; /* (items) */
240 | __be32 sys_uptime_ms;
241 | __be32 export_time_s;
242 | __be32 seq;
243 | __be32 source_id; /* Exporter Observation Domain */
244 | __u8 data[1400];
245 | } __attribute__ ((packed));
246 |
247 | /* IPFIX packet. */
248 | struct ipfix_pdu {
249 | __be16 version;
250 | __be16 length; /* (bytes) */
251 | __be32 export_time_s;
252 | __be32 seq;
253 | __be32 odomain_id; /* Observation Domain ID */
254 | __u8 data[1400];
255 | } __attribute__ ((packed));
256 |
257 | /* Maximum bytes flow can have, after it's reached flow will become
258 | * not searchable and will be exported soon. */
259 | #define FLOW_FULL_WATERMARK 0xffefffff
260 |
261 | #define EXTRACT_SPI(tuple) ((tuple.s_port << 16) | tuple.d_port)
262 | #define SAVE_SPI(tuple, spi) { tuple.s_port = spi >> 16; \
263 | tuple.d_port = spi; }
264 | #define MAX_VLAN_TAGS 2
265 |
266 | /* hashed data which identify unique flow */
267 | /* 16+16 + 2+2 + 2+1+1+1 = 41 */
268 | struct ipt_netflow_tuple {
269 | union nf_inet_addr src;
270 | union nf_inet_addr dst;
271 | __be16 s_port; // Network byte order
272 | __be16 d_port; // -"-
273 | #ifdef MPLS_DEPTH
274 | __be32 mpls[MPLS_DEPTH]; /* Network byte order */
275 | #endif
276 | __u16 i_ifc; // Host byte order
277 | #ifdef ENABLE_VLAN
278 | __be16 tag[MAX_VLAN_TAGS]; // Network byte order (outer tag first)
279 | #endif
280 | __u8 protocol;
281 | __u8 tos;
282 | __u8 l3proto;
283 | #ifdef ENABLE_MAC
284 | __u8 h_dst[ETH_ALEN];
285 | __u8 h_src[ETH_ALEN];
286 | #endif
287 | } __attribute__ ((packed));
288 |
289 | /* hlist[2] + tuple[]: 8+8 + 41 = 57 (less than usual cache line, 64) */
290 | struct ipt_netflow {
291 | struct hlist_node hlist; // hashtable search chain
292 |
293 | /* unique per flow data (hashed, NETFLOW_TUPLE_SIZE) */
294 | struct ipt_netflow_tuple tuple;
295 |
296 | /* volatile data */
297 | union nf_inet_addr nh;
298 | #if defined(ENABLE_MAC) || defined(ENABLE_VLAN)
299 | __be16 ethernetType; /* Network byte order */
300 | #endif
301 | __u16 o_ifc;
302 | #ifdef ENABLE_PHYSDEV
303 | __u16 i_ifphys;
304 | __u16 o_ifphys;
305 | #endif
306 | #ifdef SNMP_RULES
307 | __u16 i_ifcr; /* translated interface numbers*/
308 | __u16 o_ifcr;
309 | #endif
310 | __u8 s_mask;
311 | __u8 d_mask;
312 | __u8 tcp_flags; /* `OR' of all tcp flags */
313 | __u8 flowEndReason;
314 | #ifdef ENABLE_DIRECTION
315 | __u8 hooknumx; /* hooknum + 1 */
316 | #endif
317 | /* flow statistics */
318 | u_int32_t nr_packets;
319 | u_int32_t nr_bytes;
320 | #ifdef ENABLE_SAMPLER
321 | unsigned int sampler_count; /* for deterministic sampler only */
322 | #endif
323 | union {
324 | struct {
325 | unsigned long first;
326 | unsigned long last;
327 | } ts;
328 | ktime_t ts_obs;
329 | } _ts_un;
330 | #define nf_ts_first _ts_un.ts.first
331 | #define nf_ts_last _ts_un.ts.last
332 | #define nf_ts_obs _ts_un.ts_obs
333 | u_int32_t flow_label; /* IPv6 */
334 | u_int32_t options; /* IPv4(16) & IPv6(32) Options */
335 | u_int32_t tcpoptions;
336 | #ifdef CONFIG_NF_NAT_NEEDED
337 | __be32 s_as;
338 | __be32 d_as;
339 | struct nat_event *nat;
340 | #endif
341 | union {
342 | struct list_head list; /* all flows in ipt_netflow_list */
343 | #ifdef HAVE_LLIST
344 | struct llist_node llnode; /* purged flows */
345 | #endif
346 | } _flow_list;
347 | #define flows_list _flow_list.list
348 | #define flows_llnode _flow_list.llnode
349 | };
350 |
351 | #ifdef CONFIG_NF_NAT_NEEDED
352 | enum {
353 | NAT_CREATE = 1, NAT_DESTROY = 2, NAT_POOLEXHAUSTED = 3
354 | };
355 | struct nat_event {
356 | struct list_head list;
357 | struct {
358 | __be32 s_addr;
359 | __be32 d_addr;
360 | __be16 s_port;
361 | __be16 d_port;
362 | } pre, post;
363 | ktime_t ts_ktime;
364 | unsigned long ts_jiffies;
365 | __u8 protocol;
366 | __u8 nat_event;
367 | };
368 | #define IS_DUMMY_FLOW(nf) (nf->nat)
369 | #else
370 | #define IS_DUMMY_FLOW(nf) 0
371 | #endif
372 |
373 | static inline int ipt_netflow_tuple_equal(const struct ipt_netflow_tuple *t1,
374 | const struct ipt_netflow_tuple *t2)
375 | {
376 | return (!memcmp(t1, t2, sizeof(struct ipt_netflow_tuple)));
377 | }
378 |
379 | struct ipt_netflow_sock {
380 | struct list_head list;
381 | struct socket *sock;
382 | struct sockaddr_storage addr; // destination
383 | struct sockaddr_storage saddr; // source
384 | char sdev[IFNAMSIZ]; // source device
385 | atomic_t wmem_peak; // sk_wmem_alloc peak value
386 | unsigned int err_connect; // connect errors
387 | unsigned int err_full; // socket filled error
388 | unsigned int err_other; // other socket errors
389 | unsigned int err_cberr; // async errors, icmp
390 | unsigned int pkt_exp; // pkts expoted to this dest
391 | u64 bytes_exp; // bytes -"-
392 | u64 bytes_exp_old; // for rate calculation
393 | unsigned int bytes_rate; // bytes per second
394 | unsigned int pkt_sent; // pkts sent to this dest
395 | unsigned int pkt_fail; // pkts failed to send to this dest
396 | };
397 |
398 | struct netflow_aggr_n {
399 | struct list_head list;
400 | atomic_t usage;
401 | __u32 mask;
402 | __u32 addr;
403 | __u32 aggr_mask;
404 | __u8 prefix;
405 | };
406 |
407 | struct netflow_aggr_p {
408 | struct list_head list;
409 | atomic_t usage;
410 | __u16 port1;
411 | __u16 port2;
412 | __u16 aggr_port;
413 | };
414 |
415 | #define NETFLOW_STAT_INC(count) (__get_cpu_var(ipt_netflow_stat).count++)
416 | #define NETFLOW_STAT_ADD(count, val) (__get_cpu_var(ipt_netflow_stat).count += (unsigned long long)val)
417 | #define NETFLOW_STAT_SET(count, val) (__get_cpu_var(ipt_netflow_stat).count = (unsigned long long)val)
418 | #define NETFLOW_STAT_TS(count) \
419 | do { \
420 | ktime_t kts = ktime_get_real(); \
421 | if (!(__get_cpu_var(ipt_netflow_stat)).count.first_tv64) \
422 | __get_cpu_var(ipt_netflow_stat).count.first = kts; \
423 | __get_cpu_var(ipt_netflow_stat).count.last = kts; \
424 | } while (0);
425 |
426 | #define NETFLOW_STAT_INC_ATOMIC(count) \
427 | do { \
428 | preempt_disable(); \
429 | (__get_cpu_var(ipt_netflow_stat).count++); \
430 | preempt_enable(); \
431 | } while (0);
432 |
433 | #define NETFLOW_STAT_ADD_ATOMIC(count, val) \
434 | do { \
435 | preempt_disable(); \
436 | (__get_cpu_var(ipt_netflow_stat).count += (unsigned long long)val); \
437 | preempt_enable(); \
438 | } while (0);
439 | #define NETFLOW_STAT_READ(count) ({ \
440 | unsigned int _tmp = 0, _cpu; \
441 | for_each_present_cpu(_cpu) \
442 | _tmp += per_cpu(ipt_netflow_stat, _cpu).count; \
443 | _tmp; \
444 | })
445 |
446 | struct duration {
447 | ktime_t first;
448 | ktime_t last;
449 | };
450 |
451 | /* statistics */
452 | struct ipt_netflow_stat {
453 | u64 searched; // hash stat
454 | u64 found; // hash stat
455 | u64 notfound; // hash stat (new flows)
456 | u64 pkt_total; // packets metered
457 | u64 traf_total; // traffic metered
458 | #ifdef ENABLE_PROMISC
459 | u64 pkt_promisc; // how much packets passed promisc code
460 | u64 pkt_promisc_drop; // how much packets discarded
461 | #endif
462 | /* above is grouped for cache */
463 | unsigned int truncated; // packets stat (drop)
464 | unsigned int frags; // packets stat (drop)
465 | unsigned int maxflows_err; // maxflows reached (drop)
466 | unsigned int alloc_err; // failed to allocate memory (drop & lost)
467 | struct duration drop;
468 | unsigned int send_success; // sendmsg() ok
469 | unsigned int send_failed; // sendmsg() failed
470 | unsigned int sock_cberr; // socket error callback called (got icmp refused)
471 | unsigned int exported_rate; // netflow traffic itself
472 | u64 exported_pkt; // netflow traffic itself
473 | u64 exported_flow; // netflow traffic itself
474 | u64 exported_traf; // netflow traffic itself
475 | u64 exported_trafo; // netflow traffic itself
476 | u64 pkt_total_prev; // packets metered previous interval
477 | u32 pkt_total_rate; // packet rate for this cpu
478 | u64 pkt_drop; // packets not metered
479 | u64 traf_drop; // traffic not metered
480 | u64 flow_lost; // flows not sent to collector
481 | u64 pkt_lost; // packets not sent to collector
482 | u64 traf_lost; // traffic not sent to collector
483 | struct duration lost;
484 | u64 pkt_out; // packets out of the hash
485 | u64 traf_out; // traffic out of the hash
486 | #ifdef ENABLE_SAMPLER
487 | u64 pkts_observed; // sampler stat
488 | u64 pkts_selected; // sampler stat
489 | #endif
490 | u64 old_searched; // previous hash stat
491 | u64 old_found; // for calculation per cpu metric
492 | u64 old_notfound;
493 | int metric; // one minute ewma of hash efficiency
494 | };
495 |
496 | #endif
497 | /* vim: set sw=8: */
498 |
--------------------------------------------------------------------------------
/irqtop:
--------------------------------------------------------------------------------
1 | #!/usr/bin/ruby
2 | # SPDX-License-Identifier: GPL-2.0-only
3 | #
4 | # Observe irq and softirq in top fashion
5 | # (c) 2014
6 | # License: GPL-2.0-only.
7 |
8 | require 'getoptlong'
9 | require 'curses'
10 | require 'stringio'
11 |
12 | @imode = :both
13 | @omode = :table
14 | @color = true
15 | @showrps = false
16 |
17 | GetoptLong.new(
18 | ["--help", "-h", GetoptLong::NO_ARGUMENT],
19 | ["--batch", "-b", GetoptLong::NO_ARGUMENT],
20 | ["--delay", "-d", GetoptLong::REQUIRED_ARGUMENT],
21 | ["--top", "-t", GetoptLong::NO_ARGUMENT],
22 | ["--table", "-x", GetoptLong::NO_ARGUMENT],
23 | ["--soft", "-s", GetoptLong::NO_ARGUMENT],
24 | ["--softirq", GetoptLong::NO_ARGUMENT],
25 | ["--softirqs", GetoptLong::NO_ARGUMENT],
26 | ["--irq", "-i", GetoptLong::NO_ARGUMENT],
27 | ["--irqs", GetoptLong::NO_ARGUMENT],
28 | ["--reverse", "-r", GetoptLong::NO_ARGUMENT],
29 | ["--nocolor", "-C", GetoptLong::NO_ARGUMENT],
30 | ["--eth", "-e", "--pps", GetoptLong::NO_ARGUMENT],
31 | ["--rps", "-R", "--xps", GetoptLong::NO_ARGUMENT]
32 | ).each do |opt, arg|
33 | case opt
34 | when '--help'
35 | puts " Shows interrupt rates (per second) per cpu."
36 | puts " Also shows irq affinity ('.' for disabled cpus),"
37 | puts " and rps/xps affinity ('+' rx, '-' tx, '*' tx/rx)."
38 | puts " Can show packet rate per eth queue."
39 | puts
40 | puts " Usage: #{$0} [-h] [-d #{@delay}] [-b] [-t|-x] [-i|-s] [-r]"
41 | puts " -d --delay=n refresh interval"
42 | puts " -s --softirq select softirqs only"
43 | puts " -i --irq select hardware irqs only"
44 | puts " -e --eth show extra eth stats (from ethtool)"
45 | puts " -R --rps enable display of rps/xps"
46 | puts " -x --table output in table mode (default)"
47 | puts " -t --top output in flat top mode"
48 | puts " -b --batch output non-interactively"
49 | puts " -r --reverse reverse sort order"
50 | puts " -C --nocolor disable colors"
51 | puts
52 | puts " Rates marked as '.' is forbidden by smp_affinity mask."
53 | exit 0
54 | when '--reverse'
55 | @reverse = !@reverse
56 | when '--batch'
57 | @batch = true
58 | @reverse = !@reverse if @omode == :top
59 | when '--delay'
60 | @delay = arg.to_i
61 | when '--top'
62 | @omode = :top
63 | when '--table'
64 | @omode = :table
65 | when /--irq/
66 | @imode = :irq
67 | when /--soft/
68 | @imode = :soft
69 | when /--pps/
70 | @pps = true
71 | when /--nocolor/
72 | @color = false
73 | when /--rps/
74 | @showrps = !@showrps
75 | end
76 | end
77 | if !@delay && ARGV[0].to_f > 0
78 | @delay = ARGV.shift.to_f
79 | else
80 | @delay = 5
81 | end
82 | @count = ARGV.shift.to_f if ARGV[0].to_i > 0
83 |
84 | def read_table(tag, file)
85 | @cpus = []
86 | lines = IO.readlines(file)
87 | @cpus = lines[0].scan(/CPU\d+/)
88 | @icpus = @cpus if tag == 'i'
89 | lines[2..-1].each do |li|
90 | irq, stat, desc = li.match(/^\s*(\S+):((?:\s+\d+)+)(.*)$/).captures
91 | stat = stat.scan(/\d+/)
92 | @irqs << [tag, irq, desc]
93 | stat.each_with_index do |val, i|
94 | # interruptsN, 's|i', irq'N', 'cpuX', 'descr...'
95 | @stats << [val.to_i, tag, irq, @cpus[i], desc.strip]
96 | end
97 | end
98 | end
99 |
100 | def read_procstat
101 | @cstat = {}
102 | lines = IO.readlines("/proc/stat").grep(/^cpu\d+ /)
103 | lines.each do |li|
104 | c, *d = li.split(" ")
105 | d = d.map {|e| e.to_i}
106 | @cstat[c] = d
107 | end
108 | end
109 |
110 | def read_affinity
111 | @aff = {}
112 | Dir.glob("/proc/irq/*/smp_affinity").each do |af|
113 | irq = af[%r{\d+}].to_i
114 | a = IO.read(af).strip.to_i(16)
115 | @aff[irq] = a
116 | end
117 | end
118 |
119 | # list ethernet devices
120 | def net_devices_pci
121 | Dir['/sys/class/net/*'].reject do |f|
122 | f += "/device" unless File.symlink?(f)
123 | if File.symlink?(f)
124 | !(File.readlink(f) =~ %r{devices/pci})
125 | else
126 | false
127 | end
128 | end.map {|f| File.basename(f)}
129 | end
130 |
131 | @devlist = net_devices_pci
132 | @devre = Regexp.union(@devlist)
133 | def get_rps(desc)
134 | @rps = @xps = 0
135 | return unless @showrps
136 | return if @devlist.empty?
137 | dev = desc[/\b(#{@devre})\b/, 1]
138 | return unless dev
139 | return unless desc =~ /-(tx|rx)+-\d+/i
140 | qnr = desc[/-(\d+)\s*$/, 1]
141 | return unless qnr
142 | begin
143 | @rps = IO.read("/sys/class/net/#{dev}/queues/rx-#{qnr}/rps_cpus").hex if desc =~ /rx/i
144 | @xps = IO.read("/sys/class/net/#{dev}/queues/tx-#{qnr}/xps_cpus").hex if desc =~ /tx/i
145 | rescue
146 | end
147 | end
148 |
149 | def calc_rps(cpu)
150 | m = 0
151 | m |= 1 if @rps & (1 << cpu) != 0
152 | m |= 2 if @xps & (1 << cpu) != 0
153 | " +-*".slice(m, 1)
154 | end
155 |
156 | # ethtool -S eth0
157 | def ethtool_grab_stat(dev = nil)
158 | unless dev
159 | @esto = @est if @est
160 | @est = Hash.new { |h,k| h[k] = Hash.new(&h.default_proc) }
161 | @devlist = net_devices_pci
162 | @devre = Regexp.union(@devlist)
163 | # own time counter because this stat could be paused
164 | @ehts = @ets if @ets
165 | @ets = @ts
166 | @edt = @ets - @ehts if @ehts
167 | @devlist.each {|e| ethtool_grab_stat(e)}
168 | return
169 | end
170 | h = Hash.new {|k,v| k[v] = Array.new}
171 | t = `ethtool -S #{dev} 2>/dev/null`
172 | return if t == ''
173 | t.split("\n").map { |e|
174 | e.split(':')
175 | }.reject { |e|
176 | !e[1]
177 | }.each { |k,v|
178 | k.strip!
179 | v = v.strip.to_i
180 | if k =~ /^.x_queue_(\d+)_/
181 | t = k.split('_', 4)
182 | qdir = t[0]
183 | qnr = t[2]
184 | qk = t[3]
185 | @est[dev][qdir][qnr][qk] = v
186 | else
187 | @est[dev][k] = v
188 | end
189 | }
190 | end
191 |
192 | def e_queue_stat(dev, qdir, qnr, k)
193 | n = @est[dev][qdir][qnr][k]
194 | o = @esto[dev][qdir][qnr][k]
195 | d = (n - o) / @edt
196 | if d > 0
197 | "%s:%d" % [qdir, d]
198 | else
199 | nil
200 | end
201 | end
202 |
203 | def e_dev_stat(dev, k, ks)
204 | n = @est[dev][k]
205 | o = @esto[dev][k]
206 | r = (n - o) / @edt
207 | ks = k unless ks
208 | "%s:%d" % [ks, r]
209 | end
210 |
211 | def e_queue_stat_err(dev, qdir, qnr)
212 | r = []
213 | ek = @est[dev][qdir][qnr].keys.reject{|e| e =~ /^(bytes|packets)$/}
214 | ek.each do |k|
215 | n = @est[dev][qdir][qnr][k]
216 | o = @esto[dev][qdir][qnr][k]
217 | d = n - o
218 | r << "%s_%s:%d" % [qdir, k, d] if d.to_i > 0
219 | end
220 | r
221 | end
222 |
223 | # this is not rate
224 | def e_dev_stat_sum(dev, rk, ks)
225 | ek = @est[dev].keys.reject{|ek| !(ek =~ rk)}
226 | n = ek.inject(0) {|sum,k| sum += @est[dev][k].to_i}
227 | o = ek.inject(0) {|sum,k| sum += @esto[dev][k].to_i rescue 0}
228 | r = (n - o)
229 | if r > 0
230 | "%s:%d" % [ks, r]
231 | else
232 | nil
233 | end
234 | end
235 |
236 | def print_ethstat(desc)
237 | return if @devlist.empty?
238 | dev = desc[/\b(#{@devre})\b/, 1]
239 | return unless dev
240 | unless @esto && @est
241 | print ' []'
242 | return
243 | end
244 | t = []
245 | if desc =~ /-(tx|rx)+-\d+/i
246 | qnr = desc[/-(\d+)\s*$/, 1]
247 | if qnr
248 | if desc =~ /rx/i
249 | t << e_queue_stat(dev, "rx", qnr, "packets")
250 | t += e_queue_stat_err(dev, "rx", qnr)
251 | end
252 | if desc =~ /tx/i
253 | t << e_queue_stat(dev, "tx", qnr, "packets")
254 | t += e_queue_stat_err(dev, "tx", qnr)
255 | end
256 | end
257 | else
258 | t << e_dev_stat(dev, "rx_packets", 'rx')
259 | t << e_dev_stat(dev, "tx_packets", 'tx')
260 | t << e_dev_stat_sum(dev, /_err/, 'err')
261 | t << e_dev_stat_sum(dev, /_drop/, 'drop')
262 | end
263 | t.delete(nil)
264 | print ' [' + t.join(' ') + ']'
265 | end
266 |
267 | def grab_stat
268 | # @h[istorical]
269 | @hstats = @stats
270 | @hcstat = @cstat
271 | @hts = @ts
272 |
273 | @stats = []
274 | @irqs = []
275 | @ts = Time.now
276 | @dt = @ts - @hts if @hts
277 |
278 | read_table 'i', "/proc/interrupts"
279 | read_table 's', "/proc/softirqs"
280 | read_affinity
281 | read_procstat
282 | ethtool_grab_stat if @pps
283 | end
284 |
285 | def calc_speed
286 | s = []
287 | # calc speed
288 | h = Hash.new(0)
289 | @hstats.each do |v, t, i, c, d|
290 | h[[t, i, c]] = v
291 | end
292 | # output
293 | @h = {}
294 | @t = Hash.new(0) # rate per cpu
295 | @w = Hash.new(0) # irqs per irqN
296 | @s = @stats.map do |v, t, i, c, d|
297 | rate = (v - h[[t, i, c]]) / @dt
298 | @t[c] += rate if t == 'i'
299 | @w[[t, i]] += (v - h[[t, i, c]])
300 | @h[[t, i, c]] = rate
301 | [rate, v, t, i, c, d]
302 | end
303 | end
304 |
305 | def calc_cpu
306 | @cBusy = Hash.new(0)
307 | @cHIrq = Hash.new(0)
308 | @cSIrq = Hash.new(0)
309 | # user, nice, system, [3] idle, [4] iowait, irq, softirq, etc.
310 | @cstat.each do |c, d|
311 | d = d.zip(@hcstat[c]).map {|a, b| a - b}
312 | c = c.upcase
313 | sum = d.reduce(:+)
314 | @cBusy[c] = 100 - (d[3] + d[4]).to_f / sum * 100
315 | @cHIrq[c] = (d[5]).to_f / sum * 100
316 | @cSIrq[c] = (d[6]).to_f / sum * 100
317 | end
318 | end
319 |
320 | def show_top
321 | @s.sort!.reverse!
322 | @s.reverse! if @reverse
323 | rej = nil
324 | rej = 's' if @imode == :irq
325 | rej = 'i' if @imode == :soft
326 | @s.each do |s, v, t, i, c, d|
327 | next if t == rej
328 | if s > 0
329 | print "%9.1f %s %s <%s> %s" % [s, c.downcase, t, i, d]
330 | print_ethstat(d) if @pps
331 | puts
332 | end
333 | end
334 | end
335 |
336 | @ifilter = {}
337 | def show_interrupts
338 | maxlen = 7
339 | @irqs.reverse! if @reverse
340 | print "%s %*s " % [" ", maxlen, " "]
341 | @icpus.each { |c| print " %6s" % c }
342 | puts
343 |
344 | # load
345 | print "%*s: " % [maxlen + 2, "cpuUtil"]
346 | @icpus.each { |c| print " %6.1f" % @cBusy[c] }
347 | puts " total CPU utilization %"
348 | #
349 | print "%*s: " % [maxlen + 2, "%irq"]
350 | @icpus.each { |c| print " %6.1f" % @cHIrq[c] }
351 | puts " hardware IRQ CPU util%"
352 | print "%*s: " % [maxlen + 2, "%sirq"]
353 | @icpus.each { |c| print " %6.1f" % @cSIrq[c] }
354 | puts " software IRQ CPU util%"
355 |
356 | # total
357 | print "%*s: " % [maxlen + 2, "irqTotal"]
358 | @icpus.each { |c| print " %6d" % @t[c] }
359 | puts " total hardware IRQs"
360 |
361 | rej = nil
362 | rej = 's' if @imode == :irq
363 | rej = 'i' if @imode == :soft
364 | @irqs.each do |t, i, desc|
365 | next if t == rej
366 |
367 | # include incrementally and all eth
368 | unless @ifilter[[t, i]] || @showall
369 | next unless @w[[t, i]] > 0 || desc =~ /eth/
370 | @ifilter[[t, i]] = true
371 | end
372 |
373 | print "%s %*s: " % [t.to_s, maxlen, i.slice(0, maxlen)]
374 | rps = get_rps(desc)
375 | @icpus.each do |c|
376 | cpu = c[/\d+/].to_i
377 | aff = @aff[i.to_i]
378 | off = ((aff & 1 << cpu) ==0)? true : false if aff
379 | fla = calc_rps(cpu)
380 | begin
381 | v = @h[[t, i, c]]
382 | if v > 0 || !off
383 | print "%6d%c" % [v, fla]
384 | elsif aff
385 | print "%6s%c" % [".", fla]
386 | end
387 | rescue
388 | end
389 | end
390 | print desc
391 | print_ethstat(desc) if @pps
392 | puts
393 | end
394 | end
395 |
396 | def select_output
397 | if @omode == :top
398 | show_top
399 | else
400 | show_interrupts
401 | end
402 | end
403 |
404 | def curses_choplines(text)
405 | cols = Curses.cols - 1
406 | rows = Curses.lines - 2
407 | lines = text.split("\n").map {|e| e.slice(0, cols)}.slice(0, rows)
408 | text = lines.join("\n")
409 | text << "\n" * (rows - lines.size) if lines.size < rows
410 | text
411 | end
412 |
413 | def show_help
414 | puts "irqtop help:"
415 | puts
416 | puts " In table view, cells marked with '.' mean this hw irq is"
417 | puts " disabled via /proc/irq//smp_affinity"
418 | puts " Interactive keys:"
419 | puts " i Toggle (hardware) irqs view"
420 | puts " s Toggle software irqs (softirqs) view"
421 | puts " e Show eth stat per queue"
422 | puts " R Show rps/xps affinity"
423 | puts " t Flat top display mode"
424 | puts " x Table display mode"
425 | puts " r Reverse rows order"
426 | puts " c Toggle colors (for eth)"
427 | puts " a Show lines with zero rate (all)"
428 | puts " A Clear lines with zero rates"
429 | puts " . Pause screen updating"
430 | puts " h,? This help screen"
431 | puts " q Quit."
432 | puts " Any other key will update display."
433 | puts
434 | puts "Press any key to continue."
435 | end
436 |
437 | hostname = `hostname`.strip
438 | #
439 | grab_stat
440 | sleep 0.5
441 |
442 | COLOR_GREEN = "\033[0;32m"
443 | COLOR_YELLOW = "\033[0;33m"
444 | COLOR_CYAN = "\033[0;36m"
445 | COLOR_RED = "\033[0;31m"
446 | COLOR_OFF = "\033[m"
447 | def tty_printline(t)
448 | latr = nil # line color
449 | if t =~ /-rx-/
450 | latr = COLOR_GREEN
451 | elsif t =~ /-tx-/
452 | latr = COLOR_YELLOW
453 | elsif t =~ /\beth/
454 | latr = COLOR_CYAN
455 | end
456 | print latr if latr
457 |
458 | if t =~ /cpuUtil:|irq:|sirq:/
459 | # colorize percentage values
460 | t.scan(/\s+\S+/) do |e|
461 | eatr = nil
462 | if e =~ /^\s*[\d.]+$/
463 | if e.to_i >= 90
464 | eatr = COLOR_RED
465 | elsif e.to_i <= 10
466 | eatr = COLOR_GREEN
467 | else
468 | eatr = COLOR_YELLOW
469 | end
470 | end
471 | print eatr if eatr
472 | print e
473 | print (latr)? latr : COLOR_OFF if eatr
474 | end
475 | elsif latr && t =~ / \[[^\]]+\]$/
476 | # colorize eth stats
477 | print $`
478 | print COLOR_OFF if latr
479 | $&.scan(/(.*?)(\w+)(:)(\d+)/) do |e|
480 | eatr = nil
481 | case e[1]
482 | when 'rx'
483 | eatr = COLOR_GREEN
484 | when 'tx'
485 | eatr = COLOR_YELLOW
486 | else
487 | eatr = COLOR_RED
488 | end
489 | eatr = nil if e[3].to_i == 0
490 |
491 | print e[0]
492 | print eatr if eatr
493 | print e[1..-1].join
494 | print (latr)? latr : COLOR_OFF if eatr
495 | end
496 | print $'
497 | else
498 | print t
499 | end
500 |
501 | print COLOR_OFF if latr
502 | puts
503 | end
504 | def tty_output
505 | if @color
506 | $stdout = StringIO.new
507 | yield
508 | $stdout.rewind
509 | txt = $stdout.read
510 | $stdout = STDOUT
511 |
512 | txt.split("\n", -1).each do |li|
513 | tty_printline(li)
514 | end
515 | else
516 | yield
517 | end
518 | end
519 |
520 | if @batch
521 | @color = @color && $stdout.tty?
522 | loop do
523 | grab_stat
524 | calc_speed
525 | calc_cpu
526 | puts "#{hostname} - irqtop - #{Time.now}"
527 | tty_output {
528 | select_output
529 | }
530 | $stdout.flush
531 | break if @count && (@count -= 1) == 0
532 | sleep @delay
533 | end
534 | exit 0
535 | end
536 |
537 | Curses.init_screen
538 | Curses.start_color
539 | Curses.cbreak
540 | Curses.noecho
541 | Curses.nonl
542 | Curses.init_pair(1, Curses::COLOR_GREEN, Curses::COLOR_BLACK);
543 | Curses.init_pair(2, Curses::COLOR_YELLOW, Curses::COLOR_BLACK);
544 | Curses.init_pair(3, Curses::COLOR_CYAN, Curses::COLOR_BLACK);
545 | Curses.init_pair(4, Curses::COLOR_RED, Curses::COLOR_BLACK);
546 | $stdscr = Curses.stdscr
547 | $stdscr.keypad(true)
548 |
549 | def curses_printline(t)
550 | latr = nil # line color
551 | if t =~ /-rx-/
552 | latr = Curses.color_pair(1)
553 | elsif t =~ /-tx-/
554 | latr = Curses.color_pair(2)
555 | elsif t =~ /\beth/
556 | latr = Curses.color_pair(3)
557 | end
558 | $stdscr.attron(latr) if latr
559 |
560 | if t =~ /cpuUtil:|irq:|sirq:/
561 | # colorize percentage values
562 | t.scan(/\s+\S+/) do |e|
563 | eatr = nil
564 | if e =~ /^\s*[\d.]+$/
565 | if e.to_i >= 90
566 | eatr = Curses.color_pair(4)
567 | elsif e.to_i <= 10
568 | eatr = Curses.color_pair(1)
569 | else
570 | eatr = Curses.color_pair(2)
571 | end
572 | end
573 | $stdscr.attron(eatr) if eatr
574 | $stdscr.addstr("#{e}")
575 | $stdscr.attroff(eatr) if eatr
576 | end
577 | elsif latr && t =~ / \[[^\]]+\]$/
578 | # colorize eth stats
579 | $stdscr.addstr($`)
580 | $stdscr.attroff(latr) if latr
581 | $&.scan(/(.*?)(\w+)(:)(\d+)/) do |e|
582 | eatr = nil
583 | case e[1]
584 | when 'rx'
585 | eatr = Curses.color_pair(1)
586 | when 'tx'
587 | eatr = Curses.color_pair(2)
588 | else
589 | eatr = Curses.color_pair(4)
590 | end
591 | eatr = nil if e[3].to_i == 0
592 |
593 | $stdscr.addstr(e[0])
594 | $stdscr.attron(eatr) if eatr
595 | $stdscr.addstr(e[1..-1].join)
596 | $stdscr.attroff(eatr) if eatr
597 | end
598 | $stdscr.addstr($' + "\n")
599 | else
600 | $stdscr.addstr("#{t}\n")
601 | end
602 |
603 | $stdscr.attroff(latr) if latr
604 | end
605 |
606 | def curses_output
607 | $stdout = StringIO.new
608 | yield
609 | $stdout.rewind
610 | text = $stdout.read
611 | $stdout = STDOUT
612 | txt = curses_choplines(text)
613 | if @color
614 | txt.split("\n", -1).each_with_index do |li, i|
615 | $stdscr.setpos(i, 0)
616 | curses_printline(li)
617 | end
618 | else
619 | $stdscr.setpos(0, 0)
620 | $stdscr.addstr(txt)
621 | end
622 | $stdscr.setpos(1, 0)
623 | Curses.refresh
624 | end
625 |
626 | def curses_enter(text, echo = true)
627 | $stdscr.setpos(1, 0)
628 | $stdscr.addstr(text + "\n")
629 | $stdscr.setpos(1, 0)
630 | Curses.attron(Curses::A_BOLD)
631 | $stdscr.addstr(text)
632 | Curses.attroff(Curses::A_BOLD)
633 | Curses.refresh
634 | Curses.echo if echo
635 | Curses.timeout = -1
636 | line = Curses.getstr
637 | Curses.noecho
638 | line
639 | end
640 |
641 | loop do
642 | grab_stat
643 | calc_speed
644 | calc_cpu
645 |
646 | curses_output {
647 | puts "#{hostname} - irqtop - #{Time.now}"
648 | select_output
649 | }
650 |
651 | Curses.timeout = @delay * 1000
652 | ch = Curses.getch.chr rescue nil
653 | case ch
654 | when "\f"
655 | Curses.clear
656 | when "q", "Z", "z"
657 | break
658 | when 'i'
659 | @imode = (@imode == :both)? :soft : :both
660 | when 's'
661 | @imode = (@imode == :both)? :irq : :both
662 | when 't'
663 | @omode = (@omode == :top)? :table : :top
664 | when 'x'
665 | @omode = (@omode == :table)? :top : :table
666 | when 'e', 'p'
667 | @pps = !@pps
668 | when 'r'
669 | @reverse = !@reverse
670 | when 'c'
671 | @color = !@color
672 | when 'A'
673 | @ifilter = {}
674 | when 'a'
675 | @ifilter = {}
676 | @showall = !@showall
677 | when 'R'
678 | @showrps = !@showrps
679 | when '.'
680 | curses_enter("Pause, press enter to to continue: ", false)
681 | when 'd'
682 | d = curses_enter("Enter display interval: ")
683 | @delay = d.to_f if d.to_f > 0
684 | when 'h', '?'
685 | curses_output { show_help }
686 | Curses.timeout = -1
687 | ch = Curses.getch.chr rescue nil
688 | break if ch == 'q'
689 | end
690 | end
691 |
692 |
--------------------------------------------------------------------------------
/libipt_NETFLOW.c:
--------------------------------------------------------------------------------
1 | /* SPDX-License-Identifier: GPL-2.0-only
2 | *
3 | * iptables helper for NETFLOW target
4 | *
5 | *
6 | *
7 | * This file is part of NetFlow exporting module.
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU General Public License as published by
11 | * the Free Software Foundation, either version 2 of the License, or
12 | * (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU General Public License
20 | * along with this program. If not, see .
21 | *
22 | */
23 |
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 |
33 | #define __EXPORTED_HEADERS__
34 | #ifdef XTABLES
35 | #include
36 | #else
37 | #include
38 | #endif
39 |
40 | #ifdef XTABLES_VERSION_CODE // since 1.4.1
41 | #define MOD140
42 | #define iptables_target xtables_target
43 | #endif
44 |
45 | #ifdef iptables_target // only in 1.4.0
46 | #define MOD140
47 | #endif
48 |
49 | #ifdef MOD140
50 | #define ipt_entry_target xt_entry_target
51 | #define register_target xtables_register_target
52 | #define _IPT_ENTRY void
53 | #define _IPT_IP void
54 | #ifndef IPT_ALIGN
55 | #define IPT_ALIGN XT_ALIGN
56 | #endif
57 | #else // before 1.3.x
58 | #define _IPT_ENTRY struct ipt_entry
59 | #define _IPT_IP struct ipt_ip
60 | #endif
61 |
62 | #ifndef IPTABLES_VERSION
63 | #define IPTABLES_VERSION XTABLES_VERSION
64 | #endif
65 |
66 | static struct option opts[] = {
67 | { 0 }
68 | };
69 |
70 | static void help(void)
71 | {
72 | printf("NETFLOW target\n");
73 | }
74 |
75 | static int parse(int c, char **argv, int invert, unsigned int *flags,
76 | const _IPT_ENTRY *entry,
77 | struct ipt_entry_target **targetinfo)
78 |
79 | {
80 | return 1;
81 | }
82 |
83 | static void final_check(unsigned int flags)
84 | {
85 | }
86 |
87 | static void save(const _IPT_IP *ip, const struct ipt_entry_target *match)
88 | {
89 | }
90 |
91 | static void print(const _IPT_IP *ip,
92 | const struct ipt_entry_target *target,
93 | int numeric)
94 | {
95 | printf("NETFLOW ");
96 | }
97 |
98 | static struct iptables_target netflow = {
99 | .next = NULL,
100 | .name = "NETFLOW",
101 | .version = IPTABLES_VERSION,
102 | .size = IPT_ALIGN(0),
103 | .userspacesize = IPT_ALIGN(0),
104 | .help = &help,
105 | .parse = &parse,
106 | .final_check = &final_check,
107 | .print = &print,
108 | .save = &save,
109 | .extra_opts = opts
110 | };
111 |
112 | #ifndef _init
113 | #define _init __attribute__((constructor)) _INIT
114 | #endif
115 | void _init(void)
116 | {
117 | register_target(&netflow);
118 | }
119 |
--------------------------------------------------------------------------------
/murmur3.h:
--------------------------------------------------------------------------------
1 | /* MurmurHash3, based on https://code.google.com/p/smhasher of Austin Appleby. */
2 |
3 | static __always_inline uint32_t rotl32(const uint32_t x, const int8_t r)
4 | {
5 | return (x << r) | (x >> (32 - r));
6 | }
7 |
8 | static __always_inline uint32_t fmix32(register uint32_t h)
9 | {
10 | h ^= h >> 16;
11 | h *= 0x85ebca6b;
12 | h ^= h >> 13;
13 | h *= 0xc2b2ae35;
14 | h ^= h >> 16;
15 | return h;
16 | }
17 |
18 | static inline uint32_t murmur3(const void *key, const uint32_t len, const uint32_t seed)
19 | {
20 | const uint32_t c1 = 0xcc9e2d51;
21 | const uint32_t c2 = 0x1b873593;
22 | const uint32_t *blocks;
23 | const uint8_t *tail;
24 | register uint32_t h1 = seed;
25 | uint32_t k1 = 0;
26 | uint32_t i;
27 |
28 | blocks = (const uint32_t *)key;
29 | for (i = len / 4; i; --i) {
30 | h1 ^= rotl32(*blocks++ * c1, 15) * c2;
31 | h1 = rotl32(h1, 13) * 5 + 0xe6546b64;
32 | }
33 | tail = (const uint8_t*)blocks;
34 | switch (len & 3) {
35 | case 3: k1 ^= tail[2] << 16; fallthrough;
36 | case 2: k1 ^= tail[1] << 8; fallthrough;
37 | case 1: k1 ^= tail[0];
38 | h1 ^= rotl32(k1 * c1, 15) * c2;
39 | }
40 | return fmix32(h1^ len);
41 | }
42 |
43 |
--------------------------------------------------------------------------------
/openwrt/Makefile:
--------------------------------------------------------------------------------
1 | include $(TOPDIR)/rules.mk
2 | include $(INCLUDE_DIR)/kernel.mk
3 |
4 | PKG_NAME:=ipt-netflow
5 | PKG_RELEASE:=2
6 |
7 | PKG_SOURCE_URL:=https://github.com/aabc/$(PKG_NAME).git
8 | PKG_VERSION:=2.5.1
9 | PKG_SOURCE_VERSION:=v$(PKG_VERSION)
10 |
11 | #TO BUILD development version uncomment 2 rows below and remove patches
12 | #PKG_VERSION:=$(shell (git ls-remote $(PKG_SOURCE_URL) | grep refs/heads/master | cut -f 1 | head -c 7))
13 | #PKG_SOURCE_VERSION:=HEAD
14 |
15 | PKG_SOURCE_PROTO:=git
16 | PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
17 |
18 | PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
19 |
20 | PKG_BUILD_DIR := $(KERNEL_BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
21 | PKG_DEPENDS:=iptables
22 |
23 | include $(INCLUDE_DIR)/package.mk
24 |
25 |
26 | define KernelPackage/ipt-netflow
27 | SECTION:=net
28 | CATEGORY:=Network
29 | SUBMENU:=Netflow
30 | TITLE:=Netflow iptables module for Linux kernel
31 | URL:=http://ipt-netflow.sourceforge.net/
32 | FILES:=$(PKG_BUILD_DIR)/ipt_NETFLOW.ko
33 | DEPENDS:=+iptables +iptables-mod-netflow
34 | endef
35 |
36 |
37 | define Package/iptables-mod-netflow
38 | SECTION:=net
39 | CATEGORY:=Network
40 | SUBMENU:=Netflow
41 | TITLE:=Netflow iptables module for Linux kernel
42 | URL:=http://ipt-netflow.sourceforge.net/
43 | #DEPENDS:=+kmod-ipt-netflow
44 | DEPENDS:=+iptables
45 | endef
46 |
47 | CONFIGURE_ARGS:= \
48 | --kdir="$(LINUX_DIR)"
49 |
50 | define Package/iptables-mod-netflow/config
51 | menu "Configuration"
52 | depends on PACKAGE_iptables-mod-netflow
53 | config PACKAGE_iptables-mod-netflow_natevents
54 | bool "enables natevents support"
55 | default n
56 | config PACKAGE_iptables-mod-netflow_snmp-rules
57 | bool "enables SNMP-index conversion rules"
58 | default n
59 | config PACKAGE_iptables-mod-netflow_macaddress
60 | bool "enables MAC address for v9/IPFIX"
61 | default n
62 | config PACKAGE_iptables-mod-netflow_vlan
63 | bool "enables VLAN Ids for v9/IPFIX"
64 | default n
65 | config PACKAGE_iptables-mod-netflow_direction
66 | bool "enables flowDirection(61) Element"
67 | default n
68 | config PACKAGE_iptables-mod-netflow_sampler
69 | bool "enables Flow Sampling"
70 | default n
71 | config PACKAGE_iptables-mod-netflow_aggregation
72 | bool "enables aggregation rules"
73 | default n
74 | config PACKAGE_iptables-mod-netflow_promisc
75 | bool "enables promisc hack mode"
76 | default n
77 | config PACKAGE_iptables-mod-netflow_promisc-mpls
78 | bool "decapsulate MPLS in promisc mode"
79 | default n
80 | config PACKAGE_iptables-mod-netflow_physdev
81 | bool "enables physdev reporting"
82 | default n
83 | config PACKAGE_iptables-mod-netflow_physdev-override
84 | bool "to override interfaces"
85 | default n
86 | config PACKAGE_iptables-mod-netflow_snmp-agent
87 | bool "disables net-snmp agent"
88 | default y
89 | config PACKAGE_iptables-mod-netflow_dkms
90 | bool "disables DKMS support completely"
91 | default y
92 | config PACKAGE_iptables-mod-netflow_dkms-install
93 | bool "no DKMS install but still create dkms.conf"
94 | default n
95 | endmenu
96 | endef
97 |
98 | CONFIGURE_ARGS += \
99 | $(if $(CONFIG_PACKAGE_iptables-mod-netflow_natevents),--enable-natevents) \
100 | $(if $(CONFIG_PACKAGE_iptables-mod-netflow_snmp-rules),--enable-snmp-rules) \
101 | $(if $(CONFIG_PACKAGE_iptables-mod-netflow_macaddress),--enable-macaddress) \
102 | $(if $(CONFIG_PACKAGE_iptables-mod-netflow_vlan),--enable-vlan) \
103 | $(if $(CONFIG_PACKAGE_iptables-mod-netflow_direction),--enable-direction) \
104 | $(if $(CONFIG_PACKAGE_iptables-mod-netflow_sampler),--enable-sampler) \
105 | $(if $(CONFIG_PACKAGE_iptables-mod-netflow_aggregation),--enable-aggregation) \
106 | $(if $(CONFIG_PACKAGE_iptables-mod-netflow_promisc),--enable-promisc) \
107 | $(if $(CONFIG_PACKAGE_iptables-mod-netflow_promisc-mpls),--promisc-mpls) \
108 | $(if $(CONFIG_PACKAGE_iptables-mod-netflow_physdev),--enable-physdev) \
109 | $(if $(CONFIG_PACKAGE_iptables-mod-netflow_physdev-override),--enable-physdev-override) \
110 | $(if $(CONFIG_PACKAGE_iptables-mod-netflow_snmp-agent),--disable-snmp-agent) \
111 | $(if $(CONFIG_PACKAGE_iptables-mod-netflow_dkms),--disable-dkms) \
112 | $(if $(CONFIG_PACKAGE_iptables-mod-netflow_dkms-install),--disable-dkms-install)
113 |
114 | #TODO: --enable-sampler=hash --promisc-mpls=N
115 |
116 |
117 | $(eval $(call KernelPackage,ipt-netflow))
118 |
119 | $(eval $(call Package,kmod-ipt-netflow))
120 |
121 | define Package/iptables-mod-netflow/install
122 | $(MAKE) -C $(PKG_BUILD_DIR) DESTDIR=$(1) linstall
123 | #TODO: snmp install, dkms install
124 | endef
125 |
126 | $(eval $(call BuildPackage,iptables-mod-netflow))
127 |
--------------------------------------------------------------------------------
/openwrt/Readme.md:
--------------------------------------------------------------------------------
1 | Cross-compiling and packages for openwrt
2 | ===
3 |
4 | Place Makefile in `packages/network/ipt-netflow` directory in OpenWRT bouldroot.
5 | Run `make menuconfig` and select package in Network/Netflow menu. Configure args partially supported.
6 |
7 | Run `make` to build full firmware or `make package/network/ipt-netflow/{clean,prepare,configure,compile,install}` to rebuild packages.
8 |
9 | To make git version uncomment two lines in Makefile.
10 |
11 | Tested to work on Chaos Calmer and Designated Driver with Atheros AR7xxx/AR9xxx target.
12 |
13 | For ipt-netflow 2.2 patches are needed, drop it for next version or git master to build.
14 |
15 | Making and installilng
16 | ===
17 |
18 | ```shell
19 | mkdir debian-toolchain
20 | sudo debootstrap jessie debian-toolchain
21 | sudo chroot debian-toolchain
22 |
23 | . /etc/profile
24 | apt update
25 | apt install git ssh-client build-essential mercurial subversion \
26 | binutils flex bzip2 asciidoc ncurses-dev libssl-dev gawk zlib1g-dev fastjar
27 |
28 | adduser user
29 | su user
30 | . /etc/profile
31 | cd ~
32 |
33 | git clone https://github.com/openwrt/openwrt.git openwrt-trunk
34 | git clone https://github.com/aabc/ipt-netflow.git
35 |
36 | cd openwrt-trunk
37 | ./scripts/feeds update -a
38 | ln -s ~/ipt-netflow/openwrt/ package/network/ipt-netflow
39 |
40 |
41 | make menuconfig
42 | #select target and device
43 | #go to network/netflow and check both
44 |
45 | make
46 | #and go for dinner or a walk ;)
47 | #after five hours
48 |
49 | scp bin/ar71xx/packages/kernel/kmod-ipt-netflow_4.4.14+2.2-2_ar71xx.ipk \
50 | root@192.168.236.79:/tmp/
51 | scp bin/ar71xx/packages/base/iptables-mod-netflow_2.2-2_ar71xx.ipk \
52 | root@192.168.236.79:/tmp/
53 | scp bin/ar71xx/packages/base/kernel_4.4.14-1-abf9cc6feb410252d667326556dae184_ar71xx.ipk \
54 | root@192.168.236.79:/tmp/
55 |
56 | #goto router
57 | ssh root@192.168.236.79
58 |
59 | opkg install /tmp/*.ipk
60 |
61 | insmod /lib/modules/4.4.14/ipt_NETFLOW.ko
62 | sysctl -w net.netflow.protocol=5
63 | sysctl -w net.netflow.destination=192.168.236.34:2055
64 |
65 | iptables -I FORWARD -j NETFLOW
66 | iptables -I INPUT -j NETFLOW
67 | iptables -I OUTPUT -j NETFLOW
68 |
69 | ```
70 |
--------------------------------------------------------------------------------
/openwrt/patches/310-Makefile_crosscompile.patch:
--------------------------------------------------------------------------------
1 | Index: ipt-netflow-2.2/Makefile.in
2 | ===================================================================
3 | --- ipt-netflow-2.2.orig/Makefile.in
4 | +++ ipt-netflow-2.2/Makefile.in
5 | @@ -64,10 +64,10 @@ sinstall: | snmp_NETFLOW.so IPT-NETFLOW-
6 | fi
7 |
8 | %_sh.o: libipt_NETFLOW.c
9 | - gcc -O2 -Wall -Wunused $(IPTABLES_CFLAGS) -fPIC -o $@ -c libipt_NETFLOW.c
10 | + $(CC) $(CFLAGS) -O2 -Wall -Wunused $(IPTABLES_CFLAGS) -fPIC -o $@ -c libipt_NETFLOW.c
11 |
12 | %.so: %_sh.o
13 | - gcc -shared -o $@ $<
14 | + $(CC) -shared -o $@ $<
15 |
16 | version.h: ipt_NETFLOW.c ipt_NETFLOW.h compat.h Makefile
17 | @./version.sh --define > version.h
18 |
--------------------------------------------------------------------------------
/raw_promisc.patch:
--------------------------------------------------------------------------------
1 |
2 | This simple hack will allow to see promisc traffic in raw table of
3 | iptables. Of course you will need to enable promisc on the interface.
4 | Refer to README.promisc for details.
5 |
6 | Example how to catch desired traffic:
7 | iptables -A PREROUTING -t raw -i eth2 -j NETFLOW
8 |
9 |
10 | --- linux-2.6.26/net/ipv4/ip_input.old.c 2008-07-14 01:51:29.000000000 +0400
11 | +++ linux-2.6.26/net/ipv4/ip_input.c 2008-08-06 14:02:16.000000000 +0400
12 | @@ -378,12 +378,6 @@
13 | struct iphdr *iph;
14 | u32 len;
15 |
16 | - /* When the interface is in promisc. mode, drop all the crap
17 | - * that it receives, do not try to analyse it.
18 | - */
19 | - if (skb->pkt_type == PACKET_OTHERHOST)
20 | - goto drop;
21 | -
22 | IP_INC_STATS_BH(IPSTATS_MIB_INRECEIVES);
23 |
24 | if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
25 |
--------------------------------------------------------------------------------
/raw_promisc_debian_squeeze6.patch:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aabc/ipt-netflow/d46ef265f2084eb92daa5d59f9a11df85c809357/raw_promisc_debian_squeeze6.patch
--------------------------------------------------------------------------------
/snmp_NETFLOW.c:
--------------------------------------------------------------------------------
1 | /* SPDX-License-Identifier: GPL-2.0-only
2 | *
3 | * dlmod plugin for net-snmp for monitoring
4 | * ipt_NETFLOW module via IPT-NETFLOW-MIB.
5 | *
6 | * (c) 2014
7 | *
8 | * This program is free software; you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License version 2 as
10 | * published by the Free Software Foundation.
11 | */
12 |
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | #include
20 | #include
21 | #include
22 |
23 | #define iptNetflowMIB_oid 1, 3, 6, 1, 4, 1, 37476, 9000, 10, 1 /* .1.3.6.1.4.1.37476.9000.10.1 */
24 |
25 | /* iptNetflowObjects */
26 | static oid iptNetflowModule_oid[] = { iptNetflowMIB_oid, 1, 1 };
27 | static oid iptNetflowSysctl_oid[] = { iptNetflowMIB_oid, 1, 2 };
28 | /* iptNetflowStatistics */
29 | static oid iptNetflowTotals_oid[] = { iptNetflowMIB_oid, 2, 1 };
30 | static oid iptNetflowCpuTable_oid[] = { iptNetflowMIB_oid, 2, 2 };
31 | static oid iptNetflowSockTable_oid[] = { iptNetflowMIB_oid, 2, 3 };
32 |
33 | struct snmp_vars {
34 | int obj;
35 | int type;
36 | char *name;
37 |
38 | time_t ts; /* when value last read */
39 | long long val64;
40 | };
41 |
42 | struct snmp_vars modinfos[] = {
43 | {1, ASN_OCTET_STR, "name"},
44 | {2, ASN_OCTET_STR, "version"},
45 | {3, ASN_OCTET_STR, "srcversion"},
46 | {4, ASN_OCTET_STR, "loadTime"}, /* DateAndTime */
47 | {5, ASN_INTEGER, "refcnt"},
48 | { 0 }
49 | };
50 | #define MODINFO_NAME "ipt_NETFLOW"
51 | #define MODINFO_NAME_ID 1
52 | #define MODINFO_DATE_ID 4
53 |
54 | struct snmp_vars sysctls[] = {
55 | {1, ASN_INTEGER, "protocol"},
56 | {2, ASN_INTEGER, "hashsize"},
57 | {3, ASN_INTEGER, "maxflows"},
58 | {4, ASN_INTEGER, "active_timeout"},
59 | {5, ASN_INTEGER, "inactive_timeout"},
60 | {6, ASN_INTEGER, "sndbuf"},
61 | {7, ASN_OCTET_STR, "destination"},
62 | {8, ASN_OCTET_STR, "aggregation"},
63 | {9, ASN_OCTET_STR, "sampler"},
64 | {10, ASN_INTEGER, "natevents"},
65 | {11, ASN_INTEGER, "promisc"},
66 | {12, ASN_OCTET_STR, "snmp-rules"},
67 | {13, ASN_INTEGER, "scan-min"},
68 | { 0 }
69 | };
70 |
71 | struct snmp_vars totals[] = {
72 | {1, ASN_COUNTER64, "inBitRate"},
73 | {2, ASN_GAUGE, "inPacketRate"},
74 | {3, ASN_COUNTER64, "inFlows"},
75 | {4, ASN_COUNTER64, "inPackets"},
76 | {5, ASN_COUNTER64, "inBytes"},
77 | {6, ASN_GAUGE, "hashMetric"},
78 | {7, ASN_GAUGE, "hashMemory"},
79 | {8, ASN_GAUGE, "hashFlows"},
80 | {9, ASN_GAUGE, "hashPackets"},
81 | {10, ASN_COUNTER64, "hashBytes"},
82 | {11, ASN_COUNTER64, "dropPackets"},
83 | {12, ASN_COUNTER64, "dropBytes"},
84 | {13, ASN_GAUGE, "outByteRate"},
85 | {14, ASN_COUNTER64, "outFlows"},
86 | {15, ASN_COUNTER64, "outPackets"},
87 | {16, ASN_COUNTER64, "outBytes"},
88 | {17, ASN_COUNTER64, "lostFlows"},
89 | {18, ASN_COUNTER64, "lostPackets"},
90 | {19, ASN_COUNTER64, "lostBytes"},
91 | {20, ASN_COUNTER, "errTotal"},
92 | {21, ASN_COUNTER, "sndbufPeak"},
93 | { 0 }
94 | };
95 | #define TOTALS_METRIC_ID 6
96 |
97 | static netsnmp_table_data_set *cpu_data_set;
98 | static netsnmp_cache *stat_cache = NULL;
99 |
100 | struct snmp_vars cputable[] = {
101 | {1, ASN_INTEGER, "cpuIndex"},
102 | {2, ASN_GAUGE, "cpuInPacketRate"},
103 | {3, ASN_COUNTER64, "cpuInFlows"},
104 | {4, ASN_COUNTER64, "cpuInPackets"},
105 | {5, ASN_COUNTER64, "cpuInBytes"},
106 | {6, ASN_GAUGE, "cpuHashMetric"},
107 | {7, ASN_COUNTER64, "cpuDropPackets"},
108 | {8, ASN_COUNTER64, "cpuDropBytes"},
109 | {9, ASN_COUNTER, "cpuErrTrunc"},
110 | {10, ASN_COUNTER, "cpuErrFrag"},
111 | {11, ASN_COUNTER, "cpuErrAlloc"},
112 | {12, ASN_COUNTER, "cpuErrMaxflows"},
113 | { 0 }
114 | };
115 |
116 | static netsnmp_table_data_set *sock_data_set;
117 | struct snmp_vars socktable[] = {
118 | {1, ASN_INTEGER, "sockIndex"},
119 | {2, ASN_OCTET_STR, "sockDestination"},
120 | {3, ASN_INTEGER, "sockActive"},
121 | {4, ASN_COUNTER, "sockErrConnect"},
122 | {5, ASN_COUNTER, "sockErrFull"},
123 | {6, ASN_COUNTER, "sockErrCberr"},
124 | {7, ASN_COUNTER, "sockErrOther"},
125 | {8, ASN_GAUGE, "sockSndbuf"},
126 | {9, ASN_GAUGE, "sockSndbufFill"},
127 | {10, ASN_GAUGE, "sockSndbufPeak"},
128 | { 0 }
129 | };
130 |
131 | static time_t totals_ts; /* when statistics last read from kernel */
132 |
133 | static int var_max(struct snmp_vars *head)
134 | {
135 | struct snmp_vars *sys;
136 | int max = 0;
137 |
138 | for (sys = head; sys->obj; sys++)
139 | if (max < sys->obj)
140 | max = sys->obj;
141 | return max;
142 | }
143 |
144 | static struct snmp_vars *find_varinfo(struct snmp_vars *head, const int obj)
145 | {
146 | struct snmp_vars *sys;
147 |
148 | for (sys = head; sys->obj; sys++) {
149 | if (sys->obj == obj)
150 | return sys;
151 | }
152 | return NULL;
153 | }
154 |
155 | static struct snmp_vars *find_varinfo_str(struct snmp_vars *head, const char *name)
156 | {
157 | struct snmp_vars *sys;
158 |
159 | for (sys = head; sys->obj; sys++) {
160 | if (!strcmp(sys->name, name))
161 | return sys;
162 | }
163 | return NULL;
164 | }
165 |
166 | static void modinfo_fname(char *name, char *fname, size_t flen)
167 | {
168 | snprintf(fname, flen, "/sys/module/" MODINFO_NAME "/%s", name);
169 | }
170 |
171 | static void sysctl_fname(char *name, char *fname, size_t flen)
172 | {
173 | snprintf(fname, flen, "/proc/sys/net/netflow/%s", name);
174 | }
175 |
176 | static int sysctl_access_ok(char *name)
177 | {
178 | char fname[64];
179 |
180 | sysctl_fname(name, fname, sizeof(fname));
181 | if (access(fname, W_OK) < 0)
182 | return 0;
183 | return 1;
184 | }
185 |
186 | static char *file_read_string(char *name, char *buf, size_t size)
187 | {
188 | int fd = open(name, O_RDONLY);
189 | if (fd < 0)
190 | return NULL;
191 | int n = read(fd, buf, size - 1);
192 | if (n < 0) {
193 | close(fd);
194 | return NULL;
195 | }
196 | buf[n] = '\0';
197 | close(fd);
198 | return buf;
199 | }
200 |
201 | static char *modinfo_read_string(char *name, char *buf, size_t size)
202 | {
203 | char fname[64];
204 |
205 | modinfo_fname(name, fname, sizeof(fname));
206 | return file_read_string(fname, buf, size);
207 | }
208 |
209 | static char *sysctl_read_string(char *name, char *buf, size_t size)
210 | {
211 | char fname[64];
212 |
213 | sysctl_fname(name, fname, sizeof(fname));
214 | return file_read_string(fname, buf, size);
215 | }
216 |
217 | static int sysctl_write_string(char *name, char *buf, size_t size)
218 | {
219 | char fname[64];
220 | int fd;
221 | int n;
222 |
223 | sysctl_fname(name, fname, sizeof(fname));
224 | fd = open(fname, O_RDWR, 0644);
225 | if (fd < 0)
226 | return fd;
227 | n = write(fd, buf, size);
228 | close(fd);
229 | return n;
230 | }
231 |
232 | static int sysctl_read(netsnmp_request_info *request, int obj)
233 | {
234 | struct snmp_vars *sys = find_varinfo(sysctls, obj);
235 | char buf[225];
236 | char *p;
237 | long value;
238 |
239 | if (!sys)
240 | goto nosuchobject;
241 |
242 | p = sysctl_read_string(sys->name, buf, sizeof(buf));
243 | if (!p)
244 | goto nosuchobject;
245 |
246 | switch (sys->type) {
247 | case ASN_INTEGER:
248 | value = atoi(p);
249 | snmp_set_var_typed_value(request->requestvb,
250 | sys->type,
251 | (u_char *)&value, sizeof(value));
252 | return SNMP_ERR_NOERROR;
253 | case ASN_OCTET_STR:
254 | snmp_set_var_typed_value(request->requestvb,
255 | sys->type,
256 | (u_char *)p, strcspn(p, "\n"));
257 | return SNMP_ERR_NOERROR;
258 | }
259 | nosuchobject:
260 | netsnmp_request_set_error(request, SNMP_NOSUCHOBJECT);
261 | return SNMP_ERR_NOERROR;
262 | }
263 |
264 | static int sysctl_write(netsnmp_request_info *request, int obj)
265 | {
266 | struct snmp_vars *sys = find_varinfo(sysctls, obj);
267 | char buf[225];
268 | int len;
269 |
270 | if (!sys) {
271 | netsnmp_request_set_error(request, SNMP_NOSUCHOBJECT);
272 | return SNMP_ERR_NOERROR;
273 | }
274 | switch (sys->type) {
275 | case ASN_INTEGER:
276 | snprintf(buf, sizeof(buf), "%ld\n", *(request->requestvb->val.integer));
277 | break;
278 | case ASN_UNSIGNED:
279 | snprintf(buf, sizeof(buf), "%lu\n", *(request->requestvb->val.integer));
280 | break;
281 | case ASN_OCTET_STR:
282 | snprintf(buf, sizeof(buf), "%s\n", request->requestvb->val.string);
283 | break;
284 | default:
285 | netsnmp_request_set_error(request, SNMP_ERR_WRONGTYPE);
286 | return SNMP_ERR_NOERROR;
287 | }
288 | len = strlen(buf);
289 | if (sysctl_write_string(sys->name, buf, len) < len)
290 | netsnmp_request_set_error(request, SNMP_ERR_BADVALUE);
291 | return SNMP_ERR_NOERROR;
292 | }
293 |
294 | static int iptNetflowModule_handler(
295 | netsnmp_mib_handler *handler,
296 | netsnmp_handler_registration *reginfo,
297 | netsnmp_agent_request_info *reqinfo,
298 | netsnmp_request_info *request)
299 | {
300 | struct snmp_vars *sys;
301 | oid obj;
302 | char buf[225];
303 | char *p = NULL;
304 | long value;
305 |
306 | obj = request->requestvb->name[request->requestvb->name_length - 2];
307 | sys = find_varinfo(modinfos, obj);
308 | if (!sys) {
309 | netsnmp_request_set_error(request, SNMP_ERR_NOSUCHNAME);
310 | return SNMP_ERR_NOERROR;
311 | }
312 | if (reqinfo->mode != MODE_GET) {
313 | netsnmp_request_set_error(request, SNMP_ERR_READONLY);
314 | return SNMP_ERR_NOERROR;
315 | }
316 | switch (obj) {
317 | case MODINFO_NAME_ID:
318 | p = MODINFO_NAME;
319 | break;
320 | case MODINFO_DATE_ID: {
321 | size_t len;
322 | struct stat st;
323 |
324 | modinfo_fname(".", buf, sizeof(buf));
325 | if (stat(buf, &st) < 0)
326 | break;
327 | p = (char *)date_n_time(&st.st_mtime, &len);
328 | snmp_set_var_typed_value(request->requestvb, ASN_OCTET_STR, p, len);
329 | return SNMP_ERR_NOERROR;
330 | }
331 | default:
332 | p = modinfo_read_string(sys->name, buf, sizeof(buf));
333 | }
334 | if (!p) {
335 | netsnmp_request_set_error(request, SNMP_ERR_NOSUCHNAME);
336 | return SNMP_ERR_NOERROR;
337 | }
338 |
339 | switch (sys->type) {
340 | case ASN_INTEGER:
341 | value = atoi(p);
342 | snmp_set_var_typed_value(request->requestvb,
343 | sys->type,
344 | (u_char *)&value, sizeof(value));
345 | break;
346 | case ASN_OCTET_STR:
347 | snmp_set_var_typed_value(request->requestvb,
348 | sys->type,
349 | (u_char *)p, strcspn(p, "\n"));
350 | break;
351 | default:
352 | netsnmp_request_set_error(request, SNMP_ERR_WRONGTYPE);
353 |
354 | }
355 | return SNMP_ERR_NOERROR;
356 | }
357 |
358 | static int iptNetflowSysctl_handler(
359 | netsnmp_mib_handler *handler,
360 | netsnmp_handler_registration *reginfo,
361 | netsnmp_agent_request_info *reqinfo,
362 | netsnmp_request_info *request)
363 | {
364 | struct snmp_vars *sys;
365 | oid obj;
366 |
367 | obj = request->requestvb->name[request->requestvb->name_length - 2];
368 | switch (reqinfo->mode) {
369 | case MODE_GET:
370 | return sysctl_read(request, obj);
371 | case MODE_SET_RESERVE1:
372 | sys = find_varinfo(sysctls, obj);
373 | if (!sys || !sysctl_access_ok(sys->name))
374 | netsnmp_request_set_error(request, SNMP_ERR_NOSUCHNAME);
375 | if (sys && request->requestvb->type != sys->type)
376 | netsnmp_request_set_error(request, SNMP_ERR_WRONGTYPE);
377 | break;
378 | case MODE_SET_RESERVE2:
379 | case MODE_SET_FREE:
380 | case MODE_SET_UNDO:
381 | case MODE_SET_COMMIT:
382 | return SNMP_ERR_NOERROR;
383 | case MODE_SET_ACTION:
384 | return sysctl_write(request, obj);
385 | default:
386 | return SNMP_ERR_GENERR;
387 |
388 | }
389 | return SNMP_ERR_NOERROR;
390 | }
391 |
392 | #define TOTAL_INTERVAL 1
393 |
394 | static void clear_data_set(netsnmp_table_data_set *data_set)
395 | {
396 | netsnmp_table_row *row, *nextrow;
397 |
398 | for (row = netsnmp_table_data_set_get_first_row(data_set); row; row = nextrow) {
399 | nextrow = netsnmp_table_data_set_get_next_row(data_set, row);
400 | netsnmp_table_dataset_remove_and_delete_row(data_set, row);
401 | }
402 | }
403 |
404 | static void parse_table_row(
405 | int cpu,
406 | char *p,
407 | struct snmp_vars *sys,
408 | netsnmp_table_data_set *data_set)
409 | {
410 | netsnmp_table_row *row;
411 |
412 | row = netsnmp_create_table_data_row();
413 | netsnmp_table_row_add_index(row, ASN_INTEGER, (u_char *)&cpu, sizeof(cpu));
414 |
415 | if (sys == cputable) {
416 | /* add cpuIndex as column too to break SMIv2 */
417 | netsnmp_set_row_column(row, 1, sys->type, (char *)&cpu, sizeof(cpu));
418 | }
419 | for (++sys; p && sys->obj; sys++) {
420 | char *val;
421 | long long val64;
422 | unsigned int uval32;
423 | int val32;
424 | struct counter64 c64;
425 |
426 | p += strspn(p, " \t");
427 | val = p;
428 | if ((p = strpbrk(p, " \t")))
429 | *p++ = '\0';
430 | if (index(val, '.')) {
431 | double d = strtod(val, NULL);
432 |
433 | val64 = (long long)(d * 100);
434 | } else
435 | val64 = strtoll(val, NULL, 10);
436 |
437 | switch (sys->type) {
438 | case ASN_OCTET_STR:
439 | netsnmp_set_row_column(row, sys->obj,
440 | sys->type, (char *)val, strlen(val));
441 | break;
442 | case ASN_INTEGER:
443 | case ASN_GAUGE:
444 | val32 = (int)val64;
445 | netsnmp_set_row_column(row, sys->obj,
446 | sys->type, (char *)&val32, sizeof(val32));
447 | break;
448 | case ASN_COUNTER:
449 | uval32 = (unsigned int)val64;
450 | netsnmp_set_row_column(row, sys->obj,
451 | sys->type, (char *)&uval32, sizeof(uval32));
452 | break;
453 | case ASN_COUNTER64:
454 | c64.low = (uint32_t)val64;
455 | c64.high = val64 >> 32;
456 | netsnmp_set_row_column(row, sys->obj,
457 | sys->type, (char *)&c64, sizeof(c64));
458 | break;
459 | default:
460 | netsnmp_table_dataset_delete_row(row);
461 | continue;
462 | }
463 |
464 | }
465 | netsnmp_table_data_add_row(data_set->table, row);
466 | }
467 |
468 | static void grab_ipt_netflow_snmp(time_t now)
469 | {
470 | static char buf[4096];
471 | int fd;
472 | int n;
473 | char *p = buf;
474 |
475 | if ((now - totals_ts) < (TOTAL_INTERVAL + 1))
476 | return;
477 |
478 | if ((fd = open("/proc/net/stat/ipt_netflow_snmp", O_RDONLY)) < 0)
479 | return;
480 |
481 | n = read(fd, buf, sizeof(buf) - 1);
482 | close(fd);
483 | if (n <= 0)
484 | return;
485 | buf[n] = '\0';
486 |
487 | DEBUGMSGTL(("netflow", "%s\n", buf));
488 | clear_data_set(cpu_data_set);
489 | clear_data_set(sock_data_set);
490 | while (*p) {
491 | struct snmp_vars *sys;
492 | char *name = p;
493 | char *val;
494 |
495 | if (!(p = strpbrk(p, " \t")))
496 | break;
497 | *p++ = '\0';
498 | val = p + strspn(p, " \t");
499 | p = index(p, '\n');
500 | *p++ = '\0';
501 |
502 | if (!strncmp(name, "cpu", 3)) {
503 | parse_table_row(atoi(name + 3), val, cputable, cpu_data_set);
504 | continue;
505 | } else if (!strncmp(name, "sock", 4)) {
506 | parse_table_row(atoi(name + 4), val, socktable, sock_data_set);
507 | continue;
508 | }
509 | if (!(sys = find_varinfo_str(totals, name)))
510 | continue;
511 | if (index(val, '.')) {
512 | double d = strtod(val, NULL);
513 | sys->val64 = (long long)(d * 100);
514 | } else
515 | sys->val64 = strtoll(val, NULL, 10);
516 | sys->ts = now;
517 | }
518 | totals_ts = now;
519 | }
520 |
521 | static int iptNetflowTotals_handler(
522 | netsnmp_mib_handler *handler,
523 | netsnmp_handler_registration *reginfo,
524 | netsnmp_agent_request_info *reqinfo,
525 | netsnmp_request_info *request)
526 | {
527 | struct snmp_vars *sys;
528 | time_t now = time(NULL);
529 | oid obj;
530 | unsigned int uval32;
531 | int val32;
532 | struct counter64 c64;
533 |
534 | grab_ipt_netflow_snmp(now);
535 |
536 | obj = request->requestvb->name[request->requestvb->name_length - 2];
537 | sys = find_varinfo(totals, obj);
538 | if (!sys || ((now - sys->ts) > (TOTAL_INTERVAL * 2 + 3))) {
539 | netsnmp_request_set_error(request, SNMP_ERR_NOSUCHNAME);
540 | return SNMP_ERR_NOERROR;
541 | }
542 | if (reqinfo->mode != MODE_GET) {
543 | netsnmp_request_set_error(request, SNMP_ERR_READONLY);
544 | return SNMP_ERR_NOERROR;
545 | }
546 | switch (sys->type) {
547 | case ASN_GAUGE:
548 | val32 = (int)sys->val64;
549 | snmp_set_var_typed_value(request->requestvb,
550 | sys->type, (u_char *)&val32, sizeof(val32));
551 | break;
552 | case ASN_COUNTER:
553 | uval32 = (unsigned int)sys->val64;
554 | snmp_set_var_typed_value(request->requestvb,
555 | sys->type, (u_char *)&uval32, sizeof(uval32));
556 | break;
557 | case ASN_COUNTER64:
558 | c64.low = (uint32_t)sys->val64;
559 | c64.high = sys->val64 >> 32;
560 | snmp_set_var_typed_value(request->requestvb,
561 | ASN_COUNTER64, (u_char *)&c64, sizeof(c64));
562 | break;
563 | default:
564 | return SNMP_ERR_GENERR;
565 | }
566 | return SNMP_ERR_NOERROR;
567 | }
568 |
569 | static int stat_cache_load(netsnmp_cache *cache, void *x)
570 | {
571 | grab_ipt_netflow_snmp(time(NULL));
572 | return 0;
573 | }
574 |
575 | static void dummy_cache_free(netsnmp_cache *cache, void *x)
576 | {
577 | /* free_cache callback is not always checked for NULL
578 | * pointer. */
579 | }
580 |
581 | void init_netflow(void)
582 | {
583 | netsnmp_handler_registration *reg;
584 | struct snmp_vars *sys;
585 |
586 | /* snmpd -f -L -Dnetflow,dlmod */
587 | DEBUGMSGTL(("netflow", "init_netflow\n"));
588 |
589 | netsnmp_register_scalar_group(
590 | netsnmp_create_handler_registration(
591 | "iptNetflowModule",
592 | iptNetflowModule_handler,
593 | iptNetflowModule_oid,
594 | OID_LENGTH(iptNetflowModule_oid),
595 | HANDLER_CAN_RONLY),
596 | 1, var_max(modinfos));
597 |
598 | netsnmp_register_scalar_group(
599 | netsnmp_create_handler_registration(
600 | "iptNetflowSysctl",
601 | iptNetflowSysctl_handler,
602 | iptNetflowSysctl_oid,
603 | OID_LENGTH(iptNetflowSysctl_oid),
604 | HANDLER_CAN_RWRITE),
605 | 1, var_max(sysctls));
606 |
607 | netsnmp_register_scalar_group(
608 | netsnmp_create_handler_registration(
609 | "iptNetflowTotals",
610 | iptNetflowTotals_handler,
611 | iptNetflowTotals_oid,
612 | OID_LENGTH(iptNetflowTotals_oid),
613 | HANDLER_CAN_RONLY),
614 | 1, var_max(totals));
615 |
616 | /* Register first table. */
617 | reg = netsnmp_create_handler_registration(
618 | "iptNetflowCpuTable", /* no handler */ NULL,
619 | iptNetflowCpuTable_oid, OID_LENGTH(iptNetflowCpuTable_oid),
620 | HANDLER_CAN_RONLY);
621 |
622 | /* set up columns */
623 | cpu_data_set = netsnmp_create_table_data_set("iptNetflowCpuDataSet");
624 | netsnmp_table_set_add_indexes(cpu_data_set, ASN_INTEGER, 0);
625 | /* I include cpuIndex into columns, which is not SMIv2'ish */
626 | for (sys = cputable; sys->obj; sys++)
627 | netsnmp_table_set_add_default_row(cpu_data_set, sys->obj, sys->type, 0, NULL, 0);
628 | netsnmp_register_table_data_set(reg, cpu_data_set, NULL);
629 |
630 | /* cache handler will load actual data, and it needs to be
631 | * injected in front of dataset handler to be called first */
632 | stat_cache = netsnmp_cache_create(
633 | /* no timeout */ -1,
634 | stat_cache_load, dummy_cache_free,
635 | iptNetflowCpuTable_oid, OID_LENGTH(iptNetflowCpuTable_oid));
636 | netsnmp_inject_handler(reg, netsnmp_cache_handler_get(stat_cache));
637 |
638 | /* Register second table. */
639 | reg = netsnmp_create_handler_registration(
640 | "iptNetflowSockTable", /* no handler */ NULL,
641 | iptNetflowSockTable_oid, OID_LENGTH(iptNetflowSockTable_oid),
642 | HANDLER_CAN_RONLY);
643 |
644 | /* set up columns */
645 | sock_data_set = netsnmp_create_table_data_set("iptNetflowSockDataSet");
646 | /* I don't include sockIndex into columns, which is more SMIv2'ish */
647 | netsnmp_table_set_add_indexes(sock_data_set, ASN_INTEGER, 0);
648 | for (sys = &socktable[1]; sys->obj; sys++)
649 | netsnmp_table_set_add_default_row(sock_data_set, sys->obj, sys->type, 0, NULL, 0);
650 | netsnmp_register_table_data_set(reg, sock_data_set, NULL);
651 |
652 | /* as before, cache handler will load actual data, and it needs
653 | * to be injected in front of dataset handler to be called first */
654 | stat_cache = netsnmp_cache_create(
655 | /* no timeout */ -1,
656 | stat_cache_load, dummy_cache_free,
657 | iptNetflowSockTable_oid, OID_LENGTH(iptNetflowSockTable_oid));
658 | netsnmp_inject_handler(reg, netsnmp_cache_handler_get(stat_cache));
659 | }
660 |
661 | void deinit_netflow(void)
662 | {
663 | DEBUGMSGTL(("netflow", "deinit_netflow\n"));
664 | }
665 |
666 |
--------------------------------------------------------------------------------
/test_update_config.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -efu
2 | # SPDX-License-Identifier: GPL-2.0-only
3 | #
4 | # Update default .config for values required to run tests
5 | #
6 |
7 | COLOR=11
8 | V() {
9 | [ -t 1 ] && tput setaf "$COLOR"
10 | printf '+'
11 | printf ' %q' "$@"
12 | printf '\n'
13 | [ -t 1 ] && tput op
14 | "$@"
15 | }
16 |
17 | for opt; do
18 | case $opt in
19 | --kdir=*) KDIR=${opt#*=} ;;
20 | --checkout=*) BRANCH=${opt#*=} ;&
21 | --defconfig) DEFCONFIG=defconfig ;;
22 | --debug) ADD_DEBUG=y ;;
23 | --force) FORCE=--force ;;
24 | --prepare) TARGETS="prepare modules_prepare" ;&
25 | --clean) CLEAN=clean ;;
26 | --cmd=*) KBUILD_PREPARE_CMD=${opt#*=} ;;
27 | --build) DO_BUILD=y ;;
28 | --configure) DO_CONFIGURE=y ;;
29 | --pick=*) PICKS+=("${opt#*=}") ;;
30 | --*) echo >&2 "$0: Unknown option $opt"; exit 1 ;;
31 | gcc-*) OPTS+=(CC=$opt HOSTCC=$opt) ;;
32 | -no-* | -[fDWO]*) KBUILD_CFLAGS+=("$opt") ;;
33 | *=*) OPTS+=("${opt%%=*}=${opt#*=}") ;;
34 | *) echo >&2 "$0: Unknown argument $opt"; exit 1 ;;
35 | esac
36 | done
37 |
38 | # Patch applying command assuming --force checkout.
39 | [ -n "$KBUILD_PREPARE_CMD" ] && [ -n "$TARGETS" ] && FORCE=-f
40 |
41 | [ -n "${KDIR-}" ] && V cd "$KDIR"
42 | [ -n "${BRANCH-}" ] && V git switch ${FORCE-} --detach "$BRANCH"
43 | [ -n "${DEFCONFIG-}" ] && V make $DEFCONFIG
44 |
45 | V cp -f .config .config-pkt-netflow.bak
46 |
47 | if type virtme-configkernel >/dev/null 2>&1; then
48 | V virtme-configkernel --update
49 | fi
50 |
51 | V scripts/config \
52 | -e CONFIG_VETH \
53 | -e CONFIG_PACKET \
54 | -e CONFIG_NETFILTER \
55 | -e CONFIG_NETFILTER_XTABLES \
56 | -e NETFILTER_ADVANCED \
57 | -e CONFIG_IP_NF_FILTER \
58 | -e CONFIG_IP_NF_IPTABLES \
59 | -e CONFIG_IP6_NF_FILTER \
60 | -e CONFIG_NF_CONNTRACK_EVENTS \
61 | -e CONFIG_VLAN_8021Q \
62 |
63 | if [ -n "${ADD_DEBUG-}" ]; then
64 | V scripts/config \
65 | -e CONFIG_LOCK_DEBUGGING_SUPPORT \
66 | -e CONFIG_PROVE_LOCKING \
67 | -e CONFIG_DEBUG_SPINLOCK \
68 | -e CONFIG_FRAME_POINTER \
69 | -d CONFIG_RANDOMIZE_BASE \
70 |
71 | fi
72 |
73 | V make olddefconfig
74 |
75 | V scripts/diffconfig .config-pkt-netflow.bak .config || :
76 |
77 | [ -n "${CLEAN-}" ] && V make $CLEAN
78 | [ -n "${KBUILD_PREPARE_CMD-}" ] && V eval "$KBUILD_PREPARE_CMD" || :
79 | for commit in "${PICKS[@]}"; do
80 | V git cherry-pick --no-commit "$commit" || :
81 | done
82 | [ -n "${KBUILD_CFLAGS-}" ] && OPTS+=("KBUILD_CFLAGS=${KBUILD_CFLAGS[*]}")
83 | [ -n "${TARGETS-}" ] && V make $TARGETS "${OPTS[@]}"
84 |
85 | echo
86 | V cd "$OLDPWD"
87 | COLOR=14
88 |
89 | if [ -n "${DO_CONFIGURE-}" ]; then
90 | readarray -t confs <<-EOF
91 | --disable-snmp-agent
92 | --enable-aggregation
93 | --enable-natevents
94 | --enable-snmp-rules
95 | --enable-macaddress
96 | --enable-vlan
97 | --promisc-mpls
98 | --enable-direction
99 | --enable-sampler
100 | --enable-sampler=hash
101 | --enable-promisc --promisc-mpls
102 | --enable-physdev
103 | --enable-physdev-override
104 | EOF
105 | mv -f Makefile Makefile- || :
106 | V ./configure ${confs[@]}
107 | fi
108 |
109 | if [ -n "${DO_BUILD-}" ]; then
110 | V make "${OPTS[@]}" $CLEAN ipt_NETFLOW.ko
111 | size ipt_NETFLOW.ko
112 | fi
113 |
114 | # export XTABLES_LIBDIR=
115 |
--------------------------------------------------------------------------------
/testing.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | if [ "$1" = "" ]; then
6 | echo Maintainer only tool.
7 | exit 1
8 | elif [ "$1" = all ]; then
9 | exec bash $0 linux-2.6.18 centos5 linux-3.11.2 centos6 linux-3.4.66 linux-3.9.11 centos7 linux-3.14 linux-3.17 linux-3.19
10 | exit 1
11 | fi
12 |
13 | smilint IPT-NETFLOW-MIB.my
14 |
15 | cfg=()
16 | echo -n Testing for:
17 | for k in "$@"; do
18 | if [ ! -d /usr/src/$k ]; then continue; fi
19 | echo -n " $k"
20 | cfg+=("./configure --kdir=/usr/src/$k")
21 | done
22 | echo
23 |
24 | readarray -t opts </dev/null 2>&1; then \
16 | GVERSION=`git describe --dirty 2>/dev/null`
17 | if [ "$GVERSION" ]; then
18 | MVERSION=${GVERSION#v}
19 | fi
20 | else
21 | GVERSION=
22 | fi
23 |
24 | if [ "$1" = --define ]; then
25 | # called from Makefile to create version.h
26 | # which should contain GITVERSION or be empty.
27 | if [ "$GVERSION" ]; then
28 | echo "#define GITVERSION \"$MVERSION\""
29 | else
30 | echo "/* placeholder, because kernel doesn't like empty files */"
31 | fi
32 | else
33 | # normal run
34 | echo $MVERSION
35 | fi
36 |
--------------------------------------------------------------------------------