Compare commits

..

13 Commits

39 changed files with 200 additions and 48 deletions

View File

@ -1,4 +1,4 @@
VERSION=0.0.6 VERSION=0.0.8
VPPCFG:=vppcfg VPPCFG:=vppcfg
PYTHON?=python3 PYTHON?=python3
PIP?=pip PIP?=pip

12
debian/changelog vendored
View File

@ -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 vppcfg (0.0.6) unstable; urgency=low
Feature release: Feature release:

6
debian/control vendored
View File

@ -2,11 +2,11 @@ Source: vppcfg
Section: python Section: python
Priority: extra Priority: extra
Maintainer: Ray Kinsella <mdr@ashroe.eu> 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 Standards-Version: 3.9.5
Package: vppcfg Package: vppcfg
Architecture: any Architecture: any
Pre-Depends: dpkg (>= 1.16.1), python3 (>=3.8), ${misc:Pre-Depends} Pre-Depends: ${misc:Pre-Depends}
Depends: python3-netaddr, python3-ipaddr, ${misc:Depends} Depends: ${misc:Depends}, ${python3:Depends}, python3-importlib-metadata, python3-yamale, python3-vpp-api
Description: A configuration tool for FD.io VPP Description: A configuration tool for FD.io VPP

View File

@ -522,7 +522,7 @@ be changed.
The following configuration elements are provided for the plugin: 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 bitrate divided by 1000, so for GigabitEthernet choose 1000, for TenGigabitEthernet choose
10000 (the default). 10000 (the default).
* **polling-interval**: Determines the period of interface byte and packet counter reads. This * **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: sflow:
sample-rate: 10000 sampling-rate: 10000
polling-interval: 20 polling-interval: 20
header-bytes: 128 header-bytes: 128
``` ```

View File

