]> git.proxmox.com Git - mirror_ifupdown2.git/commitdiff
Add support GRE/SIT tunnels. (#20)
authorMaximilian Wilhelm <max+gh@rfc2324.org>
Sat, 28 Jan 2017 22:54:43 +0000 (23:54 +0100)
committerJulien Fortin <julien@cumulusnetworks.com>
Tue, 13 Mar 2018 03:50:31 +0000 (14:50 +1100)
This commit adds support for configuring GRE/IPIP/SIT tunnel interfaces as know
from previous versions of ifupdown. Currently only configuration checks for GRE
and SIT tunnels are implemented.

A tunnel interface configuration could look like this:

auto gre42
iface gre42 inet tunnel
        mode     gre
        local    198.51.100.1
        endpoint 203.0.113.2
#
# optional tunnel attributes
        ttl      64
        mtu      1400
tunnel-physdev eth0
        #
        address  192.0.2.42/31
        address  2001:db8:d0c:23::42/64

auto he-ipv6
iface he-ipv6 inet tunnel
mode sit
endpoint 203.0.113.6
local    198.51.100.66
#
# optional tunnel attributes
ttl 255
mtu 1466
tunnel-physdev vrf_external
#
address 2001:db8:666::2/64

Signed-off-by: Maximilian Wilhelm <max@rfc2324.org>
addons/tunnel.py [new file with mode: 0644]
config/addons.conf
ifupdown/networkinterfaces.py
ifupdownaddons/iproute2.py
setup.py

diff --git a/addons/tunnel.py b/addons/tunnel.py
new file mode 100644 (file)
index 0000000..35e3c91
--- /dev/null
@@ -0,0 +1,151 @@
+#!/usr/bin/python
+#
+# Maximilian Wilhelm <max@rfc2324.org>
+#  --  Mon 10 Oct 2016 10:53:13 PM CEST
+#
+
+from ifupdown.iface import *
+from ifupdownaddons.modulebase import moduleBase
+from ifupdownaddons.iproute2 import iproute2
+import ifupdown.ifupdownflags as ifupdownflags
+import logging
+
+#
+# TODO: Add checks for ipip tunnels.
+#
+class tunnel (moduleBase):
+    _modinfo = { 'mhelp' : 'create/configure GRE/IPIP/SIT tunnel interfaces',
+                 'attrs' : {
+                   'mode' :
+                        { 'help' : 'type of tunnel as in \'ip link\' command.',
+                          'validvals' : ['gre' 'ipip', 'sit'],
+                          'required' : True,
+                          'example' : ['mode gre']},
+                   'local' :
+                        { 'help' : 'IP of local tunnel endpoint',
+                          'validvals' : ['<ipv4>', '<ipv6>'],
+                          'required' : True,
+                          'example' : ['local 192.2.0.42']},
+                   'endpoint' :
+                        { 'help' : 'IP of remote tunnel endpoint',
+                          'validvals' : ['<ipv4>', '<ipv6>'],
+                          'required' : True,
+                          'example' : ['endpoint 192.2.0.23']},
+                   'ttl' :
+                        { 'help' : 'TTL for tunnel packets',
+                          'validvals' : ['<number>'],
+                          'required' : False,
+                          'example' : ['ttl 64']},
+                   'tunnel-physdev' :
+                        { 'help' : 'Physical underlay device to use for tunnel packets',
+                          'validvals' : ['<interface>'],
+                          'required' : False,
+                          'example' : ['tunnel-physdev eth1']},
+                 }
+               }
+
+
+    def __init__ (self, *args, **kargs):
+        moduleBase.__init__ (self, *args, **kargs)
+        self.ipcmd = None
+
+
+    def _is_my_interface (self, ifaceobj):
+        if ifaceobj.addr_method == "tunnel" and ifaceobj.get_attr_value_first ('mode'):
+            return True
+        return False
+
+
+    def _up (self, ifaceobj):
+        attr_map = {
+            # attr_name -> ip route param name
+            'local' : 'local',
+            'endpoint' : 'remote',
+            'ttl' : 'ttl',
+            'tunnel-physdev' : 'dev',
+        }
+
+        mode = ifaceobj.get_attr_value_first ('mode')
+        attrs = {}
+
+        # Only include attributes which have been set and map ifupdown2 names
+        # to attribute names expected by iproute
+        for attr, iproute_attr in attr_map.items ():
+            attr_val = ifaceobj.get_attr_value_first (attr)
+            if attr_val != None:
+                attrs[iproute_attr] = attr_val
+
+        self.ipcmd.link_create (ifaceobj.name, mode, attrs)
+
+
+    def _down (self, ifaceobj):
+        if not ifupdownflags.flags.PERFMODE and not self.ipcmd.link_exists (ifaceobj.name):
+           return
+        try:
+            self.ipcmd.link_delete (ifaceobj.name)
+        except Exception, e:
+            self.log_warn (str (e))
+
+
+    def _query_check_n_update (self, ifaceobj, ifaceobjcurr, attrname, attrval,
+                               running_attrval):
+        if not ifaceobj.get_attr_value_first (attrname):
+            return
+
+        if running_attrval and attrval == running_attrval:
+           ifaceobjcurr.update_config_with_status (attrname, attrval, 0)
+        else:
+           ifaceobjcurr.update_config_with_status (attrname, running_attrval, 1)
+
+
+    def _query_check (self, ifaceobj, ifaceobjcurr):
+        if not self.ipcmd.link_exists (ifaceobj.name):
+            return
+
+        tunattrs = self.ipcmd.link_get_linkinfo_attrs (ifaceobj.name)
+        if not tunattrs:
+            ifaceobjcurr.check_n_update_config_with_status_many (ifaceobj, self.get_mod_attrs (), -1)
+            return
+
+        for attr in self.get_mod_attrs ():
+            if not ifaceobj.get_attr_value_first (attr):
+                continue
+
+            # Validate all interface attributes set in the config.
+            # Remote any leading 'tunnel-' prefix in front of the attr name
+            # when accessing tunattrs parsed from 'ip -d link'.
+            self._query_check_n_update (ifaceobj, ifaceobjcurr, attr,
+                                        ifaceobj.get_attr_value_first (attr),
+                                        tunattrs.get (attr.replace ("tunnel-", "")))
+
+
+    # Operations supported by this addon (yet).
+    _run_ops = {
+        'pre-up' : _up,
+        'post-down' : _down,
+        'query-checkcurr' : _query_check
+    }
+
+
+    def get_ops (self):
+        return self._run_ops.keys()
+
+
+    def _init_command_handlers (self):
+        if not self.ipcmd:
+            self.ipcmd = iproute2 ()
+
+
+    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)
index 4ae19a73056454089fdadfcf93b15f965c28e5ac..fa4b23f2fcbe5b27ea1e2b725264f074b3252918 100644 (file)
@@ -1,4 +1,5 @@
 pre-up,link
