Files
vppcfg/vppcfg/config/prefixlist.py
Pim van Pelt efef03ea42 address pylint
2023-01-16 14:41:07 +00:00

127 lines
3.8 KiB
Python

#
# 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 prefixlists """
import logging
import ipaddress
def get_prefixlists(yaml):
"""Return a list of all prefixlists."""
ret = []
if "prefixlists" in yaml:
for plname, _pl in yaml["prefixlists"].items():
ret.append(plname)
return ret
def get_by_name(yaml, plname):
"""Return the prefixlist by name, if it exists. Return None otherwise."""
try:
if plname in yaml["prefixlists"]:
return plname, yaml["prefixlists"][plname]
except KeyError:
pass
return None, None
def get_network_list(yaml, plname, want_ipv4=True, want_ipv6=True):
"""Returns a list of 0 or more ip_network elements, that represent the members
in a prefixlist of given name. Return the empty list if the prefixlist doesn't
exist. Optionally, want_ipv4 or want_ipv6 can be set to False to filter the list."""
ret = []
plname, plist = get_by_name(yaml, plname)
if not plist:
return ret
for member in plist["members"]:
ipn = ipaddress.ip_network(member, strict=False)
if ipn.version == 4 and want_ipv4:
ret.append(ipn)
if ipn.version == 6 and want_ipv6:
ret.append(ipn)
return ret
def count(yaml, plname):
"""Return the number of IPv4 and IPv6 entries in the prefixlist.
Returns 0, 0 if it doesn't exist"""
ipv4, ipv6 = 0, 0
plname, plist = get_by_name(yaml, plname)
if not plist:
return 0, 0
for member in plist["members"]:
ipn = ipaddress.ip_network(member, strict=False)
if ipn.version == 4:
ipv4 += 1
elif ipn.version == 6:
ipv6 += 1
return ipv4, ipv6
def count_ipv4(yaml, plname):
"""Return the number of IPv4 entries in the prefixlist."""
ipv4, _ = count(yaml, plname)
return ipv4
def count_ipv6(yaml, plname):
"""Return the number of IPv6 entries in the prefixlist."""
_, ipv6 = count(yaml, plname)
return ipv6
def has_ipv4(yaml, plname):
"""Return True if the prefixlist has at least one IPv4 entry."""
ipv4, _ = count(yaml, plname)
return ipv4 > 0
def has_ipv6(yaml, plname):
"""Return True if the prefixlist has at least one IPv6 entry."""
_, ipv6 = count(yaml, plname)
return ipv6 > 0
def is_empty(yaml, plname):
"""Return True if the prefixlist has no entries."""
ipv4, ipv6 = count(yaml, plname)
return ipv4 + ipv6 == 0
def validate_prefixlists(yaml):
"""Validate the semantics of all YAML 'prefixlists' entries"""
result = True
msgs = []
logger = logging.getLogger("vppcfg.config")
logger.addHandler(logging.NullHandler())
if not "prefixlists" in yaml:
return result, msgs
for plname, plist in yaml["prefixlists"].items():
logger.debug(f"prefixlist {plname}: {plist}")
if plname in ["any"]:
## Note: ACL 'source' and 'destination', when they are empty, will resolve
## to 'any', and can thus never refer to a prefixlist called 'any'.
msgs.append(f"prefixlist {plname} is a reserved name")
result = False
members = 0
for pl_member in plist["members"]:
members += 1
logger.debug(f"prefixlist {plname} member {members} is {pl_member}")
return result, msgs