Пример #1
0
class PacketOut(GenericMessage):
    """Send packet (controller -> datapath)."""

    #: :class:`~pyof.v0x01.common.header.Header`
    header = Header(message_type=Type.OFPT_PACKET_OUT)
    buffer_id = UBInt32()
    in_port = UBInt16()
    actions_len = UBInt16()
    actions = ListOfActions()
    data = BinaryData()

    def __init__(self,
                 xid=None,
                 buffer_id=NO_BUFFER,
                 in_port=Port.OFPP_NONE,
                 actions=None,
                 data=b''):
        """Create a PacketOut with the optional parameters below.

        Args:
            xid (int): xid of the message header.
            buffer_id (int): ID assigned by datapath (-1 if none).
            in_port (:class:`int` / :class:`~pyof.v0x01.common.phy_port.Port`):
                Packet's input port (:attr:`.Port.OFPP_NONE` if none). Virtual
                ports :attr:`Port.OFPP_IN_PORT`, :attr:`Port.OFPP_TABLE`,
                :attr:`Port.OFPP_NORMAL`, :attr:`Port.OFPP_FLOOD`, and
                :attr:`Port.OFPP_ALL` cannot be used as input port.
            actions (~pyof.v0x01.common.action.ListOfActions): List of Actions.
            data (bytes): Packet data. The length is inferred from the length
                field in the header. (Only meaningful if ``buffer_id`` == -1).
        """
        super().__init__(xid)
        self.buffer_id = buffer_id
        self.in_port = in_port
        self.actions = [] if actions is None else actions
        self.data = data

    def validate(self):
        """Validate the entire message."""
        if not super().is_valid():
            raise ValidationError()
        self._validate_in_port()

    def is_valid(self):
        """Answer if this message is valid."""
        try:
            self.validate()
            return True
        except ValidationError:
            return False

    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()
        elif isinstance(value, type(self)):
            return value.pack()
        else:
            msg = "{} is not an instance of {}".format(value,
                                                       type(self).__name__)
            raise PackException(msg)

    def unpack(self, buff, offset=0):
        """Unpack a binary message into this object's attributes.

        Unpack the binary value *buff* and update this object attributes based
        on the results. It is an inplace method and it receives the binary data
        of the message **without the header**.

        This class' unpack method is like the :meth:`.GenericMessage.unpack`
        one, except for the ``actions`` attribute which has a length determined
        by the ``actions_len`` attribute.

        Args:
            buff (bytes): Binary data package to be unpacked, without the
                header.
            offset (int): Where to begin unpacking.
        """
        begin = offset
        for attribute_name, class_attribute in self.get_class_attributes():
            if type(class_attribute).__name__ != "Header":
                attribute = deepcopy(class_attribute)
                if attribute_name == 'actions':
                    length = self.actions_len.value
                    attribute.unpack(buff[begin:begin + length])
                else:
                    attribute.unpack(buff, begin)
                setattr(self, attribute_name, attribute)
                begin += attribute.get_size()

    def _update_actions_len(self):
        """Update the actions_len field based on actions value."""
        if isinstance(self.actions, ListOfActions):
            self.actions_len = self.actions.get_size()
        else:
            self.actions_len = ListOfActions(self.actions).get_size()

    def _validate_in_port(self):
        """Validate in_port attribute.

        A valid port is either:

            * Greater than 0 and less than or equals to Port.OFPP_MAX
            * One of the valid virtual ports: Port.OFPP_LOCAL,
              Port.OFPP_CONTROLLER or Port.OFPP_NONE

        Raises:
            ValidationError: If in_port is an invalid port.

        """
        is_valid_range = self.in_port > 0 and self.in_port <= Port.OFPP_MAX
        is_valid_virtual_in_ports = self.in_port in _VIRT_IN_PORTS

        if (is_valid_range or is_valid_virtual_in_ports) is False:
            raise ValidationError(f'{self.in_port} is not a valid input port.')
