Files
vppcfg/config/tap.py

117 lines
3.8 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.
#
import logging
import config.mac as 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:
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 not iface == 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):
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:
n = iface["rx-ring-size"]
if n & (n - 1) != 0:
msgs.append(f"tap {ifname} rx-ring-size must be a power of two")
result = False
if "tx-ring-size" in iface:
n = iface["tx-ring-size"]
if n & (n - 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