Compare commits
	
		
			13 Commits
		
	
	
		
			c859738b0f
			...
			4e139d02f3
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 4e139d02f3 | ||
|  | 641d0f0190 | ||
|  | 6879fa85dd | ||
|  | ac13ffbdb1 | ||
|  | 9a7003c46f | ||
|  | ab5f1e43c0 | ||
|  | 8f7c65d8ca | ||
|  | 4ba8c59fd8 | ||
|  | 80058fceed | ||
|  | 78a6f413aa | ||
|  | 19b0354e85 | ||
|  | 55700429de | ||
|  | e7c9a93702 | 
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| VERSION=0.0.6 | ||||
| VERSION=0.0.8 | ||||
| VPPCFG:=vppcfg | ||||
| PYTHON?=python3 | ||||
| PIP?=pip | ||||
|   | ||||
							
								
								
									
										12
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							| @@ -1,3 +1,15 @@ | ||||
| vppcfg (0.0.8) unstable; urgency=low | ||||
|  | ||||
|   Feature release: | ||||
|     * Support af-packet interfaces | ||||
|  | ||||
|  -- Pim van Pelt <pim@ipng.nl>  Sat, 03 May 2025 14:45:37 +0000 | ||||
| vppcfg (0.0.7) unstable; urgency=low | ||||
|  | ||||
|   Feature release: | ||||
|     * Support VPP sFlow plugin | ||||
|  | ||||
|  -- Pim van Pelt <pim@ipng.nl>  Mon, 28 Oct 2024 16:56:47 +0000 | ||||
| vppcfg (0.0.6) unstable; urgency=low | ||||
|  | ||||
|   Feature release: | ||||
|   | ||||
							
								
								
									
										6
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							| @@ -2,11 +2,11 @@ Source: vppcfg | ||||
| Section: python | ||||
| Priority: extra | ||||
| Maintainer: Ray Kinsella <mdr@ashroe.eu> | ||||
| Build-Depends: debhelper (>= 9), python3-all, dh-python | ||||
| Build-Depends: debhelper (>= 9), python3-all, python3-setuptools, dh-python | ||||
| Standards-Version: 3.9.5 | ||||
|  | ||||
| Package: vppcfg | ||||
| Architecture: any | ||||
| Pre-Depends: dpkg (>= 1.16.1), python3 (>=3.8), ${misc:Pre-Depends} | ||||
| Depends: python3-netaddr, python3-ipaddr, ${misc:Depends} | ||||
| Pre-Depends: ${misc:Pre-Depends} | ||||
| Depends: ${misc:Depends}, ${python3:Depends}, python3-importlib-metadata, python3-yamale, python3-vpp-api | ||||
| Description: A configuration tool for FD.io VPP | ||||
|   | ||||
| @@ -522,7 +522,7 @@ be changed. | ||||
|  | ||||
| The following configuration elements are provided for the plugin: | ||||
|  | ||||
| *   **sample-rate**: Capture 1-in-N packets. Defaults to 10000. A good value is the interface | ||||
| *   **sampling-rate**: Capture 1-in-N packets. Defaults to 10000. A good value is the interface | ||||
|     bitrate divided by 1000, so for GigabitEthernet choose 1000, for TenGigabitEthernet choose | ||||
|     10000 (the default). | ||||
| *   **polling-interval**: Determines the period of interface byte and packet counter reads. This | ||||
| @@ -532,7 +532,7 @@ The following configuration elements are provided for the plugin: | ||||
|  | ||||
| ``` | ||||
| sflow: | ||||
|   sample-rate: 10000 | ||||
|   sampling-rate: 10000 | ||||
|   polling-interval: 20 | ||||
|   header-bytes: 128 | ||||
| ``` | ||||
|   | ||||
							
								
								
									
										2
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								setup.py
									
									
									
									
									
								
							| @@ -4,7 +4,7 @@ from setuptools import setup | ||||
