Exemplo n.º 1
0
    def __init__(self, *args, **kargs):
        Addon.__init__(self)
        moduleBase.__init__(self, *args, **kargs)
        self._bridge_fdb_query_cache = {}
        self.addressvirtual_with_route_metric = utils.get_boolean_from_string(
            policymanager.policymanager_api.get_module_globals(
                module_name=self.__class__.__name__,
                attr='addressvirtual_with_route_metric'
            ),
            default=True
        )

        self.address_virtual_ipv6_addrgen_value_dict = {'on': 0, 'yes': 0, '0': 0, 'off': 1, 'no': 1, '1': 1}

        if addressvirtual.ADDR_METRIC_SUPPORT is None:
            try:
                cmd = [utils.ip_cmd, 'addr', 'help']
                self.logger.info('executing %s addr help' % utils.ip_cmd)

                process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                stdout, stderr = process.communicate()
                addressvirtual.ADDR_METRIC_SUPPORT = '[ metric METRIC ]' in stderr.decode() or ''
                self.logger.info('address metric support: %s' % ('OK' if addressvirtual.ADDR_METRIC_SUPPORT else 'KO'))
            except Exception:
                addressvirtual.ADDR_METRIC_SUPPORT = False
                self.logger.info('address metric support: KO')
Exemplo n.º 2
0
    def _query_check_link_down(self, ifaceobj, ifaceobjcurr):
        link_down = ifaceobj.get_attr_value_first('link-down')

        if link_down:
            link_should_be_down = utils.get_boolean_from_string(link_down)
        else:
            link_should_be_down = False

        link_up = self.cache.link_is_up(ifaceobj.name)

        if not link_up and not link_should_be_down and not link_down:
            ifaceobjcurr.status_str = 'link is down'
            ifaceobjcurr.status = ifaceStatus.ERROR
        elif link_down:
            if link_should_be_down and link_up:
                status = 1
                link_down = 'no'
            elif link_should_be_down and not link_up:
                status = 0
            elif not link_should_be_down and link_up:
                status = 0
            else:
                status = 1

            ifaceobjcurr.update_config_with_status('link-down', link_down, status)
Exemplo n.º 3
0
    def __init__(self, *args, **kargs):
        Addon.__init__(self)
        moduleBase.__init__(self, *args, **kargs)

        self.check_physical_port_existance = utils.get_boolean_from_string(
            policymanager.policymanager_api.get_module_globals(
                self.__class__.__name__, 'warn_on_physdev_not_present'))
Exemplo n.º 4
0
    def _query_check(self, ifaceobj, ifaceobjcurr):
        if ifaceobj.get_attr_value('link-type'):
            if not self.cache.link_exists(ifaceobj.name):
                ifaceobjcurr.update_config_with_status('link-type', 'None', 1)
            else:
                link_type = ifaceobj.get_attr_value_first('link-type')
                if self.cache.get_link_kind(ifaceobj.name) == link_type:
                    ifaceobjcurr.update_config_with_status(
                        'link-type', link_type, 0)
                else:
                    ifaceobjcurr.update_config_with_status(
                        'link-type', link_type, 1)

        link_down = ifaceobj.get_attr_value_first('link-down')
        if link_down:
            link_up = self.cache.link_is_up(ifaceobj.name)
            link_should_be_down = utils.get_boolean_from_string(link_down)

            if link_should_be_down and link_up:
                status = 1
                link_down = 'no'
            elif link_should_be_down and not link_up:
                status = 0
            elif not link_should_be_down and link_up:
                status = 0
            else:
                status = 1

            ifaceobjcurr.update_config_with_status('link-down', link_down,
                                                   status)
Exemplo n.º 5
0
 def __get_vlxan_purge_remotes(self, ifaceobj):
     if not ifaceobj:
         return self._vxlan_purge_remotes
     purge_remotes = ifaceobj.get_attr_value_first('vxlan-purge-remotes')
     if purge_remotes:
         purge_remotes = utils.get_boolean_from_string(purge_remotes)
     else:
         purge_remotes = self._vxlan_purge_remotes
     return purge_remotes
Exemplo n.º 6
0
    def __config_vxlan_learning(self, ifaceobj, link_exists, user_request_vxlan_info_data, cached_vxlan_ifla_info_data):
        if not link_exists or not ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT:
            vxlan_learning = ifaceobj.get_attr_value_first('vxlan-learning')
            if not vxlan_learning:
                vxlan_learning = self.get_attr_default_value('vxlan-learning')
            vxlan_learning = utils.get_boolean_from_string(vxlan_learning)
        else:
            vxlan_learning = cached_vxlan_ifla_info_data.get(Link.IFLA_VXLAN_LEARNING)

        if vxlan_learning != cached_vxlan_ifla_info_data.get(Link.IFLA_VXLAN_LEARNING):
            self.logger.info("%s: set vxlan-learning %s" % (ifaceobj.name, "on" if vxlan_learning else "off"))
            user_request_vxlan_info_data[Link.IFLA_VXLAN_LEARNING] = vxlan_learning
    def _query_check(self, ifaceobj, ifaceobjcurr):

        if not self.cache.link_exists(ifaceobj.name):
            return

        user_config_address_virtual_ipv6_addr = ifaceobj.get_attr_value_first(
            'address-virtual-ipv6-addrgen')
        if user_config_address_virtual_ipv6_addr and user_config_address_virtual_ipv6_addr not in utils._string_values:
            ifaceobjcurr.update_config_with_status(
                'address-virtual-ipv6-addrgen',
                user_config_address_virtual_ipv6_addr, 1)
            user_config_address_virtual_ipv6_addr = None

        address_virtual_list = ifaceobj.get_attr_value('address-virtual')

        macvlans_running_ipv6_addr_virtual = self.query_check_macvlan_config(
            ifaceobj,
            ifaceobjcurr,
            "address-virtual",
            user_config_address_virtual_ipv6_addr,
            virtual_addr_list_raw=address_virtual_list,
            macvlan_config_list=self.translate_addrvirtual_user_config_to_list(
                ifaceobj, address_virtual_list))

        vrr_config_list = ifaceobj.get_attr_value("vrrp")

        macvlans_running_ipv6_addr_vrr = self.query_check_macvlan_config(
            ifaceobj,
            ifaceobjcurr,
            "vrrp",
            user_config_address_virtual_ipv6_addr,
            virtual_addr_list_raw=vrr_config_list,
            macvlan_config_list=self.translate_vrr_user_config_to_list(
                ifaceobj, vrr_config_list, ifquery=True))

        macvlans_running_ipv6_addr = macvlans_running_ipv6_addr_virtual + macvlans_running_ipv6_addr_vrr
        if user_config_address_virtual_ipv6_addr:
            bool_user_ipv6_addrgen = utils.get_boolean_from_string(
                user_config_address_virtual_ipv6_addr)
            for running_ipv6_addrgen in macvlans_running_ipv6_addr:
                if (not bool_user_ipv6_addrgen) != running_ipv6_addrgen:
                    ifaceobjcurr.update_config_with_status(
                        'address-virtual-ipv6-addrgen',
                        user_config_address_virtual_ipv6_addr, 1)
                    return
            ifaceobjcurr.update_config_with_status(
                'address-virtual-ipv6-addrgen',
                user_config_address_virtual_ipv6_addr, 0)
Exemplo n.º 8
0
    def __init__(self, *args, **kargs):
        Addon.__init__(self)
        moduleBase.__init__(self, *args, **kargs)

        self._vxlan_purge_remotes = utils.get_boolean_from_string(
            policymanager.policymanager_api.get_module_globals(
                module_name=self.__class__.__name__,
                attr="vxlan-purge-remotes"))
        self._vxlan_local_tunnelip = None
        self._clagd_vxlan_anycast_ip = ""

        # If mcastgrp is specified we need to rely on a user-configred device (via physdev)
        # or via a policy variable "vxlan-physdev_mcastgrp". If the device doesn't exist we
        # create it as a dummy device. We need to keep track of the user configuration to
        # know when to delete this dummy device (when user remove mcastgrp from it's config)
        self.vxlan_mcastgrp_ref = False
        self.vxlan_physdev_mcast = policymanager.policymanager_api.get_module_globals(
            module_name=self.__class__.__name__, attr="vxlan-physdev-mcastgrp"
        ) or self.VXLAN_PHYSDEV_MCASTGRP_DEFAULT
