]> git.proxmox.com Git - mirror_ifupdown2.git/blame - ifupdown2/addons/tunnel.py
addons: tunnel: fix tunnel creation (#80)- master branch refactoring
[mirror_ifupdown2.git] / ifupdown2 / addons / tunnel.py
CommitLineData
22aa65c7
MW
1#!/usr/bin/python
2#
3# Maximilian Wilhelm <max@rfc2324.org>
4# -- Mon 10 Oct 2016 10:53:13 PM CEST
5#
c3c78d97
JF
6try:
7 from ifupdown2.ifupdown.iface import *
73083400 8 from ifupdown2.ifupdown.netlink import netlink
c3c78d97 9
c3c78d97 10 from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
84ca91f1 11 from ifupdown2.ifupdownaddons.modulebase import moduleBase
c3c78d97
JF
12
13 import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
84ca91f1 14except ImportError:
c3c78d97 15 from ifupdown.iface import *
73083400 16 from ifupdown.netlink import netlink
c3c78d97 17
c3c78d97 18 from ifupdownaddons.LinkUtils import LinkUtils
84ca91f1 19 from ifupdownaddons.modulebase import moduleBase
c3c78d97
JF
20
21 import ifupdown.ifupdownflags as ifupdownflags
22
73083400 23
22aa65c7
MW
24#
25# TODO: Add checks for ipip tunnels.
26#
c3c78d97 27class tunnel(moduleBase):
84ca91f1
SA
28 """
29 ifupdown2 addon module to configure tunnels
30 """
c3c78d97
JF
31 _modinfo = {
32 'mhelp': 'create/configure GRE/IPIP/SIT and GRETAP tunnel interfaces',
33 'attrs': {
73083400
JF
34 'mode': {
35 'help': 'type of tunnel as in \'ip link\' command.',
36 'validvals': ['gre', 'gretap', 'ipip', 'sit', 'vti', 'ip6gre', 'ipip6', 'ip6ip6', 'vti6'],
37 'required': True,
38 'example': ['mode gre']
c3c78d97 39 },
73083400
JF
40 'local': {
41 'help': 'IP of local tunnel endpoint',
42 'validvals': ['<ipv4>', '<ipv6>'],
43 'required': True,
44 'example': ['local 192.2.0.42']
c3c78d97
JF
45 },
46 'endpoint': {
73083400
JF
47 'help': 'IP of remote tunnel endpoint',
48 'validvals': ['<ipv4>', '<ipv6>'],
49 'required': True,
50 'example': ['endpoint 192.2.0.23']
c3c78d97
JF
51 },
52 'ttl': {
73083400
JF
53 'help': 'TTL for tunnel packets',
54 'validvals': ['<number>'],
55 'required': False,
56 'example': ['ttl 64']
c3c78d97
JF
57 },
58 'tunnel-physdev': {
73083400
JF
59 'help': 'Physical underlay device to use for tunnel packets',
60 'validvals': ['<interface>'],
61 'required': False,
62 'example': ['tunnel-physdev eth1']
c3c78d97
JF
63 },
64 }
65 }
22aa65c7 66
73083400
JF
67 def __init__(self, *args, **kargs):
68 moduleBase.__init__(self, *args, **kargs)
c3c78d97 69 self.ipcmd = None
22aa65c7 70
73083400
JF
71 @staticmethod
72 def _is_my_interface(ifaceobj):
73 return ifaceobj.addr_method == "tunnel" and ifaceobj.get_attr_value_first('mode')
22aa65c7 74
6039c4d7
JF
75 def _has_config_changed(self, attrs_present, attrs_configured):
76 for key, value in attrs_configured.iteritems():
77 if attrs_present.get(key) != value:
78 return True
79 return False
22aa65c7 80
73083400 81 def _up(self, ifaceobj):
22aa65c7
MW
82 attr_map = {
83 # attr_name -> ip route param name
73083400
JF
84 'local': 'local',
85 'endpoint': 'remote',
86 'ttl': 'ttl',
87 'tunnel-physdev': 'dev',
22aa65c7
MW
88 }
89
c3c78d97 90 mode = ifaceobj.get_attr_value_first('mode')
22aa65c7 91 attrs = {}
6039c4d7 92 attrs_mapped = {}
22aa65c7
MW
93
94 # Only include attributes which have been set and map ifupdown2 names
95 # to attribute names expected by iproute
c3c78d97
JF
96 for attr, iproute_attr in attr_map.items():
97 attr_val = ifaceobj.get_attr_value_first(attr)
22aa65c7 98 if attr_val != None:
6039c4d7
JF
99 attrs_mapped[iproute_attr] = attr_val
100 attrs[attr] = attr_val
101
102 # Create the tunnel if it doesn't exist yet...
103 if not self.ipcmd.link_exists(ifaceobj.name):
104 self.ipcmd.tunnel_create(ifaceobj.name, mode, attrs_mapped)
105 return
22aa65c7 106
6039c4d7
JF
107 # If it's present, check if there were changes
108 current_attrs = self.ipcmd.link_get_linkinfo_attrs(ifaceobj.name)
84ca91f1 109 current_mode = self.ipcmd.link_cache_get([ifaceobj.name, 'kind'])
22aa65c7 110
f40c6294 111 try:
6039c4d7
JF
112 if current_attrs and current_mode != mode or self._has_config_changed(current_attrs, attrs):
113 # Mode and some other changes are not possible without recreating the interface,
114 # so just recreate it IFF there have been changes.
c3c78d97 115 self.ipcmd.link_delete(ifaceobj.name)
6039c4d7 116 self.ipcmd.tunnel_create(ifaceobj.name, mode, attrs_mapped)
f40c6294 117 except Exception, e:
c3c78d97 118 self.log_warn(str(e))
22aa65c7 119
73083400 120 def _down(self, ifaceobj):
c3c78d97 121 if not ifupdownflags.flags.PERFMODE and not self.ipcmd.link_exists(ifaceobj.name):
73083400 122 return
22aa65c7 123 try:
c3c78d97 124 self.ipcmd.link_delete(ifaceobj.name)
22aa65c7 125 except Exception, e:
c3c78d97 126 self.log_warn(str(e))
22aa65c7 127
60e7dc3a
SA
128 def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
129 if not self._is_my_interface(ifaceobj):
130 return None
73083400 131
c3c78d97 132 device = ifaceobj.get_attr_value_first('tunnel-physdev')
60e7dc3a 133 if device:
8e2f5fbe 134 return [device]
60e7dc3a
SA
135
136 return None
22aa65c7 137
73083400
JF
138 @staticmethod
139 def _query_check_n_update(ifaceobj, ifaceobjcurr, attrname, attrval, running_attrval):
c3c78d97 140 if not ifaceobj.get_attr_value_first(attrname):
22aa65c7 141 return
22aa65c7 142 if running_attrval and attrval == running_attrval:
73083400 143 ifaceobjcurr.update_config_with_status(attrname, attrval, 0)
22aa65c7 144 else:
73083400 145 ifaceobjcurr.update_config_with_status(attrname, running_attrval, 1)
22aa65c7 146
c3c78d97 147 def _query_check(self, ifaceobj, ifaceobjcurr):
5a4147c4
JF
148 ifname = ifaceobj.name
149
150 if not self.ipcmd.link_exists(ifname):
22aa65c7
MW
151 return
152
c3c78d97 153 tunattrs = self.ipcmd.link_get_linkinfo_attrs(ifaceobj.name)
22aa65c7 154 if not tunattrs:
73083400 155 ifaceobjcurr.check_n_update_config_with_status_many(ifaceobj, self.get_mod_attrs(), -1)
22aa65c7
MW
156 return
157
5a4147c4
JF
158 tunattrs["mode"] = self.ipcmd.link_get_kind(ifname)
159
160 user_config_mode = ifaceobj.get_attr_value_first("mode")
161 if user_config_mode in ('ipip6', 'ip6ip6'):
162 ifaceobj.replace_config("mode", "ip6tnl")
163
c3c78d97
JF
164 for attr in self.get_mod_attrs():
165 if not ifaceobj.get_attr_value_first(attr):
22aa65c7
MW
166 continue
167
168 # Validate all interface attributes set in the config.
169 # Remote any leading 'tunnel-' prefix in front of the attr name
170 # when accessing tunattrs parsed from 'ip -d link'.
c3c78d97 171 self._query_check_n_update(ifaceobj, ifaceobjcurr, attr,
73083400 172 ifaceobj.get_attr_value_first(attr),
6039c4d7 173 tunattrs.get(attr))
22aa65c7
MW
174
175 # Operations supported by this addon (yet).
176 _run_ops = {
73083400
JF
177 'pre-up': _up,
178 'post-down': _down,
179 'query-checkcurr': _query_check
22aa65c7
MW
180 }
181
c3c78d97 182 def get_ops(self):
22aa65c7
MW
183 return self._run_ops.keys()
184
c3c78d97 185 def _init_command_handlers(self):
22aa65c7 186 if not self.ipcmd:
c3c78d97 187 self.ipcmd = LinkUtils()
22aa65c7 188
73083400 189 def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
c3c78d97 190 op_handler = self._run_ops.get(operation)
22aa65c7
MW
191 if not op_handler:
192 return
193
c3c78d97 194 if operation != 'query-running' and not self._is_my_interface(ifaceobj):
22aa65c7
MW
195 return
196
c3c78d97 197 self._init_command_handlers()
22aa65c7 198 if operation == 'query-checkcurr':
c3c78d97 199 op_handler(self, ifaceobj, query_ifaceobj)
22aa65c7 200 else:
c3c78d97 201 op_handler(self, ifaceobj)