Skip to content

Commit

Permalink
T6895: Merge the hsflowd-based sFlow and uacctd-based sFlow
Browse files Browse the repository at this point in the history
  • Loading branch information
natali-rs1985 committed Jan 20, 2025
1 parent 99d0c7a commit 973b712
Show file tree
Hide file tree
Showing 11 changed files with 123 additions and 244 deletions.
23 changes: 0 additions & 23 deletions data/templates/pmacct/uacctd.conf.j2
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,6 @@ imt_mem_pools_number: 169
{% set _ = plugin.append('nfprobe['~ nf_server_key ~ ']') %}
{% endfor %}
{% endif %}
{% if sflow.server is vyos_defined %}
{% for server in sflow.server %}
{% set sf_server_key = 'sf_' ~ server | dot_colon_to_dash %}
{% set _ = plugin.append('sfprobe[' ~ sf_server_key ~ ']') %}
{% endfor %}
{% endif %}
{% if disable_imt is not defined %}
{% set _ = plugin.append('memory') %}
{% endif %}
Expand Down Expand Up @@ -61,20 +55,3 @@ nfprobe_timeouts[{{ nf_server_key }}]: expint={{ netflow.timeout.expiry_interval

{% endfor %}
{% endif %}

{% if sflow.server is vyos_defined %}
# sFlow servers
{% for server, server_config in sflow.server.items() %}
{# # prevent pmacct syntax error when using IPv6 flow collectors #}
{% set sf_server_key = 'sf_' ~ server | dot_colon_to_dash %}
sfprobe_receiver[{{ sf_server_key }}]: {{ server | bracketize_ipv6 }}:{{ server_config.port }}
sfprobe_agentip[{{ sf_server_key }}]: {{ sflow.agent_address }}
{% if sflow.sampling_rate is vyos_defined %}
sampling_rate[{{ sf_server_key }}]: {{ sflow.sampling_rate }}
{% endif %}
{% if sflow.source_address is vyos_defined %}
sfprobe_source_ip[{{ sf_server_key }}]: {{ sflow.source_address | bracketize_ipv6 }}
{% endif %}

{% endfor %}
{% endif %}
3 changes: 3 additions & 0 deletions data/templates/sflow/hsflowd.conf.j2
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ sflow {
pcap { dev={{ iface }} }
{% endfor %}
{% endif %}
{% if enable_egress is vyos_defined %}
psample { group=1 egress=on }
{% endif %}
{% if drop_monitor_limit is vyos_defined %}
dropmon { limit={{ drop_monitor_limit }} start=on sw=on hw=off }
{% endif %}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<!-- include start from include/version/flow-accounting-version.xml.i -->
<syntaxVersion component='flow-accounting' version='1'></syntaxVersion>
<syntaxVersion component='flow-accounting' version='2'></syntaxVersion>
<!-- include end -->
67 changes: 0 additions & 67 deletions interface-definitions/system_flow-accounting.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -362,73 +362,6 @@
</node>
</children>
</node>
<node name="sflow">
<properties>
<help>sFlow settings</help>
</properties>
<children>
<leafNode name="agent-address">
<properties>
<help>sFlow agent IPv4 address</help>
<completionHelp>
<list>auto</list>
<script>${vyos_completion_dir}/list_local_ips.sh --ipv4</script>
</completionHelp>
<valueHelp>
<format>ipv4</format>
<description>sFlow IPv4 agent address</description>
</valueHelp>
<constraint>
<validator name="ipv4-address"/>
</constraint>
</properties>
</leafNode>
<leafNode name="sampling-rate">
<properties>
<help>sFlow sampling-rate</help>
<valueHelp>
<format>u32</format>
<description>Sampling rate (1 in N packets)</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 0-4294967295"/>
</constraint>
</properties>
</leafNode>
<tagNode name="server">
<properties>
<help>sFlow destination server</help>
<valueHelp>
<format>ipv4</format>
<description>IPv4 server to export sFlow</description>
</valueHelp>
<valueHelp>
<format>ipv6</format>
<description>IPv6 server to export sFlow</description>
</valueHelp>
<constraint>
<validator name="ip-address"/>
</constraint>
</properties>
<children>
<leafNode name="port">
<properties>
<help>sFlow port number</help>
<valueHelp>
<format>u32:1025-65535</format>
<description>sFlow port number</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 1025-65535"/>
</constraint>
</properties>
<defaultValue>6343</defaultValue>
</leafNode>
</children>
</tagNode>
#include <include/source-address-ipv4-ipv6.xml.i>
</children>
</node>
#include <include/interface/vrf.xml.i>
</children>
</node>
Expand Down
6 changes: 6 additions & 0 deletions interface-definitions/system_sflow.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,12 @@
</leafNode>
</children>
</tagNode>
<leafNode name="enable-egress">
<properties>
<help>Enable egress sampling</help>
<valueless/>
</properties>
</leafNode>
#include <include/interface/vrf.xml.i>
</children>
</node>
Expand Down
4 changes: 3 additions & 1 deletion smoketest/config-tests/bgp-big-as-cloud
Original file line number Diff line number Diff line change
Expand Up @@ -836,7 +836,6 @@ set system flow-accounting interface 'eth0.4089'
set system flow-accounting netflow engine-id '1'
set system flow-accounting netflow server 192.0.2.55 port '2055'
set system flow-accounting netflow version '9'
set system flow-accounting sflow server 1.2.3.4 port '1234'
set system flow-accounting syslog-facility 'daemon'
set system host-name 'vyos'
set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/'
Expand All @@ -845,6 +844,9 @@ set system name-server '2001:db8::1'
set system name-server '2001:db8::2'
set system name-server '192.0.2.1'
set system name-server '192.0.2.2'
set system sflow interface 'eth0.4088'
set system sflow interface 'eth0.4089'
set system sflow server 1.2.3.4 port '1234'
set system syslog global facility all level 'all'
set system syslog global preserve-fqdn
set system time-zone 'Europe/Zurich'
107 changes: 1 addition & 106 deletions smoketest/scripts/cli/test_system_flow-accounting.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,111 +97,6 @@ def test_basic(self):
self.assertIn(f'syslog: {syslog}', uacctd)
self.assertIn(f'plugins: memory', uacctd)

def test_sflow(self):
sampling_rate = '4000'
source_address = '192.0.2.1'
dummy_if = 'dum3841'
agent_address = '192.0.2.2'

sflow_server = {
'1.2.3.4' : { },
'5.6.7.8' : { 'port' : '6000' },
}

self.cli_set(['interfaces', 'dummy', dummy_if, 'address', agent_address + '/32'])
self.cli_set(['interfaces', 'dummy', dummy_if, 'address', source_address + '/32'])
self.cli_set(base_path + ['disable-imt'])

# You need to configure at least one interface for flow-accounting
with self.assertRaises(ConfigSessionError):
self.cli_commit()
for interface in Section.interfaces('ethernet'):
self.cli_set(base_path + ['interface', interface])


# You need to configure at least one sFlow or NetFlow protocol, or not
# set "disable-imt" for flow-accounting
with self.assertRaises(ConfigSessionError):
self.cli_commit()

self.cli_set(base_path + ['sflow', 'agent-address', agent_address])
self.cli_set(base_path + ['sflow', 'sampling-rate', sampling_rate])
self.cli_set(base_path + ['sflow', 'source-address', source_address])
for server, server_config in sflow_server.items():
self.cli_set(base_path + ['sflow', 'server', server])
if 'port' in server_config:
self.cli_set(base_path + ['sflow', 'server', server, 'port', server_config['port']])

# commit changes
self.cli_commit()

uacctd = read_file(uacctd_conf)

# when 'disable-imt' is not configured on the CLI it must be present
self.assertNotIn(f'imt_path: /tmp/uacctd.pipe', uacctd)
self.assertNotIn(f'imt_mem_pools_number: 169', uacctd)
self.assertNotIn(f'plugins: memory', uacctd)

for server, server_config in sflow_server.items():
plugin_name = server.replace('.', '-')
if 'port' in server_config:
self.assertIn(f'sfprobe_receiver[sf_{plugin_name}]: {server}', uacctd)
else:
self.assertIn(f'sfprobe_receiver[sf_{plugin_name}]: {server}:6343', uacctd)

self.assertIn(f'sfprobe_agentip[sf_{plugin_name}]: {agent_address}', uacctd)
self.assertIn(f'sampling_rate[sf_{plugin_name}]: {sampling_rate}', uacctd)
self.assertIn(f'sfprobe_source_ip[sf_{plugin_name}]: {source_address}', uacctd)

self.cli_delete(['interfaces', 'dummy', dummy_if])

def test_sflow_ipv6(self):
sampling_rate = '100'
sflow_server = {
'2001:db8::1' : { },
'2001:db8::2' : { 'port' : '6000' },
}

self.cli_set(base_path + ['disable-imt'])

# You need to configure at least one interface for flow-accounting
with self.assertRaises(ConfigSessionError):
self.cli_commit()
for interface in Section.interfaces('ethernet'):
self.cli_set(base_path + ['interface', interface])


# You need to configure at least one sFlow or NetFlow protocol, or not
# set "disable-imt" for flow-accounting
with self.assertRaises(ConfigSessionError):
self.cli_commit()

self.cli_set(base_path + ['sflow', 'sampling-rate', sampling_rate])
for server, server_config in sflow_server.items():
self.cli_set(base_path + ['sflow', 'server', server])
if 'port' in server_config:
self.cli_set(base_path + ['sflow', 'server', server, 'port', server_config['port']])

# commit changes
self.cli_commit()

uacctd = read_file(uacctd_conf)

# when 'disable-imt' is not configured on the CLI it must be present
self.assertNotIn(f'imt_path: /tmp/uacctd.pipe', uacctd)
self.assertNotIn(f'imt_mem_pools_number: 169', uacctd)
self.assertNotIn(f'plugins: memory', uacctd)

for server, server_config in sflow_server.items():
tmp_srv = server
tmp_srv = tmp_srv.replace(':', '-')

if 'port' in server_config:
self.assertIn(f'sfprobe_receiver[sf_{tmp_srv}]: {bracketize_ipv6(server)}', uacctd)
else:
self.assertIn(f'sfprobe_receiver[sf_{tmp_srv}]: {bracketize_ipv6(server)}:6343', uacctd)
self.assertIn(f'sampling_rate[sf_{tmp_srv}]: {sampling_rate}', uacctd)

def test_netflow(self):
engine_id = '33'
max_flows = '667'
Expand Down Expand Up @@ -288,8 +183,8 @@ def test_netflow(self):

self.assertIn(f'nfprobe_timeouts[nf_{tmp_srv}]: expint={tmo_expiry}:general={tmo_flow}:icmp={tmo_icmp}:maxlife={tmo_max}:tcp.fin={tmo_tcp_fin}:tcp={tmo_tcp_generic}:tcp.rst={tmo_tcp_rst}:udp={tmo_udp}', uacctd)


self.cli_delete(['interfaces', 'dummy', dummy_if])


if __name__ == '__main__':
unittest.main(verbosity=2)
33 changes: 33 additions & 0 deletions smoketest/scripts/cli/test_system_sflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,39 @@ def test_sflow(self):
for interface in Section.interfaces('ethernet'):
self.assertIn(f'pcap {{ dev={interface} }}', hsflowd)

def test_sflow_ipv6(self):
sampling_rate = '100'
default_polling = '30'
default_port = '6343'
sflow_server = {
'2001:db8::1': {},
'2001:db8::2': {'port': '8023'},
}

for interface in Section.interfaces('ethernet'):
self.cli_set(base_path + ['interface', interface])

self.cli_set(base_path + ['sampling-rate', sampling_rate])
for server, server_config in sflow_server.items():
self.cli_set(base_path + ['server', server])
if 'port' in server_config:
self.cli_set(base_path + ['server', server, 'port', server_config['port']])

# commit changes
self.cli_commit()

# verify configuration
hsflowd = read_file(hsflowd_conf)

self.assertIn(f'sampling={sampling_rate}', hsflowd)
self.assertIn(f'polling={default_polling}', hsflowd)

for server, server_config in sflow_server.items():
if 'port' in server_config:
self.assertIn(f'collector {{ ip = {server} udpport = {server_config["port"]} }}', hsflowd)
else:
self.assertIn(f'collector {{ ip = {server} udpport = {default_port} }}', hsflowd)

def test_vrf(self):
interface = 'eth0'
server = '192.0.2.1'
Expand Down
6 changes: 6 additions & 0 deletions smoketest/scripts/system/test_kernel_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,5 +128,11 @@ def test_container_cpu(self):
tmp = re.findall(f'{option}=(y|m)', self._config_data)
self.assertTrue(tmp)

def test_psample_enabled(self):
# Psample must be enabled in the OS Kernel to enable egress flow for hsflowd
for option in ['CONFIG_PSAMPLE']:
tmp = re.findall(f'{option}=y', self._config_data)
self.assertTrue(tmp)

if __name__ == '__main__':
unittest.main(verbosity=2)
Loading

0 comments on commit 973b712

Please sign in to comment.