def test_unpacked_pack(self): """Pack and then unpack the result and check for equality. Use two TLVs to also test match-field list packing/unpacking. """ unpacked = Match() unpacked.unpack(self.match.pack()) self.assertEqual(self.match, unpacked)
class TestMatch(TestCase): """Test Match class.""" tlv1 = OxmTLV(oxm_class=OxmClass.OFPXMC_OPENFLOW_BASIC, oxm_field=OxmOfbMatchField.OFPXMT_OFB_IN_PHY_PORT, oxm_hasmask=True, oxm_value=b'abc') tlv2 = OxmTLV(oxm_class=OxmClass.OFPXMC_EXPERIMENTER, oxm_field=OxmOfbMatchField.OFPXMT_OFB_METADATA, oxm_hasmask=False, oxm_value=b'abcdef') match = Match(match_type=MatchType.OFPMT_OXM, oxm_match_fields=[tlv1, tlv2]) def test_unpacked_pack(self): """Pack and then unpack the result and check for equality. Use two TLVs to also test match-field list packing/unpacking. """ unpacked = Match() unpacked.unpack(self.match.pack()) self.assertEqual(self.match, unpacked) def test_pack_other_instance(self): """Test packing another Match instance by using the value argument.""" expected = self.match.pack() valued_pack = Match().pack(self.match) self.assertEqual(expected, valued_pack)
def __init__(self, table_id=Table.OFPTT_ALL, out_port=PortNo.OFPP_ANY, out_group=Group.OFPG_ANY, cookie=0, cookie_mask=0, match=None): """Create a FlowStatsRequest with the optional parameters below. Args: table_id (int): ID of table to read (from pyof_table_stats) 0xff for all tables or 0xfe for emergency. out_port (:class:`int`, :class:`~pyof.v0x04.common.port.PortNo`): Require matching entries to include this as an output port. A value of :attr:`.PortNo.OFPP_ANY` indicates no restriction. out_group: Require matching entries to include this as an output group. A value of :attr:`Group.OFPG_ANY` indicates no restriction. cookie: Requires matching entries to contain this cookie value cookie_mask: Mask used to restrict the cookie bits that must match. A value of 0 indicates no restriction. match (~pyof.v0x04.common.flow_match.Match): Fields to match. """ super().__init__() self.table_id = table_id self.out_port = out_port self.out_group = out_group self.cookie = cookie self.cookie_mask = cookie_mask self.match = Match() if match is None else match
def __init__(self, table_id=Table.OFPTT_ALL, out_port=PortNo.OFPP_ANY, out_group=Group.OFPG_ANY, cookie=0, cookie_mask=0, match=None): """Create a AggregateStatsRequest with the optional parameters below. Args: table_id (int): ID of table to read (from ofp_table_stats) OFPTT_ALL for all tables. out_port (int): Require matching entries to include this as an output port. A value of OFPP_ANY indicates no restriction. out_group (int): Require matching entries to include this as an output group. A value of OFPG_ANY indicates no restriction. cookie (int): Require matching entries to contain this cookie value cookie_mask (int): Mask used to restrict the cookie bits that must match. A value of 0 indicates no restriction. match (~pyof.v0x04.common.flow_match.Match): Fields to match. Variable size """ super().__init__() self.table_id = table_id self.out_port = out_port self.out_group = out_group self.cookie = cookie self.cookie_mask = cookie_mask self.match = Match() if match is None else match
def _new_match(): """Crate new Match instance.""" oxmtlv = OxmTLV(oxm_class=OxmClass.OFPXMC_OPENFLOW_BASIC, oxm_field=OxmOfbMatchField.OFPXMT_OFB_IN_PORT, oxm_hasmask=False, oxm_value=b'\x00\x00\x00\x02') return Match(match_type=MatchType.OFPMT_OXM, oxm_match_fields=[oxmtlv])
def __init__(self, xid=None, cookie=0, cookie_mask=0, table_id=0, command=None, idle_timeout=0, hard_timeout=0, priority=0, buffer_id=OFP_NO_BUFFER, out_port=PortNo.OFPP_ANY, out_group=Group.OFPG_ANY, flags=FlowModFlags.OFPFF_SEND_FLOW_REM, match=None, instructions=None): """Create a FlowMod with the optional parameters below. Args: xid (int): xid to be used on the message header. cookie (int): Opaque controller-issued identifier. cookie_mask (int): Mask used to restrict the cookie bits that must match when the command is OFPFC_MODIFY* or OFPFC_DELETE*. A value of 0 indicates no restriction. table_id (int): ID of the table to put the flow in. For OFPFC_DELETE_* commands, OFPTT_ALL can also be used to delete matching flows from all tables. command (~pyof.v0x04.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_id (int): Buffered packet to apply to, or OFP_NO_BUFFER. Not meaningful for OFPFC_DELETE*. out_port (int): For OFPFC_DELETE* commands, require matching entries to include this as an output port. A value of OFPP_ANY indicates no restriction. out_group (int): For OFPFC_DELETE* commands, require matching entries to include this as an output group. A value of OFPG_ANY indicates no restriction. flags (~pyof.v0x04.controller2switch.flow_mod.FlowModFlags): One of OFPFF_*. match (~pyof.v0x04.common.flow_match.Match): Fields to match. Variable size. """ super().__init__(xid) self.cookie = cookie self.cookie_mask = cookie_mask self.table_id = table_id 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.out_group = out_group self.flags = flags self.match = Match() if match is None else match self.instructions = instructions or ListOfInstruction()
def _new_match(): """Crate new Match instance.""" tlv1 = OxmTLV(oxm_class=OxmClass.OFPXMC_OPENFLOW_BASIC, oxm_field=OxmOfbMatchField.OFPXMT_OFB_ETH_TYPE, oxm_hasmask=False, oxm_value=b'\x88\xcc') tlv2 = OxmTLV(oxm_class=OxmClass.OFPXMC_OPENFLOW_BASIC, oxm_field=OxmOfbMatchField.OFPXMT_OFB_VLAN_VID, oxm_hasmask=False, oxm_value=b'\x1e\xd7') return Match(match_type=MatchType.OFPMT_OXM, oxm_match_fields=[tlv1, tlv2])
class FlowStats(GenericStruct): """Body of reply to OFPST_FLOW request.""" length = UBInt16() table_id = UBInt8() #: Align to 32 bits. pad = Pad(1) duration_sec = UBInt32() duration_nsec = UBInt32() priority = UBInt16() idle_timeout = UBInt16() hard_timeout = UBInt16() flags = UBInt16() #: Align to 64-bits pad2 = Pad(4) cookie = UBInt64() packet_count = UBInt64() byte_count = UBInt64() match = Match() def __init__(self, length=None, table_id=None, duration_sec=None, duration_nsec=None, priority=None, idle_timeout=None, hard_timeout=None, flags=None, cookie=None, packet_count=None, byte_count=None, match=None): """The constructor just assings parameters to object attributes. Args: length (int): Length of this entry. table_id (int): ID of table flow came from. 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. match (Match): Description of fields. """ super().__init__() self.length = length self.table_id = table_id self.duration_sec = duration_sec self.duration_nsec = duration_nsec self.priority = priority self.idle_timeout = idle_timeout self.hard_timeout = hard_timeout self.flags = flags self.cookie = cookie self.packet_count = packet_count self.byte_count = byte_count
class AggregateStatsRequest(GenericStruct): """Body for ofp_stats_request of type OFPST_AGGREGATE.""" #: ID of table to read (from ofp_table_stats) OFPTT_ALL for all tables. table_id = UBInt8() #: Align to 32 bits. pad = Pad(3) #: Require matching entries to include this as an output port. A value of #: OFPP_ANY indicates no restriction. out_port = UBInt32() #: Require matching entries to include this as an output group. A value of #: OFPG_ANY indicates no restriction. out_group = UBInt32() #: Align to 64 bits pad2 = Pad(4) #: Require matching entries to contain this cookie value cookie = UBInt64() #: Mask used to restrict the cookie bits that must match. A value of 0 #: indicates no restriction. cookie_mask = UBInt64() #: Fields to match. Variable size. match = Match() def __init__(self, table_id=Table.OFPTT_ALL, out_port=PortNo.OFPP_ANY, out_group=Group.OFPG_ANY, cookie=0, cookie_mask=0, match=None): """Create a AggregateStatsRequest with the optional parameters below. Args: table_id (int): ID of table to read (from ofp_table_stats) OFPTT_ALL for all tables. out_port (int): Require matching entries to include this as an output port. A value of OFPP_ANY indicates no restriction. out_group (int): Require matching entries to include this as an output group. A value of OFPG_ANY indicates no restriction. cookie (int): Require matching entries to contain this cookie value cookie_mask (int): Mask used to restrict the cookie bits that must match. A value of 0 indicates no restriction. match (~pyof.v0x04.common.flow_match.Match): Fields to match. Variable size """ super().__init__() self.table_id = table_id self.out_port = out_port self.out_group = out_group self.cookie = cookie self.cookie_mask = cookie_mask self.match = Match() if match is None else match
class PacketIn(GenericMessage): """Packet received on port (datapath -> controller).""" #: :class:`~.header.Header`: OpenFlow Header header = Header(message_type=Type.OFPT_PACKET_IN) #: ID assigned by datapath. buffer_id = UBInt32() #: Full length of frame. total_len = UBInt16() #: Reason packet is being sent (one of OFPR_*), reason = UBInt8(enum_ref=PacketInReason) #: ID of the table that was looked up. table_id = UBInt8() #: Cookie of the flow entry that was looked up. cookie = UBInt64() #: Packet metadata. Variable size. match = Match() #: Align to 64 bit + 16 bit pad = Pad(2) #: Ethernet frame whose length is inferred from header.length. #: The padding bytes preceding the Ethernet frame ensure that the IP #: header (if any) following the Ethernet header is 32-bit aligned. data = BinaryData() def __init__(self, xid=None, buffer_id=None, total_len=None, reason=None, table_id=None, cookie=None, match=None, data=b''): """Assign parameters to object attributes. Args: xid (int): Header's xid. buffer_id (int): ID assigned by datapath. total_len (int): Full length of frame. reason (PacketInReason): The reason why the packet is being sent table_id (int): ID of the table that was looked up cookie (int): Cookie of the flow entry that was looked up match (:class:`~.common.flow_match.Match`): Packet metadata. Variable size. data (bytes): Ethernet frame, halfway through 32-bit word, so the IP header is 32-bit aligned. The amount of data is inferred from the length field in the header. Because of padding, offsetof(struct ofp_packet_in, data) == sizeof(struct ofp_packet_in) - 2. """ super().__init__(xid) self.buffer_id = buffer_id self.total_len = total_len self.reason = reason self.table_id = table_id self.cookie = cookie self.match = match self.data = data
class AggregateStatsRequest(GenericStruct): """Body for ofp_stats_request of type OFPST_AGGREGATE.""" #: ID of table to read (from ofp_table_stats) OFPTT_ALL for all tables. table_id = UBInt8() #: Align to 32 bits. pad = Pad(3) #: Require matching entries to include this as an output port. A value of #: OFPP_ANY indicates no restriction. out_port = UBInt32() #: Require matching entries to include this as an output group. A value of #: OFPG_ANY indicates no restriction. out_group = UBInt32() #: Align to 64 bits pad2 = Pad(4) #: Require matching entries to contain this cookie value cookie = UBInt64() #: Mask used to restrict the cookie bits that must match. A value of 0 #: indicates no restriction. cookie_mask = UBInt64() #: Fields to match. Variable size. match = Match() def __init__(self, table_id=None, out_port=None, out_group=None, cookie=None, cookie_mask=None, match=None): """The constructor just assings parameters to object attributes. Args: table_id (int): ID of table to read (from ofp_table_stats) OFPTT_ALL for all tables. out_port (int): Require matching entries to include this as an output port. A value of OFPP_ANY indicates no restriction. out_group (in): Require matching entries to include this as an output group. A value of OFPG_ANY indicates no restriction. cookie (int): Require matching entries to contain this cookie value cookie_mask (int): Mask used to restrict the cookie bits that must match. A value of 0 indicates no restriction. match (Match): Fields to match. Variable size """ super().__init__() self.table_id = table_id self.out_port = out_port self.out_group = out_group self.cookie = cookie self.cookie_mask = cookie_mask self.match = match
def setUpClass(cls): """Configure raw file and its object in parent class (TestDump).""" super().setUpClass() super().set_raw_dump_file('v0x04', 'ofpt_flow_removed') super().set_raw_dump_object(FlowRemoved, xid=1, cookie=1, priority=1, reason=1, table_id=1, duration_sec=1, duration_nsec=2, idle_timeout=3, hard_timeout=4, packet_count=1, byte_count=1, match=Match()) super().set_minimum_size(56)
class FlowStatsRequest(GenericStruct): """Body for ofp_stats_request of type OFPST_FLOW.""" table_id = UBInt8() #: Align to 32 bits. pad = Pad(3) out_port = UBInt32() out_group = UBInt32() pad2 = Pad(4) cookie = UBInt64() cookie_mask = UBInt64() match = Match() def __init__(self, table_id=None, out_port=None, out_group=None, cookie=None, cookie_mask=None, match=None): """The constructor just assings parameters to object attributes. Args: table_id (int): ID of table to read (from pyof_table_stats) 0xff for all tables or 0xfe for emergency. out_port (:class:`int`, :class:`.Port`): Require matching entries to include this as an output port. A value of :attr:`.Port.OFPP_NONE` indicates no restriction. out_group: Require matching entries to include this as an output group. A value of OFPG_ANY indicates no restriction. cookie: Requires matching entries to contain this cookie value cookie_mask: Mask used to restrict the cookie bits that must match. A value of 0 indicates no restriction. match (Match): Fields to match. """ super().__init__() self.table_id = table_id self.out_port = out_port self.out_group = out_group self.cookie = cookie self.cookie_mask = cookie_mask self.match = match
"""Packet in message tests.""" from unittest import TestCase from pyof.v0x04.asynchronous.packet_in import PacketIn, PacketInReason from pyof.v0x04.common.constants import OFP_NO_BUFFER from pyof.v0x04.common.flow_match import (Match, MatchType, OxmClass, OxmOfbMatchField, OxmTLV) from pyof.v0x04.common.header import Header from tests.test_struct import TestStruct OXMTLV = OxmTLV(oxm_class=32768, oxm_field=0, oxm_hasmask=0, oxm_value=b'\x00\x00\x00\x16') MATCH = Match(match_type=1, oxm_match_fields=[OXMTLV]) PACKETIN = PacketIn(xid=0, buffer_id=257, total_len=81, reason=1, table_id=0, cookie=18446744073709551615, match=MATCH, data=81 * b'\x00') DUMP = b'\x04\n\x00{\x00\x00\x00\x00\x00\x00\x01\x01\x00Q\x01\x00\xff\xff' DUMP += b'\xff\xff\xff\xff\xff\xff\x00\x01\x00\x0c\x80\x00\x00\x04\x00\x00' DUMP += b'\x00\x16\x00\x00\x00\x00\x00\x00' DUMP += 81 * b'\x00'
class PacketIn(GenericMessage): """Packet received on port (datapath -> controller).""" #: :class:`~pyof.v0x04.common.header.Header`: OpenFlow Header header = Header(message_type=Type.OFPT_PACKET_IN) #: ID assigned by datapath. buffer_id = UBInt32() #: Full length of frame. total_len = UBInt16() #: Reason packet is being sent (one of OFPR_*), reason = UBInt8(enum_ref=PacketInReason) #: ID of the table that was looked up. table_id = UBInt8() #: Cookie of the flow entry that was looked up. cookie = UBInt64() #: Packet metadata. Variable size. match = Match() #: Align to 64 bit + 16 bit pad = Pad(2) #: Ethernet frame whose length is inferred from header.length. #: The padding bytes preceding the Ethernet frame ensure that the IP #: header (if any) following the Ethernet header is 32-bit aligned. data = BinaryData() def __init__(self, xid=None, buffer_id=None, total_len=None, reason=None, table_id=None, cookie=None, match=None, data=b''): """Assign parameters to object attributes. Args: xid (int): Header's xid. buffer_id (int): ID assigned by datapath. total_len (int): Full length of frame. reason (~pyof.v0x04.asynchronous.packet_in.PacketInReason): The reason why the packet is being sent table_id (int): ID of the table that was looked up cookie (int): Cookie of the flow entry that was looked up match (:class:`~pyof.v0x04.common.flow_match.Match`): Packet metadata with variable size. data (bytes): Ethernet frame, halfway through 32-bit word, so the IP header is 32-bit aligned. The amount of data is inferred from the length field in the header. Because of padding, offsetof(struct ofp_packet_in, data) == sizeof(struct ofp_packet_in) - 2. """ super().__init__(xid) self.buffer_id = buffer_id self.total_len = total_len self.reason = reason self.table_id = table_id self.cookie = cookie self.match = match self.data = data @property def in_port(self): """Retrieve the 'in_port' that generated the PacketIn. This method will look for the OXM_TLV with type OFPXMT_OFB_IN_PORT on the `oxm_match_fields` field from `match` field and return its value, if the OXM exists. Returns: The integer number of the 'in_port' that generated the PacketIn if it exists. Otherwise return None. """ in_port = self.match.get_field(OxmOfbMatchField.OFPXMT_OFB_IN_PORT) return int.from_bytes(in_port, 'big')
class FlowMod(GenericMessage): """Modifies the flow table from the controller.""" header = Header(message_type=Type.OFPT_FLOW_MOD) cookie = UBInt64() cookie_mask = UBInt64() # Flow actions table_id = UBInt8() command = UBInt8(enum_ref=FlowModCommand) idle_timeout = UBInt16() hard_timeout = UBInt16() priority = UBInt16() buffer_id = UBInt32() out_port = UBInt32() out_group = UBInt32() flags = UBInt16(enum_ref=FlowModFlags) pad = Pad(2) match = Match() def __init__(self, xid=None, cookie=None, cookie_mask=None, table_id=None, command=None, idle_timeout=None, hard_timeout=None, priority=None, buffer_id=None, out_port=None, out_group=None, flags=None, match=None): """The constructor just assings parameters to object attributes. Args: xid (int): xid to be used on the message header. cookie (int): Opaque controller-issued identifier. cookie_mask (int): Mask used to restrict the cookie bits that must match when the command is OFPFC_MODIFY* or OFPFC_DELETE*. A value of 0 indicates no restriction. table_id (int): ID of the table to put the flow in. For OFPFC_DELETE_* commands, OFPTT_ALL can also be used to delete matching flows from all tables. command (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_id (int): Buffered packet to apply to, or OFP_NO_BUFFER. Not meaningful for OFPFC_DELETE*. out_port (int): For OFPFC_DELETE* commands, require matching entries to include this as an output port. A value of OFPP_ANY indicates no restriction. out_group (int): For OFPFC_DELETE* commands, require matching entries to include this as an output group. A value of OFPG_ANY indicates no restriction. flags (FlowModFlags): One of OFPFF_*. match (Match): Fields to match. Variable size. """ super().__init__(xid) self.cookie = cookie self.cookie_mask = cookie_mask self.table_id = table_id 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.out_group = out_group self.flags = flags self.match = match
def _get_body(): """Return the body used by MultipartRequest message.""" return FlowStatsRequest(match=Match())
"""Packet in message tests.""" from unittest import TestCase from pyof.v0x04.asynchronous.packet_in import PacketIn, PacketInReason from pyof.v0x04.common.flow_match import Match, OxmTLV from pyof.v0x04.common.header import Header from tests.test_struct import TestStruct oxmtlv = OxmTLV(oxm_class=32768, oxm_field=0, oxm_hasmask=0, oxm_value=b'\x00\x00\x00\x16') match = Match(match_type=1, oxm_match_fields=[oxmtlv]) packetin = PacketIn(xid=0, buffer_id=257, total_len=81, reason=1, table_id=0, cookie=18446744073709551615, match=match, data=81 * b'\x00') dump = b'\x04\n\x00{\x00\x00\x00\x00\x00\x00\x01\x01\x00Q\x01\x00\xff\xff' dump += b'\xff\xff\xff\xff\xff\xff\x00\x01\x00\x0c\x80\x00\x00\x04\x00\x00' dump += b'\x00\x16\x00\x00\x00\x00\x00\x00' dump += 81 * b'\x00' class TestPacketIn(TestCase):
class FlowStats(GenericStruct): """Body of reply to OFPST_FLOW request.""" length = UBInt16() table_id = UBInt8() #: Align to 32 bits. pad = Pad(1) duration_sec = UBInt32() duration_nsec = UBInt32() priority = UBInt16() idle_timeout = UBInt16() hard_timeout = UBInt16() flags = UBInt16() #: Align to 64-bits pad2 = Pad(4) cookie = UBInt64() packet_count = UBInt64() byte_count = UBInt64() match = Match() instructions = ListOfInstruction() def __init__(self, length=None, table_id=None, duration_sec=None, duration_nsec=None, priority=None, idle_timeout=None, hard_timeout=None, flags=None, cookie=None, packet_count=None, byte_count=None, match=None, instructions=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. 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. match (~pyof.v0x04.common.flow_match.Match): Description of fields. """ super().__init__() self.length = length self.table_id = table_id self.duration_sec = duration_sec self.duration_nsec = duration_nsec self.priority = priority self.idle_timeout = idle_timeout self.hard_timeout = hard_timeout self.flags = flags self.cookie = cookie self.packet_count = packet_count self.byte_count = byte_count self.match = match self.instructions = instructions or [] def unpack(self, buff, offset=0): """Unpack a binary message into this object's attributes. Pass the correct length for list unpacking. Args: buff (bytes): Binary data package to be unpacked. offset (int): Where to begin unpacking. """ unpack_length = UBInt16() unpack_length.unpack(buff, offset) super().unpack(buff[:offset+unpack_length], offset)
class FlowRemoved(GenericMessage): """Flow removed (datapath -> controller). If the controller has requested to be notified when flow entries time out or are deleted from tables, the datapath does this with the OFPT_FLOW_REMOVED message. """ #: :class:`~.header.Header`: OpenFlow Header header = Header(message_type=Type.OFPT_FLOW_REMOVED) #: Opaque controller-issued identifier. cookie = UBInt64() #: Priority level of flow entry. priority = UBInt16() #: One of OFPRR_*. reason = UBInt8(enum_ref=FlowRemovedReason) #: ID of the table table_id = UBInt8() #: Time flow was alive in seconds. duration_sec = UBInt32() #: Time flow was alive in nanoseconds beyond duration_sec. duration_nsec = UBInt32() #: Idle timeout from original flow mod. idle_timeout = UBInt16() #: Hard timeout from original flow mod. hard_timeout = UBInt16() packet_count = UBInt64() byte_count = UBInt64() #: Description of fields. Variable size. #: :class:`~.common.flow_match.Match` match = Match() def __init__(self, xid=None, cookie=None, priority=None, reason=None, table_id=None, duration_sec=None, duration_nsec=None, idle_timeout=None, hard_timeout=None, packet_count=None, byte_count=None, match=None): """Assign parameters to object attributes. Args: xid (int): OpenFlow Header's xid. cookie (int): Opaque controller-issued identifier. priority (int): Priority level of flow entry. reason (FlowRemovedReason): Why the flow was removed. table_id (int): ID of the table. duration_sec (int): Time the flow was alive in seconds. duration_nsec (int): Time the flow was alive in nanoseconds in addition to duration_sec. idle_timeout (int): Idle timeout from original flow mod. hard_timeout (int): Hard timeout from original flow mod. packet_count (int): Number of packets. byte_count (int): Byte count. match (Match): Fields' description. """ super().__init__(xid) self.cookie = cookie self.priority = priority self.reason = reason self.duration_sec = duration_sec self.duration_nsec = duration_nsec self.idle_timeout = idle_timeout self.hard_timeout = hard_timeout self.packet_count = packet_count self.byte_count = byte_count self.match = match
def test_pack_other_instance(self): """Test packing another Match instance by using the value argument.""" expected = self.match.pack() valued_pack = Match().pack(self.match) self.assertEqual(expected, valued_pack)