Exemple #1
0
    def apply(self, do_apply):
        excpts = ExceptionCollector(self.settings['ifname'])
        osettings = copy.deepcopy(self.settings)

        # lookup for attributes requiring a interface index
        for attr in self.attr_idx:
            if attr in self.settings:
                self.settings[attr] = next(
                    iter(ipr.link_lookup(ifname=self.settings[attr])),
                    self.settings[attr])

        if self.idx is None:
            self.idx = next(
                iter(ipr.link_lookup(ifname=self.settings['ifname'])), None)

        if self.idx is not None:
            self.iface = next(iter(ipr.get_links(self.idx)), None)
            permaddr = ipr.get_permaddr(self.iface.get_attr('IFLA_IFNAME'))
            if not permaddr is None:
                self.iface['permaddr'] = permaddr
            businfo = ipr.get_businfo(self.iface.get_attr('IFLA_IFNAME'))
            if not businfo is None:
                self.iface['businfo'] = businfo

            # check for ifname collisions
            idx = next(iter(ipr.link_lookup(ifname=self.settings['ifname'])),
                       None)
            if idx is not None and idx != self.idx and do_apply:
                try:
                    ipr.link('set', index=idx, state='down')
                    ipr.link('set',
                             index=idx,
                             ifname='{}!'.format(self.settings['ifname']))
                except Exception as err:
                    if not isinstance(err, netlinkerror_classes):
                        raise
                    excpts.add('set', err, state='down', ifname='{}!')

            if self.cap_create and self.get_if_attr(
                    'kind') != self.settings['kind']:
                self.recreate(do_apply, excpts)
            else:
                excpts.set_quiet(self.cap_create)
                self.update(do_apply, excpts)
                if self.cap_create and excpts.get_all():
                    excpts.reset()
                    self.recreate(do_apply, excpts)
        else:
            self.create(do_apply, excpts)

        self.settings = osettings
        return excpts
Exemple #2
0
    def __init__(self, name, link, ethtool, vrrp):
        self.cap_create = True
        self.cap_ethtool = False
        self.settings = {
            'ifname': name,
        }
        self.settings.update(link)
        self.ethtool = None
        self.vrrp = vrrp
        self.attr_map = {
            'kind': ['IFLA_LINKINFO', 'IFLA_INFO_KIND'],
        }
        self.attr_idx = [
            'link', 'master', 'gre_link', 'ip6gre_link', 'vxlan_link',
            'xfrm_link'
        ]
        self.idx = None

        if 'address' in self.settings:
            self.settings['address'] = self.settings['address'].lower()
            self.idx = next(
                iter(ipr.link_lookup(address=self.settings['address'])), None)
        if 'permaddr' in self.settings:
            self.settings['permaddr'] = self.settings['permaddr'].lower()
            self.idx = ipr.get_iface_by_permaddr(self.settings['permaddr'])
        if 'businfo' in self.settings:
            self.settings['businfo'] = self.settings['businfo'].lower()
            self.idx = ipr.get_iface_by_businfo(self.settings['businfo'])

        for attr, mappings in self.attr_value_maps.items():
            if attr in self.settings and type(self.settings[attr]) != int:
                self.settings[attr] = next(
                    (k
                     for k, v in mappings.items() if v == self.settings[attr]),
                    self.settings[attr])
Exemple #3
0
    def create(self, do_apply, excpts, oper="add"):
        logger.info(oper,
                    extra={
                        'iface': self.settings['ifname'],
                        'style': IfStateLogging.STYLE_CHG
                    })

        logger.debug("ip link add: {}".format(" ".join(
            "{}={}".format(k, v) for k, v in self.settings.items())))
        if do_apply:
            try:
                state = self.settings.pop('state', None)
                ipr.link('add', **(self.settings))
                self.idx = next(
                    iter(ipr.link_lookup(ifname=self.settings['ifname'])),
                    None)
                if not state is None and not self.idx is None:
                    try:
                        ipr.link('set', index=self.idx, state=state)
                    except Exception as err:
                        if not isinstance(err, netlinkerror_classes):
                            raise
                        excpts.add('set', err, state=state)
            except Exception as err:
                if not isinstance(err, netlinkerror_classes):
                    raise
                excpts.add('add', err, **(self.settings))

        if not self.ethtool is None:
            logger.debug("ethtool: {}".format(self.ethtool))
            self.set_ethtool_state(self.settings['ifname'],
                                   self.ethtool.keys(), do_apply)
