299 Commits

Author SHA1 Message Date
Vincent Bernat
c6a9319b57 common/schema: turns into a component
This is a first step to make it accept configuration. Most of the
changes are quite trivial, but I also ran into some difficulties with
query columns and filters. They need the schema for parsing, but parsing
happens before dependencies are instantiated (and even if it was not the
case, parsing is stateless). Therefore, I have added a `Validate()`
method that must be called after instantiation. Various bits `panic()`
if not validated to ensure we catch all cases.

The alternative to make the component manages a global state would have
been simpler but it would break once we add the ability to add or
disable columns.
2023-01-18 12:22:10 +01:00
Vincent Bernat
1ae890cd7d common/schema: make SrcPort/DstPort 16-bit to reduce ClickHouse storage
We would need to do it for EType, Proto and ForwardingStatus but as they
are primary keys, this is something difficult to change right now.
2023-01-17 20:53:00 +01:00
Vincent Bernat
e352202631 inlet: make use of schema for inlet
This is a huge change to make the various subcomponents of the inlet use
the schema to generate the protobuf. For it to make sense, we also
modify the way we parse flows to directly serialize non-essential fields
to Protobuf.

The performance is mostly on par with the previous commit. We are a bit
less efficient because we don't have a fixed structure, but we avoid
loosing too much performance by not relying on reflection and keeping
the production of messages as code. We use less of Goflow2: raw flow
parsing is still done by Goflow2, but we don't use the producer part
anymore. This helps a bit with the performance as we parse less.
Overall, we are 20% than the previous commit and twice faster than the
1.6.4!

```
goos: linux
goarch: amd64
pkg: akvorado/inlet/flow
cpu: AMD Ryzen 5 5600X 6-Core Processor
BenchmarkDecodeEncodeNetflow
BenchmarkDecodeEncodeNetflow/with_encoding
BenchmarkDecodeEncodeNetflow/with_encoding-12             151484              7789 ns/op            8272 B/op        143 allocs/op
BenchmarkDecodeEncodeNetflow/without_encoding
BenchmarkDecodeEncodeNetflow/without_encoding-12          162550              7133 ns/op            8272 B/op        143 allocs/op
BenchmarkDecodeEncodeSflow
BenchmarkDecodeEncodeSflow/with_encoding
BenchmarkDecodeEncodeSflow/with_encoding-12                94844             13193 ns/op            9816 B/op        295 allocs/op
BenchmarkDecodeEncodeSflow/without_encoding
BenchmarkDecodeEncodeSflow/without_encoding-12             92569             12456 ns/op            9816 B/op        295 allocs/op
```

There was a tentative to parse sFlow packets with gopackets, but the
adhoc parser used here is more performant.
2023-01-17 20:53:00 +01:00
Vincent Bernat
8a779fb905 common/schema: make schema fields private
This is useful later to bundle cached field and ensure they stay
up-to-date.
2023-01-17 20:53:00 +01:00
Vincent Bernat
727807b937 common/schema: use a symbol to identify columns 2023-01-17 20:53:00 +01:00
Vincent Bernat
e88d2a2974 common/schema: namespace column members by subsystem
Otherwise, it will be a mess once we introduce IPFIX/sFlow specific fields
2023-01-17 20:53:00 +01:00
Vincent Bernat
5cfa7607d0 inlet/flow: move protobuf message encoding to decoder package
There is still an odd bug somewhere...
2023-01-09 14:15:54 +01:00
Vincent Bernat
727bd1fe1d common/helper: fix protobuf handling 2023-01-09 12:16:37 +01:00
Vincent Bernat
3dfc04be1d inlet/core: use vtprotobuf to speed up protobuf
New situation:

