def syntax_check_localip_anycastip_equal(self, ifname, local_ip, anycast_ip): try: if local_ip and anycast_ip and ipnetwork.IPNetwork(local_ip) == ipnetwork.IPNetwork(anycast_ip): self.logger.warning('%s: vxlan-local-tunnelip and clagd-vxlan-anycast-ip are identical (%s)' % (ifname, local_ip)) return False except Exception: pass return True
class AddonWithIpBlackList(Addon): try: ip_blacklist = [ipnetwork.IPNetwork(ip).ip for ip in policymanager.policymanager_api.get_module_globals( module_name="address", attr="ip_blacklist" ) or []] __ip_blacklist_exception = None except Exception as e: __ip_blacklist_exception = e ip_blacklist = [] def __init__(self): """ If an exception occurred during the ip blacklist parsing we need to display it (once) Also we keep this as a class variable to share it between the address and addressvirtual module """ super(AddonWithIpBlackList, self).__init__() if AddonWithIpBlackList.__ip_blacklist_exception: self.logger.warning("policy.d: address: 'ip_blacklist': %s" % AddonWithIpBlackList.__ip_blacklist_exception) AddonWithIpBlackList.__ip_blacklist_exception = None def ip_blacklist_check(self, ifname, ip): """ Check if the ip address is not blacklisted (in ip_blacklist) :param ifname: :param ip: :return: """ if ip.ip in AddonWithIpBlackList.ip_blacklist: raise Exception("%s: blacklisted ip address in use: %s" % (ifname, ip.ip))
def convert_user_config_to_ipnetwork(self, user_config, attr_name): """ Ideally this convertion should be done by ifupdown2 at a lower level (after parsing /e/n/i) and should be done directly on each ifaceobj. """ try: user_config[attr_name] = ipnetwork.IPNetwork(user_config[attr_name]) except Exception: pass
def __config_vxlan_local_tunnelip(self, ifname, ifaceobj, link_exists, user_request_vxlan_info_data, cached_vxlan_ifla_info_data): """ Get vxlan-local-tunnelip user config or policy, validate ip address format and insert in netlink dict :param ifname: :param ifaceobj: :param link_exists: :param user_request_vxlan_info_data: :param cached_vxlan_ifla_info_data: :return: """ local = ifaceobj.get_attr_value_first("vxlan-local-tunnelip") if not local and self._vxlan_local_tunnelip: local = self._vxlan_local_tunnelip if link_exists: # on ifreload do not overwrite anycast_ip to individual ip # if clagd has modified running_localtunnelip = cached_vxlan_ifla_info_data.get(Link.IFLA_VXLAN_LOCAL) if self._clagd_vxlan_anycast_ip and running_localtunnelip: anycastip = ipnetwork.IPNetwork(self._clagd_vxlan_anycast_ip) if anycastip == running_localtunnelip: local = running_localtunnelip if not local: local = policymanager.policymanager_api.get_attr_default( module_name=self.__class__.__name__, attr="vxlan-local-tunnelip" ) if local: try: local = ipnetwork.IPv4Address(local) if local.initialized_with_prefixlen: self.logger.warning("%s: vxlan-local-tunnelip %s: netmask ignored" % (ifname, local)) except Exception as e: raise Exception("%s: invalid vxlan-local-tunnelip %s: %s" % (ifname, local, str(e))) cached_ifla_vxlan_local = cached_vxlan_ifla_info_data.get(Link.IFLA_VXLAN_LOCAL) if local: if local != cached_ifla_vxlan_local: self.logger.info("%s: set vxlan-local-tunnelip %s" % (ifname, local)) user_request_vxlan_info_data[Link.IFLA_VXLAN_LOCAL] = local # if both local-ip and anycast-ip are identical the function prints a warning self.syntax_check_localip_anycastip_equal(ifname, local, self._clagd_vxlan_anycast_ip) elif cached_ifla_vxlan_local: self.logger.info("%s: removing vxlan-local-tunnelip (cache %s)" % (ifname, cached_ifla_vxlan_local)) user_request_vxlan_info_data[Link.IFLA_VXLAN_LOCAL] = None return local
def translate_addrvirtual_user_config_to_list(self, ifaceobj, address_virtual_list): """ # Translate: # address-virtual 00:11:22:33:44:01 2001:0db8::0370:7334/64 11.0.1.1/24 11.0.1.2/24 # To: # [ # { # "ifname": "macvlan_ifname", # "hwaddress": "macvlan_hwaddress", # "ips": [str(IPNetwork), ] # }, # ] """ user_config_list = [] if not address_virtual_list: return user_config_list macvlan_prefix = self._get_macvlan_prefix(ifaceobj) for index, addr_virtual in enumerate(address_virtual_list): av_attrs = addr_virtual.split() mac = av_attrs[0] if mac: mac = mac.lower() if not self.check_mac_address(ifaceobj, mac): continue config = { "ifname": "%s%d" % (macvlan_prefix, index), "mode": "private" } if mac != "none": config["hwaddress"] = mac config["hwaddress_int"] = utils.mac_str_to_int(mac) ip_network_obj_list = [] for ip in av_attrs[1:]: ip_network_obj_list.append(ipnetwork.IPNetwork(ip)) config["ips"] = ip_network_obj_list user_config_list.append(config) return user_config_list
def __config_vxlan_group(self, ifname, ifaceobj, link_exists, mcast_grp, group, physdev, user_request_vxlan_info_data, cached_vxlan_ifla_info_data): """ vxlan-mcastgrp and vxlan-svcnodeip are mutually exclusive this function validates ip format for both attribute and tries to understand what the user really want (remote or group option). :param ifname: :param ifaceobj: :param mcast_grp: :param group: :param physdev: :param user_request_vxlan_info_data: :param cached_vxlan_ifla_info_data: :return: """ if mcast_grp and group: self.log_error( "%s: both group (vxlan-mcastgrp %s) and " "remote (vxlan-svcnodeip %s) cannot be specified" % (ifname, mcast_grp, group), ifaceobj) attribute_name = "vxlan-svcnodeip" multicast_group_change = False if group: try: group = ipnetwork.IPv4Address(group) if group.initialized_with_prefixlen: self.logger.warning( "%s: vxlan-svcnodeip %s: netmask ignored" % (ifname, group)) except Exception as e: raise Exception("%s: invalid vxlan-svcnodeip %s: %s" % (ifname, group, str(e))) if group.ip.is_multicast: self.logger.warning( "%s: vxlan-svcnodeip %s: invalid group address, " "for multicast IP please use attribute \"vxlan-mcastgrp\"" % (ifname, group)) # if svcnodeip is used instead of mcastgrp we warn the user # if mcast_grp is not provided by the user we can instead # use the svcnodeip value if not physdev: self.log_error( "%s: vxlan: 'group' (vxlan-mcastgrp) requires 'vxlan-physdev' to be specified" % (ifname)) elif mcast_grp: try: mcast_grp = ipnetwork.IPv4Address(mcast_grp) if mcast_grp.initialized_with_prefixlen: self.logger.warning( "%s: vxlan-mcastgrp %s: netmask ignored" % (ifname, mcast_grp)) except Exception as e: raise Exception("%s: invalid vxlan-mcastgrp %s: %s" % (ifname, mcast_grp, str(e))) if not mcast_grp.ip.is_multicast: self.logger.warning( "%s: vxlan-mcastgrp %s: invalid group address, " "for non-multicast IP please use attribute \"vxlan-svcnodeip\"" % (ifname, mcast_grp)) # if mcastgrp is specified with a non-multicast address # we warn the user. If the svcnodeip wasn't specified by # the user we can use the mcastgrp value as svcnodeip if not group: group = mcast_grp mcast_grp = None else: attribute_name = "vxlan-mcastgrp" if mcast_grp: group = mcast_grp if not physdev: self.log_error( "%s: vxlan: 'group' (vxlan-mcastgrp) requires 'vxlan-physdev' to be specified" % (ifname)) cached_ifla_vxlan_group = cached_vxlan_ifla_info_data.get( Link.IFLA_VXLAN_GROUP) if group != cached_ifla_vxlan_group: if not group: group = ipnetwork.IPNetwork("0.0.0.0") attribute_name = "vxlan-svcnodeip/vxlan-mcastgrp" self.logger.info("%s: set %s %s" % (ifname, attribute_name, group)) user_request_vxlan_info_data[Link.IFLA_VXLAN_GROUP] = group # if the mcastgrp address is changed we need to signal this to the upper function # in this case vxlan needs to be down before applying changes then up'd multicast_group_change = True if link_exists: if cached_ifla_vxlan_group: self.logger.info( "%s: vxlan-mcastgrp configuration changed (cache %s): flapping vxlan device required" % (ifname, cached_ifla_vxlan_group)) else: self.logger.info( "%s: vxlan-mcastgrp configuration changed: flapping vxlan device required" % ifname) return group, multicast_group_change
def translate_vrr_user_config_to_list(self, ifaceobj, vrr_config_list, ifquery=False): """ If (IPv4 addresses provided): 00:00:5e:00:01:<V> else if (IPv6 addresses provided): 00:00:5e:00:02:<V> vrrp 1 10.0.0.15/24 vrrp 1 2001:0db8::0370:7334/64 # Translate: # vrrp 255 10.0.0.15/24 10.0.0.2/1 # To: # [ # { # "ifname": "macvlan_ifname", # "hwaddress": "macvlan_hwaddress", # "mode": "macvlan_mode", # "ips": [str(IPNetwork), ] # }, # ] """ ifname = ifaceobj.name user_config_list = [] for index, config in enumerate(vrr_config_list or []): vrrp_id, ip_addrs = config.split(" ", 1) hex_id = '%02x' % int(vrrp_id) ip4 = [] ip6 = [] for ip_addr in ip_addrs.split(): ip_network_obj = ipnetwork.IPNetwork(ip_addr) is_ip6 = ip_network_obj.version == 6 if is_ip6: ip6.append(ip_network_obj) else: ip4.append(ip_network_obj) macvlan_ip4_ifname = "%s%s" % (self.get_vrrp_prefix(ifname, "4"), vrrp_id) macvlan_ip6_ifname = "%s%s" % (self.get_vrrp_prefix(ifname, "6"), vrrp_id) if ip4 or ifquery: merged_with_existing_obj = False macvlan_ip4_mac = "00:00:5e:00:01:%s" % hex_id macvlan_ip4_mac_int = utils.mac_str_to_int(macvlan_ip4_mac) # if the vrr config is defined in different lines for the same ID # we need to save the ip4 and ip6 in the objects we previously # created, example: # vrrp 255 10.0.0.15/24 10.0.0.2/15 # vrrp 255 fe80::a00:27ff:fe04:42/64 for obj in user_config_list: if obj.get("hwaddress_int") == macvlan_ip4_mac_int: obj["ips"] += ip4 merged_with_existing_obj = True if not merged_with_existing_obj: # if ip4 config wasn't merge with an existing object # we need to insert it in our list user_config_list.append({ "ifname": macvlan_ip4_ifname, "hwaddress": macvlan_ip4_mac, "hwaddress_int": macvlan_ip4_mac_int, "mode": "bridge", "ips": ip4, "id": vrrp_id }) elif not ip4 and not ifquery: # special check to see if all ipv4 were removed from the vrrp # configuration, if so we need to remove the associated macvlan if self.cache.link_exists(macvlan_ip4_ifname): self.netlink.link_del(macvlan_ip4_ifname) if ip6 or ifquery: merged_with_existing_obj = False macvlan_ip6_mac = "00:00:5e:00:02:%s" % hex_id macvlan_ip6_mac_int = utils.mac_str_to_int(macvlan_ip6_mac) # if the vrr config is defined in different lines for the same ID # we need to save the ip4 and ip6 in the objects we previously # created, example: # vrrp 255 10.0.0.15/24 10.0.0.2/15 # vrrp 255 fe80::a00:27ff:fe04:42/64 for obj in user_config_list: if obj.get("hwaddress_int") == macvlan_ip6_mac_int: obj["ips"] += ip6 merged_with_existing_obj = True if not merged_with_existing_obj: # if ip6 config wasn't merge with an existing object # we need to insert it in our list user_config_list.append({ "ifname": macvlan_ip6_ifname, "hwaddress": macvlan_ip6_mac, "hwaddress_int": macvlan_ip6_mac_int, "mode": "bridge", "ips": ip6, "id": vrrp_id }) elif not ip6 and not ifquery: # special check to see if all ipv6 were removed from the vrrp # configuration, if so we need to remove the associated macvlan if self.cache.link_exists(macvlan_ip6_ifname): self.netlink.link_del(macvlan_ip6_ifname) if not ifquery: # check if vrrp attribute was removed/re-assigned old_vrr_ids = set() try: for old_ifaceobj in statemanager.statemanager_api.get_ifaceobjs( ifname) or []: for vrr_config in old_ifaceobj.get_attr_value( "vrrp") or []: try: old_vrr_ids.add(vrr_config.split()[0]) except Exception: continue if old_vrr_ids: for config in user_config_list: try: old_vrr_ids.remove(config["id"]) except KeyError: pass for id_to_remove in old_vrr_ids: macvlan_ip4_ifname = "%s%s" % (self.get_vrrp_prefix( ifname, "4"), id_to_remove) macvlan_ip6_ifname = "%s%s" % (self.get_vrrp_prefix( ifname, "6"), id_to_remove) if self.cache.link_exists(macvlan_ip4_ifname): self.netlink.link_del(macvlan_ip4_ifname) if self.cache.link_exists(macvlan_ip6_ifname): self.netlink.link_del(macvlan_ip6_ifname) except Exception as e: self.logger.debug( "%s: vrrp: failure while removing unused macvlan(s)" % ifname) return user_config_list