Test Failed
Pull Request — master (#573)
by Gleyberson
01:50
created

pyof.v0x04.controller2switch.common   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 666
Duplicated Lines 0 %

Test Coverage

Coverage 82.18%

Importance

Changes 0
Metric Value
wmc 29
eloc 225
dl 0
loc 666
ccs 166
cts 202
cp 0.8218
rs 10
c 0
b 0
f 0

21 Methods

Rating   Name   Duplication   Size   Complexity  
A TableFeaturePropType.find_class() 0 10 4
A BucketCounter.__init__() 0 10 1
A Bucket.__init__() 0 22 1
A ExperimenterMultipartHeader.__init__() 0 12 1
A TableFeatures.unpack() 0 17 1
A Property.__init__() 0 9 1
A InstructionsProperty.__init__() 0 13 2
A OxmProperty.__init__() 0 13 2
A Property.update_length() 0 3 1
A ListOfProperty.__init__() 0 7 1
A NextTablesProperty.__init__() 0 14 2
A RoleBaseMessage.__init__() 0 11 1
A SwitchConfig.__init__() 0 13 1
A TableFeatures.update_length() 0 3 1
A TableFeatures.__init__() 0 36 2
A Property.unpack() 0 21 1
A TableFeatures.pack() 0 8 1
A AsyncConfig.__init__() 0 33 1
A ActionsProperty.__init__() 0 14 2
A ListOfBucketCounter.__init__() 0 7 1
A Property.pack() 0 8 1
1
"""Defines common structures and enums for controller2switch."""
2
3
# System imports
4 1
from enum import IntEnum
5
6 1
from pyof.foundation.base import GenericMessage, GenericStruct
7 1
from pyof.foundation.basic_types import (
8
    Char, FixedTypeList, Pad, UBInt8, UBInt16, UBInt32, UBInt64)
9 1
from pyof.foundation.constants import OFP_MAX_TABLE_NAME_LEN
10 1
from pyof.v0x04.asynchronous.flow_removed import FlowRemovedReason
11 1
from pyof.v0x04.asynchronous.packet_in import PacketInReason
12 1
from pyof.v0x04.asynchronous.port_status import PortReason
13
# Local source tree imports
14 1
from pyof.v0x04.common.action import (
15
    ActionHeader, ControllerMaxLen, ListOfActions)
16 1
from pyof.v0x04.common.flow_instructions import ListOfInstruction
17 1
from pyof.v0x04.common.flow_match import ListOfOxmHeader
18 1
from pyof.v0x04.common.header import Header
19 1
from pyof.v0x04.controller2switch.table_mod import Table
20
21 1
__all__ = ('ConfigFlag', 'ControllerRole', 'TableFeaturePropType',
22
           'MultipartType', 'Bucket', 'BucketCounter', 'ListOfBucketCounter',
23
           'ExperimenterMultipartHeader', 'Property', 'InstructionsProperty',
24
           'NextTablesProperty', 'ActionsProperty', 'OxmProperty',
25
           'ListOfProperty', 'TableFeatures')
26
27
# Enum
28
29
30 1
class ConfigFlag(IntEnum):
31
    """Handling of IP fragments."""
32
33
    #: No special handling for fragments.
34 1
    OFPC_FRAG_NORMAL = 0
35
    #: Drop fragments.
36 1
    OFPC_FRAG_DROP = 1
37
    #: Reassemble (only if OFPC_IP_REASM set).
38 1
    OFPC_FRAG_REASM = 2
39 1
    OFPC_FRAG_MASK = 3
40
41
42 1
class ControllerRole(IntEnum):
43
    """Controller roles."""
44
45
    #: Don’t change current role.
46 1
    OFPCR_ROLE_NOCHANGE = 0
47
    #: Default role, full access.
48 1
    OFPCR_ROLE_EQUAL = 1
49
    #: Full access, at most one master.
50 1
    OFPCR_ROLE_MASTER = 2
51
    #: Read-only access.
52 1
    OFPCR_ROLE_SLAVE = 3
53
54
55 1
class TableFeaturePropType(IntEnum):
56
    """Table Property Types.
57
58
    Low order bit cleared indicates a property for a regular Flow Entry.
59
    Low order bit set indicates a property for the Table-Miss Flow Entry.
60
    """
61
62
    # Instructions property.
63 1
    OFPTFPT_INSTRUCTIONS = 0
64
    # Instructions for table-miss.
65 1
    OFPTFPT_INSTRUCTIONS_MISS = 1
66
    # Next Table property.
67 1
    OFPTFPT_NEXT_TABLES = 2
68
    # Next Table for table-miss.
69 1
    OFPTFPT_NEXT_TABLES_MISS = 3
70
    # Write Actions property.
71 1
    OFPTFPT_WRITE_ACTIONS = 4
72
    # Write Actions for table-miss.
73 1
    OFPTFPT_WRITE_ACTIONS_MISS = 5
74
    # Apply Actions property.
75 1
    OFPTFPT_APPLY_ACTIONS = 6
76
    # Apply Actions for table-miss.
77 1
    OFPTFPT_APPLY_ACTIONS_MISS = 7
78
    # Match property.
79 1
    OFPTFPT_MATCH = 8
80
    # Wildcards property.
81 1
    OFPTFPT_WILDCARDS = 10
82
    # Write Set-Field property.
83 1
    OFPTFPT_WRITE_SETFIELD = 12
84
    # Write Set-Field for table-miss.
85 1
    OFPTFPT_WRITE_SETFIELD_MISS = 13
86
    # Apply Set-Field property.
87 1
    OFPTFPT_APPLY_SETFIELD = 14
88
    # Apply Set-Field for table-miss.
89 1
    OFPTFPT_APPLY_SETFIELD_MISS = 15
90
    # Experimenter property.
91 1
    OFPTFPT_EXPERIMENTER = 0xFFFE
92
    # Experimenter for table-miss.
93 1
    OFPTFPT_EXPERIMENTER_MISS = 0xFFFF
94
95 1
    def find_class(self):
96
        """Return a class related with this type."""
97
        if self.value <= 1:
98
            return InstructionsProperty
99
        elif self.value <= 3:
100
            return NextTablesProperty
101
        elif self.value <= 7:
102
            return ActionsProperty
103
104
        return OxmProperty
105
106
107 1
class MultipartType(IntEnum):
108
    """Types of Multipart Messages, both Request and Reply."""
109
110
    #: Description of this OpenFlow switch.
111
    #: The request body is empty.
112
    #: The reply body is struct ofp_desc.
113 1
    OFPMP_DESC = 0
114
115
    #: Individual flow statistics.
116
    #: The request body is struct ofp_flow_stats_request.
117
    #: The reply body is an array of struct ofp_flow_stats.
118 1
    OFPMP_FLOW = 1
119
120
    #: Aggregate flow statistics.
121
    #: The request body is struct ofp_aggregate_stats_request.
122
    #: The reply body is struct ofp_aggregate_stats_reply.
123 1
    OFPMP_AGGREGATE = 2
124
125
    #: Flow table statistics.
126
    #: The request body is empty.
127
    #: The reply body is an array of struct ofp_table_stats.
128 1
    OFPMP_TABLE = 3
129
130
    #: Port statistics.
131
    #: The request body is struct ofp_port_stats_request.
132
    #: The reply body is an array of struct ofp_port_stats.
133 1
    OFPMP_PORT_STATS = 4
134
135
    #: Queue statistics for a port.
136
    #: The request body is struct ofp_queue_stats_request.
137
    #: The reply body is an array of struct ofp_queue_stats.
138 1
    OFPMP_QUEUE = 5
139
140
    #: Group counter statistics.
141
    #: The request body is struct ofp_group_stats_request.
142
    #: The reply is an array of struct ofp_group_stats.
143 1
    OFPMP_GROUP = 6
144
145
    #: Group description.
146
    #: The request body is empty.
147
    #: The reply body is an array of struct ofp_group_desc_stats.
148 1
    OFPMP_GROUP_DESC = 7
149
150
    #: Group features.
151
    #: The request body is empty.
152
    #: The reply body is struct ofp_group_features.
153 1
    OFPMP_GROUP_FEATURES = 8
154
155
    #: Meter statistics.
156
    #: The request body is struct ofp_meter_multipart_requests.
157
    #: The reply body is an array of struct ofp_meter_stats.
158 1
    OFPMP_METER = 9
159
160
    #: Meter configuration.
161
    #: The request body is struct ofp_meter_multipart_requests.
162
    #: The reply body is an array of struct ofp_meter_config.
163 1
    OFPMP_METER_CONFIG = 10
164
165
    #: Meter features.
166
    #: The request body is empty.
167
    #: The reply body is struct ofp_meter_features.
168 1
    OFPMP_METER_FEATURES = 11
169
170
    #: Table features.
171
    #: The request body is either empty or contains an array of
172
    #: struct ofp_table_features containing the controller’s desired view of
173
    #: the switch. If the switch is unable to set the specified view an error
174
    #: is returned.
175
    #: The reply body is an array of struct ofp_table_features.
176 1
    OFPMP_TABLE_FEATURES = 12
177
178
    #: Port description.
179
    #: The request body is empty.
180
    #: The reply body is an array of struct ofp_port.
181 1
    OFPMP_PORT_DESC = 13
182
183
    #: Experimenter extension.
184
    #: The request and reply bodies begin with
185
    #: struct ofp_experimenter_multipart_header.
186
    #: The request and reply bodies are otherwise experimenter-defined.
187 1
    OFPMP_EXPERIMENTER = 0xffff
188
189
190
# Classes
191
192 1
class Bucket(GenericStruct):
193
    """Bucket for use in groups."""
194
195 1
    length = UBInt16()
196 1
    weight = UBInt16()
197 1
    watch_port = UBInt32()
198 1
    watch_group = UBInt32()
199 1
    pad = Pad(4)
200 1
    actions = FixedTypeList(ActionHeader)
201
202 1
    def __init__(self, length=None, weight=None, watch_port=None,
203
                 watch_group=None, actions=None):
204
        """Initialize all instance variables.
205
206
        Args:
207
            length (int): Length the bucket in bytes, including this header and
208
                any padding to make it 64-bit aligned.
209
            weight (int): Relative weight of bucket. Only defined for select
210
                groups.
211
            watch_port (int): Port whose state affects whether this bucket is
212
                live. Only required for fast failover groups.
213
            watch_group (int): Group whose state affects whether this bucket is
214
                live. Only required for fast failover groups.
215
            actions (~pyof.v0x04.common.action.ListOfActions): The action
216
                length is inferred from the length field in the header.
217
        """
218 1
        super().__init__()
219 1
        self.length = length
220 1
        self.weight = weight
221 1
        self.watch_port = watch_port
222 1
        self.watch_group = watch_group
223 1
        self.actions = actions
224
225
226 1
class BucketCounter(GenericStruct):
227
    """Used in group stats replies."""
228
229
    #: Number of packets processed by bucket.
230 1
    packet_count = UBInt64()
231
    #: Number of bytes processed by bucket.
232 1
    byte_count = UBInt64()
233
234 1
    def __init__(self, packet_count=None, byte_count=None):
235
        """Create BucketCounter with the optional parameters below.
236
237
        Args:
238
            packet_count (int): Number of packets processed by bucket.
239
            byte_count (int): Number of bytes processed by bucket.
240
        """
241
        super().__init__()
242
        self.packet_count = packet_count
243
        self.byte_count = byte_count
244
245
246 1
class ListOfBucketCounter(FixedTypeList):
247
    """List of BucketCounter.
248
249
    Represented by instances of BucketCounter.
250
    """
251
252 1
    def __init__(self, items=None):
253
        """Create a ListOfBucketCounter with the optional parameters below.
254
255
        Args:
256
            items (|BucketCounter_v0x04|): Instance or a list of instances.
257
        """
258 1
        super().__init__(pyof_class=BucketCounter, items=items)
259
260
261
# Base Classes for other messages - not meant to be directly used, so, because
262
# of that, they will not be inserted on the __all__ attribute.
263
264
265 1
class AsyncConfig(GenericMessage):
266
    """Asynchronous message configuration base class.
267
268
    Common structure for SetAsync and GetAsyncReply messages.
269
270
    AsyncConfig contains three 2-element arrays. Each array controls whether
271
    the controller receives asynchronous messages with a specific
272
    :class:`~pyof.v0x04.common.header.Type`. Within each array, element
273
    0 specifies messages of interest when the controller has a OFPCR_ROLE_EQUAL
274
    or OFPCR_ROLE_MASTER role; element 1, when the controller has a
275
    OFPCR_ROLE_SLAVE role. Each array element is a bit-mask in which a 0-bit
276
    disables receiving a message sent with the reason code corresponding to the
277
    bit index and a 1-bit enables receiving it.
278
    """
279
280
    #: OpenFlow :class:`~pyof.v0x04.common.header.Header`
281
    #: OFPT_GET_ASYNC_REPLY or OFPT_SET_ASYNC.
282 1
    header = Header()
283 1
    packet_in_mask1 = UBInt32(enum_ref=PacketInReason)
284 1
    packet_in_mask2 = UBInt32(enum_ref=PacketInReason)
285 1
    port_status_mask1 = UBInt32(enum_ref=PortReason)
286 1
    port_status_mask2 = UBInt32(enum_ref=PortReason)
287 1
    flow_removed_mask1 = UBInt32(enum_ref=FlowRemovedReason)
288 1
    flow_removed_mask2 = UBInt32(enum_ref=FlowRemovedReason)
289
290 1
    def __init__(self, xid=None, packet_in_mask1=None, packet_in_mask2=None,
291
                 port_status_mask1=None, port_status_mask2=None,
292
                 flow_removed_mask1=None, flow_removed_mask2=None):
293
        """Create a AsyncConfig with the optional parameters below.
294
295
        Args:
296
            xid (int): xid to be used on the message header.
297
            packet_in_mask1
298
                (~pyof.v0x04.asynchronous.packet_in.PacketInReason):
299
                    A instance of PacketInReason
300
            packet_in_mask2
301
                (~pyof.v0x04.asynchronous.packet_in.PacketInReason):
302
                    A instance of PacketInReason
303
            port_status_mask1
304
                (~pyof.v0x04.asynchronous.port_status.PortReason):
305
                    A instance of PortReason
306
            port_status_mask2
307
                (~pyof.v0x04.asynchronous.port_status.PortReason):
308
                    A instance of PortReason
309
            flow_removed_mask1
310
                (~pyof.v0x04.asynchronous.flow_removed.FlowRemoved):
311
                    A instance of FlowRemoved.
312
            flow_removed_mask2
313
                (~pyof.v0x04.asynchronous.flow_removed.FlowRemoved):
314
                    A instance of FlowRemoved.
315
        """
316 1
        super().__init__(xid)
317 1
        self.packet_in_mask1 = packet_in_mask1
318 1
        self.packet_in_mask2 = packet_in_mask2
319 1
        self.port_status_mask1 = port_status_mask1
320 1
        self.port_status_mask2 = port_status_mask2
321 1
        self.flow_removed_mask1 = flow_removed_mask1
322 1
        self.flow_removed_mask2 = flow_removed_mask2
323
324
325 1
class RoleBaseMessage(GenericMessage):
326
    """Role basic structure for RoleRequest and RoleReply messages."""
327
328
    #: :class:`~pyof.v0x04.common.header.Header`
329
    #: Type OFPT_ROLE_REQUEST/OFPT_ROLE_REPLY.
330 1
    header = Header()
331
    #: One of NX_ROLE_*. (:class:`~.controller2switch.common.ControllerRole`)
332 1
    role = UBInt32(enum_ref=ControllerRole)
333
    #: Align to 64 bits.
334 1
    pad = Pad(4)
335
    #: Master Election Generation Id.
336 1
    generation_id = UBInt64()
337
338 1
    def __init__(self, xid=None, role=None, generation_id=None):
339
        """Create a RoleBaseMessage with the optional parameters below.
340
341
        Args:
342
            xid (int): OpenFlow xid to the header.
343
            role (:class:`~.controller2switch.common.ControllerRole`): .
344
            generation_id (int): Master Election Generation Id.
345
        """
346 1
        super().__init__(xid)
347 1
        self.role = role
348 1
        self.generation_id = generation_id
349
350
351 1
class SwitchConfig(GenericMessage):
352
    """Used as base class for SET_CONFIG and GET_CONFIG_REPLY messages."""
353
354
    #: OpenFlow :class:`~pyof.v0x04.common.header.Header`
355 1
    header = Header()
356 1
    flags = UBInt16(enum_ref=ConfigFlag)
357 1
    miss_send_len = UBInt16()
358
359 1
    def __init__(self, xid=None, flags=ConfigFlag.OFPC_FRAG_NORMAL,
360
                 miss_send_len=ControllerMaxLen.OFPCML_NO_BUFFER):
361
        """Create a SwitchConfig with the optional parameters below.
362
363
        Args:
364
            xid (int): xid to be used on the message header.
365
            flags (ConfigFlag): OFPC_* flags.
366
            miss_send_len (int): UBInt16 max bytes of new flow that the
367
                datapath should send to the controller.
368
        """
369 1
        super().__init__(xid)
370 1
        self.flags = flags
371 1
        self.miss_send_len = miss_send_len
372
373
374
# Multipart body
375
376 1
class ExperimenterMultipartHeader(GenericStruct):
377
    """Body for ofp_multipart_request/reply of type OFPMP_EXPERIMENTER."""
378
379 1
    experimenter = UBInt32()
380 1
    exp_type = UBInt32()
381
    #: Followed by experimenter-defined arbitrary data.
382
383 1
    def __init__(self, experimenter=None, exp_type=None):
384
        """Create a ExperimenterMultipartHeader with the parameters below.
385
386
        Args:
387
            experimenter: Experimenter ID which takes the same form as in
388
                struct ofp_experimenter_header (
389
                :class:`~pyof.v0x04.symmetric.experimenter.ExperimenterHeader`)
390
            exp_type: Experimenter defined.
391
        """
392
        super().__init__()
393
        self.experimenter = experimenter
394
        self.exp_type = exp_type
395
396
397 1
class Property(GenericStruct):
398
    """Table Property class.
399
400
    This class represents a Table Property generic structure.
401
    """
402
403 1
    property_type = UBInt16(enum_ref=TableFeaturePropType)
404 1
    length = UBInt16(4)
405
406 1
    def __init__(self, property_type=None):
407
        """Create a Property with the optional parameters below.
408
409
        Args:
410
            type(|TableFeaturePropType_v0x04|):
411
                Property Type value of this instance.
412
        """
413
        super().__init__()
414
        self.property_type = property_type
415
416 1
    def pack(self, value=None):
417
        """Pack method used to update the length of instance and  packing.
418
419
        Args:
420
            value: Structure to be packed.
421
        """
422
        self.update_length()
423
        return super().pack(value)
424
425 1
    def unpack(self, buff=None, offset=0):
426
        """Unpack *buff* into this object.
427
428
        This method will convert a binary data into a readable value according
429
        to the attribute format.
430
431
        Args:
432
            buff (bytes): Binary buffer.
433
            offset (int): Where to begin unpacking.
434
435
        Raises:
436
            :exc:`~.exceptions.UnpackException`: If unpack fails.
437
438
        """
439
        property_type = UBInt16(enum_ref=TableFeaturePropType)
440
        property_type.unpack(buff, offset)
441
        self.__class__ = TableFeaturePropType(property_type.value).find_class()
442
443
        length = UBInt16()
444
        length.unpack(buff, offset=offset+2)
445
        super().unpack(buff[:offset+length.value], offset=offset)
446
447 1
    def update_length(self):
448
        """Update the length of current instance."""
449
        self.length = self.get_size()
450
451
452 1
class InstructionsProperty(Property):
453
    """Instructions property.
454
455
    This class represents Property with the following types:
456
        OFPTFPT_INSTRUCTIONS
457
        OFPTFPT_INSTRUCTIONS_MISS
458
    """
459
460 1
    instruction_ids = ListOfInstruction()
461
462 1
    def __init__(self, property_type=TableFeaturePropType.OFPTFPT_INSTRUCTIONS,
463
                 instruction_ids=None):
464
        """Create a InstructionsProperty with the optional parameters below.
465
466
        Args:
467
            type(|TableFeaturePropType_v0x04|):
468
                Property Type value of this instance.
469
            next_table_ids(|ListOfInstruction_v0x04|):
470
                List of InstructionGotoTable instances.
471
        """
472
        super().__init__(property_type=property_type)
473
        self.instruction_ids = instruction_ids if instruction_ids else []
474
        self.update_length()
475
476
477 1
class NextTablesProperty(Property):
478
    """Next Tables Property.
479
480
    This class represents Property with the following types:
481
        OFPTFPT_NEXT_TABLES
482
        OFPTFPT_NEXT_TABLES_MISS
483
    """
484
485 1
    next_table_ids = ListOfInstruction()
486
487 1
    def __init__(self, property_type=TableFeaturePropType.OFPTFPT_NEXT_TABLES,
488
                 next_table_ids=None):
489
        """Create a NextTablesProperty with the optional parameters below.
490
491
        Args:
492
            type(|TableFeaturePropType_v0x04|):
493
                Property Type value of this instance.
494
            next_table_ids (|ListOfInstruction_v0x04|):
495
                List of InstructionGotoTable instances.
496
        """
497
        super().__init__(property_type)
498
        self.next_table_ids = (ListOfInstruction() if next_table_ids is None
499
                               else next_table_ids)
500
        self.update_length()
501
502
503 1
class ActionsProperty(Property):
504
    """Actions Property.
505
506
    This class represents Property with the following type:
507
        OFPTFPT_WRITE_ACTIONS
508
        OFPTFPT_WRITE_ACTIONS_MISS
509
        OFPTFPT_APPLY_ACTIONS
510
        OFPTFPT_APPLY_ACTIONS_MISS
511
    """
512
513 1
    action_ids = ListOfActions()
514
515 1
    def __init__(self,
516
                 property_type=TableFeaturePropType.OFPTFPT_WRITE_ACTIONS,
517
                 action_ids=None):
518
        """Create a ActionsProperty with the optional parameters below.
519
520
        Args:
521
            type(|TableFeaturePropType_v0x04|):
522
                Property Type value of this instance.
523
            action_ids(|ListOfActions_v0x04|):
524
                List of Action instances.
525
        """
526
        super().__init__(property_type)
527
        self.action_ids = action_ids if action_ids else ListOfActions()
528
        self.update_length()
529
530
531 1
class OxmProperty(Property):
532
    """Match, Wildcard or Set-Field property.
533
534
    This class represents Property with the following types:
535
        OFPTFPT_MATCH
536
        OFPTFPT_WILDCARDS
537
        OFPTFPT_WRITE_SETFIELD
538
        OFPTFPT_WRITE_SETFIELD_MISS
539
        OFPTFPT_APPLY_SETFIELD
540
        OFPTFPT_APPLY_SETFIELD_MISS
541
    """
542
543 1
    oxm_ids = ListOfOxmHeader()
544
545 1
    def __init__(self, property_type=TableFeaturePropType.OFPTFPT_MATCH,
546
                 oxm_ids=None):
547
        """Create an OxmProperty with the optional parameters below.
548
549
        Args:
550
            type(|TableFeaturePropType_v0x04|):
551
                Property Type value of this instance.
552
            oxm_ids(|ListOfOxmHeader_v0x04|):
553
                List of OxmHeader instances.
554
        """
555
        super().__init__(property_type)
556
        self.oxm_ids = ListOfOxmHeader() if oxm_ids is None else oxm_ids
557
        self.update_length()
558
559
560 1
class ListOfProperty(FixedTypeList):
561
    """List of Table Property.
562
563
    Represented by instances of Property.
564
    """
565
566 1
    def __init__(self, items=None):
567
        """Create a ListOfProperty with the optional parameters below.
568
569
        Args:
570
            items (|Property_v0x04|): Instance or a list of instances.
571
        """
572 1
        super().__init__(pyof_class=Property, items=items)
573
574
575 1
class TableFeatures(GenericStruct):
576
    """Abstration of common class Table Features.
577
578
    Body for MultipartRequest of type OFPMP_TABLE_FEATURES.
579
    Body of reply to OFPMP_TABLE_FEATURES request.
580
    """
581
582 1
    length = UBInt16()
583
    # /* Identifier of table.  Lower numbered tables are consulted first. */
584 1
    table_id = UBInt8()
585
    # /* Align to 64-bits. */
586 1
    pad = Pad(5)
587 1
    name = Char(length=OFP_MAX_TABLE_NAME_LEN)
588
    # /* Bits of metadata table can match. */
589 1
    metadata_match = UBInt64()
590
    # /* Bits of metadata table can write. */
591 1
    metadata_write = UBInt64()
592
    # /* Bitmap of OFPTC_* values */
593 1
    config = UBInt32()
594
    # /* Max number of entries supported. */
595 1
    max_entries = UBInt32()
596
    # /* Table Feature Property list */
597 1
    properties = ListOfProperty()
598
599 1
    def __init__(self, table_id=Table.OFPTT_ALL, name="",
600
                 metadata_match=0xFFFFFFFFFFFFFFFF,
601
                 metadata_write=0xFFFFFFFFFFFFFFFF,
602
                 config=0,
603
                 max_entries=0,
604
                 properties=None):
605
        """Create a TableFeatures with the optional parameters below.
606
607
        Args:
608
            table_id(int): Indetifier of table.The default value
609
                OFPTT_ALL(``0xff``) will apply the configuration to all tables
610
                in the switch.
611
            name(Char): Characters representing the table name.
612
            metadata_match(int): Indicate the bits of the metadata field that
613
               the table can match on.The default value ``0xFFFFFFFFFFFFFFFF``
614
               indicates that the table can match the full metadata field.
615
            metadata_write(int): Indicates the bits of the metadata field that
616
               the table can write using the OFPIT_WRITE_METADATA instruction.
617
               The default value ``0xFFFFFFFFFFFFFFFF`` indicates that the
618
               table can write the full metadata field.
619
            config(int): Field reseved for future use.
620
            max_entries(int): Describe the maximum number of flow entries that
621
                can be inserted into that table.
622
            properties(~pyof.v0x04.controller2switch.common.ListOfProperty):
623
                List of Property intances.
624
        """
625 1
        super().__init__()
626 1
        self.table_id = table_id
627 1
        self.name = name
628 1
        self.metadata_match = metadata_match
629 1
        self.metadata_write = metadata_write
630 1
        self.config = config
631 1
        self.max_entries = max_entries
632 1
        self.properties = (ListOfProperty() if properties is None else
633
                           properties)
634 1
        self.update_length()
635
636 1
    def pack(self, value=None):
637
        """Pack method used to update the length of instance and packing.
638
639
        Args:
640
            value: Structure to be packed.
641
        """
642 1
        self.update_length()
643 1
        return super().pack(value)
644
645 1
    def update_length(self):
646
        """Update the length of current instance."""
647 1
        self.length = self.get_size()
648
649 1
    def unpack(self, buff=None, offset=0):
650
        """Unpack *buff* into this object.
651
652
        This method will convert a binary data into a readable value according
653
        to the attribute format.
654
655
        Args:
656
            buff (bytes): Binary buffer.
657
            offset (int): Where to begin unpacking.
658
659
        Raises:
660
            :exc:`~.exceptions.UnpackException`: If unpack fails.
661
662
        """
663 1
        length = UBInt16()
664 1
        length.unpack(buff, offset)
665
        super().unpack(buff[:offset+length.value], offset)
666