```
goos: linux
goarch: amd64
pkg: akvorado/inlet/flow
cpu: AMD Ryzen 5 5600X 6-Core Processor
BenchmarkDecodeEncodeNetflow
BenchmarkDecodeEncodeNetflow/with_encoding
BenchmarkDecodeEncodeNetflow/with_encoding-12             124512              9861 ns/op
BenchmarkDecodeEncodeNetflow/without_encoding
BenchmarkDecodeEncodeNetflow/without_encoding-12          141937              8915 ns/op
BenchmarkDecodeEncodeSflow
BenchmarkDecodeEncodeSflow/with_encoding
BenchmarkDecodeEncodeSflow/with_encoding-12                79558             15796 ns/op
BenchmarkDecodeEncodeSflow/without_encoding
BenchmarkDecodeEncodeSflow/without_encoding-12             88330             14711 ns/op
```

Encoding is now quite negligible compared to parsing.
2023-01-09 08:36:58 +01:00
Vincent Bernat
14c4391620 inlet/flow: add a benchmark for flow decoding/encoding
This will serve as a base for converting this to a one-step conversion
to Protobuf. The main goal is not to be faster, but we don't want to be
slower and faster would be a nice bonus.

```
goos: linux
goarch: amd64
pkg: akvorado/inlet/flow
cpu: AMD Ryzen 5 5600X 6-Core Processor
BenchmarkDecodeEncodeNetflow
BenchmarkDecodeEncodeNetflow-12            39586             29199 ns/op
BenchmarkDecodeEncodeSflow
BenchmarkDecodeEncodeSflow-12              24349             48914 ns/op
ok      akvorado/inlet/flow     3.167s

DONE 0 tests in 3.636s
```
2023-01-07 13:30:12 +01:00
Vincent Bernat
0217d283b4 common/http: add a finalizer to get rid of Redis client 2023-01-05 10:31:28 +01:00
Vincent Bernat
a30024cfa1 console: use common/schema for dimensions
This is a bit less type-safe. We could keep type safety by redefining
all the consts in `query_consts.go` in `common/schema`, but this is
pointless as the goal is to have arbitrary dimensions at some point.
2023-01-03 18:40:19 +01:00
Vincent Bernat
aae92e7fe0 common/schema: use an ordered map for columns
For ClickHouse, we can iterate, but for other aspects, we need a direct
access.
2023-01-03 17:45:50 +01:00
Vincent Bernat
7d1ba478a1 orchestrator/clickhouse: rework migrations to use an abstract schema
We introduce an leaky abstraction for flows schema and use it for
migrations as a first step.

For views and dictionaries, we stop relying on a hash to know if they
need to be recreated, but we compare the select statements with our
target statement. This is a bit fragile, but strictly better than the
hash.

For data tables, we add the missing columns.

We give up on the abstraction of a migration step and just rely on
helper functions to get the same result. The migration code is now
shorter and we don't need to update it when adding new columns.

This is a preparatory work for #211 to allow a user to specify
additional fields to collect.
2023-01-02 23:42:05 +01:00
Vincent Bernat
c610a738a1 common/http: use SHA256 to compare POST requests
In our case, this shouldn't matter. However, performance hit should be
low and maybe at some point this middleware could be used for more
sensitive stuff.
2022-12-24 11:33:58 +01:00
Vincent Bernat
4db5ac7544 http: fix cache configuration marshal/unmarshal
Also, enable Redis by default, as stated in changelog.
2022-12-22 18:32:52 +01:00
Vincent Bernat
775dc08db2 console: implement an HTTP cache for Clickhouse-backed requests
Fix #328
2022-12-22 16:23:49 +01:00
Vincent Bernat
f1f83a2ba8 common/helpers: move parametrized configuration to helpers package 2022-12-21 16:34:22 +01:00
Vincent Bernat
44e9e96490 common/helpers: move race helpers to dedicated package 2022-11-28 16:58:19 +01:00
Vincent Bernat
b506a76afe common/helpers: keep RWMutex integration with race detector 2022-11-28 16:34:38 +01:00
Vincent Bernat
a5d5b14112 inlet/bmp: after flushing peers, allocate some time for readers
By downgrading the lock, we ensure readers get some time to work.
Otherwise, writers may take the lock back. The downgrade code was stolen
from https://github.com/google/gvisor/tree/master/pkg/sync.
2022-11-28 15:22:59 +01:00
Vincent Bernat
24cfabb682 common/helpers: move bimap and intern to separate packages
subnetmap would be a candidate too, but there are cyclic dependencies
because we want diff to handle it correctly.
2022-11-28 15:22:59 +01:00
Vincent Bernat
7196ccf73b inlet/bmp: revert new BMP design
It needs more work to be stable. Let's do a release without it.
2022-11-26 11:42:46 +01:00
Vincent Bernat
fa7e4b6ac7 inlet/kafka: add TLS support to Kafka
Fix #277
2022-11-25 01:00:21 +01:00
Vincent Bernat
bf99e2211e common/helpers: correctly validate netip.Addr/netip.Prefix
validate is only able to validate non-struct types (or recurse inside
struct). So, if we want to use "required" on some of them, we need a
custom type.