+pre-up,tunnel
 pre-up,bond
 pre-up,batman_adv
 pre-up,vlan
@@ -35,3 +36,4 @@ post-down,bond
 post-down,batman_adv
 post-down,usercmds
 post-down,link
+post-down,tunnel
index 6de8468ed7c21c283af310edb635f5a3929e24d1..a12005d91b4ebe5acaec7d7573689d4b58f2abaf 100644 (file)
@@ -27,8 +27,8 @@ class networkInterfaces():
     callbacks = {}
     auto_all = False
 
-    _addrfams = {'inet' : ['static', 'manual', 'loopback', 'dhcp', 'dhcp6'],
-                 'inet6' : ['static', 'manual', 'loopback', 'dhcp', 'dhcp6']}
+    _addrfams = {'inet' : ['static', 'manual', 'loopback', 'dhcp', 'dhcp6', 'tunnel'],
+                 'inet6' : ['static', 'manual', 'loopback', 'dhcp', 'dhcp6', 'tunnel']}
 
     def __init__(self, interfacesfile='/etc/network/interfaces',
                  interfacesfileiobuf=None, interfacesfileformat='native',
index 00c79d9c282244c80f1452fb886560b2591aa3a0..1ae385dd2d58db61c255d34dd2022a3af74c4838 100644 (file)
@@ -103,6 +103,24 @@ class iproute2(utilsBase):
                         linkattrs['state'] = citems[i + 1]
                     elif citems[i] == 'link/ether':
                         linkattrs['hwaddress'] = citems[i + 1]
+                    elif citems[i] in [ 'link/gre', 'link/sit' ]:
+                        linkattrs['kind'] = 'tunnel'
+                        tunattrs = {'mode' : citems[i].split ('/')[1],
+                                    'endpoint' : None,
+                                    'local' : None,
+                                    'ttl' : None,
+                                    'physdev' : None}
+                        for j in range(i + 2, len(citems)):
+                            if citems[j] == 'local':
+                                tunattrs['local'] = citems[j + 1]
+                            elif citems[j] == 'remote':
+                                tunattrs['endpoint'] = citems[j + 1]
+                            elif citems[j] == 'ttl':
+                                tunattrs['ttl'] = citems[j + 1]
+                            elif citems[j] == 'dev':
+                                tunattrs['physdev'] = citems[j + 1]
+                        linkattrs['linkinfo'] = tunattrs
+                        break
                     elif citems[i] == 'vlan':
                         vlanid = self._get_vland_id(citems, i, warn)
                         if vlanid:
index 7cffe28ff04e1ff5ec2b110eaa3bba51b2a0194b..d54133f2376b7dfba683bd39b0da41f4cd0879f1 100755 (executable)
--- a/setup.py
+++ b/setup.py
@@ -16,7 +16,7 @@ setup(name='ifupdown2',
                       'addons/dhcp.py', 'addons/usercmds.py',
                       'addons/ethtool.py',
                       'addons/addressvirtual.py', 'addons/vxlan.py',
-                      'addons/link.py', 'addons/vrf.py',
+                      'addons/link.py', 'addons/tunnel.py', 'addons/vrf.py',
                       'addons/bridgevlan.py', 'addons/batman_adv.py']),
                    ('/usr/share/ifupdown2/nlmanager/',
                     ['nlmanager/nllistener.py',