Passed
Pull Request — master (#489)
by
unknown
02:11
created

ActionSetField.pack()   A

Complexity

Conditions 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1.4218

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 5
ccs 1
cts 4
cp 0.25
rs 9.4285
cc 1
crap 1.4218
1
"""Defines actions that may be associated with flows packets."""
2
# System imports
3 1
from enum import IntEnum
4
5
# Local source tree imports
6 1
from pyof.foundation.base import GenericStruct
7 1
from pyof.foundation.basic_types import (
8
    FixedTypeList, Pad, UBInt8, UBInt16, UBInt32)
9 1
from pyof.v0x04.common.flow_match import OxmTLV
10
11
# Third-party imports
12
13 1
__all__ = ('ActionExperimenterHeader', 'ActionGroup', 'ActionHeader',
14
           'ActionCopyTTLIn', 'ActionCopyTTLOut', 'ActionDecMPLSTTL',
15
           'ActionSetMPLSTTL', 'ActionDecNWTTL', 'ActionSetNWTTL',
16
           'ActionOutput', 'ActionPopMPLS', 'ActionPopPBB', 'ActionPopVLAN',
17
           'ActionPush', 'ActionSetField', 'ActionSetQueue', 'ActionType',
18
           'ControllerMaxLen', 'ListOfActions')
19
20
# Enums
21
22
23 1
class ActionType(IntEnum):
24
    """Actions associated with flows and packets."""
25
26
    #: Output to switch port.
27 1
    OFPAT_OUTPUT = 0
28
    #: Copy TTL "outwards" -- from next-to-outermost to outermost
29 1
    OFPAT_COPY_TTL_OUT = 11
30
    #: Copy TTL "inwards" -- from outermost to next-to-outermost
31 1
    OFPAT_COPY_TTL_IN = 12
32
    #: MPLS TTL
33 1
    OFPAT_SET_MPLS_TTL = 15
34
    #: Decrement MPLS TTL
35 1
    OFPAT_DEC_MPLS_TTL = 16
36
    #: Push a new VLAN tag
37 1
    OFPAT_PUSH_VLAN = 17
38
    #: Pop the outer VLAN tag
39 1
    OFPAT_POP_VLAN = 18
40
    #: Push a new MPLS tag
41 1
    OFPAT_PUSH_MPLS = 19
42
    #: Pop the outer MPLS tag
43 1
    OFPAT_POP_MPLS = 20
44
    #: Set queue id when outputting to a port
45 1
    OFPAT_SET_QUEUE = 21
46
    #: Apply group.
47 1
    OFPAT_GROUP = 22
48
    #: IP TTL.
49 1
    OFPAT_SET_NW_TTL = 23
50
    #: Decrement IP TTL.
51 1
    OFPAT_DEC_NW_TTL = 24
52
    #: Set a header field using OXM TLV format.
53 1
    OFPAT_SET_FIELD = 25
54
    #: Push a new PBB service tag (I-TAG)
55 1
    OFPAT_PUSH_PBB = 26
56
    #: Pop the outer PBB service tag (I-TAG)
57 1
    OFPAT_POP_PBB = 27
58
    #: Experimenter type
59 1
    OFPAT_EXPERIMENTER = 0xffff
60
61
62 1
class ControllerMaxLen(IntEnum):
63
    """A max_len of OFPCML_NO_BUFFER means not to buffer.
64
65
    The packet should be sent.
66
    """
67
68
    #: maximum max_len value which can be used to request a specific byte
69
    #:     length.
70 1
    OFPCML_MAX = 0xffe5
71
    #: indicates that no buffering should be applied and the whole packet is to
72
    #:     be sent to the controller.
73 1
    OFPCML_NO_BUFFER = 0xffff
74
75
76
# Classes
77
78
79 1
class ActionHeader(GenericStruct):
80
    """Action header that is common to all actions.
81
82
    The length includes the header and any padding used to make the action
83
    64-bit aligned.
84
    NB: The length of an action *must* always be a multiple of eight.
85
    """
86
87
    #: One of OFPAT_*.
88 1
    action_type = UBInt16(enum_ref=ActionType)
89
    #: Length of action, including this header. This is the length of actions,
90
    #:    including any padding to make it 64-bit aligned.
91 1
    length = UBInt16()
92
    # Pad for 64-bit alignment.
93
    # This should not be implemented, as each action type has its own padding.
94
    # pad = Pad(4)
95
96 1
    _allowed_types = ()
97
98 1
    def __init__(self, action_type=None, length=None):
99
        """Create an ActionHeader with the optional parameters below.
100
101
        Args:
102
            action_type (~pyof.v0x04.common.action.ActionType):
103
                The type of the action.
104
            length (int): Length of action, including this header.
105
        """
106
        super().__init__()
107
        self.action_type = action_type
108
        self.length = length
109
110 1
    def unpack(self, buff, offset=0):
111
        """Unpack a binary message into this object's attributes.
112
113
        Unpack the binary value *buff* and update this object attributes based
114
        on the results.
115
116
        Args:
117
            buff (bytes): Binary data package to be unpacked.
118
            offset (int): Where to begin unpacking.
119
120
        Raises:
121
            Exception: If there is a struct unpacking error.
122
123
        """
124
        self.action_type = UBInt16(enum_ref=ActionType)
125
        self.action_type.unpack(buff, offset)
126
127
        for cls in ActionHeader.__subclasses__():
128
            if self.action_type.value in cls.get_allowed_types():
129
                self.__class__ = cls
130
                break
131
132
        super().unpack(buff, offset)
133
134 1
    @classmethod
135
    def get_allowed_types(cls):
136
        """Return allowed types for the class."""
137
        return cls._allowed_types
138
139
140 1
class ActionExperimenterHeader(ActionHeader):
141
    """Action structure for OFPAT_EXPERIMENTER."""
142
143 1
    experimenter = UBInt32()
144
145 1
    _allowed_types = ActionType.OFPAT_EXPERIMENTER,
146
147 1
    def __init__(self, length=None, experimenter=None):
148
        """Create ActionExperimenterHeader with the optional parameters below.
149
150
        Args:
151
            experimenter (int): The experimenter field is the Experimenter ID,
152
                which takes the same form as in struct ofp_experimenter.
153
        """
154
        super().__init__(action_type=ActionType.OFPAT_EXPERIMENTER)
155
        self.length = length
156
        self.experimenter = experimenter
157
158
159 1
class ActionGroup(ActionHeader):
160
    """Action structure for OFPAT_GROUP."""
161
162 1
    group_id = UBInt32()
163
164 1
    _allowed_types = ActionType.OFPAT_GROUP,
165
166 1
    def __init__(self, group_id=None):
167
        """Create an ActionGroup with the optional parameters below.
168
169
        Args:
170
            group_id (int): The group_id indicates the group used to process
171
                this packet. The set of buckets to apply depends on the group
172
                type.
173
        """
174
        super().__init__(action_type=ActionType.OFPAT_GROUP, length=8)
175
        self.group_id = group_id
176
177
178 1
class ActionDecMPLSTTL(ActionHeader):
179
    """Action structure for OFPAT_DEC_MPLS_TTL."""
180
181 1
    pad = Pad(4)
182
183 1
    _allowed_types = ActionType.OFPAT_DEC_MPLS_TTL,
184
185 1
    def __init__(self):
186
        """Create an ActionDecMPLSTTL."""
187
        super().__init__(action_type=ActionType.OFPAT_DEC_MPLS_TTL, length=8)
188
189
190 1
class ActionSetMPLSTTL(ActionHeader):
191
    """Action structure for OFPAT_SET_MPLS_TTL."""
192
193 1
    mpls_ttl = UBInt8()
194 1
    pad = Pad(3)
195
196 1
    _allowed_types = ActionType.OFPAT_SET_MPLS_TTL,
197
198 1
    def __init__(self, mpls_ttl=None):
199
        """Create an ActionSetMPLSTTL with the optional parameters below.
200
201
        Args:
202
            mpls_ttl (int): The mpls_ttl field is the MPLS TTL to set.
203
        """
204
        super().__init__(action_type=ActionType.OFPAT_SET_MPLS_TTL, length=8)
205
        self.mpls_ttl = mpls_ttl
206
207
208 1
class ActionCopyTTLIn(ActionHeader):
209
    """Action structure for OFPAT_COPY_TTL_IN."""
210
211 1
    pad = Pad(4)
212
213 1
    _allowed_types = ActionType.OFPAT_COPY_TTL_IN,
214
215 1
    def __init__(self):
216
        """Create an ActionCopyTTLIn."""
217
        super().__init__(action_type=ActionType.OFPAT_COPY_TTL_IN, length=8)
218
219
220 1
class ActionCopyTTLOut(ActionHeader):
221
    """Action structure for OFPAT_COPY_TTL_OUT."""
222
223 1
    pad = Pad(4)
224
225 1
    _allowed_types = ActionType.OFPAT_COPY_TTL_OUT,
226
227 1
    def __init__(self):
228
        """Create an ActionCopyTTLOut."""
229
        super().__init__(action_type=ActionType.OFPAT_COPY_TTL_OUT, length=8)
230
231
232 1
class ActionPopVLAN(ActionHeader):
233
    """Action structure for OFPAT_POP_VLAN."""
234
235 1
    pad = Pad(4)
236
237 1
    _allowed_types = ActionType.OFPAT_POP_VLAN,
238
239 1
    def __init__(self):
240
        """Create an ActionPopVLAN."""
241
        super().__init__(action_type=ActionType.OFPAT_POP_VLAN, length=8)
242
243
244 1
class ActionPopPBB(ActionHeader):
245
    """Action structure for OFPAT_POP_PBB."""
246
247 1
    pad = Pad(4)
248
249 1
    _allowed_types = ActionType.OFPAT_POP_PBB,
250
251 1
    def __init__(self):
252
        """Create an ActionPopPBB."""
253
        super().__init__(action_type=ActionType.OFPAT_POP_PBB, length=8)
254
255
256 1
class ActionDecNWTTL(ActionHeader):
257
    """Action structure for OFPAT_DEC_NW_TTL."""
258
259 1
    pad = Pad(4)
260
261 1
    _allowed_types = ActionType.OFPAT_DEC_NW_TTL,
262
263 1
    def __init__(self):
264
        """Create a ActionDecNWTTL."""
265
        super().__init__(action_type=ActionType.OFPAT_DEC_NW_TTL, length=8)
266
267
268 1
class ActionSetNWTTL(ActionHeader):
269
    """Action structure for OFPAT_SET_NW_TTL."""
270
271 1
    nw_ttl = UBInt8()
272 1
    pad = Pad(3)
273
274 1
    _allowed_types = ActionType.OFPAT_SET_NW_TTL,
275
276 1
    def __init__(self, nw_ttl=None):
277
        """Create an ActionSetNWTTL with the optional parameters below.
278
279
        Args:
280
            nw_ttl (int): the TTL address to set in the IP header.
281
        """
282
        super().__init__(action_type=ActionType.OFPAT_SET_NW_TTL, length=8)
283
        self.nw_ttl = nw_ttl
284
285
286 1
class ActionOutput(ActionHeader):
287
    """Defines the actions output.
288
289
    Action structure for :attr:`ActionType.OFPAT_OUTPUT`, which sends packets
290
    out :attr:`port`. When the :attr:`port` is the
291
    :attr:`.Port.OFPP_CONTROLLER`, :attr:`max_length` indicates the max number
292
    of bytes to send. A :attr:`max_length` of zero means no bytes of the packet
293
    should be sent.
294
    """
295
296 1
    port = UBInt32()
297 1
    max_length = UBInt16()
298 1
    pad = Pad(6)
299
300 1
    _allowed_types = ActionType.OFPAT_OUTPUT,
301
302 1
    def __init__(self, port=None,
303
                 max_length=ControllerMaxLen.OFPCML_NO_BUFFER):
304
        """Create a ActionOutput with the optional parameters below.
305
306
        Args:
307
            port (:class:`Port` or :class:`int`): Output port.
308
            max_length (int): Max length to send to controller.
309
        """
310
        super().__init__(action_type=ActionType.OFPAT_OUTPUT, length=16)
311
        self.port = port
312
        self.max_length = max_length
313
314
315 1
class ActionPopMPLS(ActionHeader):
316
    """Action structure for OFPAT_POP_MPLS."""
317
318 1
    ethertype = UBInt16()
319 1
    pad = Pad(2)
320
321 1
    _allowed_types = ActionType.OFPAT_POP_MPLS,
322
323 1
    def __init__(self, ethertype=None):
324
        """Create an ActionPopMPLS with the optional parameters below.
325
326
        Args:
327
            ethertype (int): indicates the Ethertype of the payload.
328
        """
329
        super().__init__(action_type=ActionType.OFPAT_POP_MPLS)
330
        self.ethertype = ethertype
331
332
333 1
class ActionPush(ActionHeader):
334
    """Action structure for OFPAT_PUSH_[VLAN/MPLS/PBB]."""
335
336 1
    ethertype = UBInt16()
337 1
    pad = Pad(2)
338
339 1
    _allowed_types = (ActionType.OFPAT_PUSH_VLAN, ActionType.OFPAT_PUSH_MPLS,
340
                      ActionType.OFPAT_PUSH_PBB)
341
342 1
    def __init__(self, action_type=None, ethertype=None):
343
        """Create a ActionPush with the optional parameters below.
344
345
        Args:
346
            action_type (:class:`ActionType`): indicates which tag will be
347
                pushed (VLAN, MPLS, PBB).
348
            ethertype (int): indicates the Ethertype of the new tag.
349
        """
350
        super().__init__(action_type, length=8)
351
        self.ethertype = ethertype
352
353
354 1
class ActionSetField(ActionHeader):
355
    """Action structure for OFPAT_SET_FIELD."""
356
357 1
    field = OxmTLV()
358
359 1
    _allowed_types = ActionType.OFPAT_SET_FIELD,
360
361 1
    def __init__(self, field=None):
362
        """Create a ActionSetField with the optional parameters below.
363
364
        Args:
365
            length (int): length padded to 64 bits, followed by exactly
366
                          oxm_len bytes containing a single OXM TLV, then
367
                          exactly ((oxm_len + 4) + 7)/8*8 - (oxm_len + 4)
368
                          (between 0 and 7) bytes of all-zero bytes
369
            field (:class:`OxmTLV`): OXM field and value.
370
        """
371
        super().__init__(action_type=ActionType.OFPAT_SET_FIELD)
372
        self.field = OxmTLV() if field is None else field
373
374 1
    def pack(self, value=None):
375
        """Pack this structure updating the length and padding it."""
376
        self._update_length()
377
        packet = super().pack()
378
        return self._complete_last_byte(packet)
379
380 1
    def _update_length(self):
381
        """Update the length field of the struct."""
382
        action_length = 4 + len(self.field.pack())
383
        overflow = action_length % 8
384
        self.length = action_length
385
        if overflow:
386
            self.length = action_length + 8 - overflow
387
388 1
    def _complete_last_byte(self, packet):
389
        """Pad until the packet length is a multiple of 8 (bytes)."""
390
        padded_size = self.length
391
        padding_bytes = padded_size - len(packet)
392
        if padding_bytes > 0:
393
            packet += Pad(padding_bytes).pack()
394
        return packet
395
396
397 1
class ActionSetQueue(ActionHeader):
398
    """Action structure for OFPAT_SET_QUEUE."""
399
400 1
    queue_id = UBInt32()
401
402 1
    _allowed_types = ActionType.OFPAT_SET_QUEUE,
403
404 1
    def __init__(self, queue_id=None):
405
        """Create an ActionSetQueue with the optional parameters below.
406
407
        Args:
408
            queue_id (int): The queue_id send packets to given queue on port.
409
        """
410
        super().__init__(action_type=ActionType.OFPAT_SET_QUEUE, length=8)
411
        self.queue_id = queue_id
412
413
414 1
class ListOfActions(FixedTypeList):
415
    """List of actions.
416
417
    Represented by instances of ActionHeader and used on ActionHeader objects.
418
    """
419
420 1
    def __init__(self, items=None):
421
        """Create a ListOfActions with the optional parameters below.
422
423
        Args:
424
            items (~pyof.v0x04.common.action.ActionHeader):
425
                Instance or a list of instances.
426
        """
427
        super().__init__(pyof_class=ActionHeader, items=items)
428