Commit 68a9163e by Sunil Kumar Veerappa

Add m2dc driver

1. Checks for MAC address of the FPGA systems in RECS_Master
2. Extract IP address by arping the MAC
3. Upload FPGA bitstream in Glance
4. Program FPGA with bitstream through SSH
parent bec9a173
......@@ -19,8 +19,7 @@ Cyborg FPGA driver implementation.
from cyborg.accelerator.drivers.fpga import utils
VENDOR_MAPS = {"0x8086": "intel"}
VENDOR_MAPS = {"0x8086": "intel","0xXXXX": "m2dc"}
class FPGADriver(object):
......
# Copyright 2018 Huawei Technologies
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
Cyborg M2DC FPGA driver implementation.
"""
import subprocess
import os
import ast
from collections import Counter
from oslo_log import log as logging
import paramiko
import sys
from cyborg import objects
from cyborg.objects.device import Device
from cyborg.accelerator.drivers.fpga.base import FPGADriver
from cyborg.accelerator.drivers.fpga.m2dc import sysinfo
LOG = logging.getLogger(__name__)
class M2DCFPGADriver(FPGADriver):
"""Base class for FPGA drivers.
This is just a virtual FPGA drivers interface.
Vedor should implement their specific drivers.
"""
VENDOR = "m2dc"
def __init__(self, *args, **kwargs):
pass
def discover(self):
return sysinfo.discover_boards()
def program(self, device_id, image):
device_details = Device.get_by_id(self, device_id)
p = subprocess.Popen(["scp", "-c", "aes128-ctr", str(image), "root@" + device_details.std_board_info + ":/tmp/."])
sts = os.waitpid(p.pid, 0)
SSH_USERNAME = "root"
SSH_PASSWORD = ''
SSH_COMMAND = "source /home/root/init_opencl.sh; aocl program " + image
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_stdin = ssh_stdout = ssh_stderr = None
try:
ssh.connect(device_details.std_board_info, username=SSH_USERNAME, password=SSH_PASSWORD)
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command(SSH_COMMAND)
except Exception as e:
sys.stderr.write("SSH connection error: {0}".format(e))
if ssh_stdout:
sys.stdout.write(ssh_stdout.read())
if ssh_stderr:
sys.stderr.write(ssh_stderr.read())
# Copyright 2018 Huawei Technologies
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
Cyborg M2DC FPGA driver implementation.
"""
from oslo_log import log as logging
import glob
import os,sys
import json
import ast
import flask
import requests
import subprocess
import re
import fcntl, socket, struct
import hashlib
from requests import auth
import paramiko
import cyborg.conf
from cyborg.objects.driver_objects import driver_deployable, driver_device,\
driver_attach_handle, driver_controlpath_id
from cyborg.common import constants
headers = {'Content-Type': 'application/json'}
CONF = cyborg.conf.CONF
RECS_URL = None
list_fpga_id=[]
list_fpga_mac=[]
list_fpga_ip=[]
LOG = logging.getLogger(__name__)
def get_configuration():
global RECS_URL
RECS_URL = str(CONF.agent.url)
def available_Systems():
listed_systems = []
r = requests.get(RECS_URL+"Systems", headers=headers)
json_data = json.loads(r.text)
j = ast.literal_eval(str(json_data['Members']))
for item in j:
sys_res = requests.get(RECS_URL+"Systems" + str(
str(str(str(item).replace("'", "")).split('u@odata.id: u'))[26:])[:-3], headers=headers)
listed_systems.append(str(str(str(str(item).replace("'", "")).split('u@odata.id: u'))[27:])[:-3])
return listed_systems
def checkFPGA(system_id):
response = requests.get(RECS_URL+'Systems/' + system_id, headers=headers)
json_data = json.loads(response.text)
if json_data["ProcessorSummary"]["Model"] == "Stratix 10 SX 2800":
response_eth = requests.get(RECS_URL + 'Systems/' + system_id + "/EthernetInterfaces/" + system_id + "_IF_Eth_0",
headers=headers)
json_data_eth = json.loads(response_eth.text)
if json_data_eth["PermanentMACAddress"] not in list_fpga_mac:
list_fpga_mac.append(json_data_eth["PermanentMACAddress"])
return True
return False
def list_fpga():
get_configuration()
available_systems_RECSmaster=[]
# First list down all the systems from RECS master
available_systems_RECSmaster = available_Systems()
# Check if any of the system is fpga or not
for system in available_systems_RECSmaster:
if checkFPGA(system):
if system not in list_fpga_id:
list_fpga_id.append(system)
def _generate_dep_list(item):
dep_list = []
driver_dep = driver_deployable.DriverDeployable()
driver_dep.attach_handle_list = []
driver_dep.num_accelerators = 2
driver_dep.attach_handle_list = \
[_generate_attach_handle(item)]
driver_dep.name = item
dep_list.append(driver_dep)
return dep_list
def _generate_attach_handle(item):
driver_ah = driver_attach_handle.DriverAttachHandle()
driver_ah.attach_type = "PCI"
driver_ah.attach_info = item
driver_ah.in_use = False
return driver_ah
def _generate_controlpath_id(item):
driver_cpid = driver_controlpath_id.DriverControlPathID()
driver_cpid.cpid_type = "PCI"
driver_cpid.cpid_info = item
return driver_cpid
def _generate_driver_device(item, ip_item, device_data):
driver_device_obj = driver_device.DriverDevice()
driver_device_obj.vendor = "stratix 10 "+device_data["vendorName"]
driver_device_obj.model = device_data["physicalName"]
driver_device_obj.std_board_info = ip_item
driver_device_obj.vendor_board_info = device_data["deviceName"]
driver_device_obj.type = constants.DEVICE_FPGA
driver_device_obj.controlpath_id = _generate_controlpath_id(item)
driver_device_obj.deployable_list = _generate_dep_list(item)
return driver_device_obj
def extractData(Data):
deviceDict={}
device_name = str(str(Data.split("\n")[2:3]).split("['")[1]).split("']")[0]
vendor_name = str(Data.split("\n")[7:8])[10:19]
phy_name = str(Data.split("\n")[11:12])[2:21]
deviceDict["deviceName"] = device_name
deviceDict["vendorName"] = vendor_name
deviceDict["physicalName"] = phy_name
return deviceDict
def discover_boards():
devs = []
device_data={}
#Added mechanism to extract IP addresses of the FPGA available in RECS board
list_fpga()
#extract ip from the mac address
for mac_record in list_fpga_mac:
ip_fpga = subprocess.check_output(str("arp -n | grep -w -i " + mac_record + " | awk \'{print $1}\'"),
stdin=subprocess.PIPE, shell=True)
if ip_fpga.rstrip() not in list_fpga_ip:
list_fpga_ip.append(ip_fpga.rstrip())
#feed to the agent service using the extracted IP
for item, ip_item in zip(list_fpga_id, list_fpga_ip):
SSH_USERNAME = "root"
SSH_PASSWORD = ''
SSH_COMMAND = "source /home/root/init_opencl.sh ; aocl diagnose"
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_stdin = ssh_stdout = ssh_stderr = None
try:
ssh.connect(ip_item, username=SSH_USERNAME, password=SSH_PASSWORD)
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command(SSH_COMMAND)
except Exception as e:
sys.stderr.write("SSH connection error: {0}".format(e))
if ssh_stdout:
Data = str(ssh_stdout.read())
LOG.error(str(Data))
ssh.close()
device_data = extractData(Data)
devs.append(_generate_driver_device(item, ip_item, device_data))
return devs
......@@ -16,6 +16,7 @@
import oslo_messaging as messaging
from oslo_service import periodic_task
from stevedore.extension import ExtensionManager
from cyborg.accelerator.drivers.fpga.base import FPGADriver
from cyborg.agent.resource_tracker import ResourceTracker
from cyborg.agent.rpcapi import AgentAPI
......@@ -23,6 +24,7 @@ from cyborg.image.api import API as ImageAPI
from cyborg.conductor import rpcapi as cond_api
from cyborg.conf import CONF
from cyborg.common import exception
class AgentManager(periodic_task.PeriodicTasks):
"""Cyborg Agent manager main class."""
......@@ -53,8 +55,17 @@ class AgentManager(periodic_task.PeriodicTasks):
# And add claim and rollback logical.
path = self._download_bitstream(context, image_uuid)
dep = self.cond_api.deployable_get(context, deployable_uuid)
driver = self.fpga_driver.create(dep.vendor)
driver.program(dep.address, path)
enabled_drivers = CONF.agent.enabled_drivers
valid_drivers = ExtensionManager(
namespace='cyborg.accelerator.driver').names()
for d in enabled_drivers:
if d not in valid_drivers:
raise exception.InvalidDriver(name=d)
acc_driver = driver.DriverManager(
namespace='cyborg.accelerator.driver', name=d,
invoke_on_load=True).driver
acc_driver.program(dep.device_id, path)
def _download_bitstream(self, context, bitstream_uuid):
"""download the bistream
......
......@@ -22,6 +22,10 @@ opts = [
default=[],
help=_('The accelerator drivers enabled on this agent. Such '
'as intel_fpga_driver, nvidia_gpu_driver, etc.')),
cfg.StrOpt('url',
help=_('The URL of Redfish API server. (e.g.: '
'http(s)://<IP>:<PORT>/). Required.')),
]
opt_group = cfg.OptGroup(name='agent',
......
......@@ -359,6 +359,15 @@ class Connection(api.Connection):
except NoResultFound:
raise exception.DeviceNotFound(uuid=uuid)
def device_get_by_id(self, context, id):
query = model_query(
context,
models.Device).filter_by(id=id)
try:
return query.one()
except NoResultFound:
raise exception.DeviceNotFound(id=id)
def device_list_by_filters(self, context,
filters, sort_key='created_at',
sort_dir='desc', limit=None,
......
......@@ -60,6 +60,13 @@ class Device(base.CyborgObject, object_base.VersionedObjectDictCompat):
return obj_device
@classmethod
def get_by_id(cls, context, id):
"""Find a DB Deployable and return an Obj Deployable."""
db_device = cls.dbapi.device_get_by_id(context, id)
obj_device = cls._from_db_object(cls(context), db_device)
return obj_device
@classmethod
def list(cls, context, filters={}):
"""Return a list of Device objects."""
if filters:
......
......@@ -47,6 +47,7 @@ cyborg.database.migration_backend =
cyborg.accelerator.driver =
intel_fpga_driver = cyborg.accelerator.drivers.fpga.intel.driver:IntelFPGADriver
m2dc_fpga_driver = cyborg.accelerator.drivers.fpga.m2dc.driver:M2DCFPGADriver
nvmf_spdk_driver = cyborg.accelerator.drivers.spdk.nvmf.nvmf:NVMFDRIVER
nvidia_gpu_driver = cyborg.accelerator.drivers.gpu.nvidia.driver:NVIDIAGPUDriver
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment