This commit adds support for the new IPSec Interface XFRM.
+pre-up,xfrm
pre-up,link
pre-up,ppp
pre-up,bond
post-down,usercmds
post-down,link
post-down,tunnel
+post-down,xfrm
\ No newline at end of file
--- /dev/null
+#!/usr/bin/python
+#
+# Copyright 2019 Voleatech GmbH. All rights reserved.
+# Author: Sven Auhagen, sven.auhagen@voleatech.de
+#
+
+import os
+import glob
+import socket
+
+from ipaddr import IPNetwork, IPv6Network
+
+try:
+ from ifupdown2.ifupdown.iface import *
+ from ifupdown2.ifupdown.utils import utils
+ from ifupdown2.ifupdown.netlink import netlink
+
+ from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
+ from ifupdown2.ifupdownaddons.modulebase import moduleBase
+
+ import ifupdown2.ifupdown.statemanager as statemanager
+ import ifupdown2.ifupdown.policymanager as policymanager
+ import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
+ import ifupdown2.ifupdown.ifupdownconfig as ifupdownconfig
+except ImportError:
+ from ifupdown.iface import *
+ from ifupdown.utils import utils
+ from ifupdown.netlink import netlink
+
+ from ifupdownaddons.LinkUtils import LinkUtils
+ from ifupdownaddons.modulebase import moduleBase
+
+ import ifupdown.statemanager as statemanager
+ import ifupdown.policymanager as policymanager
+ import ifupdown.ifupdownflags as ifupdownflags
+ import ifupdown.ifupdownconfig as ifupdownconfig
+
+
+class xfrm(moduleBase):
+ """ ifupdown2 addon module to create a xfrm interface """
+ _modinfo = {'mhelp' : 'xfrm module creates a xfrm interface for',
+ 'attrs' : {
+ 'xfrm-id' :
+ { 'help' : 'xfrm id',
+ 'validrange' : ['1', '65535'],
+ 'example': ['xfrm-id 1']
+ },
+ 'xfrm-physdev':
+ {'help': 'xfrm physical device',
+ 'example': ['xfrm-physdev lo']
+ },
+ },
+ }
+
+
+ def __init__(self, *args, **kargs):
+ moduleBase.__init__(self, *args, **kargs)
+ self.ipcmd = None
+
+ def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
+
+ parent_int = self._get_parent_ifacename(ifaceobj)
+ if parent_int:
+ return [parent_int]
+
+ return None
+
+ def _get_parent_ifacename(self, ifaceobj):
+ if ifaceobj.get_attr_value('xfrm-physdev'):
+ av_attr = ifaceobj.get_attr_value_first('xfrm-physdev')
+ return av_attr
+
+ return None
+
+ def _get_xfrmid(self, ifaceobj):
+ if ifaceobj.get_attr_value('xfrm-id'):
+ av_attr = ifaceobj.get_attr_value_first('xfrm-id')
+ return av_attr
+
+ return None
+
+ def _get_xfrm_name(self, ifaceobj):
+ return ifaceobj.name
+
+ @staticmethod
+ def _is_my_interface(ifaceobj):
+ return ifaceobj.get_attr_value_first('xfrm-id')
+
+ def _up(self, ifaceobj):
+ """
+ Up the XFRM Interface
+ """
+ # Create a xfrm device on this device and set the virtual
+ # router mac and ip on it
+ link_created = False
+ xfrm_ifacename = self._get_xfrm_name(ifaceobj)
+ physdev = self._get_parent_ifacename(ifaceobj)
+ xfrmid = self._get_xfrmid(ifaceobj)
+ if not self.ipcmd.link_exists(xfrm_ifacename):
+ try:
+ netlink.link_add_xfrm(physdev, xfrm_ifacename, xfrmid)
+ except:
+ self.ipcmd.link_add_xfrm(physdev, xfrm_ifacename, xfrmid)
+ link_created = True
+ else:
+ current_attrs = self.ipcmd.link_get_linkinfo_attrs(ifaceobj.name)
+ xfrmid_cur = current_attrs.get('xfrm-id', None)
+ physdev_cur = current_attrs.get('xfrm-physdev', None)
+ # Check XFRM Values
+ if xfrmid != xfrmid_cur or physdev != physdev_cur:
+ # Delete and recreate
+ self.ipcmd.link_delete(xfrm_ifacename)
+ try:
+ netlink.link_add_xfrm(physdev, xfrm_ifacename, xfrmid)
+ except:
+ self.ipcmd.link_add_xfrm(physdev, xfrm_ifacename, xfrmid)
+ link_created = True
+
+ def _down(self, ifaceobj, ifaceobj_getfunc=None):
+ """
+ Down the XFRM Interface
+ """
+ try:
+ xfrm_ifacename = self._get_xfrm_name(ifaceobj)
+ self.ipcmd.link_delete(xfrm_ifacename)
+ except Exception, e:
+ self.log_warn(str(e))
+
+ def _query_check(self, ifaceobj, ifaceobjcurr):
+ if not self.ipcmd.link_exists(ifaceobj.name):
+ return
+ ifaceobjcurr.status = ifaceStatus.SUCCESS
+
+ def _query_running(self, ifaceobjrunning):
+ if not self.ipcmd.link_exists(ifaceobjrunning.name):
+ return
+
+ # Operations supported by this addon (yet).
+ _run_ops = {
+ 'pre-up': _up,
+ 'post-down': _down,
+ 'query-checkcurr': _query_check,
+ 'query-running': _query_running,
+ }
+
+ def get_ops(self):
+ return self._run_ops.keys()
+
+ def _init_command_handlers(self):
+ if not self.ipcmd:
+ self.ipcmd = LinkUtils()
+
+ def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
+ op_handler = self._run_ops.get(operation)
+
+ if not op_handler:
+ return
+
+ if operation != 'query-running' and not self._is_my_interface(ifaceobj):
+ return
+
+ self._init_command_handlers()
+ if operation == 'query-checkcurr':
+ op_handler(self, ifaceobj, query_ifaceobj)
+ else:
+ op_handler(self, ifaceobj)
'sit': self._link_dump_info_data_iptun_tunnel,
'ip6tnl': self._link_dump_info_data_iptun_tunnel,
'vti': self._link_dump_info_data_vti_tunnel,
- 'vti6': self._link_dump_info_data_vti_tunnel
+ 'vti6': self._link_dump_info_data_vti_tunnel,
+ 'xfrm': self._link_dump_info_data_xfrm
}
except Exception as e:
except Exception as e:
raise Exception('netlink: %s: cannot create macvlan %s: %s'
% (ifacename, macvlan_ifacename, str(e)))
+
+ def link_add_xfrm(self, ifacename, xfrm_ifacename, xfrm_id):
+ self.logger.info('%s: netlink: ip link add %s type xfrm dev %s if_id %s'
+ % (xfrm_ifacename, xfrm_ifacename, ifacename, xfrm_id))
+ if ifupdownflags.flags.DRYRUN: return
+ ifindex = self.get_iface_index(ifacename)
+ try:
+ return self._nlmanager_api.link_add_xfrm(ifindex, xfrm_ifacename, xfrm_id)
+ except Exception as e:
+ raise Exception('netlink: %s: cannot create xfrm %s id %s: %s'
+ % (ifacename, xfrm_ifacename, xfrm_id, str(e)))
def link_set_updown(self, ifacename, state):
self.logger.info('%s: netlink: ip link set dev %s %s'
"tunnel-physdev": self.get_iface_name(tunnel_link_ifindex) if tunnel_link_ifindex else ""
}
+ def _link_dump_info_data_xfrm(self, ifname, linkdata):
+ xfrm_physdev_link_ifindex = linkdata.get(Link.IFLA_XFRM_LINK)
+
+ return {
+ 'xfrm-id': str(linkdata.get(Link.IFLA_XFRM_IF_ID, '')),
+ 'xfrm-physdev': self.get_iface_name(xfrm_physdev_link_ifindex) if xfrm_physdev_link_ifindex else ""
+ }
+
def _link_dump_linkinfo(self, link, dump):
linkinfo = link.attributes[Link.IFLA_LINKINFO].get_pretty_value(dict)
break
elif citems[i] == 'macvlan' and citems[i + 1] == 'mode':
linkattrs['kind'] = 'macvlan'
+ elif citems[i] == 'xfrm':
+ linkattrs['kind'] = 'xfrm'
except Exception as e:
if warn:
self.logger.debug('%s: parsing error: id, mtu, state, '
def link_add_macvlan(ifname, macvlan_ifacename, mode):
utils.exec_commandl(['ip', 'link', 'add', 'link', ifname, 'name', macvlan_ifacename, 'type', 'macvlan', 'mode', mode])
+ @staticmethod
+ def link_add_xfrm(ifname, xfrm_name, xfrm_id):
+ utils.exec_commandl(['ip', 'link', 'add', xfrm_name, 'type', 'xfrm', 'dev', ifname, 'if_id', xfrm_id])
+
@staticmethod
def route_add(route):
utils.exec_command('%s route add %s' % (utils.ip_cmd,
"""
return self._link_add(ifindex, ifname, 'macvlan', {Link.IFLA_MACVLAN_MODE: Link.MACVLAN_MODE_PRIVATE})
+ def link_add_xfrm(self, physdev, xfrm_ifname, xfrm_id):
+ """
+ ifindex is the index of the parent interface that this sub-interface
+ is being added to
+ """
+ ifla_info_data = {
+ Link.IFLA_XFRM_IF_ID: int(xfrm_id),
+ Link.IFLA_XFRM_LINK: int(physdev)
+ }
+
+ return self._link_add(ifindex=None, ifname=xfrm_ifname, kind='xfrm', ifla_info_data=ifla_info_data)
+
def vlan_get(self, filter_ifindex=None, filter_vlanid=None, compress_vlans=True):
"""
filter_ifindex should be a tuple if interface indexes, this is a whitelist filter
kind = self.value.get(Link.IFLA_INFO_KIND)
slave_kind = self.value.get(Link.IFLA_INFO_SLAVE_KIND)
- if not slave_kind and kind not in ('vlan', 'macvlan', 'vxlan', 'bond', 'bridge'):
+ if not slave_kind and kind not in ('vlan', 'macvlan', 'vxlan', 'bond', 'bridge', 'xfrm'):
raise Exception('Unsupported IFLA_INFO_KIND %s' % kind)
elif not kind and slave_kind != 'bridge':
# only support brport for now.
else:
self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for encoding IFLA_INFO_DATA macvlan sub-attribute type %d' % info_data_type)
+ elif kind == 'xfrm':
+ if info_data_type in (Link.IFLA_XFRM_IF_ID, Link.IFLA_XFRM_LINK):
+ sub_attr_pack_layout.append('HH')
+ sub_attr_payload.append(8) # length
+ sub_attr_payload.append(info_data_type)
+
+ sub_attr_pack_layout.append('L')
+ sub_attr_payload.append(info_data_value)
+
elif kind == 'vxlan':
if info_data_type in (Link.IFLA_VXLAN_ID,
Link.IFLA_VXLAN_LINK,
self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for decoding IFLA_INFO_KIND macvlan type %s (%d), length %d, padded to %d' %
(parent_msg.get_ifla_macvlan_string(info_data_type), info_data_type, info_data_length, info_data_end))
+ elif ifla_info_kind == 'xfrm':
+ # 4-byte int
+ if info_data_type in (Link.IFLA_XFRM_IF_ID, Link.IFLA_XFRM_LINK):
+ self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=L', sub_attr_data[4:8])[0]
+
elif ifla_info_kind == 'vxlan':
# IPv4Address
'vti6': Link.ifla_vti_to_string,
'ipip': Link.ifla_iptun_to_string,
'sit': Link.ifla_iptun_to_string,
- 'ip6tnl': Link.ifla_iptun_to_string
+ 'ip6tnl': Link.ifla_iptun_to_string,
+ 'xfrm': Link.ifla_xfrm_to_string
}.get(ifla_info_kind, {})
kind_dict[Link.IFLA_INFO_SLAVE_DATA] = {
MACVLAN_MODE_PASSTHRU : 'MACVLAN_MODE_PASSTHRU'
}
+ # =========================================
+ # IFLA_INFO_DATA attributes for xfrm
+ # =========================================
+ IFLA_XFRM_UNSPEC = 0
+ IFLA_XFRM_LINK = 1
+ IFLA_XFRM_IF_ID = 2
+
+ ifla_xfrm_to_string = {
+ IFLA_XFRM_UNSPEC : 'IFLA_XFRM_UNSPEC',
+ IFLA_XFRM_LINK : 'IFLA_XFRM_LINK',
+ IFLA_XFRM_IF_ID : 'IFLA_XFRM_IF_ID'
+ }
+
# =========================================
# IFLA_INFO_DATA attributes for vxlan
# =========================================
def get_ifla_macvlan_string(self, index):
return self.get_string(self.ifla_macvlan_to_string, index)
+ def get_ifla_xfrm_string(self, index):
+ return self.get_string(self.ifla_xfrm_to_string, index)
+
def get_macvlan_mode_string(self, index):
return self.get_string(self.macvlan_mode_to_string, index)