Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

addons: vxlan: add vxlan-local-tunnelip6 #182

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 107 additions & 12 deletions ifupdown2/addons/vxlan.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ class vxlan(Addon, moduleBase):
"validvals": ["<ipv4>"],
"example": ["vxlan-local-tunnelip 172.16.20.103"]
},
"vxlan-local-tunnelip6": {
"help": "vxlan local tunnel ip",
"validvals": ["<ipv6>"],
"example": ["vxlan-local-tunnelip6 2001:DB8::20:103"]
},
"vxlan-svcnodeip": {
"help": "vxlan svc node id",
"validvals": ["<ipv4>"],
Expand Down Expand Up @@ -131,6 +136,7 @@ def __init__(self, *args, **kargs):
)
)
self._vxlan_local_tunnelip = None
self._vxlan_local_tunnelip6 = None
self._clagd_vxlan_anycast_ip = ""

# If mcastgrp is specified we need to rely on a user-configred device (via physdev)
Expand All @@ -150,14 +156,18 @@ def reset(self):

def syntax_check(self, ifaceobj, ifaceobj_getfunc):
if self._is_vxlan_device(ifaceobj):
if not ifaceobj.get_attr_value_first('vxlan-local-tunnelip') and not self._vxlan_local_tunnelip:
self.logger.warning('%s: missing vxlan-local-tunnelip' % ifaceobj.name)
if not ifaceobj.get_attr_value_first('vxlan-local-tunnelip') and not self._vxlan_local_tunnelip \
and not ifaceobj.get_attr_value_first('vxlan-local-tunnelip6') and not self._vxlan_local_tunnelip6:
self.logger.warning('%s: missing vxlan-local-tunnelip or vxlan-local-tunnelip6' % ifaceobj.name)
return False
return self.syntax_check_localip_anycastip_equal(
ifaceobj.name,
ifaceobj.get_attr_value_first('vxlan-local-tunnelip') or self._vxlan_local_tunnelip,
self._clagd_vxlan_anycast_ip
)
) or self.syntax_check_localip_anycastip_equal(
ifaceobj.name,
ifaceobj.get_attr_value_first('vxlan-local-tunnelip6') or self._vxlan_local_tunnelip6,
self._clagd_vxlan_anycast_ip)
return True

def syntax_check_localip_anycastip_equal(self, ifname, local_ip, anycast_ip):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The syntax check will still report "tunnelip" even if tunnelip6 is identical to clagd-vxlan-anycast-ip.

I am unsure wether clagd-vxlan-anycast-ip could even be IPv6 or (if that is not the case) how this should be properly refactored.

Expand Down Expand Up @@ -207,6 +217,10 @@ def _set_global_local_ip(self, ifaceobj):
if vxlan_local_tunnel_ip and not self._vxlan_local_tunnelip:
self._vxlan_local_tunnelip = vxlan_local_tunnel_ip

vxlan_local_tunnel_ip6 = ifaceobj.get_attr_value_first('vxlan-local-tunnelip6')
if vxlan_local_tunnel_ip6 and not self._vxlan_local_tunnelip6:
self._vxlan_local_tunnelip6 = vxlan_local_tunnel_ip6

