From a697c2db2ed4a2f7a16227563a7d0a5ab31b583b Mon Sep 17 00:00:00 2001 From: "Joshua M. Boniface" Date: Mon, 21 Jun 2021 01:42:55 -0400 Subject: [PATCH] Add SRIOV PF and VF listing to API --- api-daemon/pvcapid/flaskapi.py | 128 +++++++++++++++++++++++++++++++++ api-daemon/pvcapid/helper.py | 56 +++++++++++++++ daemon-common/network.py | 111 ++++++++++++++++++++++++++++ 3 files changed, 295 insertions(+) diff --git a/api-daemon/pvcapid/flaskapi.py b/api-daemon/pvcapid/flaskapi.py index 2ce9c16b..54691368 100755 --- a/api-daemon/pvcapid/flaskapi.py +++ b/api-daemon/pvcapid/flaskapi.py @@ -2719,6 +2719,134 @@ class API_Network_ACL_Element(Resource): api.add_resource(API_Network_ACL_Element, '/network//acl/') +########################################################## +# Client API - SR-IOV +########################################################## + +# /sriov +class API_SRIOV_Root(Resource): + @Authenticator + def get(self): + pass + + +api.add_resource(API_SRIOV_Root, '/sriov') + + +# /sriov/pf +class API_SRIOV_PF_Root(Resource): + @RequestParser([ + {'name': 'node', 'required': True, 'helptext': "A valid node must be specified."}, + ]) + @Authenticator + def get(self, reqargs): + """ + Return a list of SR-IOV PFs on a given node + --- + tags: + - network / sriov + responses: + 200: + description: OK + schema: + type: object + id: sriov_pf + properties: + phy: + type: string + description: The name of the SR-IOV PF device + mtu: + type: string + description: The MTU of the SR-IOV PF device + vfs: + type: list + items: + type: string + description: The PHY name of a VF of this PF + """ + return api_helper.sriov_pf_list(reqargs.get('node')) + + +api.add_resource(API_SRIOV_PF_Root, '/sriov/pf') + + +# /sriov/vf +class API_SRIOV_VF_Root(Resource): + @RequestParser([ + {'name': 'node', 'required': True, 'helptext': "A valid node must be specified."}, + {'name': 'pf', 'required': False, 'helptext': "A PF parent may be specified."}, + ]) + @Authenticator + def get(self, reqargs): + """ + Return a list of SR-IOV VFs on a given node, optionally limited to those in the specified PF + --- + tags: + - network / sriov + responses: + 200: + description: OK + schema: + type: object + id: sriov_vf + properties: + phy: + type: string + description: The name of the SR-IOV VF device + pf: + type: string + description: The name of the SR-IOV PF parent of this VF device + mtu: + type: integer + description: The current MTU of the VF device + mac: + type: string + description: The current MAC address of the VF device + config: + type: object + id: sriov_vf_config + properties: + vlan_id: + type: string + description: The tagged vLAN ID of the SR-IOV VF device + vlan_qos: + type: string + description: The QOS group of the tagged vLAN + tx_rate_min: + type: string + description: The minimum TX rate of the SR-IOV VF device + tx_rate_max: + type: string + description: The maximum TX rate of the SR-IOV VF device + spoof_check: + type: boolean + description: Whether device spoof checking is enabled or disabled + link_state: + type: string + description: The current SR-IOV VF link state (either enabled, disabled, or auto) + trust: + type: boolean + description: Whether guest device trust is enabled or disabled + query_rss: + type: boolean + description: Whether VF RSS querying is enabled or disabled + usage: + type: object + id: sriov_vf_usage + properties: + used: + type: boolean + description: Whether the SR-IOV VF is currently used by a VM or not + domain: + type: boolean + description: The UUID of the domain the SR-IOV VF is currently used by + """ + return api_helper.sriov_vf_list(reqargs.get('node'), reqargs.get('pf', None)) + + +api.add_resource(API_SRIOV_VF_Root, '/sriov/vf') + + ########################################################## # Client API - Storage ########################################################## diff --git a/api-daemon/pvcapid/helper.py b/api-daemon/pvcapid/helper.py index 974130c6..bf6f345f 100755 --- a/api-daemon/pvcapid/helper.py +++ b/api-daemon/pvcapid/helper.py @@ -978,6 +978,62 @@ def net_acl_remove(zkhandler, network, description): return output, retcode +# +# SR-IOV functions +# +@ZKConnection(config) +def sriov_pf_list(zkhandler, node): + """ + List all PFs on a given node. + """ + retflag, retdata = pvc_network.get_list_sriov_pf(zkhandler, node) + + if retflag: + if retdata: + retcode = 200 + else: + retcode = 404 + retdata = { + 'message': 'PF not found.' + } + else: + retcode = 400 + retdata = { + 'message': retdata + } + + return retdata, retcode + + +@ZKConnection(config) +def sriov_vf_list(zkhandler, node, pf=None): + """ + List all VFs on a given node, optionally limited to PF. + """ + retflag, retdata = pvc_network.get_list_sriov_vf(zkhandler, node, pf) + + if retflag: + retcode = 200 + else: + retcode = 400 + + if retflag: + if retdata: + retcode = 200 + else: + retcode = 404 + retdata = { + 'message': 'VF not found.' + } + else: + retcode = 400 + retdata = { + 'message': retdata + } + + return retdata, retcode + + # # Ceph functions # diff --git a/daemon-common/network.py b/daemon-common/network.py index 67f7bdea..d810d1dd 100644 --- a/daemon-common/network.py +++ b/daemon-common/network.py @@ -629,3 +629,114 @@ def get_list_acl(zkhandler, network, limit, direction, is_fuzzy=True): acl_list.append(acl) return True, acl_list + + +# +# SR-IOV functions +# +# These are separate since they don't work like other network types +# +def getSRIOVPFInformation(zkhandler, node, pf): + mtu = zkhandler.read(('node.sriov.pf', node, 'sriov_pf.mtu', pf)) + + retcode, vf_list = get_list_sriov_vf(zkhandler, node, pf) + if retcode: + vfs = [vf['phy'] for vf in vf_list if vf['pf'] == pf] + else: + vfs = [] + + # Construct a data structure to represent the data + pf_information = { + 'phy': pf, + 'mtu': mtu, + 'vfs': vfs, + } + return pf_information + + +def get_info_sriov_pf(zkhandler, node, pf): + pf_information = getSRIOVPFInformation(zkhandler, node, pf) + if not pf_information: + return False, 'ERROR: Could not get information about SR-IOV PF "{}" on node "{}"'.format(pf, node) + + return True, pf_information + + +def get_list_sriov_pf(zkhandler, node): + pf_list = list() + pf_phy_list = zkhandler.children(('node.sriov.pf', node)) + for phy in pf_phy_list: + retcode, pf_information = get_info_sriov_pf(zkhandler, node, phy) + if retcode: + pf_list.append(pf_information) + + return True, pf_list + + +def getSRIOVVFInformation(zkhandler, node, vf): + pf = zkhandler.read(('node.sriov.vf', node, 'sriov_vf.pf', vf)) + mtu = zkhandler.read(('node.sriov.vf', node, 'sriov_vf.mtu', vf)) + mac = zkhandler.read(('node.sriov.vf', node, 'sriov_vf.mac', vf)) + vlan_id = zkhandler.read(('node.sriov.vf', node, 'sriov_vf.config.vlan_id', vf)) + vlan_qos = zkhandler.read(('node.sriov.vf', node, 'sriov_vf.config.vlan_qos', vf)) + tx_rate_min = zkhandler.read(('node.sriov.vf', node, 'sriov_vf.config.tx_rate_min', vf)) + tx_rate_max = zkhandler.read(('node.sriov.vf', node, 'sriov_vf.config.tx_rate_max', vf)) + spoof_check = zkhandler.read(('node.sriov.vf', node, 'sriov_vf.config.spoof_check', vf)) + link_state = zkhandler.read(('node.sriov.vf', node, 'sriov_vf.config.link_state', vf)) + trust = zkhandler.read(('node.sriov.vf', node, 'sriov_vf.config.trust', vf)) + query_rss = zkhandler.read(('node.sriov.vf', node, 'sriov_vf.config.query_rss', vf)) + used = zkhandler.read(('node.sriov.vf', node, 'sriov_vf.used', vf)) + used_by_domain = zkhandler.read(('node.sriov.vf', node, 'sriov_vf.used_by', vf)) + + vf_information = { + 'phy': vf, + 'pf': pf, + 'mtu': mtu, + 'mac': mac, + 'config': { + 'vlan_id': vlan_id, + 'vlan_qos': vlan_qos, + 'tx_rate_min': tx_rate_min, + 'tx_rate_max': tx_rate_max, + 'spoof_check': spoof_check, + 'link_state': link_state, + 'trust': trust, + 'query_rss': query_rss, + }, + 'usage': { + 'used': used, + 'domain': used_by_domain, + } + } + return vf_information + + +def get_info_sriov_vf(zkhandler, node, vf): + vf_information = getSRIOVVFInformation(zkhandler, node, vf) + if not vf_information: + return False, 'ERROR: Could not get information about SR-IOV VF "{}" on node "{}"'.format(vf, node) + + return True, vf_information + + +def get_list_sriov_vf(zkhandler, node, pf=None): + vf_list = list() + vf_phy_list = sorted(zkhandler.children(('node.sriov.vf', node))) + for phy in vf_phy_list: + retcode, vf_information = get_info_sriov_vf(zkhandler, node, phy) + if retcode: + if pf is not None: + if vf_information['pf'] == pf: + vf_list.append(vf_information) + else: + vf_list.append(vf_information) + + return True, vf_list + + +def set_sriov_vf_config(zkhandler, node, vf, vlan_id=None, vlan_qos=None, tx_rate_min=None, tx_rate_max=None, spoof_check=None, link_state=None, trust=None, query_rss=None): + pass + + +def set_sriov_vf_vm(zkhandler, node, vf, vm_name, vm_macaddr): + pass