Exemplo n.º 9
0
    def link_add_single_vxlan(self,
                              link_exists,
                              ifname,
                              ip,
                              group,
                              physdev,
                              port,
                              vnifilter="off",
                              ttl=None):
        self.logger.info("creating single vxlan device: %s" % ifname)

        if link_exists:
            # When updating an SVD we need to use `ip link set` and we have to
            # drop the external keyword:
            # $ ip link set dev vxlan0 type vxlan external local 27.0.0.242 dev ipmr-lo
            # Error: vxlan: cannot change COLLECT_METADATA flag.
            cmd = ["link set dev %s type vxlan" % ifname]
        else:
            cmd = ["link add dev %s type vxlan external" % ifname]

            # when changing local ip, if we specify vnifilter we get:
            # Error: vxlan: cannot change flag.
            # So we are only setting this attribute on vxlan creation
            if vnifilter and utils.get_boolean_from_string(vnifilter):
                cmd.append("vnifilter")

        if ip:
            cmd.append("local %s" % ip)

        if physdev:
            cmd.append("dev %s" % physdev)

        if group:
            cmd.append("group %s" % group)

        if port:
            cmd.append("dstport %s" % port)

        if ttl:
            cmd.append("ttl %s" % ttl)

        self.__execute_or_batch(utils.ip_cmd, " ".join(cmd))
        self.__update_cache_after_link_creation(ifname, "vxlan")
Exemplo n.º 10
0
    def __init__(self, *args, **kargs):
        Addon.__init__(self)
        moduleBase.__init__(self, *args, **kargs)

        if not os.path.exists('/sys/class/net/bonding_masters'):
            try:
                utils.exec_command('modprobe -q bonding')
            except Exception as e:
                self.logger.info(
                    "bond: error while loading bonding module: %s" % str(e))

        self._bond_attr_ifquery_check_translate_func[
            Link.IFLA_BOND_PRIMARY] = self.cache.get_ifindex
        self._bond_attr_set_list = self._bond_attr_set_list + (
            ('bond-primary', Link.IFLA_BOND_PRIMARY, self.cache.get_ifindex), )

        self.bond_mac_mgmt = utils.get_boolean_from_string(
            policymanager.policymanager_api.get_module_globals(
                module_name=self.__class__.__name__, attr="bond_mac_mgmt"),
            True)
Exemplo n.º 11
0
    def _query_check(self, ifaceobj, ifaceobjcurr):
        ifname = ifaceobj.name

        if not self.cache.link_exists(ifname):
            return

        cached_vxlan_ifla_info_data = self.cache.get_link_info_data(ifname)

        if not cached_vxlan_ifla_info_data:
            ifaceobjcurr.check_n_update_config_with_status_many(
                ifaceobj, self.get_mod_attrs(), -1)
            return

        for vxlan_attr_str, vxlan_attr_nl, callable_type in (
            ('vxlan-id', Link.IFLA_VXLAN_ID, int),
            ('vxlan-ttl', Link.IFLA_VXLAN_TTL, int),
            ('vxlan-port', Link.IFLA_VXLAN_PORT, int),
            ('vxlan-ageing', Link.IFLA_VXLAN_AGEING, int),
            ('vxlan-mcastgrp', Link.IFLA_VXLAN_GROUP, ipnetwork.IPv4Address),
            ('vxlan-svcnodeip', Link.IFLA_VXLAN_GROUP, ipnetwork.IPv4Address),
            ('vxlan-physdev', Link.IFLA_VXLAN_LINK,
             lambda x: self.cache.get_ifindex(x)),
            ('vxlan-learning', Link.IFLA_VXLAN_LEARNING,
             lambda boolean_str: utils.get_boolean_from_string(boolean_str)),
        ):
            vxlan_attr_value = ifaceobj.get_attr_value_first(vxlan_attr_str)

            if not vxlan_attr_value:
                continue

            cached_vxlan_attr_value = cached_vxlan_ifla_info_data.get(
                vxlan_attr_nl)

            try:
                vxlan_attr_value_nl = callable_type(vxlan_attr_value)
            except Exception as e:
                self.logger.warning('%s: %s: %s' %
                                    (ifname, vxlan_attr_str, str(e)))
                ifaceobjcurr.update_config_with_status(
                    vxlan_attr_str, cached_vxlan_attr_value or 'None', 1)
                continue

            if vxlan_attr_value_nl == cached_vxlan_attr_value:
                ifaceobjcurr.update_config_with_status(vxlan_attr_str,
                                                       vxlan_attr_value, 0)
            else:
                ifaceobjcurr.update_config_with_status(
                    vxlan_attr_str, cached_vxlan_attr_value or 'None', 1)

        #
        # vxlan-local-tunnelip
        #
        running_attrval = cached_vxlan_ifla_info_data.get(
            Link.IFLA_VXLAN_LOCAL)
        attrval = ifaceobj.get_attr_value_first('vxlan-local-tunnelip')
        if not attrval:
            attrval = self._vxlan_local_tunnelip
            # TODO: vxlan._vxlan_local_tunnelip should be a ipnetwork.IPNetwork obj
            ifaceobj.update_config('vxlan-local-tunnelip', attrval)

        if str(running_attrval) == self._clagd_vxlan_anycast_ip:
            # if local ip is anycast_ip, then let query_check to go through
            attrval = self._clagd_vxlan_anycast_ip

        self._query_check_n_update(
            ifaceobj, ifaceobjcurr, 'vxlan-local-tunnelip', str(attrval),
            str(running_attrval.ip) if running_attrval else None)

        #
        # vxlan-remoteip
        #
        purge_remotes = self.__get_vlxan_purge_remotes(ifaceobj)
        if purge_remotes or ifaceobj.get_attr_value('vxlan-remoteip'):
            # If purge remotes or if vxlan-remoteip's are set
            # in the config file, we are owners of the installed
            # remote-ip's, lets check and report any remote ips we don't
            # understand
            cached_svcnode = cached_vxlan_ifla_info_data.get(
                Link.IFLA_VXLAN_GROUP)

            self._query_check_n_update_addresses(
                ifaceobjcurr, 'vxlan-remoteip',
                ifaceobj.get_attr_value('vxlan-remoteip'),
                self.iproute2.get_vxlan_peers(
                    ifaceobj.name,
                    str(cached_svcnode.ip) if cached_svcnode else None))