Exemple #4
0
    def apply(self, do_apply):
        excpts = ExceptionCollector(ifname=self.iface)

        # get ifindex
        self.idx = next(iter(ipr.link_lookup(ifname=self.iface)), None)

        if self.idx == None:
            logger.warning('link missing', extra={'iface': self.iface})
            return

        changes = []
        ipr_qdiscs = None

        # apply ingress qdics
        if "ingress" in self.tc:
            ipr_qdiscs = ipr.get_qdiscs(index=self.idx)
            if self.apply_ingress(self.tc["ingress"],
                                  self.get_qdisc(
                                      ipr_qdiscs, TC.INGRESS_PARENT),
                                  excpts,
                                  do_apply):
                changes.append("ingress")

        # apply qdisc tree
        if "qdisc" in self.tc:
            if ipr_qdiscs is None:
                ipr_qdiscs = ipr.get_qdiscs(index=self.idx)
            logger.debug('checking qdisc tree', extra={'iface': self.iface})
            if self.apply_qtree(
                    self.tc["qdisc"],
                    self.get_qdisc(ipr_qdiscs, TC.ROOT_HANDLE),
                    ipr_qdiscs,
                    TC.ROOT_HANDLE,
                    excpts,
                    do_apply):
                changes.append("qdisc")

        # apply filters
        if "filter" in self.tc:
            ipr_filters = ipr.get_filters(
                index=self.idx) + ipr.get_filters(index=self.idx, parent=TC.INGRESS_HANDLE)
            logger.debug('checking filters', extra={'iface': self.iface})
            if self.apply_filter(
                    self.tc["filter"],
                    ipr_filters,
                    excpts,
                    do_apply):
                changes.append("filter")

        if len(changes) > 0:
            logger.info(
                'change ({})'.format(", ".join(changes)),
                extra={'iface': self.iface, 'style': IfStateLogging.STYLE_CHG})
        else:
            logger.info(
                'ok',
                extra={'iface': self.iface, 'style': IfStateLogging.STYLE_OK})

        return excpts
Exemple #5
0
    def apply(self, do_apply):
        logger.debug('getting neighbours', extra={'iface': self.iface})

        # get ifindex
        idx = next(iter(ipr.link_lookup(ifname=self.iface)), None)

        if idx == None:
            logger.warning('link missing', extra={'iface': self.iface})
            return

        # get neighbour entries (only NUD_PERMANENT)
        ipr_neigh = {}
        neigh_add = {}
        for neigh in ipr.get_neighbours(ifindex=idx, state=128):
            ip = ip_address(neigh.get_attr('NDA_DST'))
            ipr_neigh[ip] = neigh.get_attr('NDA_LLADDR')

        for ip, lladdr in self.neighbours.items():
            if ip in ipr_neigh and lladdr == ipr_neigh[ip]:
                logger.info(' %s', ip, extra={
                            'iface': self.iface, 'style': IfStateLogging.STYLE_OK})
                del ipr_neigh[ip]
            else:
                neigh_add[ip] = lladdr

        for ip, lladdr in ipr_neigh.items():
            logger.info(
                '-%s', str(ip), extra={'iface': self.iface, 'style': IfStateLogging.STYLE_DEL})
            try:
                if do_apply:
                    ipr.neigh("del", ifindex=idx, dst=str(
                        ip))
            except Exception as err:
                if not isinstance(err, netlinkerror_classes):
                    raise
                logger.warning('removing neighbour {} failed: {}'.format(
                    str(ip), err.args[1]))

        for ip, lladdr in neigh_add.items():
            logger.info('+%s', str(ip),
                        extra={'iface': self.iface, 'style': IfStateLogging.STYLE_CHG})
            if do_apply:
                try:
                    opts = {
                        'ifindex': idx,
                        'dst': str(ip),
                        'lladdr': lladdr,
                        'state': 128
                    }

                    ipr.neigh('replace', **opts)
                except Exception as err:
                    if not isinstance(err, netlinkerror_classes):
                        raise
                    logger.warning('adding neighbour {} failed: {}'.format(
                        str(ip), err.args[1]))
