Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions data/config-mode-dependencies/vyos-1x.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,5 +80,8 @@
"system_option": {
"ip_ipv6": ["system_ip", "system_ipv6"],
"sysctl": ["system_sysctl"]
},
"system_sflow": {
"vpp_sflow": ["vpp_sflow"]
}
}
2 changes: 1 addition & 1 deletion interface-definitions/include/version/vpp-version.xml.i
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<!-- include start from include/version/vpp-version.xml.i -->
<syntaxVersion component='vpp' version='2'></syntaxVersion>
<syntaxVersion component='vpp' version='3'></syntaxVersion>
<!-- include end -->
39 changes: 35 additions & 4 deletions interface-definitions/vpp.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -952,14 +952,45 @@
<multi/>
</properties>
</leafNode>
<leafNode name="sample-rate">
<leafNode name="header-bytes">
<properties>
<help>sFlow sample rate</help>
<help>sFlow maximum packet-header length</help>
<completionHelp>
<list>64 96 128 160 192 224 256</list>
</completionHelp>
<valueHelp>
<format>64</format>
<description>64 bytes</description>
</valueHelp>
<valueHelp>
<format>96</format>
<description>96 bytes</description>
</valueHelp>
<valueHelp>
<format>128</format>
<description>128 bytes</description>
</valueHelp>
<valueHelp>
<format>160</format>
<description>160 bytes</description>
</valueHelp>
<valueHelp>
<format>192</format>
<description>192 bytes</description>
</valueHelp>
<valueHelp>
<format>224</format>
<description>224 bytes</description>
</valueHelp>
<valueHelp>
<format>u32</format>
<description>sFlow sample rate</description>
<format>256</format>
<description>256 bytes</description>
</valueHelp>
<constraint>
<regex>(64|96|128|160|192|224|256)</regex>
</constraint>
</properties>
<defaultValue>128</defaultValue>
</leafNode>
</children>
</node>
Expand Down
17 changes: 17 additions & 0 deletions op-mode-definitions/vpp_sflow.xml.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0"?>
<interfaceDefinition>
<node name="show">
<children>
<node name="vpp">
<children>
<node name="sflow">
<properties>
<help>Show VPP sFlow information</help>
</properties>
<command>bash -c 'if cli-shell-api existsActive vpp sflow; then sudo vppctl show sflow; else echo "vpp sflow is not configured"; fi'</command>
</node>
</children>
</node>
</children>
</node>
</interfaceDefinition>
3 changes: 3 additions & 0 deletions python/vyos/vpp/sflow/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .sflow import SFlow

__all__ = ['SFlow']
49 changes: 49 additions & 0 deletions python/vyos/vpp/sflow/sflow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#
# Copyright (C) VyOS Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

from vyos.vpp import VPPControl


class SFlow:
def __init__(self):
self.vpp = VPPControl()

def enable_sflow(self, interface):
"""Enable sFlow on interface"""
self.vpp.api.sflow_enable_disable(
enable_disable=True,
sw_if_index=self.vpp.get_sw_if_index(interface),
)

def disable_sflow(self, interface):
"""Disable sFlow on interface"""
self.vpp.api.sflow_enable_disable(
enable_disable=False,
sw_if_index=self.vpp.get_sw_if_index(interface),
)

def set_sampling_rate(self, sample_rate):
"""Set sFlow sampling-rate"""
self.vpp.api.sflow_sampling_rate(sampling_N=sample_rate)

def set_polling_interval(self, interval):
"""Set sFlow polling interval"""
self.vpp.api.sflow_polling_interval(polling_S=interval)

def set_header_bytes(self, header_bytes):
"""Set sFlow maximum header length in bytes"""
self.vpp.api.sflow_header_bytes(header_B=header_bytes)
37 changes: 37 additions & 0 deletions smoketest/scripts/cli/test_vpp.py
Original file line number Diff line number Diff line change
Expand Up @@ -1423,28 +1423,65 @@ def test_16_vpp_nat(self):

def test_17_vpp_sflow(self):
base_sflow = ['system', 'sflow']
sampling_rate = '1500'
polling_interval = '55'
header_bytes = '256'
iface_2 = 'eth0'

self.cli_set(base_path + ['sflow', 'interface', interface])
self.cli_set(base_path + ['sflow', 'header-bytes', header_bytes])
self.cli_set(base_sflow + ['interface', interface])
self.cli_set(base_sflow + ['server', '127.0.0.1'])
self.cli_set(base_sflow + ['sampling-rate', sampling_rate])
self.cli_set(base_sflow + ['polling', polling_interval])
self.cli_set(base_sflow + ['vpp'])
self.cli_commit()

