Fixed python load paths so that vppcfg will work installed as python library and standalone from the source directory, fixing load pathes for resources such as yaml files along the way. Added a make target for pylint called 'make check-style', fixed a number of minor pylint issues along the way. Signed-off-by: Ray Kinsella <mdr@ashroe.eu>
119 lines
3.9 KiB
Python
119 lines
3.9 KiB
Python
#
|
|
# Copyright (c) 2022 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 taps """
|
|
import logging
|
|
from . import mac
|
|
|
|
|
|
def get_taps(yaml):
|
|
"""Return a list of all taps."""
|
|
ret = []
|
|
if "taps" in yaml:
|
|
for ifname, _iface in yaml["taps"].items():
|
|
ret.append(ifname)
|
|
return ret
|
|
|
|
|
|
def get_by_name(yaml, ifname):
|
|
"""Return the tap by name, if it exists. Return None otherwise."""
|
|
try:
|
|
if ifname in yaml["taps"]:
|
|
return ifname, yaml["taps"][ifname]
|
|
except KeyError:
|
|
pass
|
|
return None, None
|
|
|
|
|
|
def is_tap(yaml, ifname):
|
|
"""Returns True if the interface name is an existing tap in the config.
|
|
The TAP has to be explicitly named in the configuration, and notably
|
|
a TAP belonging to a Linux Control Plane (LCP) will return False.
|
|
"""
|
|
ifname, iface = get_by_name(yaml, ifname)
|
|
return iface is not None
|
|
|
|
|
|
def is_host_name_unique(yaml, hostname):
|
|
"""Returns True if there is at most one occurence of the given ifname amonst all host-names of TAPs."""
|
|
if not "taps" in yaml:
|
|
return True
|
|
host_names = []
|
|
for _tap_ifname, tap_iface in yaml["taps"].items():
|
|
host_names.append(tap_iface["host"]["name"])
|
|
return host_names.count(hostname) < 2
|
|
|
|
|
|
def validate_taps(yaml):
|
|
"""Validate the semantics of all YAML 'taps' entries"""
|
|
result = True
|
|
msgs = []
|
|
logger = logging.getLogger("vppcfg.config")
|
|
logger.addHandler(logging.NullHandler())
|
|
|
|
if not "taps" in yaml:
|
|
return result, msgs
|
|
|
|
for ifname, iface in yaml["taps"].items():
|
|
logger.debug(f"tap {iface}")
|
|
instance = int(ifname[3:])
|
|
|
|
## NOTE(pim): 1024 is not off-by-one, tap1024 is precisely the highest permissible id
|
|
if instance > 1024:
|
|
msgs.append(f"tap {ifname} has instance {int(instance)} which is too large")
|
|
result = False
|
|
|
|
if not is_host_name_unique(yaml, iface["host"]["name"]):
|
|
msgs.append(
|
|
f"tap {ifname} does not have a unique host name {iface['host']['name']}"
|
|
)
|
|
result = False
|
|
|
|
if "rx-ring-size" in iface:
|
|
ncount = iface["rx-ring-size"]
|
|
if ncount & (ncount - 1) != 0:
|
|
msgs.append(f"tap {ifname} rx-ring-size must be a power of two")
|
|
result = False
|
|
|
|
if "tx-ring-size" in iface:
|
|
ncount = iface["tx-ring-size"]
|
|
if ncount & (ncount - 1) != 0:
|
|
msgs.append(f"tap {ifname} tx-ring-size must be a power of two")
|
|
result = False
|
|
|
|
if (
|
|
"namespace-create" in iface["host"]
|
|
and iface["host"]["namespace-create"]
|
|
and not "namespace" in iface["host"]
|
|
):
|
|
msgs.append(
|
|
f"tap {ifname} namespace-create can only be set if namespace is set"
|
|
)
|
|
result = False
|
|
|
|
if (
|
|
"bridge-create" in iface["host"]
|
|
and iface["host"]["bridge-create"]
|
|
and not "bridge" in iface["host"]
|
|
):
|
|
msgs.append(f"tap {ifname} bridge-create can only be set if bridge is set")
|
|
result = False
|
|
|
|
if "mac" in iface["host"] and mac.is_multicast(iface["host"]["mac"]):
|
|
msgs.append(
|
|
f"tap {ifname} host MAC address {iface['host']['mac']} cannot be multicast"
|
|
)
|
|
result = False
|
|
|
|
return result, msgs
|