Passed
Pull Request — master (#577)
by Gleyberson
02:14
created

AggregateStatsRequest.__init__()   A

Complexity

Conditions 2

Size

Total Lines 25
Code Lines 10

Duplication

Lines 25
Ratio 100 %

Code Coverage

Tests 8
CRAP Score 2

Importance

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