1
0
mirror of https://github.com/CumulusNetworks/ifupdown2.git synced 2024-05-06 15:54:50 +00:00

addons: bridge: add support for new bridge-always-up attribute

Enabling this attribute on a bridge will
enslave a dummy interface to the bridge

example:

auto bridge
iface bridge
      bridge-vlan-aware yes
      bridge-always-up yes
      bridge-ports vni42

Signed-off-by: Julien Fortin <julien@cumulusnetworks.com>
This commit is contained in:
Julien Fortin
2020-03-07 00:34:41 +01:00
parent 4b706d71e2
commit 7840bd2c09
2 changed files with 83 additions and 0 deletions

View File

@@ -441,6 +441,11 @@ class bridge(Addon, moduleBase):
"required": False,
"example": ["bridge-ports-condone-regex ^[a-zA-Z0-9]+_v[0-9]{1,4}$"]
},
"bridge-always-up": {
"help": "Enabling this attribute on a bridge will enslave a dummy interface to the bridge",
"required": False,
"validvals": ["yes", "no", "on", "off"]
}
}
}
@@ -1083,6 +1088,17 @@ class bridge(Addon, moduleBase):
bridgeportscondoneregex = self._get_bridge_port_condone_regex(ifaceobj)
runningbridgeports = []
# bridge-always-up #####################################################
bridge_always_up = ifaceobj.get_attr_value_first("bridge-always-up")
dummy_brport = None
if utils.get_boolean_from_string(bridge_always_up):
# the dummy port will be added to the bridgeports list so the
# following code don't de-enslave the dummy device.
dummy_brport = self.bridge_always_up(ifaceobj.name, bridgeports)
########################################################################
self._process_bridge_waitport(ifaceobj, bridgeports)
# Delete active ports not in the new port list
if not ifupdownflags.flags.PERFMODE:
@@ -1113,6 +1129,12 @@ class bridge(Addon, moduleBase):
if br_port in newbridgeports:
newbridgeports_ordered.append(br_port)
if dummy_brport:
# add the dummy port to the list of interface to enslave
# link_set_master should make sure that the device is not
# already enslaved.
newbridgeports_ordered.append(dummy_brport)
self.iproute2.batch_start()
for bridgeport in newbridgeports_ordered:
@@ -1143,8 +1165,34 @@ class bridge(Addon, moduleBase):
if err:
self.log_error('bridge configuration failed (missing ports)')
try:
# to avoid any side effect we remove the dummy brport from the
# list of supposedly newly configured ports.
newly_enslaved_ports.remove(dummy_brport)
except:
pass
return newly_enslaved_ports
def get_dummy_brport_name_for_bridge(self, bridge_name):
"""
dummy brport will have pre-formated name: brport-if$BRIDGE_IFINDEX
That way we can avoid collision with existing interfaces
"""
# this can raise: NetlinkCacheIfnameNotFoundError
return "brport-if%d" % self.cache.get_ifindex(bridge_name)
def bridge_always_up(self, bridge_name, newbridgeports_ordered):
dummy_brport = self.get_dummy_brport_name_for_bridge(bridge_name)
if not self.cache.link_exists(dummy_brport):
self.logger.info("%s: bridge-always-up yes: enslaving dummy port: %s" % (bridge_name, dummy_brport))
self.netlink.link_add(ifname=dummy_brport, kind="dummy")
self.netlink.link_up_force(dummy_brport)
newbridgeports_ordered.append(dummy_brport)
return dummy_brport
def _process_bridge_maxwait(self, ifaceobj, portlist):
maxwait = ifaceobj.get_attr_value_first('bridge-maxwait')
if not maxwait: return
@@ -2478,6 +2526,12 @@ class bridge(Addon, moduleBase):
ifname = ifaceobj.name
if not self.cache.link_exists(ifname):
return
try:
self.netlink.link_del(self.get_dummy_brport_name_for_bridge(ifname))
except:
pass
try:
running_ports = self.cache.get_slaves(ifname)
if running_ports:
@@ -2921,6 +2975,24 @@ class bridge(Addon, moduleBase):
self._query_check_mcqv4src(ifaceobj, ifaceobjcurr)
self._query_check_l2protocol_tunnel_on_bridge(ifname, ifaceobj, ifaceobjcurr)
def _query_check_bridge_always_up(self, ifname, ifaceobj, ifaceobjcurr, bridge_config):
bridge_always_up = ifaceobj.get_attr_value_first("bridge-always-up")
if bridge_always_up:
bridge_config.remove("bridge-always-up")
if utils.get_boolean_from_string(bridge_always_up):
try:
link_exists = self.cache.link_exists(self.get_dummy_brport_name_for_bridge(ifname))
except:
link_exists = False
ifaceobjcurr.update_config_with_status(
"bridge-always-up",
"yes" if link_exists else "no",
not link_exists
)
def _query_check_bridge_attributes(self, ifaceobj, ifaceobjcurr, bridge_config, cached_ifla_info_data):
for attr in list(bridge_config):
query_check_handler, netlink_attr = self._bridge_attribute_query_check_handler.get(attr, (None, None))
@@ -2929,6 +3001,8 @@ class bridge(Addon, moduleBase):
query_check_handler(attr, ifaceobj.get_attr_value_first(attr), ifaceobjcurr, cached_ifla_info_data.get(netlink_attr))
bridge_config.remove(attr)
self._query_check_bridge_always_up(ifaceobj.name, ifaceobj, ifaceobjcurr, bridge_config)
def _query_check_brport_attributes_on_bridge(self, ifname, ifaceobj, ifaceobjcurr, bridge_config):
brports_info_slave_data = {}
# bridge_config should only have bridge-port-list attributes
@@ -3046,6 +3120,14 @@ class bridge(Addon, moduleBase):
####################################################################################################################
def query_check_bridge_ports(self, ifaceobj, ifaceobjcurr, running_port_list, ifaceobj_getfunc):
# if bridge-always-up is set we need to remove the dummy brport from the running_port_list
if utils.get_boolean_from_string(ifaceobj.get_attr_value_first("bridge-always-up")):
try:
running_port_list.remove(self.get_dummy_brport_name_for_bridge(ifaceobj.name))
except:
pass
bridge_all_ports = []
for obj in ifaceobj_getfunc(ifaceobj.name) or []:
bridge_all_ports.extend(self._get_bridge_port_list(obj) or [])