# Check sFlow
_, out = rc_cmd('sudo vppctl show sflow')

expected_entries = (
f'sflow sampling-rate {sampling_rate}',
'sflow sampling-direction ingress',
f'sflow polling-interval {polling_interval}',
f'sflow header-bytes {header_bytes}',
f'sflow enable {interface}',
'interfaces enabled: 1',
)

for expected_entry in expected_entries:
self.assertIn(expected_entry, out)

self.cli_set(base_path + ['settings', 'interface', iface_2, 'driver', driver])
self.cli_set(base_path + ['sflow', 'interface', iface_2])

self.cli_commit()

# Check sFlow
_, out = rc_cmd('sudo vppctl show sflow')

expected_entries = (
f'sflow enable {interface}',
f'sflow enable {iface_2}',
'interfaces enabled: 2',
)

for expected_entry in expected_entries:
self.assertIn(expected_entry, out)

# cannot delete system sFlow configuration if VPP sFlow is configured
# expect raise ConfigError
self.cli_delete(base_sflow)
with self.assertRaises(ConfigSessionError):
self.cli_commit()

self.cli_delete(base_path + ['sflow'])
self.cli_commit()

# Check interfaces are deleted from VPP sFlow
_, out = rc_cmd('sudo vppctl show sflow')
self.assertIn('interfaces enabled: 0', out)

def test_18_resource_limits(self):
max_map_count = '100000'
shmmax = '55555555555555'
Expand Down
44 changes: 35 additions & 9 deletions src/conf_mode/system_sflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@
from sys import exit

from vyos.config import Config
from vyos.configdep import set_dependents, call_dependents
from vyos.configverify import verify_vrf
from vyos.template import render
from vyos.utils.process import call
from vyos.utils.network import is_addr_assigned
from vyos import ConfigError
from vyos import airbag

airbag.enable()

hsflowd_conf_path = '/run/sflow/hsflowd.conf'
Expand All @@ -38,17 +40,37 @@ def get_config(config=None):
else:
conf = Config()
base = ['system', 'sflow']

vpp_sflow = conf.exists(['vpp', 'sflow'])

if not conf.exists(base):
return None
return {
'remove': True,
'vpp_sflow': vpp_sflow,
}

sflow = conf.get_config_dict(base, key_mangling=('-', '_'),
get_first_key=True,
with_recursive_defaults=True)
sflow = conf.get_config_dict(
base, key_mangling=('-', '_'), get_first_key=True, with_recursive_defaults=True
)

sflow.update({'vpp_sflow': vpp_sflow})

if vpp_sflow:
set_dependents('vpp_sflow', conf)

return sflow


def verify(sflow):
if not sflow:
# Check if "vpp" flag could be deleted from configuration
if sflow.get('vpp_sflow'):
if 'vpp' not in sflow or 'remove' in sflow:
raise ConfigError(
'sFlow is still configured in VPP. '
'Please remove sFlow configuration from VPP before proceeding.'
)

if 'remove' in sflow:
return None

# Check if configured sflow agent-address exist in the system
Expand All @@ -62,8 +84,7 @@ def verify(sflow):
# Check if at least one interface is configured
# Skip this check if VPP is enabled
if 'interface' not in sflow and 'vpp' not in sflow:
raise ConfigError(
'sFlow requires at least one interface to be configured!')
raise ConfigError('sFlow requires at least one interface to be configured!')

# Check if at least one server is configured
if 'server' not in sflow:
Expand All @@ -72,17 +93,19 @@ def verify(sflow):
verify_vrf(sflow)
return None


def generate(sflow):
if not sflow:
if 'remove' in sflow:
return None

render(hsflowd_conf_path, 'sflow/hsflowd.conf.j2', sflow)
render(systemd_override, 'sflow/override.conf.j2', sflow)
# Reload systemd manager configuration
call('systemctl daemon-reload')


def apply(sflow):
if not sflow:
if 'remove' in sflow:
# Stop flow-accounting daemon and remove configuration file
call(f'systemctl stop {systemd_service}')
if os.path.exists(hsflowd_conf_path):
Expand All @@ -92,6 +115,9 @@ def apply(sflow):
# Start/reload flow-accounting daemon
call(f'systemctl restart {systemd_service}')

call_dependents()


if __name__ == '__main__':
try:
config = get_config()
Expand Down
Loading
Loading