@staticmethod
def _is_vxlan_device(ifaceobj):
return ifaceobj.link_kind & ifaceLinkKind.VXLAN \
Expand Down Expand Up @@ -394,6 +408,7 @@ def __config_vxlan_local_tunnelip(self, ifname, ifaceobj, link_exists, user_requ
# 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)
running_localtunnelip6 = cached_vxlan_ifla_info_data.get(Link.IFLA_VXLAN_LOCAL6)

if self._clagd_vxlan_anycast_ip and running_localtunnelip:
anycastip = ipnetwork.IPNetwork(self._clagd_vxlan_anycast_ip)
Expand Down Expand Up @@ -431,6 +446,62 @@ def __config_vxlan_local_tunnelip(self, ifname, ifaceobj, link_exists, user_requ

return local

def __config_vxlan_local_tunnelip6(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:
"""
local6 = ifaceobj.get_attr_value_first("vxlan-local-tunnelip6")

if not local6 and self._vxlan_local_tunnelip6:
local6 = self._vxlan_local_tunnelip6

if link_exists:
# on ifreload do not overwrite anycast_ip to individual ip
# if clagd has modified
running_localtunnelip6 = cached_vxlan_ifla_info_data.get(Link.IFLA_VXLAN_LOCAL6)

if self._clagd_vxlan_anycast_ip and running_localtunnelip6:
anycastip = ipnetwork.IPNetwork(self._clagd_vxlan_anycast_ip)
if anycastip == running_localtunnelip6:
local6 = running_localtunnelip6

if not local6:
local6 = policymanager.policymanager_api.get_attr_default(
module_name=self.__class__.__name__,
attr="vxlan-local-tunnelip6"
)

if local6:
try:
local6 = ipnetwork.IPv6Address(local6)

if local6.initialized_with_prefixlen:
self.logger.warning("%s: vxlan-local-tunnelip6 %s: netmask ignored" % (ifname, local6))

except Exception as e:
raise Exception("%s: invalid vxlan-local-tunnelip6 %s: %s" % (ifname, local6, str(e)))

cached_ifla_vxlan_local6 = cached_vxlan_ifla_info_data.get(Link.IFLA_VXLAN_LOCAL6)

if local6:
if local6 != cached_ifla_vxlan_local6:
self.logger.info("%s: set vxlan-local-tunnelip6 %s" % (ifname, local6))
user_request_vxlan_info_data[Link.IFLA_VXLAN_LOCAL6] = local6

# if both local-ip and anycast-ip are identical the function prints a warning
self.syntax_check_localip_anycastip_equal(ifname, local6, self._clagd_vxlan_anycast_ip)
elif cached_ifla_vxlan_local6:
self.logger.info("%s: removing vxlan-local-tunnelip6 (cache %s)" % (ifname, cached_ifla_vxlan_local6))
user_request_vxlan_info_data[Link.IFLA_VXLAN_LOCAL6] = None

return local6

def __get_vxlan_attribute(self, ifaceobj, attr_name):
vxlan_attr_value = ifaceobj.get_attr_value_first(attr_name)

Expand Down Expand Up @@ -745,6 +816,7 @@ def _up(self, ifaceobj):
self.__config_vxlan_port(ifname, ifaceobj, link_exists, user_request_vxlan_info_data, cached_vxlan_ifla_info_data)
self.__config_vxlan_ttl(ifname, ifaceobj, user_request_vxlan_info_data, cached_vxlan_ifla_info_data)
local = self.__config_vxlan_local_tunnelip(ifname, ifaceobj, link_exists, user_request_vxlan_info_data, cached_vxlan_ifla_info_data)
local6 = self.__config_vxlan_local_tunnelip6(ifname, ifaceobj, link_exists, user_request_vxlan_info_data, cached_vxlan_ifla_info_data)

vxlan_mcast_grp = self.__get_vxlan_attribute(ifaceobj, "vxlan-mcastgrp")
vxlan_svcnodeip = self.__get_vxlan_attribute(ifaceobj, "vxlan-svcnodeip")
Expand Down Expand Up @@ -980,23 +1052,45 @@ def _query_check(self, ifaceobj, ifaceobjcurr):
#
# 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
running_local_tunnelip = cached_vxlan_ifla_info_data.get(Link.IFLA_VXLAN_LOCAL)
local_tunnelip = ifaceobj.get_attr_value_first('vxlan-local-tunnelip')
if not local_tunnelip:
local_tunnelip = self._vxlan_local_tunnelip
# TODO: vxlan._vxlan_local_tunnelip should be a ipnetwork.IPNetwork obj
ifaceobj.update_config('vxlan-local-tunnelip', attrval)
ifaceobj.update_config('vxlan-local-tunnelip', local_tunnelip)

if str(running_attrval) == self._clagd_vxlan_anycast_ip:
if str(running_local_tunnelip) == self._clagd_vxlan_anycast_ip:
# if local ip is anycast_ip, then let query_check to go through
attrval = self._clagd_vxlan_anycast_ip
local_tunnelip = 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
str(local_tunnelip),
str(running_local_tunnelip.ip) if running_local_tunnelip else None
)

#
# vxlan-local-tunnelip6
#
running_local_tunnelip6 = cached_vxlan_ifla_info_data.get(Link.IFLA_VXLAN_LOCAL6)
local_tunnelip6 = ifaceobj.get_attr_value_first('vxlan-local-tunnelip6')
if not local_tunnelip6:
local_tunnelip6 = self._vxlan_local_tunnelip6
# TODO: vxlan._vxlan_local_tunnelip6 should be a ipnetwork.IPNetwork obj
ifaceobj.update_config('vxlan-local-tunnelip6', local_tunnelip6)

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

self._query_check_n_update(
ifaceobj,
ifaceobjcurr,
'vxlan-local-tunnelip6',
str(local_tunnelip6),
str(running_local_tunnelip6.ip) if running_local_tunnelip6 else None
)

#
Expand Down Expand Up @@ -1081,6 +1175,7 @@ def _query_running(self, ifaceobjrunning):
('vxlan-ageing', Link.IFLA_VXLAN_AGEING, str),
('vxlan-learning', Link.IFLA_VXLAN_LEARNING, lambda value: 'on' if value else 'off'),
('vxlan-local-tunnelip', Link.IFLA_VXLAN_LOCAL, str),
('vxlan-local-tunnelip6', Link.IFLA_VXLAN_LOCAL6, str),
):
vxlan_attr_value = cached_vxlan_ifla_info_data.get(vxlan_attr_nl)

Expand Down