]>
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 | |
33ebe60a | 75 | def _check_settings(self, ifaceobj, attrs): |
33ebe60a SA |
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') | |
22aa65c7 | 85 | |
73083400 | 86 | def _up(self, ifaceobj): |
22aa65c7 MW |
87 | attr_map = { |
88 | # attr_name -> ip route param name | |
73083400 JF |
89 | 'local': 'local', |
90 | 'endpoint': 'remote', | |
91 | 'ttl': 'ttl', | |
92 | 'tunnel-physdev': 'dev', | |
22aa65c7 MW |
93 | } |
94 | ||
c3c78d97 | 95 | mode = ifaceobj.get_attr_value_first('mode') |
22aa65c7 MW |
96 | attrs = {} |
97 | ||
98 | # Only include attributes which have been set and map ifupdown2 names | |
99 | # to attribute names expected by iproute | |
c3c78d97 JF |
100 | for attr, iproute_attr in attr_map.items(): |
101 | attr_val = ifaceobj.get_attr_value_first(attr) | |
22aa65c7 MW |
102 | if attr_val != None: |
103 | attrs[iproute_attr] = attr_val | |
104 | ||
84ca91f1 | 105 | current_mode = self.ipcmd.link_cache_get([ifaceobj.name, 'kind']) |
22aa65c7 | 106 | |
f40c6294 SA |
107 | try: |
108 | if not self.ipcmd.link_exists(ifaceobj.name): | |
c3c78d97 | 109 | self.ipcmd.tunnel_create(ifaceobj.name, mode, attrs) |
73083400 | 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)): |
f40c6294 | 111 | # Mode changes between ipv4 and ipv6 are not possible without recreating the interface |
c3c78d97 JF |
112 | self.ipcmd.link_delete(ifaceobj.name) |
113 | self.ipcmd.tunnel_create(ifaceobj.name, mode, attrs) | |
f40c6294 SA |
114 | else: |
115 | attrs['mode'] = mode | |
116 | self._check_settings(ifaceobj, attrs) | |
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 JF |
147 | def _query_check(self, ifaceobj, ifaceobjcurr): |
148 | if not self.ipcmd.link_exists(ifaceobj.name): | |
22aa65c7 MW |
149 | return |
150 | ||
c3c78d97 | 151 | tunattrs = self.ipcmd.link_get_linkinfo_attrs(ifaceobj.name) |
22aa65c7 | 152 | if not tunattrs: |
73083400 | 153 | ifaceobjcurr.check_n_update_config_with_status_many(ifaceobj, self.get_mod_attrs(), -1) |
22aa65c7 MW |
154 | return |
155 | ||
c3c78d97 JF |
156 | for attr in self.get_mod_attrs(): |
157 | if not ifaceobj.get_attr_value_first(attr): | |
22aa65c7 MW |
158 | continue |
159 | ||
160 | # Validate all interface attributes set in the config. | |
161 | # Remote any leading 'tunnel-' prefix in front of the attr name | |
162 | # when accessing tunattrs parsed from 'ip -d link'. | |
c3c78d97 | 163 | self._query_check_n_update(ifaceobj, ifaceobjcurr, attr, |
73083400 JF |
164 | ifaceobj.get_attr_value_first(attr), |
165 | tunattrs.get(attr.replace("tunnel-", ""))) | |
22aa65c7 MW |
166 | |
167 | # Operations supported by this addon (yet). | |
168 | _run_ops = { | |
73083400 JF |
169 | 'pre-up': _up, |
170 | 'post-down': _down, | |
171 | 'query-checkcurr': _query_check | |
22aa65c7 MW |
172 | } |
173 | ||
c3c78d97 | 174 | def get_ops(self): |
22aa65c7 MW |
175 | return self._run_ops.keys() |
176 | ||
c3c78d97 | 177 | def _init_command_handlers(self): |
22aa65c7 | 178 | if not self.ipcmd: |
c3c78d97 | 179 | self.ipcmd = LinkUtils() |
22aa65c7 | 180 | |
73083400 | 181 | def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args): |
c3c78d97 | 182 | op_handler = self._run_ops.get(operation) |
22aa65c7 MW |
183 | if not op_handler: |
184 | return | |
185 | ||
c3c78d97 | 186 | if operation != 'query-running' and not self._is_my_interface(ifaceobj): |
22aa65c7 MW |
187 | return |
188 | ||
c3c78d97 | 189 | self._init_command_handlers() |
22aa65c7 | 190 | if operation == 'query-checkcurr': |
c3c78d97 | 191 | op_handler(self, ifaceobj, query_ifaceobj) |
22aa65c7 | 192 | else: |
c3c78d97 | 193 | op_handler(self, ifaceobj) |