]> git.proxmox.com Git - mirror_ifupdown2.git/blob - addons/vlan.py
attribute syntax check using validvals/validrange and keywords
[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 if ifupdownConfig.config.get('adjust_logical_dev_mtu', '1') != '0' and len(ifaceobj.lowerifaces):
142 lower_iface_mtu = self.ipcmd.link_get_mtu(ifaceobj.lowerifaces[0], refresh=True)
143 if not lower_iface_mtu == self.ipcmd.link_get_mtu(ifaceobj.name):
144 self.ipcmd.link_set_mtu(ifaceobj.name, lower_iface_mtu)
145 return
146 netlink.link_add_vlan(vlanrawdevice, ifaceobj.name, vlanid)
147 self._bridge_vid_add_del(ifaceobj, vlanrawdevice, vlanid)
148 if ifaceobj.addr_method == 'manual':
149 netlink.link_set_updown(ifaceobj.name, "up")
150
151 def _down(self, ifaceobj):
152 vlanid = self._get_vlan_id(ifaceobj)
153 if vlanid == -1:
154 raise Exception('could not determine vlanid')
155 vlanrawdevice = self._get_vlan_raw_device(ifaceobj)
156 if not vlanrawdevice:
157 raise Exception('could not determine vlan raw device')
158 if (not ifupdownflags.flags.PERFMODE and
159 not self.ipcmd.link_exists(ifaceobj.name)):
160 return
161 try:
162 self.ipcmd.link_delete(ifaceobj.name)
163 self._bridge_vid_add_del(ifaceobj, vlanrawdevice, vlanid, add=False)
164 except Exception, e:
165 self.log_warn(str(e))
166
167 def _query_check(self, ifaceobj, ifaceobjcurr):
168 if not self.ipcmd.link_exists(ifaceobj.name):
169 return
170 if not '.' in ifaceobj.name:
171 # if vlan name is not in the dot format, check its running state
172 (vlanrawdev, vlanid) = self.ipcmd.get_vlandev_attrs(ifaceobj.name)
173 if vlanrawdev != ifaceobj.get_attr_value_first('vlan-raw-device'):
174 ifaceobjcurr.update_config_with_status('vlan-raw-device',
175 vlanrawdev, 1)
176 else:
177 ifaceobjcurr.update_config_with_status('vlan-raw-device',
178 vlanrawdev, 0)
179 vlanid_config = ifaceobj.get_attr_value_first('vlan-id')
180 if not vlanid_config:
181 vlanid_config = str(self._get_vlan_id(ifaceobj))
182 if vlanid != vlanid_config:
183 ifaceobjcurr.update_config_with_status('vlan-id', vlanid, 1)
184 else:
185 ifaceobjcurr.update_config_with_status('vlan-id', vlanid, 0)
186 self._bridge_vid_check(ifaceobj, ifaceobjcurr, vlanrawdev, vlanid)
187
188 def _query_running(self, ifaceobjrunning):
189 if not self.ipcmd.link_exists(ifaceobjrunning.name):
190 return
191 if not self.ipcmd.get_vlandev_attrs(ifaceobjrunning.name):
192 return
193 # If vlan name is not in the dot format, get the
194 # vlan dev and vlan id
195 if not '.' in ifaceobjrunning.name:
196 (vlanrawdev, vlanid) = self.ipcmd.get_vlandev_attrs(ifaceobjrunning.name)
197 ifaceobjrunning.update_config_dict({(k, v) for k, v in
198 {'vlan-raw-device' : vlanrawdev,
199 'vlan-id' : vlanid}.items()
200 if v})
201
202 _run_ops = {'pre-up' : _up,
203 'post-down' : _down,
204 'query-checkcurr' : _query_check,
205 'query-running' : _query_running}
206
207 def get_ops(self):
208 """ returns list of ops supported by this module """
209 return self._run_ops.keys()
210
211 def _init_command_handlers(self):
212 if not self.ipcmd:
213 self.ipcmd = iproute2()
214
215 def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
216 """ run vlan configuration on the interface object passed as argument
217
218 Args:
219 **ifaceobj** (object): iface object
220
221 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
222 'query-running'
223 Kwargs:
224 **query_ifaceobj** (object): query check ifaceobject. This is only
225 valid when op is 'query-checkcurr'. It is an object same as
226 ifaceobj, but contains running attribute values and its config
227 status. The modules can use it to return queried running state
228 of interfaces. status is success if the running state is same
229 as user required state in ifaceobj. error otherwise.
230 """
231 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
232 return
233 op_handler = self._run_ops.get(operation)
234 if not op_handler:
235 return
236 if (operation != 'query-running' and
237 not self._is_vlan_device(ifaceobj)):
238 return
239 self._init_command_handlers()
240 if operation == 'query-checkcurr':
241 op_handler(self, ifaceobj, query_ifaceobj)
242 else:
243 op_handler(self, ifaceobj)