Exemple #6
0
    def apply_filter(self, tc, ipr_filters, excpts, do_apply):
        tc_filters = {}
        # assign prio numbers if missing
        for i in range(len(tc)):
            if not "prio" in tc[i]:
                tc[i]["prio"] = 0xc001 - len(tc) + i

            parent = TC.handle2int(tc[i].get("parent", 0))
            if not parent in tc_filters:
                tc_filters[parent] = {}

            tc_filters[parent][tc[i]["prio"]] = tc[i]

        changes = False
        # remove unreferenced filters
        removed = {}
        for ipr_filter in ipr_filters:
            prio = ipr_filter["info"] >> 16

            parent = TC.handle2int(ipr_filter.get("parent", 0))
            rm = not parent in tc_filters
            rm |= parent in tc_filters and \
                prio not in tc_filters[parent]
            if rm and prio not in removed.get(parent, []):
                changes = True
                if not parent in removed:
                    removed[parent] = []
                removed[parent].append(prio)
                if do_apply:
                    opts = {
                        "index": self.idx,
                        "info": ipr_filter["info"],
                        "parent": parent,
                    }
                    try:
                        ipr.del_filter_by_info(**opts)
                    except Exception as err:
                        if not isinstance(err, netlinkerror_classes):
                            raise
                        logger.warning('deleting filter #{} on {} failed: {}'.format(
                            prio, self.iface, err.args[1]))
                        excpts.add('del', err, **opts)

        if do_apply:
            for parent in tc_filters.keys():
                for tc_filter in tc_filters[parent].values():
                    tc_filter['index'] = self.idx
                    if "action" in tc_filter:
                        for action in tc_filter["action"]:
                            if action["kind"] == "mirred":
                                # get ifindex
                                action["ifindex"] = next(
                                    iter(ipr.link_lookup(ifname=action["dev"])), None)

                                if self.idx == None:
                                    logger.warning("filter #{} references unknown interface {}".format(
                                        tc_filter["prio"], action["dev"]), extra={'iface': self.iface})
                                    continue
                    if "parent" in tc_filter:
                        tc_filter["parent"] = TC.handle2int(tc_filter["parent"])
                    try:
                        try:
                            ipr.tc("replace-filter", **tc_filter)
                            # replace seems only to work if there is no filter
                            # => something has changed
                            changes = True
                        except Exception as err:
                            if not isinstance(err, netlinkerror_classes):
                                raise
                            # replace does not work, supress changes result
                            # for now
                            #changes = True
                            opts = {
                                "index": self.idx,
                                "info": tc_filter["prio"] << 16,
                                "parent": parent,
                            }
                            ipr.del_filter_by_info(**opts)
                            ipr.tc("add-filter", **tc_filter)

                    except Exception as err:
                        if not isinstance(err, netlinkerror_classes):
                            raise
                        logger.warning('replace filter #{} on {} failed: {}'.format(
                            tc_filter['prio'], self.iface, err.args[1]))
                        excpts.add('replace', err, **tc_filter)

        return changes
