summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Poessinger <christian@poessinger.com>2021-12-24 22:12:19 +0100
committerChristian Poessinger <christian@poessinger.com>2021-12-25 23:27:15 +0100
commit015e26acc8ed65b6a7d778107a83ee8604950f90 (patch)
tree7cc2810b6061d5251b0d82103e72896680d67a9f
parent4abca54698edb09b76e7d059dd35cdcef3512ec4 (diff)
downloadvyos-1x-015e26acc8ed65b6a7d778107a83ee8604950f90.tar.gz
vyos-1x-015e26acc8ed65b6a7d778107a83ee8604950f90.zip
flow-accounting: T4097: move to get_config_dict()
-rw-r--r--data/configd-include.json1
-rw-r--r--data/templates/netflow/uacctd.conf.tmpl111
-rw-r--r--interface-definitions/flow-accounting-conf.xml.in15
-rwxr-xr-xsmoketest/scripts/cli/test_system_flow-accounting.py8
-rwxr-xr-xsrc/conf_mode/flow_accounting_conf.py314
5 files changed, 186 insertions, 263 deletions
diff --git a/data/configd-include.json b/data/configd-include.json
index 6893aaa86..ee4cb0d42 100644
--- a/data/configd-include.json
+++ b/data/configd-include.json
@@ -6,6 +6,7 @@
"dhcpv6_relay.py",
"dns_forwarding.py",
"dynamic_dns.py",
+"flow_accounting_conf.py",
"host_name.py",
"https.py",
"igmp_proxy.py",
diff --git a/data/templates/netflow/uacctd.conf.tmpl b/data/templates/netflow/uacctd.conf.tmpl
index 11fc76769..2a43b3ce2 100644
--- a/data/templates/netflow/uacctd.conf.tmpl
+++ b/data/templates/netflow/uacctd.conf.tmpl
@@ -5,71 +5,68 @@ pidfile: /var/run/uacctd.pid
uacctd_group: 2
uacctd_nl_size: 2097152
snaplen: {{ snaplen }}
-{% if templatecfg['enable-egress'] != none %}
-aggregate: in_iface,out_iface,src_mac,dst_mac,vlan,src_host,dst_host,src_port,dst_port,proto,tos,flows
-{% else %}
-aggregate: in_iface,src_mac,dst_mac,vlan,src_host,dst_host,src_port,dst_port,proto,tos,flows
+aggregate: in_iface{{ ',out_iface' if enable_egress is defined }},src_mac,dst_mac,vlan,src_host,dst_host,src_port,dst_port,proto,tos,flows
+{% set pipe_size = buffer_size | int *1024 *1024 %}
+plugin_pipe_size: {{ pipe_size }}
+{# We need an integer division (//) without any remainder or fraction #}
+plugin_buffer_size: {{ pipe_size // 1000 }}
+{% if syslog_facility is defined and syslog_facility is not none %}
+syslog: {{ syslog_facility }}
{% endif %}
-plugin_pipe_size: {{ templatecfg['plugin_pipe_size'] }}
-plugin_buffer_size: {{ templatecfg['plugin_buffer_size'] }}
-{% if templatecfg['syslog-facility'] != none %}
-syslog: {{ templatecfg['syslog-facility'] }}
-{% endif %}
-{% if templatecfg['disable-imt'] == none %}
+{% if disable_imt is not defined %}
imt_path: /tmp/uacctd.pipe
imt_mem_pools_number: 169
{% endif %}
-plugins: {% if templatecfg['netflow']['servers'] != none %}
-{% for server in templatecfg['netflow']['servers'] %}
-{% if loop.last %}nfprobe[nf_{{ server['address'] }}]{% else %}nfprobe[nf_{{ server['address'] }}],{% endif %}
-{% endfor %}
-{% set plugins_presented = true %}
-{% endif %}
-{% if templatecfg['sflow']['servers'] != none %}
-{% if plugins_presented %}
-{% for server in templatecfg['sflow']['servers'] %},sfprobe[sf_{{ server['address'] }}]{% endfor %}
-{% else %}
-{% for server in templatecfg['sflow']['servers'] %}
-{% if loop.last %}sfprobe[sf_{{ server['address'] }}]{% else %}sfprobe[sf_{{ server['address'] }}],{% endif %}
-{% endfor %}
-{% endif %}
-{% set plugins_presented = true %}
-{% endif %}
-{% if templatecfg['disable-imt'] == none %}
-{% if plugins_presented %},memory{% else %}memory{% endif %}
-{% endif %}
-{% if templatecfg['netflow']['servers'] != none %}
-{% for server in templatecfg['netflow']['servers'] %}
-nfprobe_receiver[nf_{{ server['address'] }}]: {{ server['address'] }}:{{ server['port'] }}
-nfprobe_version[nf_{{ server['address'] }}]: {{ templatecfg['netflow']['version'] }}
-{% if templatecfg['netflow']['engine-id'] != none %}
-nfprobe_engine[nf_{{ server['address'] }}]: {{ templatecfg['netflow']['engine-id'] }}
-{% endif %}
-{% if templatecfg['netflow']['max-flows'] != none %}
-nfprobe_maxflows[nf_{{ server['address'] }}]: {{ templatecfg['netflow']['max-flows'] }}
-{% endif %}
-{% if templatecfg['netflow']['sampling-rate'] != none %}
-sampling_rate[nf_{{ server['address'] }}]: {{ templatecfg['netflow']['sampling-rate'] }}
+{% set plugin = [] %}
+{% if disable_imt is not defined %}
+{% set plugin = ['memory'] %}
{% endif %}
-{% if templatecfg['netflow']['source-ip'] != none %}
-nfprobe_source_ip[nf_{{ server['address'] }}]: {{ templatecfg['netflow']['source-ip'] }}
-{% endif %}
-{% if templatecfg['netflow']['timeout_string'] != '' %}
-nfprobe_timeouts[nf_{{ server['address'] }}]: {{ templatecfg['netflow']['timeout_string'] }}
+{% if netflow is defined and netflow.server is defined and netflow.server is not none %}
+{% for server in netflow.server %}
+{% set plugin = plugin.append('nfprobe[nf_' ~ server ~ ']') %}
+{% endfor %}
{% endif %}
-{% endfor %}
+{% if sflow is defined and sflow.server is defined and sflow.server is not none %}
+{% for server in sflow.server %}
+{% set plugin = plugin.append('sfprobe[sf_' ~ server ~ ']') %}
+{% endfor %}
{% endif %}
+plugins: {{ plugin | join(',') }}
-{% if templatecfg['sflow']['servers'] != none %}
-{% for server in templatecfg['sflow']['servers'] %}
-sfprobe_receiver[sf_{{ server['address'] }}]: {{ server['address'] }}:{{ server['port'] }}
-sfprobe_agentip[sf_{{ server['address'] }}]: {{ templatecfg['sflow']['agent-address'] }}
-{% if templatecfg['sflow']['sampling-rate'] != none %}
-sampling_rate[sf_{{ server['address'] }}]: {{ templatecfg['sflow']['sampling-rate'] }}
-{% endif %}
-{% if templatecfg['sflow']['source-address'] != none %}
-sfprobe_source_ip[sf_{{ server['address'] }}]: {{ templatecfg['sflow']['source-address'] }}
+{% if netflow is defined and netflow.server is defined and netflow.server is not none %}
+# NetFlow servers
+{% for server, server_config in netflow.server.items() %}
+nfprobe_receiver[nf_{{ server }}]: {{ server }}:{{ server_config.port }}
+nfprobe_version[nf_{{ server }}]: {{ netflow.version }}
+{% if netflow.engine_id is defined and netflow.engine_id is not none %}
+nfprobe_engine[nf_{{ server }}]: {{ netflow.engine_id }}
+{% endif %}
+{% if netflow.max_flows is defined and netflow.max_flows is not none %}
+nfprobe_maxflows[nf_{{ server }}]: {{ netflow.max_flows }}
+{% endif %}
+{% if netflow.sampling_rate is defined and netflow.sampling_rate is not none %}
+sampling_rate[nf_{{ server }}]: {{ netflow.sampling_rate }}
+{% endif %}
+{% if netflow.source_ip is defined and netflow.source_ip is not none %}
+nfprobe_source_ip[nf_{{ server }}]: {{ netflow.source_ip }}
+{% endif %}
+{% if netflow.timeout is defined and netflow.timeout is not none %}
+nfprobe_timeouts[nf_{{ server }}]: expint={{ netflow.timeout.expiry_interval }}:general={{ netflow.timeout.flow_generic }}:icmp={{ netflow.timeout.icmp }}:maxlife={{ netflow.timeout.max_active_life }}:tcp.fin={{ netflow.timeout.tcp_fin }}:tcp={{ netflow.timeout.tcp_generic }}:tcp.rst={{ netflow.timeout.tcp_rst }}:udp={{ netflow.timeout.udp }}
+{% endif %}
+{% endfor %}
{% endif %}
-{% endfor %}
+
+{% if sflow is defined and sflow.server is defined and sflow.server is not none %}
+# sFlow servers
+{% for server, server_config in sflow.server.items() %}
+sfprobe_receiver[sf_{{ server }}]: {{ server }}:{{ server_config.port }}
+sfprobe_agentip[sf_{{ server }}]: {{ sflow.agent_address }}
+{% if sflow.sampling_rate is defined and sflow.sampling_rate is not none %}
+sampling_rate[sf_{{ server }}]: {{ sflow.sampling_rate }}
+{% endif %}
+{% if sflow.source_address is defined and sflow.source_address is not none %}
+sfprobe_source_ip[sf_{{ server }}]: {{ sflow.source_address }}
+{% endif %}
+{% endfor %}
{% endif %}
diff --git a/interface-definitions/flow-accounting-conf.xml.in b/interface-definitions/flow-accounting-conf.xml.in
index 9f13c295b..02364425f 100644
--- a/interface-definitions/flow-accounting-conf.xml.in
+++ b/interface-definitions/flow-accounting-conf.xml.in
@@ -14,12 +14,13 @@
<help>Buffer size</help>
<valueHelp>
<format>u32</format>
- <description>Buffer size in MiB</description>
+ <description>Buffer size in MiB (default: 10)</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 0-4294967295"/>
</constraint>
</properties>
+ <defaultValue>10</defaultValue>
</leafNode>
<leafNode name="enable-egress">
<properties>
@@ -218,6 +219,7 @@
<description>Internet Protocol Flow Information Export (IPFIX)</description>
</valueHelp>
</properties>
+ <defaultValue>9</defaultValue>
</leafNode>
<tagNode name="server">
<properties>
@@ -247,6 +249,7 @@
<validator name="numeric" argument="--range 1025-65535"/>
</constraint>
</properties>
+ <defaultValue>2055</defaultValue>
</leafNode>
</children>
</tagNode>
@@ -266,6 +269,7 @@
<validator name="numeric" argument="--range 0-2147483647"/>
</constraint>
</properties>
+ <defaultValue>60</defaultValue>
</leafNode>
<leafNode name="flow-generic">
<properties>
@@ -278,6 +282,7 @@
<validator name="numeric" argument="--range 0-2147483647"/>
</constraint>
</properties>
+ <defaultValue>3600</defaultValue>
</leafNode>
<leafNode name="icmp">
<properties>
@@ -290,6 +295,7 @@
<validator name="numeric" argument="--range 0-2147483647"/>
</constraint>
</properties>
+ <defaultValue>300</defaultValue>
</leafNode>
<leafNode name="max-active-life">
<properties>
@@ -302,6 +308,7 @@
<validator name="numeric" argument="--range 0-2147483647"/>
</constraint>
</properties>
+ <defaultValue>604800</defaultValue>
</leafNode>
<leafNode name="tcp-fin">
<properties>
@@ -314,6 +321,7 @@
<validator name="numeric" argument="--range 0-2147483647"/>
</constraint>
</properties>
+ <defaultValue>300</defaultValue>
</leafNode>
<leafNode name="tcp-generic">
<properties>
@@ -326,6 +334,7 @@
<validator name="numeric" argument="--range 0-2147483647"/>
</constraint>
</properties>
+ <defaultValue>3600</defaultValue>
</leafNode>
<leafNode name="tcp-rst">
<properties>
@@ -338,6 +347,7 @@
<validator name="numeric" argument="--range 0-2147483647"/>
</constraint>
</properties>
+ <defaultValue>120</defaultValue>
</leafNode>
<leafNode name="udp">
<properties>
@@ -350,6 +360,7 @@
<validator name="numeric" argument="--range 0-2147483647"/>
</constraint>
</properties>
+ <defaultValue>300</defaultValue>
</leafNode>
</children>
</node>
@@ -380,6 +391,7 @@
<regex>^auto$</regex>
</constraint>
</properties>
+ <defaultValue>auto</defaultValue>
</leafNode>
<leafNode name="sampling-rate">
<properties>
@@ -421,6 +433,7 @@
<validator name="numeric" argument="--range 1025-65535"/>
</constraint>
</properties>
+ <defaultValue>6343</defaultValue>
</leafNode>
</children>
</tagNode>
diff --git a/smoketest/scripts/cli/test_system_flow-accounting.py b/smoketest/scripts/cli/test_system_flow-accounting.py
index 57866a198..f3bed635c 100755
--- a/smoketest/scripts/cli/test_system_flow-accounting.py
+++ b/smoketest/scripts/cli/test_system_flow-accounting.py
@@ -201,11 +201,11 @@ class TestSystemFlowAccounting(VyOSUnitTestSHIM.TestCase):
uacctd = read_file(uacctd_conf)
- tmp = 'plugins: '
+ tmp = []
+ tmp.append('memory')
for server, server_config in netflow_server.items():
- tmp += f'nfprobe[nf_{server}],'
- tmp += 'memory'
- self.assertIn(f'{tmp}', uacctd)
+ tmp.append(f'nfprobe[nf_{server}]')
+ self.assertIn('plugins: ' + ','.join(tmp), uacctd)
for server, server_config in netflow_server.items():
self.assertIn(f'nfprobe_engine[nf_{server}]: {engine_id}', uacctd)
diff --git a/src/conf_mode/flow_accounting_conf.py b/src/conf_mode/flow_accounting_conf.py
index daad00067..5f903bf69 100755
--- a/src/conf_mode/flow_accounting_conf.py
+++ b/src/conf_mode/flow_accounting_conf.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2020 VyOS maintainers and contributors
+# Copyright (C) 2018-2021 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -16,42 +16,33 @@
import os
import re
+
from sys import exit
import ipaddress
from ipaddress import ip_address
-from jinja2 import FileSystemLoader, Environment
+from vyos.config import Config
+from vyos.configdict import dict_merge
from vyos.ifconfig import Section
from vyos.ifconfig import Interface
-from vyos.config import Config
-from vyos import ConfigError
-from vyos.util import cmd
from vyos.template import render
-
+from vyos.util import cmd
+from vyos.validate import is_addr_assigned
+from vyos.xml import defaults
+from vyos import ConfigError
from vyos import airbag
airbag.enable()
# default values
-default_sflow_server_port = 6343
-default_netflow_server_port = 2055
-default_plugin_pipe_size = 10
default_captured_packet_size = 128
-default_netflow_version = '9'
-default_sflow_agentip = 'auto'
+
uacctd_conf_path = '/etc/pmacct/uacctd.conf'
iptables_nflog_table = 'raw'
iptables_nflog_chain = 'VYATTA_CT_PREROUTING_HOOK'
egress_iptables_nflog_table = 'mangle'
egress_iptables_nflog_chain = 'FORWARD'
-# helper functions
-# check if node exists and return True if this is true
-def _node_exists(path):
- vyos_config = Config()
- if vyos_config.exists(path):
- return True
-
# get sFlow agent-ip if agent-address is "auto" (default behaviour)
def _sflow_default_agentip(config):
# check if any of BGP, OSPF, OSPFv3 protocols are configured and use router-id from there
@@ -154,232 +145,153 @@ def _iptables_config(configured_ifaces, direction):
cmd(command, raising=ConfigError)
-def get_config():
- vc = Config()
- vc.set_level('')
- # Convert the VyOS config to an abstract internal representation
- flow_config = {
- 'flow-accounting-configured': vc.exists('system flow-accounting'),
- 'buffer-size': vc.return_value('system flow-accounting buffer-size'),
- 'enable-egress': _node_exists('system flow-accounting enable-egress'),
- 'disable-imt': _node_exists('system flow-accounting disable-imt'),
- 'syslog-facility': vc.return_value('system flow-accounting syslog-facility'),
- 'interfaces': None,
- 'sflow': {
- 'configured': vc.exists('system flow-accounting sflow'),
- 'agent-address': vc.return_value('system flow-accounting sflow agent-address'),
- 'sampling-rate': vc.return_value('system flow-accounting sflow sampling-rate'),
- 'servers': None,
- 'source-address': vc.return_value('system flow-accounting sflow source-address')
- },
- 'netflow': {
- 'configured': vc.exists('system flow-accounting netflow'),
- 'engine-id': vc.return_value('system flow-accounting netflow engine-id'),
- 'max-flows': vc.return_value('system flow-accounting netflow max-flows'),
- 'sampling-rate': vc.return_value('system flow-accounting netflow sampling-rate'),
- 'source-ip': vc.return_value('system flow-accounting netflow source-ip'),
- 'version': vc.return_value('system flow-accounting netflow version'),
- 'timeout': {
- 'expint': vc.return_value('system flow-accounting netflow timeout expiry-interval'),
- 'general': vc.return_value('system flow-accounting netflow timeout flow-generic'),
- 'icmp': vc.return_value('system flow-accounting netflow timeout icmp'),
- 'maxlife': vc.return_value('system flow-accounting netflow timeout max-active-life'),
- 'tcp.fin': vc.return_value('system flow-accounting netflow timeout tcp-fin'),
- 'tcp': vc.return_value('system flow-accounting netflow timeout tcp-generic'),
- 'tcp.rst': vc.return_value('system flow-accounting netflow timeout tcp-rst'),
- 'udp': vc.return_value('system flow-accounting netflow timeout udp')
- },
- 'servers': None
- }
- }
-
- # get interfaces list
- if vc.exists('system flow-accounting interface'):
- flow_config['interfaces'] = vc.return_values('system flow-accounting interface')
-
- # get sFlow collectors list
- if vc.exists('system flow-accounting sflow server'):
- flow_config['sflow']['servers'] = []
- sflow_collectors = vc.list_nodes('system flow-accounting sflow server')
- for collector in sflow_collectors:
- port = default_sflow_server_port
- if vc.return_value("system flow-accounting sflow server {} port".format(collector)):
- port = vc.return_value("system flow-accounting sflow server {} port".format(collector))
- flow_config['sflow']['servers'].append({ 'address': collector, 'port': port })
-
- # get NetFlow collectors list
- if vc.exists('system flow-accounting netflow server'):
- flow_config['netflow']['servers'] = []
- netflow_collectors = vc.list_nodes('system flow-accounting netflow server')
- for collector in netflow_collectors:
- port = default_netflow_server_port
- if vc.return_value("system flow-accounting netflow server {} port".format(collector)):
- port = vc.return_value("system flow-accounting netflow server {} port".format(collector))
- flow_config['netflow']['servers'].append({ 'address': collector, 'port': port })
-
- # get sflow agent-id
- if flow_config['sflow']['agent-address'] == None or flow_config['sflow']['agent-address'] == 'auto':
- flow_config['sflow']['agent-address'] = _sflow_default_agentip(vc)
-
- # get NetFlow version
- if not flow_config['netflow']['version']:
- flow_config['netflow']['version'] = default_netflow_version
-
- # convert NetFlow engine-id format, if this is necessary
- if flow_config['netflow']['engine-id'] and flow_config['netflow']['version'] == '5':
- regex_filter = re.compile('^\d+$')
- if regex_filter.search(flow_config['netflow']['engine-id']):
- flow_config['netflow']['engine-id'] = "{}:0".format(flow_config['netflow']['engine-id'])
-
- # return dict with flow-accounting configuration
- return flow_config
-
-def verify(config):
- # Verify that configuration is valid
- # skip all checks if flow-accounting was removed
- if not config['flow-accounting-configured']:
- return True
+def get_config(config=None):
+ if config:
+ conf = config
+ else:
+ conf = Config()
+ base = ['system', 'flow-accounting']
+ if not conf.exists(base):
+ return None
+
+ flow_accounting = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
+
+ # We have gathered the dict representation of the CLI, but there are default
+ # options which we need to update into the dictionary retrived.
+ default_values = defaults(base)
+
+ # delete individual flow type default - should only be added if user uses
+ # this feature
+ for flow_type in ['sflow', 'netflow']:
+ if flow_type in default_values:
+ del default_values[flow_type]
+ flow_accounting = dict_merge(default_values, flow_accounting)
+
+ for flow_type in ['sflow', 'netflow']:
+ if flow_type in flow_accounting:
+ default_values = defaults(base + [flow_type])
+ # we need to merge individual server configurations
+ if 'server' in default_values:
+ del default_values['server']
+ flow_accounting[flow_type] = dict_merge(default_values, flow_accounting[flow_type])
+
+ if 'server' in flow_accounting[flow_type]:
+ default_values = defaults(base + [flow_type, 'server'])
+ for server in flow_accounting[flow_type]['server']:
+ flow_accounting[flow_type]['server'][server] = dict_merge(
+ default_values,flow_accounting[flow_type]['server'][server])
+
+ flow_accounting['snaplen'] = default_captured_packet_size
+
+ return flow_accounting
+
+def verify(flow_config):
+ if not flow_config:
+ return None
# check if at least one collector is enabled
- if not (config['sflow']['configured'] or config['netflow']['configured'] or not config['disable-imt']):
- raise ConfigError("You need to configure at least one sFlow or NetFlow protocol, or not set \"disable-imt\" for flow-accounting")
+ if 'sflow' not in flow_config and 'netflow' not in flow_config and 'disable_imt' in flow_config:
+ raise ConfigError('You need to configure at least sFlow or NetFlow, ' \
+ 'or not set "disable-imt" for flow-accounting!')
# Check if at least one interface is configured
- if not config['interfaces']:
- raise ConfigError("You need to configure at least one interface for flow-accounting")
+ if 'interface' not in flow_config:
+ raise ConfigError('Flow accounting requires at least one interface to ' \
+ 'be configured!')
# check that all configured interfaces exists in the system
- for iface in config['interfaces']:
- if not iface in Section.interfaces():
- # chnged from error to warning to allow adding dynamic interfaces and interface templates
- # raise ConfigError("The {} interface is not presented in the system".format(iface))
- print("Warning: the {} interface is not presented in the system".format(iface))
+ for interface in flow_config['interface']:
+ if interface not in Section.interfaces():
+ # Changed from error to warning to allow adding dynamic interfaces
+ # and interface templates
+ print(f'Warning: Interface "{interface}" is not presented in the system')
# check sFlow configuration
- if config['sflow']['configured']:
- # check if at least one sFlow collector is configured if sFlow configuration is presented
- if not config['sflow']['servers']:
- raise ConfigError("You need to configure at least one sFlow server")
+ if 'sflow' in flow_config:
+ # check if at least one sFlow collector is configured
+ if 'server' not in flow_config['sflow']:
+ raise ConfigError('You need to configure at least one sFlow server!')
# check that all sFlow collectors use the same IP protocol version
sflow_collector_ipver = None
- for sflow_collector in config['sflow']['servers']:
+ for server in flow_config['sflow']['server']:
if sflow_collector_ipver:
- if sflow_collector_ipver != ip_address(sflow_collector['address']).version:
+ if sflow_collector_ipver != ip_address(server).version:
raise ConfigError("All sFlow servers must use the same IP protocol")
else:
- sflow_collector_ipver = ip_address(sflow_collector['address']).version
-
+ sflow_collector_ipver = ip_address(server).version
# check agent-id for sFlow: we should avoid mixing IPv4 agent-id with IPv6 collectors and vice-versa
- for sflow_collector in config['sflow']['servers']:
- if ip_address(sflow_collector['address']).version != ip_address(config['sflow']['agent-address']).version:
- raise ConfigError("Different IP address versions cannot be mixed in \"sflow agent-address\" and \"sflow server\". You need to set manually the same IP version for \"agent-address\" as for all sFlow servers")
-
- # check if configured sFlow agent-id exist in the system
- agent_id_presented = None
- for iface in Section.interfaces():
- for address in Interface(iface).get_addr():
- # check an IP, if this is not loopback
- regex_filter = re.compile('^(?!(127)|(::1)|(fe80))(?P<ipaddr>[a-f\d\.:]+)/\d+$')
- if regex_filter.search(address):
- if regex_filter.search(address).group('ipaddr') == config['sflow']['agent-address']:
- agent_id_presented = True
- break
- if not agent_id_presented:
- raise ConfigError("Your \"sflow agent-address\" does not exist in the system")
+ for server in flow_config['sflow']['server']:
+ if flow_config['sflow']['agent_address'] != 'auto':
+ if ip_address(server).version != ip_address(flow_config['sflow']['agent_address']).version:
+ raise ConfigError("Different IP address versions cannot be mixed in \"sflow agent-address\" and \"sflow server\". You need to set manually the same IP version for \"agent-address\" as for all sFlow servers")
+
+ if 'agent_address' in flow_config['sflow']:
+ agent_address = flow_config['sflow']['agent_address']
+ if agent_address != 'auto' and not is_addr_assigned(agent_address):
+ print(f'Warning: Configured "sflow agent-address" does not exist in the system!')
# check NetFlow configuration
- if config['netflow']['configured']:
+ if 'netflow' in flow_config:
# check if at least one NetFlow collector is configured if NetFlow configuration is presented
- if not config['netflow']['servers']:
- raise ConfigError("You need to configure at least one NetFlow server")
+ if 'server' not in flow_config['netflow']:
+ raise ConfigError('You need to configure at least one NetFlow server!')
# check if configured netflow source-ip exist in the system
- if config['netflow']['source-ip']:
- source_ip_presented = None
- for iface in Section.interfaces():
- for address in Interface(iface).get_addr():
- # check an IP
- regex_filter = re.compile('^(?!(127)|(::1)|(fe80))(?P<ipaddr>[a-f\d\.:]+)/\d+$')
- if regex_filter.search(address):
- if regex_filter.search(address).group('ipaddr') == config['netflow']['source-ip']:
- source_ip_presented = True
- break
- if not source_ip_presented:
- print("Warning: your \"netflow source-ip\" does not exist in the system")
+ if 'source_ip' in flow_config['netflow']:
+ if not is_addr_assigned(flow_config['netflow']['source_ip']):
+ print(f'Warning: your "netflow source-ip" does not exist in the system!')
# check if engine-id compatible with selected protocol version
- if config['netflow']['engine-id']:
+ if 'engine_id' in flow_config['netflow']:
v5_filter = '^(\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]):(\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])$'
v9v10_filter = '^(\d|[1-9]\d{1,8}|[1-3]\d{9}|4[01]\d{8}|42[0-8]\d{7}|429[0-3]\d{6}|4294[0-8]\d{5}|42949[0-5]\d{4}|429496[0-6]\d{3}|4294967[01]\d{2}|42949672[0-8]\d|429496729[0-5])$'
- if config['netflow']['version'] == '5':
+ engine_id = flow_config['netflow']['engine_id']
+ version = flow_config['netflow']['version']
+
+ if flow_config['netflow']['version'] == '5':
regex_filter = re.compile(v5_filter)
- if not regex_filter.search(config['netflow']['engine-id']):
- raise ConfigError("You cannot use NetFlow engine-id {} together with NetFlow protocol version {}".format(config['netflow']['engine-id'], config['netflow']['version']))
+ if not regex_filter.search(engine_id):
+ raise ConfigError(f'You cannot use NetFlow engine-id "{engine_id}" '\
+ f'together with NetFlow protocol version "{version}"!')
else:
regex_filter = re.compile(v9v10_filter)
- if not regex_filter.search(config['netflow']['engine-id']):
+ if not regex_filter.search(flow_config['netflow']['engine_id']):
raise ConfigError("You cannot use NetFlow engine-id {} together with NetFlow protocol version {}".format(config['netflow']['engine-id'], config['netflow']['version']))
# return True if all checks were passed
return True
-def generate(config):
- # skip all checks if flow-accounting was removed
- if not config['flow-accounting-configured']:
- return True
+def generate(flow_config):
+ if not flow_config:
+ return None
- # Calculate all necessary values
- if config['buffer-size']:
- # circular queue size
- config['plugin_pipe_size'] = int(config['buffer-size']) * 1024**2
- else:
- config['plugin_pipe_size'] = default_plugin_pipe_size * 1024**2
- # transfer buffer size
- # recommended value from pmacct developers 1/1000 of pipe size
- config['plugin_buffer_size'] = int(config['plugin_pipe_size'] / 1000)
-
- # Prepare a timeouts string
- timeout_string = ''
- for timeout_type, timeout_value in config['netflow']['timeout'].items():
- if timeout_value:
- if timeout_string == '':
- timeout_string = "{}{}={}".format(timeout_string, timeout_type, timeout_value)
- else:
- timeout_string = "{}:{}={}".format(timeout_string, timeout_type, timeout_value)
- config['netflow']['timeout_string'] = timeout_string
+ render(uacctd_conf_path, 'netflow/uacctd.conf.tmpl', flow_config)
- render(uacctd_conf_path, 'netflow/uacctd.conf.tmpl', {
- 'templatecfg': config,
- 'snaplen': default_captured_packet_size,
- })
-
-
-def apply(config):
- # define variables
- command = None
+def apply(flow_config):
+ action = 'restart'
# Check if flow-accounting was removed and define command
- if not config['flow-accounting-configured']:
- command = 'systemctl stop uacctd.service'
- else:
- command = 'systemctl restart uacctd.service'
+ if not flow_config:
+ _iptables_config([], 'ingress')
+ _iptables_config([], 'egress')
+
+ # Stop flow-accounting daemon
+ cmd('systemctl stop uacctd.service')
+ return
- # run command to start or stop flow-accounting
- cmd(command, raising=ConfigError, message='Failed to start/stop flow-accounting')
+ # Start/reload flow-accounting daemon
+ cmd(f'systemctl restart uacctd.service')
# configure iptables rules for defined interfaces
- if config['interfaces']:
- _iptables_config(config['interfaces'], 'ingress')
+ if 'interface' in flow_config:
+ _iptables_config(flow_config['interface'], 'ingress')
# configure egress the same way if configured otherwise remove it
- if config['enable-egress']:
- _iptables_config(config['interfaces'], 'egress')
+ if 'enable_egress' in flow_config:
+ _iptables_config(flow_config['interface'], 'egress')
else:
_iptables_config([], 'egress')
- else:
- _iptables_config([], 'ingress')
- _iptables_config([], 'egress')
if __name__ == '__main__':
try: