Test Failed
Push — master ( 182015...f7f025 )
by Carlos Eduardo
01:35
created

MultipartRequest   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 112
Duplicated Lines 25 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 12
c 1
b 0
f 0
dl 28
loc 112
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __init__() 0 13 1
B pack() 28 28 5
A unpack() 0 17 1
A _unpack_body() 0 5 1
B _get_body_instance() 0 27 4

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
"""Controller requesting state from datapath."""
2
3
# System imports
4
from enum import Enum
5
6
# Local source tree imports
7
from pyof.foundation.base import GenericMessage, GenericStruct
8
from pyof.foundation.basic_types import (BinaryData, FixedTypeList, Pad,
9
                                         UBInt8, UBInt16, UBInt32, UBInt64)
10
from pyof.v0x04.common.flow_match import Match
11
from pyof.v0x04.common.header import Header, Type
12
from pyof.v0x04.controller2switch.common import (ExperimenterMultipartHeader,
13
                                                 MultipartTypes, TableFeatures)
14
15
# Third-party imports
16
17
__all__ = ('MultipartRequest', 'MultipartRequestFlags',
18
           'AggregateStatsRequest', 'FlowStatsRequest',
19
           'PortStatsRequest', 'QueueStatsRequest',
20
           'GroupStatsRequest', 'MeterMultipartRequest',
21
           'TableFeatures')
22
23
# Enum
24
25
26
class MultipartRequestFlags(Enum):
27
    """Flags for MultipartRequest."""
28
29
    #: More requests to follow
30
    OFPMPF_REQ_MORE = 1 << 0
31
32
33
# Classes
34
35
36
class MultipartRequest(GenericMessage):
37
    """Request datapath state.
38
39
    While the system is running, the controller may request state from the
40
    datapath using the OFPT_MULTIPART_REQUEST message.
41
    """
42
43
    #: :class:`~.common.header.Header`
44
    header = Header(message_type=Type.OFPT_MULTIPART_REQUEST)
45
    #: One of the OFPMP_* constants.
46
    multipart_type = UBInt16(enum_ref=MultipartTypes)
47
    #: OFPMPF_REQ_* flags.
48
    flags = UBInt16(enum_ref=MultipartRequestFlags)
49
    #: Padding
50
    pad = Pad(4)
51
    #: Body of the request
52
    body = BinaryData()
53
54
    def __init__(self, xid=None, multipart_type=None, flags=None, body=b''):
55
        """The constructor just assings parameters to object attributes.
56
57
        Args:
58
            xid (int): xid to the header.
59
            multipart_type (int): One of the OFPMP_* constants.
60
            flags (int): OFPMPF_REQ_* flags.
61
            body (bytes): Body of the request.
62
        """
63
        super().__init__(xid)
64
        self.multipart_type = multipart_type
65
        self.flags = flags
66
        self.body = body
67
68 View Code Duplication
    def pack(self, value=None):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
69
        """Pack a MultipartRequest using the object's attributes.
70
71
        This method will pack the attribute body and multipart_type before pack
72
        the MultipartRequest object, then will return this struct as a
73
         binary data.
74
75
        Returns:
76
            multiparty_packed (bytes): Binary data with MultipartRequest
77
                                       packed.
78
        """
79
        buff = self.body
80
        if not value:
81
            value = self.body
82
83
        if value:
84
            if isinstance(value, (list, FixedTypeList)):
85
                obj = self._get_body_instance()
86
                obj.extend(value)
87
            elif hasattr(value, 'pack'):
88
                obj = value
89
90
            self.body = obj.pack()
91
92
        multiparty_packed = super().pack()
93
        self.body = buff
94
95
        return multiparty_packed
96
97
    def unpack(self, buff, offset=0):
98
        """Unpack a binary message into this object's attributes.
99
100
        Unpack the binary value *buff* and update this object attributes based
101
        on the results. It is an inplace method and it receives the binary data
102
        of the message **without the header**.
103
104
        This class' unpack method is like the :meth:`.GenericMessage.unpack`
105
        one, except for the ``body`` attribute which has its type determined
106
        by the ``multipart_type`` attribute.
107
108
        Args:
109
            buff (bytes): Binary data package to be unpacked, without the
110
                header.
111
        """
112
        super().unpack(buff[offset:])
113
        self._unpack_body()
114
115
    def _unpack_body(self):
116
        """Unpack `body` replace it by the result."""
117
        obj = self._get_body_instance()
118
        obj.unpack(self.body.value)
119
        self.body = obj
120
121
    def _get_body_instance(self):
122
        """Method used to return the body instance."""
123
        simple_body = {
124
            MultipartTypes.OFPMP_FLOW: FlowStatsRequest,
125
            MultipartTypes.OFPMP_AGGREGATE: AggregateStatsRequest,
126
            MultipartTypes.OFPMP_PORT_STATS: PortStatsRequest,
127
            MultipartTypes.OFPMP_QUEUE: QueueStatsRequest,
128
            MultipartTypes.OFPMP_GROUP: GroupStatsRequest,
129
            MultipartTypes.OFPMP_METER: MeterMultipartRequest,
130
            MultipartTypes.OFPMP_EXPERIMENTER: ExperimenterMultipartHeader
131
        }
132
133
        array_of_bodies = {MultipartTypes.OFPMP_TABLE_FEATURES: TableFeatures}
134
135
        if isinstance(self.multipart_type, (int, UBInt16)):
136
            self.multipart_type = self.multipart_type.enum_ref(
137
                self.multipart_type.value)
138
139
        pyof_class = simple_body.get(self.multipart_type, None)
140
        if pyof_class:
141
            return pyof_class()
142
143
        array_of_class = array_of_bodies.get(self.multipart_type, None)
144
        if array_of_class:
145
            return FixedTypeList(pyof_class=array_of_class)
146
147
        return BinaryData(b'')
148
149
150
class AggregateStatsRequest(GenericStruct):
151
    """Body for ofp_stats_request of type OFPST_AGGREGATE."""
152
153
    #: ID of table to read (from ofp_table_stats) OFPTT_ALL for all tables.
154
    table_id = UBInt8()
155
    #: Align to 32 bits.
156
    pad = Pad(3)
157
    #: Require matching entries to include this as an output port. A value of
158
    #: OFPP_ANY indicates no restriction.
159
    out_port = UBInt32()
160
    #: Require matching entries to include this as an output group. A value of
161
    #: OFPG_ANY indicates no restriction.
162
    out_group = UBInt32()
163
    #: Align to 64 bits
164
    pad2 = Pad(4)
165
    #: Require matching entries to contain this cookie value
166
    cookie = UBInt64()
167
    #: Mask used to restrict the cookie bits that must match. A value of 0
168
    #: indicates no restriction.
169
    cookie_mask = UBInt64()
170
    #: Fields to match. Variable size.
171
    match = Match()
172
173
    def __init__(self, table_id=None, out_port=None, out_group=None,
174
                 cookie=None, cookie_mask=None, match=None):
175
        """The constructor just assings parameters to object attributes.
176
177
        Args:
178
            table_id (int): ID of table to read (from ofp_table_stats)
179
                OFPTT_ALL for all tables.
180
            out_port (int): Require matching entries to include this as an
181
                output port. A value of OFPP_ANY indicates no restriction.
182
            out_group (in): Require matching entries to include this as an
183
                output group. A value of OFPG_ANY indicates no restriction.
184
            cookie (int): Require matching entries to contain this cookie value
185
            cookie_mask (int): Mask used to restrict the cookie bits that must
186
                match. A value of 0 indicates no restriction.
187
            match (Match): Fields to match. Variable size
188
        """
189
        super().__init__()
190
        self.table_id = table_id
191
        self.out_port = out_port
192
        self.out_group = out_group
193
        self.cookie = cookie
194
        self.cookie_mask = cookie_mask
195
        self.match = match
196
197
198
class FlowStatsRequest(GenericStruct):
199
    """Body for ofp_stats_request of type OFPST_FLOW."""
200
201
    table_id = UBInt8()
202
    #: Align to 32 bits.
203
    pad = Pad(3)
204
    out_port = UBInt32()
205
    out_group = UBInt32()
206
    pad2 = Pad(4)
207
    cookie = UBInt64()
208
    cookie_mask = UBInt64()
209
    match = Match()
210
211
    def __init__(self, table_id=None, out_port=None, out_group=None,
212
                 cookie=None, cookie_mask=None, match=None):
213
        """The constructor just assings parameters to object attributes.
214
215
        Args:
216
            table_id (int): ID of table to read (from pyof_table_stats)
217
                0xff for all tables or 0xfe for emergency.
218
            out_port (:class:`int`, :class:`.Port`): Require matching entries
219
                to include this as an output port. A value of
220
                :attr:`.Port.OFPP_NONE` indicates no restriction.
221
            out_group: Require matching entries to include this as an output
222
                group. A value of OFPG_ANY indicates no restriction.
223
            cookie: Requires matching entries to contain this cookie value
224
            cookie_mask: Mask used to restrict the cookie bits that must match.
225
                A value of 0 indicates no restriction.
226
            match (Match): Fields to match.
227
        """
228
        super().__init__()
229
        self.table_id = table_id
230
        self.out_port = out_port
231
        self.out_group = out_group
232
        self.cookie = cookie
233
        self.cookie_mask = cookie_mask
234
        self.match = match
235
236
237
class PortStatsRequest(GenericStruct):
238
    """Body for ofp_stats_request of type OFPST_PORT."""
239
240
    port_no = UBInt32()
241
    #: Align to 64-bits.
242
    pad = Pad(4)
243
244
    def __init__(self, port_no=None):
245
        """The constructor just assings parameters to object attributes.
246
247
        Args:
248
            port_no (:class:`int`, :class:`.Port`): OFPST_PORT message must
249
                request statistics either for a single port (specified in
250
                ``port_no``) or for all ports (if port_no ==
251
                :attr:`.Port.OFPP_NONE`).
252
        """
253
        super().__init__()
254
        self.port_no = port_no
255
256
257
class QueueStatsRequest(GenericStruct):
258
    """Implements the request body of a ``port_no``."""
259
260
    port_no = UBInt32()
261
    queue_id = UBInt32()
262
263
    def __init__(self, port_no=None, queue_id=None):
264
        """The constructor just assings parameters to object attributes.
265
266
        Args:
267
            port_no (:class:`int`, :class:`.Port`): All ports if
268
                :attr:`.Port.OFPP_ALL`.
269
            queue_id (int): All queues if OFPQ_ALL.
270
        """
271
        super().__init__()
272
        self.port_no = port_no
273
        self.queue_id = queue_id
274
275
276
class GroupStatsRequest(GenericStruct):
277
    """Body of OFPMP_GROUP request."""
278
279
    #: Group id. All groups is OFPG_ALL
280
    group_id = UBInt32()
281
    #: Align to 64 bits
282
    pad = Pad(4)
283
284
    def __init__(self, group_id=None):
285
        """The constructor just assigns parameters to object attributes.
286
287
        Args:
288
            group_id(int): ID of group to read. OFPG_ALL to request informatio
289
                for all groups.
290
        """
291
        super().__init__()
292
        self.group_id = group_id
293
294
295
class MeterMultipartRequest(GenericStruct):
296
    """MeterMultipartRequest structure.
297
298
    This class represents the structure for ofp_meter_multipart_request.
299
    This structure is a body of OFPMP_METER and OFPMP_METER_CONFIG requests.
300
    """
301
302
    # Meter instance, or OFPM_ALL.
303
    meter_id = UBInt32()
304
305
    # Align to 64 bits.
306
    pad = Pad(4)
307
308
    def __init__(self, meter_id=None):
309
        """Constructor of MeterMultipartRequest receives the parameters below.
310
311
        Args:
312
            meter_id(Meter): Meter Indentify.The value Meter.OFPM_ALL is used
313
                             to refer to all Meters on the switch.
314
        """
315
        super().__init__()
316
        self.meter_id = meter_id
317