]> git.proxmox.com Git - mirror_ifupdown2.git/commitdiff
Merge pull request #121 from aderumier/arpaccept
authorJulien Fortin <julien@cumulusnetworks.com>
Thu, 24 Oct 2019 23:21:29 +0000 (16:21 -0700)
committerGitHub <noreply@github.com>
Thu, 24 Oct 2019 23:21:29 +0000 (16:21 -0700)
add arp-accept option.

ifupdown2/addons/address.py
ifupdown2/addons/bond.py
ifupdown2/addons/vrf.py
ifupdown2/ifupdown/ifupdownmain.py
ifupdown2/ifupdown/log.py
ifupdown2/ifupdownaddons/LinkUtils.py
ifupdown2/nlmanager/nlmanager.py

index 762c58c77d3fa2c06cb31ff1956788378a29ea0c..a8ef1e25fe38a5132bc2443c54fb5392ce7295a9 100644 (file)
@@ -299,10 +299,19 @@ class address(moduleBase):
                 else:
                     self.write_file('/proc/sys/net/ipv4/conf/%s/arp_accept' % ifaceobj.name, arp_accept)
         if hwaddress and is_vlan_dev_on_vlan_aware_bridge:
-           if up:
-              self.ipcmd.bridge_fdb_add(bridgename, hwaddress, vlan)
-           else:
-              self.ipcmd.bridge_fdb_del(bridgename, hwaddress, vlan)
+            if up:
+                # check statemanager to delete the old entry if necessary
+                try:
+                    for old_obj in statemanager.statemanager_api.get_ifaceobjs(ifaceobj.name) or []:
+                        old_hwaddress = old_obj.get_attr_value_first("hwaddress")
+                        if old_hwaddress and self.ipcmd.mac_str_to_int(old_hwaddress) != self.ipcmd.mac_str_to_int(hwaddress):
+                            self.ipcmd.bridge_fdb_del(bridgename, old_hwaddress, vlan)
+                            break
+                except:
+                    pass
+                self.ipcmd.bridge_fdb_add(bridgename, hwaddress, vlan)
+            else:
+                self.ipcmd.bridge_fdb_del(bridgename, hwaddress, vlan)
 
     def _get_anycast_addr(self, ifaceobjlist):
         for ifaceobj in ifaceobjlist:
@@ -863,6 +872,12 @@ class address(moduleBase):
         if addr_method not in ["dhcp", "ppp"]:
             self._inet_address_config(ifaceobj, ifaceobj_getfunc,
                                       force_reapply)
+        else:
+            # remove old addresses added by ifupdown2
+            # (if intf was moved from static config to dhcp)
+            for old_ifaceobj in statemanager.statemanager_api.get_ifaceobjs(ifaceobj.name) or []:
+                for addr in old_ifaceobj.get_attr_value("address") or []:
+                    self.ipcmd.addr_del(ifaceobj.name, addr)
 
         self.process_mtu(ifaceobj, ifaceobj_getfunc)
 
index 467c8ba07e1de62355dc1fa66b4de6aae7a961d3..72096b3617093d0e2775cda33149113f83b9f507 100644 (file)
@@ -259,6 +259,16 @@ class bond(moduleBase):
         else:
             return None
 
+    def enable_ipv6_if_prev_brport(self, ifname):
+        """
+        If the intf was previously enslaved to a bridge it is possible ipv6 is still disabled.
+        """
+        try:
+            if os.path.exists("/sys/class/net/%s/brport" % ifname):
+                self.write_file("/proc/sys/net/ipv6/conf/%s/disable_ipv6" % ifname, "0")
+        except Exception, e:
+            self.logger.info(str(e))
+
     def _is_clag_bond(self, ifaceobj):
         if self.get_bond_slaves(ifaceobj):
             attrval = ifaceobj.get_attr_value_first('clag-id')
@@ -297,6 +307,7 @@ class bond(moduleBase):
                     netlink.link_set_protodown(slave, "on")
                 except Exception, e:
                     self.logger.error('%s: %s' % (ifaceobj.name, str(e)))