Exemplo n.º 12
0
class bond(Addon, moduleBase):
    """  ifupdown2 addon module to configure bond interfaces """

    overrides_ifupdown_scripts = ['ifenslave', ]

    _modinfo = {
        "mhelp": "bond configuration module",
        "attrs": {
            "bond-use-carrier": {
                "help": "bond use carrier",
                "validvals": ["yes", "no", "0", "1"],
                "default": "yes",
                "example": ["bond-use-carrier yes"]},
            "bond-num-grat-arp": {
                "help": "bond use carrier",
                "validrange": ["0", "255"],
                "default": "1",
                "example": ["bond-num-grat-arp 1"]
            },
            "bond-num-unsol-na": {
                "help": "bond slave devices",
                "validrange": ["0", "255"],
                "default": "1",
                "example": ["bond-num-unsol-na 1"]
            },
            "bond-xmit-hash-policy": {
                "help": "bond slave devices",
                "validvals": [
                    "0", "layer2",
                    "1", "layer3+4",
                    "2", "layer2+3",
                    "3", "encap2+3",
                    "4", "encap3+4"
                ],
                "default": "layer2",
                "example": ["bond-xmit-hash-policy layer2"]
            },
            "bond-miimon": {
                "help": "bond miimon",
                "validrange": ["0", "255"],
                "default": "0",
                "example": ["bond-miimon 0"]
            },
            "bond-mode": {
                "help": "bond mode",
                "validvals": [
                    "0", "balance-rr",
                    "1", "active-backup",
                    "2", "balance-xor",
                    "3", "broadcast",
                    "4", "802.3ad",
                    "5", "balance-tlb",
                    "6", "balance-alb"
                ],
                "default": "balance-rr",
                "example": ["bond-mode 802.3ad"]
            },
            "bond-lacp-rate": {
                "help": "bond lacp rate",
                "validvals": ["0", "slow", "1", "fast"],
                "default": "0",
                "example": ["bond-lacp-rate 0"]
            },
            "bond-min-links": {
                "help": "bond min links",
                "default": "0",
                "validrange": ["0", "255"],
                "example": ["bond-min-links 0"]
            },
            "bond-ad-sys-priority": {
                "help": "802.3ad system priority",
                "default": "65535",
                "validrange": ["0", "65535"],
                "example": ["bond-ad-sys-priority 65535"],
                "deprecated": True,
                "new-attribute": "bond-ad-actor-sys-prio"
            },
            "bond-ad-actor-sys-prio": {
                "help": "802.3ad system priority",
                "default": "65535",
                "validrange": ["0", "65535"],
                "example": ["bond-ad-actor-sys-prio 65535"]
            },
            "bond-ad-sys-mac-addr": {
                "help": "802.3ad system mac address",
                "validvals": ["<mac>", ],
                "example": ["bond-ad-sys-mac-addr 00:00:00:00:00:00"],
                "deprecated": True,
                "new-attribute": "bond-ad-actor-system"
            },
            "bond-ad-actor-system": {
                "help": "802.3ad system mac address",
                "validvals": ["<mac>", ],
                "example": ["bond-ad-actor-system 00:00:00:00:00:00"],
            },
            "bond-lacp-bypass-allow": {
                "help": "allow lacp bypass",
                "validvals": ["yes", "no", "0", "1"],
                "default": "no",
                "example": ["bond-lacp-bypass-allow no"]
            },
            "bond-slaves": {
                "help": "bond slaves",
                "required": True,
                "multivalue": True,
                "validvals": ["<interface-list>"],
                "example": [
                    "bond-slaves swp1 swp2",
                    "bond-slaves glob swp1-2",
                    "bond-slaves regex (swp[1|2)"
                ],
                "aliases": ["bond-ports"]
            },
            "bond-updelay": {
                "help": "bond updelay",
                "default": "0",
                "validrange": ["0", "65535"],
                "example": ["bond-updelay 100"]
            },
            "bond-downdelay": {
                "help": "bond downdelay",
                "default": "0",
                "validrange": ["0", "65535"],
                "example": ["bond-downdelay 100"]
            },
            "bond-primary": {
                "help": "Control which slave interface is "
                        "preferred active member",
                "example": ["bond-primary swp1"]
            },
            "bond-primary-reselect": {
                "help": "bond primary reselect",
                "validvals": [
                    "0", "always",
                    "1", "better",
                    "2", "failure",
                ],
                "example": ["bond-primary-reselect failure"]
            }
        }
    }

    _bond_attr_netlink_map = {
        'bond-mode': Link.IFLA_BOND_MODE,
        'bond-miimon': Link.IFLA_BOND_MIIMON,
        'bond-use-carrier': Link.IFLA_BOND_USE_CARRIER,
        'bond-lacp-rate': Link.IFLA_BOND_AD_LACP_RATE,
        'bond-xmit-hash-policy': Link.IFLA_BOND_XMIT_HASH_POLICY,
        'bond-min-links': Link.IFLA_BOND_MIN_LINKS,
        'bond-num-grat-arp': Link.IFLA_BOND_NUM_PEER_NOTIF,
        'bond-num-unsol-na': Link.IFLA_BOND_NUM_PEER_NOTIF,
        'bond-ad-sys-mac-addr': Link.IFLA_BOND_AD_ACTOR_SYSTEM,
        'bond-ad-actor-system': Link.IFLA_BOND_AD_ACTOR_SYSTEM,
        'bond-ad-sys-priority': Link.IFLA_BOND_AD_ACTOR_SYS_PRIO,
        'bond-ad-actor-sys-prio': Link.IFLA_BOND_AD_ACTOR_SYS_PRIO,
        'bond-lacp-bypass-allow': Link.IFLA_BOND_AD_LACP_BYPASS,
        'bond-updelay': Link.IFLA_BOND_UPDELAY,
        'bond-downdelay': Link.IFLA_BOND_DOWNDELAY,
        'bond-primary': Link.IFLA_BOND_PRIMARY,
        'bond-primary-reselect': Link.IFLA_BOND_PRIMARY_RESELECT

    }

    # ifquery-check attr dictionary with callable object to translate user data to netlink format
    _bond_attr_ifquery_check_translate_func = {
        Link.IFLA_BOND_MODE: lambda x: Link.ifla_bond_mode_tbl[x],
        Link.IFLA_BOND_MIIMON: int,
        Link.IFLA_BOND_USE_CARRIER: utils.get_boolean_from_string,
        Link.IFLA_BOND_AD_LACP_RATE: lambda x: int(utils.get_boolean_from_string(x)),
        Link.IFLA_BOND_XMIT_HASH_POLICY: lambda x: Link.ifla_bond_xmit_hash_policy_tbl[x],
        Link.IFLA_BOND_MIN_LINKS: int,
        Link.IFLA_BOND_NUM_PEER_NOTIF: int,
        Link.IFLA_BOND_AD_ACTOR_SYSTEM: str,
        Link.IFLA_BOND_AD_ACTOR_SYS_PRIO: int,
        Link.IFLA_BOND_AD_LACP_BYPASS: lambda x: int(utils.get_boolean_from_string(x)),
        Link.IFLA_BOND_UPDELAY: int,
        Link.IFLA_BOND_DOWNDELAY: int,
        Link.IFLA_BOND_PRIMARY_RESELECT: lambda x: Link.ifla_bond_primary_reselect_tbl[x],
        # Link.IFLA_BOND_PRIMARY: self.netlink.get_ifname is added in __init__()
    }

    # ifup attr list with callable object to translate user data to netlink format
    # in the future this can be moved to a dictionary, whenever we detect that some
    # netlink capabilities are missing we can dynamically remove them from the dict.
    _bond_attr_set_list = (
        ('bond-mode', Link.IFLA_BOND_MODE, lambda x: Link.ifla_bond_mode_tbl[x]),
        ('bond-xmit-hash-policy', Link.IFLA_BOND_XMIT_HASH_POLICY, lambda x: Link.ifla_bond_xmit_hash_policy_tbl[x]),
        ('bond-miimon', Link.IFLA_BOND_MIIMON, int),
        ('bond-min-links', Link.IFLA_BOND_MIN_LINKS, int),
        ('bond-num-grat-arp', Link.IFLA_BOND_NUM_PEER_NOTIF, int),
        ('bond-num-unsol-na', Link.IFLA_BOND_NUM_PEER_NOTIF, int),
        ('bond-ad-sys-priority', Link.IFLA_BOND_AD_ACTOR_SYS_PRIO, int),
        ('bond-ad-actor-sys-prio', Link.IFLA_BOND_AD_ACTOR_SYS_PRIO, int),
        ('bond-updelay', Link.IFLA_BOND_UPDELAY, int),
        ('bond-downdelay', Link.IFLA_BOND_DOWNDELAY, int),
        ('bond-use-carrier', Link.IFLA_BOND_USE_CARRIER, lambda x: int(utils.get_boolean_from_string(x))),
        ('bond-lacp-rate', Link.IFLA_BOND_AD_LACP_RATE, lambda x: int(utils.get_boolean_from_string(x))),
        ('bond-lacp-bypass-allow', Link.IFLA_BOND_AD_LACP_BYPASS, lambda x: int(utils.get_boolean_from_string(x))),
        ('bond-ad-sys-mac-addr', Link.IFLA_BOND_AD_ACTOR_SYSTEM, str),
        ('bond-ad-actor-system', Link.IFLA_BOND_AD_ACTOR_SYSTEM, str),
        ('bond-primary-reselect', Link.IFLA_BOND_PRIMARY_RESELECT, lambda x: Link.ifla_bond_primary_reselect_tbl[x])
        # ('bond-primary', Link.IFLA_BOND_PRIMARY, self.cache.get_ifindex) added in __init__()
    )

    def __init__(self, *args, **kargs):
        Addon.__init__(self)
        moduleBase.__init__(self, *args, **kargs)

        if not os.path.exists('/sys/class/net/bonding_masters'):
            try:
                utils.exec_command('modprobe -q bonding')
            except Exception as e:
                self.logger.info("bond: error while loading bonding module: %s" % str(e))

        self._bond_attr_ifquery_check_translate_func[Link.IFLA_BOND_PRIMARY] = self.cache.get_ifindex
        self._bond_attr_set_list = self._bond_attr_set_list + (('bond-primary', Link.IFLA_BOND_PRIMARY, self.cache.get_ifindex),)


    def get_bond_slaves(self, ifaceobj):
        # bond-ports aliases should be translated to bond-slaves
        return ifaceobj.get_attr_value_first('bond-slaves')

    def _is_bond(self, ifaceobj):
        # at first link_kind is not set but once ifupdownmain
        # calls get_dependent_ifacenames link_kind is set to BOND
        return ifaceobj.link_kind & ifaceLinkKind.BOND or self.get_bond_slaves(ifaceobj)

    def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
        """ Returns list of interfaces dependent on ifaceobj """

        if not self._is_bond(ifaceobj):
            return None
        slave_list = self.parse_port_list(ifaceobj.name,
                                          self.get_bond_slaves(ifaceobj),
                                          ifacenames_all)
        ifaceobj.dependency_type = ifaceDependencyType.MASTER_SLAVE
        # Also save a copy for future use
        ifaceobj.priv_data = list(slave_list)
        if ifaceobj.link_type != ifaceLinkType.LINK_NA:
           ifaceobj.link_type = ifaceLinkType.LINK_MASTER
        ifaceobj.link_kind |= ifaceLinkKind.BOND
        ifaceobj.role |= ifaceRole.MASTER

        return slave_list

    def syntax_check(self, ifaceobj, ifaceobj_getfunc):
        return self.syntax_check_updown_delay(ifaceobj)

    def get_dependent_ifacenames_running(self, ifaceobj):
        return self.cache.get_slaves(ifaceobj.name)

    def _get_slave_list(self, ifaceobj):
        """ Returns slave list present in ifaceobj config """

        # If priv data already has slave list use that first.
        if ifaceobj.priv_data:
            return ifaceobj.priv_data
        slaves = self.get_bond_slaves(ifaceobj)
        if slaves:
            return self.parse_port_list(ifaceobj.name, slaves)
        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:
            for ifaceobj in statemanager.get_ifaceobjs(ifname) or []:
                if ifaceobj.link_privflags & ifaceLinkPrivFlags.BRIDGE_PORT:
                    self.write_file("/proc/sys/net/ipv6/conf/%s/disable_ipv6" % ifname, "0")
                    return
        except Exception as 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')
            if attrval and attrval != '0':
                return True
        return False

    def _add_slaves(self, ifaceobj, runningslaves, ifaceobj_getfunc=None):
        slaves = self._get_slave_list(ifaceobj)
        if not slaves:
            self.logger.debug('%s: no slaves found' %ifaceobj.name)
            return

        clag_bond = self._is_clag_bond(ifaceobj)

        # remove duplicates and devices that are already enslaved
        devices_to_enslave = []
        for s in slaves:
            if s not in runningslaves and s not in devices_to_enslave:
                devices_to_enslave.append(s)

        for slave in devices_to_enslave:
            if (not ifupdownflags.flags.PERFMODE and
                not self.cache.link_exists(slave)):
                    self.log_error('%s: skipping slave %s, does not exist'
                                   %(ifaceobj.name, slave), ifaceobj,
                                     raise_error=False)
                    continue
            link_up = False
            if self.cache.link_is_up(slave):
                self.netlink.link_down_force(slave)
                link_up = True
            # If clag bond place the slave in a protodown state; clagd
            # will protoup it when it is ready
            if clag_bond:
                try:
                    self.netlink.link_set_protodown_on(slave)
                except Exception as e:
                    self.logger.error('%s: %s' % (ifaceobj.name, str(e)))

            self.enable_ipv6_if_prev_brport(slave)
            self.netlink.link_set_master(slave, ifaceobj.name)
            # TODO: if this fail we should switch to iproute2
            # start a batch: down - set master - up
            if link_up or ifaceobj.link_type != ifaceLinkType.LINK_NA:
               try:
                    if (ifaceobj_getfunc(slave)[0].link_privflags &
                        ifaceLinkPrivFlags.KEEP_LINK_DOWN):
                        self.netlink.link_down_force(slave)
                    else:
                        self.netlink.link_up(slave)
               except Exception as e:
                    self.logger.debug('%s: %s' % (ifaceobj.name, str(e)))
                    pass

        if runningslaves:
            for s in runningslaves:
                if s not in slaves:
                    self.sysfs.bond_remove_slave(ifaceobj.name, s)
                    if clag_bond:
                        try:
                            self.netlink.link_set_protodown_off(s)
                        except Exception as e:
                            self.logger.error('%s: %s' % (ifaceobj.name, str(e)))
                else:
                    # apply link-down config changes on running slaves
                    try:
                        link_up = self.cache.link_is_up(s)
                        config_link_down = (ifaceobj_getfunc(s)[0].link_privflags &
                                            ifaceLinkPrivFlags.KEEP_LINK_DOWN)
                        if (config_link_down and link_up):
                            self.netlink.link_down_force(s)
                        elif (not config_link_down and not link_up):
                            self.netlink.link_up_force(s)
                    except Exception as e:
                        self.logger.warning('%s: %s' % (ifaceobj.name, str(e)))

    def _check_updown_delay_log(self, ifaceobj, attr_name, value):
        ifaceobj.status = ifaceStatus.ERROR
        self.logger.error('%s: unable to set %s %s as MII link monitoring is '
                          'disabled' % (ifaceobj.name, attr_name, value))
        # return False to notify syntax_check that an error has been logged
        return False

    def syntax_check_updown_delay(self, ifaceobj):
        result      = True
        updelay     = ifaceobj.get_attr_value_first('bond-updelay')
        downdelay   = ifaceobj.get_attr_value_first('bond-downdelay')

        if not updelay and not downdelay:
            return True

        try:
            miimon = int(ifaceobj.get_attr_value_first('bond-miimon'))
        except:
            try:
                miimon = int(policymanager.policymanager_api.get_iface_default(
                    module_name=self.__class__.__name__,
                    ifname=ifaceobj.name,
                    attr='bond-miimon'))
            except:
                miimon = 0

        if not miimon:
            # self._check_updown_delay_log returns False no matter what
            if updelay and int(updelay):
                result = self._check_updown_delay_log(ifaceobj, 'bond-updelay', updelay)
            if downdelay and int(downdelay):
                result = self._check_updown_delay_log(ifaceobj, 'bond-downdelay', downdelay)

        return result

    _bond_updown_delay_nl_list = (
        (Link.IFLA_BOND_UPDELAY, 'bond-updelay'),
        (Link.IFLA_BOND_DOWNDELAY, 'bond-downdelay')
    )

    def check_updown_delay_nl(self, link_exists, ifaceobj, ifla_info_data):
        """
            IFLA_BOND_MIIMON
            Specifies the time, in milliseconds, to wait before enabling a slave
            after a link recovery has been detected. This option is only valid
            for the miimon link monitor. The updelay value should be a multiple
            of the miimon value; if not, it will be rounded down to the nearest
            multiple. The default value is 0.

            This ifla_bond_miimon code should be move to get_ifla_bond_attr_from_user_config
            but we need to know if the operation was successful to update the cache accordingly
        """
        ifla_bond_miimon = ifla_info_data.get(Link.IFLA_BOND_MIIMON)
        if link_exists and ifla_bond_miimon is None:
            ifla_bond_miimon = self.cache.get_link_info_data_attribute(ifaceobj.name, Link.IFLA_BOND_MIIMON)

        if ifla_bond_miimon == 0:
            for nl_attr, attr_name in self._bond_updown_delay_nl_list:
                delay = ifla_info_data.get(nl_attr)
                # if up-down-delay exists we need to remove it, if non zero log error
                if delay is not None:
                    if delay > 0:
                        self._check_updown_delay_log(ifaceobj, attr_name, delay)
                    del ifla_info_data[nl_attr]
            return True
        return False

    _bond_lacp_attrs = (
        (Link.IFLA_BOND_AD_LACP_RATE, 'bond-lacp-rate'),
        (Link.IFLA_BOND_AD_LACP_BYPASS, 'bond-lacp-bypass')
    )

    def _check_bond_mode_user_config(self, ifname, link_exists, ifla_info_data):
        ifla_bond_mode = ifla_info_data.get(Link.IFLA_BOND_MODE)
        if ifla_bond_mode is None and link_exists:
            ifla_bond_mode = self.cache.get_link_info_data_attribute(ifname, Link.IFLA_BOND_MODE)
            # in this case the link already exists (we have a cached value):
            # if IFLA_BOND_MODE is not present in ifla_info_data it means:
            #   - that bond-mode was present in the user config and didn't change
            #   - never was in the user config so bond mode should be the system default value
            #   - was removed from the stanza so we might have to reset it to default value
            # nevertheless we need to add it back to the ifla_info_data dict to check
            # if we need to reset the mode to system default
            ifla_info_data[Link.IFLA_BOND_MODE] = ifla_bond_mode

        if ifla_bond_mode == 4:  # 802.3ad
            min_links = ifla_info_data.get(Link.IFLA_BOND_MIN_LINKS)
            if min_links is None:
                min_links = self.cache.get_link_info_data_attribute(ifname, Link.IFLA_BOND_MIN_LINKS)
            # get_min_links_nl may return None so we need to strictly check 0
            if min_links == 0:
                self.logger.warning('%s: attribute bond-min-links is set to \'0\'' % ifname)
        else:
            # IFLA_BOND_AD_LACP_RATE and IFLA_BOND_AD_LACP_BYPASS only for 802.3ad mode (4)
            for nl_attr, attr_name in self._bond_lacp_attrs:
                if nl_attr in ifla_info_data:
                    self.logger.info('%s: ignoring %s: only available for 802.3ad mode (4)' % (ifname, attr_name))
                    del ifla_info_data[nl_attr]

    @staticmethod
    def get_saved_ifaceobj(link_exists, ifname):
        if link_exists:
            old_config = statemanager.get_ifaceobjs(ifname)
            if old_config:
                return old_config[0]
        return None

    def get_ifla_bond_attr_from_user_config(self, ifaceobj, link_exists):
        """
            Potential issue: if a user load the bond driver with custom
            default values (say bond-mode 3), ifupdown2 has no knowledge
            of these default values.
            At bond creation everything should work, bonds will be created
            with mode 3 (even if not specified under the stanza).
            But, for example: if the user specifies a value under bond-mode
            and later on the user removes the bond-mode line from the stanza
            we will detect it and reset to MODINFO: BOND-MODE: DEFAULT aka 0
            which is not the real default value that the user may expect.
        """
        ifname          = ifaceobj.name
        ifla_info_data  = OrderedDict()
        old_config      = self.get_saved_ifaceobj(link_exists, ifname)

        # for each bond attribute we fetch the user configuration
        # if no configuration is provided we look for a config in policy files
        for attr_name, netlink_attr, func_ptr in self._bond_attr_set_list:
            cached_value        = None
            user_config         = ifaceobj.get_attr_value_first(attr_name)

            if not user_config:
                user_config = policymanager.policymanager_api.get_iface_default(
                    module_name=self.__class__.__name__,
                    ifname=ifname,
                    attr=attr_name)
                if user_config:
                    self.logger.debug('%s: %s %s: extracted from policy files'
                                      % (ifname, attr_name, user_config))

            # no policy override, do we need to reset an attr to default value?
            if not user_config and old_config and old_config.get_attr_value_first(attr_name):
                # if the link already exists but the value is set
                # (potentially removed from the stanza, we need to reset it to default)
                # might not work for specific cases, see explanation at the top of this function :)
                user_config = self.get_attr_default_value(attr_name)
                if user_config:
                    self.logger.debug('%s: %s: removed from stanza, resetting to default value: %s'
                                      % (ifname, attr_name, user_config))

            if user_config:
                try:
                    nl_value = func_ptr(user_config.lower())

                    if link_exists:
                        cached_value = self.cache.get_link_info_data_attribute(ifname, netlink_attr)

                    if link_exists and cached_value is None:
                        # the link already exists but we don't have any value
                        # cached for this attr, it probably means that the
                        # capability is not available on this system (i.e old kernel)
                        self.logger.debug('%s: ignoring %s %s: capability '
                                          'probably not supported on this system'
                                          % (ifname, attr_name, user_config))
                        continue
                    elif link_exists:
                        # there should be a cached value if the link already exists
                        if cached_value == nl_value:
                            # if the user value is already cached: continue
                            continue

                    # else: the link doesn't exist so we create the bond with
                    # all the user/policy defined values without extra checks
                    ifla_info_data[netlink_attr] = nl_value

                    if cached_value is not None:
                        self.logger.info('%s: set %s %s (cache %s)' % (ifname, attr_name, user_config, cached_value))
                    else:
                        self.logger.info('%s: set %s %s' % (ifname, attr_name, user_config))

                except KeyError:
                    self.logger.warning('%s: invalid %s value %s' % (ifname, attr_name, user_config))

        self._check_bond_mode_user_config(ifname, link_exists, ifla_info_data)
        return ifla_info_data

    _bond_down_nl_attributes_list = (
        Link.IFLA_BOND_MODE,
        Link.IFLA_BOND_XMIT_HASH_POLICY,
        Link.IFLA_BOND_AD_LACP_RATE,
        Link.IFLA_BOND_MIN_LINKS
    )

    def _should_down_bond(self, ifla_info_data):
        for nl_attr in self._bond_down_nl_attributes_list:
            if nl_attr in ifla_info_data:
                return True
        return False

    def should_update_bond_mode(self, ifaceobj, ifname, is_link_up, ifla_info_data, bond_slaves):
        # if bond-mode was changed the bond needs to be brought
        # down and slaves un-slaved before bond mode is changed.
        cached_bond_mode = self.cache.get_link_info_data_attribute(ifname, Link.IFLA_BOND_MODE)
        ifla_bond_mode = ifla_info_data.get(Link.IFLA_BOND_MODE)

        # bond-mode was changed or is not specified
        if ifla_bond_mode is not None:
            if ifla_bond_mode != cached_bond_mode:
                self.logger.info('%s: bond mode changed to %s: running ops on bond and slaves'
                                 % (ifname, ifla_bond_mode))
                if is_link_up:
                    self.netlink.link_down(ifname)
                    is_link_up = False

                for lower_dev in ifaceobj.lowerifaces:
                    self.netlink.link_set_nomaster(lower_dev)
                    try:
                        bond_slaves.remove(lower_dev)
                    except:
                        pass

            else:
                # bond-mode user config value is the current running(cached) value
                # no need to reset it again we can ignore this attribute
                del ifla_info_data[Link.IFLA_BOND_MODE]

        return is_link_up, bond_slaves

    def create_or_set_bond_config(self, ifaceobj):
        ifname          = ifaceobj.name
        link_exists, is_link_up = self.cache.link_exists_and_up(ifname)
        ifla_info_data  = self.get_ifla_bond_attr_from_user_config(ifaceobj, link_exists)

        remove_delay_from_cache = self.check_updown_delay_nl(link_exists, ifaceobj, ifla_info_data)

        # if link exists: down link if specific attributes are specified
        if link_exists:
            # did bond-mode changed?
            is_link_up, bond_slaves = self.should_update_bond_mode(
                ifaceobj,
                ifname,
                is_link_up,
                ifla_info_data,
                self.cache.get_slaves(ifname)
            )

            # if specific attributes need to be set we need to down the bond first
            if ifla_info_data and is_link_up:
                if self._should_down_bond(ifla_info_data):
                    self.netlink.link_down_force(ifname)
                    is_link_up = False
        else:
            bond_slaves = []

        if link_exists and not ifla_info_data:
            # if the bond already exists and no attrs need to be set
            # ignore the netlink call
            self.logger.info('%s: already exists, no change detected' % ifname)
        else:
            try:
                self.netlink.link_add_bond_with_info_data(ifname, ifla_info_data)
            except Exception as e:
                # defensive code
                # if anything happens, we try to set up the bond with the sysfs api
                self.logger.debug('%s: bond setup: %s' % (ifname, str(e)))
                self.create_or_set_bond_config_sysfs(ifaceobj, ifla_info_data)

            if remove_delay_from_cache:
                # making sure up/down delay attributes are set to 0 before caching
                # this can be removed when moving to a nllistener/live cache
                ifla_info_data[Link.IFLA_BOND_UPDELAY] = 0
                ifla_info_data[Link.IFLA_BOND_DOWNDELAY] = 0

        if link_exists and ifla_info_data and not is_link_up:
            self.netlink.link_up_force(ifname)

        return bond_slaves

    def create_or_set_bond_config_sysfs(self, ifaceobj, ifla_info_data):
        if not self.cache.link_exists(ifaceobj.name):
            self.sysfs.bond_create(ifaceobj.name)
        self.sysfs.bond_set_attrs_nl(ifaceobj.name, ifla_info_data)

    def _up(self, ifaceobj, ifaceobj_getfunc=None):
        try:
            bond_slaves = self.create_or_set_bond_config(ifaceobj)
            self._add_slaves(
                ifaceobj,
                bond_slaves,
                ifaceobj_getfunc,
            )
        except Exception as e:
            self.log_error(str(e), ifaceobj)

    def _down(self, ifaceobj, ifaceobj_getfunc=None):
        try:
            self.netlink.link_del(ifaceobj.name)
        except Exception as e:
            self.log_warn('%s: %s' % (ifaceobj.name, str(e)))

    def _query_check_bond_slaves(self, ifaceobjcurr, attr, user_bond_slaves, running_bond_slaves):
        query = 1

        if user_bond_slaves and running_bond_slaves:
            if not set(user_bond_slaves).symmetric_difference(running_bond_slaves):
                query = 0

        # we want to display the same bond-slaves list as provided
        # in the interfaces file but if this list contains regexes or
        # globs, for now, we won't try to change it.
        if 'regex' in user_bond_slaves or 'glob' in user_bond_slaves:
            user_bond_slaves = running_bond_slaves
        else:
            ordered = []
            for slave in user_bond_slaves:
                if slave in running_bond_slaves:
                    ordered.append(slave)
            user_bond_slaves = ordered
        ifaceobjcurr.update_config_with_status(attr, ' '.join(user_bond_slaves) if user_bond_slaves else 'None', query)

    def _query_check(self, ifaceobj, ifaceobjcurr, ifaceobj_getfunc=None):
        if not self.cache.bond_exists(ifaceobj.name):
            self.logger.debug('bond iface %s does not exist' % ifaceobj.name)
            return

        iface_attrs = self.dict_key_subset(ifaceobj.config, self.get_mod_attrs())
        if not iface_attrs:
            return

        # remove bond-slaves and bond-ports from the list,
        # because there aren't any ifla_info_data netlink attr for slaves
        # an exception is raised when index is not found, so query_slaves will stay False
        query_slaves = False

        user_bond_slaves    = None
        running_bond_slaves = None
        try:
            del iface_attrs[iface_attrs.index('bond-slaves')]

            # if user specified bond-slaves we need to display it
            query_slaves = True
            if not user_bond_slaves:
                user_bond_slaves = self._get_slave_list(ifaceobj)
                running_bond_slaves = self.cache.get_slaves(ifaceobj.name)

            self._query_check_bond_slaves(ifaceobjcurr, 'bond-slaves', user_bond_slaves, running_bond_slaves)
        except:
            pass
        try:
            del iface_attrs[iface_attrs.index('bond-ports')]

            # if user specified bond-ports we need to display it
            if not query_slaves and not user_bond_slaves: # if get_slave_list was already called for slaves
                user_bond_slaves = self._get_slave_list(ifaceobj)
                running_bond_slaves = self.cache.get_slaves(ifaceobj.name)

            self._query_check_bond_slaves(ifaceobjcurr, 'bond-ports', user_bond_slaves, running_bond_slaves)
        except:
            pass

        for attr in iface_attrs:
            nl_attr         = self._bond_attr_netlink_map[attr]
            translate_func  = self._bond_attr_ifquery_check_translate_func[nl_attr]
            current_config  = self.cache.get_link_info_data_attribute(ifaceobj.name, nl_attr)
            user_config     = ifaceobj.get_attr_value_first(attr)

            if current_config == translate_func(user_config):
                ifaceobjcurr.update_config_with_status(attr, user_config, 0)
            else:
                ifaceobjcurr.update_config_with_status(attr, str(current_config), 1)

    @staticmethod
    def translate_nl_value_yesno(value):
        return 'yes' if value else 'no'

    @staticmethod
    def translate_nl_value_slowfast(value):
        return 'fast' if value else 'slow'

    def _query_running_attrs(self, bondname):
        cached_vxlan_ifla_info_data = self.cache.get_link_info_data(bondname)

        bond_attrs = {
            'bond-mode': Link.ifla_bond_mode_pretty_tbl.get(cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_MODE)),
            'bond-miimon': cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_MIIMON),
            'bond-use-carrier': self.translate_nl_value_yesno(cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_USE_CARRIER)),
            'bond-lacp-rate': self.translate_nl_value_slowfast(cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_AD_LACP_RATE)),
            'bond-min-links': cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_MIN_LINKS),
            'bond-ad-actor-system': cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_AD_ACTOR_SYSTEM),
            'bond-ad-actor-sys-prio': cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_AD_ACTOR_SYS_PRIO),
            'bond-xmit-hash-policy': Link.ifla_bond_xmit_hash_policy_pretty_tbl.get(cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_XMIT_HASH_POLICY)),
            'bond-lacp-bypass-allow': self.translate_nl_value_yesno(cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_AD_LACP_BYPASS)),
            'bond-num-unsol-na': cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_NUM_PEER_NOTIF),
            'bond-num-grat-arp': cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_NUM_PEER_NOTIF),
            'bond-updelay': cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_UPDELAY),
            'bond-downdelay': cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_DOWNDELAY)
        }

        cached_bond_primary = cached_vxlan_ifla_info_data.get(Link.IFLA_BOND_PRIMARY)
        if cached_bond_primary:
            bond_attrs['bond-primary'] = self.cache.get_ifname(cached_bond_primary)

        slaves = self.cache.get_slaves(bondname)
        if slaves:
            bond_attrs['bond-slaves'] = slaves
        return bond_attrs

    def _query_running(self, ifaceobjrunning, ifaceobj_getfunc=None):
        if not self.cache.bond_exists(ifaceobjrunning.name):
            return
        bond_attrs = self._query_running_attrs(ifaceobjrunning.name)
        if bond_attrs.get('bond-slaves'):
            bond_attrs['bond-slaves'] = ' '.join(bond_attrs.get('bond-slaves'))

        [ifaceobjrunning.update_config(k, str(v))
         for k, v in list(bond_attrs.items())
         if v is not None]

    _run_ops = {
        'pre-up': _up,
        'post-down': _down,
        'query-running': _query_running,
        'query-checkcurr': _query_check
    }

    def get_ops(self):
        """ returns list of ops supported by this module """
        return list(self._run_ops.keys())

    def run(self, ifaceobj, operation, query_ifaceobj=None,
            ifaceobj_getfunc=None):
        """ run bond configuration on the interface object passed as argument

        Args:
            **ifaceobj** (object): iface object

            **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
                'query-running'

        Kwargs:
            **query_ifaceobj** (object): query check ifaceobject. This is only
                valid when op is 'query-checkcurr'. It is an object same as
                ifaceobj, but contains running attribute values and its config
                status. The modules can use it to return queried running state
                of interfaces. status is success if the running state is same
                as user required state in ifaceobj. error otherwise.
        """
        op_handler = self._run_ops.get(operation)
        if not op_handler:
            return
        if operation != 'query-running' and not self._is_bond(ifaceobj):
            return
        if operation == 'query-checkcurr':
            op_handler(self, ifaceobj, query_ifaceobj,
                       ifaceobj_getfunc=ifaceobj_getfunc)
        else:
            op_handler(self, ifaceobj, ifaceobj_getfunc=ifaceobj_getfunc)