Exemple #7
0
    def apply(self, ignore, ign_dynamic, do_apply):
        logger.debug('getting addresses', extra={'iface': self.iface})

        # get ifindex
        idx = next(iter(ipr.link_lookup(ifname=self.iface)), None)

        if idx == None:
            logger.warning('link missing', extra={'iface': self.iface})
            return

        # get active ip addresses
        ipr_addr = {}
        addr_add = []
        for addr in ipr.get_addr(index=idx):
            ip = ip_interface(
                addr.get_attr('IFA_ADDRESS') + '/' + str(addr['prefixlen']))
            ipr_addr[ip] = addr

        for addr in self.addresses:
            if addr in ipr_addr:
                logger.info(' %s',
                            addr.with_prefixlen,
                            extra={
                                'iface': self.iface,
                                'style': IfStateLogging.STYLE_OK
                            })
                del ipr_addr[addr]
            else:
                addr_add.append(addr)

        for ip, addr in ipr_addr.items():
            if not any(ip in net for net in ignore):
                if not ign_dynamic or ipr_addr[ip][
                        'flags'] & IFA_F_PERMANENT == IFA_F_PERMANENT:
                    logger.info('-%s',
                                ip.with_prefixlen,
                                extra={
                                    'iface': self.iface,
                                    'style': IfStateLogging.STYLE_DEL
                                })
                    try:
                        if do_apply:
                            ipr.addr("del",
                                     index=idx,
                                     address=str(ip.ip),
                                     mask=ip.network.prefixlen)
                    except Exception as err:
                        if not isinstance(err, netlinkerror_classes):
                            raise
                        logger.warning('removing ip {}/{} failed: {}'.format(
                            str(ip.ip), ip.network.prefixlen, err.args[1]))

        for addr in addr_add:
            logger.info('+%s',
                        addr.with_prefixlen,
                        extra={
                            'iface': self.iface,
                            'style': IfStateLogging.STYLE_CHG
                        })
            if do_apply:
                try:
                    ipr.addr("add",
                             index=idx,
                             address=str(addr.ip),
                             mask=addr.network.prefixlen)
                except Exception as err:
                    if not isinstance(err, netlinkerror_classes):
                        raise
                    logger.warning('adding ip {}/{} failed: {}'.format(
                        str(addr.ip), addr.network.prefixlen, err.args[1]))
Exemple #8
0
    def apply(self, ignores, do_apply):
        for table, croutes in self.tables.items():
            pfx = RTLookups.tables.lookup_str(table)
            logger.info('\nconfiguring routing table {}...'.format(pfx))

            kroutes = self.kernel_routes(table)

            for route in croutes:
                if 'oif' in route and type(route['oif']) == str:
                    route['oif'] = next(
                        iter(ipr.link_lookup(ifname=route['oif'])), None)
                found = False
                identical = False
                for i, kroute in enumerate(kroutes):
                    if route_matches(route, kroute):
                        del kroutes[i]
                        found = True
                        if route_matches(route,
                                         kroute,
                                         route.keys(),
                                         indent=route['dst']):
                            identical = True
                            break

                if identical:
                    logger.info('ok',
                                extra={
                                    'iface': route['dst'],
                                    'style': IfStateLogging.STYLE_OK
                                })
                else:
                    if found:
                        logger.info('change',
                                    extra={
                                        'iface': route['dst'],
                                        'style': IfStateLogging.STYLE_CHG
                                    })
                    else:
                        logger.info('add',
                                    extra={
                                        'iface': route['dst'],
                                        'style': IfStateLogging.STYLE_CHG
                                    })

                    logger.debug("ip route replace: {}".format(" ".join(
                        "{}={}".format(k, v) for k, v in route.items())))
                    try:
                        if do_apply:
                            ipr.route('replace', **route)
                    except Exception as err:
                        if not isinstance(err, netlinkerror_classes):
                            raise
                        logger.warning('route setup {} failed: {}'.format(
                            route['dst'], err.args[1]))

            for route in kroutes:
                ignore = False
                for iroute in ignores:
                    if route_matches(route, iroute, iroute.keys()):
                        ignore = True
                        break
                if ignore:
                    continue

                logger.info('del',
                            extra={
                                'iface': route['dst'],
                                'style': IfStateLogging.STYLE_DEL
                            })
                try:
                    if do_apply:
                        ipr.route('del', **route)
                except Exception as err:
                    if not isinstance(err, netlinkerror_classes):
                        raise
                    logger.warning('removing route {} failed: {}'.format(
                        route['dst'], err.args[1]))