@ -4,7 +4,7 @@ from setuptools import setup
setup( setup(
name="vppcfg", name="vppcfg",
version="0.0.6", version="0.0.8",
install_requires=[ install_requires=[
"requests", "requests",
'importlib-metadata; python_version >= "3.8"', 'importlib-metadata; python_version >= "3.8"',

View File

@ -13,4 +13,4 @@
# limitations under the License. # limitations under the License.
# #
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" __init__.py added to suppress pylint error """ """__init__.py added to suppress pylint error"""

View File

@ -13,7 +13,7 @@
# limitations under the License. # limitations under the License.
# #
# -*- coding: utf-8 -*- # -*- 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 ( from __future__ import (
absolute_import, absolute_import,
division, division,
@ -40,6 +40,7 @@ from .vxlan_tunnel import validate_vxlan_tunnels
from .tap import validate_taps from .tap import validate_taps
from .prefixlist import validate_prefixlists from .prefixlist import validate_prefixlists
from .acl import validate_acls from .acl import validate_acls
from .sflow import validate_sflow
class IPInterfaceWithPrefixLength(validators.Validator): class IPInterfaceWithPrefixLength(validators.Validator):
@ -94,6 +95,7 @@ class Validator:
validate_taps, validate_taps,
validate_prefixlists, validate_prefixlists,
validate_acls, validate_acls,
validate_sflow,
] ]
def validate(self, yaml): def validate(self, yaml):

View File

@ -11,7 +11,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
""" A vppcfg configuration module that validates acls """ """A vppcfg configuration module that validates acls"""
import logging import logging
import socket import socket
import ipaddress import ipaddress

View File

@ -11,7 +11,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
""" A vppcfg configuration module that handles addresses """ """A vppcfg configuration module that handles addresses"""
import ipaddress import ipaddress

View File

@ -11,7 +11,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
""" A vppcfg configuration module that handles bondethernets """ """A vppcfg configuration module that handles bondethernets"""
import logging import logging
from . import interface from . import interface
from . import mac from . import mac

View File

@ -11,7 +11,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
""" A vppcfg configuration module that handles bridgedomains """ """A vppcfg configuration module that handles bridgedomains"""
import logging import logging
from . import interface from . import interface
from . import loopback from . import loopback

View File

@ -11,7 +11,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
""" A vppcfg configuration module that validates interfaces """ """A vppcfg configuration module that validates interfaces"""
import logging import logging
from . import bondethernet from . import bondethernet
from . import bridgedomain from . import bridgedomain

View File

@ -11,7 +11,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # 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): def get_lcps(yaml, interfaces=True, loopbacks=True, bridgedomains=True):

View File

@ -11,7 +11,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
""" A vppcfg configuration module that validates loopbacks """ """A vppcfg configuration module that validates loopbacks"""
import logging import logging
from . import lcp from . import lcp
from . import address from . import address

View File

@ -11,7 +11,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
""" A vppcfg configuration module that validates MAC addresses """ """A vppcfg configuration module that validates MAC addresses"""
import netaddr import netaddr

View File

@ -11,7 +11,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
""" A vppcfg configuration module that validates prefixlists """ """A vppcfg configuration module that validates prefixlists"""
import logging import logging
import ipaddress import ipaddress

30
vppcfg/config/sflow.py Normal file
View 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

View File

@ -11,7 +11,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
""" A vppcfg configuration module that validates taps """ """A vppcfg configuration module that validates taps"""
import logging import logging
from . import mac from . import mac

View File

@ -12,7 +12,7 @@
# limitations under the License. # limitations under the License.
# #
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" Unit tests for taps """ """Unit tests for taps"""
import unittest import unittest
import yaml import yaml
from . import acl 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"]: 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) l = acl.get_network_list(self.cfg, s)
self.assertIsInstance(l, list) self.assertIsInstance(l, list)
self.assertEquals(1, len(l)) self.assertEqual(1, len(l))
n = l[0] n = l[0]
l = acl.get_network_list(self.cfg, "trusted") l = acl.get_network_list(self.cfg, "trusted")
self.assertIsInstance(l, list) 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) l = acl.get_network_list(self.cfg, "trusted", want_ipv6=False)
self.assertIsInstance(l, list) 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) l = acl.get_network_list(self.cfg, "trusted", want_ipv4=False)
self.assertIsInstance(l, list) 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) l = acl.get_network_list(self.cfg, "trusted", want_ipv4=False, want_ipv6=False)
self.assertIsInstance(l, list) self.assertIsInstance(l, list)
self.assertEquals(0, len(l)) self.assertEqual(0, len(l))
l = acl.get_network_list(self.cfg, "pl-notexist") l = acl.get_network_list(self.cfg, "pl-notexist")
self.assertIsInstance(l, list) self.assertIsInstance(l, list)
self.assertEquals(0, len(l)) self.assertEqual(0, len(l))
def test_network_list_has_family(self): def test_network_list_has_family(self):
l = acl.get_network_list(self.cfg, "trusted") l = acl.get_network_list(self.cfg, "trusted")

View File

@ -12,7 +12,7 @@
# limitations under the License. # limitations under the License.
# #
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" Unit tests for addresses """ """Unit tests for addresses"""
import unittest import unittest
import yaml import yaml
from . import address from . import address

View File

@ -12,7 +12,7 @@
# limitations under the License. # limitations under the License.
# #
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" Unit tests for bondethernet """ """Unit tests for bondethernet"""
import unittest import unittest
import yaml import yaml
from . import bondethernet from . import bondethernet

View File

@ -12,7 +12,7 @@
# limitations under the License. # limitations under the License.
# #
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" Unit tests for bridgedomains """ """Unit tests for bridgedomains"""
import unittest import unittest
import yaml import yaml
from . import bridgedomain from . import bridgedomain

View File

@ -12,7 +12,7 @@
# limitations under the License. # limitations under the License.
# #
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" Unit tests for interfaces """ """Unit tests for interfaces"""
import unittest import unittest
import yaml import yaml
from . import interface from . import interface

View File

@ -12,7 +12,7 @@
# limitations under the License. # limitations under the License.
# #
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" Unit tests for LCPs """ """Unit tests for LCPs"""
import unittest import unittest
import yaml import yaml
from . import lcp from . import lcp

View File

@ -12,7 +12,7 @@
# limitations under the License. # limitations under the License.
# #
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" Unit tests for loopbacks """ """Unit tests for loopbacks"""
import unittest import unittest
import yaml import yaml
from . import loopback from . import loopback

View File

@ -12,7 +12,7 @@
# limitations under the License. # limitations under the License.
# #
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" Unit tests for MAC addresses """ """Unit tests for MAC addresses"""
import unittest import unittest
from . import mac from . import mac

View File

