pmacct Local Traffic Monitoring

What pmacct does

pmacct is the flow accounting toolkit bundled with the Network Probe. It ships as several daemons, and Energy Logserver uses them in two distinct roles:

  • Collector (nfacctd, sfacctd): receives NetFlow, IPFIX, or sFlow that network devices export to the probe over UDP, and forwards it into the collection pipeline. This is the default role, covered in Bundled Services and Technical Configuration.

  • Generator (pmacctd): captures packets directly from a host interface in promiscuous mode, aggregates them into flows, and exports those flows as NetFlow. This chapter covers the generator role.

Use the generator when you want to account for the traffic of a host that does not export NetFlow on its own, most commonly the Energy Logserver server itself. It complements Suricata IDS and Zeek: where those inspect content and protocols, pmacctd answers who talked to whom, over which protocol and port, and how much data moved.

How pmacctd fits the Network Probe

pmacctd does not write to Energy Logserver directly. It produces NetFlow and hands it to the collector that already runs on the probe:

Host interface (promiscuous, libpcap)
        |
        v
pmacctd  -- aggregates packets into flows, nfprobe plugin exports NetFlow v9
        |  UDP 127.0.0.1:2055
        v
nfacctd  -- the bundled NetFlow collector (plugins: kafka)
        |  Kafka topic "netflow"
        v
Network Probe network-stream pipeline  -- /etc/logserver-probe/conf.d/network-stream/
        |
        v
Index  stream-netflow-pmacct-*

The right-hand side of this chain already exists on a probe that collects NetFlow: nfacctd listens on UDP 2055, publishes to the Kafka netflow topic, and the network-stream pipeline writes the enriched flows (GeoIP, DNS, bad-IP lookups) to stream-netflow-pmacct-*. What you configure here is only pmacctd, so it captures on the correct interface and exports to the port the collector is already listening on.

This is why there is no One Click step for the generator. One Click installs the Energy Logserver side of a pipeline; here the Energy Logserver side is the existing NetFlow collection path, and the work is entirely host-side.

Note

The hand-off from pmacctd to the collector is a UDP protocol, not a file. pmacctd sends flows and receives no acknowledgement. That shapes what goes wrong: if flows do not arrive, the question is whether pmacctd is exporting and whether the collector is listening on UDP 2055, not whether a file is readable.

Why manual configuration is needed

The pmacct package ships the pmacctd binary but no generator configuration and no service unit. Energy Logserver ships setup scripts for the nfacctd/sfacctd collector role, not for pmacctd. To run the generator you create its configuration file and a systemd unit yourself, described below.

Requirements

  • The pmacct package, installed with the Network Probe (rpm -qa | grep pmacct).

  • A running NetFlow collector on the probe: nfacctd listening on UDP 2055, with the network-stream pipeline active, so the generated flows have somewhere to go. The installer does not create the collector, see Setting Up the NetFlow and sFlow Collectors.

  • Root access on the host you want to account for.

  • The interface that carries the traffic you want to measure.

Step 1: Create the configuration and log directories

The package ships no generator directories, so create them:

mkdir -p /etc/pmacct
chmod 755 /etc/pmacct

mkdir -p /var/log/pmacct
chmod 755 /var/log/pmacct

Step 2: Identify the capture interface

Find the interface that carries the traffic you want to account for. You will write its name into the configuration in the next step.

ip -br addr show

Note the interface name (for example ens192, eth0, enp0s3). The interface does not need an address of its own to be captured, but it must be UP.

Step 3: Create the pmacctd configuration

Create /etc/pmacct/pmacctd.conf. Replace INTERFACE_NAME with the interface from Step 2:

! pmacctd generator configuration for Energy Logserver
! Local traffic accounting with NetFlow v9 export to the local collector

! General
daemonize: true
pidfile: /var/run/pmacctd.pid
syslog: daemon

! Capture
pcap_interface: INTERFACE_NAME
promisc: true

! Export flows as NetFlow v9 to the local collector on UDP 2055
plugins: nfprobe
nfprobe_version: 9
nfprobe_receiver: 127.0.0.1:2055
nfprobe_timeouts: tcp=120:maxlife=3600