Пример #2
0
class FlowMod(GenericMessage):
    """Modifies the flow table from the controller."""

    header = Header(message_type=Type.OFPT_FLOW_MOD)
    match = Match()
    cookie = UBInt64()
    command = UBInt16(enum_ref=FlowModCommand)
    idle_timeout = UBInt16()
    hard_timeout = UBInt16()
    priority = UBInt16()
    buffer_id = UBInt32()
    out_port = UBInt16(enum_ref=Port)
    flags = UBInt16(enum_ref=FlowModFlags)
    actions = ListOfActions()

    def __init__(self,
                 xid=None,
                 match=None,
                 cookie=0,
                 command=None,
                 idle_timeout=0,
                 hard_timeout=0,
                 priority=0,
                 buffer_id=NO_BUFFER,
                 out_port=Port.OFPP_NONE,
                 flags=FlowModFlags.OFPFF_SEND_FLOW_REM,
                 actions=None):
        """Create a FlowMod with the optional parameters below.

        Args:
            xid (int): xid to be used on the message header.
            match (~pyof.v0x01.common.flow_match.Match): Fields to match.
            cookie (int): Opaque controller-issued identifier.
            command (~pyof.v0x01.controller2switch.flow_mod.FlowModCommand):
                One of OFPFC_*.
            idle_timeout (int): Idle time before discarding (seconds).
            hard_timeout (int): Max time before discarding (seconds).
            priority (int): Priority level of flow entry.
            buffer_idle (int): Buffered packet to apply to (or -1).
                Not meaningful for OFPFC_DELETE*.
            out_port (~pyof.v0x01.common.phy_port.Port):
                For OFPFC_DELETE* commands, require matching entries to include
                this as an output port. A value of OFPP_NONE indicates no
                restriction.
            flags (~pyof.v0x01.controller2switch.flow_mod.FlowModFlags):
                One of OFPFF_*.
            actions (~pyof.v0x01.common.action.ListOfActions):
                The action length is inferred from the length field in the
                header.
        """
        super().__init__(xid)
        self.match = match or Match()
        self.cookie = cookie
        self.command = command
        self.idle_timeout = idle_timeout
        self.hard_timeout = hard_timeout
        self.priority = priority
        self.buffer_id = buffer_id
        self.out_port = out_port
        self.flags = flags
        self.actions = actions or []
Пример #3
0
 def _update_actions_len(self):
     """Update the actions_len field based on actions value."""
     if isinstance(self.actions, ListOfActions):
         self.actions_len = self.actions.get_size()
     else:
         self.actions_len = ListOfActions(self.actions).get_size()
Пример #4
0
class FlowStats(GenericStruct):
    """Body of reply to OFPST_FLOW request."""

    length = UBInt16()
    table_id = UBInt8()
    #: Align to 32 bits.
    pad = Pad(1)
    match = Match()
    duration_sec = UBInt32()
    duration_nsec = UBInt32()
    priority = UBInt16()
    idle_timeout = UBInt16()
    hard_timeout = UBInt16()
    #: Align to 64-bits
    pad2 = Pad(6)
    cookie = UBInt64()
    packet_count = UBInt64()
    byte_count = UBInt64()
    actions = ListOfActions()

    def __init__(self,
                 length=None,
                 table_id=None,
                 match=None,
                 duration_sec=None,
                 duration_nsec=None,
                 priority=None,
                 idle_timeout=None,
                 hard_timeout=None,
                 cookie=None,
                 packet_count=None,
                 byte_count=None,
                 actions=None):
        """Create a FlowStats with the optional parameters below.

        Args:
            length (int): Length of this entry.
            table_id (int): ID of table flow came from.
            match (~pyof.v0x01.common.flow_match.Match): Description of fields.
            duration_sec (int): Time flow has been alive in seconds.
            duration_nsec (int): Time flow has been alive in nanoseconds in
                addition to duration_sec.
            priority (int): Priority of the entry. Only meaningful when this
                is not an exact-match entry.
            idle_timeout (int): Number of seconds idle before expiration.
            hard_timeout (int): Number of seconds before expiration.
            cookie (int): Opaque controller-issued identifier.
            packet_count (int): Number of packets in flow.
            byte_count (int): Number of bytes in flow.
            actions (:class:`~pyof.v0x01.common.actions.ListOfActions`):
                List of Actions.
        """
        super().__init__()
        self.length = length
        self.table_id = table_id
        self.match = match
        self.duration_sec = duration_sec
        self.duration_nsec = duration_nsec
        self.priority = priority
        self.idle_timeout = idle_timeout
        self.hard_timeout = hard_timeout
        self.cookie = cookie
        self.packet_count = packet_count
        self.byte_count = byte_count
        self.actions = [] if actions is None else actions

    def unpack(self, buff, offset=0):
        """Unpack *buff* into this object.

        Do nothing, since the _length is already defined and it is just a Pad.
        Keep buff and offset just for compability with other unpack methods.

        Args:
            buff (bytes): Buffer where data is located.
            offset (int): Where data stream begins.
        """
        self.length = UBInt16()
        self.length.unpack(buff, offset)
        max_length = offset + self.length.value
        super().unpack(buff[:max_length], offset)