1
0
mirror of https://github.com/CumulusNetworks/ifupdown2.git synced 2024-05-06 15:54:50 +00:00
Julien Fortin 995c38e29a addons: bridge: bridge_vlan_aware_list is now a set()
in the case of ifreload bridge.py:get_dependent is entered twice,
once for the old ifaceobjs and once for the new ones. Thus adding
bridges twice to the list. Having a set will prevent this issue.

Signed-off-by: Julien Fortin <jfortin@nvidia.com>
2021-07-01 17:45:59 +02:00

220 lines
8.0 KiB
Python

# Copyright (C) 2017, 2018 Cumulus Networks, Inc. all rights reserved
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; version 2.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
#
# https://www.gnu.org/licenses/gpl-2.0-standalone.html
#
# Author:
# Julien Fortin, julien@cumulusnetworks.com
#
# addon -- Addon base class
#
import logging
from collections import OrderedDict
try:
from ifupdown2.lib.io import IO
from ifupdown2.lib.sysfs import Sysfs
from ifupdown2.lib.iproute2 import IPRoute2
from ifupdown2.lib.base_objects import Netlink, Cache, Requirements
from ifupdown2.ifupdown.iface import ifaceLinkPrivFlags, ifaceLinkKind
import ifupdown2.ifupdown.policymanager as policymanager
import ifupdown2.nlmanager.ipnetwork as ipnetwork
except (ImportError, ModuleNotFoundError):
from lib.io import IO
from lib.sysfs import Sysfs
from lib.iproute2 import IPRoute2
from lib.base_objects import Netlink, Cache, Requirements
from ifupdown.iface import ifaceLinkPrivFlags, ifaceLinkKind
import ifupdown.policymanager as policymanager
import nlmanager.ipnetwork as ipnetwork
class Addon(Netlink, Cache):
"""
Base class for ifupdown2 addon modules
Provides common infrastructure methods for all addon modules
"""
def __init__(self):
Netlink.__init__(self)
Cache.__init__(self)
self.logger = logging.getLogger("ifupdown2.addons.%s" % self.__class__.__name__)
self.io = IO()
self.sysfs = Sysfs
self.iproute2 = IPRoute2()
self.requirements = Requirements()
self.__alias_to_attribute = {}
for attribute_name, attribute_object in self.__get_modinfo().get("attrs", {}).items():
for alias in attribute_object.get("aliases", []):
self.__alias_to_attribute[alias] = attribute_name
def __get_modinfo(self) -> dict:
try:
return self._modinfo
except AttributeError:
return {}
def translate(self, ifaceobjs):
"""
Replace attribute aliases from user configuration with real attribute name
"""
for ifaceobj in ifaceobjs:
ifaceobj.config = OrderedDict(
[
(self.__alias_to_attribute[user_attr], user_value)
if user_attr in self.__alias_to_attribute
else (user_attr, user_value)
for user_attr, user_value in ifaceobj.config.items()
]
)
class Bridge(Addon):
bridge_vlan_aware_list = set()
def __init__(self):
super(Bridge, self).__init__()
def _re_evaluate_bridge_vxlan(self, ifaceobj, ifaceobj_getfunc=None):
"""
Quick fix for BRIDGE_VXLAN
BRIDGE_VXLAN is not set on the bridge because the VXLAN hasn't been processed yet
(because its defined after the bridge in /e/n/i), here is what happens:
- ifupdownmain:populate_dependency_info()
- loops over all the intf from /e/n/i (with the example config:
['lo', 'eth0', 'swp1', 'swp2', 'bridge', 'vni-10', 'bridge.100', 'vlan100'])
----> bridge is first in the list of interface (that we care about)
- ifupdownmain:query_lowerifaces()
- bridge:get_dependent is called (debug: bridge: evaluating port expr '['swp1', 'swp2', 'vni-10']')
- ifupdownmain:preprocess_dependency_list()
- calls ifupdownmain:_set_iface_role_n_kind() on all the brports:
in _set_iface_role_n_kind:
ifaceobj is the brport
upperifaceobj is the bridge
it tries to see if the bridge has a VXLAN:
if (ifaceobj.link_kind & ifaceLinkKind.VXLAN) \
and (upperifaceobj.link_kind & ifaceLinkKind.BRIDGE):
upperifaceobj.link_privflags |= ifaceLinkPrivFlags.BRIDGE_VXLAN
but because the bridge is first in the /e/n/i ifupdown2 didn't
call vxlan:get_dependent_ifacenames so VXLAN is not set on ifaceobj
:return:
"""
if not ifaceobj_getfunc:
return
if ifaceobj.link_kind & ifaceLinkKind.BRIDGE and not ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VXLAN:
for port in self._get_bridge_port_list(ifaceobj) or []:
for brport_ifaceobj in ifaceobj_getfunc(port):
if brport_ifaceobj.link_kind & ifaceLinkKind.VXLAN:
ifaceobj.link_privflags |= ifaceLinkPrivFlags.BRIDGE_VXLAN
self.__check_l3vni_bridge(ifaceobj)
return
elif ifaceobj.link_kind & ifaceLinkKind.BRIDGE:
self.__check_l3vni_bridge(ifaceobj)
elif ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT and ifaceobj.link_kind & ifaceLinkKind.VXLAN:
for iface in ifaceobj.upperifaces if ifaceobj.upperifaces else []:
for bridge_ifaceobj in ifaceobj_getfunc(iface) or []:
bridge_ifaceobj.link_privflags |= ifaceLinkPrivFlags.BRIDGE_VXLAN
self.__check_l3vni_bridge(bridge_ifaceobj)
def __check_l3vni_bridge(self, ifaceobj):
# the calling function needs to make sure that the following checks were performed:
# ifaceobj.link_kind & ifaceLinkKind.BRIDGE
# ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VXLAN
if ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_VLAN_AWARE \
and len(self._get_ifaceobj_bridge_ports(ifaceobj, as_list=True)) == 1:
ifaceobj.link_privflags |= ifaceLinkPrivFlags.BRIDGE_l3VNI
@staticmethod
def _get_ifaceobj_bridge_ports(ifaceobj, as_list=False):
bridge_ports = []
for brport in ifaceobj.get_attr_value('bridge-ports') or []:
if brport != 'none':
bridge_ports.extend(brport.split())
if as_list:
return bridge_ports
return ' '.join(bridge_ports)
def _get_bridge_port_list(self, ifaceobj):
# port list is also available in the previously
# parsed dependent list. Use that if available, instead
# of parsing port expr again
port_list = ifaceobj.lowerifaces
if port_list:
return port_list
ports = self._get_ifaceobj_bridge_ports(ifaceobj)
if ports:
return self.parse_port_list(ifaceobj.name, ports)
else:
return None
class AddonWithIpBlackList(Addon):
try:
ip_blacklist = [ipnetwork.IPNetwork(ip).ip for ip in policymanager.policymanager_api.get_module_globals(
module_name="address",
attr="ip_blacklist"
) or []]
__ip_blacklist_exception = None
except Exception as e:
__ip_blacklist_exception = e
ip_blacklist = []
def __init__(self):
"""
If an exception occurred during the ip blacklist parsing we need to display it (once)
Also we keep this as a class variable to share it between the address and addressvirtual module
"""
super(AddonWithIpBlackList, self).__init__()
if AddonWithIpBlackList.__ip_blacklist_exception:
self.logger.warning("policy.d: address: 'ip_blacklist': %s" % AddonWithIpBlackList.__ip_blacklist_exception)
AddonWithIpBlackList.__ip_blacklist_exception = None
def ip_blacklist_check(self, ifname, ip):
"""
Check if the ip address is not blacklisted (in ip_blacklist)
:param ifname:
:param ip:
:return:
"""
if ip.ip in AddonWithIpBlackList.ip_blacklist:
raise Exception("%s: blacklisted ip address in use: %s" % (ifname, ip.ip))