2014-10-09 16:02:46 -07:00
|
|
|
#!/usr/bin/python
|
|
|
|
#
|
|
|
|
# Copyright 2014 Cumulus Networks, Inc. All rights reserved.
|
|
|
|
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
|
|
|
|
#
|
|
|
|
|
|
|
|
from ifupdown.iface import *
|
|
|
|
from ifupdownaddons.modulebase import moduleBase
|
|
|
|
from ifupdownaddons.iproute2 import iproute2
|
2016-04-29 21:19:42 +02:00
|
|
|
import ifupdown.ifupdownconfig as ifupdownConfig
|
|
|
|
|
2016-05-29 18:04:23 +01:00
|
|
|
from ifupdown.netlink import netlink
|
2016-04-14 14:45:47 -07:00
|
|
|
import ifupdown.ifupdownflags as ifupdownflags
|
2014-10-09 16:02:46 -07:00
|
|
|
import logging
|
2014-10-28 16:10:00 -07:00
|
|
|
import re
|
2014-10-09 16:02:46 -07:00
|
|
|
|
|
|
|
class vlan(moduleBase):
|
|
|
|
""" ifupdown2 addon module to configure vlans """
|
|
|
|
|
|
|
|
_modinfo = {'mhelp' : 'vlan module configures vlan interfaces.' +
|
|
|
|
'This module understands vlan interfaces with dot ' +
|
|
|
|
'notations. eg swp1.100. Vlan interfaces with any ' +
|
|
|
|
'other names need to have raw device and vlan id ' +
|
|
|
|
'attributes',
|
|
|
|
'attrs' : {
|
|
|
|
'vlan-raw-device' :
|
|
|
|
{'help' : 'vlan raw device'},
|
|
|
|
'vlan-id' :
|
|
|
|
{'help' : 'vlan id'}}}
|
|
|
|
|
2014-11-03 17:55:51 -08:00
|
|
|
|
2014-10-09 16:02:46 -07:00
|
|
|
def __init__(self, *args, **kargs):
|
|
|
|
moduleBase.__init__(self, *args, **kargs)
|
|
|
|
self.ipcmd = None
|
2014-11-03 17:55:51 -08:00
|
|
|
self._bridge_vids_query_cache = {}
|
2014-11-11 21:58:12 -08:00
|
|
|
self._resv_vlan_range = self._get_reserved_vlan_range()
|
|
|
|
self.logger.debug('%s: using reserved vlan range %s'
|
|
|
|
%(self.__class__.__name__, str(self._resv_vlan_range)))
|
2014-10-09 16:02:46 -07:00
|
|
|
|
|
|
|
def _is_vlan_device(self, ifaceobj):
|
|
|
|
vlan_raw_device = ifaceobj.get_attr_value_first('vlan-raw-device')
|
|
|
|
if vlan_raw_device:
|
|
|
|
return True
|
|
|
|
elif '.' in ifaceobj.name:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def _get_vlan_id(self, ifaceobj):
|
|
|
|
""" Derives vlanid from iface name
|
|
|
|
|
|
|
|
Example:
|
|
|
|
Returns 1 for ifname vlan0001 returns 1
|
|
|
|
Returns 1 for ifname vlan1
|
|
|
|
Returns 1 for ifname eth0.1
|
|
|
|
|
|
|
|
Returns -1 if vlan id cannot be determined
|
|
|
|
"""
|
|
|
|
vid_str = ifaceobj.get_attr_value_first('vlan-id')
|
|
|
|
try:
|
|
|
|
if vid_str: return int(vid_str)
|
|
|
|
except:
|
|
|
|
return -1
|
|
|
|
|
2014-10-29 12:51:21 -07:00
|
|
|
if '.' in ifaceobj.name:
|
2014-10-09 16:02:46 -07:00
|
|
|
vid_str = ifaceobj.name.split('.', 1)[1]
|
2014-10-29 12:51:21 -07:00
|
|
|
elif ifaceobj.name.startswith('vlan'):
|
|
|
|
vid_str = ifaceobj.name[4:]
|
2014-10-09 16:02:46 -07:00
|
|
|
else:
|
|
|
|
return -1
|
|
|
|
try:
|
|
|
|
vid = int(vid_str)
|
|
|
|
except:
|
|
|
|
return -1
|
|
|
|
return vid
|
|
|
|
|
|
|
|
def _is_vlan_by_name(self, ifacename):
|
|
|
|
return '.' in ifacename
|
|
|
|
|
|
|
|
def _get_vlan_raw_device_from_ifacename(self, ifacename):
|
|
|
|
""" Returns vlan raw device from ifname
|
|
|
|
Example:
|
|
|
|
Returns eth0 for ifname eth0.100
|
|
|
|
|
|
|
|
Returns None if vlan raw device name cannot
|
|
|
|
be determined
|
|
|
|
"""
|
|
|
|
vlist = ifacename.split('.', 1)
|
|
|
|
if len(vlist) == 2:
|
|
|
|
return vlist[0]
|
|
|
|
return None
|
|
|
|
|
|
|
|
def _get_vlan_raw_device(self, ifaceobj):
|
|
|
|
vlan_raw_device = ifaceobj.get_attr_value_first('vlan-raw-device')
|
|
|
|
if vlan_raw_device:
|
|
|
|
return vlan_raw_device
|
|
|
|
return self._get_vlan_raw_device_from_ifacename(ifaceobj.name)
|
2016-04-29 21:19:42 +02:00
|
|
|
|
2014-10-09 16:02:46 -07:00
|
|
|
def get_dependent_ifacenames(self, ifaceobj, ifaceobjs_all=None):
|
|
|
|
if not self._is_vlan_device(ifaceobj):
|
|
|
|
return None
|
2015-06-02 20:35:08 -04:00
|
|
|
ifaceobj.link_kind |= ifaceLinkKind.VLAN
|
2014-10-09 16:02:46 -07:00
|
|
|
return [self._get_vlan_raw_device(ifaceobj)]
|
|
|
|
|
2014-10-28 16:10:00 -07:00
|
|
|
def _bridge_vid_add_del(self, ifaceobj, bridgename, vlanid,
|
2014-11-03 17:55:51 -08:00
|
|
|
add=True):
|
|
|
|
""" If the lower device is a vlan aware bridge, add/del the vlanid
|
|
|
|
to the bridge """
|
2014-10-28 16:10:00 -07:00
|
|
|
if self.ipcmd.bridge_is_vlan_aware(bridgename):
|
2014-11-03 17:55:51 -08:00
|
|
|
if add:
|
2016-05-29 18:04:23 +01:00
|
|
|
netlink.link_add_bridge_vlan(bridgename, vlanid)
|
2014-11-03 17:55:51 -08:00
|
|
|
else:
|
2016-05-29 18:04:23 +01:00
|
|
|
netlink.link_del_bridge_vlan(bridgename, vlanid)
|
2014-11-03 17:55:51 -08:00
|
|
|
|
|
|
|
def _bridge_vid_check(self, ifaceobj, ifaceobjcurr, bridgename, vlanid):
|
|
|
|
""" If the lower device is a vlan aware bridge, check if the vlanid
|
|
|
|
is configured on the bridge """
|
|
|
|
if not self.ipcmd.bridge_is_vlan_aware(bridgename):
|
|
|
|
return
|
|
|
|
vids = self._bridge_vids_query_cache.get(bridgename)
|
|
|
|
if vids == None:
|
|
|
|
vids = self.ipcmd.bridge_port_vids_get(bridgename)
|
|
|
|
self._bridge_vids_query_cache[bridgename] = vids
|
|
|
|
if not vids or vlanid not in vids:
|
|
|
|
ifaceobjcurr.status = ifaceStatus.ERROR
|
|
|
|
ifaceobjcurr.status_str = 'bridge vid error'
|
|
|
|
|
|
|
|
def _up(self, ifaceobj):
|
2014-10-09 16:02:46 -07:00
|
|
|
vlanid = self._get_vlan_id(ifaceobj)
|
|
|
|
if vlanid == -1:
|
|
|
|
raise Exception('could not determine vlanid')
|
|
|
|
vlanrawdevice = self._get_vlan_raw_device(ifaceobj)
|
|
|
|
if not vlanrawdevice:
|
|
|
|
raise Exception('could not determine vlan raw device')
|
2016-04-14 14:45:47 -07:00
|
|
|
if not ifupdownflags.flags.PERFMODE:
|
2014-10-24 10:11:07 -07:00
|
|
|
if not self.ipcmd.link_exists(vlanrawdevice):
|
|
|
|
raise Exception('rawdevice %s not present' %vlanrawdevice)
|
|
|
|
if self.ipcmd.link_exists(ifaceobj.name):
|
2014-11-03 17:55:51 -08:00
|
|
|
self._bridge_vid_add_del(ifaceobj, vlanrawdevice, vlanid)
|
2016-04-29 21:19:42 +02:00
|
|
|
if ifupdownConfig.config.get('adjust_logical_dev_mtu', '1') != '0' and len(ifaceobj.lowerifaces):
|
|
|
|
lower_iface_mtu = self.ipcmd.link_get_mtu(ifaceobj.lowerifaces[0], refresh=True)
|
|
|
|
if not lower_iface_mtu == self.ipcmd.link_get_mtu(ifaceobj.name):
|
|
|
|
self.ipcmd.link_set_mtu(ifaceobj.name, lower_iface_mtu)
|
2014-10-24 10:11:07 -07:00
|
|
|
return
|
2016-05-29 18:04:23 +01:00
|
|
|
netlink.link_add_vlan(vlanrawdevice, ifaceobj.name, vlanid)
|
2014-11-03 17:55:51 -08:00
|
|
|
self._bridge_vid_add_del(ifaceobj, vlanrawdevice, vlanid)
|
2014-11-12 10:51:07 -08:00
|
|
|
if ifaceobj.addr_method == 'manual':
|
2016-05-29 18:04:23 +01:00
|
|
|
netlink.link_set_updown(ifaceobj.name, "up")
|
2014-10-09 16:02:46 -07:00
|
|
|
|
2014-11-03 17:55:51 -08:00
|
|
|
def _down(self, ifaceobj):
|
2014-10-09 16:02:46 -07:00
|
|
|
vlanid = self._get_vlan_id(ifaceobj)
|
|
|
|
if vlanid == -1:
|
|
|
|
raise Exception('could not determine vlanid')
|
2014-10-28 16:10:00 -07:00
|
|
|
vlanrawdevice = self._get_vlan_raw_device(ifaceobj)
|
|
|
|
if not vlanrawdevice:
|
2014-10-09 16:02:46 -07:00
|
|
|
raise Exception('could not determine vlan raw device')
|
2016-04-14 14:45:47 -07:00
|
|
|
if (not ifupdownflags.flags.PERFMODE and
|
|
|
|
not self.ipcmd.link_exists(ifaceobj.name)):
|
2014-10-09 16:02:46 -07:00
|
|
|
return
|
|
|
|
try:
|
|
|
|
self.ipcmd.link_delete(ifaceobj.name)
|
2014-11-03 17:55:51 -08:00
|
|
|
self._bridge_vid_add_del(ifaceobj, vlanrawdevice, vlanid, add=False)
|
2014-10-09 16:02:46 -07:00
|
|
|
except Exception, e:
|
|
|
|
self.log_warn(str(e))
|
|
|
|
|
2014-11-03 17:55:51 -08:00
|
|
|
def _query_check(self, ifaceobj, ifaceobjcurr):
|
2014-10-09 16:02:46 -07:00
|
|
|
if not self.ipcmd.link_exists(ifaceobj.name):
|
|
|
|
return
|
|
|
|
if not '.' in ifaceobj.name:
|
|
|
|
# if vlan name is not in the dot format, check its running state
|
|
|
|
(vlanrawdev, vlanid) = self.ipcmd.get_vlandev_attrs(ifaceobj.name)
|
|
|
|
if vlanrawdev != ifaceobj.get_attr_value_first('vlan-raw-device'):
|
|
|
|
ifaceobjcurr.update_config_with_status('vlan-raw-device',
|
|
|
|
vlanrawdev, 1)
|
|
|
|
else:
|
|
|
|
ifaceobjcurr.update_config_with_status('vlan-raw-device',
|
|
|
|
vlanrawdev, 0)
|
|
|
|
if vlanid != ifaceobj.get_attr_value_first('vlan-id'):
|
|
|
|
ifaceobjcurr.update_config_with_status('vlan-id', vlanid, 1)
|
|
|
|
else:
|
|
|
|
ifaceobjcurr.update_config_with_status('vlan-id',
|
|
|
|
vlanid, 0)
|
2014-11-03 17:55:51 -08:00
|
|
|
self._bridge_vid_check(ifaceobj, ifaceobjcurr, vlanrawdev, vlanid)
|
2014-10-09 16:02:46 -07:00
|
|
|
|
2014-11-03 17:55:51 -08:00
|
|
|
def _query_running(self, ifaceobjrunning):
|
2014-10-09 16:02:46 -07:00
|
|
|
if not self.ipcmd.link_exists(ifaceobjrunning.name):
|
|
|
|
return
|
|
|
|
if not self.ipcmd.get_vlandev_attrs(ifaceobjrunning.name):
|
|
|
|
return
|
|
|
|
# If vlan name is not in the dot format, get the
|
|
|
|
# vlan dev and vlan id
|
|
|
|
if not '.' in ifaceobjrunning.name:
|
|
|
|
(vlanrawdev, vlanid) = self.ipcmd.get_vlandev_attrs(ifaceobjrunning.name)
|
|
|
|
ifaceobjrunning.update_config_dict({(k, v) for k, v in
|
|
|
|
{'vlan-raw-device' : vlanrawdev,
|
|
|
|
'vlan-id' : vlanid}.items()
|
|
|
|
if v})
|
|
|
|
|
|
|
|
_run_ops = {'pre-up' : _up,
|
|
|
|
'post-down' : _down,
|
|
|
|
'query-checkcurr' : _query_check,
|
|
|
|
'query-running' : _query_running}
|
|
|
|
|
|
|
|
def get_ops(self):
|
|
|
|
""" returns list of ops supported by this module """
|
|
|
|
return self._run_ops.keys()
|
|
|
|
|
|
|
|
def _init_command_handlers(self):
|
|
|
|
if not self.ipcmd:
|
2016-04-14 14:45:47 -07:00
|
|
|
self.ipcmd = iproute2()
|
2016-04-29 21:19:42 +02:00
|
|
|
|
2014-11-03 17:55:51 -08:00
|
|
|
def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args):
|
2014-10-09 16:02:46 -07:00
|
|
|
""" run vlan configuration on the interface object passed as argument
|
|
|
|
|
|
|
|
Args:
|
|
|
|
**ifaceobj** (object): iface object
|
|
|
|
|
|
|
|
**operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
|
|
|
|
'query-running'
|
|
|
|
Kwargs:
|
|
|
|
**query_ifaceobj** (object): query check ifaceobject. This is only
|
|
|
|
valid when op is 'query-checkcurr'. It is an object same as
|
|
|
|
ifaceobj, but contains running attribute values and its config
|
|
|
|
status. The modules can use it to return queried running state
|
|
|
|
of interfaces. status is success if the running state is same
|
|
|
|
as user required state in ifaceobj. error otherwise.
|
|
|
|
"""
|
2014-10-24 10:11:07 -07:00
|
|
|
if ifaceobj.type == ifaceType.BRIDGE_VLAN:
|
|
|
|
return
|
2014-10-09 16:02:46 -07:00
|
|
|
op_handler = self._run_ops.get(operation)
|
|
|
|
if not op_handler:
|
|
|
|
return
|
|
|
|
if (operation != 'query-running' and
|
|
|
|
not self._is_vlan_device(ifaceobj)):
|
|
|
|
return
|
|
|
|
self._init_command_handlers()
|
|
|
|
if operation == 'query-checkcurr':
|
2014-11-03 17:55:51 -08:00
|
|
|
op_handler(self, ifaceobj, query_ifaceobj)
|
2014-10-09 16:02:46 -07:00
|
|
|
else:
|
2014-11-03 17:55:51 -08:00
|
|
|
op_handler(self, ifaceobj)
|