Test Failed
Pull Request — master (#636)
by Humberto
01:14
created

AsyncConfig.__init__()   A

Complexity

Conditions 1

Size

Total Lines 34
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 10
dl 0
loc 34
ccs 8
cts 8
cp 1
rs 9.9
c 0
b 0
f 0
cc 1
nop 8
crap 1

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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