+            self.enable_ipv6_if_prev_brport(slave)
             netlink.link_set_master(slave, ifaceobj.name)
             if link_up or ifaceobj.link_type != ifaceLinkType.LINK_NA:
                try:
index 3fbec5b6a29c016930d75fd076f42d65d484d7e9..5d7f562e2e33534a851d9997e4f575506cb1304c 100644 (file)
@@ -15,6 +15,7 @@ from sets import Set
 try:
     import ifupdown2.ifupdown.policymanager as policymanager
     import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
+    from ifupdown2.ifupdown.statemanager import statemanager_api as statemanager
 
     from ifupdown2.ifupdown.iface import *
     from ifupdown2.ifupdown.utils import utils
@@ -27,6 +28,7 @@ try:
 except ImportError:
     import ifupdown.policymanager as policymanager
     import ifupdown.ifupdownflags as ifupdownflags
+    from ifupdown.statemanager import statemanager_api as statemanager
 
     from ifupdown.iface import *
     from ifupdown.utils import utils
@@ -438,9 +440,20 @@ class vrf(moduleBase):
                     raise
                 break
         self._handle_existing_connections(ifaceobj, vrfname)
+        self.enable_ipv6_if_prev_brport(ifacename)
         self.ipcmd.link_set(ifacename, 'master', vrfname)
         return
 
+    def enable_ipv6_if_prev_brport(self, ifname):
+        """
+        If the intf was previously enslaved to a bridge it is possible ipv6 is still disabled.
+        """
+        try:
+            if os.path.exists("/sys/class/net/%s/brport" % ifname):
+                self.write_file("/proc/sys/net/ipv6/conf/%s/disable_ipv6" % ifname, "0")
+        except Exception, e:
+            self.logger.info(str(e))
+
     def _down_dhcp_slave(self, ifaceobj, vrfname):
         try:
             dhclient_cmd_prefix = None
@@ -470,6 +483,7 @@ class vrf(moduleBase):
                 uppers = self.ipcmd.link_get_uppers(ifacename)
                 if not uppers or vrfname not in uppers:
                     self._handle_existing_connections(ifaceobj, vrfname)
+                    self.enable_ipv6_if_prev_brport(ifacename)
                     self.ipcmd.link_set(ifacename, 'master', vrfname)
             elif ifaceobj:
                 vrf_master_objs = ifaceobj_getfunc(vrfname)
index f520994511d5486ecb585cc73cb7dc06779430d6..57b17a2743a906e0a1a69b854b6fed4f877c9986 100644 (file)
@@ -1800,6 +1800,9 @@ class ifupdownMain(ifupdownBase):
         if self.flags.STATEMANAGER_ENABLE and ops[0] == 'query-savedstate':
             return self.statemanager.dump_pretty(ifacenames)
         self.flags.STATEMANAGER_UPDATE = False
+
+        iface_read_ret = True
+
         if auto:
             self.logger.debug('setting flag ALL')
             ifupdownflags.flags.ALL = True
@@ -1814,7 +1817,7 @@ class ifupdownMain(ifupdownBase):
                                 ifacePrivFlags(False, True)), ifacenames)
         else:
             try:
-                self.read_iface_config()
+                iface_read_ret = self.read_iface_config()
             except Exception:
                 raise
 
@@ -1865,14 +1868,16 @@ class ifupdownMain(ifupdownBase):
         if ops[0] == 'query' and ifupdownflags.flags.WITHDEFAULTS:
             return self.print_ifaceobjs_pretty(filtered_ifacenames, format)
         elif ops[0] == 'query-checkcurr':
-            ret = self.print_ifaceobjscurr_pretty(filtered_ifacenames, format)
-            if ret != 0:
+            if self.print_ifaceobjscurr_pretty(filtered_ifacenames, format):
                 # if any of the object has an error, signal that silently
                 raise Exception('')
         elif ops[0] == 'query-running':
             self.print_ifaceobjsrunning_pretty(filtered_ifacenames, format)
             return
 