Exemplo n.º 13
0
    def do_speed_settings(self, ifaceobj, operation='post_up'):
        cmd = ''

        autoneg_to_configure = None
        speed_to_configure = None
        duplex_to_configure = None

        config_speed = ifaceobj.get_attr_value_first('link-speed')
        config_duplex = ifaceobj.get_attr_value_first('link-duplex')
        config_autoneg = ifaceobj.get_attr_value_first('link-autoneg')

        default_speed = policymanager.policymanager_api.get_iface_default(
            module_name='ethtool', ifname=ifaceobj.name, attr='link-speed')

        default_duplex = policymanager.policymanager_api.get_iface_default(
            module_name='ethtool', ifname=ifaceobj.name, attr='link-duplex')

        default_autoneg = policymanager.policymanager_api.get_iface_default(
            module_name='ethtool', ifname=ifaceobj.name, attr='link-autoneg')

        # autoneg wins if provided by user and is on
        if config_autoneg and utils.get_boolean_from_string(config_autoneg):
            autoneg_to_configure = config_autoneg
            speed_to_configure = None
            duplex_to_configure = None
        elif config_speed:
            # Any speed settings configured by the user wins
            autoneg_to_configure = None
            speed_to_configure = config_speed
            duplex_to_configure = config_duplex
            if not config_duplex:
                duplex_to_configure = default_duplex
        else:
            # if user given autoneg config is off, we must respect that and
            # override any default autoneg config
            if config_autoneg and not utils.get_boolean_from_string(
                    config_autoneg):
                default_autoneg = 'off'

            if default_autoneg and utils.get_boolean_from_string(
                    default_autoneg):
                autoneg_to_configure = utils.get_onoff_bool(default_autoneg)
                speed_to_configure = None
                duplex_to_configure = None
            else:
                autoneg_to_configure = None
                speed_to_configure = default_speed
                duplex_to_configure = default_duplex

        if autoneg_to_configure:
            autoneg_to_configure = utils.get_onoff_bool(autoneg_to_configure)
            # check running values
            running_val = self.get_running_attr('autoneg', ifaceobj)
            if autoneg_to_configure != running_val:
                # if the configured value is not set, set it
                cmd += ' autoneg %s' % autoneg_to_configure
        else:
            force_set = False
            if speed_to_configure:
                # check running values
                if utils.get_boolean_from_string(
                        self.get_running_attr('autoneg', ifaceobj) or 'off'):
                    cmd = 'autoneg off'
                    # if we are transitioning from autoneg 'on' to 'off'
                    # don't check running speed
                    force_set = True

                running_val = self.get_running_attr('speed', ifaceobj)
                if force_set or (speed_to_configure != running_val):
                    # if the configured value is not set, set it
                    cmd += ' speed %s' % speed_to_configure

            if duplex_to_configure:
                # check running values
                running_val = self.get_running_attr('duplex', ifaceobj)
                if force_set or (duplex_to_configure != running_val):
                    # if the configured value is not set, set it
                    cmd += ' duplex %s' % duplex_to_configure

        if cmd:
            try:
                cmd = ('%s -s %s %s' % (utils.ethtool_cmd, ifaceobj.name, cmd))
                utils.exec_command(cmd)
            except Exception as e:
                if not self.ethtool_ignore_errors:
                    self.log_error('%s: %s' % (ifaceobj.name, str(e)),
                                   ifaceobj)