@ -12,7 +12,7 @@
# limitations under the License. # limitations under the License.
# #
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" Unit tests for taps """ """Unit tests for taps"""
import unittest import unittest
import yaml import yaml
from . import prefixlist from . import prefixlist
@ -79,22 +79,22 @@ class TestACLMethods(unittest.TestCase):
def test_get_network_list(self): def test_get_network_list(self):
l = prefixlist.get_network_list(self.cfg, "trusted") l = prefixlist.get_network_list(self.cfg, "trusted")
self.assertIsInstance(l, list) 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) l = prefixlist.get_network_list(self.cfg, "trusted", want_ipv6=False)
self.assertIsInstance(l, list) 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) l = prefixlist.get_network_list(self.cfg, "trusted", want_ipv4=False)
self.assertIsInstance(l, list) self.assertIsInstance(l, list)
self.assertEquals(3, len(l)) self.assertEqual(3, len(l))
l = prefixlist.get_network_list( l = prefixlist.get_network_list(
self.cfg, "trusted", want_ipv4=False, want_ipv6=False self.cfg, "trusted", want_ipv4=False, want_ipv6=False
) )
self.assertIsInstance(l, list) self.assertIsInstance(l, list)
self.assertEquals(0, len(l)) self.assertEqual(0, len(l))
l = prefixlist.get_network_list(self.cfg, "pl-notexist") l = prefixlist.get_network_list(self.cfg, "pl-notexist")
self.assertIsInstance(l, list) self.assertIsInstance(l, list)
self.assertEquals(0, len(l)) self.assertEqual(0, len(l))

View File

@ -12,7 +12,7 @@
# limitations under the License. # limitations under the License.
# #
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" Unit tests for taps """ """Unit tests for taps"""
import unittest import unittest
import yaml import yaml
from . import tap from . import tap

View File

@ -12,7 +12,7 @@
# limitations under the License. # limitations under the License.
# #
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" Unit tests for vxlan_tunnels """ """Unit tests for vxlan_tunnels"""
import unittest import unittest
import yaml import yaml
from . import vxlan_tunnel from . import vxlan_tunnel

View File

@ -1,4 +1,4 @@
""" module to help locate unittest resources """ """module to help locate unittest resources"""
#!/usr/bin/env python #!/usr/bin/env python
# #

View File

@ -11,7 +11,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
""" A vppcfg configuration module that validates vxlan_tunnels """ """A vppcfg configuration module that validates vxlan_tunnels"""
import logging import logging
import ipaddress import ipaddress

View File

@ -10,10 +10,12 @@ interfaces:
device-type: dpdk device-type: dpdk
mtu: 9000 mtu: 9000
description: "LAG #1" description: "LAG #1"
sflow: true
GigabitEthernet3/0/1: GigabitEthernet3/0/1:
device-type: dpdk device-type: dpdk
mtu: 9000 mtu: 9000
description: "LAG #2" description: "LAG #2"
sflow: false
HundredGigabitEthernet12/0/0: HundredGigabitEthernet12/0/0:
device-type: dpdk device-type: dpdk
@ -163,3 +165,8 @@ acls:
icmp-code: any icmp-code: any
- description: "Deny any IPv4 or IPv6" - description: "Deny any IPv4 or IPv6"
action: deny action: deny
sflow:
header-bytes: 128
polling-interval: 30
sampling-rate: 1000

View File

@ -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) 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) 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) acls: map(include('acl'),key=str(matches='[a-z][a-z0-9\-]+',min=1,max=56),required=False)
sflow: include('sflow',required=False)
--- ---
vxlan: vxlan:
description: str(exclude='\'"',len=64,required=False) description: str(exclude='\'"',len=64,required=False)
@ -56,7 +57,8 @@ interface:
l2xc: str(required=False) l2xc: str(required=False)
state: enum('up', 'down', required=False) state: enum('up', 'down', required=False)
mpls: bool(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: sub-interface:
description: str(exclude='\'"',len=64,required=False) description: str(exclude='\'"',len=64,required=False)
@ -113,3 +115,8 @@ acl-term:
acl: acl:
description: str(exclude='\'"',len=64,required=False) description: str(exclude='\'"',len=64,required=False)
terms: list(include('acl-term'), min=1, max=100, required=True) 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)

View File

