]> git.proxmox.com Git - mirror_ifupdown2.git/blobdiff - addons/vrf.py
addons: vrf: fix vrf slave link kind (fixes #39)
[mirror_ifupdown2.git] / addons / vrf.py
index 7e02ce35522d0dac6ba3d4c48284820b32a73f25..5e46aa3076e4781b2f71d6d1241ae0251f983e68 100644 (file)
@@ -123,6 +123,8 @@ class vrf(moduleBase):
         self.vrf_fix_local_table = True
         self.vrf_count = 0
         self.vrf_helper = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vrf-helper')
+        self.vrf_close_socks_on_down = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vrf-close-socks-on-down')
+        self.warn_on_vrf_map_write_err = True
 
     def _iproute2_vrf_map_initialize(self, writetodisk=True):
         if self._iproute2_vrf_map_initialized:
@@ -149,8 +151,7 @@ class vrf(moduleBase):
                             continue
                         self.iproute2_vrf_map[int(table)] = vrf_name
                     except Exception, e:
-                        self.logger.info('vrf: iproute2_vrf_map: unable to parse %s'
-                                         %l)
+                        self.logger.info('vrf: iproute2_vrf_map: unable to parse %s (%s)' %(l, str(e)))
                         pass
 
         vrfs = self.ipcmd.link_get_vrfs()
@@ -189,18 +190,35 @@ class vrf(moduleBase):
         self._iproute2_vrf_map_initialized = True
         self.vrf_count = len(self.iproute2_vrf_map)
 
+    def _iproute2_map_warn(self, errstr):
+        if self.warn_on_vrf_map_write_err:
+            if not os.path.exists('/etc/iproute2/rt_tables.d/'):
+                self.logger.info('unable to save iproute2 vrf to table ' +
+                                 'map (%s)\n' %errstr)
+                self.logger.info('cannot find /etc/iproute2/rt_tables.d.' +
+                                 ' pls check if your iproute2 version' +
+                                 ' supports rt_tables.d')
+            else:
+                self.logger.warn('unable to open iproute2 vrf to table ' +
+                                 'map (%s)\n' %errstr)
+            self.warn_on_vrf_map_write_err = False
+
     def _iproute2_vrf_map_sync_to_disk(self):
         if (ifupdownflags.flags.DRYRUN or
             not self.iproute2_vrf_map_sync_to_disk):
             return
         self.logger.info('vrf: syncing table map to %s'
                          %self.iproute2_vrf_filename)
-        with open(self.iproute2_vrf_filename, 'w') as f:
-            f.write(self.iproute2_vrf_filehdr %(self.vrf_table_id_start,
-                    self.vrf_table_id_end))
-            for t, v in self.iproute2_vrf_map.iteritems():
-                f.write('%s %s\n' %(t, v))
-            f.flush()
+        try:
+            with open(self.iproute2_vrf_filename, 'w') as f:
+                f.write(self.iproute2_vrf_filehdr %(self.vrf_table_id_start,
+                        self.vrf_table_id_end))
+                for t, v in self.iproute2_vrf_map.iteritems():
+                    f.write('%s %s\n' %(t, v))
+                f.flush()
+        except Exception, e:
+            self._iproute2_map_warn(str(e))
+            pass
 
     def _iproute2_vrf_map_open(self, sync_vrfs=False, append=False):
         self.logger.info('vrf: syncing table map to %s'
@@ -213,8 +231,7 @@ class vrf(moduleBase):
                                          '%s' %fmode)
             fcntl.fcntl(self.iproute2_vrf_map_fd, fcntl.F_SETFD, fcntl.FD_CLOEXEC)
         except Exception, e:
-            self.log_warn('vrf: error opening %s (%s)'
-                          %(self.iproute2_vrf_filename, str(e)))
+            self._iproute2_map_warn(str(e))
             return
 
         if not append:
@@ -294,7 +311,7 @@ class vrf(moduleBase):
             self.iproute2_vrf_map_sync_to_disk = True
             del self.iproute2_vrf_map[int(table_id)]
         except Exception, e:
-            self.logger.info('vrf: iproute2 vrf map del failed for %d (%s)'
+            self.logger.info('vrf: iproute2 vrf map del failed for %s (%s)'
                              %(table_id, str(e)))
             pass
 
@@ -345,7 +362,7 @@ class vrf(moduleBase):
                     raise
                 break
         self._handle_existing_connections(ifaceobj, vrfname)
-        self.ipcmd.link_set(ifacename, 'master', vrfname)
+        netlink.link_set_master(ifacename, vrfname)
         return
 
     def _down_dhcp_slave(self, ifaceobj, vrfname):
@@ -374,10 +391,10 @@ class vrf(moduleBase):
         try:
             master_exists = True
             if vrf_exists or self.ipcmd.link_exists(vrfname):
-                upper = self.ipcmd.link_get_upper(ifacename)
-                if not upper or upper != vrfname:
+                uppers = self.ipcmd.link_get_uppers(ifacename)
+                if not uppers or vrfname not in uppers:
                     self._handle_existing_connections(ifaceobj, vrfname)
-                    self.ipcmd.link_set(ifacename, 'master', vrfname)
+                    netlink.link_set_master(ifacename, vrfname)
             elif ifaceobj:
                 vrf_master_objs = ifaceobj_getfunc(vrfname)
                 if not vrf_master_objs:
@@ -390,6 +407,7 @@ class vrf(moduleBase):
                                    %vrfname)
                     return
                 if (ifupdownflags.flags.ALL or
+                    ifupdownflags.flags.WITH_DEPENDS or
                     (ifupdownflags.flags.CLASS and
                      ifaceobj.classes and vrf_master_objs[0].classes and
                      Set(ifaceobj.classes).intersection(vrf_master_objs[0].classes))):
@@ -586,14 +604,12 @@ class vrf(moduleBase):
                                 %(str(self.system_reserved_rt_tables.values())),
                                 ifaceobj)
             if self.vrf_count == self.vrf_max_count:
-                self.log_error('%s: max vrf count %d hit...not '
-                               'creating vrf' %(ifaceobj.name,
-                                                self.vrf_count), ifaceobj)
+                self.log_error('max vrf count %d hit...not '
+                               'creating vrf' % self.vrf_count, ifaceobj)
             if vrf_table == 'auto':
                 vrf_table = self._get_avail_vrf_table_id()
                 if not vrf_table:
-                    self.log_error('%s: unable to get an auto table id'
-                                   %ifaceobj.name, ifaceobj)
+                    self.log_error('unable to get an auto table id', ifaceobj)
                 self.logger.info('%s: table id auto: selected table id %s\n'
                                  %(ifaceobj.name, vrf_table))
             else:
@@ -604,41 +620,38 @@ class vrf(moduleBase):
                                   ifaceobj)
 
             if not vrf_table.isdigit():
-                self.log_error('%s: vrf-table must be an integer or \'auto\''
-                               %(ifaceobj.name), ifaceobj)
+                self.log_error('vrf-table must be an integer or \'auto\'', ifaceobj)
 
             # XXX: If we decide to not allow vrf id usages out of
             # the reserved ifupdown range, then uncomment this code.
             else:
                 if (int(vrf_table) < self.vrf_table_id_start or
                     int(vrf_table) > self.vrf_table_id_end):