Exemplo n.º 14
0
    def _query_check(self, ifaceobj, ifaceobjcurr):
        if not self.cache.link_exists(ifaceobj.name):
            return
        if '.' not in ifaceobj.name:
            # if vlan name is not in the dot format, check its running state

            ifname = ifaceobj.name
            cached_vlan_raw_device = self.cache.get_lower_device_ifname(ifname)

            #
            # vlan-raw-device
            #
            ifaceobjcurr.update_config_with_status(
                'vlan-raw-device',
                cached_vlan_raw_device,
                cached_vlan_raw_device != ifaceobj.get_attr_value_first('vlan-raw-device')
            )

            cached_vlan_info_data = self.cache.get_link_info_data(ifname)

            #
            # vlan-id
            #
            vlanid_config = ifaceobj.get_attr_value_first('vlan-id')
            if not vlanid_config:
                vlanid_config = str(self._get_vlan_id(ifaceobj))

            cached_vlan_id = cached_vlan_info_data.get(Link.IFLA_VLAN_ID)
            cached_vlan_id_str = str(cached_vlan_id)
            ifaceobjcurr.update_config_with_status('vlan-id', cached_vlan_id_str, vlanid_config != cached_vlan_id_str)

            #
            # vlan-protocol
            #
            protocol_config = ifaceobj.get_attr_value_first('vlan-protocol')
            if protocol_config:

                cached_vlan_protocol = cached_vlan_info_data.get(Link.IFLA_VLAN_PROTOCOL)

                if protocol_config.upper() != cached_vlan_protocol.upper():
                    ifaceobjcurr.update_config_with_status(
                        'vlan-protocol',
                        cached_vlan_protocol,
                        1
                    )
                else:
                    ifaceobjcurr.update_config_with_status(
                        'vlan-protocol',
                        protocol_config,
                        0
                    )

            #
            # vlan-bridge-binding
            #
            vlan_bridge_binding = ifaceobj.get_attr_value_first("vlan-bridge-binding")
            if vlan_bridge_binding:
                cached_vlan_bridge_binding = cached_vlan_info_data.get(Link.IFLA_VLAN_FLAGS, {}).get(
                    Link.VLAN_FLAG_BRIDGE_BINDING, False)

                ifaceobjcurr.update_config_with_status(
                    "vlan-bridge-binding",
                    "on" if cached_vlan_bridge_binding else "off",
                    cached_vlan_bridge_binding != utils.get_boolean_from_string(vlan_bridge_binding)
                )

            self._bridge_vid_check(ifaceobjcurr, cached_vlan_raw_device, cached_vlan_id)
