diff options
| author | Viacheslav Hletenko <v.gletenko@vyos.io> | 2025-11-03 22:45:28 +0000 |
|---|---|---|
| committer | Viacheslav Hletenko <v.gletenko@vyos.io> | 2025-11-14 15:41:04 +0000 |
| commit | 0cc39141dba576609480f6707d16964de4a8a6bc (patch) | |
| tree | 567f815168e1fb05f40a2f225e9272924b982686 /src/op_mode | |
| parent | 23e61833f4ac2a0dce040520c1324bab8c025209 (diff) | |
| download | vyos-1x-0cc39141dba576609480f6707d16964de4a8a6bc.tar.gz vyos-1x-0cc39141dba576609480f6707d16964de4a8a6bc.zip | |
T7556: VPP add IPFIX collector configuration
Add VPP IPFIX configuration commands:
```
set vpp ipfix active-timeout '8'
set vpp ipfix collector 192.0.2.2 port '2055'
set vpp ipfix collector 192.0.2.2 source-address '192.0.2.1'
set vpp ipfix flowprobe-record 'l2'
set vpp ipfix flowprobe-record 'l3'
set vpp ipfix flowprobe-record 'l4'
set vpp ipfix inactive-timeout '32'
set vpp ipfix interface eth0
set vpp ipfix interface eth1 direction 'both'
set vpp ipfix interface eth1 flow-variant 'ipv4'
```
Diffstat (limited to 'src/op_mode')
| -rwxr-xr-x | src/op_mode/vpp.py | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/src/op_mode/vpp.py b/src/op_mode/vpp.py new file mode 100755 index 000000000..fea874909 --- /dev/null +++ b/src/op_mode/vpp.py @@ -0,0 +1,165 @@ +#!/usr/bin/env python3 +# +# Copyright VyOS maintainers and contributors <maintainers@vyos.io> +# +# 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 +# published by the Free Software Foundation. +# +# 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, see <http://www.gnu.org/licenses/>. + +import sys +import typing + +from tabulate import tabulate +from vyos.vpp import VPPControl +from vyos.configquery import ConfigTreeQuery +import vyos.opmode + + +class VPPShow: + def __init__(self): + self.config = ConfigTreeQuery() + self.vpp = VPPControl() + + # ----------------------------- + # IPFIX Interfaces + # ----------------------------- + def _get_ipfix_interfaces_raw(self) -> typing.List[dict]: + interfaces = self.vpp.api.flowprobe_interface_dump() + index_map = { + i.sw_if_index: i.interface_name for i in self.vpp.api.sw_interface_dump() + } + + return [ + { + 'interface': index_map.get(e.sw_if_index, f'if{e.sw_if_index}'), + 'sw_if_index': e.sw_if_index, + 'which': e.which.name.replace('FLOWPROBE_WHICH_', '').lower(), + 'direction': e.direction.name.replace( + 'FLOWPROBE_DIRECTION_', '' + ).lower(), + } + for e in interfaces + ] + + def _show_ipfix_interfaces_formatted(self, data: typing.List[dict]) -> str: + if not data: + return 'No flowprobe interfaces configured.' + table_data = [ + { + 'Interface': d['interface'], + 'VppIfIndex': d['sw_if_index'], + 'Flow-variant': d['which'], + 'Direction': d['direction'], + } + for d in data + ] + return tabulate(table_data, headers='keys', tablefmt='simple') + + def ipfix_interfaces(self, raw: bool): + base = ['vpp', 'ipfix', 'interface'] + if not self.config.exists(base): + raise vyos.opmode.UnconfiguredSubsystem( + 'vpp ipfix interface is not configured' + ) + + data = self._get_ipfix_interfaces_raw() + return data if raw else self._show_ipfix_interfaces_formatted(data) + + # ----------------------------- + # IPFIX Collectors + # ----------------------------- + def _get_ipfix_collectors_raw(self) -> typing.List[dict]: + _, collectors = self.vpp.api.ipfix_all_exporter_get() + return [ + { + 'collector_address': str(c.collector_address), + 'collector_port': c.collector_port, + 'src_address': str(c.src_address), + 'vrf_id': c.vrf_id, + 'path_mtu': c.path_mtu, + 'template_interval': c.template_interval, + 'udp_checksum': bool(c.udp_checksum), + } + for c in collectors + ] + + def _show_ipfix_collectors_formatted(self, data: typing.List[dict]) -> str: + if not data: + return 'No IPFIX collectors configured.' + table_data = [ + { + 'Collector': f"{d['collector_address']}:{d['collector_port']}", + 'Source': d['src_address'], + 'VRF': d['vrf_id'], + 'MTU': d['path_mtu'], + 'Template Intvl': d['template_interval'], + 'UDP Cksum': 'on' if d['udp_checksum'] else 'off', + } + for d in data + ] + return tabulate(table_data, headers='keys', tablefmt='simple') + + def ipfix_collectors(self, raw: bool): + base = ['vpp', 'ipfix', 'collector'] + if not self.config.exists(base): + raise vyos.opmode.UnconfiguredSubsystem( + 'vpp ipfix collector is not configured' + ) + + data = self._get_ipfix_collectors_raw() + return data if raw else self._show_ipfix_collectors_formatted(data) + + # ----------------------------- + # IPFIX table + # ----------------------------- + def _get_ipfix_table_raw(self): + # VPP does not have API call to get this data + data = self.vpp.cli_cmd('show flowprobe table') + return [data.reply] + + def _show_ipfix_table_formatted(self) -> str: + data = self.vpp.cli_cmd('show flowprobe table') + return data.reply + + def ipfix_table(self, raw: bool): + base = ['vpp', 'ipfix', 'collector'] + if not self.config.exists(base): + raise vyos.opmode.UnconfiguredSubsystem( + 'vpp ipfix collector is not configured' + ) + + data = self._get_ipfix_table_raw() + return data if raw else self._show_ipfix_table_formatted() + + +# ----------------------------- +# VyOS IPFIX op-mode entries +# ----------------------------- +def show_ipfix_interfaces(raw: bool): + return VPPShow().ipfix_interfaces(raw) + + +def show_ipfix_collectors(raw: bool): + return VPPShow().ipfix_collectors(raw) + + +def show_ipfix_table(raw: bool): + return VPPShow().ipfix_table(raw) + + +if __name__ == '__main__': + try: + res = vyos.opmode.run(sys.modules[__name__]) + if res: + print(res) + except (ValueError, vyos.opmode.Error) as e: + print(e) + sys.exit(1) |
