def test_bucket_list(self): bucket1 = Bucket(length=48, weight=1, watch_port=PortNo.OFPP_ANY, watch_group=PortNo.OFPP_ANY, actions=ListOfActions([self.action1, self.action2])) bucket2 = Bucket(length=80, weight=2, watch_port=PortNo.OFPP_ANY, watch_group=PortNo.OFPP_ANY, actions=ListOfActions([self.action1, self.action2, self.action3, self.action4])) bucket3 = Bucket(length=48, weight=3, watch_port=PortNo.OFPP_ANY, watch_group=PortNo.OFPP_ANY, actions=ListOfActions([self.action3, self.action4])) # Packing buckets buckets = ListOfBuckets([bucket1, bucket2, bucket3]) buff = packed_buff = buckets.pack() # Unpacking buckets bytes unpacked_buckets = ListOfBuckets() unpacked_buckets.unpack(buff) self.assertEqual(len(unpacked_buckets), 3) self.assertEqual(unpacked_buckets[0].length, 48) self.assertEqual(unpacked_buckets[0].weight, 1) self.assertEqual(len(unpacked_buckets[0].actions), 2) self.assertEqual(unpacked_buckets[0].actions[0].field.oxm_value, self.oxmtlv1.oxm_value) self.assertEqual(unpacked_buckets[0].actions[1].field.oxm_value, self.oxmtlv2.oxm_value) self.assertEqual(unpacked_buckets[1].length, 80) self.assertEqual(unpacked_buckets[1].weight, 2) self.assertEqual(len(unpacked_buckets[1].actions), 4) self.assertEqual(unpacked_buckets[1].actions[0].field.oxm_value, self.oxmtlv1.oxm_value) self.assertEqual(unpacked_buckets[1].actions[1].field.oxm_value, self.oxmtlv2.oxm_value) self.assertEqual(unpacked_buckets[1].actions[2].body, self.action3.body) self.assertEqual(unpacked_buckets[1].actions[3].body, self.action4.body) self.assertEqual(unpacked_buckets[2].length, 48) self.assertEqual(unpacked_buckets[2].weight, 3) self.assertEqual(len(unpacked_buckets[2].actions), 2) self.assertEqual(unpacked_buckets[2].actions[0].body, self.action3.body) self.assertEqual(unpacked_buckets[2].actions[1].body, self.action4.body)
class ActionsProperty(Property): """Actions Property. This class represents Property with the following type: OFPTFPT_WRITE_ACTIONS OFPTFPT_WRITE_ACTIONS_MISS OFPTFPT_APPLY_ACTIONS OFPTFPT_APPLY_ACTIONS_MISS """ action_ids = ListOfActions() def __init__(self, property_type=TableFeaturePropType.OFPTFPT_WRITE_ACTIONS, action_ids=None): """Create a ActionsProperty with the optional parameters below. Args: type(|TableFeaturePropType_v0x04|): Property Type value of this instance. action_ids(|ListOfActions_v0x04|): List of Action instances. """ super().__init__(property_type) self.action_ids = action_ids if action_ids else ListOfActions() self.update_length()
class InstructionApplyAction(GenericStruct): """Instruction structure for OFPIT_APPLY_ACTIONS. The :attr:`~actions` field is treated as a list, and the actions are applied to the packet in-order. """ #: OFPIT_APPLY_ACTIONS instruction_type = UBInt16(InstructionType.OFPIT_APPLY_ACTIONS, enum_ref=InstructionType) #: Length of this struct in bytes. length = UBInt16() #: Align to 64-bits pad = Pad(4) #: Actions associated with OFPIT_APPLY_ACTIONS actions = ListOfActions() def __init__(self, length=None, actions=None): """Instruction structure for OFPIT_APPLY_ACTIONS. Args: - length (int): Length of this struct in bytes. - actions (:class:`~.actions.ListOfActions`): Actions associated with OFPIT_APPLY_ACTIONS. """ super().__init__() self.length = length self.actions = actions if actions is not None else []
class InstructionWriteAction(GenericStruct): """Instruction structure for OFPIT_WRITE_ACTIONS. The actions field must be treated as a SET, so the actions are not repeated. """ #: OFPIT_WRITE_ACTIONS instruction_type = UBInt16(InstructionType.OFPIT_WRITE_ACTIONS, enum_ref=InstructionType) #: Length of this struct in bytes. length = UBInt16() #: Align to 64-bits pad = Pad(4) #: Actions associated with OFPIT_WRITE_ACTIONS actions = ListOfActions() def __init__(self, length=None, actions=None): """Instruction structure for OFPIT_WRITE_ACTIONS. Args: - length (int): Length of this struct in bytes. - actions (:class:`~.actions.ListOfActions`): Actions associated with OFPIT_WRITE_ACTIONS. """ super().__init__() self.length = length self.actions = actions if actions is not None else []
def __init__(self, property_type=TableFeaturePropType.OFPTFPT_WRITE_ACTIONS, action_ids=None): """Create a ActionsProperty with the optional parameters below. Args: type(|TableFeaturePropType_v0x04|): Property Type value of this instance. action_ids(|ListOfActions_v0x04|): List of Action instances. """ super().__init__(property_type) self.action_ids = action_ids if action_ids else ListOfActions() self.update_length()
class InstructionClearAction(GenericStruct): """Instruction structure for OFPIT_CLEAR_ACTIONS. This structure does not contain any actions. """ #: OFPIT_CLEAR_ACTIONS instruction_type = UBInt16(InstructionType.OFPIT_CLEAR_ACTIONS, enum_ref=InstructionType) #: Length of this struct in bytes. length = UBInt16(8) #: Align to 64-bits pad = Pad(4) #: OFPIT_CLEAR_ACTIONS does not have any action on the list of actions. actions = ListOfActions()
class InstructionClearAction(Instruction): """Instruction structure for OFPIT_CLEAR_ACTIONS. This structure does not contain any actions. """ #: Align to 64-bits pad = Pad(4) #: OFPIT_CLEAR_ACTIONS does not have any action on the list of actions. actions = ListOfActions() def __init__(self, actions=None): """Create a InstructionClearAction with the optional parameters below. Args: actions (:class:`~.actions.ListOfActions`): Actions associated with OFPIT_CLEAR_ACTIONS. """ super().__init__(InstructionType.OFPIT_CLEAR_ACTIONS) self.actions = actions if actions else []
def test_buckets_no_action(self): bucket1 = Bucket(length=48, weight=1, watch_port=PortNo.OFPP_ANY, watch_group=PortNo.OFPP_ANY, actions=ListOfActions([self.action1])) # Packing buckets buckets = ListOfBuckets([bucket1]) buff = packed_buff = buckets.pack() # Unpacking buckets bytes unpacked_buckets = ListOfBuckets() unpacked_buckets.unpack(buff) self.assertEqual(len(unpacked_buckets), 1) self.assertEqual(unpacked_buckets[0].length, 48) self.assertEqual(unpacked_buckets[0].weight, 1) self.assertEqual(len(unpacked_buckets[0].actions), 1) self.assertEqual(unpacked_buckets[0].actions[0].field.oxm_value, self.oxmtlv1.oxm_value)
class InstructionWriteAction(Instruction): """Instruction structure for OFPIT_WRITE_ACTIONS. The actions field must be treated as a SET, so the actions are not repeated. """ #: Align to 64-bits pad = Pad(4) #: Actions associated with OFPIT_WRITE_ACTIONS actions = ListOfActions() def __init__(self, actions=None): """Create a InstructionWriteAction with the optional parameters below. Args: actions (:class:`~.actions.ListOfActions`): Actions associated with OFPIT_WRITE_ACTIONS. """ super().__init__(InstructionType.OFPIT_WRITE_ACTIONS) self.actions = actions if actions else []
class InstructionApplyAction(Instruction): """Instruction structure for OFPIT_APPLY_ACTIONS. The :attr:`~actions` field is treated as a list, and the actions are applied to the packet in-order. """ #: Align to 64-bits pad = Pad(4) #: Actions associated with OFPIT_APPLY_ACTIONS actions = ListOfActions() def __init__(self, actions=None): """Create a InstructionApplyAction with the optional parameters below. Args: actions (:class:`~.actions.ListOfActions`): Actions associated with OFPIT_APPLY_ACTIONS. """ super().__init__(InstructionType.OFPIT_APPLY_ACTIONS) self.actions = actions if actions else []
class PacketOut(GenericMessage): """Send packet (controller -> datapath).""" #: Openflow :class:`~pyof.v0x04.common.header.Header` header = Header(message_type=Type.OFPT_PACKET_OUT) #: ID assigned by datapath (OFP_NO_BUFFER if none). buffer_id = UBInt32() #: Packet’s input port or OFPP_CONTROLLER. in_port = UBInt32() #: Size of action array in bytes. actions_len = UBInt16() #: Padding pad = Pad(6) #: Action List. actions = ListOfActions() #: Packet data. The length is inferred from the length field in the header. #: (Only meaningful if buffer_id == -1.) data = BinaryData() def __init__(self, xid=None, buffer_id=UBINT32_MAX_VALUE, in_port=PortNo.OFPP_CONTROLLER, 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 this case UBINT32_MAX_VALUE is -1 for the field. in_port (:class:`int`, :class:`~pyof.v0x04.common.port.Port`): Packet's input port (:attr:`Port.OFPP_NONE` if none). Virtual ports OFPP_IN_PORT, OFPP_TABLE, OFPP_NORMAL, OFPP_FLOOD, and OFPP_ALL cannot be used as input port. actions (:class:`~pyof.v0x04.common.action.ListOfActions`): List of Action instances. 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() if isinstance(value, type(self)): return value.pack() 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): is_valid_range = self.in_port > 0 and self.in_port <= PortNo.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.')
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 _new_list_of_instructions(): """Crate new ListOfInstruction.""" output = ActionOutput(port=PortNo.OFPP_CONTROLLER) loa = ListOfActions([output]) instruction = InstructionApplyAction(loa) return ListOfInstruction([instruction])