]> git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdown2/addons/tunnel.py
fd05929d2d3982ffffbf9a8104d032de5d3a3849
[mirror_ifupdown2.git] / ifupdown2 / addons / tunnel.py
1 #!/usr/bin/python
2 #
3 # Maximilian Wilhelm <max@rfc2324.org>
4 # -- Mon 10 Oct 2016 10:53:13 PM CEST
5 #
6 try:
7 from ifupdown2.ifupdown.iface import *
8 from ifupdown2.ifupdown.netlink import netlink
9
10 from ifupdown2.ifupdownaddons.LinkUtils import LinkUtils
11 from ifupdown2.ifupdownaddons.modulebase import moduleBase
12
13 import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
14 except ImportError:
15 from ifupdown.iface import *
16 from ifupdown.netlink import netlink
17
18 from ifupdownaddons.LinkUtils import LinkUtils
19 from ifupdownaddons.modulebase import moduleBase
20
21 import ifupdown.ifupdownflags as ifupdownflags
22
23
24 #
25 # TODO: Add checks for ipip tunnels.
26 #
27 class tunnel(moduleBase):
28 """
29 ifupdown2 addon module to configure tunnels
30 """
31 _modinfo = {
32 'mhelp': 'create/configure GRE/IPIP/SIT and GRETAP tunnel interfaces',
33 'attrs': {
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']
39 },
40 'local': {
41 'help': 'IP of local tunnel endpoint',
42 'validvals': ['<ipv4>', '<ipv6>'],
43 'required': True,
44 'example': ['local 192.2.0.42']
45 },
46 'endpoint': {
47 'help': 'IP of remote tunnel endpoint',
48 'validvals': ['<ipv4>', '<ipv6>'],
49 'required': True,
50 'example': ['endpoint 192.2.0.23']
51 },
52 'ttl': {
53 'help': 'TTL for tunnel packets',
54 'validvals': ['<number>'],
55 'required': False,
56 'example': ['ttl 64']
57 },
58 'tunnel-physdev': {
59 'help': 'Physical underlay device to use for tunnel packets',
60 'validvals': ['<interface>'],
61 'required': False,
62 'example': ['tunnel-physdev eth1']
63 },
64 }
65 }
66
67 def __init__(self, *args, **kargs):
68 moduleBase.__init__(self, *args, **kargs)
69 self.ipcmd = None
70
71 @staticmethod
72 def _is_my_interface(ifaceobj):
73 return ifaceobj.addr_method == "tunnel" and ifaceobj.get_attr_value_first('mode')
74
75 def _check_settings(self, ifaceobj, attrs):
76 linkup = self.ipcmd.is_link_up(ifaceobj.name)
77 try:
78 if attrs:
79 self.ipcmd.tunnel_change(ifaceobj.name, attrs)
80 except:
81 raise
82 finally:
83 if attrs and linkup:
84 netlink.link_set_updown(ifaceobj.name, 'up')
85
86 def _up(self, ifaceobj):
87 attr_map = {
88 # attr_name -> ip route param name
89 'local': 'local',
90 'endpoint': 'remote',
91 'ttl': 'ttl',
92 'tunnel-physdev': 'dev',
93 }
94
95 mode = ifaceobj.get_attr_value_first('mode')
96 attrs = {}
97
98 # Only include attributes which have been set and map ifupdown2 names
99 # to attribute names expected by iproute
100 for attr, iproute_attr in attr_map.items():
101 attr_val = ifaceobj.get_attr_value_first(attr)
102 if attr_val != None:
103 attrs[iproute_attr] = attr_val
104
105 current_mode = self.ipcmd.link_cache_get([ifaceobj.name, 'kind'])
106
107 try:
108 if not self.ipcmd.link_exists(ifaceobj.name):
109 self.ipcmd.tunnel_create(ifaceobj.name, mode, attrs)
110 elif current_mode and current_mode != mode and (('6' in mode and '6' not in current_mode) or ('6' not in mode and '6' in current_mode)):
111 # Mode changes between ipv4 and ipv6 are not possible without recreating the interface
112 self.ipcmd.link_delete(ifaceobj.name)
113 self.ipcmd.tunnel_create(ifaceobj.name, mode, attrs)
114 else:
115 attrs['mode'] = mode
116 self._check_settings(ifaceobj, attrs)
117 except Exception, e:
118 self.log_warn(str(e))
119
120 def _down(self, ifaceobj):
121 if not ifupdownflags.flags.PERFMODE and not self.ipcmd.link_exists(ifaceobj.name):
122 return
123 try:
124 self.ipcmd.link_delete(ifaceobj.name)
125 except Exception, e:
126 self.log_warn(str(e))
127
128 def get_dependent_ifacenames(self, ifaceobj, ifacenames_all=None):
129 if not self._is_my_interface(ifaceobj):
130 return None
131
132 device = ifaceobj.get_attr_value_first('tunnel-physdev')
133 if device:
134 return [device]
135
136 return None
137
138 @staticmethod
139 def _query_check_n_update(ifaceobj, ifaceobjcurr, attrname, attrval, running_attrval):
140 if not ifaceobj.get_attr_value_first(attrname):
141 return
142 if running_attrval and attrval == running_attrval:
143 ifaceobjcurr.update_config_with_status(attrname, attrval, 0)
144 else:
145 ifaceobjcurr.update_config_with_status(attrname, running_attrval, 1)
146
147 def _query_check(self, ifaceobj, ifaceobjcurr):
148 ifname = ifaceobj.name
149
150 if not self.ipcmd.link_exists(ifname):
151 return
152
153 tunattrs = self.ipcmd.link_get_linkinfo_attrs(ifaceobj.name)
154 if not tunattrs:
155 ifaceobjcurr.check_n_update_config_with_status_many(ifaceobj, self.get_mod_attrs(), -1)
156 return
157
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
164 for attr in self.get_mod_attrs():
165 if not ifaceobj.get_attr_value_first(attr):
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'.
171 self._query_check_n_update(ifaceobj, ifaceobjcurr, attr,
172 ifaceobj.get_attr_value_first(attr),
173 tunattrs.get(attr.replace("tunnel-", "")))
174
175 # Operations supported by this addon (yet).
176 _run_ops = {
177 'pre-up': _up,
178 'post-down': _down,
179 'query-checkcurr': _query_check
180 }
181
182 def get_ops(self):
183 return self._run_ops.keys()
184
185 def _init_command_handlers(self):
186 if not self.ipcmd:
187 self.ipcmd = LinkUtils()
188
189 def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
190 op_handler = self._run_ops.get(operation)
191 if not op_handler:
192 return
193
194 if operation != 'query-running' and not self._is_my_interface(ifaceobj):
195 return
196
197 self._init_command_handlers()
198 if operation == 'query-checkcurr':
199 op_handler(self, ifaceobj, query_ifaceobj)
200 else:
201 op_handler(self, ifaceobj)