Ejemplo n.º 1
0
    def load_netlink(self, msg):
        with self._direct_state:
            if self['ipdb_scope'] == 'locked':
                # do not touch locked interfaces
                return

            self['ipdb_scope'] = 'system'
            for (key, value) in msg.items():
                self[key] = value

            # merge NLA
            for cell in msg['attrs']:
                #
                # Parse on demand
                #
                norm = fibmsg.nla2name(cell[0])
                if norm in self.cleanup:
                    continue
                self[norm] = cell[1]

            if msg.get_attr('FRA_DST'):
                dst = '%s/%s' % (msg.get_attr('FRA_DST'),
                                 msg['dst_len'])
                self['dst'] = dst
            if msg.get_attr('FRA_SRC'):
                src = '%s/%s' % (msg.get_attr('FRA_SRC'),
                                 msg['src_len'])
                self['src'] = src

            # finally, cleanup all not needed
            for item in self.cleanup:
                if item in self:
                    del self[item]
        return self
Ejemplo n.º 2
0
class Rule(Transactional):
    '''
    Persistent transactional rule object
    '''

    _fields = [fibmsg.nla2name(i[1]) for i in fibmsg.nla_map]
    for key, _ in fibmsg.fields:
        _fields.append(key)
    _fields.append('removal')
    _virtual_fields = ['ipdb_scope', 'ipdb_priority']
    _fields.extend(_virtual_fields)
    cleanup = ('attrs',
               'header',
               'event',
               'src_len',
               'dst_len',
               'res1',
               'res2')

    @classmethod
    def make_key(cls, msg):
        values = []
        if isinstance(msg, fibmsg):
            for field in RuleKey._fields:
                v = msg.get_attr(msg.name2nla(field))
                if v is None:
                    v = msg.get(field, 0)
                values.append(v)
        elif isinstance(msg, dict):
            for field in RuleKey._fields:
                values.append(msg.get(field, 0))
        else:
            raise TypeError('prime not supported: %s' % type(msg))
        return RuleKey(*values)

    def __init__(self, ipdb, mode=None, parent=None, uid=None):
        Transactional.__init__(self, ipdb, mode, parent, uid)
        with self._direct_state:
            self['ipdb_priority'] = 0

    def load_netlink(self, msg):
        with self._direct_state:
            if self['ipdb_scope'] == 'locked':
                # do not touch locked interfaces
                return

            self['ipdb_scope'] = 'system'
            for (key, value) in msg.items():
                self[key] = value

            # merge NLA
            for cell in msg['attrs']:
                #
                # Parse on demand
                #
                norm = fibmsg.nla2name(cell[0])
                if norm in self.cleanup:
                    continue
                self[norm] = cell[1]

            if msg.get_attr('FRA_DST'):
                dst = '%s/%s' % (msg.get_attr('FRA_DST'),
                                 msg['dst_len'])
                self['dst'] = dst
            if msg.get_attr('FRA_SRC'):
                src = '%s/%s' % (msg.get_attr('FRA_SRC'),
                                 msg['src_len'])
                self['src'] = src

            # finally, cleanup all not needed
            for item in self.cleanup:
                if item in self:
                    del self[item]
        return self

    def commit(self,
               tid=None,
               transaction=None,
               commit_phase=1,
               commit_mask=0xff):

        if not commit_phase & commit_mask:
            return self

        error = None
        drop = self.ipdb.txdrop
        devop = 'set'
        debug = {'traceback': None,
                 'next_stage': None}
        notx = True

        if tid or transaction:
            notx = False
        if tid:
            transaction = self.global_tx[tid]
        else:
            transaction = transaction or self.current_tx

        # create a new route
        if self['ipdb_scope'] != 'system':
            devop = 'add'

        # work on an existing route
        snapshot = self.pick()
        added, removed = transaction // snapshot
        added.pop('ipdb_scope', None)
        removed.pop('ipdb_scope', None)

        try:
            # rule add/set
            if any(added.values()) or devop == 'add':

                old_key = self.make_key(self)
                new_key = self.make_key(transaction)

                if new_key != old_key:
                    # check for the key conflict
                    if new_key in self.ipdb.rules:
                        raise CommitException('rule priority conflict')
                    else:
                        self.ipdb.rules[new_key] = self
                        self.nl.rule('del', **old_key._asdict())
                        self.nl.rule('add', **transaction)
                else:
                    if devop != 'add':
                        with self._direct_state:
                            self['ipdb_scope'] = 'locked'
                        wd = self.ipdb.watchdog('RTM_DELRULE',
                                                **old_key._asdict())
                        self.nl.rule('del', **old_key._asdict())
                        wd.wait()
                        with self._direct_state:
                            self['ipdb_scope'] = 'reload'
                    self.nl.rule('add', **transaction)
                transaction.wait_all_targets()
            # rule removal
            if (transaction['ipdb_scope'] in ('shadow', 'remove')) or\
                    ((transaction['ipdb_scope'] == 'create') and
                     commit_phase == 2):
                if transaction['ipdb_scope'] == 'shadow':
                    with self._direct_state:
                        self['ipdb_scope'] = 'locked'
                # create watchdog
                key = self.make_key(snapshot)
                wd = self.ipdb.watchdog('RTM_DELRULE', **key._asdict())
                self.nl.rule('del', **key._asdict())
                wd.wait()
                if transaction['ipdb_scope'] == 'shadow':
                    with self._direct_state:
                        self['ipdb_scope'] = 'shadow'
            # everything ok
            drop = True

        except Exception as e:

            error = e
            # prepare postmortem
            debug['traceback'] = traceback.format_exc()
            debug['error_stack'] = []
            debug['next_stage'] = None

            if commit_phase == 1:
                try:
                    self.commit(transaction=snapshot,
                                commit_phase=2,
                                commit_mask=commit_mask)
                except Exception as i_e:
                    debug['next_stage'] = i_e
                    error = RuntimeError()

        if drop and notx:
            self.drop(transaction.uid)

        if error is not None:
            error.debug = debug
            raise error

        return self

    def remove(self):
        self['ipdb_scope'] = 'remove'
        return self

    def shadow(self):
        self['ipdb_scope'] = 'shadow'
        return self