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