Exemplo n.º 15
0
    def _up(self, ifaceobj):
        vlanid = self._get_vlan_id(ifaceobj)
        if vlanid == -1:
            raise Exception('could not determine vlanid')
        vlanrawdevice = self._get_vlan_raw_device(ifaceobj)
        if not vlanrawdevice:
            raise Exception('could not determine vlan raw device')

        ifname = ifaceobj.name

        if ifupdownflags.flags.PERFMODE:
            cached_vlan_ifla_info_data = {}
        else:
            cached_vlan_ifla_info_data = self.cache.get_link_info_data(ifname)

        vlan_bridge_binding = ifaceobj.get_attr_value_first("vlan-bridge-binding")

        if not vlan_bridge_binding:
            vlan_bridge_binding = policymanager.policymanager_api.get_attr_default(
                self.__class__.__name__,
                "vlan-bridge-binding"
            ) or self.get_attr_default_value("vlan-bridge-binding")

        bool_vlan_bridge_binding = utils.get_boolean_from_string(vlan_bridge_binding)

        vlan_protocol = ifaceobj.get_attr_value_first('vlan-protocol')
        cached_vlan_protocol = cached_vlan_ifla_info_data.get(Link.IFLA_VLAN_PROTOCOL)

        if not vlan_protocol:
            vlan_protocol = self.get_attr_default_value('vlan-protocol')

        if cached_vlan_protocol and vlan_protocol.lower() != cached_vlan_protocol.lower():
            raise Exception('%s: cannot change vlan-protocol to %s: operation not supported. '
                            'Please delete the device with \'ifdown %s\' and recreate it to '
                            'apply the change.'
                            % (ifaceobj.name, vlan_protocol, ifaceobj.name))

        cached_vlan_id = cached_vlan_ifla_info_data.get(Link.IFLA_VLAN_ID)
        if cached_vlan_id is not None and vlanid != cached_vlan_id:
            raise Exception('%s: cannot change vlan-id to %s: operation not supported. '
                            'Please delete the device with \'ifdown %s\' and recreate it to '
                            'apply the change.'
                            % (ifaceobj.name, vlanid, ifaceobj.name))

        if not ifupdownflags.flags.PERFMODE:

            vlan_exists = self.cache.link_exists(ifaceobj.name)

            if vlan_exists:
                user_vlan_raw_device = ifaceobj.get_attr_value_first('vlan-raw-device')
                cached_vlan_raw_device = self.cache.get_lower_device_ifname(ifname)

                if cached_vlan_raw_device and user_vlan_raw_device and cached_vlan_raw_device != user_vlan_raw_device:
                    raise Exception('%s: cannot change vlan-raw-device from %s to %s: operation not supported. '
                                    'Please delete the device with \'ifdown %s\' and recreate it to apply the change.'
                                    % (ifaceobj.name, cached_vlan_raw_device, user_vlan_raw_device, ifaceobj.name))

            if not self.cache.link_exists(vlanrawdevice):
                if ifupdownflags.flags.DRYRUN:
                    return
                else:
                    raise Exception('rawdevice %s not present' % vlanrawdevice)
            if vlan_exists:

                # vlan-bridge-binding has changed we need to update it
                if vlan_bridge_binding is not None and bool_vlan_bridge_binding != cached_vlan_ifla_info_data.get(Link.IFLA_VLAN_FLAGS, {}).get(Link.VLAN_FLAG_BRIDGE_BINDING, False):
                    self.logger.info("%s: mismatch detected: resetting: vlan-bridge-binding %s" % (ifname, vlan_bridge_binding))
                    self.netlink.link_add_vlan(vlanrawdevice, ifaceobj.name, vlanid, vlan_protocol, bool_vlan_bridge_binding)

                self._bridge_vid_add_del(vlanrawdevice, vlanid)
                return

        try:
            self.netlink.link_add_vlan(vlanrawdevice, ifaceobj.name, vlanid, vlan_protocol, bool_vlan_bridge_binding if vlan_bridge_binding is not None else None)
        except RetryCMD as e:
            self.logger.info("%s: attempting to create vlan without bridge_binding (capability not detected on the system)" % ifaceobj.name)
            utils.exec_command(e.cmd)
        self._bridge_vid_add_del(vlanrawdevice, vlanid)