! Aggregation key
aggregate: src_host, dst_host, src_port, dst_port, proto, tos

Note

Do not add imt_mem_pools_size or imt_buckets here. Those tune the in-memory table of the memory plugin. With plugins: nfprobe there is no memory table, so pmacctd accepts the keys without error but they do nothing. The memory plugin is only useful if you query flows locally with the pmacct client (pmacct -s), which this setup does not.

Step 4: Create the systemd service

pmacctd ships without a unit. Create /etc/systemd/system/pmacctd.service:

[Unit]
Description=pmacctd - Promiscuous Mode Accounting Daemon
Documentation=man:pmacctd(8)
After=network-online.target
Wants=network-online.target

[Service]
Type=forking
PIDFile=/var/run/pmacctd.pid
ExecStart=/usr/sbin/pmacctd -f /etc/pmacct/pmacctd.conf
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=10
CapabilityBoundingSet=CAP_NET_RAW CAP_NET_ADMIN
AmbientCapabilities=CAP_NET_RAW CAP_NET_ADMIN

[Install]
WantedBy=multi-user.target

Reload systemd and enable the service:

systemctl daemon-reload
systemctl enable pmacctd

Step 5: Start pmacctd

systemctl start pmacctd
systemctl status pmacctd --no-pager

A healthy start reports active (running) with two tasks: the core process and the NetFlow probe plugin. pmacctd parses the configuration only when it starts, so this is also the check for Step 3. If the service fails, read the log as described in pmacctd will not start.

Note

Do not test the configuration by running pmacctd -f /etc/pmacct/pmacctd.conf -d by hand. The -d option only enables debug output. With daemonize: true in the file, the process goes to the background at once, Ctrl+C does not stop it, and it keeps running. If you already started it this way, stop it with kill $(cat /var/run/pmacctd.pid).

Step 6: Verify pmacctd is exporting

Confirm the process is up and the log shows flows leaving for the collector:

journalctl -u pmacctd -n 20 --no-pager

The log line Exporting flows to [127.0.0.1]:iop confirms export; iop is the service-name notation for port 2055.

Verify end to end with test traffic

pmacctd exports a flow only when the flow expires, not on every packet. With the default nfprobe timeouts, which pmacctd prints to the log at start, an ICMP or UDP flow expires after 300 seconds without packets, and a TCP flow 300 seconds after it closes. Generate traffic and wait at least six minutes before concluding anything is wrong:

ping -c 10 8.8.8.8 > /dev/null 2>&1
curl -s https://example.com > /dev/null 2>&1

# wait for flow expiry before the count updates
sleep 360

Then confirm documents are landing in the collector’s index:

curl -s -u admin:PASSWORD \
  "http://localhost:9200/_cat/indices/stream-netflow-pmacct-*?v&h=index,docs.count,store.size"

A growing docs.count on today’s stream-netflow-pmacct-* index confirms the whole chain: capture, export, collection, and indexing.

Explore in Discover

The generated flows join the same index pattern as all collected NetFlow. Open Discover, select the stream-* index pattern, and set a recent time range. To isolate the generator’s own flows, filter on the index stream-netflow-pmacct-*.

Useful fields:

  • netflow.src.ip, netflow.dst.ip: the endpoints of each flow.

  • netflow.src.port, netflow.dst.port: the ports.

  • netflow.protocol_name: TCP, UDP, ICMP.

  • netflow.bytes, netflow.packets: the volume of each flow.

  • netflow.exporter: the address that exported the flow (127.0.0.1 for the local generator). In 8.1.0 this field holds the literal text %{peer_ip_src} until you add peer_src_ip to the collector configuration, see Setting Up the NetFlow and sFlow Collectors.

Troubleshooting

pmacctd will not start

Read the service log for the cause:

journalctl -u pmacctd -n 50 --no-pager

pcap_open_live(): INTERFACE_NAME: No such device means the interface name is wrong. Either the placeholder from Step 3 was never replaced, or the name does not exist on this host. List the real interfaces with ip -br link show and correct pcap_interface.

