Source code for linuxnet.qos.exceptions

# Copyright (c) 2021, 2022, Panagiotis Tsirigotis

# This file is part of linuxnet-qos.
#
# linuxnet-qos is free software: you can redistribute it and/or
# modify it under the terms of version 3 of the GNU Affero General Public
# License as published by the Free Software Foundation.
#
# linuxnet-qos 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 Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General
# Public License along with linuxnet-qos. If not, see
# <https://www.gnu.org/licenses/>.

"""Exceptions raised by the QoS classes
"""

import errno
import os

from typing import Optional

[docs]class TcError(Exception): """Traffic control error; this is the base exception class for all QoS-related exceptions. """
[docs]class TcConfigError(TcError): """Raised when an error is encountered while processing the existing queuing discipline configuration of an interface. """
[docs]class TcParsingError(TcConfigError): """Error while parsing the output of the **tc(8)** command. """ def __init__(self, *args, **kwargs): self.__line = kwargs.pop('line', None) super().__init__(*args, **kwargs)
[docs] def set_line(self, line: str) -> None: """Identify the line where the parsing error happened. Once set, this cannot be changed. Note that it may be set via the constructor. """ if self.__line is None: self.__line = line
[docs] def get_line(self) -> Optional[str]: """Returns the line where the parsing error was encountered. """ return self.__line
def __str__(self): if self.__line: return super().__str__() + ": " + self.__line return super().__str__()
[docs]class TcExecutionError(TcError): """Error executing the **tc(8)** command. """ __RTNETLINK_PREFIX = 'RTNETLINK answers: ' __RTNETLINK_PREFIX_LEN = len(__RTNETLINK_PREFIX) __ERROR_PREFIX = 'Error: ' __ERROR_PREFIX_LEN = len(__ERROR_PREFIX) def __init__(self, msg, procerr=None): # tc will report the string corresponding to an # errno value prefixed by __RTNETLINK_PREFIX for some # failures. We attempt to detect that and save # the errno value. self.__rtnetlink_errno = 0 self.__error_message = None self.__stderr_line = None if procerr is not None: self.__init_from_stderr(procerr) if self.__stderr_line is not None: msg += ': ' + self.__stderr_line super().__init__(msg) def __init_from_stderr(self, procerr): """Initialize attributes from standard error """ if procerr.stderr is None: return stderr_lines = procerr.stderr.strip().split('\n') if not stderr_lines: return self.__stderr_line = stderr_lines[0] # If the netlink exchange includes an error message from the kernel # (e.g. as seen in 4.18.0) tc will report that prefixed with the # __ERROR_PREFIX above. In this case, we determine the errno from # the message string. # Otherwise, if netlink exchange reports an errno value, tc will # report that prefixed with __RTNETLINK_PREFIX. In this case, # we save the error string. if self.__stderr_line.startswith(self.__RTNETLINK_PREFIX): rtnetlink_msg = self.__stderr_line[self.__RTNETLINK_PREFIX_LEN:] for errval in errno.errorcode: if os.strerror(errval) == rtnetlink_msg: self.__rtnetlink_errno = errval break else: self.__error_message = rtnetlink_msg elif self.__stderr_line.startswith(self.__ERROR_PREFIX): self.__error_message = self.__stderr_line[self.__ERROR_PREFIX_LEN:]
[docs] def get_error_message(self): """Return the netlink error message If None, no message was detected. """ return self.__error_message
[docs]class TcBandwidthError(TcError): """Raised when a bandwidth request cannot be satisfied. """