We used to ignore source endpoints that are associated with multiple
destination endpoints, which is a partial workaround for our inability
to correctly represent two connections from the same source ip/port
but different processes, or the same destination ip/port but different
processes. See #2665.
However, that condition is too coarse. In particular, we end up
ignoring endpoints that are connected to NATed destinations, since the
latter are represented by two (or more) endpoints.
The change here corrects that.
Edges between the incoming and outgoing internet nodes are typically
artifacts of imperfect connection tracking, e.g. when VIPs and NAT
traversal are in use.
So lets filter them out.
This eliminates the awkward distinction between ProcessRenderer and
ColorConnectedProcessRenderer.
It also ensures that processes resulting from direct rendering of the
process topology (/api/topology/processes is invoking
ProcessWithContainerNameRenderer and /api/topology/processes-by-name
is invoking ProcessNameRenderer) are colored and hence summarising
them correctly sets the 'linkable' property. This was the behaviour
prior to the revamping of the rendering pipeline. However, it doesn't
actually make a practical difference since process detail panels only
show other processes as connection endpoints, and these are always
marked linkable anyway.
It's now done via a special filter, once, after all other filters have
been applied.
Some tests need updating since they were relying on ordinary filters
doing that filtering.
...rather than before. That way, nodes which become unconnected during
filtering are removed, which is what we want. ATM we are depending on
some 'unconnected' filtering inside every filter, which is expensive
and largely redundant. We should soon be able to remove that.
downside: 'unconnected' filtering is no longer memoised.
Instead of three passes
1. building a 'connected' node set
2. marking nodes from that set with a LatestMap entry
3. removing unmarked nodes
we just do two
1. building a 'connected' node set
2. removing nodes not in that set
This does entail duplication of the adjecency list pruning code from
FilterFunc.Apply. We will be able to eliminate that eventually, but
not just yet.
Also, we cannot get rid of ColorConnected completely;
ColorConnectedProcessRenderer uses it to mark nodes, and that
information is required by detailed.processNodeSummary to determine
whether a process in the details panel can be rendered as a link.
All outputs of Memoise() are fixpoints to the function, i.e. feeding
them as inputs to the function just returns them.
We don't hit this optimisation in current code but have had instances
in the past.
This is preparatory to future refactorings: all existing calls are to
Endpoints which have no children and where we don't want a Counter.
We make addChildAndChildren an obvious extension of addChild even
though it adds a dead code path (we never call addChildAndChildren
with an endpoint).
Decoration is in fact quite a simple process that is applied on entry
to rendering: we take a base renderer, transform it with a decorator,
and then render a report with it. The new render.Decorate() function
does exactly that.
There is one exception. When rendering an individual node, e.g. for
showing its details panel in the UI, we must not lose the node during
decoration. That requires some special logic, which previously resided
in the PreciousNodeRenderer, and now lives in handleNode.
Pass in a slice on the stack instead of allocating one on the heap:
reduces garbage, hence makes the program run faster
Also apply knowledge that critbitgo will do an append() with one extra
byte, so we do that allocation up-front too. This is innocuous should
we stop using critbitgo or should its internals change.
This allows us to avoid creating a host of 'IP' type Nodes then
discarding them after matching; instead we match directly and create
just the result we want.