mirror of
				https://github.com/CumulusNetworks/ifupdown2.git
				synced 2024-05-06 15:54:50 +00:00 
			
		
		
		
	Add bridge-ports-condone-regex option (closes #117)
The bridge-ports-condone-regex option can be used to tell ifupdown2 to let some bridge member ports alone and do not remove them on ifreload runs. This might come in handy when running a KVM (or any other virtualization system) host with a bridged network setup. Before this option, ifupdown2 would either complain about not existing member ports when setting up the bridge (if all VM interfaces were to be specified in /etc/network/interfaces) or remove any VM interface from a bridge if it was not specified in /e/n/i. Signed-off-by: Maximilian Wilhelm <max@rfc2324.org> Signed-off-by: Julien Fortin <julien@cumulusnetworks.com> Co-authored-by: Julien Fortin <julien@cumulusnetworks.com> Signed-off-by: Julien Fortin <julien@cumulusnetworks.com>
This commit is contained in:
		
				
					committed by
					
						
						Julien Fortin
					
				
			
			
				
	
			
			
			
						parent
						
							c9091d7108
						
					
				
				
					commit
					f5c97c0d6b
				
			@@ -76,6 +76,10 @@ class bridge(moduleBase):
 | 
			
		||||
                         'example' : ['bridge-ports swp1.100 swp2.100 swp3.100',
 | 
			
		||||
                                      'bridge-ports glob swp1-3.100',
 | 
			
		||||
                                      'bridge-ports regex (swp[1|2|3].100)']},
 | 
			
		||||
                   'bridge-ports-condone-regex' :
 | 
			
		||||
                        {'help' : 'bridge ports to ignore/condone when reloading config / removing interfaces',
 | 
			
		||||
                         'required' : False,
 | 
			
		||||
                         'example' : [ 'bridge-ports-condone-regex ^[a-zA-Z0-9]+_v[0-9]{1,4}$']},
 | 
			
		||||
                   'bridge-stp' :
 | 
			
		||||
                        {'help': 'bridge-stp yes/no',
 | 
			
		||||
                         'example' : ['bridge-stp no'],
 | 
			
		||||
@@ -901,6 +905,19 @@ class bridge(moduleBase):
 | 
			
		||||
        ports = self._get_ifaceobj_bridge_ports(ifaceobj)
 | 
			
		||||
        return self.parse_port_list(ifaceobj.name, ports) if ports else None
 | 
			
		||||
 | 
			
		||||
    def _get_bridge_port_condone_regex(self, ifaceobj, get_string = False):
 | 
			
		||||
        bridge_port_condone_regex = ifaceobj.get_attr_value_first('bridge-ports-condone-regex')
 | 
			
		||||
        # If bridge-ports-ignore-regex is configured, do NOT use the parse_port_list()
 | 
			
		||||
        # function to gather a list of ports matching the regex here and now but set
 | 
			
		||||
        # up a compiled regex to be used in a match later. This way we try to avoid
 | 
			
		||||
        # a race condition where an (possibly VM) interface is created after this
 | 
			
		||||
        # function has been called but before the bridgeports are validated.
 | 
			
		||||
        if bridge_port_condone_regex:
 | 
			
		||||
            if get_string:
 | 
			
		||||
                return bridge_port_condone_regex
 | 
			
		||||
            return re.compile (r"%s" % bridge_port_condone_regex)
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
    def _process_bridge_waitport(self, ifaceobj, portlist):
 | 
			
		||||
        waitport_value = ifaceobj.get_attr_value_first('bridge-waitport')
 | 
			
		||||
        if not waitport_value: return
 | 
			
		||||
@@ -974,6 +991,7 @@ class bridge(moduleBase):
 | 
			
		||||
 | 
			
		||||
    def _add_ports(self, ifaceobj, ifaceobj_getfunc):
 | 
			
		||||
        bridgeports = self._get_bridge_port_list(ifaceobj)
 | 
			
		||||
        bridgeportscondoneregex = self._get_bridge_port_condone_regex(ifaceobj)
 | 
			
		||||
        runningbridgeports = []
 | 
			
		||||
 | 
			
		||||
        self.ipcmd.batch_start()
 | 
			
		||||
@@ -985,6 +1003,9 @@ class bridge(moduleBase):
 | 
			
		||||
            if runningbridgeports:
 | 
			
		||||
                for bport in runningbridgeports:
 | 
			
		||||
                    if not bridgeports or bport not in bridgeports:
 | 
			
		||||
                        if bridgeportscondoneregex and bridgeportscondoneregex.match(bport):
 | 
			
		||||
                            self.logger.info("%s: port %s will stay enslaved as it matches with bridge-ports-condone-regex" % (ifaceobj.name, bport))
 | 
			
		||||
                            continue
 | 
			
		||||
                        self.ipcmd.link_set(bport, 'nomaster')
 | 
			
		||||
                        # set admin DOWN on all removed ports
 | 
			
		||||
                        # that don't have config outside bridge
 | 
			
		||||
@@ -2617,6 +2638,14 @@ class bridge(moduleBase):
 | 
			
		||||
            self.query_check_bridge_ports(ifaceobj, ifaceobjcurr, runningattrs.get('ports', {}).keys(), ifaceobj_getfunc)
 | 
			
		||||
            diff.remove('bridge-ports')
 | 
			
		||||
 | 
			
		||||
        if "bridge-ports-condone-regex" in diff:
 | 
			
		||||
            ifaceobjcurr.update_config_with_status(
 | 
			
		||||
                "bridge-ports-condone-regex",
 | 
			
		||||
                self._get_bridge_port_condone_regex(ifaceobj, True),
 | 
			
		||||
                0
 | 
			
		||||
            )
 | 
			
		||||
            diff.remove("bridge-ports-condone-regex")
 | 
			
		||||
 | 
			
		||||
        for k in diff:
 | 
			
		||||
            # get the corresponding ifaceobj attr
 | 
			
		||||
            v = ifaceobj.get_attr_value_first(k)
 | 
			
		||||
@@ -2740,8 +2769,6 @@ class bridge(moduleBase):
 | 
			
		||||
        if not running_port_list and not bridge_all_ports:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        ports_list_status = 0 if not set(running_port_list).symmetric_difference(bridge_all_ports) else 1
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            port_list = self._get_ifaceobj_bridge_ports(ifaceobj).split()
 | 
			
		||||
            # we want to display the same bridge-ports list as provided
 | 
			
		||||
@@ -2757,7 +2784,29 @@ class bridge(moduleBase):
 | 
			
		||||
                port_list = ordered
 | 
			
		||||
        except:
 | 
			
		||||
            port_list = running_port_list
 | 
			
		||||
        ifaceobjcurr.update_config_with_status('bridge-ports', (' '.join(port_list) if port_list else ''), ports_list_status)
 | 
			
		||||
 | 
			
		||||
        difference = set(running_port_list).symmetric_difference(bridge_all_ports)
 | 
			
		||||
        bridge_port_condone_regex = self._get_bridge_port_condone_regex(ifaceobj)
 | 
			
		||||
 | 
			
		||||
        if bridge_port_condone_regex:
 | 
			
		||||
            # Drop any condoned port from the difference set
 | 
			
		||||
            condone_ports = [port for port in difference if bridge_port_condone_regex.match(port)]
 | 
			
		||||
 | 
			
		||||
            for port in condone_ports:
 | 
			
		||||
                try:
 | 
			
		||||
                    difference.remove(port)
 | 
			
		||||
                except ValueError:
 | 
			
		||||
                    pass
 | 
			
		||||
 | 
			
		||||
                # Tag all condoned ports in brackets in output
 | 
			
		||||
                if port not in bridge_all_ports:
 | 
			
		||||
                    port_list.append("(%s)" % port)
 | 
			
		||||
 | 
			
		||||
        ifaceobjcurr.update_config_with_status(
 | 
			
		||||
            "bridge-ports",
 | 
			
		||||
            " ".join(port_list) if port_list else "",
 | 
			
		||||
            0 if not difference else 1
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def get_ifaceobj_bridge_vids(self, ifaceobj):
 | 
			
		||||
        vids = ('bridge-vids', ifaceobj.get_attr_value_first('bridge-vids'))
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user