diff --git a/vppcfg/config/__init__.py b/vppcfg/config/__init__.py index e62dd98..0bd0cbc 100644 --- a/vppcfg/config/__init__.py +++ b/vppcfg/config/__init__.py @@ -38,6 +38,7 @@ from .interface import validate_interfaces from .bridgedomain import validate_bridgedomains from .vxlan_tunnel import validate_vxlan_tunnels from .tap import validate_taps +from .acl import validate_acls class IPInterfaceWithPrefixLength(validators.Validator): @@ -89,6 +90,7 @@ class Validator: validate_bridgedomains, validate_vxlan_tunnels, validate_taps, + validate_acls, ] def validate(self, yaml): diff --git a/vppcfg/config/acl.py b/vppcfg/config/acl.py new file mode 100644 index 0000000..c98f879 --- /dev/null +++ b/vppcfg/config/acl.py @@ -0,0 +1,60 @@ +# +# Copyright (c) 2023 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 acls """ +import logging + + +def get_aclx(yaml): + """Return a list of all acls.""" + ret = [] + if "acls" in yaml: + for aclname, _acl in yaml["acls"].items(): + ret.append(aclname) + return ret + + +def get_by_name(yaml, aclname): + """Return the acl by name, if it exists. Return None otherwise.""" + try: + if aclname in yaml["acls"]: + return aclname, yaml["acls"][aclname] + except KeyError: + pass + return None, None + + +def validate_acls(yaml): + """Validate the semantics of all YAML 'acls' entries""" + result = True + msgs = [] + logger = logging.getLogger("vppcfg.config") + logger.addHandler(logging.NullHandler()) + + if not "acls" in yaml: + return result, msgs + + for aclname, acl in yaml["acls"].items(): + logger.debug(f"acl {acl}") + terms = 0 + for acl_term in acl["terms"]: + terms += 1 + if "family" in acl_term and "any" in acl_term["family"]: + if "source" in acl_term: + msgs.append(f"acl term {terms} family any cannot have source") + result = False + if "destination" in acl_term: + msgs.append(f"acl term {terms} family any cannot have destination") + result = False + + return result, msgs diff --git a/vppcfg/unittest/yaml/error-acl1.yaml b/vppcfg/unittest/yaml/error-acl1.yaml new file mode 100644 index 0000000..1812395 --- /dev/null +++ b/vppcfg/unittest/yaml/error-acl1.yaml @@ -0,0 +1,22 @@ +test: + description: "Family any precludes source/destination" + errors: + expected: + - "acl term .* family any cannot have (source|destination)" + count: 4 +--- +acls: + acl01: + terms: + - family: any + source: 0.0.0.0/0 + action: permit + - family: any + source: ::/0 + action: permit + - family: any + destination: 0.0.0.0/0 + action: permit + - family: any + destination: ::/0 + action: permit