예제 #1
0
    def pack(self, value=None):
        """Pack the struct in a binary representation.

        Iterate over the class attributes, according to the
        order of definition, and then convert each attribute to its byte
        representation using its own ``pack`` method.

        Returns:
            bytes: Binary representation of the struct object.

        Raises:
            :exc:`~.exceptions.ValidationError`: If validation fails.

        """
        if value is None:
            if not self.is_valid():
                error_msg = "Error on validation prior to pack() on class "
                error_msg += "{}.".format(type(self).__name__)
                raise ValidationError(error_msg)
            message = b''
            # pylint: disable=no-member
            for attr_info in self._get_named_attributes():
                name, instance_value, class_value = attr_info
                try:
                    message += class_value.pack(instance_value)
                except PackException as pack_exception:
                    cls = type(self).__name__
                    msg = f'{cls}.{name} - {pack_exception}'
                    raise PackException(msg)
            return message
        if isinstance(value, type(self)):
            return value.pack()
        msg = "{} is not an instance of {}".format(value, type(self).__name__)
        raise PackException(msg)
예제 #2
0
    def pack(self, value=None):
        """Pack the value as a binary representation.

        :attr:`data` is packed before the calling :meth:`.GenericMessage.pack`.
        After that, :attr:`data`'s value is restored.

        Returns:
            bytes: The binary representation.

        Raises:
            :exc:`~.exceptions.PackException`: If pack fails.

        """
        if value is None:
            data_backup = None
            if self.data is not None and not isinstance(self.data, bytes):
                data_backup = self.data
                self.data = self.data.pack()
            packed = super().pack()
            if data_backup is not None:
                self.data = data_backup
            return packed
        if isinstance(value, type(self)):
            return value.pack()
        msg = "{} is not an instance of {}".format(value, type(self).__name__)
        raise PackException(msg)
예제 #3
0
    def pack(self, value=None):
        """Pack the message into a binary data.

        One of the basic operations on a Message is the pack operation. During
        the packing process, we convert all message attributes to binary
        format.

        Since that this is usually used before sending the message to a switch,
        here we also call :meth:`update_header_length`.

        .. seealso:: This method call its parent's :meth:`GenericStruct.pack`
            after :meth:`update_header_length`.

        Returns:
            bytes: A binary data thats represents the Message.

        Raises:
            Exception: If there are validation errors.

        """
        if value is None:
            self.update_header_length()
            return super().pack()
        elif isinstance(value, type(self)):
            return value.pack()
        else:
            msg = "{} is not an instance of {}".format(value,
                                                       type(self).__name__)
            raise PackException(msg)
예제 #4
0
    def get_size(self, value=None):
        """Calculate the total struct size in bytes.

        For each struct attribute, sum the result of each one's ``get_size()``
        method.

        Args:
            value: In structs, the user can assign other value instead of a
                class' instance.

        Returns:
            int: Total number of bytes used by the struct.

        Raises:
            Exception: If the struct is not valid.

        """
        if value is None:
            return sum(
                cls_val.get_size(obj_val)
                for obj_val, cls_val in self._get_attributes())
        elif isinstance(value, type(self)):
            return value.get_size()
        else:
            msg = "{} is not an instance of {}".format(value,
                                                       type(self).__name__)
            raise PackException(msg)
예제 #5
0
 def pack(self, value=None):
     """Update the action_len attribute and call super's pack."""
     if value is None:
         self._update_actions_len()
         return super().pack()
     if isinstance(value, type(self)):
         return value.pack()
     msg = "{} is not an instance of {}".format(value, type(self).__name__)
     raise PackException(msg)
예제 #6
0
 def pack(self, value=None):
     """Pack and complete the last byte by padding."""
     if isinstance(value, Match):
         return value.pack()
     if value is None:
         self._update_match_length()
         packet = super().pack()
         return self._complete_last_byte(packet)
     raise PackException(f'Match can\'t unpack "{value}".')
예제 #7
0
    def pack(self, value=None):
        """Update the length and pack the massege into binary data.

        Returns:
            bytes: A binary data that represents the Message.

        Raises:
            Exception: If there are validation errors.

        """
        if value is None:
            self.update_length()
            return super().pack()
        if isinstance(value, type(self)):
            return value.pack()
        msg = "{} is not an instance of {}".format(value, type(self).__name__)
        raise PackException(msg)
예제 #8
0
    def pack(self, value=None):
        r"""Pack the value as a binary representation.

        Considering an example with UBInt8 class, that inherits from
        GenericType:

        >>> from pyof.foundation.basic_types import UBInt8
        >>> objectA = UBInt8(1)
        >>> objectB = 5
        >>> objectA.pack()
        b'\x01'
        >>> objectA.pack(objectB)
        b'\x05'

        Args:
            value: If the value is None, then we will pack the value of the
                current instance. Otherwise, if value is an instance of the
                same type as the current instance, then we call the pack of the
                value object. Otherwise, we will use the current instance pack
                method on the passed value.

        Returns:
            bytes: The binary representation.

        Raises:
            :exc:`~.exceptions.BadValueException`: If the value does not
                fit the binary format.

        """
        if isinstance(value, type(self)):
            return value.pack()

        if value is None:
            value = self.value
        elif 'value' in dir(value):
            # if it is enum or bitmask gets only the 'int' value
            value = value.value

        try:
            return struct.pack(self._fmt, value)
        except struct.error:
            expected_type = type(self).__name__
            actual_type = type(value).__name__
            msg_args = expected_type, value, actual_type
            msg = 'Expected {}, found value "{}" of type {}'.format(*msg_args)
            raise PackException(msg)
예제 #9
0
    def pack(self, value=None):
        """Pack the TLV in a binary representation.

        Returns:
            bytes: Binary representation of the struct object.

        Raises:
            :exc:`~.exceptions.ValidationError`: If validation fails.

        """
        if value is None:
            output = self.header.pack()
            output += self.value.pack()
            return output
        if isinstance(value, type(self)):
            return value.pack()
        msg = "{} is not an instance of {}".format(value, type(self).__name__)
        raise PackException(msg)
예제 #10
0
    def pack(self, value=None):
        """Join oxm_hasmask bit and 7-bit oxm_field."""
        if value is not None:
            return value.pack()

        # Set oxm_field_and_mask instance attribute
        # 1. Move field integer one bit to the left
        try:
            field_int = self._get_oxm_field_int()
        except ValueError as exception:
            raise PackException(exception)
        field_bits = field_int << 1
        # 2. hasmask bit
        hasmask_bit = self.oxm_hasmask & 1
        # 3. Add hasmask bit to field value
        self.oxm_field_and_mask = field_bits + hasmask_bit

        self._update_length()
        return super().pack(value)