Skip to content

Commit

Permalink
Rewrite of the initscripts
Browse files Browse the repository at this point in the history
The logic of the scripts is in a module called arista
This brings more modularity and better platform support.
A script named arista is added under /usr/bin that makes use of this lib
It currently allows to read the prefdl, setup/clean the drivers, and reset devices

Change-Id: I7c3c994b7fe9eadf6525ceddeb869e241c716eab
  • Loading branch information
Staphylo committed Jan 4, 2017
1 parent 1ed181b commit 16cc6f6
Show file tree
Hide file tree
Showing 17 changed files with 605 additions and 22 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,9 @@ modules.order
DEBIAN
.tmp_versions
.finished.build

# python
*.pyc
/build
/*.egg-info
/venv
Empty file added arista/__init__.py
Empty file.
Empty file added arista/components/__init__.py
Empty file.
71 changes: 71 additions & 0 deletions arista/components/common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@

import logging
import os

from ..core.component import Component
from ..core.driver import KernelDriver
from ..core.utils import simulation
from ..core.types import PciAddr, I2cAddr

class PciComponent(Component):
def __init__(self, addr, **kwargs):
assert isinstance(addr, PciAddr)
super(PciComponent, self).__init__(addr=addr, **kwargs)

class I2cComponent(Component):
def __init__(self, addr, **kwargs):
assert isinstance(addr, I2cAddr)
super(I2cComponent, self).__init__(addr=addr, **kwargs)

class I2cKernelComponent(I2cComponent):
def __init__(self, addr, name):
super(I2cKernelComponent, self).__init__(addr)
self.addDriver(I2cKernelDriver, name)

class PciKernelDriver(KernelDriver):
def __init__(self, component, name, args=None):
assert isinstance(component, PciComponent)
super(PciKernelDriver, self).__init__(component, name, args)

def getSysfsPath(self):
return os.path.join('/sys/bus/pci/devices', str(self.component.addr))

class I2cKernelDriver(KernelDriver):
def __init__(self, component, name):
assert isinstance(component, I2cComponent)
super(I2cKernelDriver, self).__init__(component, None)
self.name = name

def getSysfsPath(self):
return os.path.join('/sys/bus/i2c/devices', str(self.component.addr))

def getSysfsBusPath(self):
return '/sys/bus/i2c/devices/i2c-%d' % self.component.addr.bus

def setup(self):
addr = self.component.addr
devicePath = self.getSysfsPath()
path = os.path.join(self.getSysfsBusPath(), 'new_device')
logging.debug('creating i2c device %s on bus %d at 0x%02x' %
(self.name, addr.bus, addr.address))
if simulation:
return
if os.path.exists(devicePath):
logging.debug('i2c device %s already exists' % devicePath)
else:
with open(path, 'w') as f:
f.write('%s 0x%02x' % (self.name, self.component.addr.address))

def clean(self):
# i2c kernel devices are automatically cleaned when the module is removed
if simulation:
return
path = os.path.join(self.getSysfsBusPath(), 'delete_device')
addr = self.component.addr
if os.path.exists(self.getSysfsPath()):
logging.debug('removing i2c device %s from bus %d' % (self.name, addr.bus))
with open(path, 'w') as f:
f.write('0x%02x' % addr.address)

def __str__(self):
return '%s(%s)' % (self.__class__.__name__, self.name)
Empty file added arista/core/__init__.py
Empty file.
90 changes: 90 additions & 0 deletions arista/core/component.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
from __future__ import print_function

from driver import Driver

class Component(object):
def __init__(self, **kwargs):
self.components = []
self.drivers = []
for key, value in kwargs.items():
setattr(self, key, value)
self.params = kwargs.keys()

def __str__(self):
kwargs = ['%s=%s' % (k, getattr(self, k)) for k in self.params]
return '%s(%s)' % (self.__class__.__name__, ', '.join(kwargs))

def addComponents(self, components):
assert all(isinstance(c, Component) for c in components)
self.components += components
return self

def addComponent(self, component):
assert isinstance(component, Component)
self.components += [component]
return self

def addDriver(self, driverCls, *args, **kwargs):
assert issubclass(driverCls, Driver)
self.drivers += [driverCls(self, *args, **kwargs)]
return self

def setup(self):
for driver in self.drivers:
driver.setup()
for driver in self.drivers:
driver.finish()

def finish(self):
# underlying component are initialized recursively but require the parent to
# be fully initialized
for component in self.components:
component.setup()
for component in self.components:
component.finish()

def clean(self):
for component in reversed(self.components):
component.clean()
for driver in reversed(self.drivers):
driver.clean()

def resetIn(self):
for component in reversed(self.components):
component.resetIn()
for driver in reversed(self.drivers):
driver.resetIn()

def resetOut(self):
for driver in self.drivers:
driver.resetOut()
for component in self.components:
component.resetOut()

def _dumpDrivers(self, depth, prefix):
if len(self.drivers) == 1:
self.drivers[0].dump(prefix=' => ')
elif self.drivers:
spacer = ' ' * (depth * 3)
print('%s%sdrivers:' % (spacer, prefix))
for driver in self.drivers:
driver.dump(depth + 1)

def _dumpNode(self, depth, prefix):
depth += 1
spacer = ' ' * (depth * 3)
if self.drivers:
self._dumpDrivers(depth, prefix)
print('%s%scomponents:' % (spacer, prefix))
for component in self.components:
component.dump(depth + 1)

def dump(self, depth=0, prefix=' - '):
spacer = ' ' * (depth * 3)
end = '' if len(self.drivers) == 1 else '\n'
print('%s%s%s' % (spacer, prefix,self), end=end)
if self.components:
self._dumpNode(depth, prefix)
else:
self._dumpDrivers(depth, prefix)

84 changes: 84 additions & 0 deletions arista/core/driver.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
from __future__ import print_function

import logging
import subprocess

from utils import simulation

def modprobe(name, args=None):
logging.debug('loading module %s' % name)
if args is None:
args = []
args = ['modprobe', name.replace('-', '_')] + args
if simulation:
logging.debug('exec: %s' % ' '.join(args))
else:
subprocess.check_call(args)

def rmmod(name):
logging.debug('unloading module %s' % name)
args = ['modprobe', '-r', name.replace('-', '_')]
if simulation:
logging.debug('exec: %s' % ' '.join(args))
else:
subprocess.check_call(args)

def isModuleLoaded(name):
with open('/proc/modules') as f:
start = '%s ' % name.replace('-', '_')
for line in f.readlines():
if line.startswith(start):
return True
return False

class Driver(object):
def __init__(self, component):
self.component = component

def setup(self):
pass

def finish(self):
pass

def clean(self):
pass

def resetIn(self):
pass

def resetOut(self):
pass

def dump(self, depth=0, prefix=' - '):
spacer = ' ' * (depth * 3)
print('%s%s%s' % (spacer, prefix, self))

class KernelDriver(Driver):
# TODO: handle multiple kernel modules
def __init__(self, component, module, args=None):
super(KernelDriver, self).__init__(component)
self.component = component
self.module = module
self.args = args if args is not None else []

def setup(self):
modprobe(self.module, self.args)

def clean(self):
if self.loaded():
try:
rmmod(self.module)
except Exception as e:
logging.error('Failed to unload %s: %s' % (self.module, e))
else:
logging.debug('Module %s is not loaded' % self.module)

def loaded(self):
return isModuleLoaded(self.module)

def getSysfsPath(self):
raise NotImplementedError

def __str__(self):
return '%s(%s)' % (self.__class__.__name__, self.module)
75 changes: 75 additions & 0 deletions arista/core/platform.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
from __future__ import print_function

import logging
import subprocess
import os
import sys

from collections import OrderedDict

from component import Component
from utils import simulation
from driver import modprobe, rmmod, KernelDriver

platforms = {}
syseeprom = None

def readPrefdl():
if simulation:
logging.debug('bypass prefdl reading by returning default values')
return {'SKU': 'simulation'}

# FIXME: currently a hack that import an out of module script
# the prefdl should be added as part of the module
prefdl = {}
execfile('/usr/share/arista/prefdl', prefdl)

modprobe('eeprom')
for addr in ['1-0052']:
eeprompath = os.path.join('/sys/bus/i2c/drivers/eeprom', addr, 'eeprom')
if not os.path.exists(eeprompath):
continue
try:
with open(eeprompath) as f:
logging.debug('reading system eeprom from %s' % eeprompath)
return prefdl['decode'](f).data()
except Exception as e:
logging.warn('could not obtain prefdl from %s' % eeprompath)
logging.warn('error seen: %s' % e)

raise RuntimeError("Could not find valid system eeprom")

def getSysEeprom():
global syseeprom
if not syseeprom:
syseeprom = readPrefdl()
assert 'SKU' in syseeprom
return syseeprom

def detectPlatform():
return getSysEeprom()['SKU']

def getPlatform(name=None):
if name == None:
name = detectPlatform()
return platforms[name]()

def getPlatforms():
return platforms

def registerPlatform(sku):
global platforms
def wrapper(cls):
platforms[sku] = cls
return cls
return wrapper

class Platform(Component):
def __init__(self):
super(Platform, self).__init__()
self.addDriver(KernelDriver, 'eeprom')
self.addDriver(KernelDriver, 'i2c-dev')

def setup(self):
super(Platform, self).setup()
super(Platform, self).finish()
29 changes: 29 additions & 0 deletions arista/core/types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from collections import namedtuple

Register = namedtuple("Register", ["addr", "ro"])
NamedRegister = namedtuple("NamedRegister", Register._fields + ("name", ))

Gpio = namedtuple("Gpio", ["bit", "ro", "activeLow"])
NamedGpio = namedtuple("NamedGpio", ("addr",) + Gpio._fields + ("name",))

ResetGpio = namedtuple("ResetGpio", ["addr", "bit", "activeLow", "name"])

class I2cAddr(object):
def __init__(self, bus, address):
self.bus = bus
self.address = address

def __str__(self):
return '%d-00%02x' % (self.bus, self.address)

class PciAddr(object):
def __init__(self, domain=0, bus=0, device=0, func=0):
self.domain = domain
self.bus = bus
self.device = device
self.func = func

def __str__(self):
return '%04x:%02x:%02x.%d' % (self.domain, self.bus, self.device, self.func)


Loading

0 comments on commit 16cc6f6

Please sign in to comment.