Fix #263
2022-11-15 18:38:41 +01:00
Vincent Bernat
3199f8f1a7 inlet/bmp: switch to a lockless design for the RIB
RIB updates are handled by a single goroutine accepting update requests
through a channel receiving functions to execute on the state (RIB +
peer state).

For lookups, we have 3 options (better to lower performance, higher to
lower memory usage):

1. have a read-only copy updated "atomically" at regular interval,
2. have a read-only copy updated behind a lock at regular interval,
3. handle lookups by the worker through a high priority channel.

This commit implements option 3. It may be a regression in latency
compared to the previous design because long updates (flushing peers)
may prevent answering lookup requests. This will be addressed in the
next commit.
2022-11-13 10:38:24 +01:00
Vincent Bernat
eee9f32f86 inlet/bmp: internalize NLRI for better memory usage
This could help performance as we will skip removing a prefix if we
don't have the associated NLRI. However, this is an unlikely corner
case (all routes we have should have been added first).
2022-11-11 17:51:34 +01:00
Vincent Bernat
9d85bb7db0 inlet/bmp: avoid long lock times when flushing peers
When the RIB is locked for too long, inlet is hung. Try to ensure give a
bit of time for the inlet to move forward between two flush of the RIB.
There are various knobs not documnted yet until we get better defaults:

- `inlet.bmp.peer-removal-max-time`: how long to keep the lock
- `inlet.bmp.peer-removal-sleep-interval`: how long to sleep between two
  runs if we were unable to flush the whole peer
- `inlet.bmp.peer-removal-max-queue`: maximum number of flush requests
- `inlet.bmp.peer-removal-min-routes`: minimum number of routes to flush
  before yielding

May fix #253
2022-11-09 17:30:59 +01:00
Vincent Bernat
95482c9201 orchestrator/clickhouse: ability to fetch network attributes with HTTP 2022-10-14 19:50:04 +02:00
Vincent Bernat
c769bb5234 inlet/bmp: initial support for BMP protocol
At first, there was a tentative to use BMP collector implementation
from bio-rd. However, this current implementation is using GoBGP
instead:

- BMP is very simple from a protocol point of view. The hard work is
  mostly around decoding. Both bio-rd and GoBGP can decode, but for
  testing, GoBGP is able to generate messages as well (this is its
  primary purpose, I suppose parsing was done for testing purpose).
  Using only one library is always better. An alternative would be
  GoBMP, but it also only do parsing.
- Logging and metrics can be customized easily (but the work was done
  for bio-rd, so not a real argument).
- bio-rd is an application and there is no API stability (and I did
  that too)
- GoBGP supports FlowSpec, which may be useful in the future for the
  DDoS part. Again, one library for everything is better (but
  honestly, GoBGP as a lib is not the best part of it, maybe
  github.com/jwhited/corebgp would be a better fit while keeping GoBGP
  for decoding/encoding).

There was a huge effort around having a RIB which is efficient
memory-wise (data are interned to save memory), performant during
reads, while being decent during insertions. We rely on a patched
version of Kentik's Patricia trees to be able to apply mutations to
the tree.

There was several tentatives to implement some kind of graceful
restart, but ultimetaly, the design is kept simple: when a BMP
connection goes down, routes will be removed after a configurable
time. If the connection comes back up, then it is just considered new.
It would have been ideal to rely on EoR markers, but the RFC is
unclear about them, and they are likely to be per peer, making it
difficult to know what to do if one peer is back, but not the other.