Exemplo n.º 16
0
class bond(moduleBase):
    """  ifupdown2 addon module to configure bond interfaces """

    overrides_ifupdown_scripts = [
        'ifenslave',
    ]

    _modinfo = {
        'mhelp': 'bond configuration module',
        'attrs': {
            'bond-use-carrier': {
                'help': 'bond use carrier',
                'validvals': ['yes', 'no', '0', '1'],
                'default': 'yes',
                'example': ['bond-use-carrier yes']
            },
            'bond-num-grat-arp': {
                'help': 'bond use carrier',
                'validrange': ['0', '255'],
                'default': '1',
                'example': ['bond-num-grat-arp 1']
            },
            'bond-num-unsol-na': {
                'help': 'bond slave devices',
                'validrange': ['0', '255'],
                'default': '1',
                'example': ['bond-num-unsol-na 1']
            },
            'bond-xmit-hash-policy': {
                'help':
                'bond slave devices',
                'validvals': [
                    '0', 'layer2', '1', 'layer3+4', '2', 'layer2+3', '3',
                    'encap2+3', '4', 'encap3+4'
                ],
                'default':
                'layer2',
                'example': ['bond-xmit-hash-policy layer2']
            },
            'bond-miimon': {
                'help': 'bond miimon',
                'validrange': ['0', '255'],
                'default': '0',
                'example': ['bond-miimon 0']
            },
            'bond-mode': {
                'help':
                'bond mode',
                'validvals': [
                    '0', 'balance-rr', '1', 'active-backup', '2',
                    'balance-xor', '3', 'broadcast', '4', '802.3ad', '5',
                    'balance-tlb', '6', 'balance-alb'
                ],
                'default':
                'balance-rr',
                'example': ['bond-mode 802.3ad']
            },
            'bond-lacp-rate': {
                'help': 'bond lacp rate',
                'validvals': ['0', 'slow', '1', 'fast'],
                'default': '0',
                'example': ['bond-lacp-rate 0']
            },
            'bond-min-links': {
                'help': 'bond min links',
                'default': '0',
                'validrange': ['0', '255'],
                'example': ['bond-min-links 0']
            },
            'bond-ad-sys-priority': {
                'help': '802.3ad system priority',
                'default': '65535',
                'validrange': ['0', '65535'],
                'example': ['bond-ad-sys-priority 65535'],
                'deprecated': True,
                'new-attribute': 'bond-ad-actor-sys-prio'
            },
            'bond-ad-actor-sys-prio': {
                'help': '802.3ad system priority',
                'default': '65535',
                'validrange': ['0', '65535'],
                'example': ['bond-ad-actor-sys-prio 65535']
            },
            'bond-ad-sys-mac-addr': {
                'help': '802.3ad system mac address',
                'validvals': [
                    '<mac>',
                ],
                'example': ['bond-ad-sys-mac-addr 00:00:00:00:00:00'],
                'deprecated': True,
                'new-attribute': 'bond-ad-actor-system'
            },
            'bond-ad-actor-system': {
                'help': '802.3ad system mac address',
                'validvals': [
                    '<mac>',
                ],
                'example': ['bond-ad-actor-system 00:00:00:00:00:00'],
            },
            'bond-lacp-bypass-allow': {
                'help': 'allow lacp bypass',
                'validvals': ['yes', 'no', '0', '1'],
                'default': 'no',
                'example': ['bond-lacp-bypass-allow no']
            },
            'bond-slaves': {
                'help':
                'bond slaves',
                'required':
                True,
                'multivalue':
                True,
                'validvals': ['<interface-list>'],
                'example': [
                    'bond-slaves swp1 swp2', 'bond-slaves glob swp1-2',
                    'bond-slaves regex (swp[1|2)'
                ],
                'aliases': ['bond-ports']
            },
            'bond-updelay': {
                'help': 'bond updelay',
                'default': '0',
                'validrange': ['0', '65535'],
                'example': ['bond-updelay 100']
            },
            'bond-downdelay': {
                'help': 'bond downdelay',
                'default': '0',
                'validrange': ['0', '65535'],
                'example': ['bond-downdelay 100']
            }
        }
    }

    _bond_attr_netlink_map = {
        'bond-mode': Link.IFLA_BOND_MODE,
        'bond-miimon': Link.IFLA_BOND_MIIMON,
        'bond-use-carrier': Link.IFLA_BOND_USE_CARRIER,
        'bond-lacp-rate': Link.IFLA_BOND_AD_LACP_RATE,
        'bond-xmit-hash-policy': Link.IFLA_BOND_XMIT_HASH_POLICY,
        'bond-min-links': Link.IFLA_BOND_MIN_LINKS,
        'bond-num-grat-arp': Link.IFLA_BOND_NUM_PEER_NOTIF,
        'bond-num-unsol-na': Link.IFLA_BOND_NUM_PEER_NOTIF,
        'bond-ad-sys-mac-addr': Link.IFLA_BOND_AD_ACTOR_SYSTEM,
        'bond-ad-actor-system': Link.IFLA_BOND_AD_ACTOR_SYSTEM,
        'bond-ad-sys-priority': Link.IFLA_BOND_AD_ACTOR_SYS_PRIO,
        'bond-ad-actor-sys-prio': Link.IFLA_BOND_AD_ACTOR_SYS_PRIO,
        'bond-lacp-bypass-allow': Link.IFLA_BOND_AD_LACP_BYPASS,
        'bond-updelay': Link.IFLA_BOND_UPDELAY,
        'bond-downdelay': Link.IFLA_BOND_DOWNDELAY
    }

    # ifquery-check attr dictionary with callable object to translate user data to netlink format
    _bond_attr_ifquery_check_translate_func = {
        Link.IFLA_BOND_MODE:
        lambda x: Link.ifla_bond_mode_tbl[x],
        Link.IFLA_BOND_MIIMON:
        int,
        Link.IFLA_BOND_USE_CARRIER:
        utils.get_boolean_from_string,
        Link.IFLA_BOND_AD_LACP_RATE:
        lambda x: int(utils.get_boolean_from_string(x)),
        Link.IFLA_BOND_XMIT_HASH_POLICY:
        lambda x: Link.ifla_bond_xmit_hash_policy_tbl[x],
        Link.IFLA_BOND_MIN_LINKS:
        int,
        Link.IFLA_BOND_NUM_PEER_NOTIF:
        int,
        Link.IFLA_BOND_AD_ACTOR_SYSTEM:
        str,
        Link.IFLA_BOND_AD_ACTOR_SYS_PRIO:
        int,
        Link.IFLA_BOND_AD_LACP_BYPASS:
        lambda x: int(utils.get_boolean_from_string(x)),
        Link.IFLA_BOND_UPDELAY:
        int,
        Link.IFLA_BOND_DOWNDELAY:
        int
    }

    # ifup attr list with callable object to translate user data to netlink format
    # in the future this can be moved to a dictionary, whenever we detect that some
    # netlink capabilities are missing we can dynamically remove them from the dict.
    _bond_attr_set_list = (
        ('bond-mode', Link.IFLA_BOND_MODE,
         lambda x: Link.ifla_bond_mode_tbl[x]),
        ('bond-xmit-hash-policy', Link.IFLA_BOND_XMIT_HASH_POLICY,
         lambda x: Link.ifla_bond_xmit_hash_policy_tbl[x]),
        ('bond-miimon', Link.IFLA_BOND_MIIMON, int),
        ('bond-min-links', Link.IFLA_BOND_MIN_LINKS, int),
        ('bond-num-grat-arp', Link.IFLA_BOND_NUM_PEER_NOTIF, int),
        ('bond-num-unsol-na', Link.IFLA_BOND_NUM_PEER_NOTIF, int),
        ('bond-ad-sys-priority', Link.IFLA_BOND_AD_ACTOR_SYS_PRIO, int),
        ('bond-ad-actor-sys-prio', Link.IFLA_BOND_AD_ACTOR_SYS_PRIO, int),
        ('bond-updelay', Link.IFLA_BOND_UPDELAY, int),
        ('bond-downdelay', Link.IFLA_BOND_DOWNDELAY, int),
        ('bond-use-carrier', Link.IFLA_BOND_USE_CARRIER,
         lambda x: int(utils.get_boolean_from_string(x))),
        ('bond-lacp-rate', Link.IFLA_BOND_AD_LACP_RATE,
         lambda x: int(utils.get_boolean_from_string(x))),
        ('bond-lacp-bypass-allow', Link.IFLA_BOND_AD_LACP_BYPASS,
         lambda x: int(utils.get_boolean_from_string(x))),
        ('bond-ad-sys-mac-addr', Link.IFLA_BOND_AD_ACTOR_SYSTEM, str),
        ('bond-ad-actor-system', Link.IFLA_BOND_AD_ACTOR_SYSTEM, str),
    )

    def __init__(self, *args, **kargs):
        moduleBase.__init__(self, *args, **kargs)
        self.ipcmd = None
        self.bondcmd = None

        if not os.path.exists('/sys/class/net/bonding_masters'):
            try:
                utils.exec_command('modprobe -q bonding')
            except Exception as e:
                self.logger.info(
                    "bond: error while loading bonding module: %s" % str(e))

    @staticmethod
    def get_bond_slaves(ifaceobj):
        slaves = ifaceobj.get_attr_value_first('bond-slaves')
        if not slaves:
            slaves = ifaceobj.get_attr_value_first('bond-ports')
        return slaves

    def _is_bond(self, ifaceobj):
        # at first link_kind is not set but once ifupdownmain
        # calls get_dependent_ifacenames link_kind is set to BOND
        if ifaceobj.link_kind & ifaceLinkKind.BOND or self.get_bond_slaves(
                ifaceobj):
            return True
        return False

    def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
        """ Returns list of interfaces dependent on ifaceobj """

        if not self._is_bond(ifaceobj):
            return None
        slave_list = self.parse_port_list(ifaceobj.name,
                                          self.get_bond_slaves(ifaceobj),
                                          ifacenames_all)
        ifaceobj.dependency_type = ifaceDependencyType.MASTER_SLAVE
        # Also save a copy for future use
        ifaceobj.priv_data = list(slave_list)
        if ifaceobj.link_type != ifaceLinkType.LINK_NA:
            ifaceobj.link_type = ifaceLinkType.LINK_MASTER
        ifaceobj.link_kind |= ifaceLinkKind.BOND
        ifaceobj.role |= ifaceRole.MASTER

        return slave_list

    def syntax_check(self, ifaceobj, ifaceobj_getfunc):
        return self.syntax_check_updown_delay(ifaceobj)

    def get_dependent_ifacenames_running(self, ifaceobj):
        self._init_command_handlers()
        return self.bondcmd.bond_get_slaves(ifaceobj.name)

    def _get_slave_list(self, ifaceobj):
        """ Returns slave list present in ifaceobj config """

        # If priv data already has slave list use that first.
        if ifaceobj.priv_data:
            return ifaceobj.priv_data
        slaves = self.get_bond_slaves(ifaceobj)
        if slaves:
            return self.parse_port_list(ifaceobj.name, slaves)
        else:
            return None

    def _is_clag_bond(self, ifaceobj):
        if self.get_bond_slaves(ifaceobj):
            attrval = ifaceobj.get_attr_value_first('clag-id')
            if attrval and attrval != '0':
                return True
        return False

    def _add_slaves(self, ifaceobj, ifaceobj_getfunc=None):
        runningslaves = []

        slaves = self._get_slave_list(ifaceobj)
        if not slaves:
            self.logger.debug('%s: no slaves found' % ifaceobj.name)
            return

        if not ifupdownflags.flags.PERFMODE:
            runningslaves = self.bondcmd.bond_get_slaves(ifaceobj.name)

        clag_bond = self._is_clag_bond(ifaceobj)

        for slave in Set(slaves).difference(Set(runningslaves)):
            if (not ifupdownflags.flags.PERFMODE
                    and not self.ipcmd.link_exists(slave)):
                self.log_error('%s: skipping slave %s, does not exist' %
                               (ifaceobj.name, slave),
                               ifaceobj,
                               raise_error=False)
                continue
            link_up = False
            if self.ipcmd.is_link_up(slave):
                netlink.link_set_updown(slave, "down")
                link_up = True
            # If clag bond place the slave in a protodown state; clagd
            # will protoup it when it is ready
            if clag_bond:
                try:
                    netlink.link_set_protodown(slave, "on")
                except Exception, e:
                    self.logger.error('%s: %s' % (ifaceobj.name, str(e)))
            netlink.link_set_master(slave, ifaceobj.name)
            if link_up or ifaceobj.link_type != ifaceLinkType.LINK_NA:
                try:
                    if (ifaceobj_getfunc(slave)[0].link_privflags
                            & ifaceLinkPrivFlags.KEEP_LINK_DOWN):
                        netlink.link_set_updown(slave, "down")
                    else:
                        netlink.link_set_updown(slave, "up")
                except Exception, e:
                    self.logger.debug('%s: %s' % (ifaceobj.name, str(e)))
                    pass