pcap_open_live(): Permission denied means the process lacks CAP_NET_RAW. Run pmacctd as root, or confirm the CapabilityBoundingSet and AmbientCapabilities lines are present in the unit.

No flows reach the index

pmacctd exports over UDP, which is fire-and-forget: it reports no error even when nothing receives the flows. If the collector is not listening, the kernel discards every packet silently while pmacctd still logs Exporting flows.

Confirm something is bound to the collector port:

ss -ulnp | grep 2055

If nothing is listening, the NetFlow collector is not running. Start it and confirm the network-stream pipeline is active on the probe (see Setting Up the NetFlow and sFlow Collectors). If the collector is listening but the index stays empty, generate traffic and wait for flow expiry, then re-check, since flows are exported only when they expire.

High CPU use

pmacctd builds an aggregation key for every packet and keeps a flow entry for each unique combination. The more fields in the key, the more distinct flows exist, and the more CPU each packet costs. At high traffic volumes a fine-grained aggregate directive is usually what drives the load.

Reduce the aggregation granularity first. Check what you currently aggregate on:

grep aggregate /etc/pmacct/pmacctd.conf

Drop the fields you do not query on. Source and destination IP, port, and protocol produce far fewer flows than adding ToS, interfaces, and MAC addresses on top. Restart and measure again:

systemctl restart pmacctd
top -p "$(pgrep -d, pmacctd)"

If trimming the key is not enough, sample the traffic:

sampling_rate: 100  ! analyse 1 packet in 100

Warning

Sampling trades accuracy for CPU. With sampling_rate: 100, byte and packet counters become estimates scaled by 100, and short flows can be missed entirely. That is acceptable for traffic trends and top-talker views, but not for accounting or forensic use where individual flows matter. Trim the aggregation key first; sample only if the sensor still cannot keep up.

Reducing data volume

To lower the number of exported flows and the storage they consume, raise the export timeouts so flows are batched over longer intervals:

nfprobe_timeouts: tcp=300:maxlife=7200

This reduces the volume of NetFlow records and downstream documents, not the per-packet CPU cost of capture and aggregation. It also delays when data appears: with a long maxlife, an active session may not reach Energy Logserver until it ends or the timeout elapses. Use it to control data volume, and keep the timeouts short if you need flows to surface quickly.

Flows land under the wrong date

NetFlow indices are date-based (stream-netflow-pmacct-YYYY.MM.DD), and the index a flow lands in follows its timestamp. If the host clock is wrong, flows are written to an index for another date and do not appear under a normal time range in Discover. Confirm the clock and enable time synchronisation:

timedatectl
timedatectl set-ntp true

List the indices that actually exist to find where the flows went:

curl -s -u admin:PASSWORD "http://localhost:9200/_cat/indices/stream-netflow-pmacct-*?v"

Many flows to port 53 of the DNS server

The network-stream pipeline resolves flow addresses to hostnames with reverse DNS lookups sent to the server set in DNS_SRV, 8.8.8.8 by default. pmacctd captures these lookups on the interface and exports them as flows, so expect flows from the probe to port 53 of that server. When the same collector also receives flows from a busy network device, such as a firewall exporting NetFlow to the probe, the lookups can reach thousands per minute, and the matching flows keep arriving for several minutes after that traffic stops.

Missing GeoIP data

GeoIP enrichment is applied by the Network Probe network-stream pipeline, not by pmacctd. If flow records have no netflow.geoip fields, confirm the GeoIP databases are installed and current on the probe, and check the probe log for GeoIP errors. Local flows between private addresses have no GeoIP by design.

Definition of terms

  • pmacctd: the pmacct generator daemon. Captures packets from an interface with libpcap and exports flows. Distinct from nfacctd/sfacctd, which receive flows over UDP.

  • nfprobe: the pmacctd plugin that formats flows as NetFlow and exports them to a receiver.

  • Flow: an aggregate of packets that share the same key (source and destination address, ports, protocol) over a time window.

  • Flow expiry: the point at which pmacctd stops accumulating a flow and exports it, either when the connection ends or when a timeout elapses.

  • Promiscuous mode: an interface mode in which the card accepts all packets it sees, not only those addressed to it. Required to account for traffic that passes the interface.