Remaining tasks:

- [ ] Confirm support for LocRIB
- [ ] Import data in ClickHouse
- [ ] Make data available in the frontend

Fix #52
2022-09-27 00:34:41 +02:00
Vincent Bernat
ae69bcb70f common/helpers: fix Diff configuration 2022-09-09 22:49:52 +02:00
Vincent Bernat
06b3fbe400 common/reporter: add deny-list for GetMetrics() 2022-09-09 15:21:58 +02:00
Vincent Bernat
9a3258719a common/helpers: remove global side-effect from DiffFormatter option 2022-09-09 13:58:25 +02:00
Vincent Bernat
f8a795282e inlet/flow: replace raw data test files with PCAP files
Raw data files can be converted with Scapy:

```python
from scapy.all import *
wrpcap("data-1140.pcap",
  Ether(src="00:53:00:11:22:33",dst="00:53:00:44:55:66")/
  IP(src="192.0.2.100", dst="192.0.2.101")/
  UDP(sport=47873,dport=6343)/
  open("data-1140.data", "rb").read())
```
2022-09-09 13:55:09 +02:00
Vincent Bernat
1587c5ff44 common/helpers: move some test functions to separate files 2022-09-09 11:22:35 +02:00
Vincent Bernat
a9bef1c3fc tests: extend Diff() helper to accept new options 2022-08-31 14:30:08 +02:00
Vincent Bernat
c3d2fc64f8 helpers/mapstructure: turn panic while decoding to an error message
While there is more helpful information in a panic, this is confusing
to the user. With the amount of code using reflection, it seems better
to have clearer messages to help the user find the faulty section if
any.
2022-08-30 20:32:45 +02:00
Vincent Bernat
6bfd3a0bd0 inlet/snmp: use netip.Addr internally instead of string
Also, make SubnetMap use `netip.Addr` as well.
2022-08-27 08:13:57 +02:00
Vincent Bernat
e93b57034c orchestrator/clickhouse: fix Networks field validation 2022-08-24 10:10:22 +02:00
Vincent Bernat
d9d3e8023a http: do not restrict LocalAddr() to tests
It is also used to let the orchestrator knows its own address.
2022-08-21 14:51:08 +02:00
Vincent Bernat
3e3bcbdada http: use a method to get local address
And limit its export to testing.
2022-08-21 08:20:14 +02:00
Vincent Bernat
18ee3eac6f build: switch to Go 1.19
This enables us to use atomic.Pointer!
2022-08-19 17:46:49 +02:00
Vincent Bernat
c41fa8cb55 common/helpers: opt-in for custom formatters for diff
Many stuff has a `String()` method that would hide details.
2022-08-16 21:21:22 +02:00
Vincent Bernat
f9b507ff35 common/helpers: add a helper to test configuration decoding
For each case, we test from native map and from YAML. This should
capture all the cases we are interested.

Also, simplify pretty diff by using stringer for everything. I don't
remember why this wasn't the case. Maybe IP addresses? It's possible
to opt out by overriding formatters.
2022-08-16 21:15:23 +02:00
Vincent Bernat
985e678e42 chore: replace map[string]interface{} by gin.H 2022-08-16 19:43:28 +02:00
Vincent Bernat
086536ad03 common/helpers: rename AddMapstructureUnmarshallerHook to Register* 2022-08-14 15:08:00 +02:00
Vincent Bernat
d9a8262f76 common/helpers: make validation work for SubnetMap 2022-08-14 15:06:53 +02:00
Vincent Bernat
574ec7e79e inlet/snmp: add proper support for SNMPv3 2022-08-14 10:20:19 +02:00
Vincent Bernat
0a4275d87d inlet/snmp: add ability to set a version for SNMP
This is mostly useless as we don't provide a way to specify SNMPv3
authentication. We won't keep this config option as is.
2022-08-14 00:57:33 +02:00
Vincent Bernat
cd535c915d common/helpers: make subnetmap work with struct as values
The way it was converted from a mapstruct made it not possible to have
struct as values. Fix that by checking if keys look like IP or not.
2022-08-14 00:54:55 +02:00