#!/usr/bin/env python3 # SRIOVVFInstance.py - Class implementing a PVC SR-IOV VF and run by pvcnoded # Part of the Parallel Virtual Cluster (PVC) system # # Copyright (C) 2018-2024 Joshua M. Boniface # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # ############################################################################### import daemon_lib.common as common def boolToOnOff(state): if state and str(state) == "True": return "on" else: return "off" class SRIOVVFInstance(object): # Initialization function def __init__(self, vf, zkhandler, config, logger, this_node): self.vf = vf self.zkhandler = zkhandler self.config = config self.logger = logger self.this_node = this_node self.myhostname = self.this_node.name self.pf = self.zkhandler.read( ("node.sriov.vf", self.myhostname, "sriov_vf.pf", self.vf) ) self.mtu = self.zkhandler.read( ("node.sriov.vf", self.myhostname, "sriov_vf.mtu", self.vf) ) self.vfid = self.vf.replace("{}v".format(self.pf), "") self.logger.out( "Setting MTU to {}".format(self.mtu), state="i", prefix="SR-IOV VF {}".format(self.vf), ) common.run_os_command("ip link set {} mtu {}".format(self.vf, self.mtu)) # These properties are set via the DataWatch functions, to ensure they are configured on the system self.mac = None self.vlan_id = None self.vlan_qos = None self.tx_rate_min = None self.tx_rate_max = None self.spoof_check = None self.link_state = None self.trust = None self.query_rss = None # Zookeeper handlers for changed configs @self.zkhandler.zk_conn.DataWatch( self.zkhandler.schema.path("node.sriov.vf", self.myhostname) + self.zkhandler.schema.path("sriov_vf.mac", self.vf) ) def watch_vf_mac(data, stat, event=""): if event and event.type == "DELETED": # The key has been deleted after existing before; terminate this watcher # because this class instance is about to be reaped in Daemon.py return False try: data = data.decode("ascii") except AttributeError: data = "00:00:00:00:00:00" if data != self.mac: self.mac = data @self.zkhandler.zk_conn.DataWatch( self.zkhandler.schema.path("node.sriov.vf", self.myhostname) + self.zkhandler.schema.path("sriov_vf.config.vlan_id", self.vf) ) def watch_vf_vlan_id(data, stat, event=""): if event and event.type == "DELETED": # The key has been deleted after existing before; terminate this watcher # because this class instance is about to be reaped in Daemon.py return False try: data = data.decode("ascii") except AttributeError: data = "0" if data != self.vlan_id: self.vlan_id = data self.logger.out( "Setting vLAN ID to {}".format(self.vlan_id), state="i", prefix="SR-IOV VF {}".format(self.vf), ) common.run_os_command( "ip link set {} vf {} vlan {} qos {}".format( self.pf, self.vfid, self.vlan_id, self.vlan_qos ) ) @self.zkhandler.zk_conn.DataWatch( self.zkhandler.schema.path("node.sriov.vf", self.myhostname) + self.zkhandler.schema.path("sriov_vf.config.vlan_qos", self.vf) ) def watch_vf_vlan_qos(data, stat, event=""): if event and event.type == "DELETED": # The key has been deleted after existing before; terminate this watcher # because this class instance is about to be reaped in Daemon.py return False try: data = data.decode("ascii") except AttributeError: data = "0" if data != self.vlan_qos: self.vlan_qos = data self.logger.out( "Setting vLAN QOS to {}".format(self.vlan_qos), state="i", prefix="SR-IOV VF {}".format(self.vf), ) common.run_os_command( "ip link set {} vf {} vlan {} qos {}".format( self.pf, self.vfid, self.vlan_id, self.vlan_qos ) ) @self.zkhandler.zk_conn.DataWatch( self.zkhandler.schema.path("node.sriov.vf", self.myhostname) + self.zkhandler.schema.path("sriov_vf.config.tx_rate_min", self.vf) ) def watch_vf_tx_rate_min(data, stat, event=""): if event and event.type == "DELETED": # The key has been deleted after existing before; terminate this watcher # because this class instance is about to be reaped in Daemon.py return False try: data = data.decode("ascii") except AttributeError: data = "0" if data != self.tx_rate_min: self.tx_rate_min = data self.logger.out( "Setting minimum TX rate to {}".format(self.tx_rate_min), state="i", prefix="SR-IOV VF {}".format(self.vf), ) common.run_os_command( "ip link set {} vf {} min_tx_rate {}".format( self.pf, self.vfid, self.tx_rate_min ) ) @self.zkhandler.zk_conn.DataWatch( self.zkhandler.schema.path("node.sriov.vf", self.myhostname) + self.zkhandler.schema.path("sriov_vf.config.tx_rate_max", self.vf) ) def watch_vf_tx_rate_max(data, stat, event=""): if event and event.type == "DELETED": # The key has been deleted after existing before; termaxate this watcher # because this class instance is about to be reaped in Daemon.py return False try: data = data.decode("ascii") except AttributeError: data = "0" if data != self.tx_rate_max: self.tx_rate_max = data self.logger.out( "Setting maximum TX rate to {}".format(self.tx_rate_max), state="i", prefix="SR-IOV VF {}".format(self.vf), ) common.run_os_command( "ip link set {} vf {} max_tx_rate {}".format( self.pf, self.vfid, self.tx_rate_max ) ) @self.zkhandler.zk_conn.DataWatch( self.zkhandler.schema.path("node.sriov.vf", self.myhostname) + self.zkhandler.schema.path("sriov_vf.config.spoof_check", self.vf) ) def watch_vf_spoof_check(data, stat, event=""): if event and event.type == "DELETED": # The key has been deleted after existing before; terminate this watcher # because this class instance is about to be reaped in Daemon.py return False try: data = data.decode("ascii") except AttributeError: data = "0" if data != self.spoof_check: self.spoof_check = data self.logger.out( "Setting spoof checking {}".format(boolToOnOff(self.spoof_check)), state="i", prefix="SR-IOV VF {}".format(self.vf), ) common.run_os_command( "ip link set {} vf {} spoofchk {}".format( self.pf, self.vfid, boolToOnOff(self.spoof_check) ) ) @self.zkhandler.zk_conn.DataWatch( self.zkhandler.schema.path("node.sriov.vf", self.myhostname) + self.zkhandler.schema.path("sriov_vf.config.link_state", self.vf) ) def watch_vf_link_state(data, stat, event=""): if event and event.type == "DELETED": # The key has been deleted after existing before; terminate this watcher # because this class instance is about to be reaped in Daemon.py return False try: data = data.decode("ascii") except AttributeError: data = "on" if data != self.link_state: self.link_state = data self.logger.out( "Setting link state to {}".format(boolToOnOff(self.link_state)), state="i", prefix="SR-IOV VF {}".format(self.vf), ) common.run_os_command( "ip link set {} vf {} state {}".format( self.pf, self.vfid, self.link_state ) ) @self.zkhandler.zk_conn.DataWatch( self.zkhandler.schema.path("node.sriov.vf", self.myhostname) + self.zkhandler.schema.path("sriov_vf.config.trust", self.vf) ) def watch_vf_trust(data, stat, event=""): if event and event.type == "DELETED": # The key has been deleted after existing before; terminate this watcher # because this class instance is about to be reaped in Daemon.py return False try: data = data.decode("ascii") except AttributeError: data = "off" if data != self.trust: self.trust = data self.logger.out( "Setting trust mode {}".format(boolToOnOff(self.trust)), state="i", prefix="SR-IOV VF {}".format(self.vf), ) common.run_os_command( "ip link set {} vf {} trust {}".format( self.pf, self.vfid, boolToOnOff(self.trust) ) ) @self.zkhandler.zk_conn.DataWatch( self.zkhandler.schema.path("node.sriov.vf", self.myhostname) + self.zkhandler.schema.path("sriov_vf.config.query_rss", self.vf) ) def watch_vf_query_rss(data, stat, event=""): if event and event.type == "DELETED": # The key has been deleted after existing before; terminate this watcher # because this class instance is about to be reaped in Daemon.py return False try: data = data.decode("ascii") except AttributeError: data = "off" if data != self.query_rss: self.query_rss = data self.logger.out( "Setting RSS query ability {}".format(boolToOnOff(self.query_rss)), state="i", prefix="SR-IOV VF {}".format(self.vf), ) common.run_os_command( "ip link set {} vf {} query_rss {}".format( self.pf, self.vfid, boolToOnOff(self.query_rss) ) )