@ -13,7 +13,7 @@
# limitations under the License. # limitations under the License.
# #
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" This is a unit test suite for vppcfg """ """This is a unit test suite for vppcfg"""
# pylint: disable=duplicate-code # pylint: disable=duplicate-code
import os import os
import sys import sys

View File

@ -13,4 +13,4 @@
# limitations under the License. # limitations under the License.
# #
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" __init__.py added to suppress pylint error """ """__init__.py added to suppress pylint error"""

View File

@ -67,6 +67,7 @@ class Dumper(VPPApi):
"taps": {}, "taps": {},
"prefixlists": {}, "prefixlists": {},
"acls": {}, "acls": {},
"sflow": {},
} }
for idx, bond_iface in self.cache["bondethernets"].items(): for idx, bond_iface in self.cache["bondethernets"].items():
bond = {"description": ""} bond = {"description": ""}
@ -122,6 +123,7 @@ class Dumper(VPPApi):
"bond", "bond",
"VXLAN", "VXLAN",
"dpdk", "dpdk",
"af-packet",
"virtio", "virtio",
"pg", "pg",
]: ]:
@ -141,6 +143,8 @@ class Dumper(VPPApi):
i["addresses"] = self.cache["interface_addresses"][ i["addresses"] = self.cache["interface_addresses"][
iface.sw_if_index 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"]: if iface.sw_if_index in self.cache["l2xcs"]:
l2xc = self.cache["l2xcs"][iface.sw_if_index] l2xc = self.cache["l2xcs"][iface.sw_if_index]
i["l2xc"] = self.cache["interfaces"][ i["l2xc"] = self.cache["interfaces"][
@ -152,7 +156,7 @@ class Dumper(VPPApi):
i["state"] = "down" i["state"] = "down"
if ( if (
iface.interface_dev_type == "dpdk" iface.interface_dev_type in ["dpdk", "af-packet"]
and iface.sub_number_of_tags == 0 and iface.sub_number_of_tags == 0
): ):
i["mac"] = str(iface.l2_address) i["mac"] = str(iface.l2_address)
@ -190,6 +194,10 @@ class Dumper(VPPApi):
config["interfaces"][sup_iface.interface_name]["sub-interfaces"][ config["interfaces"][sup_iface.interface_name]["sub-interfaces"][
iface.sub_id iface.sub_id
] = i ] = 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(): for idx, iface in self.cache["vxlan_tunnels"].items():
vpp_iface = self.cache["interfaces"][iface.sw_if_index] vpp_iface = self.cache["interfaces"][iface.sw_if_index]
@ -353,4 +361,9 @@ class Dumper(VPPApi):
config["acls"][aclname] = config_acl 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 return config

View File

@ -967,6 +967,9 @@ class Reconciler:
if not self.__sync_mpls_state(): if not self.__sync_mpls_state():
self.logger.warning("Could not sync interface MPLS state in VPP") self.logger.warning("Could not sync interface MPLS state in VPP")
ret = False 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(): if not self.__sync_admin_state():
self.logger.warning("Could not sync interface adminstate in VPP") self.logger.warning("Could not sync interface adminstate in VPP")
ret = False ret = False
@ -1311,6 +1314,55 @@ class Reconciler:
ret = False ret = False
return ret 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): def __sync_mpls_state(self):
"""Synchronize the VPP Dataplane configuration for interface and loopback MPLS state""" """Synchronize the VPP Dataplane configuration for interface and loopback MPLS state"""
for ifname in loopback.get_loopbacks(self.cfg) + interface.get_interfaces( for ifname in loopback.get_loopbacks(self.cfg) + interface.get_interfaces(

View File

@ -130,6 +130,8 @@ class VPPApi:
"taps": {}, "taps": {},
"acls": {}, "acls": {},
"acl_tags": {}, "acl_tags": {},
"interface_sflow": {},
"sflow": {},
} }
return True return True
@ -415,6 +417,33 @@ class VPPApi:
for tap in api_response: for tap in api_response:
self.cache["taps"][tap.sw_if_index] = tap 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 self.cache_read = True
return self.cache_read return self.cache_read

View File

@ -14,7 +14,7 @@
# #
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""vppcfg is a utility to configure a running VPP Dataplane using YAML """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 # pylint: disable=duplicate-code
import os import os
import sys import sys