]> git.proxmox.com Git - mirror_ifupdown2.git/blob - addons/vlan.py
Merge pull request #80 from BarbarossaTM/tunnel-fixes-master
[mirror_ifupdown2.git] / addons / vlan.py
1 #!/usr/bin/python
2 #
3 # Copyright 2014 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
5 #
6
7 from ifupdown.iface import *
8 from ifupdownaddons.modulebase import moduleBase
9 from ifupdownaddons.iproute2 import iproute2
10 import ifupdown.ifupdownconfig as ifupdownConfig
11
12 from ifupdown.netlink import netlink
13 import ifupdown.ifupdownflags as ifupdownflags
14 import logging
15 import re
16
17 class vlan(moduleBase):
18 """ ifupdown2 addon module to configure vlans """
19
20 _modinfo = {'mhelp' : 'vlan module configures vlan interfaces.' +
21 'This module understands vlan interfaces with dot ' +
22 'notations. eg swp1.100. Vlan interfaces with any ' +
23 'other names need to have raw device and vlan id ' +
24 'attributes',
25 'attrs' : {
26 'vlan-raw-device' :
27 {'help' : 'vlan raw device',
28 'validvals': ['<interface>']},
29 'vlan-id' :
30 {'help' : 'vlan id',
31 'validrange' : ['0', '4096']}}}
32
33
34 def __init__(self, *args, **kargs):
35 moduleBase.__init__(self, *args, **kargs)
36 self.ipcmd = None
37 self._bridge_vids_query_cache = {}
38 self._resv_vlan_range = self._get_reserved_vlan_range()
39 self.logger.debug('%s: using reserved vlan range %s'
40 %(self.__class__.__name__, str(self._resv_vlan_range)))
41
42 def _is_vlan_device(self, ifaceobj):
43 vlan_raw_device = ifaceobj.get_attr_value_first('vlan-raw-device')
44 if vlan_raw_device:
45 return True
46 elif '.' in ifaceobj.name:
47 return True
48 return False
49
50 def _get_vlan_id(self, ifaceobj):
51 """ Derives vlanid from iface name
52
53 Example:
54 Returns 1 for ifname vlan0001 returns 1
55 Returns 1 for ifname vlan1
56 Returns 1 for ifname eth0.1
57
58 Returns -1 if vlan id cannot be determined
59 """
60 vid_str = ifaceobj.get_attr_value_first('vlan-id')
61 try:
62 if vid_str: return int(vid_str)
63 except:
64 return -1
65
66 if '.' in ifaceobj.name:
67 vid_str = ifaceobj.name.split('.', 1)[1]
68 elif ifaceobj.name.startswith('vlan'):
69 vid_str = ifaceobj.name[4:]
70 else:
71 return -1
72 try:
73 vid = int(vid_str)
74 except:
75 return -1
76 return vid
77
78 def _is_vlan_by_name(self, ifacename):
79 return '.' in ifacename
80
81 def _get_vlan_raw_device_from_ifacename(self, ifacename):
82 """ Returns vlan raw device from ifname
83 Example:
84 Returns eth0 for ifname eth0.100
85
86 Returns None if vlan raw device name cannot
87 be determined
88 """
89 vlist = ifacename.split('.', 1)
90 if len(vlist) == 2:
91 return vlist[0]
92 return None
93
94 def _get_vlan_raw_device(self, ifaceobj):
95 vlan_raw_device = ifaceobj.get_attr_value_first('vlan-raw-device')
96 if vlan_raw_device:
97 return vlan_raw_device
98 return self._get_vlan_raw_device_from_ifacename(ifaceobj.name)
99
100 def get_dependent_ifacenames(self, ifaceobj, ifaceobjs_all=None):
101 if not self._is_vlan_device(ifaceobj):
102 return None
103 ifaceobj.link_kind |= ifaceLinkKind.VLAN
104 return [self._get_vlan_raw_device(ifaceobj)]
105
106 def _bridge_vid_add_del(self, ifaceobj, bridgename, vlanid,
107 add=True):
108 """ If the lower device is a vlan aware bridge, add/del the vlanid
109 to the bridge """
110 if self.ipcmd.bridge_is_vlan_aware(bridgename):
111 if add:
112 netlink.link_add_bridge_vlan(bridgename, vlanid)
113 else:
114 netlink.link_del_bridge_vlan(bridgename, vlanid)
115
116 def _bridge_vid_check(self, ifaceobj, ifaceobjcurr, bridgename, vlanid):
117 """ If the lower device is a vlan aware bridge, check if the vlanid
118 is configured on the bridge """
119 if not self.ipcmd.bridge_is_vlan_aware(bridgename):
120 return
121 vids = self._bridge_vids_query_cache.get(bridgename)
122 if vids == None:
123 vids = self.ipcmd.bridge_port_vids_get(bridgename)
124 self._bridge_vids_query_cache[bridgename] = vids
125 if not vids or vlanid not in vids:
126 ifaceobjcurr.status = ifaceStatus.ERROR
127 ifaceobjcurr.status_str = 'bridge vid error'
128
129 def _up(self, ifaceobj):
130 vlanid = self._get_vlan_id(ifaceobj)
131 if vlanid == -1:
132 raise Exception('could not determine vlanid')
133 vlanrawdevice = self._get_vlan_raw_device(ifaceobj)
134 if not vlanrawdevice:
135 raise Exception('could not determine vlan raw device')
136 if not ifupdownflags.flags.PERFMODE:
137 if not self.ipcmd.link_exists(vlanrawdevice):
138 raise Exception('rawdevice %s not present' %vlanrawdevice)
139 if self.ipcmd.link_exists(ifaceobj.name):
140 self._bridge_vid_add_del(ifaceobj, vlanrawdevice, vlanid)
141 return
142 netlink.link_add_vlan(vlanrawdevice, ifaceobj.name, vlanid)
143 self._bridge_vid_add_del(ifaceobj, vlanrawdevice, vlanid)
144
145 def _down(self, ifaceobj):
146 vlanid = self._get_vlan_id(ifaceobj)
147 if vlanid == -1:
148 raise Exception('could not determine vlanid')
149 vlanrawdevice = self._get_vlan_raw_device(ifaceobj)
150 if not vlanrawdevice:
151 raise Exception('could not determine vlan raw device')
152 if (not ifupdownflags.flags.PERFMODE and
153 not self.ipcmd.link_exists(ifaceobj.name)):
154 return
155 try:
156 self.ipcmd.link_delete(ifaceobj.name)
157 self._bridge_vid_add_del(ifaceobj, vlanrawdevice, vlanid, add=False)
158 except Exception, e:
159 self.log_warn(str(e))
160
161 def _query_check(self, ifaceobj, ifaceobjcurr):
162 if not self.ipcmd.link_exists(ifaceobj.name):
163 return
164 if not '.' in ifaceobj.name:
165 # if vlan name is not in the dot format, check its running state
166 (vlanrawdev, vlanid) = self.ipcmd.get_vlandev_attrs(ifaceobj.name)
167 if vlanrawdev != ifaceobj.get_attr_value_first('vlan-raw-device'):
168 ifaceobjcurr.update_config_with_status('vlan-raw-device',
169 vlanrawdev, 1)
170 else:
171 ifaceobjcurr.update_config_with_status('vlan-raw-device',
172 vlanrawdev, 0)
173 vlanid_config = ifaceobj.get_attr_value_first('vlan-id')
174 if not vlanid_config:
175 vlanid_config = str(self._get_vlan_id(ifaceobj))
176 if vlanid != vlanid_config:
177 ifaceobjcurr.update_config_with_status('vlan-id', vlanid, 1)
178 else:
179 ifaceobjcurr.update_config_with_status('vlan-id', vlanid, 0)
180 self._bridge_vid_check(ifaceobj, ifaceobjcurr, vlanrawdev, vlanid)
181
182 def _query_running(self, ifaceobjrunning):
183 if not self.ipcmd.link_exists(ifaceobjrunning.name):
184 return
185 (vlanrawdev, vlanid) = self.ipcmd.get_vlandev_attrs(ifaceobjrunning.name)
186 if not vlanid:
187 return
188 # If vlan name is not in the dot format, get the
189 # vlan dev and vlan id
190 if not '.' in ifaceobjrunning.name:
191 ifaceobjrunning.update_config_dict({(k, v) for k, v in
192 {'vlan-raw-device' : vlanrawdev,
193 'vlan-id' : vlanid}.items()
194 if v})
195
196 _run_ops = {'pre-up' : _up,
197 'post-down' : _down,
198 'query-checkcurr' : _query_check,
199 'query-running' : _query_running}
200
201 def get_ops(self):
202 """ returns list of ops supported by this module """
203 return self._run_ops.keys()
204
205 def _init_command_handlers(self):
206 if not self.ipcmd:
207 self.ipcmd = iproute2()
208
209 def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
210 """ run vlan configuration on the interface object passed as argument
211
212 Args:
213 **ifaceobj** (object): iface object
214
215 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
216 'query-running'
217 Kwargs:
218 **query_ifaceobj** (object): query check ifaceobject. This is only
219 valid when op is 'query-checkcurr'. It is an object same as
220 ifaceobj, but contains running attribute values and its config
221 status. The modules can use it to return queried running state
222 of interfaces. status is success if the running state is same
223 as user required state in ifaceobj. error otherwise.
224 """
225 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
226 return
227 op_handler = self._run_ops.get(operation)
228 if not op_handler:
229 return
230 if (operation != 'query-running' and
231 not self._is_vlan_device(ifaceobj)):
232 return
233 self._init_command_handlers()
234 if operation == 'query-checkcurr':
235 op_handler(self, ifaceobj, query_ifaceobj)
236 else:
237 op_handler(self, ifaceobj)