]>
Commit | Line | Data |
---|---|---|
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 |
6 | try: |
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 | 14 | except 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 | 27 | class 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) |