]> git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdown2/addons/tunnel.py
addons: tunnel: fix tunnel creation (#80)- master branch refactoring
[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 _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
80
81 def _up(self, ifaceobj):
82 attr_map = {
83 # attr_name -> ip route param name
84 'local': 'local',
85 'endpoint': 'remote',
86 'ttl': 'ttl',
87 'tunnel-physdev': 'dev',
88 }
89
90 mode = ifaceobj.get_attr_value_first('mode')
91 attrs = {}
92 attrs_mapped = {}
93
94 # Only include attributes which have been set and map ifupdown2 names
95 # to attribute names expected by iproute
96 for attr, iproute_attr in attr_map.items():
97 attr_val = ifaceobj.get_attr_value_first(attr)
98 if attr_val != None:
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
106
107 # If it's present, check if there were changes
108 current_attrs = self.ipcmd.link_get_linkinfo_attrs(ifaceobj.name)
109 current_mode = self.ipcmd.link_cache_get([ifaceobj.name, 'kind'])
110
111 try:
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.
115 self.ipcmd.link_delete(ifaceobj.name)
116 self.ipcmd.tunnel_create(ifaceobj.name, mode, attrs_mapped)
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))
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)