1 | """Defines actions that may be associated with flows packets.""" |
||
2 | |||
3 | # System imports |
||
4 | |||
5 | # Local source tree imports |
||
6 | 1 | from pyof.foundation.base import GenericBitMask, GenericStruct |
|
7 | 1 | from pyof.foundation.basic_types import ( |
|
8 | FixedTypeList, HWAddress, Pad, UBInt8, UBInt16, UBInt32) |
||
9 | 1 | from pyof.foundation.constants import UBINT16_MAX_VALUE |
|
10 | |||
11 | # Third-party imports |
||
12 | |||
13 | 1 | __all__ = ('ActionType', 'ActionHeader', 'ActionOutput', 'ActionStripVlan', |
|
14 | 'ActionEnqueue', 'ActionVlanVid', 'ActionVlanPCP', 'ActionDLAddr', |
||
15 | 'ActionNWAddr', 'ActionNWTos', 'ActionTPPort', 'ActionVendorHeader', |
||
16 | 'ListOfActions') |
||
17 | |||
18 | # Enums |
||
19 | |||
20 | |||
21 | 1 | class ActionType(GenericBitMask): |
|
22 | """Actions associated with flows and packets.""" |
||
23 | |||
24 | #: Output to switch port. |
||
25 | 1 | OFPAT_OUTPUT = 0 |
|
26 | #: Set the 802.1q VLAN id. |
||
27 | 1 | OFPAT_SET_VLAN_VID = 1 |
|
28 | #: Set the 802.1q priority. |
||
29 | 1 | OFPAT_SET_VLAN_PCP = 2 |
|
30 | #: Strip the 802.1q header. |
||
31 | 1 | OFPAT_STRIP_VLAN = 3 |
|
32 | #: Ethernet source address. |
||
33 | 1 | OFPAT_SET_DL_SRC = 4 |
|
34 | #: Ethernet destination address. |
||
35 | 1 | OFPAT_SET_DL_DST = 5 |
|
36 | #: IP source address. |
||
37 | 1 | OFPAT_SET_NW_SRC = 6 |
|
38 | #: IP destination address. |
||
39 | 1 | OFPAT_SET_NW_DST = 7 |
|
40 | #: IP ToS (DSCP field, 6 bits). |
||
41 | 1 | OFPAT_SET_NW_TOS = 8 |
|
42 | #: TCP/UDP source port. |
||
43 | 1 | OFPAT_SET_TP_SRC = 9 |
|
44 | #: TCP/UDP destination port. |
||
45 | 1 | OFPAT_SET_TP_DST = 10 |
|
46 | #: Output to queue. |
||
47 | 1 | OFPAT_ENQUEUE = 11 |
|
48 | #: Vendor specific. |
||
49 | 1 | OFPAT_VENDOR = 0xffff |
|
50 | |||
51 | |||
52 | # Classes |
||
53 | |||
54 | |||
55 | 1 | class ActionHeader(GenericStruct): |
|
56 | """Defines the Header that is common to all actions.""" |
||
57 | |||
58 | 1 | action_type = UBInt16(enum_ref=ActionType) |
|
59 | 1 | length = UBInt16() |
|
60 | # Pad for 64-bit alignment. |
||
61 | # This attribute will not be implemented since not all subclasses from |
||
62 | # this class will hold it on the same place and with the same size. |
||
63 | # pad = Pad(4) |
||
64 | |||
65 | 1 | _allowed_types = () |
|
66 | |||
67 | 1 | def __init__(self, action_type=None, length=None): |
|
68 | """Create an ActionHeader with the optional parameters below. |
||
69 | |||
70 | Args: |
||
71 | action_type (~pyof.v0x01.common.action.ActionType): |
||
72 | The type of the action. |
||
73 | length (int): Length of action, including this header. |
||
74 | """ |
||
75 | 1 | super().__init__() |
|
76 | 1 | self.action_type = action_type |
|
77 | 1 | self.length = length |
|
78 | |||
79 | 1 | View Code Duplication | def unpack(self, buff, offset=0): |
0 ignored issues
–
show
Duplication
introduced
by
![]() |
|||
80 | """Unpack a binary message into this object's attributes. |
||
81 | |||
82 | Unpack the binary value *buff* and update this object attributes based |
||
83 | on the results. |
||
84 | |||
85 | Args: |
||
86 | buff (bytes): Binary data package to be unpacked. |
||
87 | offset (int): Where to begin unpacking. |
||
88 | |||
89 | Raises: |
||
90 | Exception: If there is a struct unpacking error. |
||
91 | |||
92 | """ |
||
93 | 1 | self.action_type = UBInt16(enum_ref=ActionType) |
|
94 | 1 | self.action_type.unpack(buff, offset) |
|
95 | |||
96 | 1 | for cls in ActionHeader.__subclasses__(): |
|
97 | 1 | if self.action_type.value in cls.get_allowed_types(): |
|
98 | 1 | self.__class__ = cls |
|
99 | 1 | break |
|
100 | |||
101 | 1 | super().unpack(buff, offset) |
|
102 | |||
103 | 1 | @classmethod |
|
104 | def get_allowed_types(cls): |
||
105 | """Return allowed types for the class.""" |
||
106 | 1 | return cls._allowed_types |
|
107 | |||
108 | |||
109 | 1 | class ActionOutput(ActionHeader): |
|
110 | """Defines the actions output. |
||
111 | |||
112 | Action structure for :attr:`ActionType.OFPAT_OUTPUT`, which sends packets |
||
113 | out :attr:`port`. When the :attr:`port` is the |
||
114 | :attr:`.Port.OFPP_CONTROLLER`, :attr:`max_length` indicates the max number |
||
115 | of bytes to send. A :attr:`max_length` of zero means no bytes of the packet |
||
116 | should be sent. |
||
117 | """ |
||
118 | |||
119 | 1 | port = UBInt16() |
|
120 | 1 | max_length = UBInt16() |
|
121 | |||
122 | 1 | _allowed_types = (ActionType.OFPAT_OUTPUT,) |
|
123 | |||
124 | 1 | def __init__(self, port=None, max_length=UBINT16_MAX_VALUE): |
|
125 | """Create an ActionOutput with the optional parameters below. |
||
126 | |||
127 | Args: |
||
128 | port (:class:`~pyof.v0x01.common.phy_port.Port` or :class:`int`): |
||
129 | Output port. |
||
130 | max_length (int): Max length to send to controller. |
||
131 | """ |
||
132 | 1 | super().__init__(action_type=ActionType.OFPAT_OUTPUT, length=8) |
|
133 | 1 | self.port = port |
|
134 | 1 | self.max_length = max_length |
|
135 | |||
136 | |||
137 | 1 | class ActionStripVlan(ActionHeader): |
|
138 | """Strips VLAN information from packets. |
||
139 | |||
140 | Action defined for switches to remove the 802.1q VLAN information from |
||
141 | packets. |
||
142 | """ |
||
143 | |||
144 | 1 | pad = Pad(4) |
|
145 | |||
146 | 1 | _allowed_types = (ActionType.OFPAT_STRIP_VLAN,) |
|
147 | |||
148 | 1 | def __init__(self): |
|
149 | """Construct the ActionHeader with the appropriate ActionType. |
||
150 | |||
151 | No parameters need to be specified. |
||
152 | """ |
||
153 | super().__init__(action_type=ActionType.OFPAT_STRIP_VLAN, length=8) |
||
154 | |||
155 | |||
156 | 1 | class ActionEnqueue(ActionHeader): |
|
157 | """Send packets to a queue's port. |
||
158 | |||
159 | A switch may support only queues that are tied to specific PCP/TOS bits. |
||
160 | In that case, we cannot map an arbitrary flow to a specific queue, |
||
161 | therefore the action ENQUEUE is not supported. The user can still use |
||
162 | these queues and map flows to them by setting the relevant fields |
||
163 | (TOS, VLAN PCP). |
||
164 | """ |
||
165 | |||
166 | 1 | port = UBInt16() |
|
167 | #: Pad for 64-bit alignment. |
||
168 | 1 | pad = Pad(6) |
|
169 | 1 | queue_id = UBInt32() |
|
170 | |||
171 | 1 | _allowed_types = (ActionType.OFPAT_ENQUEUE,) |
|
172 | |||
173 | 1 | def __init__(self, port=None, queue_id=None): |
|
174 | """Create an ActionEnqueue with the optional parameters below. |
||
175 | |||
176 | Args: |
||
177 | port (physical port or :attr:`.Port.OFPP_IN_PORT`): Queue's port. |
||
178 | queue_id (int): Where to enqueue the packets. |
||
179 | """ |
||
180 | 1 | super().__init__(action_type=ActionType.OFPAT_ENQUEUE, length=16) |
|
181 | 1 | self.port = port |
|
182 | 1 | self.queue_id = queue_id |
|
183 | |||
184 | |||
185 | 1 | class ActionVlanVid(ActionHeader): |
|
186 | """Action structure for :attr:`ActionType.OFPAT_SET_VLAN_VID`. |
||
187 | |||
188 | .. note:: The vlan_vid field is 16 bits long, |
||
189 | when an actual VLAN id is only 12 bits. |
||
190 | The value 0xffff is used to indicate that no VLAN id was set |
||
191 | """ |
||
192 | |||
193 | 1 | vlan_id = UBInt16() |
|
194 | #: Pad for bit alignment. |
||
195 | 1 | pad2 = Pad(2) |
|
196 | |||
197 | 1 | _allowed_types = (ActionType.OFPAT_SET_VLAN_VID,) |
|
198 | |||
199 | 1 | def __init__(self, vlan_id=None): |
|
200 | """Create an ActionVlanVid with the optional parameters below. |
||
201 | |||
202 | Args: |
||
203 | vlan_id (int): VLAN priority. |
||
204 | """ |
||
205 | 1 | super().__init__(action_type=ActionType.OFPAT_SET_VLAN_VID, length=8) |
|
206 | 1 | self.vlan_id = vlan_id |
|
207 | |||
208 | |||
209 | 1 | class ActionVlanPCP(ActionHeader): |
|
210 | """Action structure for :attr:`ActionType.OFPAT_SET_VLAN_PCP`.""" |
||
211 | |||
212 | 1 | vlan_pcp = UBInt8() |
|
213 | #: Pad for bit alignment. |
||
214 | 1 | pad = Pad(3) |
|
215 | |||
216 | 1 | _allowed_types = (ActionType.OFPAT_SET_VLAN_PCP,) |
|
217 | |||
218 | 1 | def __init__(self, vlan_pcp=None): |
|
219 | """Create an ActionVlanPCP with the optional parameters below. |
||
220 | |||
221 | Args: |
||
222 | vlan_pcp (int): VLAN Priority. |
||
223 | |||
224 | .. note:: The vlan_pcp field is 8 bits long, |
||
225 | but only the lower 3 bits have meaning. |
||
226 | """ |
||
227 | 1 | super().__init__(action_type=ActionType.OFPAT_SET_VLAN_PCP, length=8) |
|
228 | 1 | self.vlan_pcp = vlan_pcp |
|
229 | |||
230 | |||
231 | 1 | class ActionDLAddr(ActionHeader): |
|
232 | """Action structure for :attr:`ActionType.OFPAT_SET_DL_SRC` or _DST.""" |
||
233 | |||
234 | 1 | dl_addr = HWAddress() |
|
235 | #: Pad for bit alignment. |
||
236 | 1 | pad = Pad(6) |
|
237 | |||
238 | 1 | _allowed_types = (ActionType.OFPAT_SET_DL_SRC, ActionType.OFPAT_SET_DL_DST) |
|
239 | |||
240 | 1 | def __init__(self, action_type=None, dl_addr=None): |
|
241 | """Create an ActionDLAddr with the optional parameters below. |
||
242 | |||
243 | Args: |
||
244 | action_type (:class:`~pyof.v0x01.common.action.ActionType`): |
||
245 | :attr:`~ActionType.OFPAT_SET_DL_SRC` or |
||
246 | :attr:`~ActionType.OFPAT_SET_DL_DST`. |
||
247 | dl_addr (:class:`~.HWAddress`): Ethernet address. |
||
248 | Defaults to None. |
||
249 | """ |
||
250 | 1 | super().__init__(action_type, length=16) |
|
251 | 1 | self.dl_addr = dl_addr |
|
252 | |||
253 | |||
254 | 1 | class ActionNWAddr(ActionHeader): |
|
255 | """Action structure for :attr:`ActionType.OFPAT_SET_NW_SRC` or _DST.""" |
||
256 | |||
257 | 1 | nw_addr = UBInt32() |
|
258 | |||
259 | 1 | _allowed_types = (ActionType.OFPAT_SET_NW_SRC, ActionType.OFPAT_SET_NW_DST) |
|
260 | |||
261 | 1 | def __init__(self, action_type=None, nw_addr=None): |
|
262 | """Create an ActionNWAddr with the optional parameters below. |
||
263 | |||
264 | Args: |
||
265 | action_type (:class:`~pyof.v0x01.common.action.ActionType`): |
||
266 | :attr:`~ActionType.OFPAT_SET_NW_SRC` or |
||
267 | :attr:`~ActionType.OFPAT_SET_NW_DST`. |
||
268 | nw_addr (int): IP Address. |
||
269 | """ |
||
270 | 1 | super().__init__(action_type, length=8) |
|
271 | 1 | self.nw_addr = nw_addr |
|
272 | |||
273 | |||
274 | 1 | class ActionNWTos(ActionHeader): |
|
275 | """Action structure for :attr:`ActionType.OFPAT_SET_NW_TOS`. |
||
276 | |||
277 | .. note:: The nw_tos field is the 6 upper bits of the ToS field to set, |
||
278 | in the original bit positions (shifted to the left by 2). |
||
279 | """ |
||
280 | |||
281 | 1 | nw_tos = UBInt8() |
|
282 | #: Pad for bit alignment. |
||
283 | 1 | pad = Pad(3) |
|
284 | |||
285 | 1 | _allowed_types = (ActionType.OFPAT_SET_NW_TOS,) |
|
286 | |||
287 | 1 | def __init__(self, action_type=None, nw_tos=None): |
|
288 | """Create an ActionNWTos with the optional parameters below. |
||
289 | |||
290 | Args: |
||
291 | action_type (:class:`~pyof.v0x01.common.action.ActionType`): |
||
292 | :attr:`~ActionType.OFPAT_SET_NW_SRC` or |
||
293 | :attr:`~ActionType.OFPAT_SET_NW_DST`. |
||
294 | nw_tos (int): IP ToS (DSCP field, 6 bits). |
||
295 | """ |
||
296 | 1 | super().__init__(action_type, length=8) |
|
297 | 1 | self.nw_tos = nw_tos |
|
298 | |||
299 | |||
300 | 1 | class ActionTPPort(ActionHeader): |
|
301 | """Action structure for :attr:`ActionType.OFPAT_SET_TP_SRC` or _DST.""" |
||
302 | |||
303 | 1 | tp_port = UBInt16() |
|
304 | #: Pad for bit alignment. |
||
305 | 1 | pad = Pad(2) |
|
306 | |||
307 | 1 | _allowed_types = (ActionType.OFPAT_SET_TP_SRC, ActionType.OFPAT_SET_TP_DST) |
|
308 | |||
309 | 1 | def __init__(self, action_type=None, tp_port=None): |
|
310 | """Create an ActionTPPort with the optional parameters below. |
||
311 | |||
312 | Args: |
||
313 | action_type (:class:`~pyof.v0x01.common.action.ActionType`): |
||
314 | :attr:`~ActionType.OFPAT_SET_TP_SRC` or |
||
315 | :attr:`~ActionType.OFPAT_SET_TP_DST`. |
||
316 | tp_port (int): TCP/UDP/other port to set. |
||
317 | """ |
||
318 | 1 | super().__init__(action_type, length=8) |
|
319 | 1 | self.tp_port = tp_port |
|
320 | |||
321 | |||
322 | 1 | class ActionVendorHeader(ActionHeader): |
|
323 | """Action header for :attr:`ActionType.OFPAT_VENDOR`. |
||
324 | |||
325 | The rest of the body is vendor-defined. |
||
326 | """ |
||
327 | |||
328 | 1 | vendor = UBInt32() |
|
329 | |||
330 | 1 | _allowed_types = (ActionType.OFPAT_VENDOR,) |
|
331 | |||
332 | 1 | def __init__(self, length=None, vendor=None): |
|
333 | """Create an ActionVendorHeader with the optional parameters below. |
||
334 | |||
335 | Args: |
||
336 | length (int): Length is a multiple of 8. |
||
337 | vender (int): Vendor ID with the same form as in VendorHeader. |
||
338 | Defaults to None. |
||
339 | """ |
||
340 | 1 | super().__init__(action_type=ActionType.OFPAT_VENDOR, length=length) |
|
341 | 1 | self.vendor = vendor |
|
342 | |||
343 | |||
344 | 1 | class ListOfActions(FixedTypeList): |
|
345 | """List of actions. |
||
346 | |||
347 | Represented by instances of ActionHeader and used on ActionHeader objects. |
||
348 | """ |
||
349 | |||
350 | 1 | def __init__(self, items=None): |
|
351 | """Create a ListOfActions with the optional parameters below. |
||
352 | |||
353 | Args: |
||
354 | items (:class:`~pyof.v0x01.common.action.ActionHeader`): |
||
355 | Instance or a list of instances. |
||
356 | """ |
||
357 | super().__init__(pyof_class=ActionHeader, items=items) |
||
358 |