+        if not iface_read_ret or not ret:
+            raise Exception()
+
     def _reload_currentlyup(self, upops, downops, auto=False, allow=None,
             ifacenames=None, excludepats=None, usecurrentconfig=False,
             syntaxcheck=False, **extra_args):
@@ -2082,14 +2087,57 @@ class ifupdownMain(ifupdownBase):
                     not self.is_ifaceobj_builtin(newifaceobjlist[0]) and
                     lastifaceobjlist[0].is_config_present() and
                     lastifaceobjlist[0].link_kind):
-                    self.logger.warn('%s: misconfig ? removed but still exists '
-                                     'as a dependency of %s.\nPlease remove '
-                                     'the dependency manually `ifdown %s` if '
-                                     'it is being picked up as part of a regex'
-                                     % (newifaceobjlist[objidx].name,
-                                        str(newifaceobjlist[objidx].upperifaces),
-                                        newifaceobjlist[objidx].name))
-                if (lastifaceobjlist[0].link_kind and
+
+                    # Check if interface is picked up by a regex in the upperifaces.
+                    print_warning = True
+
+                    for upper in newifaceobjlist[objidx].upperifaces or []:
+                        slaves = []
+                        for upper_ifaceobj in self.ifaceobjdict.get(upper):
+                            slaves.extend(upper_ifaceobj.get_attr_value("bond-slaves") or [])
+                            slaves.extend(upper_ifaceobj.get_attr_value("bridge-ports") or [])
+                        slaves_string = " ".join(slaves)
+                        if newifaceobjlist[objidx].name not in slaves_string:
+                            print_warning = "regex" not in slaves_string
+                            if not print_warning:
+                                break
+                    ###############################################################
+
+                    warning_no_config_regex = (
+                        "%s: misconfig ? removed but still exists as a dependency of %s.\n"
+                        "Please remove the dependency manually `ifdown %s` if it is being "
+                        "picked up as part of a regex" % (
+                            newifaceobjlist[objidx].name,
+                            str(newifaceobjlist[objidx].upperifaces),
+                            newifaceobjlist[objidx].name
+                        )
+                    )
+
+                    if print_warning:
+                        self.logger.warn(warning_no_config_regex)
+                    else:
+                        # The warning shouldn't be printed because we've detected that this
+                        # interface was pick up as part of a regex but the config doesn't
+                        # exist anymore. It was most likely removed from the config file itself
+                        # We should down this interface and remove it from the ifaceobjdict
+                        # and dependency graph used for the following ifreload.
+                        ifname_to_remove = newifaceobjlist[objidx].name
+                        ifacedownlist.append(ifname_to_remove)
+
+                        try:
+                            if new_ifaceobjdict:
+                                del new_ifaceobjdict[ifname_to_remove]
+
+                            for k, v in new_dependency_graph.iteritems():
+                                if ifname_to_remove in v:
+                                    v.remove(ifname_to_remove)
+                            del new_dependency_graph[ifname_to_remove]
+                        except Exception as e:
+                            self.logger.warning(warning_no_config_regex)
+                            self.logger.warning("while trying to fix this situation "
+                                                "we ran into the following issues: %s" % str(e))
+
+                elif (lastifaceobjlist[0].link_kind and
                     not newifaceobjlist[0].link_kind):
                     self.logger.warn('%s: moved from being a %s to a'
                                      ' physical interface (non-logical interface).'
index e569fbe5a0a680017813d37c6dc3ea53d03e7020..cd09e346c37f973c973bd125a0dbdf95926e792d 100644 (file)
@@ -167,23 +167,3 @@ class Log:
 
 
 log = Log()
-
-
-"""
-
-#logging.basicConfig( format="%(filename)s: %(username)s says '%(message)s' in %(funcname)s" )
-
-Logger.debug(msg, *args, **kwargs)
-Logs a message with level DEBUG on this logger. The msg is the message format string, and the args are the arguments which are merged into msg using the string formatting operator. (Note that this means that you can use keywords in the format string, together with a single dictionary argument.)
-
-There are two keyword arguments in kwargs which are inspected: exc_info which, if it does not evaluate as false, causes exception information to be added to the logging message. If an exception tuple (in the format returned by sys.exc_info()) is provided, it is used; otherwise, sys.exc_info() is called to get the exception information.
-
-"""
-
-"""
-USE FILTER TO IGNORE "EXITS" MESSAGES
-Now that you know the basic plot, let me introduce one more character - the Filter.
-Filter as the name suggests, allows you to filter a message before you log it. Yes, messages are filtered based on the level setting, but adding a Filter gives you more fine grained control of messages you log.
-Both Loggers and Handlers can have multiple Filters. You can add Filters using addFilter and removeFilter methods.
-When a Logger/Handler receives a message, it consults all of its filters. If the filter(record) method on any of the Filters attached returns False (or 0) the message is dropped.
-The official documentation, though detailed, is actually pretty confusing about the role of Filters. This is a pity; because Filters can be handy when you want to drop a message based on a regular expression, error code, contextual information and pretty much anything else. The default Filter is pretty much useless (and the doc string is very confusing too). Just inherit from the default filter and override the filter method according to what you want to filter out. (Be sure to download the source for logging module and check out the unit tests which have some good examples. See the references at the end of this post.)"""
index 2b29bfeb27e518e02dca37f90acb347facc7d5be..615241a8ecdf6fc893ac0ff3687aa187791a551a 100644 (file)
@@ -1012,13 +1012,13 @@ class LinkUtils(utilsBase):
             obj = IPNetwork(ip)
 
             if type(obj) == IPv6Network:
-                ip6.append(obj)
+                ip6.append(str(obj))
             else:
-                ip4.append(obj)
+                ip4.append(str(obj))
 
         running_ipobj = []
         for ip in running_addrs or []:
-            running_ipobj.append(IPNetwork(ip))
+            running_ipobj.append(str(IPNetwork(ip)))
 
         return running_ipobj == (ip4 + ip6)
 
index ba9453d4488a5e288bc4aa0fae21ccaafcf02750..deb7ecf99fe0d281f2901e46c4924499fd910475 100644 (file)
@@ -142,8 +142,39 @@ class NetlinkManager(object):
         The TX socket is used for install requests, sending RTM_GETXXXX
         requests, etc
         """
-        self.tx_socket = socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, 0)
-        self.tx_socket.bind((self.pid, 0))
+        try:
+            self.tx_socket = socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, 0)
+
+            # bind retry mechanism:
+            # in some cases we are running into weird issues... Address already in use
+            # to counter this problem, we will retry up to NLMANAGER_BIND_RETRY times to
+            # bind our socket, every time increasing the address (or pid) that we bind it
+            # to. NLMANAGER_BIND_RETRY default to 4242
+            for i in xrange(0, int(os.getenv("NLMANAGER_BIND_RETRY", 4242))):
+                try:
+                    self.tx_socket.bind((self.pid + i, 0))
+                    # the bind call succeeded, we need to update self.pid
+                    # to reflect the correct value we are binded to. If we
+                    # couldn't bind to our real pid (os.getpid()) warn user
+                    # to avoid confusion (via debug logs).
+                    if i != 0:
+                        log.debug(
+                            "nlmanager: pid %s already in use - binding netlink socket to pid %s"
+                            % (self.pid, self.pid + i)
+                        )
+                    self.pid = self.pid + i
+                    return
+                except:
+                    pass
+            # if we reach this code it means all our bind calls failed. We are trying to
+            # bind the socket one last time on the original parameters if not we will not
+            # be catching the exception
+            self.tx_socket.bind((self.pid, 0))
+        except:
+            if self.tx_socket:
+                self.tx_socket.close()
+                self.tx_socket = None
+            raise
 
     def tx_nlpacket_raw(self, message):
         """