|  | ||||
| setup( | ||||
|     name="vppcfg", | ||||
|     version="0.0.6", | ||||
|     version="0.0.8", | ||||
|     install_requires=[ | ||||
|         "requests", | ||||
|         'importlib-metadata; python_version >= "3.8"', | ||||
|   | ||||
| @@ -13,4 +13,4 @@ | ||||
| # limitations under the License. | ||||
| # | ||||
| # -*- coding: utf-8 -*- | ||||
| """ __init__.py added to suppress pylint error """ | ||||
| """__init__.py added to suppress pylint error""" | ||||
|   | ||||
| @@ -13,7 +13,7 @@ | ||||
| # limitations under the License. | ||||
| # | ||||
| # -*- coding: utf-8 -*- | ||||
| """ A vppcfg configuration module that exposes its semantic/syntax validators """ | ||||
| """A vppcfg configuration module that exposes its semantic/syntax validators""" | ||||
| from __future__ import ( | ||||
|     absolute_import, | ||||
|     division, | ||||
| @@ -40,6 +40,7 @@ from .vxlan_tunnel import validate_vxlan_tunnels | ||||
| from .tap import validate_taps | ||||
| from .prefixlist import validate_prefixlists | ||||
| from .acl import validate_acls | ||||
| from .sflow import validate_sflow | ||||
|  | ||||
|  | ||||
| class IPInterfaceWithPrefixLength(validators.Validator): | ||||
| @@ -94,6 +95,7 @@ class Validator: | ||||
|             validate_taps, | ||||
|             validate_prefixlists, | ||||
|             validate_acls, | ||||
|             validate_sflow, | ||||
|         ] | ||||
|  | ||||
|     def validate(self, yaml): | ||||
|   | ||||
| @@ -11,7 +11,7 @@ | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
| # | ||||
| """ A vppcfg configuration module that validates acls """ | ||||
| """A vppcfg configuration module that validates acls""" | ||||
| import logging | ||||
| import socket | ||||
| import ipaddress | ||||
|   | ||||
| @@ -11,7 +11,7 @@ | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
| # | ||||
| """ A vppcfg configuration module that handles addresses """ | ||||
| """A vppcfg configuration module that handles addresses""" | ||||
| import ipaddress | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -11,7 +11,7 @@ | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
| # | ||||
| """ A vppcfg configuration module that handles bondethernets """ | ||||
| """A vppcfg configuration module that handles bondethernets""" | ||||
| import logging | ||||
| from . import interface | ||||
| from . import mac | ||||
|   | ||||
| @@ -11,7 +11,7 @@ | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
| # | ||||
| """ A vppcfg configuration module that handles bridgedomains """ | ||||
| """A vppcfg configuration module that handles bridgedomains""" | ||||
| import logging | ||||
| from . import interface | ||||
| from . import loopback | ||||
|   | ||||
| @@ -11,7 +11,7 @@ | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
| # | ||||
| """ A vppcfg configuration module that validates interfaces """ | ||||
| """A vppcfg configuration module that validates interfaces""" | ||||
| import logging | ||||
| from . import bondethernet | ||||
| from . import bridgedomain | ||||
|   | ||||
| @@ -11,7 +11,7 @@ | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
| # | ||||
| """ A vppcfg configuration module that validates Linux Control Plane (lcp) elements """ | ||||
| """A vppcfg configuration module that validates Linux Control Plane (lcp) elements""" | ||||
|  | ||||
|  | ||||
| def get_lcps(yaml, interfaces=True, loopbacks=True, bridgedomains=True): | ||||
|   | ||||
| @@ -11,7 +11,7 @@ | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
| # | ||||
| """ A vppcfg configuration module that validates loopbacks """ | ||||
| """A vppcfg configuration module that validates loopbacks""" | ||||
| import logging | ||||
| from . import lcp | ||||
| from . import address | ||||
|   | ||||
| @@ -11,7 +11,7 @@ | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
| # | ||||
| """ A vppcfg configuration module that validates MAC addresses """ | ||||
| """A vppcfg configuration module that validates MAC addresses""" | ||||
| import netaddr | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -11,7 +11,7 @@ | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
| # | ||||
| """ A vppcfg configuration module that validates prefixlists """ | ||||
| """A vppcfg configuration module that validates prefixlists""" | ||||
| import logging | ||||
| import ipaddress | ||||
|  | ||||
|   | ||||
							
								
								
									
										30
									
								
								vppcfg/config/sflow.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								vppcfg/config/sflow.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| # | ||||
| # Copyright (c) 2024 Pim van Pelt | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | ||||
| # You may obtain a copy of the License at: | ||||
| #     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
| # | ||||
| """A vppcfg configuration module that validates sflow config""" | ||||
| import logging | ||||
|  | ||||
|  | ||||
| def validate_sflow(yaml): | ||||
|     """Validate the semantics of all YAML 'sflow' config entries""" | ||||
|     result = True | ||||
|     msgs = [] | ||||
|     logger = logging.getLogger("vppcfg.config") | ||||
|     logger.addHandler(logging.NullHandler()) | ||||
|  | ||||
|     if not "sflow" in yaml: | ||||
|         return result, msgs | ||||
|  | ||||
|     ## NOTE(pim): Nothing to validate. sflow config values are all | ||||
|     ##            integers and enforced by yamale. | ||||
|     return result, msgs | ||||
| @@ -11,7 +11,7 @@ | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
| # | ||||
| """ A vppcfg configuration module that validates taps """ | ||||
| """A vppcfg configuration module that validates taps""" | ||||
| import logging | ||||
| from . import mac | ||||
|  | ||||
|   | ||||
| @@ -12,7 +12,7 @@ | ||||
| # limitations under the License. | ||||
| # | ||||
| # -*- coding: utf-8 -*- | ||||
| """ Unit tests for taps """ | ||||
| """Unit tests for taps""" | ||||
| import unittest | ||||
| import yaml | ||||
| from . import acl | ||||
| @@ -130,28 +130,28 @@ class TestACLMethods(unittest.TestCase): | ||||
|         for s in ["192.0.2.1", "192.0.2.1/24", "2001:db8::1", "2001:db8::1/64"]: | ||||
|             l = acl.get_network_list(self.cfg, s) | ||||
|             self.assertIsInstance(l, list) | ||||
|             self.assertEquals(1, len(l)) | ||||
|             self.assertEqual(1, len(l)) | ||||
|             n = l[0] | ||||
|  | ||||
|         l = acl.get_network_list(self.cfg, "trusted") | ||||
|         self.assertIsInstance(l, list) | ||||
|         self.assertEquals(5, len(l)) | ||||
|         self.assertEqual(5, len(l)) | ||||
|  | ||||
|         l = acl.get_network_list(self.cfg, "trusted", want_ipv6=False) | ||||
|         self.assertIsInstance(l, list) | ||||
|         self.assertEquals(2, len(l)) | ||||
|         self.assertEqual(2, len(l)) | ||||
|  | ||||
|         l = acl.get_network_list(self.cfg, "trusted", want_ipv4=False) | ||||
|         self.assertIsInstance(l, list) | ||||
|         self.assertEquals(3, len(l)) | ||||
|         self.assertEqual(3, len(l)) | ||||
|  | ||||
|         l = acl.get_network_list(self.cfg, "trusted", want_ipv4=False, want_ipv6=False) | ||||
|         self.assertIsInstance(l, list) | ||||
|         self.assertEquals(0, len(l)) | ||||
|         self.assertEqual(0, len(l)) | ||||
|  | ||||
|         l = acl.get_network_list(self.cfg, "pl-notexist") | ||||
|         self.assertIsInstance(l, list) | ||||
|         self.assertEquals(0, len(l)) | ||||
|         self.assertEqual(0, len(l)) | ||||
|  | ||||
|     def test_network_list_has_family(self): | ||||
|         l = acl.get_network_list(self.cfg, "trusted") | ||||
|   | ||||
| @@ -12,7 +12,7 @@ | ||||
| # limitations under the License. | ||||
| # | ||||
| # -*- coding: utf-8 -*- | ||||
| """ Unit tests for addresses """ | ||||
| """Unit tests for addresses""" | ||||
| import unittest | ||||
| import yaml | ||||
| from . import address | ||||
|   | ||||
| @@ -12,7 +12,7 @@ | ||||
| # limitations under the License. | ||||
| # | ||||
| # -*- coding: utf-8 -*- | ||||
| """ Unit tests for bondethernet """ | ||||
| """Unit tests for bondethernet""" | ||||
| import unittest | ||||
| import yaml | ||||
| from . import bondethernet | ||||
|   | ||||
| @@ -12,7 +12,7 @@ | ||||
| # limitations under the License. | ||||
| # | ||||
| # -*- coding: utf-8 -*- | ||||
| """ Unit tests for bridgedomains """ | ||||
| """Unit tests for bridgedomains""" | ||||
| import unittest | ||||
| import yaml | ||||
| from . import bridgedomain | ||||
|   | ||||
| @@ -12,7 +12,7 @@ | ||||
| # limitations under the License. | ||||
| # | ||||
| # -*- coding: utf-8 -*- | ||||
| """ Unit tests for interfaces """ | ||||
| """Unit tests for interfaces""" | ||||
| import unittest | ||||
| import yaml | ||||
| from . import interface | ||||
|   | ||||
| @@ -12,7 +12,7 @@ | ||||
| # limitations under the License. | ||||
| # | ||||
| # -*- coding: utf-8 -*- | ||||
| """ Unit tests for LCPs """ | ||||
| """Unit tests for LCPs""" | ||||
| import unittest | ||||
| import yaml | ||||
| from . import lcp | ||||
|   | ||||
| @@ -12,7 +12,7 @@ | ||||
| # limitations under the License. | ||||
| # | ||||
| # -*- coding: utf-8 -*- | ||||
| """ Unit tests for loopbacks """ | ||||
| """Unit tests for loopbacks""" | ||||
| import unittest | ||||
| import yaml | ||||
| from . import loopback | ||||
|   | ||||
| @@ -12,7 +12,7 @@ | ||||
| # limitations under the License. | ||||
| # | ||||
| # -*- coding: utf-8 -*- | ||||
| """ Unit tests for MAC addresses """ | ||||
| """Unit tests for MAC addresses""" | ||||
| import unittest | ||||
| from . import mac | ||||
|  | ||||
|   | ||||
| @@ -12,7 +12,7 @@ | ||||
| # limitations under the License. | ||||
| # | ||||
| # -*- coding: utf-8 -*- | ||||
| """ Unit tests for taps """ | ||||
| """Unit tests for taps""" | ||||
| import unittest | ||||
| import yaml | ||||
| from . import prefixlist | ||||
| @@ -79,22 +79,22 @@ class TestACLMethods(unittest.TestCase): | ||||
|     def test_get_network_list(self): | ||||
|         l = prefixlist.get_network_list(self.cfg, "trusted") | ||||
|         self.assertIsInstance(l, list) | ||||
|         self.assertEquals(5, len(l)) | ||||
|         self.assertEqual(5, len(l)) | ||||
|  | ||||
|         l = prefixlist.get_network_list(self.cfg, "trusted", want_ipv6=False) | ||||
|         self.assertIsInstance(l, list) | ||||
|         self.assertEquals(2, len(l)) | ||||
|         self.assertEqual(2, len(l)) | ||||
|  | ||||
|         l = prefixlist.get_network_list(self.cfg, "trusted", want_ipv4=False) | ||||
|         self.assertIsInstance(l, list) | ||||
|         self.assertEquals(3, len(l)) | ||||
|         self.assertEqual(3, len(l)) | ||||
|  | ||||
|         l = prefixlist.get_network_list( | ||||
|             self.cfg, "trusted", want_ipv4=False, want_ipv6=False | ||||
|         ) | ||||
|         self.assertIsInstance(l, list) | ||||
|         self.assertEquals(0, len(l)) | ||||
|         self.assertEqual(0, len(l)) | ||||
|  | ||||
|         l = prefixlist.get_network_list(self.cfg, "pl-notexist") | ||||
|         self.assertIsInstance(l, list) | ||||
|         self.assertEquals(0, len(l)) | ||||
|         self.assertEqual(0, len(l)) | ||||
|   | ||||
| @@ -12,7 +12,7 @@ | ||||
| # limitations under the License. | ||||
| # | ||||
| # -*- coding: utf-8 -*- | ||||
| """ Unit tests for taps """ | ||||
| """Unit tests for taps""" | ||||
| import unittest | ||||
| import yaml | ||||
| from . import tap | ||||
|   | ||||
| @@ -12,7 +12,7 @@ | ||||
| # limitations under the License. | ||||
| # | ||||
| # -*- coding: utf-8 -*- | ||||
| """ Unit tests for vxlan_tunnels """ | ||||
| """Unit tests for vxlan_tunnels""" | ||||
| import unittest | ||||
| import yaml | ||||
| from . import vxlan_tunnel | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| """ module to help locate unittest resources """ | ||||
| """module to help locate unittest resources""" | ||||
|  | ||||
| #!/usr/bin/env python | ||||
| # | ||||
|   | ||||
| @@ -11,7 +11,7 @@ | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
| # | ||||
| """ A vppcfg configuration module that validates vxlan_tunnels """ | ||||
| """A vppcfg configuration module that validates vxlan_tunnels""" | ||||
| import logging | ||||
| import ipaddress | ||||
|  | ||||
|   | ||||
| @@ -10,10 +10,12 @@ interfaces: | ||||
|     device-type: dpdk | ||||
|     mtu: 9000 | ||||
|     description: "LAG #1" | ||||
|     sflow: true | ||||
|   GigabitEthernet3/0/1: | ||||
|     device-type: dpdk | ||||
|     mtu: 9000 | ||||
|     description: "LAG #2" | ||||
|     sflow: false | ||||
|  | ||||
|   HundredGigabitEthernet12/0/0: | ||||
|     device-type: dpdk | ||||
| @@ -163,3 +165,8 @@ acls: | ||||
|          icmp-code: any | ||||
|        - description: "Deny any IPv4 or IPv6" | ||||
|          action: deny | ||||
|  | ||||
| sflow: | ||||
|   header-bytes: 128 | ||||
|   polling-interval: 30 | ||||
|   sampling-rate: 1000 | ||||
|   | ||||
| @@ -6,6 +6,7 @@ vxlan_tunnels: map(include('vxlan'),key=str(matches='vxlan_tunnel[0-9]+'),requir | ||||
| taps: map(include('tap'),key=str(matches='tap[0-9]+'),required=False) | ||||
| prefixlists: map(include('prefixlist'),key=str(matches='[a-z][a-z0-9\-]+',min=1,max=64),required=False) | ||||
| acls: map(include('acl'),key=str(matches='[a-z][a-z0-9\-]+',min=1,max=56),required=False) | ||||
| sflow: include('sflow',required=False) | ||||
| --- | ||||
| vxlan: | ||||
|   description: str(exclude='\'"',len=64,required=False) | ||||
| @@ -56,7 +57,8 @@ interface: | ||||
|   l2xc: str(required=False) | ||||
|   state: enum('up', 'down', required=False) | ||||
|   mpls: bool(required=False) | ||||
|   device-type: enum('dpdk', required=False) | ||||
|   device-type: enum('dpdk', 'af-packet', required=False) | ||||
|   sflow: bool(required=False) | ||||
| --- | ||||
| sub-interface: | ||||
|   description: str(exclude='\'"',len=64,required=False) | ||||
| @@ -113,3 +115,8 @@ acl-term: | ||||
| acl: | ||||
|   description: str(exclude='\'"',len=64,required=False) | ||||
|   terms: list(include('acl-term'), min=1, max=100, required=True) | ||||
| --- | ||||
| sflow: | ||||
|   header-bytes: int(min=1,max=256,required=False) | ||||
|   polling-interval: int(min=5,max=600,required=False) | ||||
|   sampling-rate: int(min=100,max=1000000,required=False) | ||||
|   | ||||
| @@ -13,7 +13,7 @@ | ||||
| # limitations under the License. | ||||
| # | ||||
| # -*- coding: utf-8 -*- | ||||
| """ This is a unit test suite for vppcfg """ | ||||
| """This is a unit test suite for vppcfg""" | ||||
| # pylint: disable=duplicate-code | ||||
| import os | ||||
| import sys | ||||
|   | ||||
| @@ -13,4 +13,4 @@ | ||||
| # limitations under the License. | ||||
| # | ||||
| # -*- coding: utf-8 -*- | ||||
| """ __init__.py added to suppress pylint error """ | ||||
| """__init__.py added to suppress pylint error""" | ||||
|   | ||||
| @@ -67,6 +67,7 @@ class Dumper(VPPApi): | ||||
|             "taps": {}, | ||||
|             "prefixlists": {}, | ||||
|             "acls": {}, | ||||
|             "sflow": {}, | ||||
|         } | ||||
|         for idx, bond_iface in self.cache["bondethernets"].items(): | ||||
|             bond = {"description": ""} | ||||
| @@ -122,6 +123,7 @@ class Dumper(VPPApi): | ||||
|                     "bond", | ||||
|                     "VXLAN", | ||||
|                     "dpdk", | ||||
|                     "af-packet", | ||||
|                     "virtio", | ||||
|                     "pg", | ||||
|                 ]: | ||||
| @@ -141,6 +143,8 @@ class Dumper(VPPApi): | ||||
|                             i["addresses"] = self.cache["interface_addresses"][ | ||||
|                                 iface.sw_if_index | ||||
|                             ] | ||||
|                     if iface.sw_if_index in self.cache["interface_mpls"]: | ||||
|                         i["mpls"] = self.cache["interface_mpls"][iface.sw_if_index] | ||||
|                     if iface.sw_if_index in self.cache["l2xcs"]: | ||||
|                         l2xc = self.cache["l2xcs"][iface.sw_if_index] | ||||
|                         i["l2xc"] = self.cache["interfaces"][ | ||||
| @@ -152,7 +156,7 @@ class Dumper(VPPApi): | ||||
|                         i["state"] = "down" | ||||
|  | ||||
|                     if ( | ||||
|                         iface.interface_dev_type == "dpdk" | ||||
|                         iface.interface_dev_type in ["dpdk", "af-packet"] | ||||
|                         and iface.sub_number_of_tags == 0 | ||||
|                     ): | ||||
|                         i["mac"] = str(iface.l2_address) | ||||
| @@ -190,6 +194,10 @@ class Dumper(VPPApi): | ||||
|                     config["interfaces"][sup_iface.interface_name]["sub-interfaces"][ | ||||
|                         iface.sub_id | ||||
|                     ] = i | ||||
|         if iface.interface_dev_type in ["dpdk", "af-packet"]: | ||||
|             config["interfaces"][iface.interface_name][ | ||||
|                 "device-type" | ||||
|             ] = iface.interface_dev_type | ||||
|  | ||||
|         for idx, iface in self.cache["vxlan_tunnels"].items(): | ||||
|             vpp_iface = self.cache["interfaces"][iface.sw_if_index] | ||||
| @@ -353,4 +361,9 @@ class Dumper(VPPApi): | ||||
|  | ||||
|             config["acls"][aclname] = config_acl | ||||
|  | ||||
|         config["sflow"] = self.cache["sflow"] | ||||
|         for hw_if_index in self.cache["interface_sflow"]: | ||||
|             vpp_iface = self.cache["interfaces"][hw_if_index] | ||||
|             config["interfaces"][vpp_iface.interface_name]["sflow"] = True | ||||
|  | ||||
|         return config | ||||
|   | ||||
| @@ -967,6 +967,9 @@ class Reconciler: | ||||
|         if not self.__sync_mpls_state(): | ||||
|             self.logger.warning("Could not sync interface MPLS state in VPP") | ||||
|             ret = False | ||||
|         if not self.__sync_sflow_state(): | ||||
|             self.logger.warning("Could not sync interface sFlow state in VPP") | ||||
|             ret = False | ||||
|         if not self.__sync_admin_state(): | ||||
|             self.logger.warning("Could not sync interface adminstate in VPP") | ||||
|             ret = False | ||||
| @@ -1311,6 +1314,55 @@ class Reconciler: | ||||
|             ret = False | ||||
|         return ret | ||||
|  | ||||
|     def __sync_sflow_state(self): | ||||
|         """Synchronize the VPP Dataplane configuration and phy sFlow state""" | ||||
|  | ||||
|         if "sflow" in self.cfg and self.vpp.cache["sflow"]: | ||||
|             if "header-bytes" in self.cfg["sflow"]: | ||||
|                 if ( | ||||
|                     self.vpp.cache["sflow"]["header-bytes"] | ||||
|                     != self.cfg["sflow"]["header-bytes"] | ||||
|                 ): | ||||
|                     cli = f"sflow header-bytes {self.cfg['sflow']['header-bytes']}" | ||||
|                     self.cli["sync"].append(cli) | ||||
|             if "polling-interval" in self.cfg["sflow"]: | ||||
|                 if ( | ||||
|                     self.vpp.cache["sflow"]["polling-interval"] | ||||
|                     != self.cfg["sflow"]["polling-interval"] | ||||
|                 ): | ||||
|                     cli = f"sflow polling-interval {self.cfg['sflow']['polling-interval']}" | ||||
|                     self.cli["sync"].append(cli) | ||||
|             if "sampling-rate" in self.cfg["sflow"]: | ||||
|                 if ( | ||||
|                     self.vpp.cache["sflow"]["sampling-rate"] | ||||
|                     != self.cfg["sflow"]["sampling-rate"] | ||||
|                 ): | ||||
|                     cli = f"sflow sampling-rate {self.cfg['sflow']['sampling-rate']}" | ||||
|                     self.cli["sync"].append(cli) | ||||
|  | ||||
|         for ifname in interface.get_interfaces(self.cfg): | ||||
|             vpp_ifname, config_iface = interface.get_by_name(self.cfg, ifname) | ||||
|  | ||||
|             try: | ||||
|                 config_sflow = config_iface["sflow"] | ||||
|             except KeyError: | ||||
|                 config_sflow = False | ||||
|  | ||||
|             vpp_sflow = False | ||||
|             if vpp_ifname in self.vpp.cache["interface_names"]: | ||||
|                 hw_if_index = self.vpp.cache["interface_names"][vpp_ifname] | ||||
|                 try: | ||||
|                     vpp_sflow = self.vpp.cache["interface_sflow"][hw_if_index] | ||||
|                 except KeyError: | ||||
|                     pass | ||||
|             if vpp_sflow != config_sflow: | ||||
|                 if config_sflow: | ||||
|                     cli = f"sflow enable {vpp_ifname}" | ||||
|                 else: | ||||
|                     cli = f"sflow enable-disable {vpp_ifname} disable" | ||||
|                 self.cli["sync"].append(cli) | ||||
|         return True | ||||
|  | ||||
|     def __sync_mpls_state(self): | ||||
|         """Synchronize the VPP Dataplane configuration for interface and loopback MPLS state""" | ||||
|         for ifname in loopback.get_loopbacks(self.cfg) + interface.get_interfaces( | ||||
|   | ||||
| @@ -130,6 +130,8 @@ class VPPApi: | ||||
|             "taps": {}, | ||||
|             "acls": {}, | ||||
|             "acl_tags": {}, | ||||
|             "interface_sflow": {}, | ||||
|             "sflow": {}, | ||||
|         } | ||||
|         return True | ||||
|  | ||||
| @@ -415,6 +417,33 @@ class VPPApi: | ||||
|         for tap in api_response: | ||||
|             self.cache["taps"][tap.sw_if_index] = tap | ||||
|  | ||||
|         try: | ||||
|             self.logger.debug("Retrieving sFlow") | ||||
|  | ||||
|             api_response = self.vpp.api.sflow_sampling_rate_get() | ||||
|             if api_response: | ||||
|                 self.cache["sflow"]["sampling-rate"] = api_response.sampling_N | ||||
|             api_response = self.vpp.api.sflow_polling_interval_get() | ||||
|             if api_response: | ||||
|                 self.cache["sflow"]["polling-interval"] = api_response.polling_S | ||||
|             api_response = self.vpp.api.sflow_header_bytes_get() | ||||
|             if api_response: | ||||
|                 self.cache["sflow"]["header-bytes"] = api_response.header_B | ||||
|  | ||||
|             api_response = self.vpp.api.sflow_interface_dump() | ||||
|             for iface in api_response: | ||||
|                 self.cache["interface_sflow"][iface.hw_if_index] = True | ||||
|         except AttributeError as err: | ||||
|             self.logger.warning(f"sFlow API not found - missing plugin: {err}") | ||||
|  | ||||
|         self.logger.debug("Retrieving interface Unnumbered state") | ||||
|         api_response = self.vpp.api.ip_unnumbered_dump() | ||||
|         for iface in api_response: | ||||
|             self.cache["interface_unnumbered"][iface.sw_if_index] = iface.ip_sw_if_index | ||||
|  | ||||
|         self.logger.debug("Retrieving bondethernets") | ||||
|         api_response = self.vpp.api.sw_bond_interface_dump() | ||||
|  | ||||
|         self.cache_read = True | ||||
|         return self.cache_read | ||||
|  | ||||
|   | ||||
| @@ -14,7 +14,7 @@ | ||||
| # | ||||
| # -*- coding: utf-8 -*- | ||||
| """vppcfg is a utility to configure a running VPP Dataplane using YAML | ||||
| config files. See http://github.com/pimvanpelt/vppcfg/README.md for details. """ | ||||
| config files. See http://github.com/pimvanpelt/vppcfg/README.md for details.""" | ||||
| # pylint: disable=duplicate-code | ||||
| import os | ||||
| import sys | ||||
|   | ||||
		Reference in New Issue
	
	Block a user