-                    self.log_error('%s: vrf table id %s out of reserved range [%d,%d]'
-                                   %(ifaceobj.name, vrf_table,
+                    self.log_error('vrf table id %s out of reserved range [%d,%d]'
+                                   %(vrf_table,
                                      self.vrf_table_id_start,
                                      self.vrf_table_id_end), ifaceobj)
             try:
                 self.ipcmd.link_create(ifaceobj.name, 'vrf',
                                        {'table' : '%s' %vrf_table})
             except Exception, e:
-                self.log_error('%s: create failed (%s)\n'
-                               %(ifaceobj.name, str(e)), ifaceobj)
+                self.log_error('create failed (%s)\n' % str(e), ifaceobj)
             if vrf_table != 'auto':
                 self._iproute2_vrf_table_entry_add(ifaceobj, vrf_table)
         else:
             if vrf_table == 'auto':
                 vrf_table = self._get_iproute2_vrf_table(ifaceobj.name)
                 if not vrf_table:
-                    self.log_error('%s: unable to get vrf table id'
-                                   %ifaceobj.name, ifaceobj)
+                    self.log_error('unable to get vrf table id', ifaceobj)
 
             # if the device exists, check if table id is same
             vrfdev_attrs = self.ipcmd.link_get_linkinfo_attrs(ifaceobj.name)
             if vrfdev_attrs:
                 running_table = vrfdev_attrs.get('table', None)
                 if vrf_table != running_table:
-                    self.log_error('%s: cannot change vrf table id,running table id %s is different from config id %s' %(ifaceobj.name,
-                                         running_table, vrf_table),
-                                         ifaceobj)
+                    self.log_error('cannot change vrf table id,running table id'
+                                   ' %s is different from config id %s'
+                                   % (running_table, vrf_table), ifaceobj)
         return vrf_table
 
     def _up_vrf_helper(self, ifaceobj, vrf_table):
@@ -787,8 +800,23 @@ class vrf(moduleBase):
                                 vrf_table,
                                 mode))
 
+    def _close_sockets(self, ifaceobj, ifindex):
+        if not self.vrf_close_socks_on_down:
+            return
+
+        try:
+            utils.exec_command('/bin/ss -aK \"dev == %s\"'
+                               %ifindex)
+        except Exception, e:
+            self.logger.info('%s: closing socks using ss'
+                             ' failed (%s)\n' %(ifaceobj.name, str(e)))
+            pass
+
     def _down_vrf_dev(self, ifaceobj, vrf_table, ifaceobj_getfunc=None):
 
+        if not self.ipcmd.link_exists(ifaceobj.name):
+            return
+
         if vrf_table == 'auto':
             vrf_table = self._get_iproute2_vrf_table(ifaceobj.name)
 
@@ -823,12 +851,16 @@ class vrf(moduleBase):
             self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
             pass
 
+        ifindex = self.ipcmd.link_get_ifindex(ifaceobj.name)
+
         try:
             self.ipcmd.link_delete(ifaceobj.name)
         except Exception, e:
             self.logger.info('%s: %s' %(ifaceobj.name, str(e)))
             pass
 
+        self._close_sockets(ifaceobj, ifindex)
+
         try:
             self._iproute2_vrf_table_entry_del(vrf_table)
         except Exception, e:
@@ -839,8 +871,13 @@ class vrf(moduleBase):
     def _down_vrf_slave(self, ifacename, ifaceobj=None, vrfname=None):
         try:
             self._handle_existing_connections(ifaceobj, vrfname)
-            self.ipcmd.link_set(ifacename, 'nomaster')
-            netlink.link_set_updown(ifacename, "down")
+            netlink.link_set_nomaster(ifacename)
+            # Down this slave only if it is a slave ifupdown2 manages.
+            # we dont want to down slaves that maybe up'ed by
+            # somebody else. One such example is a macvlan device
+            # which ifupdown2 addressvirtual addon module auto creates
+            if ifaceobj:
+                netlink.link_set_updown(ifacename, "down")
         except Exception, e:
             self.logger.warn('%s: %s' %(ifacename, str(e)))
 
@@ -937,7 +974,9 @@ class vrf(moduleBase):
                     if running_table:
                         ifaceobjrunning.update_config('vrf-table',
                                                       running_table)
-            elif kind == 'vrf_slave':
+                        return
+            slave_kind = self.ipcmd.link_get_slave_kind(ifaceobjrunning.name)
+            if slave_kind == 'vrf_slave':
                 vrf = self.ipcmd.link_get_master(ifaceobjrunning.name)
                 if vrf:
                     ifaceobjrunning.update_config('vrf', vrf)