backing up
[vsorcdistro/.git] / ryu / build / lib.linux-armv7l-2.7 / ryu / ofproto / ofproto_v1_4_parser.py
1 # Copyright (C) 2012, 2013, 2014 Nippon Telegraph and Telephone Corporation.
2 # Copyright (C) 2012, 2013 Isaku Yamahata <yamahata at valinux co jp>
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 #    http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13 # implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 """
18 Decoder/Encoder implementations of OpenFlow 1.4.
19 """
20
21 import struct
22 import base64
23
24 import six
25
26 from ryu.lib import addrconv
27 from ryu.lib.pack_utils import msg_pack_into
28 from ryu.lib.packet import packet
29 from ryu import utils
30 from ryu.ofproto.ofproto_parser import StringifyMixin, MsgBase, MsgInMsgBase
31 from ryu.ofproto import ether
32 from ryu.ofproto import nx_actions
33 from ryu.ofproto import ofproto_parser
34 from ryu.ofproto import ofproto_common
35 from ryu.ofproto import ofproto_v1_4 as ofproto
36
37 _MSG_PARSERS = {}
38
39
40 def _set_msg_type(msg_type):
41     def _set_cls_msg_type(cls):
42         cls.cls_msg_type = msg_type
43         return cls
44     return _set_cls_msg_type
45
46
47 def _register_parser(cls):
48     '''class decorator to register msg parser'''
49     assert cls.cls_msg_type is not None
50     assert cls.cls_msg_type not in _MSG_PARSERS
51     _MSG_PARSERS[cls.cls_msg_type] = cls.parser
52     return cls
53
54
55 @ofproto_parser.register_msg_parser(ofproto.OFP_VERSION)
56 def msg_parser(datapath, version, msg_type, msg_len, xid, buf):
57     parser = _MSG_PARSERS.get(msg_type)
58     return parser(datapath, version, msg_type, msg_len, xid, buf)
59
60
61 @_register_parser
62 @_set_msg_type(ofproto.OFPT_HELLO)
63 class OFPHello(MsgBase):
64     """
65     Hello message
66
67     When connection is started, the hello message is exchanged between a
68     switch and a controller.
69
70     This message is handled by the Ryu framework, so the Ryu application
71     do not need to process this typically.
72
73     ========== =========================================================
74     Attribute  Description
75     ========== =========================================================
76     elements   list of ``OFPHelloElemVersionBitmap`` instance
77     ========== =========================================================
78     """
79
80     def __init__(self, datapath, elements=None):
81         elements = elements if elements else []
82         super(OFPHello, self).__init__(datapath)
83         self.elements = elements
84
85     @classmethod
86     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
87         msg = super(OFPHello, cls).parser(datapath, version, msg_type,
88                                           msg_len, xid, buf)
89
90         offset = ofproto.OFP_HELLO_HEADER_SIZE
91         elems = []
92         while offset < msg.msg_len:
93             type_, length = struct.unpack_from(
94                 ofproto.OFP_HELLO_ELEM_HEADER_PACK_STR, msg.buf, offset)
95
96             # better to register Hello Element classes but currently
97             # Only VerisonBitmap is supported so let's be simple.
98
99             if type_ == ofproto.OFPHET_VERSIONBITMAP:
100                 elem = OFPHelloElemVersionBitmap.parser(msg.buf, offset)
101                 elems.append(elem)
102
103             offset += length
104         msg.elements = elems
105         return msg
106
107
108 class OFPHelloElemVersionBitmap(StringifyMixin):
109     """
110     Version bitmap Hello Element
111
112     ========== =========================================================
113     Attribute  Description
114     ========== =========================================================
115     versions   list of versions of OpenFlow protocol a device supports
116     ========== =========================================================
117     """
118
119     def __init__(self, versions, type_=None, length=None):
120         super(OFPHelloElemVersionBitmap, self).__init__()
121         self.type = ofproto.OFPHET_VERSIONBITMAP
122         self.length = None
123         self._bitmaps = None
124         self.versions = versions
125
126     @classmethod
127     def parser(cls, buf, offset):
128         type_, length = struct.unpack_from(
129             ofproto.OFP_HELLO_ELEM_VERSIONBITMAP_HEADER_PACK_STR,
130             buf, offset)
131         assert type_ == ofproto.OFPHET_VERSIONBITMAP
132
133         bitmaps_len = (length -
134                        ofproto.OFP_HELLO_ELEM_VERSIONBITMAP_HEADER_SIZE)
135         offset += ofproto.OFP_HELLO_ELEM_VERSIONBITMAP_HEADER_SIZE
136         bitmaps = []
137         while bitmaps_len >= 4:
138             bitmap = struct.unpack_from('!I', buf, offset)
139             bitmaps.append(bitmap[0])
140             offset += 4
141             bitmaps_len -= 4
142
143         versions = [i * 32 + shift
144                     for i, bitmap in enumerate(bitmaps)
145                     for shift in range(31) if bitmap & (1 << shift)]
146         elem = cls(versions)
147         elem.length = length
148         elem._bitmaps = bitmaps
149         return elem
150
151
152 @_register_parser
153 @_set_msg_type(ofproto.OFPT_ECHO_REQUEST)
154 class OFPEchoRequest(MsgBase):
155     """
156     Echo request message
157
158     This message is handled by the Ryu framework, so the Ryu application
159     do not need to process this typically.
160
161     ========== =========================================================
162     Attribute  Description
163     ========== =========================================================
164     data       An arbitrary length data
165     ========== =========================================================
166
167     Example::
168
169         def send_echo_request(self, datapath, data):
170             ofp = datapath.ofproto
171             ofp_parser = datapath.ofproto_parser
172
173             req = ofp_parser.OFPEchoRequest(datapath, data)
174             datapath.send_msg(req)
175
176         @set_ev_cls(ofp_event.EventOFPEchoRequest,
177                     [HANDSHAKE_DISPATCHER, CONFIG_DISPATCHER, MAIN_DISPATCHER])
178         def echo_request_handler(self, ev):
179             self.logger.debug('OFPEchoRequest received: data=%s',
180                               utils.hex_array(ev.msg.data))
181     """
182
183     def __init__(self, datapath, data=None):
184         super(OFPEchoRequest, self).__init__(datapath)
185         self.data = data
186
187     @classmethod
188     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
189         msg = super(OFPEchoRequest, cls).parser(datapath, version, msg_type,
190                                                 msg_len, xid, buf)
191         msg.data = msg.buf[ofproto.OFP_HEADER_SIZE:]
192         return msg
193
194     def _serialize_body(self):
195         if self.data is not None:
196             self.buf += self.data
197
198
199 @_register_parser
200 @_set_msg_type(ofproto.OFPT_ERROR)
201 class OFPErrorMsg(MsgBase):
202     """
203     Error message
204
205     The switch notifies controller of problems by this message.
206
207     ========== =========================================================
208     Attribute  Description
209     ========== =========================================================
210     type       High level type of error
211     code       Details depending on the type
212     data       Variable length data depending on the type and code
213     ========== =========================================================
214
215     ``type`` attribute corresponds to ``type_`` parameter of __init__.
216
217     Types and codes are defined in ``ryu.ofproto.ofproto``.
218
219     ============================= ===========
220     Type                          Code
221     ============================= ===========
222     OFPET_HELLO_FAILED            OFPHFC_*
223     OFPET_BAD_REQUEST             OFPBRC_*
224     OFPET_BAD_ACTION              OFPBAC_*
225     OFPET_BAD_INSTRUCTION         OFPBIC_*
226     OFPET_BAD_MATCH               OFPBMC_*
227     OFPET_FLOW_MOD_FAILED         OFPFMFC_*
228     OFPET_GROUP_MOD_FAILED        OFPGMFC_*
229     OFPET_PORT_MOD_FAILED         OFPPMFC_*
230     OFPET_TABLE_MOD_FAILED        OFPTMFC_*
231     OFPET_QUEUE_OP_FAILED         OFPQOFC_*
232     OFPET_SWITCH_CONFIG_FAILED    OFPSCFC_*
233     OFPET_ROLE_REQUEST_FAILED     OFPRRFC_*
234     OFPET_METER_MOD_FAILED        OFPMMFC_*
235     OFPET_TABLE_FEATURES_FAILED   OFPTFFC_*
236     OFPET_EXPERIMENTER            N/A
237     ============================= ===========
238
239     If ``type == OFPET_EXPERIMENTER``, this message has also the following
240     attributes.
241
242     ============= ======================================================
243     Attribute     Description
244     ============= ======================================================
245     exp_type      Experimenter defined type
246     experimenter  Experimenter ID
247     ============= ======================================================
248
249     Example::
250
251         @set_ev_cls(ofp_event.EventOFPErrorMsg,
252                     [HANDSHAKE_DISPATCHER, CONFIG_DISPATCHER, MAIN_DISPATCHER])
253         def error_msg_handler(self, ev):
254             msg = ev.msg
255
256             self.logger.debug('OFPErrorMsg received: type=0x%02x code=0x%02x '
257                               'message=%s',
258                               msg.type, msg.code, utils.hex_array(msg.data))
259     """
260
261     def __init__(self, datapath, type_=None, code=None, data=None, **kwargs):
262         super(OFPErrorMsg, self).__init__(datapath)
263         self.type = type_
264         self.code = code
265         if isinstance(data, six.string_types):
266             data = data.encode('ascii')
267         self.data = data
268         if self.type == ofproto.OFPET_EXPERIMENTER:
269             self.exp_type = kwargs.get('exp_type', None)
270             self.experimenter = kwargs.get('experimenter', None)
271
272     @classmethod
273     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
274         type_, = struct.unpack_from('!H', six.binary_type(buf),
275                                     ofproto.OFP_HEADER_SIZE)
276         msg = super(OFPErrorMsg, cls).parser(datapath, version, msg_type,
277                                              msg_len, xid, buf)
278         if type_ == ofproto.OFPET_EXPERIMENTER:
279             (msg.type, msg.exp_type, msg.experimenter,
280              msg.data) = cls.parse_experimenter_body(buf)
281         else:
282             (msg.type, msg.code,
283              msg.data) = cls.parse_body(buf)
284         return msg
285
286     @classmethod
287     def parse_body(cls, buf):
288         type_, code = struct.unpack_from(
289             ofproto.OFP_ERROR_MSG_PACK_STR, buf,
290             ofproto.OFP_HEADER_SIZE)
291         data = buf[ofproto.OFP_ERROR_MSG_SIZE:]
292         return type_, code, data
293
294     @classmethod
295     def parse_experimenter_body(cls, buf):
296         type_, exp_type, experimenter = struct.unpack_from(
297             ofproto.OFP_ERROR_EXPERIMENTER_MSG_PACK_STR, buf,
298             ofproto.OFP_HEADER_SIZE)
299         data = buf[ofproto.OFP_ERROR_EXPERIMENTER_MSG_SIZE:]
300         return type_, exp_type, experimenter, data
301
302     def _serialize_body(self):
303         assert self.data is not None
304         if self.type == ofproto.OFPET_EXPERIMENTER:
305             msg_pack_into(ofproto.OFP_ERROR_EXPERIMENTER_MSG_PACK_STR,
306                           self.buf, ofproto.OFP_HEADER_SIZE,
307                           self.type, self.exp_type, self.experimenter)
308             self.buf += self.data
309         else:
310             msg_pack_into(ofproto.OFP_ERROR_MSG_PACK_STR,
311                           self.buf, ofproto.OFP_HEADER_SIZE,
312                           self.type, self.code)
313             self.buf += self.data
314
315
316 # For the backward compatibility
317 def OFPErrorExperimenterMsg(datapath, type_=None, exp_type=None,
318                             experimenter=None, data=None):
319     msg = OFPErrorMsg(datapath, data=data)
320     msg.type = ofproto.OFPET_EXPERIMENTER
321     msg.exp_type = exp_type
322     msg.experimenter = experimenter
323     return msg
324
325
326 @_register_parser
327 @_set_msg_type(ofproto.OFPT_ECHO_REPLY)
328 class OFPEchoReply(MsgBase):
329     """
330     Echo reply message
331
332     This message is handled by the Ryu framework, so the Ryu application
333     do not need to process this typically.
334
335     ========== =========================================================
336     Attribute  Description
337     ========== =========================================================
338     data       An arbitrary length data
339     ========== =========================================================
340
341     Example::
342
343         def send_echo_reply(self, datapath, data):
344             ofp_parser = datapath.ofproto_parser
345
346             reply = ofp_parser.OFPEchoReply(datapath, data)
347             datapath.send_msg(reply)
348
349         @set_ev_cls(ofp_event.EventOFPEchoReply,
350                     [HANDSHAKE_DISPATCHER, CONFIG_DISPATCHER, MAIN_DISPATCHER])
351         def echo_reply_handler(self, ev):
352             self.logger.debug('OFPEchoReply received: data=%s',
353                               utils.hex_array(ev.msg.data))
354     """
355
356     def __init__(self, datapath, data=None):
357         super(OFPEchoReply, self).__init__(datapath)
358         self.data = data
359
360     @classmethod
361     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
362         msg = super(OFPEchoReply, cls).parser(datapath, version, msg_type,
363                                               msg_len, xid, buf)
364         msg.data = msg.buf[ofproto.OFP_HEADER_SIZE:]
365         return msg
366
367     def _serialize_body(self):
368         assert self.data is not None
369         self.buf += self.data
370
371
372 @_set_msg_type(ofproto.OFPT_FEATURES_REQUEST)
373 class OFPFeaturesRequest(MsgBase):
374     """
375     Features request message
376
377     The controller sends a feature request to the switch upon session
378     establishment.
379
380     This message is handled by the Ryu framework, so the Ryu application
381     do not need to process this typically.
382
383     Example::
384
385         def send_features_request(self, datapath):
386             ofp_parser = datapath.ofproto_parser
387
388             req = ofp_parser.OFPFeaturesRequest(datapath)
389             datapath.send_msg(req)
390     """
391
392     def __init__(self, datapath):
393         super(OFPFeaturesRequest, self).__init__(datapath)
394
395
396 @_register_parser
397 @_set_msg_type(ofproto.OFPT_EXPERIMENTER)
398 class OFPExperimenter(MsgBase):
399     """
400     Experimenter extension message
401
402     ============= =========================================================
403     Attribute     Description
404     ============= =========================================================
405     experimenter  Experimenter ID
406     exp_type      Experimenter defined
407     data          Experimenter defined arbitrary additional data
408     ============= =========================================================
409     """
410
411     def __init__(self, datapath, experimenter=None, exp_type=None, data=None):
412         super(OFPExperimenter, self).__init__(datapath)
413         self.experimenter = experimenter
414         self.exp_type = exp_type
415         self.data = data
416
417     @classmethod
418     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
419         msg = super(OFPExperimenter, cls).parser(datapath, version,
420                                                  msg_type, msg_len,
421                                                  xid, buf)
422         (msg.experimenter, msg.exp_type) = struct.unpack_from(
423             ofproto.OFP_EXPERIMENTER_HEADER_PACK_STR, msg.buf,
424             ofproto.OFP_HEADER_SIZE)
425         msg.data = msg.buf[ofproto.OFP_EXPERIMENTER_HEADER_SIZE:]
426
427         return msg
428
429     def _serialize_body(self):
430         assert self.data is not None
431         msg_pack_into(ofproto.OFP_EXPERIMENTER_HEADER_PACK_STR,
432                       self.buf, ofproto.OFP_HEADER_SIZE,
433                       self.experimenter, self.exp_type)
434         self.buf += self.data
435
436
437 @_register_parser
438 @_set_msg_type(ofproto.OFPT_FEATURES_REPLY)
439 class OFPSwitchFeatures(MsgBase):
440     """
441     Features reply message
442
443     The switch responds with a features reply message to a features
444     request.
445
446     This message is handled by the Ryu framework, so the Ryu application
447     do not need to process this typically.
448
449     Example::
450
451         @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
452         def switch_features_handler(self, ev):
453             msg = ev.msg
454
455             self.logger.debug('OFPSwitchFeatures received: '
456                               'datapath_id=0x%016x n_buffers=%d '
457                               'n_tables=%d auxiliary_id=%d '
458                               'capabilities=0x%08x',
459                               msg.datapath_id, msg.n_buffers, msg.n_tables,
460                               msg.auxiliary_id, msg.capabilities)
461     """
462
463     def __init__(self, datapath, datapath_id=None, n_buffers=None,
464                  n_tables=None, auxiliary_id=None, capabilities=None):
465         super(OFPSwitchFeatures, self).__init__(datapath)
466         self.datapath_id = datapath_id
467         self.n_buffers = n_buffers
468         self.n_tables = n_tables
469         self.auxiliary_id = auxiliary_id
470         self.capabilities = capabilities
471
472     @classmethod
473     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
474         msg = super(OFPSwitchFeatures, cls).parser(datapath, version, msg_type,
475                                                    msg_len, xid, buf)
476         (msg.datapath_id,
477          msg.n_buffers,
478          msg.n_tables,
479          msg.auxiliary_id,
480          msg.capabilities,
481          msg._reserved) = struct.unpack_from(
482             ofproto.OFP_SWITCH_FEATURES_PACK_STR, msg.buf,
483             ofproto.OFP_HEADER_SIZE)
484         return msg
485
486
487 @_set_msg_type(ofproto.OFPT_GET_CONFIG_REQUEST)
488 class OFPGetConfigRequest(MsgBase):
489     """
490     Get config request message
491
492     The controller sends a get config request to query configuration
493     parameters in the switch.
494
495     Example::
496
497         def send_get_config_request(self, datapath):
498             ofp_parser = datapath.ofproto_parser
499
500             req = ofp_parser.OFPGetConfigRequest(datapath)
501             datapath.send_msg(req)
502     """
503
504     def __init__(self, datapath):
505         super(OFPGetConfigRequest, self).__init__(datapath)
506
507
508 @_register_parser
509 @_set_msg_type(ofproto.OFPT_GET_CONFIG_REPLY)
510 class OFPGetConfigReply(MsgBase):
511     """
512     Get config reply message
513
514     The switch responds to a configuration request with a get config reply
515     message.
516
517     ============= =========================================================
518     Attribute     Description
519     ============= =========================================================
520     flags         Bitmap of the following flags.
521
522                   | OFPC_FRAG_NORMAL
523                   | OFPC_FRAG_DROP
524                   | OFPC_FRAG_REASM
525     miss_send_len Max bytes of new flow that datapath should send to the
526                   controller
527     ============= =========================================================
528
529     Example::
530
531         @set_ev_cls(ofp_event.EventOFPGetConfigReply, MAIN_DISPATCHER)
532         def get_config_reply_handler(self, ev):
533             msg = ev.msg
534             dp = msg.datapath
535             ofp = dp.ofproto
536             flags = []
537
538             if msg.flags & ofp.OFPC_FRAG_NORMAL:
539                 flags.append('NORMAL')
540             if msg.flags & ofp.OFPC_FRAG_DROP:
541                 flags.append('DROP')
542             if msg.flags & ofp.OFPC_FRAG_REASM:
543                 flags.append('REASM')
544             self.logger.debug('OFPGetConfigReply received: '
545                               'flags=%s miss_send_len=%d',
546                               ','.join(flags), msg.miss_send_len)
547     """
548
549     def __init__(self, datapath, flags=None, miss_send_len=None):
550         super(OFPGetConfigReply, self).__init__(datapath)
551         self.flags = flags
552         self.miss_send_len = miss_send_len
553
554     @classmethod
555     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
556         msg = super(OFPGetConfigReply, cls).parser(datapath, version, msg_type,
557                                                    msg_len, xid, buf)
558         msg.flags, msg.miss_send_len = struct.unpack_from(
559             ofproto.OFP_SWITCH_CONFIG_PACK_STR, msg.buf,
560             ofproto.OFP_HEADER_SIZE)
561         return msg
562
563
564 @_set_msg_type(ofproto.OFPT_SET_CONFIG)
565 class OFPSetConfig(MsgBase):
566     """
567     Set config request message
568
569     The controller sends a set config request message to set configuraion
570     parameters.
571
572     ============= =========================================================
573     Attribute     Description
574     ============= =========================================================
575     flags         Bitmap of the following flags.
576
577                   | OFPC_FRAG_NORMAL
578                   | OFPC_FRAG_DROP
579                   | OFPC_FRAG_REASM
580     miss_send_len Max bytes of new flow that datapath should send to the
581                   controller
582     ============= =========================================================
583
584     Example::
585
586         def send_set_config(self, datapath):
587             ofp = datapath.ofproto
588             ofp_parser = datapath.ofproto_parser
589
590             req = ofp_parser.OFPSetConfig(datapath, ofp.OFPC_FRAG_NORMAL, 256)
591             datapath.send_msg(req)
592     """
593
594     def __init__(self, datapath, flags=0, miss_send_len=0):
595         super(OFPSetConfig, self).__init__(datapath)
596         self.flags = flags
597         self.miss_send_len = miss_send_len
598
599     def _serialize_body(self):
600         assert self.flags is not None
601         assert self.miss_send_len is not None
602         msg_pack_into(ofproto.OFP_SWITCH_CONFIG_PACK_STR,
603                       self.buf, ofproto.OFP_HEADER_SIZE,
604                       self.flags, self.miss_send_len)
605
606
607 class OFPMatch(StringifyMixin):
608     """
609     Flow Match Structure
610
611     This class is implementation of the flow match structure having
612     compose/query API.
613
614     You can define the flow match by the keyword arguments.
615     The following arguments are available.
616
617     ================ =============== ==================================
618     Argument         Value           Description
619     ================ =============== ==================================
620     in_port          Integer 32bit   Switch input port
621     in_phy_port      Integer 32bit   Switch physical input port
622     metadata         Integer 64bit   Metadata passed between tables
623     eth_dst          MAC address     Ethernet destination address
624     eth_src          MAC address     Ethernet source address
625     eth_type         Integer 16bit   Ethernet frame type
626     vlan_vid         Integer 16bit   VLAN id
627     vlan_pcp         Integer 8bit    VLAN priority
628     ip_dscp          Integer 8bit    IP DSCP (6 bits in ToS field)
629     ip_ecn           Integer 8bit    IP ECN (2 bits in ToS field)
630     ip_proto         Integer 8bit    IP protocol
631     ipv4_src         IPv4 address    IPv4 source address
632     ipv4_dst         IPv4 address    IPv4 destination address
633     tcp_src          Integer 16bit   TCP source port
634     tcp_dst          Integer 16bit   TCP destination port
635     udp_src          Integer 16bit   UDP source port
636     udp_dst          Integer 16bit   UDP destination port
637     sctp_src         Integer 16bit   SCTP source port
638     sctp_dst         Integer 16bit   SCTP destination port
639     icmpv4_type      Integer 8bit    ICMP type
640     icmpv4_code      Integer 8bit    ICMP code
641     arp_op           Integer 16bit   ARP opcode
642     arp_spa          IPv4 address    ARP source IPv4 address
643     arp_tpa          IPv4 address    ARP target IPv4 address
644     arp_sha          MAC address     ARP source hardware address
645     arp_tha          MAC address     ARP target hardware address
646     ipv6_src         IPv6 address    IPv6 source address
647     ipv6_dst         IPv6 address    IPv6 destination address
648     ipv6_flabel      Integer 32bit   IPv6 Flow Label
649     icmpv6_type      Integer 8bit    ICMPv6 type
650     icmpv6_code      Integer 8bit    ICMPv6 code
651     ipv6_nd_target   IPv6 address    Target address for ND
652     ipv6_nd_sll      MAC address     Source link-layer for ND
653     ipv6_nd_tll      MAC address     Target link-layer for ND
654     mpls_label       Integer 32bit   MPLS label
655     mpls_tc          Integer 8bit    MPLS TC
656     mpls_bos         Integer 8bit    MPLS BoS bit
657     pbb_isid         Integer 24bit   PBB I-SID
658     tunnel_id        Integer 64bit   Logical Port Metadata
659     ipv6_exthdr      Integer 16bit   IPv6 Extension Header pseudo-field
660     pbb_uca          Integer 8bit    PBB UCA header field
661     tcp_flags        Integer 16bit   TCP flags
662                                      (EXT-109 ONF Extension)
663     actset_output    Integer 32bit   Output port from action set metadata
664                                      (EXT-233 ONF Extension)
665     ================ =============== ==================================
666
667     Example::
668
669         >>> # compose
670         >>> match = parser.OFPMatch(
671         ...     in_port=1,
672         ...     eth_type=0x86dd,
673         ...     ipv6_src=('2001:db8:bd05:1d2:288a:1fc0:1:10ee',
674         ...               'ffff:ffff:ffff:ffff::'),
675         ...     ipv6_dst='2001:db8:bd05:1d2:288a:1fc0:1:10ee')
676         >>> # query
677         >>> if 'ipv6_src' in match:
678         ...     print match['ipv6_src']
679         ...
680         ('2001:db8:bd05:1d2:288a:1fc0:1:10ee', 'ffff:ffff:ffff:ffff::')
681
682     .. Note::
683
684         For the list of the supported Nicira experimenter matches,
685         please refer to :ref:`ryu.ofproto.nx_match <nx_match_structures>`.
686
687     .. Note::
688
689         For VLAN id match field, special values are defined in OpenFlow Spec.
690
691         1) Packets with and without a VLAN tag
692
693             - Example::
694
695                 match = parser.OFPMatch()
696
697             - Packet Matching
698
699                 ====================== =====
700                 non-VLAN-tagged        MATCH
701                 VLAN-tagged(vlan_id=3) MATCH
702                 VLAN-tagged(vlan_id=5) MATCH
703                 ====================== =====
704
705         2) Only packets without a VLAN tag
706
707             - Example::
708
709                 match = parser.OFPMatch(vlan_vid=0x0000)
710
711             - Packet Matching
712
713                 ====================== =====
714                 non-VLAN-tagged        MATCH
715                 VLAN-tagged(vlan_id=3)   x
716                 VLAN-tagged(vlan_id=5)   x
717                 ====================== =====
718
719         3) Only packets with a VLAN tag regardless of its value
720
721             - Example::
722
723                 match = parser.OFPMatch(vlan_vid=(0x1000, 0x1000))
724
725             - Packet Matching
726
727                 ====================== =====
728                 non-VLAN-tagged          x
729                 VLAN-tagged(vlan_id=3) MATCH
730                 VLAN-tagged(vlan_id=5) MATCH
731                 ====================== =====
732
733         4) Only packets with VLAN tag and VID equal
734
735             - Example::
736
737                 match = parser.OFPMatch(vlan_vid=(0x1000 | 3))
738
739             - Packet Matching
740
741                 ====================== =====
742                 non-VLAN-tagged          x
743                 VLAN-tagged(vlan_id=3) MATCH
744                 VLAN-tagged(vlan_id=5)   x
745                 ====================== =====
746     """
747
748     def __init__(self, type_=None, length=None, _ordered_fields=None,
749                  **kwargs):
750         super(OFPMatch, self).__init__()
751         self.type = ofproto.OFPMT_OXM
752         self.length = length
753
754         if _ordered_fields is not None:
755             assert not kwargs
756             self._fields2 = _ordered_fields
757         else:
758             kwargs = dict(ofproto.oxm_normalize_user(k, v) for
759                           (k, v) in kwargs.items())
760             fields = [ofproto.oxm_from_user(k, v) for (k, v)
761                       in kwargs.items()]
762             # assumption: sorting by OXM type values makes fields
763             # meet ordering requirements (eg. eth_type before ipv4_src)
764             fields.sort(
765                 key=lambda x: x[0][0] if isinstance(x[0], tuple) else x[0])
766             self._fields2 = [ofproto.oxm_to_user(n, v, m) for (n, v, m)
767                              in fields]
768
769     @classmethod
770     def parser(cls, buf, offset):
771         """
772         Returns an object which is generated from a buffer including the
773         expression of the wire protocol of the flow match.
774         """
775         match = OFPMatch()
776         type_, length = struct.unpack_from('!HH', buf, offset)
777
778         match.type = type_
779         match.length = length
780
781         # ofp_match adjustment
782         offset += 4
783         length -= 4
784
785         fields = []
786         while length > 0:
787             n, value, mask, field_len = ofproto.oxm_parse(buf, offset)
788             k, uv = ofproto.oxm_to_user(n, value, mask)
789             fields.append((k, uv))
790             offset += field_len
791             length -= field_len
792         match._fields2 = fields
793         return match
794
795     def serialize(self, buf, offset):
796         """
797         Outputs the expression of the wire protocol of the flow match into
798         the buf.
799         Returns the output length.
800         """
801         fields = [ofproto.oxm_from_user(k, uv) for (k, uv)
802                   in self._fields2]
803
804         hdr_pack_str = '!HH'
805         field_offset = offset + struct.calcsize(hdr_pack_str)
806         for (n, value, mask) in fields:
807             field_offset += ofproto.oxm_serialize(n, value, mask, buf,
808                                                   field_offset)
809
810         length = field_offset - offset
811         msg_pack_into(hdr_pack_str, buf, offset, ofproto.OFPMT_OXM, length)
812         self.length = length
813
814         pad_len = utils.round_up(length, 8) - length
815         msg_pack_into("%dx" % pad_len, buf, field_offset)
816
817         return length + pad_len
818
819     def __getitem__(self, key):
820         return dict(self._fields2)[key]
821
822     def __contains__(self, key):
823         return key in dict(self._fields2)
824
825     def iteritems(self):
826         return iter(dict(self._fields2).items())
827
828     def items(self):
829         return self._fields2
830
831     def get(self, key, default=None):
832         return dict(self._fields2).get(key, default)
833
834     def stringify_attrs(self):
835         yield "oxm_fields", dict(self._fields2)
836
837     def to_jsondict(self):
838         """
839         Returns a dict expressing the flow match.
840         """
841         body = {"oxm_fields": [ofproto.oxm_to_jsondict(k, uv) for k, uv
842                                in self._fields2],
843                 "length": self.length,
844                 "type": self.type}
845         return {self.__class__.__name__: body}
846
847     @classmethod
848     def from_jsondict(cls, dict_):
849         """
850         Returns an object which is generated from a dict.
851
852         Exception raises:
853         KeyError -- Unknown match field is defined in dict
854         """
855         fields = [ofproto.oxm_from_jsondict(f) for f
856                   in dict_['oxm_fields']]
857         return OFPMatch(_ordered_fields=fields)
858
859
860 class OFPPropUnknown(StringifyMixin):
861     def __init__(self, type_=None, length=None, buf=None):
862         self.buf = buf
863
864     @classmethod
865     def parser(cls, buf):
866         return cls(buf=buf)
867
868
869 class OFPPropBase(StringifyMixin):
870     _PACK_STR = '!HH'
871     # _TYPES = {} must be an attribute of subclass
872
873     def __init__(self, type_, length=None):
874         self.type = type_
875         self.length = length
876
877     @classmethod
878     def register_type(cls, type_):
879         def _register_type(subcls):
880             cls._TYPES[type_] = subcls
881             return subcls
882         return _register_type
883
884     @classmethod
885     def parse(cls, buf):
886         (type_, length) = struct.unpack_from(cls._PACK_STR, buf, 0)
887         rest = buf[utils.round_up(length, 8):]
888         try:
889             subcls = cls._TYPES[type_]
890         except KeyError:
891             subcls = OFPPropUnknown
892         prop = subcls.parser(buf)
893         prop.type = type_
894         prop.length = length
895         return prop, rest
896
897     @classmethod
898     def get_rest(cls, buf):
899         (type_, length) = struct.unpack_from(cls._PACK_STR, buf, 0)
900         offset = struct.calcsize(cls._PACK_STR)
901         return buf[offset:length]
902
903     def serialize(self):
904         # Body
905         # serialize_body should be implemented by subclass
906         body = bytearray()
907         body += self.serialize_body()
908
909         # fixup
910         self.length = len(body) + struct.calcsize(self._PACK_STR)
911
912         # Header
913         buf = bytearray()
914         msg_pack_into(self._PACK_STR, buf, 0, self.type, self.length)
915         buf += body
916
917         # Pad
918         pad_len = utils.round_up(self.length, 8) - self.length
919         msg_pack_into("%dx" % pad_len, buf, len(buf))
920
921         return buf
922
923
924 class OFPPropCommonExperimenter4ByteData(StringifyMixin):
925     _PACK_STR = '!HHII'
926     _EXPERIMENTER_DATA_PACK_STR = '!I'
927     _EXPERIMENTER_DATA_SIZE = 4
928
929     def __init__(self, type_=None, length=None, experimenter=None,
930                  exp_type=None, data=bytearray()):
931         self.type = type_
932         self.length = length
933         self.experimenter = experimenter
934         self.exp_type = exp_type
935         self.data = data
936
937     @classmethod
938     def parser(cls, buf):
939         (type_, length, experimenter, exp_type) = struct.unpack_from(
940             ofproto.OFP_PROP_EXPERIMENTER_PACK_STR, buf, 0)
941
942         rest = buf[ofproto.OFP_PROP_EXPERIMENTER_SIZE:length]
943         data = []
944         while rest:
945             (d,) = struct.unpack_from(
946                 cls._EXPERIMENTER_DATA_PACK_STR, rest, 0)
947             data.append(d)
948             rest = rest[cls._EXPERIMENTER_DATA_SIZE:]
949
950         return cls(type_, length, experimenter, exp_type, data)
951
952     def serialize(self):
953         offset = 0
954         bin_data = bytearray()
955         for d in self.data:
956             msg_pack_into(self._EXPERIMENTER_DATA_PACK_STR,
957                           bin_data, offset, d)
958             offset += self._EXPERIMENTER_DATA_SIZE
959
960         # fixup
961         self.length = struct.calcsize(self._PACK_STR)
962         self.length += len(bin_data)
963
964         buf = bytearray()
965         msg_pack_into(self._PACK_STR, buf,
966                       0, self.type, self.length, self.experimenter,
967                       self.exp_type)
968         buf += bin_data
969
970         # Pad
971         pad_len = utils.round_up(self.length, 8) - self.length
972         msg_pack_into("%dx" % pad_len, buf, len(buf))
973
974         return buf
975
976
977 class OFPPortDescProp(OFPPropBase):
978     _TYPES = {}
979
980
981 @OFPPortDescProp.register_type(ofproto.OFPPDPT_ETHERNET)
982 class OFPPortDescPropEthernet(OFPPortDescProp):
983     def __init__(self, type_=None, length=None, curr=None, advertised=None,
984                  supported=None, peer=None, curr_speed=None, max_speed=None):
985         self.type = type_
986         self.length = length
987         self.curr = curr
988         self.advertised = advertised
989         self.supported = supported
990         self.peer = peer
991         self.curr_speed = curr_speed
992         self.max_speed = max_speed
993
994     @classmethod
995     def parser(cls, buf):
996         ether = cls()
997         (ether.type, ether.length, ether.curr,
998          ether.advertised, ether.supported,
999          ether.peer, ether.curr_speed, ether.max_speed) = struct.unpack_from(
1000             ofproto.OFP_PORT_DESC_PROP_ETHERNET_PACK_STR, buf, 0)
1001         return ether
1002
1003
1004 @OFPPortDescProp.register_type(ofproto.OFPPDPT_OPTICAL)
1005 class OFPPortDescPropOptical(OFPPortDescProp):
1006     def __init__(self, type_=None, length=None, supported=None,
1007                  tx_min_freq_lmda=None, tx_max_freq_lmda=None,
1008                  tx_grid_freq_lmda=None, rx_min_freq_lmda=None,
1009                  rx_max_freq_lmda=None, rx_grid_freq_lmda=None,
1010                  tx_pwr_min=None, tx_pwr_max=None):
1011         self.type = type_
1012         self.length = length
1013         self.supported = supported
1014         self.tx_min_freq_lmda = tx_min_freq_lmda
1015         self.tx_max_freq_lmda = tx_max_freq_lmda
1016         self.tx_grid_freq_lmda = tx_grid_freq_lmda
1017         self.rx_min_freq_lmda = rx_min_freq_lmda
1018         self.rx_max_freq_lmda = rx_max_freq_lmda
1019         self.rx_grid_freq_lmda = rx_grid_freq_lmda
1020         self.tx_pwr_min = tx_pwr_min
1021         self.tx_pwr_max = tx_pwr_max
1022
1023     @classmethod
1024     def parser(cls, buf):
1025         optical = cls()
1026         (optical.type, optical.length, optical.supported,
1027          optical.tx_min_freq_lmda, optical.tx_max_freq_lmda,
1028          optical.tx_grid_freq_lmda, optical.rx_min_freq_lmda,
1029          optical.rx_max_freq_lmda, optical.rx_grid_freq_lmda,
1030          optical.tx_pwr_min, optical.tx_pwr_max) = struct.unpack_from(
1031             ofproto.OFP_PORT_DESC_PROP_OPTICAL_PACK_STR, buf, 0)
1032         return optical
1033
1034
1035 @OFPPortDescProp.register_type(ofproto.OFPPDPT_EXPERIMENTER)
1036 class OFPPortDescPropExperimenter(OFPPropCommonExperimenter4ByteData):
1037     pass
1038
1039
1040 class OFPTableModProp(OFPPropBase):
1041     _TYPES = {}
1042
1043
1044 @OFPTableModProp.register_type(ofproto.OFPTMPT_EVICTION)
1045 class OFPTableModPropEviction(OFPTableModProp):
1046     def __init__(self, type_=None, length=None, flags=None):
1047         self.type = type_
1048         self.length = length
1049         self.flags = flags
1050
1051     @classmethod
1052     def parser(cls, buf):
1053         eviction = cls()
1054         (eviction.type, eviction.length, eviction.flags) = struct.unpack_from(
1055             ofproto.OFP_TABLE_MOD_PROP_EVICTION_PACK_STR, buf, 0)
1056         return eviction
1057
1058     def serialize(self):
1059         # fixup
1060         self.length = ofproto.OFP_TABLE_MOD_PROP_EVICTION_SIZE
1061
1062         buf = bytearray()
1063         msg_pack_into(ofproto.OFP_TABLE_MOD_PROP_EVICTION_PACK_STR, buf, 0,
1064                       self.type, self.length, self.flags)
1065         return buf
1066
1067
1068 @OFPTableModProp.register_type(ofproto.OFPTMPT_VACANCY)
1069 class OFPTableModPropVacancy(OFPTableModProp):
1070     def __init__(self, type_=None, length=None, vacancy_down=None,
1071                  vacancy_up=None, vacancy=None):
1072         self.type = type_
1073         self.length = length
1074         self.vacancy_down = vacancy_down
1075         self.vacancy_up = vacancy_up
1076         self.vacancy = vacancy
1077
1078     @classmethod
1079     def parser(cls, buf):
1080         vacancy = cls()
1081         (vacancy.type, vacancy.length, vacancy.vacancy_down,
1082          vacancy.vacancy_up, vacancy.vacancy) = struct.unpack_from(
1083             ofproto.OFP_TABLE_MOD_PROP_VACANCY_PACK_STR, buf, 0)
1084         return vacancy
1085
1086     def serialize(self):
1087         # fixup
1088         self.length = ofproto.OFP_TABLE_MOD_PROP_VACANCY_SIZE
1089
1090         buf = bytearray()
1091         msg_pack_into(ofproto.OFP_TABLE_MOD_PROP_VACANCY_PACK_STR, buf, 0,
1092                       self.type, self.length, self.vacancy_down,
1093                       self.vacancy_up, self.vacancy)
1094         return buf
1095
1096
1097 @OFPTableModProp.register_type(ofproto.OFPTMPT_EXPERIMENTER)
1098 class OFPTableModPropExperimenter(OFPPropCommonExperimenter4ByteData):
1099     pass
1100
1101
1102 class OFPQueueDescProp(OFPPropBase):
1103     _TYPES = {}
1104
1105
1106 @OFPQueueDescProp.register_type(ofproto.OFPQDPT_MIN_RATE)
1107 class OFPQueueDescPropMinRate(OFPQueueDescProp):
1108     def __init__(self, type_=None, length=None, rate=None):
1109         self.type = type_
1110         self.length = length
1111         self.rate = rate
1112
1113     @classmethod
1114     def parser(cls, buf):
1115         minrate = cls()
1116         (minrate.type, minrate.length, minrate.rate) = struct.unpack_from(
1117             ofproto.OFP_QUEUE_DESC_PROP_MIN_RATE_PACK_STR, buf, 0)
1118         return minrate
1119
1120
1121 @OFPQueueDescProp.register_type(ofproto.OFPQDPT_MAX_RATE)
1122 class OFPQueueDescPropMaxRate(OFPQueueDescProp):
1123     def __init__(self, type_=None, length=None, rate=None):
1124         self.type = type_
1125         self.length = length
1126         self.rate = rate
1127
1128     @classmethod
1129     def parser(cls, buf):
1130         maxrate = cls()
1131         (maxrate.type, maxrate.length, maxrate.rate) = struct.unpack_from(
1132             ofproto.OFP_QUEUE_DESC_PROP_MAX_RATE_PACK_STR, buf, 0)
1133         return maxrate
1134
1135
1136 @OFPQueueDescProp.register_type(ofproto.OFPQDPT_EXPERIMENTER)
1137 class OFPQueueDescPropExperimenter(OFPPropCommonExperimenter4ByteData):
1138     pass
1139
1140
1141 class OFPRoleProp(OFPPropBase):
1142     _TYPES = {}
1143
1144
1145 @OFPRoleProp.register_type(ofproto.OFPRPT_EXPERIMENTER)
1146 class OFPRolePropExperimenter(OFPPropCommonExperimenter4ByteData):
1147     pass
1148
1149
1150 class OFPBundleProp(OFPPropBase):
1151     _TYPES = {}
1152
1153
1154 @OFPBundleProp.register_type(ofproto.OFPRPT_EXPERIMENTER)
1155 class OFPBundlePropExperimenter(OFPPropCommonExperimenter4ByteData):
1156     pass
1157
1158
1159 @_register_parser
1160 @_set_msg_type(ofproto.OFPT_PACKET_IN)
1161 class OFPPacketIn(MsgBase):
1162     """
1163     Packet-In message
1164
1165     The switch sends the packet that received to the controller by this
1166     message.
1167
1168     ============= =========================================================
1169     Attribute     Description
1170     ============= =========================================================
1171     buffer_id     ID assigned by datapath
1172     total_len     Full length of frame
1173     reason        Reason packet is being sent.
1174
1175                   | OFPR_TABLE_MISS
1176                   | OFPR_APPLY_ACTION
1177                   | OFPR_INVALID_TTL
1178                   | OFPR_ACTION_SET
1179                   | OFPR_GROUP
1180                   | OFPR_PACKET_OUT
1181     table_id      ID of the table that was looked up
1182     cookie        Cookie of the flow entry that was looked up
1183     match         Instance of ``OFPMatch``
1184     data          Ethernet frame
1185     ============= =========================================================
1186
1187     Example::
1188
1189         @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
1190         def packet_in_handler(self, ev):
1191             msg = ev.msg
1192             dp = msg.datapath
1193             ofp = dp.ofproto
1194
1195             if msg.reason == ofp.TABLE_MISS:
1196                 reason = 'TABLE MISS'
1197             elif msg.reason == ofp.OFPR_APPLY_ACTION:
1198                 reason = 'APPLY ACTION'
1199             elif msg.reason == ofp.OFPR_INVALID_TTL:
1200                 reason = 'INVALID TTL'
1201             elif msg.reason == ofp.OFPR_ACTION_SET:
1202                 reason = 'ACTION SET'
1203             elif msg.reason == ofp.OFPR_GROUP:
1204                 reason = 'GROUP'
1205             elif msg.reason == ofp.OFPR_PACKET_OUT:
1206                 reason = 'PACKET OUT'
1207             else:
1208                 reason = 'unknown'
1209
1210             self.logger.debug('OFPPacketIn received: '
1211                               'buffer_id=%x total_len=%d reason=%s '
1212                               'table_id=%d cookie=%d match=%s data=%s',
1213                               msg.buffer_id, msg.total_len, reason,
1214                               msg.table_id, msg.cookie, msg.match,
1215                               utils.hex_array(msg.data))
1216     """
1217
1218     def __init__(self, datapath, buffer_id=None, total_len=None, reason=None,
1219                  table_id=None, cookie=None, match=None, data=None):
1220         super(OFPPacketIn, self).__init__(datapath)
1221         self.buffer_id = buffer_id
1222         self.total_len = total_len
1223         self.reason = reason
1224         self.table_id = table_id
1225         self.cookie = cookie
1226         self.match = match
1227         self.data = data
1228
1229     @classmethod
1230     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
1231         msg = super(OFPPacketIn, cls).parser(datapath, version, msg_type,
1232                                              msg_len, xid, buf)
1233         (msg.buffer_id, msg.total_len, msg.reason,
1234          msg.table_id, msg.cookie) = struct.unpack_from(
1235             ofproto.OFP_PACKET_IN_PACK_STR,
1236             msg.buf, ofproto.OFP_HEADER_SIZE)
1237
1238         msg.match = OFPMatch.parser(msg.buf, ofproto.OFP_PACKET_IN_SIZE -
1239                                     ofproto.OFP_MATCH_SIZE)
1240
1241         match_len = utils.round_up(msg.match.length, 8)
1242         msg.data = msg.buf[(ofproto.OFP_PACKET_IN_SIZE -
1243                             ofproto.OFP_MATCH_SIZE + match_len + 2):]
1244
1245         if msg.total_len < len(msg.data):
1246             # discard padding for 8-byte alignment of OFP packet
1247             msg.data = msg.data[:msg.total_len]
1248
1249         return msg
1250
1251
1252 @_register_parser
1253 @_set_msg_type(ofproto.OFPT_FLOW_REMOVED)
1254 class OFPFlowRemoved(MsgBase):
1255     """
1256     Flow removed message
1257
1258     When flow entries time out or are deleted, the switch notifies controller
1259     with this message.
1260
1261     ================ ======================================================
1262     Attribute        Description
1263     ================ ======================================================
1264     cookie           Opaque controller-issued identifier
1265     priority         Priority level of flow entry
1266     reason           One of the following values.
1267
1268                      | OFPRR_IDLE_TIMEOUT
1269                      | OFPRR_HARD_TIMEOUT
1270                      | OFPRR_DELETE
1271                      | OFPRR_GROUP_DELETE
1272                      | OFPRR_METER_DELETE
1273                      | OFPRR_EVICTION
1274     table_id         ID of the table
1275     duration_sec     Time flow was alive in seconds
1276     duration_nsec    Time flow was alive in nanoseconds beyond duration_sec
1277     idle_timeout     Idle timeout from original flow mod
1278     hard_timeout     Hard timeout from original flow mod
1279     packet_count     Number of packets that was associated with the flow
1280     byte_count       Number of bytes that was associated with the flow
1281     match            Instance of ``OFPMatch``
1282     ================ ======================================================
1283
1284     Example::
1285
1286         @set_ev_cls(ofp_event.EventOFPFlowRemoved, MAIN_DISPATCHER)
1287         def flow_removed_handler(self, ev):
1288             msg = ev.msg
1289             dp = msg.datapath
1290             ofp = dp.ofproto
1291
1292             if msg.reason == ofp.OFPRR_IDLE_TIMEOUT:
1293                 reason = 'IDLE TIMEOUT'
1294             elif msg.reason == ofp.OFPRR_HARD_TIMEOUT:
1295                 reason = 'HARD TIMEOUT'
1296             elif msg.reason == ofp.OFPRR_DELETE:
1297                 reason = 'DELETE'
1298             elif msg.reason == ofp.OFPRR_GROUP_DELETE:
1299                 reason = 'GROUP DELETE'
1300             else:
1301                 reason = 'unknown'
1302
1303             self.logger.debug('OFPFlowRemoved received: '
1304                               'cookie=%d priority=%d reason=%s table_id=%d '
1305                               'duration_sec=%d duration_nsec=%d '
1306                               'idle_timeout=%d hard_timeout=%d '
1307                               'packet_count=%d byte_count=%d match.fields=%s',
1308                               msg.cookie, msg.priority, reason, msg.table_id,
1309                               msg.duration_sec, msg.duration_nsec,
1310                               msg.idle_timeout, msg.hard_timeout,
1311                               msg.packet_count, msg.byte_count, msg.match)
1312     """
1313
1314     def __init__(self, datapath, cookie=None, priority=None, reason=None,
1315                  table_id=None, duration_sec=None, duration_nsec=None,
1316                  idle_timeout=None, hard_timeout=None, packet_count=None,
1317                  byte_count=None, match=None):
1318         super(OFPFlowRemoved, self).__init__(datapath)
1319         self.cookie = cookie
1320         self.priority = priority
1321         self.reason = reason
1322         self.table_id = table_id
1323         self.duration_sec = duration_sec
1324         self.duration_nsec = duration_nsec
1325         self.idle_timeout = idle_timeout
1326         self.hard_timeout = hard_timeout
1327         self.packet_count = packet_count
1328         self.byte_count = byte_count
1329         self.match = match
1330
1331     @classmethod
1332     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
1333         msg = super(OFPFlowRemoved, cls).parser(datapath, version, msg_type,
1334                                                 msg_len, xid, buf)
1335
1336         (msg.cookie, msg.priority, msg.reason,
1337          msg.table_id, msg.duration_sec, msg.duration_nsec,
1338          msg.idle_timeout, msg.hard_timeout, msg.packet_count,
1339          msg.byte_count) = struct.unpack_from(
1340             ofproto.OFP_FLOW_REMOVED_PACK_STR0,
1341             msg.buf, ofproto.OFP_HEADER_SIZE)
1342
1343         offset = (ofproto.OFP_FLOW_REMOVED_SIZE - ofproto.OFP_MATCH_SIZE)
1344
1345         msg.match = OFPMatch.parser(msg.buf, offset)
1346
1347         return msg
1348
1349
1350 class OFPPort(StringifyMixin):
1351
1352     """
1353     Description of a port
1354
1355     ========== =========================================================
1356     Attribute  Description
1357     ========== =========================================================
1358     port_no    Port number and it uniquely identifies a port within
1359                a switch.
1360     length     Length of ofp_port (excluding padding).
1361     hw_addr    MAC address for the port.
1362     name       Null-terminated string containing a human-readable name
1363                for the interface.
1364     config     Bitmap of port configration flags.
1365
1366                | OFPPC_PORT_DOWN
1367                | OFPPC_NO_RECV
1368                | OFPPC_NO_FWD
1369                | OFPPC_NO_PACKET_IN
1370     state      Bitmap of port state flags.
1371
1372                | OFPPS_LINK_DOWN
1373                | OFPPS_BLOCKED
1374                | OFPPS_LIVE
1375     properties List of ``OFPPortDescProp`` subclass instance
1376     ========== =========================================================
1377     """
1378
1379     _TYPE = {
1380         'ascii': [
1381             'hw_addr',
1382         ],
1383         'utf-8': [
1384             # OF spec is unclear about the encoding of name.
1385             # we assumes UTF-8, which is used by OVS.
1386             'name',
1387         ]
1388     }
1389
1390     def __init__(self, port_no=None, length=None, hw_addr=None, name=None,
1391                  config=None, state=None, properties=None):
1392         super(OFPPort, self).__init__()
1393         self.port_no = port_no
1394         self.length = length
1395         self.hw_addr = hw_addr
1396         self.name = name
1397         self.config = config
1398         self.state = state
1399         self.properties = properties
1400
1401     @classmethod
1402     def parser(cls, buf, offset):
1403         (port_no, length, hw_addr, name, config, state) = struct.unpack_from(
1404             ofproto.OFP_PORT_PACK_STR, buf, offset)
1405         hw_addr = addrconv.mac.bin_to_text(hw_addr)
1406         name = name.rstrip(b'\0')
1407         props = []
1408         rest = buf[offset + ofproto.OFP_PORT_SIZE:offset + length]
1409         while rest:
1410             p, rest = OFPPortDescProp.parse(rest)
1411             props.append(p)
1412         ofpport = cls(port_no, length, hw_addr, name, config, state, props)
1413         return ofpport
1414
1415
1416 class OFPTableDesc(StringifyMixin):
1417     def __init__(self, length=None, table_id=None, config=None,
1418                  properties=None):
1419         super(OFPTableDesc, self).__init__()
1420         self.table_id = table_id
1421         self.length = length
1422         self.config = config
1423         self.properties = properties
1424
1425     @classmethod
1426     def parser(cls, buf, offset):
1427         (length, table_id, config) = struct.unpack_from(
1428             ofproto.OFP_TABLE_DESC_PACK_STR, buf, offset)
1429         props = []
1430         rest = buf[offset + ofproto.OFP_TABLE_DESC_SIZE:offset + length]
1431         while rest:
1432             p, rest = OFPTableModProp.parse(rest)
1433             props.append(p)
1434         ofptabledesc = cls(length, table_id, config, props)
1435         return ofptabledesc
1436
1437
1438 class OFPQueueDesc(StringifyMixin):
1439     def __init__(self, port_no=None, queue_id=None, len_=None,
1440                  properties=None):
1441         super(OFPQueueDesc, self).__init__()
1442         self.port_no = port_no
1443         self.queue_id = queue_id
1444         self.len = len_
1445         self.properties = properties
1446
1447     @classmethod
1448     def parser(cls, buf, offset):
1449         (port_no, queue_id, len_) = struct.unpack_from(
1450             ofproto.OFP_QUEUE_DESC_PACK_STR, buf, offset)
1451         props = []
1452         rest = buf[offset + ofproto.OFP_QUEUE_DESC_SIZE:offset + len_]
1453         while rest:
1454             p, rest = OFPQueueDescProp.parse(rest)
1455             props.append(p)
1456         ofpqueuedesc = cls(port_no, queue_id, len_, props)
1457         return ofpqueuedesc
1458
1459
1460 def _set_stats_type(stats_type, stats_body_cls):
1461     def _set_cls_stats_type(cls):
1462         cls.cls_stats_type = stats_type
1463         cls.cls_stats_body_cls = stats_body_cls
1464         return cls
1465     return _set_cls_stats_type
1466
1467
1468 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
1469 class OFPMultipartRequest(MsgBase):
1470     def __init__(self, datapath, flags):
1471         super(OFPMultipartRequest, self).__init__(datapath)
1472         self.type = self.__class__.cls_stats_type
1473         self.flags = flags
1474
1475     def _serialize_stats_body(self):
1476         pass
1477
1478     def _serialize_body(self):
1479         msg_pack_into(ofproto.OFP_MULTIPART_REQUEST_PACK_STR,
1480                       self.buf, ofproto.OFP_HEADER_SIZE,
1481                       self.type, self.flags)
1482         self._serialize_stats_body()
1483
1484
1485 @_register_parser
1486 @_set_msg_type(ofproto.OFPT_METER_MOD)
1487 class OFPMeterMod(MsgBase):
1488     """
1489     Meter modification message
1490
1491     The controller sends this message to modify the meter.
1492
1493     ================ ======================================================
1494     Attribute        Description
1495     ================ ======================================================
1496     command          One of the following values.
1497
1498                      | OFPMC_ADD
1499                      | OFPMC_MODIFY
1500                      | OFPMC_DELETE
1501     flags            Bitmap of the following flags.
1502
1503                      | OFPMF_KBPS
1504                      | OFPMF_PKTPS
1505                      | OFPMF_BURST
1506                      | OFPMF_STATS
1507     meter_id         Meter instance
1508     bands            list of the following class instance.
1509
1510                      | OFPMeterBandDrop
1511                      | OFPMeterBandDscpRemark
1512                      | OFPMeterBandExperimenter
1513     ================ ======================================================
1514     """
1515
1516     def __init__(self, datapath, command=ofproto.OFPMC_ADD,
1517                  flags=ofproto.OFPMF_KBPS, meter_id=1, bands=None):
1518         bands = bands if bands else []
1519         super(OFPMeterMod, self).__init__(datapath)
1520         self.command = command
1521         self.flags = flags
1522         self.meter_id = meter_id
1523         self.bands = bands
1524
1525     @classmethod
1526     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
1527         msg = super(OFPMeterMod, cls).parser(
1528             datapath, version, msg_type, msg_len, xid, buf)
1529
1530         (msg.command, msg.flags, msg.meter_id) = struct.unpack_from(
1531             ofproto.OFP_METER_MOD_PACK_STR, buf, ofproto.OFP_HEADER_SIZE)
1532         offset = ofproto.OFP_METER_MOD_SIZE
1533
1534         msg.bands = []
1535         while offset < msg.msg_len:
1536             band = OFPMeterBandHeader.parser(buf, offset)
1537             msg.bands.append(band)
1538             offset += band.len
1539
1540         return msg
1541
1542     def _serialize_body(self):
1543         msg_pack_into(ofproto.OFP_METER_MOD_PACK_STR, self.buf,
1544                       ofproto.OFP_HEADER_SIZE,
1545                       self.command, self.flags, self.meter_id)
1546
1547         offset = ofproto.OFP_METER_MOD_SIZE
1548         for b in self.bands:
1549             b.serialize(self.buf, offset)
1550             offset += b.len
1551
1552
1553 @_set_msg_type(ofproto.OFPT_TABLE_MOD)
1554 class OFPTableMod(MsgBase):
1555     """
1556     Flow table configuration message
1557
1558     The controller sends this message to configure table state.
1559
1560     ================ ======================================================
1561     Attribute        Description
1562     ================ ======================================================
1563     table_id         ID of the table (OFPTT_ALL indicates all tables)
1564     config           Bitmap of configuration flags.
1565
1566                      | OFPTC_EVICTION
1567                      | OFPTC_VACANCY_EVENTS
1568     properties       List of ``OFPTableModProp`` subclass instance
1569     ================ ======================================================
1570
1571     Example::
1572
1573         def send_table_mod(self, datapath):
1574             ofp = datapath.ofproto
1575             ofp_parser = datapath.ofproto_parser
1576
1577             req = ofp_parser.OFPTableMod(datapath, 1, 3)
1578             flags = ofp.OFPTC_VACANCY_EVENTS
1579             properties = [ofp_parser.OFPTableModPropEviction(flags)]
1580             req = ofp_parser.OFPTableMod(datapath, 1, 3, properties)
1581             datapath.send_msg(req)
1582     """
1583
1584     def __init__(self, datapath, table_id, config, properties):
1585         super(OFPTableMod, self).__init__(datapath)
1586         self.table_id = table_id
1587         self.config = config
1588         self.properties = properties
1589
1590     def _serialize_body(self):
1591         props_buf = bytearray()
1592         for p in self.properties:
1593             props_buf += p.serialize()
1594
1595         msg_pack_into(ofproto.OFP_TABLE_MOD_PACK_STR, self.buf,
1596                       ofproto.OFP_HEADER_SIZE,
1597                       self.table_id, self.config)
1598
1599         self.buf += props_buf
1600
1601
1602 @_register_parser
1603 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
1604 class OFPMultipartReply(MsgBase):
1605     _STATS_MSG_TYPES = {}
1606
1607     @staticmethod
1608     def register_stats_type(body_single_struct=False):
1609         def _register_stats_type(cls):
1610             assert cls.cls_stats_type is not None
1611             assert cls.cls_stats_type not in OFPMultipartReply._STATS_MSG_TYPES
1612             assert cls.cls_stats_body_cls is not None
1613             cls.cls_body_single_struct = body_single_struct
1614             OFPMultipartReply._STATS_MSG_TYPES[cls.cls_stats_type] = cls
1615             return cls
1616         return _register_stats_type
1617
1618     def __init__(self, datapath, body=None, flags=None):
1619         super(OFPMultipartReply, self).__init__(datapath)
1620         self.body = body
1621         self.flags = flags
1622
1623     @classmethod
1624     def parser_stats_body(cls, buf, msg_len, offset):
1625         body_cls = cls.cls_stats_body_cls
1626         body = []
1627         while offset < msg_len:
1628             entry = body_cls.parser(buf, offset)
1629             body.append(entry)
1630             offset += entry.length
1631
1632         if cls.cls_body_single_struct:
1633             return body[0]
1634         return body
1635
1636     @classmethod
1637     def parser_stats(cls, datapath, version, msg_type, msg_len, xid, buf):
1638         msg = MsgBase.parser.__func__(
1639             cls, datapath, version, msg_type, msg_len, xid, buf)
1640         msg.body = msg.parser_stats_body(msg.buf, msg.msg_len,
1641                                          ofproto.OFP_MULTIPART_REPLY_SIZE)
1642         return msg
1643
1644     @classmethod
1645     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
1646         type_, flags = struct.unpack_from(
1647             ofproto.OFP_MULTIPART_REPLY_PACK_STR, six.binary_type(buf),
1648             ofproto.OFP_HEADER_SIZE)
1649         stats_type_cls = cls._STATS_MSG_TYPES.get(type_)
1650         msg = super(OFPMultipartReply, stats_type_cls).parser(
1651             datapath, version, msg_type, msg_len, xid, buf)
1652         msg.type = type_
1653         msg.flags = flags
1654
1655         offset = ofproto.OFP_MULTIPART_REPLY_SIZE
1656         body = []
1657         while offset < msg_len:
1658             b = stats_type_cls.cls_stats_body_cls.parser(msg.buf, offset)
1659             body.append(b)
1660             offset += b.length if hasattr(b, 'length') else b.len
1661
1662         if stats_type_cls.cls_body_single_struct:
1663             msg.body = body[0]
1664         else:
1665             msg.body = body
1666         return msg
1667
1668
1669 class OFPDescStats(ofproto_parser.namedtuple('OFPDescStats', (
1670         'mfr_desc', 'hw_desc', 'sw_desc', 'serial_num', 'dp_desc'))):
1671
1672     _TYPE = {
1673         'ascii': [
1674             'mfr_desc',
1675             'hw_desc',
1676             'sw_desc',
1677             'serial_num',
1678             'dp_desc',
1679         ]
1680     }
1681
1682     @classmethod
1683     def parser(cls, buf, offset):
1684         desc = struct.unpack_from(ofproto.OFP_DESC_PACK_STR,
1685                                   buf, offset)
1686         desc = list(desc)
1687         desc = [x.rstrip(b'\0') for x in desc]
1688         stats = cls(*desc)
1689         stats.length = ofproto.OFP_DESC_SIZE
1690         return stats
1691
1692
1693 @_set_stats_type(ofproto.OFPMP_DESC, OFPDescStats)
1694 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
1695 class OFPDescStatsRequest(OFPMultipartRequest):
1696     """
1697     Description statistics request message
1698
1699     The controller uses this message to query description of the switch.
1700
1701     ================ ======================================================
1702     Attribute        Description
1703     ================ ======================================================
1704     flags            Zero or ``OFPMPF_REQ_MORE``
1705     ================ ======================================================
1706
1707     Example::
1708
1709         def send_desc_stats_request(self, datapath):
1710             ofp_parser = datapath.ofproto_parser
1711
1712             req = ofp_parser.OFPDescStatsRequest(datapath, 0)
1713             datapath.send_msg(req)
1714     """
1715
1716     def __init__(self, datapath, flags=0, type_=None):
1717         super(OFPDescStatsRequest, self).__init__(datapath, flags)
1718
1719
1720 @OFPMultipartReply.register_stats_type(body_single_struct=True)
1721 @_set_stats_type(ofproto.OFPMP_DESC, OFPDescStats)
1722 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
1723 class OFPDescStatsReply(OFPMultipartReply):
1724     """
1725     Description statistics reply message
1726
1727     The switch responds with this message to a description statistics
1728     request.
1729
1730     ================ ======================================================
1731     Attribute        Description
1732     ================ ======================================================
1733     body             Instance of ``OFPDescStats``
1734     ================ ======================================================
1735
1736     Example::
1737
1738         @set_ev_cls(ofp_event.EventOFPDescStatsReply, MAIN_DISPATCHER)
1739         def desc_stats_reply_handler(self, ev):
1740             body = ev.msg.body
1741
1742             self.logger.debug('DescStats: mfr_desc=%s hw_desc=%s sw_desc=%s '
1743                               'serial_num=%s dp_desc=%s',
1744                               body.mfr_desc, body.hw_desc, body.sw_desc,
1745                               body.serial_num, body.dp_desc)
1746     """
1747
1748     def __init__(self, datapath, type_=None, **kwargs):
1749         super(OFPDescStatsReply, self).__init__(datapath, **kwargs)
1750
1751
1752 class OFPTableFeaturesStats(StringifyMixin):
1753
1754     _TYPE = {
1755         'utf-8': [
1756             # OF spec is unclear about the encoding of name.
1757             # we assumes UTF-8.
1758             'name',
1759         ]
1760     }
1761
1762     def __init__(self, table_id=None, name=None, metadata_match=None,
1763                  metadata_write=None, config=None, max_entries=None,
1764                  properties=None, length=None):
1765         super(OFPTableFeaturesStats, self).__init__()
1766         self.length = None
1767         self.table_id = table_id
1768         self.name = name
1769         self.metadata_match = metadata_match
1770         self.metadata_write = metadata_write
1771         self.config = config
1772         self.max_entries = max_entries
1773         self.properties = properties
1774
1775     @classmethod
1776     def parser(cls, buf, offset):
1777         table_features = cls()
1778         (table_features.length, table_features.table_id,
1779          name, table_features.metadata_match,
1780          table_features.metadata_write, table_features.config,
1781          table_features.max_entries
1782          ) = struct.unpack_from(ofproto.OFP_TABLE_FEATURES_PACK_STR,
1783                                 buf, offset)
1784         table_features.name = name.rstrip(b'\0')
1785
1786         props = []
1787         rest = buf[offset + ofproto.OFP_TABLE_FEATURES_SIZE:
1788                    offset + table_features.length]
1789         while rest:
1790             p, rest = OFPTableFeatureProp.parse(rest)
1791             props.append(p)
1792         table_features.properties = props
1793
1794         return table_features
1795
1796     def serialize(self):
1797         # fixup
1798         bin_props = bytearray()
1799         for p in self.properties:
1800             bin_props += p.serialize()
1801         self.length = ofproto.OFP_TABLE_FEATURES_SIZE + len(bin_props)
1802
1803         buf = bytearray()
1804         msg_pack_into(ofproto.OFP_TABLE_FEATURES_PACK_STR, buf, 0,
1805                       self.length, self.table_id, self.name,
1806                       self.metadata_match, self.metadata_write,
1807                       self.config, self.max_entries)
1808         return buf + bin_props
1809
1810
1811 class OFPTableFeatureProp(OFPPropBase):
1812     _TYPES = {}
1813
1814
1815 class OFPInstructionId(StringifyMixin):
1816     _PACK_STR = '!HH'  # type, len
1817
1818     def __init__(self, type_, len_=None):
1819         self.type = type_
1820         self.len = len_
1821         # XXX experimenter
1822
1823     @classmethod
1824     def parse(cls, buf):
1825         (type_, len_,) = struct.unpack_from(cls._PACK_STR,
1826                                             six.binary_type(buf), 0)
1827         rest = buf[len_:]
1828         return cls(type_=type_, len_=len_), rest
1829
1830     def serialize(self):
1831         # fixup
1832         self.len = struct.calcsize(self._PACK_STR)
1833
1834         buf = bytearray()
1835         msg_pack_into(self._PACK_STR, buf, 0, self.type, self.len)
1836         return buf
1837
1838
1839 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_INSTRUCTIONS)
1840 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_INSTRUCTIONS_MISS)
1841 class OFPTableFeaturePropInstructions(OFPTableFeatureProp):
1842     def __init__(self, type_=None, length=None, instruction_ids=None):
1843         instruction_ids = instruction_ids if instruction_ids else []
1844         super(OFPTableFeaturePropInstructions, self).__init__(type_, length)
1845         self.instruction_ids = instruction_ids
1846
1847     @classmethod
1848     def parser(cls, buf):
1849         rest = cls.get_rest(buf)
1850         ids = []
1851         while rest:
1852             i, rest = OFPInstructionId.parse(rest)
1853             ids.append(i)
1854         return cls(instruction_ids=ids)
1855
1856     def serialize_body(self):
1857         bin_ids = bytearray()
1858         for i in self.instruction_ids:
1859             bin_ids += i.serialize()
1860
1861         return bin_ids
1862
1863
1864 # Implementation note: While OpenFlow 1.3.2 shares the same ofp_action_header
1865 # for flow_mod and table_features, we have separate classes.  We named this
1866 # class to match with OpenFlow 1.4's name.  (ofp_action_id)
1867 class OFPActionId(StringifyMixin):
1868     _PACK_STR = '!HH'  # type, len
1869
1870     def __init__(self, type_, len_=None):
1871         self.type = type_
1872         self.len = len_
1873         # XXX experimenter
1874
1875     @classmethod
1876     def parse(cls, buf):
1877         (type_, len_,) = struct.unpack_from(cls._PACK_STR,
1878                                             six.binary_type(buf), 0)
1879         rest = buf[len_:]
1880         return cls(type_=type_, len_=len_), rest
1881
1882     def serialize(self):
1883         # fixup
1884         self.len = struct.calcsize(self._PACK_STR)
1885
1886         buf = bytearray()
1887         msg_pack_into(self._PACK_STR, buf, 0, self.type, self.len)
1888         return buf
1889
1890
1891 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_WRITE_ACTIONS)
1892 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_WRITE_ACTIONS_MISS)
1893 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_APPLY_ACTIONS)
1894 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_APPLY_ACTIONS_MISS)
1895 class OFPTableFeaturePropActions(OFPTableFeatureProp):
1896     def __init__(self, type_=None, length=None, action_ids=None):
1897         action_ids = action_ids if action_ids else []
1898         super(OFPTableFeaturePropActions, self).__init__(type_, length)
1899         self.action_ids = action_ids
1900
1901     @classmethod
1902     def parser(cls, buf):
1903         rest = cls.get_rest(buf)
1904         ids = []
1905         while rest:
1906             i, rest = OFPActionId.parse(rest)
1907             ids.append(i)
1908         return cls(action_ids=ids)
1909
1910     def serialize_body(self):
1911         bin_ids = bytearray()
1912         for i in self.action_ids:
1913             bin_ids += i.serialize()
1914         return bin_ids
1915
1916
1917 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_NEXT_TABLES)
1918 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_NEXT_TABLES_MISS)
1919 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_TABLE_SYNC_FROM)
1920 class OFPTableFeaturePropNextTables(OFPTableFeatureProp):
1921     _TABLE_ID_PACK_STR = '!B'
1922
1923     def __init__(self, type_=None, length=None, table_ids=None):
1924         table_ids = table_ids if table_ids else []
1925         super(OFPTableFeaturePropNextTables, self).__init__(type_, length)
1926         self.table_ids = table_ids
1927
1928     @classmethod
1929     def parser(cls, buf):
1930         rest = cls.get_rest(buf)
1931         ids = []
1932         while rest:
1933             (i,) = struct.unpack_from(cls._TABLE_ID_PACK_STR,
1934                                       six.binary_type(rest), 0)
1935             rest = rest[struct.calcsize(cls._TABLE_ID_PACK_STR):]
1936             ids.append(i)
1937         return cls(table_ids=ids)
1938
1939     def serialize_body(self):
1940         bin_ids = bytearray()
1941         for i in self.table_ids:
1942             bin_id = bytearray()
1943             msg_pack_into(self._TABLE_ID_PACK_STR, bin_id, 0, i)
1944             bin_ids += bin_id
1945         return bin_ids
1946
1947
1948 # Implementation note: OFPOxmId is specific to this implementation.
1949 # It does not have a corresponding structure in the specification.
1950 # (the specification uses plain uint32_t for non-experimenter OXMs
1951 # and uint64_t for experimenter OXMs.)
1952 #
1953 # i have taken a look at some of software switch implementations
1954 # but they all look broken or incomplete.  according to the spec,
1955 # oxm_hasmask should be 1 if a switch supports masking for the type.
1956 # the right value for oxm_length is not clear from the spec.
1957 # update: OpenFlow 1.3.3 "clarified" that oxm_length here is the payload
1958 # length.  it's still unclear if it should be doubled for hasmask or not,
1959 # though.
1960 #   ofsoftswitch13
1961 #     oxm_hasmask  always 0
1962 #     oxm_length   same as ofp_match etc (as without mask)
1963 #   linc/of_protocol
1964 #     oxm_hasmask  always 0
1965 #     oxm_length   always 0
1966 #   ovs:
1967 #     seems in flux as of writing this [20141003]
1968 class OFPOxmId(StringifyMixin):
1969     _PACK_STR = '!I'  # oxm header
1970     _EXPERIMENTER_ID_PACK_STR = '!I'
1971
1972     _TYPE = {
1973         'ascii': [
1974             'type',
1975         ],
1976     }
1977
1978     def __init__(self, type_, hasmask=False, length=None):
1979         self.type = type_
1980         self.hasmask = hasmask
1981         self.length = length
1982
1983     @classmethod
1984     def parse(cls, buf):
1985         (oxm,) = struct.unpack_from(cls._PACK_STR, six.binary_type(buf), 0)
1986         # oxm (32 bit) == class (16) | field (7) | hasmask (1) | length (8)
1987         # in case of experimenter OXMs, another 32 bit value
1988         # (experimenter id) follows.
1989         (type_, _v) = ofproto.oxm_to_user(oxm >> (1 + 8), None, None)
1990         rest = buf[struct.calcsize(cls._PACK_STR):]
1991         hasmask = ofproto.oxm_tlv_header_extract_hasmask(oxm)
1992         length = oxm & 0xff  # XXX see the comment on OFPOxmId
1993         class_ = oxm >> (7 + 1 + 8)
1994         if class_ == ofproto.OFPXMC_EXPERIMENTER:
1995             (exp_id,) = struct.unpack_from(cls._EXPERIMENTER_ID_PACK_STR,
1996                                            six.binary_type(rest), 0)
1997             rest = rest[struct.calcsize(cls._EXPERIMENTER_ID_PACK_STR):]
1998             subcls = OFPExperimenterOxmId
1999             return subcls(type_=type_, exp_id=exp_id, hasmask=hasmask,
2000                           length=length), rest
2001         else:
2002             return cls(type_=type_, hasmask=hasmask, length=length), rest
2003
2004     def serialize(self):
2005         # fixup
2006         self.length = 0  # XXX see the comment on OFPOxmId
2007
2008         (n, _v, _m) = ofproto.oxm_from_user(self.type, None)
2009         oxm = (n << (1 + 8)) | (self.hasmask << 8) | self.length
2010         buf = bytearray()
2011         msg_pack_into(self._PACK_STR, buf, 0, oxm)
2012         assert n >> 7 != ofproto.OFPXMC_EXPERIMENTER
2013         return buf
2014
2015
2016 class OFPExperimenterOxmId(OFPOxmId):
2017     def __init__(self, type_, exp_id, hasmask=False, length=None):
2018         super(OFPExperimenterOxmId, self).__init__(type_=type_,
2019                                                    hasmask=hasmask,
2020                                                    length=length)
2021         self.exp_id = exp_id
2022
2023     def serialize(self):
2024         buf = super(OFPExperimenterOxmId, self).serialize()
2025         msg_pack_into(self._EXPERIMENTER_ID_PACK_STR, buf,
2026                       struct.calcsize(self._PACK_STR), self.exp_id)
2027
2028
2029 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_MATCH)
2030 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_WILDCARDS)
2031 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_WRITE_SETFIELD)
2032 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_WRITE_SETFIELD_MISS)
2033 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_APPLY_SETFIELD)
2034 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_APPLY_SETFIELD_MISS)
2035 class OFPTableFeaturePropOxm(OFPTableFeatureProp):
2036     def __init__(self, type_=None, length=None, oxm_ids=None):
2037         oxm_ids = oxm_ids if oxm_ids else []
2038         super(OFPTableFeaturePropOxm, self).__init__(type_, length)
2039         self.oxm_ids = oxm_ids
2040
2041     @classmethod
2042     def parser(cls, buf):
2043         rest = cls.get_rest(buf)
2044         ids = []
2045         while rest:
2046             i, rest = OFPOxmId.parse(rest)
2047             ids.append(i)
2048         return cls(oxm_ids=ids)
2049
2050     def serialize_body(self):
2051         bin_ids = bytearray()
2052         for i in self.oxm_ids:
2053             bin_ids += i.serialize()
2054         return bin_ids
2055
2056
2057 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_EXPERIMENTER)
2058 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_EXPERIMENTER_MISS)
2059 class OFPTableFeaturePropExperimenter(OFPPropCommonExperimenter4ByteData):
2060     pass
2061
2062
2063 @_set_stats_type(ofproto.OFPMP_TABLE_FEATURES, OFPTableFeaturesStats)
2064 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
2065 class OFPTableFeaturesStatsRequest(OFPMultipartRequest):
2066     """
2067     Table features statistics request message
2068
2069     The controller uses this message to query table features.
2070
2071     ================ ======================================================
2072     Attribute        Description
2073     ================ ======================================================
2074     body             List of ``OFPTableFeaturesStats`` instances.
2075                      The default is [].
2076     ================ ======================================================
2077     """
2078
2079     def __init__(self, datapath, flags=0, body=None, type_=None):
2080         body = body if body else []
2081         super(OFPTableFeaturesStatsRequest, self).__init__(datapath, flags)
2082         self.body = body
2083
2084     def _serialize_stats_body(self):
2085         bin_body = bytearray()
2086         for p in self.body:
2087             bin_body += p.serialize()
2088         self.buf += bin_body
2089
2090
2091 @OFPMultipartReply.register_stats_type()
2092 @_set_stats_type(ofproto.OFPMP_TABLE_FEATURES, OFPTableFeaturesStats)
2093 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
2094 class OFPTableFeaturesStatsReply(OFPMultipartReply):
2095     """
2096     Table features statistics reply message
2097
2098     The switch responds with this message to a table features statistics
2099     request.
2100
2101     ================ ======================================================
2102     Attribute        Description
2103     ================ ======================================================
2104     body             List of ``OFPTableFeaturesStats`` instance
2105     ================ ======================================================
2106     """
2107
2108     def __init__(self, datapath, type_=None, **kwargs):
2109         super(OFPTableFeaturesStatsReply, self).__init__(datapath, **kwargs)
2110
2111
2112 @_set_stats_type(ofproto.OFPMP_PORT_DESC, OFPPort)
2113 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
2114 class OFPPortDescStatsRequest(OFPMultipartRequest):
2115     """
2116     Port description request message
2117
2118     The controller uses this message to query description of all the ports.
2119
2120     ================ ======================================================
2121     Attribute        Description
2122     ================ ======================================================
2123     flags            Zero or ``OFPMPF_REQ_MORE``
2124     ================ ======================================================
2125
2126     Example::
2127
2128         def send_port_desc_stats_request(self, datapath):
2129             ofp_parser = datapath.ofproto_parser
2130
2131             req = ofp_parser.OFPPortDescStatsRequest(datapath, 0)
2132             datapath.send_msg(req)
2133     """
2134
2135     def __init__(self, datapath, flags=0, type_=None):
2136         super(OFPPortDescStatsRequest, self).__init__(datapath, flags)
2137
2138
2139 @OFPMultipartReply.register_stats_type()
2140 @_set_stats_type(ofproto.OFPMP_PORT_DESC, OFPPort)
2141 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
2142 class OFPPortDescStatsReply(OFPMultipartReply):
2143     """
2144     Port description reply message
2145
2146     The switch responds with this message to a port description request.
2147
2148     ================ ======================================================
2149     Attribute        Description
2150     ================ ======================================================
2151     body             List of ``OFPPort`` instance
2152     ================ ======================================================
2153
2154     Example::
2155
2156         @set_ev_cls(ofp_event.EventOFPPortDescStatsReply, MAIN_DISPATCHER)
2157         def port_desc_stats_reply_handler(self, ev):
2158             ports = []
2159             for p in ev.msg.body:
2160                 ports.append('port_no=%d hw_addr=%s name=%s config=0x%08x '
2161                              'state=0x%08x properties=%s' %
2162                              (p.port_no, p.hw_addr,
2163                               p.name, p.config, p.state, repr(p.properties)))
2164             self.logger.debug('OFPPortDescStatsReply received: %s', ports)
2165     """
2166
2167     def __init__(self, datapath, type_=None, **kwargs):
2168         super(OFPPortDescStatsReply, self).__init__(datapath, **kwargs)
2169
2170
2171 @_set_stats_type(ofproto.OFPMP_TABLE_DESC, OFPTableDesc)
2172 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
2173 class OFPTableDescStatsRequest(OFPMultipartRequest):
2174     """
2175     Table description request message
2176
2177     The controller uses this message to query description of all the tables.
2178
2179     ================ ======================================================
2180     Attribute        Description
2181     ================ ======================================================
2182     flags            Zero or ``OFPMPF_REQ_MORE``
2183     ================ ======================================================
2184
2185     Example::
2186
2187         def send_table_desc_stats_request(self, datapath):
2188             ofp_parser = datapath.ofproto_parser
2189
2190             req = ofp_parser.OFPTableDescStatsRequest(datapath, 0)
2191             datapath.send_msg(req)
2192     """
2193
2194     def __init__(self, datapath, flags=0, type_=None):
2195         super(OFPTableDescStatsRequest, self).__init__(datapath, flags)
2196
2197
2198 @OFPMultipartReply.register_stats_type()
2199 @_set_stats_type(ofproto.OFPMP_TABLE_DESC, OFPTableDesc)
2200 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
2201 class OFPTableDescStatsReply(OFPMultipartReply):
2202     """
2203     Table description reply message
2204
2205     The switch responds with this message to a table description request.
2206
2207     ================ ======================================================
2208     Attribute        Description
2209     ================ ======================================================
2210     body             List of ``OFPTableDesc`` instance
2211     ================ ======================================================
2212
2213     Example::
2214
2215         @set_ev_cls(ofp_event.EventOFPTableDescStatsReply, MAIN_DISPATCHER)
2216         def table_desc_stats_reply_handler(self, ev):
2217             tables = []
2218             for p in ev.msg.body:
2219                 tables.append('table_id=%d config=0x%08x properties=%s' %
2220                              (p.table_id, p.config, repr(p.properties)))
2221             self.logger.debug('OFPTableDescStatsReply received: %s', tables)
2222     """
2223
2224     def __init__(self, datapath, type_=None, **kwargs):
2225         super(OFPTableDescStatsReply, self).__init__(datapath, **kwargs)
2226
2227
2228 @_set_stats_type(ofproto.OFPMP_QUEUE_DESC, OFPQueueDesc)
2229 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
2230 class OFPQueueDescStatsRequest(OFPMultipartRequest):
2231     """
2232     Queue description request message
2233
2234     The controller uses this message to query description of all the queues.
2235
2236     ================ ======================================================
2237     Attribute        Description
2238     ================ ======================================================
2239     flags            Zero or ``OFPMPF_REQ_MORE``
2240     port_no          Port number to read (OFPP_ANY for all ports)
2241     queue_id         ID of queue to read (OFPQ_ALL for all queues)
2242     ================ ======================================================
2243
2244     Example::
2245
2246         def send_queue_desc_stats_request(self, datapath):
2247             ofp = datapath.ofproto
2248             ofp_parser = datapath.ofproto_parser
2249             req = ofp_parser.OFPQueueDescStatsRequest(datapath, 0,
2250                                                       ofp.OFPP_ANY,
2251                                                       ofp.OFPQ_ALL)
2252             datapath.send_msg(req)
2253     """
2254
2255     def __init__(self, datapath, flags=0, port_no=ofproto.OFPP_ANY,
2256                  queue_id=ofproto.OFPQ_ALL, type_=None):
2257         super(OFPQueueDescStatsRequest, self).__init__(datapath, flags)
2258         self.port_no = port_no
2259         self.queue_id = queue_id
2260
2261     def _serialize_stats_body(self):
2262         msg_pack_into(ofproto.OFP_QUEUE_DESC_REQUEST_PACK_STR,
2263                       self.buf,
2264                       ofproto.OFP_MULTIPART_REQUEST_SIZE,
2265                       self.port_no, self.queue_id)
2266
2267
2268 @OFPMultipartReply.register_stats_type()
2269 @_set_stats_type(ofproto.OFPMP_QUEUE_DESC, OFPQueueDesc)
2270 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
2271 class OFPQueueDescStatsReply(OFPMultipartReply):
2272     """
2273     Queue description reply message
2274
2275     The switch responds with this message to a queue description request.
2276
2277     ================ ======================================================
2278     Attribute        Description
2279     ================ ======================================================
2280     body             List of ``OFPQueueDesc`` instance
2281     ================ ======================================================
2282
2283     Example::
2284
2285         @set_ev_cls(ofp_event.EventOFPQueueDescStatsReply, MAIN_DISPATCHER)
2286         def queue_desc_stats_reply_handler(self, ev):
2287             queues = []
2288             for q in ev.msg.body:
2289                 queues.append('port_no=%d queue_id=0x%08x properties=%s' %
2290                              (q.port_no, q.queue_id, repr(q.properties)))
2291             self.logger.debug('OFPQueueDescStatsReply received: %s', queues)
2292     """
2293
2294     def __init__(self, datapath, type_=None, **kwargs):
2295         super(OFPQueueDescStatsReply, self).__init__(datapath, **kwargs)
2296
2297
2298 class OFPQueueStatsProp(OFPPropBase):
2299     _TYPES = {}
2300
2301
2302 @OFPQueueStatsProp.register_type(ofproto.OFPQSPT_EXPERIMENTER)
2303 class OFPQueueStatsPropExperimenter(OFPPropCommonExperimenter4ByteData):
2304     pass
2305
2306
2307 class OFPQueueStats(StringifyMixin):
2308     def __init__(self, length=None, port_no=None, queue_id=None,
2309                  tx_bytes=None, tx_packets=None, tx_errors=None,
2310                  duration_sec=None, duration_nsec=None, properties=None):
2311         super(OFPQueueStats, self).__init__()
2312         self.length = length
2313         self.port_no = port_no
2314         self.queue_id = queue_id
2315         self.tx_bytes = tx_bytes
2316         self.tx_packets = tx_packets
2317         self.tx_errors = tx_errors
2318         self.duration_sec = duration_sec
2319         self.duration_nsec = duration_nsec
2320         self.properties = properties
2321
2322     @classmethod
2323     def parser(cls, buf, offset):
2324         (length, port_no, queue_id, tx_bytes, tx_packets, tx_errors,
2325          duration_sec, duration_nsec) = struct.unpack_from(
2326             ofproto.OFP_QUEUE_STATS_PACK_STR, buf, offset)
2327         props = []
2328         rest = buf[offset + ofproto.OFP_QUEUE_STATS_SIZE:offset + length]
2329         while rest:
2330             p, rest = OFPQueueStatsProp.parse(rest)
2331             props.append(p)
2332         stats = cls(length, port_no, queue_id, tx_bytes, tx_packets, tx_errors,
2333                     duration_sec, duration_nsec, props)
2334         return stats
2335
2336
2337 @_set_stats_type(ofproto.OFPMP_QUEUE_STATS, OFPQueueStats)
2338 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
2339 class OFPQueueStatsRequest(OFPMultipartRequest):
2340     """
2341     Queue statistics request message
2342
2343     The controller uses this message to query queue statictics.
2344
2345     ================ ======================================================
2346     Attribute        Description
2347     ================ ======================================================
2348     flags            Zero or ``OFPMPF_REQ_MORE``
2349     port_no          Port number to read
2350     queue_id         ID of queue to read
2351     ================ ======================================================
2352
2353     Example::
2354
2355         def send_queue_stats_request(self, datapath):
2356             ofp = datapath.ofproto
2357             ofp_parser = datapath.ofproto_parser
2358
2359             req = ofp_parser.OFPQueueStatsRequest(datapath, 0, ofp.OFPP_ANY,
2360                                                   ofp.OFPQ_ALL)
2361             datapath.send_msg(req)
2362     """
2363
2364     def __init__(self, datapath, flags=0, port_no=ofproto.OFPP_ANY,
2365                  queue_id=ofproto.OFPQ_ALL, type_=None):
2366         super(OFPQueueStatsRequest, self).__init__(datapath, flags)
2367         self.port_no = port_no
2368         self.queue_id = queue_id
2369
2370     def _serialize_stats_body(self):
2371         msg_pack_into(ofproto.OFP_QUEUE_STATS_REQUEST_PACK_STR,
2372                       self.buf,
2373                       ofproto.OFP_MULTIPART_REQUEST_SIZE,
2374                       self.port_no, self.queue_id)
2375
2376
2377 @OFPMultipartReply.register_stats_type()
2378 @_set_stats_type(ofproto.OFPMP_QUEUE_STATS, OFPQueueStats)
2379 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
2380 class OFPQueueStatsReply(OFPMultipartReply):
2381     """
2382     Queue statistics reply message
2383
2384     The switch responds with this message to an aggregate flow statistics
2385     request.
2386
2387     ================ ======================================================
2388     Attribute        Description
2389     ================ ======================================================
2390     body             List of ``OFPQueueStats`` instance
2391     ================ ======================================================
2392
2393     Example::
2394
2395         @set_ev_cls(ofp_event.EventOFPQueueStatsReply, MAIN_DISPATCHER)
2396         def queue_stats_reply_handler(self, ev):
2397             queues = []
2398             for stat in ev.msg.body:
2399                 queues.append('port_no=%d queue_id=%d '
2400                               'tx_bytes=%d tx_packets=%d tx_errors=%d '
2401                               'duration_sec=%d duration_nsec=%d'
2402                               'properties=%s' %
2403                               (stat.port_no, stat.queue_id,
2404                                stat.tx_bytes, stat.tx_packets, stat.tx_errors,
2405                                stat.duration_sec, stat.duration_nsec,
2406                                repr(stat.properties)))
2407             self.logger.debug('QueueStats: %s', queues)
2408     """
2409
2410     def __init__(self, datapath, type_=None, **kwargs):
2411         super(OFPQueueStatsReply, self).__init__(datapath, **kwargs)
2412
2413
2414 class OFPBucketCounter(StringifyMixin):
2415     def __init__(self, packet_count, byte_count):
2416         super(OFPBucketCounter, self).__init__()
2417         self.packet_count = packet_count
2418         self.byte_count = byte_count
2419
2420     @classmethod
2421     def parser(cls, buf, offset):
2422         packet_count, byte_count = struct.unpack_from(
2423             ofproto.OFP_BUCKET_COUNTER_PACK_STR, buf, offset)
2424         return cls(packet_count, byte_count)
2425
2426
2427 class OFPGroupStats(StringifyMixin):
2428     def __init__(self, length=None, group_id=None, ref_count=None,
2429                  packet_count=None, byte_count=None, duration_sec=None,
2430                  duration_nsec=None, bucket_stats=None):
2431         super(OFPGroupStats, self).__init__()
2432         self.length = length
2433         self.group_id = group_id
2434         self.ref_count = ref_count
2435         self.packet_count = packet_count
2436         self.byte_count = byte_count
2437         self.duration_sec = duration_sec
2438         self.duration_nsec = duration_nsec
2439         self.bucket_stats = bucket_stats
2440
2441     @classmethod
2442     def parser(cls, buf, offset):
2443         group = struct.unpack_from(ofproto.OFP_GROUP_STATS_PACK_STR,
2444                                    buf, offset)
2445         group_stats = cls(*group)
2446
2447         group_stats.bucket_stats = []
2448         total_len = group_stats.length + offset
2449         offset += ofproto.OFP_GROUP_STATS_SIZE
2450         while total_len > offset:
2451             b = OFPBucketCounter.parser(buf, offset)
2452             group_stats.bucket_stats.append(b)
2453             offset += ofproto.OFP_BUCKET_COUNTER_SIZE
2454
2455         return group_stats
2456
2457
2458 @_set_stats_type(ofproto.OFPMP_GROUP, OFPGroupStats)
2459 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
2460 class OFPGroupStatsRequest(OFPMultipartRequest):
2461     """
2462     Group statistics request message
2463
2464     The controller uses this message to query statistics of one or more
2465     groups.
2466
2467     ================ ======================================================
2468     Attribute        Description
2469     ================ ======================================================
2470     flags            Zero or ``OFPMPF_REQ_MORE``
2471     group_id         ID of group to read (OFPG_ALL to all groups)
2472     ================ ======================================================
2473
2474     Example::
2475
2476         def send_group_stats_request(self, datapath):
2477             ofp = datapath.ofproto
2478             ofp_parser = datapath.ofproto_parser
2479
2480             req = ofp_parser.OFPGroupStatsRequest(datapath, 0, ofp.OFPG_ALL)
2481             datapath.send_msg(req)
2482     """
2483
2484     def __init__(self, datapath, flags=0, group_id=ofproto.OFPG_ALL,
2485                  type_=None):
2486         super(OFPGroupStatsRequest, self).__init__(datapath, flags)
2487         self.group_id = group_id
2488
2489     def _serialize_stats_body(self):
2490         msg_pack_into(ofproto.OFP_GROUP_STATS_REQUEST_PACK_STR,
2491                       self.buf,
2492                       ofproto.OFP_MULTIPART_REQUEST_SIZE,
2493                       self.group_id)
2494
2495
2496 @OFPMultipartReply.register_stats_type()
2497 @_set_stats_type(ofproto.OFPMP_GROUP, OFPGroupStats)
2498 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
2499 class OFPGroupStatsReply(OFPMultipartReply):
2500     """
2501     Group statistics reply message
2502
2503     The switch responds with this message to a group statistics request.
2504
2505     ================ ======================================================
2506     Attribute        Description
2507     ================ ======================================================
2508     body             List of ``OFPGroupStats`` instance
2509     ================ ======================================================
2510
2511     Example::
2512
2513         @set_ev_cls(ofp_event.EventOFPGroupStatsReply, MAIN_DISPATCHER)
2514         def group_stats_reply_handler(self, ev):
2515             groups = []
2516             for stat in ev.msg.body:
2517                 groups.append('length=%d group_id=%d '
2518                               'ref_count=%d packet_count=%d byte_count=%d '
2519                               'duration_sec=%d duration_nsec=%d' %
2520                               (stat.length, stat.group_id,
2521                                stat.ref_count, stat.packet_count,
2522                                stat.byte_count, stat.duration_sec,
2523                                stat.duration_nsec))
2524             self.logger.debug('GroupStats: %s', groups)
2525     """
2526
2527     def __init__(self, datapath, type_=None, **kwargs):
2528         super(OFPGroupStatsReply, self).__init__(datapath, **kwargs)
2529
2530
2531 class OFPGroupDescStats(StringifyMixin):
2532     def __init__(self, type_=None, group_id=None, buckets=None, length=None):
2533         super(OFPGroupDescStats, self).__init__()
2534         self.type = type_
2535         self.group_id = group_id
2536         self.buckets = buckets
2537
2538     @classmethod
2539     def parser(cls, buf, offset):
2540         stats = cls()
2541
2542         (stats.length, stats.type, stats.group_id) = struct.unpack_from(
2543             ofproto.OFP_GROUP_DESC_STATS_PACK_STR, buf, offset)
2544         offset += ofproto.OFP_GROUP_DESC_STATS_SIZE
2545
2546         stats.buckets = []
2547         length = ofproto.OFP_GROUP_DESC_STATS_SIZE
2548         while length < stats.length:
2549             bucket = OFPBucket.parser(buf, offset)
2550             stats.buckets.append(bucket)
2551
2552             offset += bucket.len
2553             length += bucket.len
2554
2555         return stats
2556
2557
2558 @_set_stats_type(ofproto.OFPMP_GROUP_DESC, OFPGroupDescStats)
2559 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
2560 class OFPGroupDescStatsRequest(OFPMultipartRequest):
2561     """
2562     Group description request message
2563
2564     The controller uses this message to list the set of groups on a switch.
2565
2566     ================ ======================================================
2567     Attribute        Description
2568     ================ ======================================================
2569     flags            Zero or ``OFPMPF_REQ_MORE``
2570     ================ ======================================================
2571
2572     Example::
2573
2574         def send_group_desc_stats_request(self, datapath):
2575             ofp = datapath.ofproto
2576             ofp_parser = datapath.ofproto_parser
2577
2578             req = ofp_parser.OFPGroupDescStatsRequest(datapath, 0)
2579             datapath.send_msg(req)
2580     """
2581
2582     def __init__(self, datapath, flags=0, type_=None):
2583         super(OFPGroupDescStatsRequest, self).__init__(datapath, flags)
2584
2585
2586 @OFPMultipartReply.register_stats_type()
2587 @_set_stats_type(ofproto.OFPMP_GROUP_DESC, OFPGroupDescStats)
2588 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
2589 class OFPGroupDescStatsReply(OFPMultipartReply):
2590     """
2591     Group description reply message
2592
2593     The switch responds with this message to a group description request.
2594
2595     ================ ======================================================
2596     Attribute        Description
2597     ================ ======================================================
2598     body             List of ``OFPGroupDescStats`` instance
2599     ================ ======================================================
2600
2601     Example::
2602
2603         @set_ev_cls(ofp_event.EventOFPGroupDescStatsReply, MAIN_DISPATCHER)
2604         def group_desc_stats_reply_handler(self, ev):
2605             descs = []
2606             for stat in ev.msg.body:
2607                 descs.append('length=%d type=%d group_id=%d '
2608                              'buckets=%s' %
2609                              (stat.length, stat.type, stat.group_id,
2610                               stat.bucket))
2611             self.logger.debug('GroupDescStats: %s', descs)
2612     """
2613
2614     def __init__(self, datapath, type_=None, **kwargs):
2615         super(OFPGroupDescStatsReply, self).__init__(datapath, **kwargs)
2616
2617
2618 class OFPGroupFeaturesStats(ofproto_parser.namedtuple('OFPGroupFeaturesStats',
2619                                                       ('types', 'capabilities', 'max_groups',
2620                                                        'actions'))):
2621     @classmethod
2622     def parser(cls, buf, offset):
2623         group_features = struct.unpack_from(
2624             ofproto.OFP_GROUP_FEATURES_PACK_STR, buf, offset)
2625         types = group_features[0]
2626         capabilities = group_features[1]
2627         max_groups = list(group_features[2:6])
2628         actions = list(group_features[6:10])
2629         stats = cls(types, capabilities, max_groups, actions)
2630         stats.length = ofproto.OFP_GROUP_FEATURES_SIZE
2631         return stats
2632
2633
2634 @_set_stats_type(ofproto.OFPMP_GROUP_FEATURES, OFPGroupFeaturesStats)
2635 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
2636 class OFPGroupFeaturesStatsRequest(OFPMultipartRequest):
2637     """
2638     Group features request message
2639
2640     The controller uses this message to list the capabilities of groups on
2641     a switch.
2642
2643     ================ ======================================================
2644     Attribute        Description
2645     ================ ======================================================
2646     flags            Zero or ``OFPMPF_REQ_MORE``
2647     ================ ======================================================
2648
2649     Example::
2650
2651         def send_group_features_stats_request(self, datapath):
2652             ofp_parser = datapath.ofproto_parser
2653
2654             req = ofp_parser.OFPGroupFeaturesStatsRequest(datapath, 0)
2655             datapath.send_msg(req)
2656     """
2657
2658     def __init__(self, datapath, flags=0, type_=None):
2659         super(OFPGroupFeaturesStatsRequest, self).__init__(datapath, flags)
2660
2661
2662 @OFPMultipartReply.register_stats_type(body_single_struct=True)
2663 @_set_stats_type(ofproto.OFPMP_GROUP_FEATURES, OFPGroupFeaturesStats)
2664 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
2665 class OFPGroupFeaturesStatsReply(OFPMultipartReply):
2666     """
2667     Group features reply message
2668
2669     The switch responds with this message to a group features request.
2670
2671     ================ ======================================================
2672     Attribute        Description
2673     ================ ======================================================
2674     body             Instance of ``OFPGroupFeaturesStats``
2675     ================ ======================================================
2676
2677     Example::
2678
2679         @set_ev_cls(ofp_event.EventOFPGroupFeaturesStatsReply, MAIN_DISPATCHER)
2680         def group_features_stats_reply_handler(self, ev):
2681             body = ev.msg.body
2682
2683             self.logger.debug('GroupFeaturesStats: types=%d '
2684                               'capabilities=0x%08x max_groups=%s '
2685                               'actions=%s',
2686                               body.types, body.capabilities,
2687                               body.max_groups, body.actions)
2688     """
2689
2690     def __init__(self, datapath, type_=None, **kwargs):
2691         super(OFPGroupFeaturesStatsReply, self).__init__(datapath, **kwargs)
2692
2693
2694 class OFPMeterBandStats(StringifyMixin):
2695     def __init__(self, packet_band_count, byte_band_count):
2696         super(OFPMeterBandStats, self).__init__()
2697         self.packet_band_count = packet_band_count
2698         self.byte_band_count = byte_band_count
2699
2700     @classmethod
2701     def parser(cls, buf, offset):
2702         band_stats = struct.unpack_from(
2703             ofproto.OFP_METER_BAND_STATS_PACK_STR, buf, offset)
2704         return cls(*band_stats)
2705
2706
2707 class OFPMeterStats(StringifyMixin):
2708     def __init__(self, meter_id=None, flow_count=None, packet_in_count=None,
2709                  byte_in_count=None, duration_sec=None, duration_nsec=None,
2710                  band_stats=None, len_=None):
2711         super(OFPMeterStats, self).__init__()
2712         self.meter_id = meter_id
2713         self.len = 0
2714         self.flow_count = flow_count
2715         self.packet_in_count = packet_in_count
2716         self.byte_in_count = byte_in_count
2717         self.duration_sec = duration_sec
2718         self.duration_nsec = duration_nsec
2719         self.band_stats = band_stats
2720
2721     @classmethod
2722     def parser(cls, buf, offset):
2723         meter_stats = cls()
2724
2725         (meter_stats.meter_id, meter_stats.len,
2726          meter_stats.flow_count, meter_stats.packet_in_count,
2727          meter_stats.byte_in_count, meter_stats.duration_sec,
2728          meter_stats.duration_nsec) = struct.unpack_from(
2729             ofproto.OFP_METER_STATS_PACK_STR, buf, offset)
2730         offset += ofproto.OFP_METER_STATS_SIZE
2731
2732         meter_stats.band_stats = []
2733         length = ofproto.OFP_METER_STATS_SIZE
2734         while length < meter_stats.len:
2735             band_stats = OFPMeterBandStats.parser(buf, offset)
2736             meter_stats.band_stats.append(band_stats)
2737             offset += ofproto.OFP_METER_BAND_STATS_SIZE
2738             length += ofproto.OFP_METER_BAND_STATS_SIZE
2739
2740         return meter_stats
2741
2742
2743 @_set_stats_type(ofproto.OFPMP_METER, OFPMeterStats)
2744 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
2745 class OFPMeterStatsRequest(OFPMultipartRequest):
2746     """
2747     Meter statistics request message
2748
2749     The controller uses this message to query statistics for one or more
2750     meters.
2751
2752     ================ ======================================================
2753     Attribute        Description
2754     ================ ======================================================
2755     flags            Zero or ``OFPMPF_REQ_MORE``
2756     meter_id         ID of meter to read (OFPM_ALL to all meters)
2757     ================ ======================================================
2758
2759     Example::
2760
2761         def send_meter_stats_request(self, datapath):
2762             ofp = datapath.ofproto
2763             ofp_parser = datapath.ofproto_parser
2764
2765             req = ofp_parser.OFPMeterStatsRequest(datapath, 0, ofp.OFPM_ALL)
2766             datapath.send_msg(req)
2767     """
2768
2769     def __init__(self, datapath, flags=0, meter_id=ofproto.OFPM_ALL,
2770                  type_=None):
2771         super(OFPMeterStatsRequest, self).__init__(datapath, flags)
2772         self.meter_id = meter_id
2773
2774     def _serialize_stats_body(self):
2775         msg_pack_into(ofproto.OFP_METER_MULTIPART_REQUEST_PACK_STR,
2776                       self.buf,
2777                       ofproto.OFP_MULTIPART_REQUEST_SIZE,
2778                       self.meter_id)
2779
2780
2781 @OFPMultipartReply.register_stats_type()
2782 @_set_stats_type(ofproto.OFPMP_METER, OFPMeterStats)
2783 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
2784 class OFPMeterStatsReply(OFPMultipartReply):
2785     """
2786     Meter statistics reply message
2787
2788     The switch responds with this message to a meter statistics request.
2789
2790     ================ ======================================================
2791     Attribute        Description
2792     ================ ======================================================
2793     body             List of ``OFPMeterStats`` instance
2794     ================ ======================================================
2795
2796     Example::
2797
2798         @set_ev_cls(ofp_event.EventOFPMeterStatsReply, MAIN_DISPATCHER)
2799         def meter_stats_reply_handler(self, ev):
2800             meters = []
2801             for stat in ev.msg.body:
2802                 meters.append('meter_id=0x%08x len=%d flow_count=%d '
2803                               'packet_in_count=%d byte_in_count=%d '
2804                               'duration_sec=%d duration_nsec=%d '
2805                               'band_stats=%s' %
2806                               (stat.meter_id, stat.len, stat.flow_count,
2807                                stat.packet_in_count, stat.byte_in_count,
2808                                stat.duration_sec, stat.duration_nsec,
2809                                stat.band_stats))
2810             self.logger.debug('MeterStats: %s', meters)
2811     """
2812
2813     def __init__(self, datapath, type_=None, **kwargs):
2814         super(OFPMeterStatsReply, self).__init__(datapath, **kwargs)
2815
2816
2817 class OFPMeterBand(StringifyMixin):
2818     def __init__(self, type_, len_):
2819         super(OFPMeterBand, self).__init__()
2820         self.type = type_
2821         self.len = len_
2822
2823
2824 class OFPMeterBandHeader(OFPMeterBand):
2825     _METER_BAND = {}
2826
2827     @staticmethod
2828     def register_meter_band_type(type_, len_):
2829         def _register_meter_band_type(cls):
2830             OFPMeterBandHeader._METER_BAND[type_] = cls
2831             cls.cls_meter_band_type = type_
2832             cls.cls_meter_band_len = len_
2833             return cls
2834         return _register_meter_band_type
2835
2836     def __init__(self):
2837         cls = self.__class__
2838         super(OFPMeterBandHeader, self).__init__(cls.cls_meter_band_type,
2839                                                  cls.cls_meter_band_len)
2840
2841     @classmethod
2842     def parser(cls, buf, offset):
2843         type_, len_, _rate, _burst_size = struct.unpack_from(
2844             ofproto.OFP_METER_BAND_HEADER_PACK_STR, buf, offset)
2845         cls_ = cls._METER_BAND[type_]
2846         assert cls_.cls_meter_band_len == len_
2847         return cls_.parser(buf, offset)
2848
2849
2850 @OFPMeterBandHeader.register_meter_band_type(
2851     ofproto.OFPMBT_DROP, ofproto.OFP_METER_BAND_DROP_SIZE)
2852 class OFPMeterBandDrop(OFPMeterBandHeader):
2853     def __init__(self, rate=0, burst_size=0, type_=None, len_=None):
2854         super(OFPMeterBandDrop, self).__init__()
2855         self.rate = rate
2856         self.burst_size = burst_size
2857
2858     def serialize(self, buf, offset):
2859         msg_pack_into(ofproto.OFP_METER_BAND_DROP_PACK_STR, buf, offset,
2860                       self.type, self.len, self.rate, self.burst_size)
2861
2862     @classmethod
2863     def parser(cls, buf, offset):
2864         type_, len_, rate, burst_size = struct.unpack_from(
2865             ofproto.OFP_METER_BAND_DROP_PACK_STR, buf, offset)
2866         assert cls.cls_meter_band_type == type_
2867         assert cls.cls_meter_band_len == len_
2868         return cls(rate, burst_size)
2869
2870
2871 @OFPMeterBandHeader.register_meter_band_type(
2872     ofproto.OFPMBT_DSCP_REMARK,
2873     ofproto.OFP_METER_BAND_DSCP_REMARK_SIZE)
2874 class OFPMeterBandDscpRemark(OFPMeterBandHeader):
2875     def __init__(self, rate=0, burst_size=0, prec_level=0,
2876                  type_=None, len_=None):
2877         super(OFPMeterBandDscpRemark, self).__init__()
2878         self.rate = rate
2879         self.burst_size = burst_size
2880         self.prec_level = prec_level
2881
2882     def serialize(self, buf, offset):
2883         msg_pack_into(ofproto.OFP_METER_BAND_DSCP_REMARK_PACK_STR, buf,
2884                       offset, self.type, self.len, self.rate,
2885                       self.burst_size, self.prec_level)
2886
2887     @classmethod
2888     def parser(cls, buf, offset):
2889         type_, len_, rate, burst_size, prec_level = struct.unpack_from(
2890             ofproto.OFP_METER_BAND_DSCP_REMARK_PACK_STR, buf, offset)
2891         assert cls.cls_meter_band_type == type_
2892         assert cls.cls_meter_band_len == len_
2893         return cls(rate, burst_size, prec_level)
2894
2895
2896 @OFPMeterBandHeader.register_meter_band_type(
2897     ofproto.OFPMBT_EXPERIMENTER,
2898     ofproto.OFP_METER_BAND_EXPERIMENTER_SIZE)
2899 class OFPMeterBandExperimenter(OFPMeterBandHeader):
2900     def __init__(self, rate=0, burst_size=0, experimenter=None,
2901                  type_=None, len_=None):
2902         super(OFPMeterBandExperimenter, self).__init__()
2903         self.rate = rate
2904         self.burst_size = burst_size
2905         self.experimenter = experimenter
2906
2907     def serialize(self, buf, offset):
2908         msg_pack_into(ofproto.OFP_METER_BAND_EXPERIMENTER_PACK_STR, buf,
2909                       offset, self.type, self.len, self.rate,
2910                       self.burst_size, self.experimenter)
2911
2912     @classmethod
2913     def parser(cls, buf, offset):
2914         type_, len_, rate, burst_size, experimenter = struct.unpack_from(
2915             ofproto.OFP_METER_BAND_EXPERIMENTER_PACK_STR, buf, offset)
2916         assert cls.cls_meter_band_type == type_
2917         assert cls.cls_meter_band_len == len_
2918         return cls(rate, burst_size, experimenter)
2919
2920
2921 class OFPMeterConfigStats(StringifyMixin):
2922     def __init__(self, flags=None, meter_id=None, bands=None, length=None):
2923         super(OFPMeterConfigStats, self).__init__()
2924         self.length = None
2925         self.flags = flags
2926         self.meter_id = meter_id
2927         self.bands = bands
2928
2929     @classmethod
2930     def parser(cls, buf, offset):
2931         meter_config = cls()
2932
2933         (meter_config.length, meter_config.flags,
2934          meter_config.meter_id) = struct.unpack_from(
2935             ofproto.OFP_METER_CONFIG_PACK_STR, buf, offset)
2936         offset += ofproto.OFP_METER_CONFIG_SIZE
2937
2938         meter_config.bands = []
2939         length = ofproto.OFP_METER_CONFIG_SIZE
2940         while length < meter_config.length:
2941             band = OFPMeterBandHeader.parser(buf, offset)
2942             meter_config.bands.append(band)
2943             offset += band.len
2944             length += band.len
2945
2946         return meter_config
2947
2948
2949 @_set_stats_type(ofproto.OFPMP_METER_CONFIG, OFPMeterConfigStats)
2950 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
2951 class OFPMeterConfigStatsRequest(OFPMultipartRequest):
2952     """
2953     Meter configuration statistics request message
2954
2955     The controller uses this message to query configuration for one or more
2956     meters.
2957
2958     ================ ======================================================
2959     Attribute        Description
2960     ================ ======================================================
2961     flags            Zero or ``OFPMPF_REQ_MORE``
2962     meter_id         ID of meter to read (OFPM_ALL to all meters)
2963     ================ ======================================================
2964
2965     Example::
2966
2967         def send_meter_config_stats_request(self, datapath):
2968             ofp = datapath.ofproto
2969             ofp_parser = datapath.ofproto_parser
2970
2971             req = ofp_parser.OFPMeterConfigStatsRequest(datapath, 0,
2972                                                         ofp.OFPM_ALL)
2973             datapath.send_msg(req)
2974     """
2975
2976     def __init__(self, datapath, flags=0, meter_id=ofproto.OFPM_ALL,
2977                  type_=None):
2978         super(OFPMeterConfigStatsRequest, self).__init__(datapath, flags)
2979         self.meter_id = meter_id
2980
2981     def _serialize_stats_body(self):
2982         msg_pack_into(ofproto.OFP_METER_MULTIPART_REQUEST_PACK_STR,
2983                       self.buf,
2984                       ofproto.OFP_MULTIPART_REQUEST_SIZE,
2985                       self.meter_id)
2986
2987
2988 @OFPMultipartReply.register_stats_type()
2989 @_set_stats_type(ofproto.OFPMP_METER_CONFIG, OFPMeterConfigStats)
2990 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
2991 class OFPMeterConfigStatsReply(OFPMultipartReply):
2992     """
2993     Meter configuration statistics reply message
2994
2995     The switch responds with this message to a meter configuration
2996     statistics request.
2997
2998     ================ ======================================================
2999     Attribute        Description
3000     ================ ======================================================
3001     body             List of ``OFPMeterConfigStats`` instance
3002     ================ ======================================================
3003
3004     Example::
3005
3006         @set_ev_cls(ofp_event.EventOFPMeterConfigStatsReply, MAIN_DISPATCHER)
3007         def meter_config_stats_reply_handler(self, ev):
3008             configs = []
3009             for stat in ev.msg.body:
3010                 configs.append('length=%d flags=0x%04x meter_id=0x%08x '
3011                                'bands=%s' %
3012                                (stat.length, stat.flags, stat.meter_id,
3013                                 stat.bands))
3014             self.logger.debug('MeterConfigStats: %s', configs)
3015     """
3016
3017     def __init__(self, datapath, type_=None, **kwargs):
3018         super(OFPMeterConfigStatsReply, self).__init__(datapath, **kwargs)
3019
3020
3021 class OFPMeterFeaturesStats(ofproto_parser.namedtuple('OFPMeterFeaturesStats',
3022                                                       ('max_meter', 'band_types', 'capabilities',
3023                                                        'max_bands', 'max_color'))):
3024     @classmethod
3025     def parser(cls, buf, offset):
3026         meter_features = struct.unpack_from(
3027             ofproto.OFP_METER_FEATURES_PACK_STR, buf, offset)
3028         stats = cls(*meter_features)
3029         stats.length = ofproto.OFP_METER_FEATURES_SIZE
3030         return stats
3031
3032
3033 @_set_stats_type(ofproto.OFPMP_METER_FEATURES, OFPMeterFeaturesStats)
3034 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
3035 class OFPMeterFeaturesStatsRequest(OFPMultipartRequest):
3036     """
3037     Meter features statistics request message
3038
3039     The controller uses this message to query the set of features of the
3040     metering subsystem.
3041
3042     ================ ======================================================
3043     Attribute        Description
3044     ================ ======================================================
3045     flags            Zero or ``OFPMPF_REQ_MORE``
3046     ================ ======================================================
3047
3048     Example::
3049
3050         def send_meter_features_stats_request(self, datapath):
3051             ofp_parser = datapath.ofproto_parser
3052
3053             req = ofp_parser.OFPMeterFeaturesStatsRequest(datapath, 0)
3054             datapath.send_msg(req)
3055     """
3056
3057     def __init__(self, datapath, flags=0, type_=None):
3058         super(OFPMeterFeaturesStatsRequest, self).__init__(datapath, flags)
3059
3060
3061 @OFPMultipartReply.register_stats_type()
3062 @_set_stats_type(ofproto.OFPMP_METER_FEATURES, OFPMeterFeaturesStats)
3063 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
3064 class OFPMeterFeaturesStatsReply(OFPMultipartReply):
3065     """
3066     Meter features statistics reply message
3067
3068     The switch responds with this message to a meter features statistics
3069     request.
3070
3071     ================ ======================================================
3072     Attribute        Description
3073     ================ ======================================================
3074     body             List of ``OFPMeterFeaturesStats`` instance
3075     ================ ======================================================
3076
3077     Example::
3078
3079         @set_ev_cls(ofp_event.EventOFPMeterFeaturesStatsReply, MAIN_DISPATCHER)
3080         def meter_features_stats_reply_handler(self, ev):
3081             features = []
3082             for stat in ev.msg.body:
3083                 features.append('max_meter=%d band_types=0x%08x '
3084                                 'capabilities=0x%08x max_bands=%d '
3085                                 'max_color=%d' %
3086                                 (stat.max_meter, stat.band_types,
3087                                  stat.capabilities, stat.max_bands,
3088                                  stat.max_color))
3089             self.logger.debug('MeterFeaturesStats: %s', features)
3090     """
3091
3092     def __init__(self, datapath, type_=None, **kwargs):
3093         super(OFPMeterFeaturesStatsReply, self).__init__(datapath, **kwargs)
3094
3095
3096 class OFPFlowUpdate(StringifyMixin):
3097     def __init__(self, length, event):
3098         super(OFPFlowUpdate, self).__init__()
3099         self.length = length
3100         self.event = event
3101
3102
3103 class OFPFlowUpdateHeader(OFPFlowUpdate):
3104     _EVENT = {}
3105
3106     @staticmethod
3107     def register_flow_update_event(event, length):
3108         def _register_flow_update_event(cls):
3109             OFPFlowUpdateHeader._EVENT[event] = cls
3110             cls.cls_flow_update_event = event
3111             cls.cls_flow_update_length = length
3112             return cls
3113         return _register_flow_update_event
3114
3115     def __init__(self, length=None, event=None):
3116         cls = self.__class__
3117         super(OFPFlowUpdateHeader, self).__init__(length,
3118                                                   cls.cls_flow_update_event)
3119         self.length = length
3120
3121     @classmethod
3122     def parser(cls, buf, offset):
3123         length, event = struct.unpack_from(
3124             ofproto.OFP_FLOW_UPDATE_HEADER_PACK_STR, buf, offset)
3125         cls_ = cls._EVENT[event]
3126         return cls_.parser(buf, offset)
3127
3128
3129 @OFPFlowUpdateHeader.register_flow_update_event(
3130     ofproto.OFPFME_INITIAL, ofproto.OFP_FLOW_UPDATE_FULL_SIZE)
3131 @OFPFlowUpdateHeader.register_flow_update_event(
3132     ofproto.OFPFME_ADDED, ofproto.OFP_FLOW_UPDATE_FULL_SIZE)
3133 @OFPFlowUpdateHeader.register_flow_update_event(
3134     ofproto.OFPFME_REMOVED, ofproto.OFP_FLOW_UPDATE_FULL_SIZE)
3135 @OFPFlowUpdateHeader.register_flow_update_event(
3136     ofproto.OFPFME_MODIFIED, ofproto.OFP_FLOW_UPDATE_FULL_SIZE)
3137 class OFPFlowUpdateFull(OFPFlowUpdateHeader):
3138     def __init__(self, length=None, event=None, table_id=None, reason=None,
3139                  idle_timeout=None, hard_timeout=None, priority=None,
3140                  cookie=None, match=None, instructions=None):
3141         instructions = instructions if instructions else []
3142         super(OFPFlowUpdateFull, self).__init__(length, event)
3143         self.table_id = table_id
3144         self.reason = reason
3145         self.idle_timeout = idle_timeout
3146         self.hard_timeout = hard_timeout
3147         self.priority = priority
3148         self.cookie = cookie
3149         self.match = match
3150         assert (event != ofproto.OFPFME_REMOVED or len(instructions) == 0)
3151         for i in instructions:
3152             assert isinstance(i, OFPInstruction)
3153         self.instructions = instructions
3154
3155     @classmethod
3156     def parser(cls, buf, offset):
3157         (length, event, table_id, reason, idle_timeout, hard_timeout, priority,
3158          cookie) = struct.unpack_from(ofproto.OFP_FLOW_UPDATE_FULL_0_PACK_STR,
3159                                       buf, offset)
3160         offset += ofproto.OFP_FLOW_UPDATE_FULL_0_SIZE
3161         assert cls.cls_flow_update_length <= length
3162         assert cls.cls_flow_update_event == event
3163
3164         match = OFPMatch.parser(buf, offset)
3165         match_length = utils.round_up(match.length, 8)
3166         offset += match_length
3167
3168         inst_length = (length - ofproto.OFP_FLOW_UPDATE_FULL_0_SIZE -
3169                        match_length)
3170         instructions = []
3171         while inst_length > 0:
3172             inst = OFPInstruction.parser(buf, offset)
3173             instructions.append(inst)
3174             offset += inst.len
3175             inst_length -= inst.len
3176
3177         return cls(length, event, table_id, reason, idle_timeout,
3178                    hard_timeout, priority, cookie, match, instructions)
3179
3180
3181 @OFPFlowUpdateHeader.register_flow_update_event(
3182     ofproto.OFPFME_ABBREV, ofproto.OFP_FLOW_UPDATE_ABBREV_SIZE)
3183 class OFPFlowUpdateAbbrev(OFPFlowUpdateHeader):
3184     def __init__(self, length=None, event=None, xid=None):
3185         super(OFPFlowUpdateAbbrev, self).__init__(length, event)
3186         self.xid = xid
3187
3188     @classmethod
3189     def parser(cls, buf, offset):
3190         length, event, xid = struct.unpack_from(
3191             ofproto.OFP_FLOW_UPDATE_ABBREV_PACK_STR, buf, offset)
3192         assert cls.cls_flow_update_length == length
3193         assert cls.cls_flow_update_event == event
3194
3195         return cls(length, event, xid)
3196
3197
3198 @OFPFlowUpdateHeader.register_flow_update_event(
3199     ofproto.OFPFME_PAUSED, ofproto.OFP_FLOW_UPDATE_PAUSED_SIZE)
3200 @OFPFlowUpdateHeader.register_flow_update_event(
3201     ofproto.OFPFME_RESUMED, ofproto.OFP_FLOW_UPDATE_PAUSED_SIZE)
3202 class OFPFlowUpdatePaused(OFPFlowUpdateHeader):
3203     @classmethod
3204     def parser(cls, buf, offset):
3205         length, event = struct.unpack_from(
3206             ofproto.OFP_FLOW_UPDATE_PAUSED_PACK_STR, buf, offset)
3207         assert cls.cls_flow_update_length == length
3208         assert cls.cls_flow_update_event == event
3209
3210         return cls(length, event)
3211
3212
3213 class OFPFlowMonitorRequestBase(OFPMultipartRequest):
3214     def __init__(self, datapath, flags, monitor_id, out_port, out_group,
3215                  monitor_flags, table_id, command, match):
3216         super(OFPFlowMonitorRequestBase, self).__init__(datapath, flags)
3217         self.monitor_id = monitor_id
3218         self.out_port = out_port
3219         self.out_group = out_group
3220         self.monitor_flags = monitor_flags
3221         self.table_id = table_id
3222         self.command = command
3223         self.match = match
3224
3225     def _serialize_stats_body(self):
3226         offset = ofproto.OFP_MULTIPART_REQUEST_SIZE
3227         msg_pack_into(ofproto.OFP_FLOW_MONITOR_REQUEST_0_PACK_STR, self.buf,
3228                       offset, self.monitor_id, self.out_port, self.out_group,
3229                       self.monitor_flags, self.table_id, self.command)
3230
3231         offset += ofproto.OFP_FLOW_MONITOR_REQUEST_0_SIZE
3232         self.match.serialize(self.buf, offset)
3233
3234
3235 @_set_stats_type(ofproto.OFPMP_FLOW_MONITOR, OFPFlowUpdateHeader)
3236 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
3237 class OFPFlowMonitorRequest(OFPFlowMonitorRequestBase):
3238     """
3239     Flow monitor request message
3240
3241     The controller uses this message to query flow monitors.
3242
3243     ================ ======================================================
3244     Attribute        Description
3245     ================ ======================================================
3246     flags            Zero or ``OFPMPF_REQ_MORE``
3247     monitor_id       Controller-assigned ID for this monitor
3248     out_port         Require matching entries to include this as an output
3249                      port
3250     out_group        Require matching entries to include this as an output
3251                      group
3252     monitor_flags    Bitmap of the following flags.
3253
3254                      | OFPFMF_INITIAL
3255                      | OFPFMF_ADD
3256                      | OFPFMF_REMOVED
3257                      | OFPFMF_MODIFY
3258                      | OFPFMF_INSTRUCTIONS
3259                      | OFPFMF_NO_ABBREV
3260                      | OFPFMF_ONLY_OWN
3261     table_id         ID of table to monitor
3262     command          One of the following values.
3263
3264                      | OFPFMC_ADD
3265                      | OFPFMC_MODIFY
3266                      | OFPFMC_DELETE
3267     match            Instance of ``OFPMatch``
3268     ================ ======================================================
3269
3270     Example::
3271
3272         def send_flow_monitor_request(self, datapath):
3273             ofp = datapath.ofproto
3274             ofp_parser = datapath.ofproto_parser
3275
3276             monitor_flags = [ofp.OFPFMF_INITIAL, ofp.OFPFMF_ONLY_OWN]
3277             match = ofp_parser.OFPMatch(in_port=1)
3278             req = ofp_parser.OFPFlowMonitorRequest(datapath, 0, 10000,
3279                                                    ofp.OFPP_ANY, ofp.OFPG_ANY,
3280                                                    monitor_flags,
3281                                                    ofp.OFPTT_ALL,
3282                                                    ofp.OFPFMC_ADD, match)
3283             datapath.send_msg(req)
3284     """
3285
3286     def __init__(self, datapath, flags=0, monitor_id=0,
3287                  out_port=ofproto.OFPP_ANY, out_group=ofproto.OFPG_ANY,
3288                  monitor_flags=0, table_id=ofproto.OFPTT_ALL,
3289                  command=ofproto.OFPFMC_ADD, match=None, type_=None):
3290         if match is None:
3291             match = OFPMatch()
3292         super(OFPFlowMonitorRequest, self).__init__(datapath, flags,
3293                                                     monitor_id, out_port,
3294                                                     out_group, monitor_flags,
3295                                                     table_id, command, match)
3296
3297
3298 @OFPMultipartReply.register_stats_type()
3299 @_set_stats_type(ofproto.OFPMP_FLOW_MONITOR, OFPFlowUpdateHeader)
3300 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
3301 class OFPFlowMonitorReply(OFPMultipartReply):
3302     """
3303     Flow monitor reply message
3304
3305     The switch responds with this message to a flow monitor request.
3306
3307     ================ ======================================================
3308     Attribute        Description
3309     ================ ======================================================
3310     body             List of list of the following class instance.
3311
3312                      | OFPFlowMonitorFull
3313                      | OFPFlowMonitorAbbrev
3314                      | OFPFlowMonitorPaused
3315     ================ ======================================================
3316
3317     Example::
3318
3319         @set_ev_cls(ofp_event.EventOFPFlowMonitorReply, MAIN_DISPATCHER)
3320         def flow_monitor_reply_handler(self, ev):
3321             msg = ev.msg
3322             dp = msg.datapath
3323             ofp = dp.ofproto
3324             flow_updates = []
3325
3326             for update in msg.body:
3327                 update_str = 'length=%d event=%d' %
3328                              (update.length, update.event)
3329                 if (update.event == ofp.OFPFME_INITIAL or
3330                     update.event == ofp.OFPFME_ADDED or
3331                     update.event == ofp.OFPFME_REMOVED or
3332                     update.event == ofp.OFPFME_MODIFIED):
3333                     update_str += 'table_id=%d reason=%d idle_timeout=%d '
3334                                   'hard_timeout=%d priority=%d cookie=%d '
3335                                   'match=%d instructions=%s' %
3336                                   (update.table_id, update.reason,
3337                                    update.idle_timeout, update.hard_timeout,
3338                                    update.priority, update.cookie,
3339                                    update.match, update.instructions)
3340                 elif update.event == ofp.OFPFME_ABBREV:
3341                     update_str += 'xid=%d' % (update.xid)
3342                 flow_updates.append(update_str)
3343             self.logger.debug('FlowUpdates: %s', flow_updates)
3344     """
3345
3346     def __init__(self, datapath, type_=None, **kwargs):
3347         super(OFPFlowMonitorReply, self).__init__(datapath, **kwargs)
3348
3349
3350 class OFPExperimenterMultipart(ofproto_parser.namedtuple(
3351                                'OFPExperimenterMultipart',
3352                                ('experimenter', 'exp_type', 'data'))):
3353     """
3354     The body of OFPExperimenterStatsReply multipart messages.
3355
3356     ================ ======================================================
3357     Attribute        Description
3358     ================ ======================================================
3359     experimenter     Experimenter ID
3360     exp_type         Experimenter defined
3361     data             Experimenter defined additional data
3362     ================ ======================================================
3363     """
3364
3365     @classmethod
3366     def parser(cls, buf, offset):
3367         args = struct.unpack_from(
3368             ofproto.OFP_EXPERIMENTER_MULTIPART_HEADER_PACK_STR, buf,
3369             offset)
3370         args = list(args)
3371         args.append(buf[offset +
3372                         ofproto.OFP_EXPERIMENTER_MULTIPART_HEADER_SIZE:])
3373         stats = cls(*args)
3374         stats.length = ofproto.OFP_METER_FEATURES_SIZE
3375         return stats
3376
3377     def serialize(self):
3378         buf = bytearray()
3379         msg_pack_into(ofproto.OFP_EXPERIMENTER_MULTIPART_HEADER_PACK_STR,
3380                       buf, 0,
3381                       self.experimenter, self.exp_type)
3382         return buf + self.data
3383
3384
3385 class OFPExperimenterStatsRequestBase(OFPMultipartRequest):
3386     def __init__(self, datapath, flags,
3387                  experimenter, exp_type,
3388                  type_=None):
3389         super(OFPExperimenterStatsRequestBase, self).__init__(datapath, flags)
3390         self.experimenter = experimenter
3391         self.exp_type = exp_type
3392
3393
3394 @_set_stats_type(ofproto.OFPMP_EXPERIMENTER, OFPExperimenterMultipart)
3395 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
3396 class OFPExperimenterStatsRequest(OFPExperimenterStatsRequestBase):
3397     """
3398     Experimenter multipart request message
3399
3400     ================ ======================================================
3401     Attribute        Description
3402     ================ ======================================================
3403     flags            Zero or ``OFPMPF_REQ_MORE``
3404     experimenter     Experimenter ID
3405     exp_type         Experimenter defined
3406     data             Experimenter defined additional data
3407     ================ ======================================================
3408     """
3409
3410     def __init__(self, datapath, flags,
3411                  experimenter, exp_type, data,
3412                  type_=None):
3413         super(OFPExperimenterStatsRequest, self).__init__(datapath, flags,
3414                                                           experimenter,
3415                                                           exp_type, type_)
3416         self.data = data
3417
3418     def _serialize_stats_body(self):
3419         body = OFPExperimenterMultipart(experimenter=self.experimenter,
3420                                         exp_type=self.exp_type,
3421                                         data=self.data)
3422         self.buf += body.serialize()
3423
3424
3425 @OFPMultipartReply.register_stats_type(body_single_struct=True)
3426 @_set_stats_type(ofproto.OFPMP_EXPERIMENTER, OFPExperimenterMultipart)
3427 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
3428 class OFPExperimenterStatsReply(OFPMultipartReply):
3429     """
3430     Experimenter multipart reply message
3431
3432     ================ ======================================================
3433     Attribute        Description
3434     ================ ======================================================
3435     body             An ``OFPExperimenterMultipart`` instance
3436     ================ ======================================================
3437     """
3438
3439     def __init__(self, datapath, type_=None, **kwargs):
3440         super(OFPExperimenterStatsReply, self).__init__(datapath, **kwargs)
3441
3442
3443 class OFPFlowStats(StringifyMixin):
3444     def __init__(self, table_id=None, duration_sec=None, duration_nsec=None,
3445                  priority=None, idle_timeout=None, hard_timeout=None,
3446                  flags=None, importance=None, cookie=None, packet_count=None,
3447                  byte_count=None, match=None, instructions=None,
3448                  length=None):
3449         super(OFPFlowStats, self).__init__()
3450         self.table_id = table_id
3451         self.duration_sec = duration_sec
3452         self.duration_nsec = duration_nsec
3453         self.priority = priority
3454         self.idle_timeout = idle_timeout
3455         self.hard_timeout = hard_timeout
3456         self.flags = flags
3457         self.importance = importance
3458         self.cookie = cookie
3459         self.packet_count = packet_count
3460         self.byte_count = byte_count
3461         self.match = match
3462         self.instructions = instructions
3463         self.length = length
3464
3465     @classmethod
3466     def parser(cls, buf, offset):
3467         flow_stats = cls()
3468
3469         (flow_stats.length, flow_stats.table_id,
3470          flow_stats.duration_sec, flow_stats.duration_nsec,
3471          flow_stats.priority, flow_stats.idle_timeout,
3472          flow_stats.hard_timeout, flow_stats.flags,
3473          flow_stats.importance, flow_stats.cookie,
3474          flow_stats.packet_count,
3475          flow_stats.byte_count) = struct.unpack_from(
3476             ofproto.OFP_FLOW_STATS_0_PACK_STR, buf, offset)
3477         offset += ofproto.OFP_FLOW_STATS_0_SIZE
3478
3479         flow_stats.match = OFPMatch.parser(buf, offset)
3480         match_length = utils.round_up(flow_stats.match.length, 8)
3481         inst_length = (flow_stats.length - (ofproto.OFP_FLOW_STATS_SIZE -
3482                                             ofproto.OFP_MATCH_SIZE +
3483                                             match_length))
3484         offset += match_length
3485         instructions = []
3486         while inst_length > 0:
3487             inst = OFPInstruction.parser(buf, offset)
3488             instructions.append(inst)
3489             offset += inst.len
3490             inst_length -= inst.len
3491
3492         flow_stats.instructions = instructions
3493         return flow_stats
3494
3495
3496 class OFPFlowStatsRequestBase(OFPMultipartRequest):
3497     def __init__(self, datapath, flags, table_id, out_port, out_group,
3498                  cookie, cookie_mask, match):
3499         super(OFPFlowStatsRequestBase, self).__init__(datapath, flags)
3500         self.table_id = table_id
3501         self.out_port = out_port
3502         self.out_group = out_group
3503         self.cookie = cookie
3504         self.cookie_mask = cookie_mask
3505         self.match = match
3506
3507     def _serialize_stats_body(self):
3508         offset = ofproto.OFP_MULTIPART_REQUEST_SIZE
3509         msg_pack_into(ofproto.OFP_FLOW_STATS_REQUEST_0_PACK_STR,
3510                       self.buf, offset, self.table_id, self.out_port,
3511                       self.out_group, self.cookie, self.cookie_mask)
3512
3513         offset += ofproto.OFP_FLOW_STATS_REQUEST_0_SIZE
3514         self.match.serialize(self.buf, offset)
3515
3516
3517 @_set_stats_type(ofproto.OFPMP_FLOW, OFPFlowStats)
3518 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
3519 class OFPFlowStatsRequest(OFPFlowStatsRequestBase):
3520     """
3521     Individual flow statistics request message
3522
3523     The controller uses this message to query individual flow statistics.
3524
3525     ================ ======================================================
3526     Attribute        Description
3527     ================ ======================================================
3528     flags            Zero or ``OFPMPF_REQ_MORE``
3529     table_id         ID of table to read
3530     out_port         Require matching entries to include this as an output
3531                      port
3532     out_group        Require matching entries to include this as an output
3533                      group
3534     cookie           Require matching entries to contain this cookie value
3535     cookie_mask      Mask used to restrict the cookie bits that must match
3536     match            Instance of ``OFPMatch``
3537     ================ ======================================================
3538
3539     Example::
3540
3541         def send_flow_stats_request(self, datapath):
3542             ofp = datapath.ofproto
3543             ofp_parser = datapath.ofproto_parser
3544
3545             cookie = cookie_mask = 0
3546             match = ofp_parser.OFPMatch(in_port=1)
3547             req = ofp_parser.OFPFlowStatsRequest(datapath, 0,
3548                                                  ofp.OFPTT_ALL,
3549                                                  ofp.OFPP_ANY, ofp.OFPG_ANY,
3550                                                  cookie, cookie_mask,
3551                                                  match)
3552             datapath.send_msg(req)
3553     """
3554
3555     def __init__(self, datapath, flags=0, table_id=ofproto.OFPTT_ALL,
3556                  out_port=ofproto.OFPP_ANY,
3557                  out_group=ofproto.OFPG_ANY,
3558                  cookie=0, cookie_mask=0, match=None, type_=None):
3559         if match is None:
3560             match = OFPMatch()
3561         super(OFPFlowStatsRequest, self).__init__(datapath, flags, table_id,
3562                                                   out_port, out_group,
3563                                                   cookie, cookie_mask, match)
3564
3565
3566 @OFPMultipartReply.register_stats_type()
3567 @_set_stats_type(ofproto.OFPMP_FLOW, OFPFlowStats)
3568 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
3569 class OFPFlowStatsReply(OFPMultipartReply):
3570     """
3571     Individual flow statistics reply message
3572
3573     The switch responds with this message to an individual flow statistics
3574     request.
3575
3576     ================ ======================================================
3577     Attribute        Description
3578     ================ ======================================================
3579     body             List of ``OFPFlowStats`` instance
3580     ================ ======================================================
3581
3582     Example::
3583
3584         @set_ev_cls(ofp_event.EventOFPFlowStatsReply, MAIN_DISPATCHER)
3585         def flow_stats_reply_handler(self, ev):
3586             flows = []
3587             for stat in ev.msg.body:
3588                 flows.append('table_id=%s '
3589                              'duration_sec=%d duration_nsec=%d '
3590                              'priority=%d '
3591                              'idle_timeout=%d hard_timeout=%d flags=0x%04x '
3592                              'importance=%d cookie=%d packet_count=%d '
3593                              'byte_count=%d match=%s instructions=%s' %
3594                              (stat.table_id,
3595                               stat.duration_sec, stat.duration_nsec,
3596                               stat.priority,
3597                               stat.idle_timeout, stat.hard_timeout,
3598                               stat.flags, stat.importance,
3599                               stat.cookie, stat.packet_count, stat.byte_count,
3600                               stat.match, stat.instructions))
3601             self.logger.debug('FlowStats: %s', flows)
3602     """
3603
3604     def __init__(self, datapath, type_=None, **kwargs):
3605         super(OFPFlowStatsReply, self).__init__(datapath, **kwargs)
3606
3607
3608 class OFPAggregateStats(ofproto_parser.namedtuple('OFPAggregateStats', (
3609         'packet_count', 'byte_count', 'flow_count'))):
3610     @classmethod
3611     def parser(cls, buf, offset):
3612         agg = struct.unpack_from(
3613             ofproto.OFP_AGGREGATE_STATS_REPLY_PACK_STR, buf, offset)
3614         stats = cls(*agg)
3615         stats.length = ofproto.OFP_AGGREGATE_STATS_REPLY_SIZE
3616         return stats
3617
3618
3619 @_set_stats_type(ofproto.OFPMP_AGGREGATE, OFPAggregateStats)
3620 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
3621 class OFPAggregateStatsRequest(OFPFlowStatsRequestBase):
3622     """
3623     Aggregate flow statistics request message
3624
3625     The controller uses this message to query aggregate flow statictics.
3626
3627     ================ ======================================================
3628     Attribute        Description
3629     ================ ======================================================
3630     flags            Zero or ``OFPMPF_REQ_MORE``
3631     table_id         ID of table to read
3632     out_port         Require matching entries to include this as an output
3633                      port
3634     out_group        Require matching entries to include this as an output
3635                      group
3636     cookie           Require matching entries to contain this cookie value
3637     cookie_mask      Mask used to restrict the cookie bits that must match
3638     match            Instance of ``OFPMatch``
3639     ================ ======================================================
3640
3641     Example::
3642
3643         def send_aggregate_stats_request(self, datapath):
3644             ofp = datapath.ofproto
3645             ofp_parser = datapath.ofproto_parser
3646
3647             cookie = cookie_mask = 0
3648             match = ofp_parser.OFPMatch(in_port=1)
3649             req = ofp_parser.OFPAggregateStatsRequest(datapath, 0,
3650                                                       ofp.OFPTT_ALL,
3651                                                       ofp.OFPP_ANY,
3652                                                       ofp.OFPG_ANY,
3653                                                       cookie, cookie_mask,
3654                                                       match)
3655             datapath.send_msg(req)
3656     """
3657
3658     def __init__(self, datapath, flags, table_id, out_port, out_group,
3659                  cookie, cookie_mask, match, type_=None):
3660         super(OFPAggregateStatsRequest, self).__init__(datapath,
3661                                                        flags,
3662                                                        table_id,
3663                                                        out_port,
3664                                                        out_group,
3665                                                        cookie,
3666                                                        cookie_mask,
3667                                                        match)
3668
3669
3670 @OFPMultipartReply.register_stats_type(body_single_struct=True)
3671 @_set_stats_type(ofproto.OFPMP_AGGREGATE, OFPAggregateStats)
3672 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
3673 class OFPAggregateStatsReply(OFPMultipartReply):
3674     """
3675     Aggregate flow statistics reply message
3676
3677     The switch responds with this message to an aggregate flow statistics
3678     request.
3679
3680     ================ ======================================================
3681     Attribute        Description
3682     ================ ======================================================
3683     body             Instance of ``OFPAggregateStats``
3684     ================ ======================================================
3685
3686     Example::
3687
3688         @set_ev_cls(ofp_event.EventOFPAggregateStatsReply, MAIN_DISPATCHER)
3689         def aggregate_stats_reply_handler(self, ev):
3690             body = ev.msg.body
3691
3692             self.logger.debug('AggregateStats: packet_count=%d byte_count=%d '
3693                               'flow_count=%d',
3694                               body.packet_count, body.byte_count,
3695                               body.flow_count)
3696     """
3697
3698     def __init__(self, datapath, type_=None, **kwargs):
3699         super(OFPAggregateStatsReply, self).__init__(datapath, **kwargs)
3700
3701
3702 class OFPTableStats(ofproto_parser.namedtuple('OFPTableStats', (
3703         'table_id', 'active_count', 'lookup_count',
3704         'matched_count'))):
3705     @classmethod
3706     def parser(cls, buf, offset):
3707         tbl = struct.unpack_from(ofproto.OFP_TABLE_STATS_PACK_STR,
3708                                  buf, offset)
3709         stats = cls(*tbl)
3710         stats.length = ofproto.OFP_TABLE_STATS_SIZE
3711         return stats
3712
3713
3714 @_set_stats_type(ofproto.OFPMP_TABLE, OFPTableStats)
3715 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
3716 class OFPTableStatsRequest(OFPMultipartRequest):
3717     """
3718     Table statistics request message
3719
3720     The controller uses this message to query flow table statictics.
3721
3722     ================ ======================================================
3723     Attribute        Description
3724     ================ ======================================================
3725     flags            Zero or ``OFPMPF_REQ_MORE``
3726     ================ ======================================================
3727
3728     Example::
3729
3730         def send_table_stats_request(self, datapath):
3731             ofp_parser = datapath.ofproto_parser
3732
3733             req = ofp_parser.OFPTableStatsRequest(datapath, 0)
3734             datapath.send_msg(req)
3735     """
3736
3737     def __init__(self, datapath, flags, type_=None):
3738         super(OFPTableStatsRequest, self).__init__(datapath, flags)
3739
3740
3741 @OFPMultipartReply.register_stats_type()
3742 @_set_stats_type(ofproto.OFPMP_TABLE, OFPTableStats)
3743 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
3744 class OFPTableStatsReply(OFPMultipartReply):
3745     """
3746     Table statistics reply message
3747
3748     The switch responds with this message to a table statistics request.
3749
3750     ================ ======================================================
3751     Attribute        Description
3752     ================ ======================================================
3753     body             List of ``OFPTableStats`` instance
3754     ================ ======================================================
3755
3756     Example::
3757
3758         @set_ev_cls(ofp_event.EventOFPTableStatsReply, MAIN_DISPATCHER)
3759         def table_stats_reply_handler(self, ev):
3760             tables = []
3761             for stat in ev.msg.body:
3762                 tables.append('table_id=%d active_count=%d lookup_count=%d '
3763                               ' matched_count=%d' %
3764                               (stat.table_id, stat.active_count,
3765                                stat.lookup_count, stat.matched_count))
3766             self.logger.debug('TableStats: %s', tables)
3767     """
3768
3769     def __init__(self, datapath, type_=None, **kwargs):
3770         super(OFPTableStatsReply, self).__init__(datapath, **kwargs)
3771
3772
3773 class OFPPortStatsProp(OFPPropBase):
3774     _TYPES = {}
3775
3776
3777 @OFPPortStatsProp.register_type(ofproto.OFPPSPT_ETHERNET)
3778 class OFPPortStatsPropEthernet(OFPPortStatsProp):
3779     def __init__(self, type_=None, length=None, rx_frame_err=None,
3780                  rx_over_err=None, rx_crc_err=None, collisions=None):
3781         self.type = type_
3782         self.length = length
3783         self.rx_frame_err = rx_frame_err
3784         self.rx_over_err = rx_over_err
3785         self.rx_crc_err = rx_crc_err
3786         self.collisions = collisions
3787
3788     @classmethod
3789     def parser(cls, buf):
3790         ether = cls()
3791         (ether.type, ether.length, ether.rx_frame_err, ether.rx_over_err,
3792          ether.rx_crc_err, ether.collisions) = struct.unpack_from(
3793             ofproto.OFP_PORT_STATS_PROP_ETHERNET_PACK_STR, buf, 0)
3794         return ether
3795
3796
3797 @OFPPortStatsProp.register_type(ofproto.OFPPSPT_OPTICAL)
3798 class OFPPortStatsPropOptical(OFPPortStatsProp):
3799     def __init__(self, type_=None, length=None, flags=None,
3800                  tx_freq_lmda=None, tx_offset=None, tx_grid_span=None,
3801                  rx_freq_lmda=None, rx_offset=None, rx_grid_span=None,
3802                  tx_pwr=None, rx_pwr=None, bias_current=None,
3803                  temperature=None):
3804         self.type = type_
3805         self.length = length
3806         self.flags = flags
3807         self.tx_freq_lmda = tx_freq_lmda
3808         self.tx_offset = tx_offset
3809         self.tx_grid_span = tx_grid_span
3810         self.rx_freq_lmda = rx_freq_lmda
3811         self.rx_offset = rx_offset
3812         self.rx_grid_span = rx_grid_span
3813         self.tx_pwr = tx_pwr
3814         self.rx_pwr = rx_pwr
3815         self.bias_current = bias_current
3816         self.temperature = temperature
3817
3818     @classmethod
3819     def parser(cls, buf):
3820         optical = cls()
3821         (optical.type, optical.length, optical.flags,
3822          optical.tx_freq_lmda, optical.tx_offset, optical.tx_grid_span,
3823          optical.rx_freq_lmda, optical.rx_offset, optical.rx_grid_span,
3824          optical.tx_pwr, optical.rx_pwr, optical.bias_current,
3825          optical.temperature) = struct.unpack_from(
3826             ofproto.OFP_PORT_STATS_PROP_OPTICAL_PACK_STR, buf, 0)
3827         return optical
3828
3829
3830 @OFPPortStatsProp.register_type(ofproto.OFPPSPT_EXPERIMENTER)
3831 class OFPPortStatsPropExperimenter(OFPPropCommonExperimenter4ByteData):
3832     pass
3833
3834
3835 class OFPPortStats(StringifyMixin):
3836     def __init__(self, length=None, port_no=None, duration_sec=None,
3837                  duration_nsec=None, rx_packets=None, tx_packets=None,
3838                  rx_bytes=None, tx_bytes=None, rx_dropped=None,
3839                  tx_dropped=None, rx_errors=None, tx_errors=None,
3840                  properties=None):
3841         super(OFPPortStats, self).__init__()
3842         self.length = length
3843         self.port_no = port_no
3844         self.duration_sec = duration_sec
3845         self.duration_nsec = duration_nsec
3846         self.rx_packets = rx_packets
3847         self.tx_packets = tx_packets
3848         self.rx_bytes = rx_bytes
3849         self.tx_bytes = tx_bytes
3850         self.rx_dropped = rx_dropped
3851         self.tx_dropped = tx_dropped
3852         self.rx_errors = rx_errors
3853         self.tx_errors = tx_errors
3854         self.properties = properties
3855
3856     @classmethod
3857     def parser(cls, buf, offset):
3858         (length, port_no, duration_sec, duration_nsec, rx_packets,
3859          tx_packets, rx_bytes, tx_bytes, rx_dropped, tx_dropped,
3860          rx_errors, tx_errors) = struct.unpack_from(
3861             ofproto.OFP_PORT_STATS_PACK_STR, buf, offset)
3862         props = []
3863         rest = buf[offset + ofproto.OFP_PORT_STATS_SIZE:offset + length]
3864         while rest:
3865             p, rest = OFPPortStatsProp.parse(rest)
3866             props.append(p)
3867         stats = cls(length, port_no, duration_sec, duration_nsec, rx_packets,
3868                     tx_packets, rx_bytes, tx_bytes, rx_dropped, tx_dropped,
3869                     rx_errors, tx_errors, props)
3870         return stats
3871
3872
3873 @_set_stats_type(ofproto.OFPMP_PORT_STATS, OFPPortStats)
3874 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
3875 class OFPPortStatsRequest(OFPMultipartRequest):
3876     """
3877     Port statistics request message
3878
3879     The controller uses this message to query information about ports
3880     statistics.
3881
3882     ================ ======================================================
3883     Attribute        Description
3884     ================ ======================================================
3885     flags            Zero or ``OFPMPF_REQ_MORE``
3886     port_no          Port number to read (OFPP_ANY to all ports)
3887     ================ ======================================================
3888
3889     Example::
3890
3891         def send_port_stats_request(self, datapath):
3892             ofp = datapath.ofproto
3893             ofp_parser = datapath.ofproto_parser
3894
3895             req = ofp_parser.OFPPortStatsRequest(datapath, 0, ofp.OFPP_ANY)
3896             datapath.send_msg(req)
3897     """
3898
3899     def __init__(self, datapath, flags, port_no, type_=None):
3900         super(OFPPortStatsRequest, self).__init__(datapath, flags)
3901         self.port_no = port_no
3902
3903     def _serialize_stats_body(self):
3904         msg_pack_into(ofproto.OFP_PORT_STATS_REQUEST_PACK_STR,
3905                       self.buf,
3906                       ofproto.OFP_MULTIPART_REQUEST_SIZE,
3907                       self.port_no)
3908
3909
3910 @OFPMultipartReply.register_stats_type()
3911 @_set_stats_type(ofproto.OFPMP_PORT_STATS, OFPPortStats)
3912 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
3913 class OFPPortStatsReply(OFPMultipartReply):
3914     """
3915     Port statistics reply message
3916
3917     The switch responds with this message to a port statistics request.
3918
3919     ================ ======================================================
3920     Attribute        Description
3921     ================ ======================================================
3922     body             List of ``OFPPortStats`` instance
3923     ================ ======================================================
3924
3925     Example::
3926
3927         @set_ev_cls(ofp_event.EventOFPPortStatsReply, MAIN_DISPATCHER)
3928         def port_stats_reply_handler(self, ev):
3929             ports = []
3930             for stat in ev.msg.body:
3931                 ports.append(stat.length, stat.port_no,
3932                              stat.duration_sec, stat.duration_nsec,
3933                              stat.rx_packets, stat.tx_packets,
3934                              stat.rx_bytes, stat.tx_bytes,
3935                              stat.rx_dropped, stat.tx_dropped,
3936                              stat.rx_errors, stat.tx_errors,
3937                              repr(stat.properties))
3938             self.logger.debug('PortStats: %s', ports)
3939     """
3940
3941     def __init__(self, datapath, type_=None, **kwargs):
3942         super(OFPPortStatsReply, self).__init__(datapath, **kwargs)
3943
3944
3945 @_set_msg_type(ofproto.OFPT_BARRIER_REQUEST)
3946 class OFPBarrierRequest(MsgBase):
3947     """
3948     Barrier request message
3949
3950     The controller sends this message to ensure message dependencies have
3951     been met or receive notifications for completed operations.
3952
3953     Example::
3954
3955         def send_barrier_request(self, datapath):
3956             ofp_parser = datapath.ofproto_parser
3957
3958             req = ofp_parser.OFPBarrierRequest(datapath)
3959             datapath.send_msg(req)
3960     """
3961
3962     def __init__(self, datapath):
3963         super(OFPBarrierRequest, self).__init__(datapath)
3964
3965
3966 @_register_parser
3967 @_set_msg_type(ofproto.OFPT_BARRIER_REPLY)
3968 class OFPBarrierReply(MsgBase):
3969     """
3970     Barrier reply message
3971
3972     The switch responds with this message to a barrier request.
3973
3974     Example::
3975
3976         @set_ev_cls(ofp_event.EventOFPBarrierReply, MAIN_DISPATCHER)
3977         def barrier_reply_handler(self, ev):
3978             self.logger.debug('OFPBarrierReply received')
3979     """
3980
3981     def __init__(self, datapath):
3982         super(OFPBarrierReply, self).__init__(datapath)
3983
3984
3985 @_register_parser
3986 @_set_msg_type(ofproto.OFPT_PORT_STATUS)
3987 class OFPPortStatus(MsgBase):
3988     """
3989     Port status message
3990
3991     The switch notifies controller of change of ports.
3992
3993     ================ ======================================================
3994     Attribute        Description
3995     ================ ======================================================
3996     reason           One of the following values.
3997
3998                      | OFPPR_ADD
3999                      | OFPPR_DELETE
4000                      | OFPPR_MODIFY
4001     desc             instance of ``OFPPort``
4002     ================ ======================================================
4003
4004     Example::
4005
4006         @set_ev_cls(ofp_event.EventOFPPortStatus, MAIN_DISPATCHER)
4007         def port_status_handler(self, ev):
4008             msg = ev.msg
4009             dp = msg.datapath
4010             ofp = dp.ofproto
4011
4012             if msg.reason == ofp.OFPPR_ADD:
4013                 reason = 'ADD'
4014             elif msg.reason == ofp.OFPPR_DELETE:
4015                 reason = 'DELETE'
4016             elif msg.reason == ofp.OFPPR_MODIFY:
4017                 reason = 'MODIFY'
4018             else:
4019                 reason = 'unknown'
4020
4021             self.logger.debug('OFPPortStatus received: reason=%s desc=%s',
4022                               reason, msg.desc)
4023     """
4024
4025     def __init__(self, datapath, reason=None, desc=None):
4026         super(OFPPortStatus, self).__init__(datapath)
4027         self.reason = reason
4028         self.desc = desc
4029
4030     @classmethod
4031     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
4032         msg = super(OFPPortStatus, cls).parser(datapath, version, msg_type,
4033                                                msg_len, xid, buf)
4034         msg.reason = struct.unpack_from(
4035             ofproto.OFP_PORT_STATUS_PACK_STR, msg.buf,
4036             ofproto.OFP_HEADER_SIZE)[0]
4037         msg.desc = OFPPort.parser(msg.buf, ofproto.OFP_PORT_STATUS_DESC_OFFSET)
4038         return msg
4039
4040
4041 @_register_parser
4042 @_set_msg_type(ofproto.OFPT_ROLE_STATUS)
4043 class OFPRoleStatus(MsgBase):
4044     """
4045     Role status message
4046
4047     The switch notifies controller of change of role.
4048
4049     ================ ======================================================
4050     Attribute        Description
4051     ================ ======================================================
4052     role             One of the following values.
4053
4054                      | OFPCR_ROLE_NOCHANGE
4055                      | OFPCR_ROLE_EQUAL
4056                      | OFPCR_ROLE_MASTER
4057     reason           One of the following values.
4058
4059                      | OFPCRR_MASTER_REQUEST
4060                      | OFPCRR_CONFIG
4061                      | OFPCRR_EXPERIMENTER
4062     generation_id    Master Election Generation ID
4063     properties       List of ``OFPRoleProp`` subclass instance
4064     ================ ======================================================
4065
4066     Example::
4067
4068         @set_ev_cls(ofp_event.EventOFPRoleStatus, MAIN_DISPATCHER)
4069         def role_status_handler(self, ev):
4070             msg = ev.msg
4071             dp = msg.datapath
4072             ofp = dp.ofproto
4073
4074             if msg.role == ofp.OFPCR_ROLE_NOCHANGE:
4075                 role = 'ROLE NOCHANGE'
4076             elif msg.role == ofp.OFPCR_ROLE_EQUAL:
4077                 role = 'ROLE EQUAL'
4078             elif msg.role == ofp.OFPCR_ROLE_MASTER:
4079                 role = 'ROLE MASTER'
4080             else:
4081                 role = 'unknown'
4082
4083             if msg.reason == ofp.OFPCRR_MASTER_REQUEST:
4084                 reason = 'MASTER REQUEST'
4085             elif msg.reason == ofp.OFPCRR_CONFIG:
4086                 reason = 'CONFIG'
4087             elif msg.reason == ofp.OFPCRR_EXPERIMENTER:
4088                 reason = 'EXPERIMENTER'
4089             else:
4090                 reason = 'unknown'
4091
4092             self.logger.debug('OFPRoleStatus received: role=%s reason=%s '
4093                               'generation_id=%d properties=%s', role, reason,
4094                               msg.generation_id, repr(msg.properties))
4095     """
4096
4097     def __init__(self, datapath, role=None, reason=None,
4098                  generation_id=None, properties=None):
4099         super(OFPRoleStatus, self).__init__(datapath)
4100         self.role = role
4101         self.reason = reason
4102         self.generation_id = generation_id
4103         self.properties = properties
4104
4105     @classmethod
4106     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
4107         msg = super(OFPRoleStatus, cls).parser(datapath, version, msg_type,
4108                                                msg_len, xid, buf)
4109         (msg.role, msg.reason, msg.generation_id) = struct.unpack_from(
4110             ofproto.OFP_ROLE_STATUS_PACK_STR, msg.buf,
4111             ofproto.OFP_HEADER_SIZE)
4112
4113         msg.properties = []
4114         rest = msg.buf[ofproto.OFP_ROLE_STATUS_SIZE:]
4115         while rest:
4116             p, rest = OFPRoleProp.parse(rest)
4117             msg.properties.append(p)
4118
4119         return msg
4120
4121
4122 @_register_parser
4123 @_set_msg_type(ofproto.OFPT_TABLE_STATUS)
4124 class OFPTableStatus(MsgBase):
4125     """
4126     Table status message
4127
4128     The switch notifies controller of change of table status.
4129
4130     ================ ======================================================
4131     Attribute        Description
4132     ================ ======================================================
4133     reason           One of the following values.
4134
4135                      | OFPTR_VACANCY_DOWN
4136                      | OFPTR_VACANCY_UP
4137     table            ``OFPTableDesc`` instance
4138     ================ ======================================================
4139
4140     Example::
4141
4142         @set_ev_cls(ofp_event.EventOFPTableStatus, MAIN_DISPATCHER)
4143         def table(self, ev):
4144             msg = ev.msg
4145             dp = msg.datapath
4146             ofp = dp.ofproto
4147
4148             if msg.reason == ofp.OFPTR_VACANCY_DOWN:
4149                 reason = 'VACANCY_DOWN'
4150             elif msg.reason == ofp.OFPTR_VACANCY_UP:
4151                 reason = 'VACANCY_UP'
4152             else:
4153                 reason = 'unknown'
4154
4155             self.logger.debug('OFPTableStatus received: reason=%s '
4156                               'table_id=%d config=0x%08x properties=%s',
4157                               reason, msg.table.table_id, msg.table.config,
4158                               repr(msg.table.properties))
4159     """
4160
4161     def __init__(self, datapath, reason=None, table=None):
4162         super(OFPTableStatus, self).__init__(datapath)
4163         self.reason = reason
4164         self.table = table
4165
4166     @classmethod
4167     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
4168         msg = super(OFPTableStatus, cls).parser(datapath, version, msg_type,
4169                                                 msg_len, xid, buf)
4170         (msg.reason,) = struct.unpack_from(ofproto.OFP_TABLE_STATUS_0_PACK_STR,
4171                                            msg.buf, ofproto.OFP_HEADER_SIZE)
4172
4173         msg.table = OFPTableDesc.parser(msg.buf,
4174                                         ofproto.OFP_TABLE_STATUS_0_SIZE)
4175
4176         return msg
4177
4178
4179 @_register_parser
4180 @_set_msg_type(ofproto.OFPT_REQUESTFORWARD)
4181 class OFPRequestForward(MsgInMsgBase):
4182     """
4183     Forwarded request message
4184
4185     The swtich forwards request messages from one controller to other
4186     controllers.
4187
4188     ================ ======================================================
4189     Attribute        Description
4190     ================ ======================================================
4191     request          ``OFPGroupMod`` or ``OFPMeterMod`` instance
4192     ================ ======================================================
4193
4194     Example::
4195
4196         @set_ev_cls(ofp_event.EventOFPRequestForward, MAIN_DISPATCHER)
4197         def request_forward_handler(self, ev):
4198             msg = ev.msg
4199             dp = msg.datapath
4200             ofp = dp.ofproto
4201
4202             if msg.request.msg_type == ofp.OFPT_GROUP_MOD:
4203                 self.logger.debug(
4204                     'OFPRequestForward received: request=OFPGroupMod('
4205                     'command=%d, type=%d, group_id=%d, buckets=%s)',
4206                     msg.request.command, msg.request.type,
4207                     msg.request.group_id, msg.request.buckets)
4208             elif msg.request.msg_type == ofp.OFPT_METER_MOD:
4209                 self.logger.debug(
4210                     'OFPRequestForward received: request=OFPMeterMod('
4211                     'command=%d, flags=%d, meter_id=%d, bands=%s)',
4212                     msg.request.command, msg.request.flags,
4213                     msg.request.meter_id, msg.request.bands)
4214             else:
4215                 self.logger.debug(
4216                     'OFPRequestForward received: request=Unknown')
4217     """
4218
4219     def __init__(self, datapath, request=None):
4220         super(OFPRequestForward, self).__init__(datapath)
4221         self.request = request
4222
4223     @classmethod
4224     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
4225         msg = super(OFPRequestForward, cls).parser(
4226             datapath, version, msg_type, msg_len, xid, buf)
4227         req_buf = buf[ofproto.OFP_HEADER_SIZE:]
4228         (_ver, _type, _len, _xid) = ofproto_parser.header(req_buf)
4229         msg.request = ofproto_parser.msg(
4230             datapath, _ver, _type, _len, _xid, req_buf)
4231         return msg
4232
4233     def _serialize_body(self):
4234         assert isinstance(self.request, (OFPGroupMod, OFPMeterMod))
4235         self.request.serialize()
4236         self.buf += self.request.buf
4237
4238
4239 @_set_msg_type(ofproto.OFPT_PACKET_OUT)
4240 class OFPPacketOut(MsgBase):
4241     """
4242     Packet-Out message
4243
4244     The controller uses this message to send a packet out throught the
4245     switch.
4246
4247     ================ ======================================================
4248     Attribute        Description
4249     ================ ======================================================
4250     buffer_id        ID assigned by datapath (OFP_NO_BUFFER if none)
4251     in_port          Packet's input port or ``OFPP_CONTROLLER``
4252     actions          list of OpenFlow action class
4253     data             Packet data of a binary type value or
4254                      an instances of packet.Packet.
4255     ================ ======================================================
4256
4257     Example::
4258
4259         def send_packet_out(self, datapath, buffer_id, in_port):
4260             ofp = datapath.ofproto
4261             ofp_parser = datapath.ofproto_parser
4262
4263             actions = [ofp_parser.OFPActionOutput(ofp.OFPP_FLOOD, 0)]
4264             req = ofp_parser.OFPPacketOut(datapath, buffer_id,
4265                                           in_port, actions)
4266             datapath.send_msg(req)
4267     """
4268
4269     def __init__(self, datapath, buffer_id=None, in_port=None, actions=None,
4270                  data=None, actions_len=None):
4271         assert in_port is not None
4272
4273         super(OFPPacketOut, self).__init__(datapath)
4274         self.buffer_id = buffer_id
4275         self.in_port = in_port
4276         self.actions_len = 0
4277         self.actions = actions
4278         self.data = data
4279
4280     def _serialize_body(self):
4281         self.actions_len = 0
4282         offset = ofproto.OFP_PACKET_OUT_SIZE
4283         for a in self.actions:
4284             a.serialize(self.buf, offset)
4285             offset += a.len
4286             self.actions_len += a.len
4287
4288         if self.data is not None:
4289             assert self.buffer_id == 0xffffffff
4290             if isinstance(self.data, packet.Packet):
4291                 self.data.serialize()
4292                 self.buf += self.data.data
4293             else:
4294                 self.buf += self.data
4295
4296         msg_pack_into(ofproto.OFP_PACKET_OUT_PACK_STR,
4297                       self.buf, ofproto.OFP_HEADER_SIZE,
4298                       self.buffer_id, self.in_port, self.actions_len)
4299
4300     @classmethod
4301     def from_jsondict(cls, dict_, decode_string=base64.b64decode,
4302                       **additional_args):
4303         if isinstance(dict_['data'], dict):
4304             data = dict_.pop('data')
4305             ins = super(OFPPacketOut, cls).from_jsondict(dict_,
4306                                                          decode_string,
4307                                                          **additional_args)
4308             ins.data = packet.Packet.from_jsondict(data['Packet'])
4309             dict_['data'] = data
4310         else:
4311             ins = super(OFPPacketOut, cls).from_jsondict(dict_,
4312                                                          decode_string,
4313                                                          **additional_args)
4314
4315         return ins
4316
4317
4318 @_register_parser
4319 @_set_msg_type(ofproto.OFPT_FLOW_MOD)
4320 class OFPFlowMod(MsgBase):
4321     """
4322     Modify Flow entry message
4323
4324     The controller sends this message to modify the flow table.
4325
4326     ================ ======================================================
4327     Attribute        Description
4328     ================ ======================================================
4329     cookie           Opaque controller-issued identifier
4330     cookie_mask      Mask used to restrict the cookie bits that must match
4331                      when the command is ``OPFFC_MODIFY*`` or
4332                      ``OFPFC_DELETE*``
4333     table_id         ID of the table to put the flow in
4334     command          One of the following values.
4335
4336                      | OFPFC_ADD
4337                      | OFPFC_MODIFY
4338                      | OFPFC_MODIFY_STRICT
4339                      | OFPFC_DELETE
4340                      | OFPFC_DELETE_STRICT
4341     idle_timeout     Idle time before discarding (seconds)
4342     hard_timeout     Max time before discarding (seconds)
4343     priority         Priority level of flow entry
4344     buffer_id        Buffered packet to apply to (or OFP_NO_BUFFER)
4345     out_port         For ``OFPFC_DELETE*`` commands, require matching
4346                      entries to include this as an output port
4347     out_group        For ``OFPFC_DELETE*`` commands, require matching
4348                      entries to include this as an output group
4349     flags            Bitmap of the following flags.
4350
4351                      | OFPFF_SEND_FLOW_REM
4352                      | OFPFF_CHECK_OVERLAP
4353                      | OFPFF_RESET_COUNTS
4354                      | OFPFF_NO_PKT_COUNTS
4355                      | OFPFF_NO_BYT_COUNTS
4356     importance       Eviction precedence
4357     match            Instance of ``OFPMatch``
4358     instructions     list of ``OFPInstruction*`` instance
4359     ================ ======================================================
4360
4361     Example::
4362
4363         def send_flow_mod(self, datapath):
4364             ofp = datapath.ofproto
4365             ofp_parser = datapath.ofproto_parser
4366
4367             cookie = cookie_mask = 0
4368             table_id = 0
4369             idle_timeout = hard_timeout = 0
4370             priority = 32768
4371             buffer_id = ofp.OFP_NO_BUFFER
4372             importance = 0
4373             match = ofp_parser.OFPMatch(in_port=1, eth_dst='ff:ff:ff:ff:ff:ff')
4374             actions = [ofp_parser.OFPActionOutput(ofp.OFPP_NORMAL, 0)]
4375             inst = [ofp_parser.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS,
4376                                                      actions)]
4377             req = ofp_parser.OFPFlowMod(datapath, cookie, cookie_mask,
4378                                         table_id, ofp.OFPFC_ADD,
4379                                         idle_timeout, hard_timeout,
4380                                         priority, buffer_id,
4381                                         ofp.OFPP_ANY, ofp.OFPG_ANY,
4382                                         ofp.OFPFF_SEND_FLOW_REM,
4383                                         importance,
4384                                         match, inst)
4385             datapath.send_msg(req)
4386     """
4387
4388     def __init__(self, datapath, cookie=0, cookie_mask=0, table_id=0,
4389                  command=ofproto.OFPFC_ADD,
4390                  idle_timeout=0, hard_timeout=0,
4391                  priority=ofproto.OFP_DEFAULT_PRIORITY,
4392                  buffer_id=ofproto.OFP_NO_BUFFER,
4393                  out_port=0, out_group=0, flags=0, importance=0,
4394                  match=None,
4395                  instructions=None):
4396         instructions = instructions if instructions else []
4397         super(OFPFlowMod, self).__init__(datapath)
4398         self.cookie = cookie
4399         self.cookie_mask = cookie_mask
4400         self.table_id = table_id
4401         self.command = command
4402         self.idle_timeout = idle_timeout
4403         self.hard_timeout = hard_timeout
4404         self.priority = priority
4405         self.buffer_id = buffer_id
4406         self.out_port = out_port
4407         self.out_group = out_group
4408         self.flags = flags
4409         self.importance = importance
4410         if match is None:
4411             match = OFPMatch()
4412         assert isinstance(match, OFPMatch)
4413         self.match = match
4414         for i in instructions:
4415             assert isinstance(i, OFPInstruction)
4416         self.instructions = instructions
4417
4418     def _serialize_body(self):
4419         msg_pack_into(ofproto.OFP_FLOW_MOD_PACK_STR0, self.buf,
4420                       ofproto.OFP_HEADER_SIZE,
4421                       self.cookie, self.cookie_mask, self.table_id,
4422                       self.command, self.idle_timeout, self.hard_timeout,
4423                       self.priority, self.buffer_id, self.out_port,
4424                       self.out_group, self.flags, self.importance)
4425
4426         offset = (ofproto.OFP_FLOW_MOD_SIZE -
4427                   ofproto.OFP_MATCH_SIZE)
4428
4429         match_len = self.match.serialize(self.buf, offset)
4430         offset += match_len
4431
4432         for inst in self.instructions:
4433             inst.serialize(self.buf, offset)
4434             offset += inst.len
4435
4436     @classmethod
4437     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
4438         msg = super(OFPFlowMod, cls).parser(
4439             datapath, version, msg_type, msg_len, xid, buf)
4440
4441         (msg.cookie, msg.cookie_mask, msg.table_id,
4442          msg.command, msg.idle_timeout, msg.hard_timeout,
4443          msg.priority, msg.buffer_id, msg.out_port,
4444          msg.out_group, msg.flags, msg.importance) = struct.unpack_from(
4445             ofproto.OFP_FLOW_MOD_PACK_STR0, msg.buf,
4446             ofproto.OFP_HEADER_SIZE)
4447         offset = ofproto.OFP_FLOW_MOD_SIZE - ofproto.OFP_HEADER_SIZE
4448
4449         msg.match = OFPMatch.parser(buf, offset)
4450         offset += utils.round_up(msg.match.length, 8)
4451
4452         instructions = []
4453         while offset < msg_len:
4454             i = OFPInstruction.parser(buf, offset)
4455             instructions.append(i)
4456             offset += i.len
4457         msg.instructions = instructions
4458
4459         return msg
4460
4461
4462 class OFPInstruction(StringifyMixin):
4463     _INSTRUCTION_TYPES = {}
4464
4465     @staticmethod
4466     def register_instruction_type(types):
4467         def _register_instruction_type(cls):
4468             for type_ in types:
4469                 OFPInstruction._INSTRUCTION_TYPES[type_] = cls
4470             return cls
4471         return _register_instruction_type
4472
4473     @classmethod
4474     def parser(cls, buf, offset):
4475         (type_, len_) = struct.unpack_from('!HH', buf, offset)
4476         cls_ = cls._INSTRUCTION_TYPES.get(type_)
4477         return cls_.parser(buf, offset)
4478
4479
4480 @OFPInstruction.register_instruction_type([ofproto.OFPIT_GOTO_TABLE])
4481 class OFPInstructionGotoTable(OFPInstruction):
4482     """
4483     Goto table instruction
4484
4485     This instruction indicates the next table in the processing pipeline.
4486
4487     ================ ======================================================
4488     Attribute        Description
4489     ================ ======================================================
4490     table_id         Next table
4491     ================ ======================================================
4492     """
4493
4494     def __init__(self, table_id, type_=None, len_=None):
4495         super(OFPInstructionGotoTable, self).__init__()
4496         self.type = ofproto.OFPIT_GOTO_TABLE
4497         self.len = ofproto.OFP_INSTRUCTION_GOTO_TABLE_SIZE
4498         self.table_id = table_id
4499
4500     @classmethod
4501     def parser(cls, buf, offset):
4502         (type_, len_, table_id) = struct.unpack_from(
4503             ofproto.OFP_INSTRUCTION_GOTO_TABLE_PACK_STR,
4504             buf, offset)
4505         return cls(table_id)
4506
4507     def serialize(self, buf, offset):
4508         msg_pack_into(ofproto.OFP_INSTRUCTION_GOTO_TABLE_PACK_STR,
4509                       buf, offset, self.type, self.len, self.table_id)
4510
4511
4512 @OFPInstruction.register_instruction_type([ofproto.OFPIT_WRITE_METADATA])
4513 class OFPInstructionWriteMetadata(OFPInstruction):
4514     """
4515     Write metadata instruction
4516
4517     This instruction writes the masked metadata value into the metadata field.
4518
4519     ================ ======================================================
4520     Attribute        Description
4521     ================ ======================================================
4522     metadata         Metadata value to write
4523     metadata_mask    Metadata write bitmask
4524     ================ ======================================================
4525     """
4526
4527     def __init__(self, metadata, metadata_mask, type_=None, len_=None):
4528         super(OFPInstructionWriteMetadata, self).__init__()
4529         self.type = ofproto.OFPIT_WRITE_METADATA
4530         self.len = ofproto.OFP_INSTRUCTION_WRITE_METADATA_SIZE
4531         self.metadata = metadata
4532         self.metadata_mask = metadata_mask
4533
4534     @classmethod
4535     def parser(cls, buf, offset):
4536         (type_, len_, metadata, metadata_mask) = struct.unpack_from(
4537             ofproto.OFP_INSTRUCTION_WRITE_METADATA_PACK_STR,
4538             buf, offset)
4539         return cls(metadata, metadata_mask)
4540
4541     def serialize(self, buf, offset):
4542         msg_pack_into(ofproto.OFP_INSTRUCTION_WRITE_METADATA_PACK_STR,
4543                       buf, offset, self.type, self.len, self.metadata,
4544                       self.metadata_mask)
4545
4546
4547 @OFPInstruction.register_instruction_type([ofproto.OFPIT_WRITE_ACTIONS,
4548                                            ofproto.OFPIT_APPLY_ACTIONS,
4549                                            ofproto.OFPIT_CLEAR_ACTIONS])
4550 class OFPInstructionActions(OFPInstruction):
4551     """
4552     Actions instruction
4553
4554     This instruction writes/applies/clears the actions.
4555
4556     ================ ======================================================
4557     Attribute        Description
4558     ================ ======================================================
4559     type             One of following values.
4560
4561                      | OFPIT_WRITE_ACTIONS
4562                      | OFPIT_APPLY_ACTIONS
4563                      | OFPIT_CLEAR_ACTIONS
4564     actions          list of OpenFlow action class
4565     ================ ======================================================
4566
4567     ``type`` attribute corresponds to ``type_`` parameter of __init__.
4568     """
4569
4570     def __init__(self, type_, actions=None, len_=None):
4571         super(OFPInstructionActions, self).__init__()
4572         self.type = type_
4573         for a in actions:
4574             assert isinstance(a, OFPAction)
4575         self.actions = actions
4576
4577     @classmethod
4578     def parser(cls, buf, offset):
4579         (type_, len_) = struct.unpack_from(
4580             ofproto.OFP_INSTRUCTION_ACTIONS_PACK_STR,
4581             buf, offset)
4582
4583         offset += ofproto.OFP_INSTRUCTION_ACTIONS_SIZE
4584         actions = []
4585         actions_len = len_ - ofproto.OFP_INSTRUCTION_ACTIONS_SIZE
4586         while actions_len > 0:
4587             a = OFPAction.parser(buf, offset)
4588             actions.append(a)
4589             actions_len -= a.len
4590             offset += a.len
4591
4592         inst = cls(type_, actions)
4593         inst.len = len_
4594         return inst
4595
4596     def serialize(self, buf, offset):
4597         action_offset = offset + ofproto.OFP_INSTRUCTION_ACTIONS_SIZE
4598         if self.actions:
4599             for a in self.actions:
4600                 a.serialize(buf, action_offset)
4601                 action_offset += a.len
4602
4603         self.len = action_offset - offset
4604         pad_len = utils.round_up(self.len, 8) - self.len
4605         msg_pack_into("%dx" % pad_len, buf, action_offset)
4606         self.len += pad_len
4607
4608         msg_pack_into(ofproto.OFP_INSTRUCTION_ACTIONS_PACK_STR,
4609                       buf, offset, self.type, self.len)
4610
4611
4612 @OFPInstruction.register_instruction_type([ofproto.OFPIT_METER])
4613 class OFPInstructionMeter(OFPInstruction):
4614     """
4615     Meter instruction
4616
4617     This instruction applies the meter.
4618
4619     ================ ======================================================
4620     Attribute        Description
4621     ================ ======================================================
4622     meter_id         Meter instance
4623     ================ ======================================================
4624     """
4625
4626     def __init__(self, meter_id=1, type_=None, len_=None):
4627         super(OFPInstructionMeter, self).__init__()
4628         self.type = ofproto.OFPIT_METER
4629         self.len = ofproto.OFP_INSTRUCTION_METER_SIZE
4630         self.meter_id = meter_id
4631
4632     @classmethod
4633     def parser(cls, buf, offset):
4634         (type_, len_, meter_id) = struct.unpack_from(
4635             ofproto.OFP_INSTRUCTION_METER_PACK_STR,
4636             buf, offset)
4637         return cls(meter_id)
4638
4639     def serialize(self, buf, offset):
4640         msg_pack_into(ofproto.OFP_INSTRUCTION_METER_PACK_STR,
4641                       buf, offset, self.type, self.len, self.meter_id)
4642
4643
4644 class OFPActionHeader(StringifyMixin):
4645     def __init__(self, type_, len_):
4646         self.type = type_
4647         self.len = len_
4648
4649     def serialize(self, buf, offset):
4650         msg_pack_into(ofproto.OFP_ACTION_HEADER_PACK_STR,
4651                       buf, offset, self.type, self.len)
4652
4653
4654 class OFPAction(OFPActionHeader):
4655     _ACTION_TYPES = {}
4656
4657     @staticmethod
4658     def register_action_type(type_, len_):
4659         def _register_action_type(cls):
4660             cls.cls_action_type = type_
4661             cls.cls_action_len = len_
4662             OFPAction._ACTION_TYPES[cls.cls_action_type] = cls
4663             return cls
4664         return _register_action_type
4665
4666     def __init__(self):
4667         cls = self.__class__
4668         super(OFPAction, self).__init__(cls.cls_action_type,
4669                                         cls.cls_action_len)
4670
4671     @classmethod
4672     def parser(cls, buf, offset):
4673         type_, len_ = struct.unpack_from(
4674             ofproto.OFP_ACTION_HEADER_PACK_STR, buf, offset)
4675         cls_ = cls._ACTION_TYPES.get(type_)
4676         assert cls_ is not None
4677         return cls_.parser(buf, offset)
4678
4679
4680 @OFPAction.register_action_type(ofproto.OFPAT_OUTPUT,
4681                                 ofproto.OFP_ACTION_OUTPUT_SIZE)
4682 class OFPActionOutput(OFPAction):
4683     """
4684     Output action
4685
4686     This action indicates output a packet to the switch port.
4687
4688     ================ ======================================================
4689     Attribute        Description
4690     ================ ======================================================
4691     port             Output port
4692     max_len          Max length to send to controller
4693     ================ ======================================================
4694     """
4695
4696     def __init__(self, port, max_len=ofproto.OFPCML_MAX,
4697                  type_=None, len_=None):
4698         super(OFPActionOutput, self).__init__()
4699         self.port = port
4700         self.max_len = max_len
4701
4702     @classmethod
4703     def parser(cls, buf, offset):
4704         type_, len_, port, max_len = struct.unpack_from(
4705             ofproto.OFP_ACTION_OUTPUT_PACK_STR, buf, offset)
4706         return cls(port, max_len)
4707
4708     def serialize(self, buf, offset):
4709         msg_pack_into(ofproto.OFP_ACTION_OUTPUT_PACK_STR, buf,
4710                       offset, self.type, self.len, self.port, self.max_len)
4711
4712
4713 @OFPAction.register_action_type(ofproto.OFPAT_GROUP,
4714                                 ofproto.OFP_ACTION_GROUP_SIZE)
4715 class OFPActionGroup(OFPAction):
4716     """
4717     Group action
4718
4719     This action indicates the group used to process the packet.
4720
4721     ================ ======================================================
4722     Attribute        Description
4723     ================ ======================================================
4724     group_id         Group identifier
4725     ================ ======================================================
4726     """
4727
4728     def __init__(self, group_id=0, type_=None, len_=None):
4729         super(OFPActionGroup, self).__init__()
4730         self.group_id = group_id
4731
4732     @classmethod
4733     def parser(cls, buf, offset):
4734         (type_, len_, group_id) = struct.unpack_from(
4735             ofproto.OFP_ACTION_GROUP_PACK_STR, buf, offset)
4736         return cls(group_id)
4737
4738     def serialize(self, buf, offset):
4739         msg_pack_into(ofproto.OFP_ACTION_GROUP_PACK_STR, buf,
4740                       offset, self.type, self.len, self.group_id)
4741
4742
4743 @OFPAction.register_action_type(ofproto.OFPAT_SET_QUEUE,
4744                                 ofproto.OFP_ACTION_SET_QUEUE_SIZE)
4745 class OFPActionSetQueue(OFPAction):
4746     """
4747     Set queue action
4748
4749     This action sets the queue id that will be used to map a flow to an
4750     already-configured queue on a port.
4751
4752     ================ ======================================================
4753     Attribute        Description
4754     ================ ======================================================
4755     queue_id         Queue ID for the packets
4756     ================ ======================================================
4757     """
4758
4759     def __init__(self, queue_id, type_=None, len_=None):
4760         super(OFPActionSetQueue, self).__init__()
4761         self.queue_id = queue_id
4762
4763     @classmethod
4764     def parser(cls, buf, offset):
4765         (type_, len_, queue_id) = struct.unpack_from(
4766             ofproto.OFP_ACTION_SET_QUEUE_PACK_STR, buf, offset)
4767         return cls(queue_id)
4768
4769     def serialize(self, buf, offset):
4770         msg_pack_into(ofproto.OFP_ACTION_SET_QUEUE_PACK_STR, buf,
4771                       offset, self.type, self.len, self.queue_id)
4772
4773
4774 @OFPAction.register_action_type(ofproto.OFPAT_SET_MPLS_TTL,
4775                                 ofproto.OFP_ACTION_MPLS_TTL_SIZE)
4776 class OFPActionSetMplsTtl(OFPAction):
4777     """
4778     Set MPLS TTL action
4779
4780     This action sets the MPLS TTL.
4781
4782     ================ ======================================================
4783     Attribute        Description
4784     ================ ======================================================
4785     mpls_ttl         MPLS TTL
4786     ================ ======================================================
4787     """
4788
4789     def __init__(self, mpls_ttl, type_=None, len_=None):
4790         super(OFPActionSetMplsTtl, self).__init__()
4791         self.mpls_ttl = mpls_ttl
4792
4793     @classmethod
4794     def parser(cls, buf, offset):
4795         (type_, len_, mpls_ttl) = struct.unpack_from(
4796             ofproto.OFP_ACTION_MPLS_TTL_PACK_STR, buf, offset)
4797         return cls(mpls_ttl)
4798
4799     def serialize(self, buf, offset):
4800         msg_pack_into(ofproto.OFP_ACTION_MPLS_TTL_PACK_STR, buf,
4801                       offset, self.type, self.len, self.mpls_ttl)
4802
4803
4804 @OFPAction.register_action_type(ofproto.OFPAT_DEC_MPLS_TTL,
4805                                 ofproto.OFP_ACTION_HEADER_SIZE)
4806 class OFPActionDecMplsTtl(OFPAction):
4807     """
4808     Decrement MPLS TTL action
4809
4810     This action decrements the MPLS TTL.
4811     """
4812
4813     def __init__(self, type_=None, len_=None):
4814         super(OFPActionDecMplsTtl, self).__init__()
4815
4816     @classmethod
4817     def parser(cls, buf, offset):
4818         (type_, len_) = struct.unpack_from(
4819             ofproto.OFP_ACTION_HEADER_PACK_STR, buf, offset)
4820         return cls()
4821
4822
4823 @OFPAction.register_action_type(ofproto.OFPAT_SET_NW_TTL,
4824                                 ofproto.OFP_ACTION_NW_TTL_SIZE)
4825 class OFPActionSetNwTtl(OFPAction):
4826     """
4827     Set IP TTL action
4828
4829     This action sets the IP TTL.
4830
4831     ================ ======================================================
4832     Attribute        Description
4833     ================ ======================================================
4834     nw_ttl           IP TTL
4835     ================ ======================================================
4836     """
4837
4838     def __init__(self, nw_ttl, type_=None, len_=None):
4839         super(OFPActionSetNwTtl, self).__init__()
4840         self.nw_ttl = nw_ttl
4841
4842     @classmethod
4843     def parser(cls, buf, offset):
4844         (type_, len_, nw_ttl) = struct.unpack_from(
4845             ofproto.OFP_ACTION_NW_TTL_PACK_STR, buf, offset)
4846         return cls(nw_ttl)
4847
4848     def serialize(self, buf, offset):
4849         msg_pack_into(ofproto.OFP_ACTION_NW_TTL_PACK_STR, buf, offset,
4850                       self.type, self.len, self.nw_ttl)
4851
4852
4853 @OFPAction.register_action_type(ofproto.OFPAT_DEC_NW_TTL,
4854                                 ofproto.OFP_ACTION_HEADER_SIZE)
4855 class OFPActionDecNwTtl(OFPAction):
4856     """
4857     Decrement IP TTL action
4858
4859     This action decrements the IP TTL.
4860     """
4861
4862     def __init__(self, type_=None, len_=None):
4863         super(OFPActionDecNwTtl, self).__init__()
4864
4865     @classmethod
4866     def parser(cls, buf, offset):
4867         (type_, len_) = struct.unpack_from(
4868             ofproto.OFP_ACTION_HEADER_PACK_STR, buf, offset)
4869         return cls()
4870
4871
4872 @OFPAction.register_action_type(ofproto.OFPAT_COPY_TTL_OUT,
4873                                 ofproto.OFP_ACTION_HEADER_SIZE)
4874 class OFPActionCopyTtlOut(OFPAction):
4875     """
4876     Copy TTL Out action
4877
4878     This action copies the TTL from the next-to-outermost header with TTL to
4879     the outermost header with TTL.
4880     """
4881
4882     def __init__(self, type_=None, len_=None):
4883         super(OFPActionCopyTtlOut, self).__init__()
4884
4885     @classmethod
4886     def parser(cls, buf, offset):
4887         (type_, len_) = struct.unpack_from(
4888             ofproto.OFP_ACTION_HEADER_PACK_STR, buf, offset)
4889         return cls()
4890
4891
4892 @OFPAction.register_action_type(ofproto.OFPAT_COPY_TTL_IN,
4893                                 ofproto.OFP_ACTION_HEADER_SIZE)
4894 class OFPActionCopyTtlIn(OFPAction):
4895     """
4896     Copy TTL In action
4897
4898     This action copies the TTL from the outermost header with TTL to the
4899     next-to-outermost header with TTL.
4900     """
4901
4902     def __init__(self, type_=None, len_=None):
4903         super(OFPActionCopyTtlIn, self).__init__()
4904
4905     @classmethod
4906     def parser(cls, buf, offset):
4907         (type_, len_) = struct.unpack_from(
4908             ofproto.OFP_ACTION_HEADER_PACK_STR, buf, offset)
4909         return cls()
4910
4911
4912 @OFPAction.register_action_type(ofproto.OFPAT_PUSH_VLAN,
4913                                 ofproto.OFP_ACTION_PUSH_SIZE)
4914 class OFPActionPushVlan(OFPAction):
4915     """
4916     Push VLAN action
4917
4918     This action pushes a new VLAN tag to the packet.
4919
4920     ================ ======================================================
4921     Attribute        Description
4922     ================ ======================================================
4923     ethertype        Ether type.  The default is 802.1Q. (0x8100)
4924     ================ ======================================================
4925     """
4926
4927     def __init__(self, ethertype=ether.ETH_TYPE_8021Q, type_=None, len_=None):
4928         super(OFPActionPushVlan, self).__init__()
4929         self.ethertype = ethertype
4930
4931     @classmethod
4932     def parser(cls, buf, offset):
4933         (type_, len_, ethertype) = struct.unpack_from(
4934             ofproto.OFP_ACTION_PUSH_PACK_STR, buf, offset)
4935         return cls(ethertype)
4936
4937     def serialize(self, buf, offset):
4938         msg_pack_into(ofproto.OFP_ACTION_PUSH_PACK_STR, buf, offset,
4939                       self.type, self.len, self.ethertype)
4940
4941
4942 @OFPAction.register_action_type(ofproto.OFPAT_PUSH_MPLS,
4943                                 ofproto.OFP_ACTION_PUSH_SIZE)
4944 class OFPActionPushMpls(OFPAction):
4945     """
4946     Push MPLS action
4947
4948     This action pushes a new MPLS header to the packet.
4949
4950     ================ ======================================================
4951     Attribute        Description
4952     ================ ======================================================
4953     ethertype        Ether type
4954     ================ ======================================================
4955     """
4956
4957     def __init__(self, ethertype=ether.ETH_TYPE_MPLS, type_=None, len_=None):
4958         super(OFPActionPushMpls, self).__init__()
4959         self.ethertype = ethertype
4960
4961     @classmethod
4962     def parser(cls, buf, offset):
4963         (type_, len_, ethertype) = struct.unpack_from(
4964             ofproto.OFP_ACTION_PUSH_PACK_STR, buf, offset)
4965         return cls(ethertype)
4966
4967     def serialize(self, buf, offset):
4968         msg_pack_into(ofproto.OFP_ACTION_PUSH_PACK_STR, buf, offset,
4969                       self.type, self.len, self.ethertype)
4970
4971
4972 @OFPAction.register_action_type(ofproto.OFPAT_POP_VLAN,
4973                                 ofproto.OFP_ACTION_HEADER_SIZE)
4974 class OFPActionPopVlan(OFPAction):
4975     """
4976     Pop VLAN action
4977
4978     This action pops the outermost VLAN tag from the packet.
4979     """
4980
4981     def __init__(self, type_=None, len_=None):
4982         super(OFPActionPopVlan, self).__init__()
4983
4984     @classmethod
4985     def parser(cls, buf, offset):
4986         (type_, len_) = struct.unpack_from(
4987             ofproto.OFP_ACTION_HEADER_PACK_STR, buf, offset)
4988         return cls()
4989
4990
4991 @OFPAction.register_action_type(ofproto.OFPAT_POP_MPLS,
4992                                 ofproto.OFP_ACTION_POP_MPLS_SIZE)
4993 class OFPActionPopMpls(OFPAction):
4994     """
4995     Pop MPLS action
4996
4997     This action pops the MPLS header from the packet.
4998     """
4999
5000     def __init__(self, ethertype=ether.ETH_TYPE_IP, type_=None, len_=None):
5001         super(OFPActionPopMpls, self).__init__()
5002         self.ethertype = ethertype
5003
5004     @classmethod
5005     def parser(cls, buf, offset):
5006         (type_, len_, ethertype) = struct.unpack_from(
5007             ofproto.OFP_ACTION_POP_MPLS_PACK_STR, buf, offset)
5008         return cls(ethertype)
5009
5010     def serialize(self, buf, offset):
5011         msg_pack_into(ofproto.OFP_ACTION_POP_MPLS_PACK_STR, buf, offset,
5012                       self.type, self.len, self.ethertype)
5013
5014
5015 @OFPAction.register_action_type(ofproto.OFPAT_SET_FIELD,
5016                                 ofproto.OFP_ACTION_SET_FIELD_SIZE)
5017 class OFPActionSetField(OFPAction):
5018     """
5019     Set field action
5020
5021     This action modifies a header field in the packet.
5022
5023     The set of keywords available for this is same as OFPMatch.
5024
5025     Example::
5026
5027         set_field = OFPActionSetField(eth_src="00:00:00:00:00:00")
5028     """
5029
5030     def __init__(self, field=None, **kwargs):
5031         super(OFPActionSetField, self).__init__()
5032         assert len(kwargs) == 1
5033         key = list(kwargs.keys())[0]
5034         value = kwargs[key]
5035         assert isinstance(key, (str, six.text_type))
5036         assert not isinstance(value, tuple)  # no mask
5037         self.key = key
5038         self.value = value
5039
5040     @classmethod
5041     def parser(cls, buf, offset):
5042         (type_, len_) = struct.unpack_from(
5043             ofproto.OFP_ACTION_SET_FIELD_PACK_STR, buf, offset)
5044         (n, value, mask, _len) = ofproto.oxm_parse(buf, offset + 4)
5045         k, uv = ofproto.oxm_to_user(n, value, mask)
5046         action = cls(**{k: uv})
5047         action.len = len_
5048         return action
5049
5050     def serialize(self, buf, offset):
5051         n, value, mask = ofproto.oxm_from_user(self.key, self.value)
5052         len_ = ofproto.oxm_serialize(n, value, mask, buf, offset + 4)
5053         self.len = utils.round_up(4 + len_, 8)
5054         msg_pack_into('!HH', buf, offset, self.type, self.len)
5055         pad_len = self.len - (4 + len_)
5056         msg_pack_into("%dx" % pad_len, buf, offset + 4 + len_)
5057
5058     def to_jsondict(self):
5059         return {
5060             self.__class__.__name__: {
5061                 'field': ofproto.oxm_to_jsondict(self.key, self.value),
5062                 "len": self.len,
5063                 "type": self.type
5064             }
5065         }
5066
5067     @classmethod
5068     def from_jsondict(cls, dict_):
5069         k, v = ofproto.oxm_from_jsondict(dict_['field'])
5070         return OFPActionSetField(**{k: v})
5071
5072     def stringify_attrs(self):
5073         yield (self.key, self.value)
5074
5075
5076 @OFPAction.register_action_type(ofproto.OFPAT_PUSH_PBB,
5077                                 ofproto.OFP_ACTION_PUSH_SIZE)
5078 class OFPActionPushPbb(OFPAction):
5079     """
5080     Push PBB action
5081
5082     This action pushes a new PBB header to the packet.
5083
5084     ================ ======================================================
5085     Attribute        Description
5086     ================ ======================================================
5087     ethertype        Ether type
5088     ================ ======================================================
5089     """
5090
5091     def __init__(self, ethertype, type_=None, len_=None):
5092         super(OFPActionPushPbb, self).__init__()
5093         self.ethertype = ethertype
5094
5095     @classmethod
5096     def parser(cls, buf, offset):
5097         (type_, len_, ethertype) = struct.unpack_from(
5098             ofproto.OFP_ACTION_PUSH_PACK_STR, buf, offset)
5099         return cls(ethertype)
5100
5101     def serialize(self, buf, offset):
5102         msg_pack_into(ofproto.OFP_ACTION_PUSH_PACK_STR, buf, offset,
5103                       self.type, self.len, self.ethertype)
5104
5105
5106 @OFPAction.register_action_type(ofproto.OFPAT_POP_PBB,
5107                                 ofproto.OFP_ACTION_HEADER_SIZE)
5108 class OFPActionPopPbb(OFPAction):
5109     """
5110     Pop PBB action
5111
5112     This action pops the outermost PBB service instance header from
5113     the packet.
5114     """
5115
5116     def __init__(self, type_=None, len_=None):
5117         super(OFPActionPopPbb, self).__init__()
5118
5119     @classmethod
5120     def parser(cls, buf, offset):
5121         (type_, len_) = struct.unpack_from(
5122             ofproto.OFP_ACTION_HEADER_PACK_STR, buf, offset)
5123         return cls()
5124
5125
5126 @OFPAction.register_action_type(
5127     ofproto.OFPAT_EXPERIMENTER,
5128     ofproto.OFP_ACTION_EXPERIMENTER_HEADER_SIZE)
5129 class OFPActionExperimenter(OFPAction):
5130     """
5131     Experimenter action
5132
5133     This action is an extensible action for the experimenter.
5134
5135     ================ ======================================================
5136     Attribute        Description
5137     ================ ======================================================
5138     experimenter     Experimenter ID
5139     ================ ======================================================
5140
5141     .. Note::
5142
5143         For the list of the supported Nicira experimenter actions,
5144         please refer to :ref:`ryu.ofproto.nx_actions <nx_actions_structures>`.
5145     """
5146
5147     def __init__(self, experimenter):
5148         super(OFPActionExperimenter, self).__init__()
5149         self.type = ofproto.OFPAT_EXPERIMENTER
5150         self.experimenter = experimenter
5151         self.len = None
5152
5153     @classmethod
5154     def parser(cls, buf, offset):
5155         (type_, len_, experimenter) = struct.unpack_from(
5156             ofproto.OFP_ACTION_EXPERIMENTER_HEADER_PACK_STR, buf, offset)
5157         data = buf[(offset + ofproto.OFP_ACTION_EXPERIMENTER_HEADER_SIZE
5158                     ): offset + len_]
5159         if experimenter == ofproto_common.NX_EXPERIMENTER_ID:
5160             obj = NXAction.parse(data)  # noqa
5161         else:
5162             obj = OFPActionExperimenterUnknown(experimenter, data)
5163         obj.len = len_
5164         return obj
5165
5166     def serialize(self, buf, offset):
5167         msg_pack_into(ofproto.OFP_ACTION_EXPERIMENTER_HEADER_PACK_STR,
5168                       buf, offset, self.type, self.len, self.experimenter)
5169
5170
5171 class OFPActionExperimenterUnknown(OFPActionExperimenter):
5172     def __init__(self, experimenter, data=None, type_=None, len_=None):
5173         super(OFPActionExperimenterUnknown,
5174               self).__init__(experimenter=experimenter)
5175         self.data = data
5176
5177     def serialize(self, buf, offset):
5178         # fixup
5179         data = self.data
5180         if data is None:
5181             data = bytearray()
5182         self.len = (utils.round_up(len(data), 8) +
5183                     ofproto.OFP_ACTION_EXPERIMENTER_HEADER_SIZE)
5184         super(OFPActionExperimenterUnknown, self).serialize(buf, offset)
5185         msg_pack_into('!%ds' % len(self.data),
5186                       buf,
5187                       offset + ofproto.OFP_ACTION_EXPERIMENTER_HEADER_SIZE,
5188                       self.data)
5189
5190
5191 @_register_parser
5192 @_set_msg_type(ofproto.OFPT_GROUP_MOD)
5193 class OFPGroupMod(MsgBase):
5194     """
5195     Modify group entry message
5196
5197     The controller sends this message to modify the group table.
5198
5199     ================ ======================================================
5200     Attribute        Description
5201     ================ ======================================================
5202     command          One of the following values.
5203
5204                      | OFPGC_ADD
5205                      | OFPGC_MODIFY
5206                      | OFPGC_DELETE
5207     type             One of the following values.
5208
5209                      | OFPGT_ALL
5210                      | OFPGT_SELECT
5211                      | OFPGT_INDIRECT
5212                      | OFPGT_FF
5213     group_id         Group identifier
5214     buckets          list of ``OFPBucket``
5215     ================ ======================================================
5216
5217     ``type`` attribute corresponds to ``type_`` parameter of __init__.
5218
5219     Example::
5220
5221         def send_group_mod(self, datapath):
5222             ofp = datapath.ofproto
5223             ofp_parser = datapath.ofproto_parser
5224
5225             port = 1
5226             max_len = 2000
5227             actions = [ofp_parser.OFPActionOutput(port, max_len)]
5228
5229             weight = 100
5230             watch_port = 0
5231             watch_group = 0
5232             buckets = [ofp_parser.OFPBucket(weight, watch_port, watch_group,
5233                                             actions)]
5234
5235             group_id = 1
5236             req = ofp_parser.OFPGroupMod(datapath, ofp.OFPGC_ADD,
5237                                          ofp.OFPGT_SELECT, group_id, buckets)
5238             datapath.send_msg(req)
5239     """
5240
5241     def __init__(self, datapath, command=ofproto.OFPGC_ADD,
5242                  type_=ofproto.OFPGT_ALL, group_id=0, buckets=None):
5243         buckets = buckets if buckets else []
5244         super(OFPGroupMod, self).__init__(datapath)
5245         self.command = command
5246         self.type = type_
5247         self.group_id = group_id
5248         self.buckets = buckets
5249
5250     @classmethod
5251     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
5252         msg = super(OFPGroupMod, cls).parser(
5253             datapath, version, msg_type, msg_len, xid, buf)
5254         (msg.command, msg.type, msg.group_id) = struct.unpack_from(
5255             ofproto.OFP_GROUP_MOD_PACK_STR, buf, ofproto.OFP_HEADER_SIZE)
5256         offset = ofproto.OFP_GROUP_MOD_SIZE
5257
5258         msg.buckets = []
5259         while offset < msg.msg_len:
5260             bucket = OFPBucket.parser(buf, offset)
5261             msg.buckets.append(bucket)
5262             offset += bucket.len
5263
5264         return msg
5265
5266     def _serialize_body(self):
5267         msg_pack_into(ofproto.OFP_GROUP_MOD_PACK_STR, self.buf,
5268                       ofproto.OFP_HEADER_SIZE,
5269                       self.command, self.type, self.group_id)
5270
5271         offset = ofproto.OFP_GROUP_MOD_SIZE
5272         for b in self.buckets:
5273             b.serialize(self.buf, offset)
5274             offset += b.len
5275
5276
5277 class OFPPortModProp(OFPPropBase):
5278     _TYPES = {}
5279
5280
5281 class OFPPortModPropEthernet(OFPPortModProp):
5282     def __init__(self, type_=None, length=None, advertise=None):
5283         self.type = type_
5284         self.advertise = advertise
5285
5286     def serialize(self):
5287         # fixup
5288         self.length = struct.calcsize(
5289             ofproto.OFP_PORT_MOD_PROP_ETHERNET_PACK_STR)
5290
5291         buf = bytearray()
5292         msg_pack_into(ofproto.OFP_PORT_MOD_PROP_ETHERNET_PACK_STR,
5293                       buf, 0, self.type, self.length, self.advertise)
5294         return buf
5295
5296
5297 class OFPPortModPropOptical(OFPPortModProp):
5298     def __init__(self, type_=None, length=None, configure=None,
5299                  freq_lmda=None, fl_offset=None, grid_span=None,
5300                  tx_pwr=None):
5301         self.type = type_
5302         self.length = length
5303         self.configure = configure
5304         self.freq_lmda = freq_lmda
5305         self.fl_offset = fl_offset
5306         self.grid_span = grid_span
5307         self.tx_pwr = tx_pwr
5308
5309     def serialize(self):
5310         # fixup
5311         self.length = struct.calcsize(
5312             ofproto.OFP_PORT_MOD_PROP_OPTICAL_PACK_STR)
5313
5314         buf = bytearray()
5315         msg_pack_into(ofproto.OFP_PORT_MOD_PROP_OPTICAL_PACK_STR, buf, 0,
5316                       self.type, self.length, self.configure, self.freq_lmda,
5317                       self.fl_offset, self.grid_span, self.tx_pwr)
5318         return buf
5319
5320
5321 class OFPPortModPropExperimenter(OFPPropCommonExperimenter4ByteData):
5322     pass
5323
5324
5325 @_set_msg_type(ofproto.OFPT_PORT_MOD)
5326 class OFPPortMod(MsgBase):
5327     """
5328     Port modification message
5329
5330     The controller sneds this message to modify the behavior of the port.
5331
5332     ================ ======================================================
5333     Attribute        Description
5334     ================ ======================================================
5335     port_no          Port number to modify
5336     hw_addr          The hardware address that must be the same as hw_addr
5337                      of ``OFPPort`` of ``OFPSwitchFeatures``
5338     config           Bitmap of configuration flags.
5339
5340                      | OFPPC_PORT_DOWN
5341                      | OFPPC_NO_RECV
5342                      | OFPPC_NO_FWD
5343                      | OFPPC_NO_PACKET_IN
5344     mask             Bitmap of configuration flags above to be changed
5345     properties       List of ``OFPPortModProp`` subclass instance
5346     ================ ======================================================
5347
5348     Example::
5349
5350         def send_port_mod(self, datapath):
5351             ofp = datapath.ofproto
5352             ofp_parser = datapath.ofproto_parser
5353
5354             port_no = 3
5355             hw_addr = 'fa:c8:e8:76:1d:7e'
5356             config = 0
5357             mask = (ofp.OFPPC_PORT_DOWN | ofp.OFPPC_NO_RECV |
5358                     ofp.OFPPC_NO_FWD | ofp.OFPPC_NO_PACKET_IN)
5359             advertise = (ofp.OFPPF_10MB_HD | ofp.OFPPF_100MB_FD |
5360                          ofp.OFPPF_1GB_FD | ofp.OFPPF_COPPER |
5361                          ofp.OFPPF_AUTONEG | ofp.OFPPF_PAUSE |
5362                          ofp.OFPPF_PAUSE_ASYM)
5363             properties = [ofp_parser.OFPPortModPropEthernet(advertise)]
5364             req = ofp_parser.OFPPortMod(datapath, port_no, hw_addr, config,
5365                                         mask, properties)
5366             datapath.send_msg(req)
5367     """
5368
5369     _TYPE = {
5370         'ascii': [
5371             'hw_addr',
5372         ]
5373     }
5374
5375     def __init__(self, datapath, port_no=0, hw_addr='00:00:00:00:00:00',
5376                  config=0, mask=0, properties=None):
5377         super(OFPPortMod, self).__init__(datapath)
5378         self.port_no = port_no
5379         self.hw_addr = hw_addr
5380         self.config = config
5381         self.mask = mask
5382         self.properties = properties or []
5383
5384     def _serialize_body(self):
5385         bin_props = bytearray()
5386         for p in self.properties:
5387             bin_props += p.serialize()
5388
5389         msg_pack_into(ofproto.OFP_PORT_MOD_PACK_STR, self.buf,
5390                       ofproto.OFP_HEADER_SIZE,
5391                       self.port_no, addrconv.mac.text_to_bin(self.hw_addr),
5392                       self.config,
5393                       self.mask)
5394         self.buf += bin_props
5395
5396
5397 class OFPBucket(StringifyMixin):
5398     def __init__(self, weight=0, watch_port=ofproto.OFPP_ANY,
5399                  watch_group=ofproto.OFPG_ANY, actions=None, len_=None):
5400         super(OFPBucket, self).__init__()
5401         self.weight = weight
5402         self.watch_port = watch_port
5403         self.watch_group = watch_group
5404         self.actions = actions
5405
5406     @classmethod
5407     def parser(cls, buf, offset):
5408         (len_, weight, watch_port, watch_group) = struct.unpack_from(
5409             ofproto.OFP_BUCKET_PACK_STR, buf, offset)
5410         msg = cls(weight, watch_port, watch_group, [])
5411         msg.len = len_
5412
5413         length = ofproto.OFP_BUCKET_SIZE
5414         offset += ofproto.OFP_BUCKET_SIZE
5415         while length < msg.len:
5416             action = OFPAction.parser(buf, offset)
5417             msg.actions.append(action)
5418             offset += action.len
5419             length += action.len
5420
5421         return msg
5422
5423     def serialize(self, buf, offset):
5424         action_offset = offset + ofproto.OFP_BUCKET_SIZE
5425         action_len = 0
5426         for a in self.actions:
5427             a.serialize(buf, action_offset)
5428             action_offset += a.len
5429             action_len += a.len
5430
5431         self.len = utils.round_up(ofproto.OFP_BUCKET_SIZE + action_len, 8)
5432         msg_pack_into(ofproto.OFP_BUCKET_PACK_STR, buf, offset,
5433                       self.len, self.weight, self.watch_port,
5434                       self.watch_group)
5435
5436
5437 @_set_msg_type(ofproto.OFPT_ROLE_REQUEST)
5438 class OFPRoleRequest(MsgBase):
5439     """
5440     Role request message
5441
5442     The controller uses this message to change its role.
5443
5444     ================ ======================================================
5445     Attribute        Description
5446     ================ ======================================================
5447     role             One of the following values.
5448
5449                      | OFPCR_ROLE_NOCHANGE
5450                      | OFPCR_ROLE_EQUAL
5451                      | OFPCR_ROLE_MASTER
5452                      | OFPCR_ROLE_SLAVE
5453     generation_id    Master Election Generation ID
5454     ================ ======================================================
5455
5456     Example::
5457
5458         def send_role_request(self, datapath):
5459             ofp = datapath.ofproto
5460             ofp_parser = datapath.ofproto_parser
5461
5462             req = ofp_parser.OFPRoleRequest(datapath, ofp.OFPCR_ROLE_EQUAL, 0)
5463             datapath.send_msg(req)
5464     """
5465
5466     def __init__(self, datapath, role=None, generation_id=None):
5467         super(OFPRoleRequest, self).__init__(datapath)
5468         self.role = role
5469         self.generation_id = generation_id
5470
5471     def _serialize_body(self):
5472         assert self.role is not None
5473         assert self.generation_id is not None
5474         msg_pack_into(ofproto.OFP_ROLE_REQUEST_PACK_STR,
5475                       self.buf, ofproto.OFP_HEADER_SIZE,
5476                       self.role, self.generation_id)
5477
5478
5479 @_register_parser
5480 @_set_msg_type(ofproto.OFPT_ROLE_REPLY)
5481 class OFPRoleReply(MsgBase):
5482     """
5483     Role reply message
5484
5485     The switch responds with this message to a role request.
5486
5487     ================ ======================================================
5488     Attribute        Description
5489     ================ ======================================================
5490     role             One of the following values.
5491
5492                      | OFPCR_ROLE_NOCHANGE
5493                      | OFPCR_ROLE_EQUAL
5494                      | OFPCR_ROLE_MASTER
5495                      | OFPCR_ROLE_SLAVE
5496     generation_id    Master Election Generation ID
5497     ================ ======================================================
5498
5499     Example::
5500
5501         @set_ev_cls(ofp_event.EventOFPRoleReply, MAIN_DISPATCHER)
5502         def role_reply_handler(self, ev):
5503             msg = ev.msg
5504             dp = msg.datapath
5505             ofp = dp.ofproto
5506
5507             if msg.role == ofp.OFPCR_ROLE_NOCHANGE:
5508                 role = 'NOCHANGE'
5509             elif msg.role == ofp.OFPCR_ROLE_EQUAL:
5510                 role = 'EQUAL'
5511             elif msg.role == ofp.OFPCR_ROLE_MASTER:
5512                 role = 'MASTER'
5513             elif msg.role == ofp.OFPCR_ROLE_SLAVE:
5514                 role = 'SLAVE'
5515             else:
5516                 role = 'unknown'
5517
5518             self.logger.debug('OFPRoleReply received: '
5519                               'role=%s generation_id=%d',
5520                               role, msg.generation_id)
5521     """
5522
5523     def __init__(self, datapath, role=None, generation_id=None):
5524         super(OFPRoleReply, self).__init__(datapath)
5525         self.role = role
5526         self.generation_id = generation_id
5527
5528     @classmethod
5529     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
5530         msg = super(OFPRoleReply, cls).parser(datapath, version,
5531                                               msg_type, msg_len, xid,
5532                                               buf)
5533         (msg.role, msg.generation_id) = struct.unpack_from(
5534             ofproto.OFP_ROLE_REQUEST_PACK_STR, msg.buf,
5535             ofproto.OFP_HEADER_SIZE)
5536         return msg
5537
5538
5539 class OFPAsyncConfigProp(OFPPropBase):
5540     _TYPES = {}
5541
5542
5543 @OFPAsyncConfigProp.register_type(ofproto.OFPACPT_PACKET_IN_SLAVE)
5544 @OFPAsyncConfigProp.register_type(ofproto.OFPACPT_PACKET_IN_MASTER)
5545 @OFPAsyncConfigProp.register_type(ofproto.OFPACPT_PORT_STATUS_SLAVE)
5546 @OFPAsyncConfigProp.register_type(ofproto.OFPACPT_PORT_STATUS_MASTER)
5547 @OFPAsyncConfigProp.register_type(ofproto.OFPACPT_FLOW_REMOVED_SLAVE)
5548 @OFPAsyncConfigProp.register_type(ofproto.OFPACPT_FLOW_REMOVED_MASTER)
5549 @OFPAsyncConfigProp.register_type(ofproto.OFPACPT_ROLE_STATUS_SLAVE)
5550 @OFPAsyncConfigProp.register_type(ofproto.OFPACPT_ROLE_STATUS_MASTER)
5551 @OFPAsyncConfigProp.register_type(ofproto.OFPACPT_TABLE_STATUS_SLAVE)
5552 @OFPAsyncConfigProp.register_type(ofproto.OFPACPT_TABLE_STATUS_MASTER)
5553 @OFPAsyncConfigProp.register_type(ofproto.OFPACPT_REQUESTFORWARD_SLAVE)
5554 @OFPAsyncConfigProp.register_type(ofproto.OFPACPT_REQUESTFORWARD_MASTER)
5555 class OFPAsyncConfigPropReasons(OFPAsyncConfigProp):
5556     def __init__(self, type_=None, length=None, mask=None):
5557         self.type = type_
5558         self.length = length
5559         self.mask = mask
5560
5561     @classmethod
5562     def parser(cls, buf):
5563         reasons = cls()
5564         (reasons.type, reasons.length, reasons.mask) = struct.unpack_from(
5565             ofproto.OFP_ASYNC_CONFIG_PROP_REASONS_PACK_STR, buf, 0)
5566         return reasons
5567
5568     def serialize(self):
5569         # fixup
5570         self.length = ofproto.OFP_ASYNC_CONFIG_PROP_REASONS_SIZE
5571
5572         buf = bytearray()
5573         msg_pack_into(ofproto.OFP_ASYNC_CONFIG_PROP_REASONS_PACK_STR, buf, 0,
5574                       self.type, self.length, self.mask)
5575         return buf
5576
5577
5578 @OFPAsyncConfigProp.register_type(ofproto.OFPACPT_EXPERIMENTER_SLAVE)
5579 @OFPAsyncConfigProp.register_type(ofproto.OFPACPT_EXPERIMENTER_MASTER)
5580 class OFPAsyncConfigPropExperimenter(OFPPropCommonExperimenter4ByteData):
5581     pass
5582
5583
5584 @_set_msg_type(ofproto.OFPT_GET_ASYNC_REQUEST)
5585 class OFPGetAsyncRequest(MsgBase):
5586     """
5587     Get asynchronous configuration request message
5588
5589     The controller uses this message to query the asynchronous message.
5590
5591     Example::
5592
5593         def send_get_async_request(self, datapath):
5594             ofp_parser = datapath.ofproto_parser
5595
5596             req = ofp_parser.OFPGetAsyncRequest(datapath)
5597             datapath.send_msg(req)
5598     """
5599
5600     def __init__(self, datapath):
5601         super(OFPGetAsyncRequest, self).__init__(datapath)
5602
5603
5604 @_register_parser
5605 @_set_msg_type(ofproto.OFPT_GET_ASYNC_REPLY)
5606 class OFPGetAsyncReply(MsgBase):
5607     """
5608     Get asynchronous configuration reply message
5609
5610     The switch responds with this message to a get asynchronous configuration
5611     request.
5612
5613     ================== ====================================================
5614     Attribute          Description
5615     ================== ====================================================
5616     properties         List of ``OFPAsyncConfigProp`` subclass instances
5617     ================== ====================================================
5618
5619     Example::
5620
5621         @set_ev_cls(ofp_event.EventOFPGetAsyncReply, MAIN_DISPATCHER)
5622         def get_async_reply_handler(self, ev):
5623             msg = ev.msg
5624
5625             self.logger.debug('OFPGetAsyncReply received: '
5626                               'properties=%s', repr(msg.properties))
5627     """
5628
5629     def __init__(self, datapath, properties=None):
5630         super(OFPGetAsyncReply, self).__init__(datapath)
5631         self.properties = properties
5632
5633     @classmethod
5634     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
5635         msg = super(OFPGetAsyncReply, cls).parser(datapath, version,
5636                                                   msg_type, msg_len,
5637                                                   xid, buf)
5638
5639         msg.properties = []
5640         rest = msg.buf[ofproto.OFP_HEADER_SIZE:]
5641         while rest:
5642             p, rest = OFPAsyncConfigProp.parse(rest)
5643             msg.properties.append(p)
5644
5645         return msg
5646
5647
5648 @_set_msg_type(ofproto.OFPT_SET_ASYNC)
5649 class OFPSetAsync(MsgBase):
5650     """
5651     Set asynchronous configuration message
5652
5653     The controller sends this message to set the asynchronous messages that
5654     it wants to receive on a given OpneFlow channel.
5655
5656     ================== ====================================================
5657     Attribute          Description
5658     ================== ====================================================
5659     properties         List of ``OFPAsyncConfigProp`` subclass instances
5660     ================== ====================================================
5661
5662     Example::
5663
5664         def send_set_async(self, datapath):
5665             ofp = datapath.ofproto
5666             ofp_parser = datapath.ofproto_parser
5667
5668             properties = [
5669                 ofp_parser.OFPAsyncConfigPropReasons(
5670                     ofp.OFPACPT_PACKET_IN_SLAVE, 8,
5671                     (1 << ofp.OFPR_APPLY_ACTION
5672                      | 1 << ofp.OFPR_INVALID_TTL))]
5673             req = ofp_parser.OFPSetAsync(datapath, properties)
5674             datapath.send_msg(req)
5675     """
5676
5677     def __init__(self, datapath, properties=None):
5678         super(OFPSetAsync, self).__init__(datapath)
5679         self.properties = properties
5680
5681     def _serialize_body(self):
5682         bin_props = bytearray()
5683         for p in self.properties:
5684             bin_props += p.serialize()
5685
5686         self.buf += bin_props
5687
5688
5689 @_register_parser
5690 @_set_msg_type(ofproto.OFPT_BUNDLE_CONTROL)
5691 class OFPBundleCtrlMsg(MsgBase):
5692     """
5693     Bundle control message
5694
5695     The controller uses this message to create, destroy and commit bundles
5696
5697     ================ ======================================================
5698     Attribute        Description
5699     ================ ======================================================
5700     bundle_id        Id of the bundle
5701     type             One of the following values.
5702
5703                      | OFPBCT_OPEN_REQUEST
5704                      | OFPBCT_OPEN_REPLY
5705                      | OFPBCT_CLOSE_REQUEST
5706                      | OFPBCT_CLOSE_REPLY
5707                      | OFPBCT_COMMIT_REQUEST
5708                      | OFPBCT_COMMIT_REPLY
5709                      | OFPBCT_DISCARD_REQUEST
5710                      | OFPBCT_DISCARD_REPLY
5711     flags            Bitmap of the following flags.
5712
5713                      | OFPBF_ATOMIC
5714                      | OFPBF_ORDERED
5715     properties       List of ``OFPBundleProp`` subclass instance
5716     ================ ======================================================
5717
5718     Example::
5719
5720         def send_bundle_control(self, datapath):
5721             ofp = datapath.ofproto
5722             ofp_parser = datapath.ofproto_parser
5723
5724             req = ofp_parser.OFPBundleCtrlMsg(datapath, 7,
5725                                               ofp.OFPBCT_OPEN_REQUEST,
5726                                               ofp.OFPBF_ATOMIC, [])
5727             datapath.send_msg(req)
5728     """
5729
5730     def __init__(self, datapath, bundle_id=None, type_=None, flags=None,
5731                  properties=None):
5732         super(OFPBundleCtrlMsg, self).__init__(datapath)
5733         self.bundle_id = bundle_id
5734         self.type = type_
5735         self.flags = flags
5736         self.properties = properties
5737
5738     def _serialize_body(self):
5739         bin_props = bytearray()
5740         for p in self.properties:
5741             bin_props += p.serialize()
5742
5743         msg_pack_into(ofproto.OFP_BUNDLE_CTRL_MSG_PACK_STR,
5744                       self.buf, ofproto.OFP_HEADER_SIZE, self.bundle_id,
5745                       self.type, self.flags)
5746         self.buf += bin_props
5747
5748     @classmethod
5749     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
5750         msg = super(OFPBundleCtrlMsg, cls).parser(datapath, version,
5751                                                   msg_type, msg_len,
5752                                                   xid, buf)
5753         (bundle_id, type_, flags) = struct.unpack_from(
5754             ofproto.OFP_BUNDLE_CTRL_MSG_PACK_STR, buf,
5755             ofproto.OFP_HEADER_SIZE)
5756         msg.bundle_id = bundle_id
5757         msg.type = type_
5758         msg.flags = flags
5759         msg.properties = []
5760         rest = msg.buf[ofproto.OFP_BUNDLE_CTRL_MSG_SIZE:]
5761         while rest:
5762             p, rest = OFPBundleProp.parse(rest)
5763             msg.properties.append(p)
5764
5765         return msg
5766
5767
5768 @_set_msg_type(ofproto.OFPT_BUNDLE_ADD_MESSAGE)
5769 class OFPBundleAddMsg(MsgInMsgBase):
5770     """
5771     Bundle add message
5772
5773     The controller uses this message to add a message to a bundle
5774
5775     ================ ======================================================
5776     Attribute        Description
5777     ================ ======================================================
5778     bundle_id        Id of the bundle
5779     flags            Bitmap of the following flags.
5780
5781                      | OFPBF_ATOMIC
5782                      | OFPBF_ORDERED
5783     message          ``MsgBase`` subclass instance
5784     properties       List of ``OFPBundleProp`` subclass instance
5785     ================ ======================================================
5786
5787     Example::
5788
5789         def send_bundle_add_message(self, datapath):
5790             ofp = datapath.ofproto
5791             ofp_parser = datapath.ofproto_parser
5792
5793             msg = ofp_parser.OFPRoleRequest(datapath, ofp.OFPCR_ROLE_EQUAL, 0)
5794
5795             req = ofp_parser.OFPBundleAddMsg(datapath, 7, ofp.OFPBF_ATOMIC,
5796                                              msg, [])
5797             datapath.send_msg(req)
5798     """
5799
5800     def __init__(self, datapath, bundle_id, flags, message, properties):
5801         super(OFPBundleAddMsg, self).__init__(datapath)
5802         self.bundle_id = bundle_id
5803         self.flags = flags
5804         self.message = message
5805         self.properties = properties
5806
5807     def _serialize_body(self):
5808         # The xid of the inner message must be the same as
5809         # that of the outer message (OF1.4.0 7.3.9.2)
5810         if self.message.xid != self.xid:
5811             self.message.set_xid(self.xid)
5812
5813         # Message
5814         self.message.serialize()
5815         tail_buf = self.message.buf
5816
5817         # Pad
5818         if len(self.properties) > 0:
5819             message_len = len(tail_buf)
5820             pad_len = utils.round_up(message_len, 8) - message_len
5821             msg_pack_into("%dx" % pad_len, tail_buf, message_len)
5822
5823         # Properties
5824         for p in self.properties:
5825             tail_buf += p.serialize()
5826
5827         # Head
5828         msg_pack_into(ofproto.OFP_BUNDLE_ADD_MSG_0_PACK_STR,
5829                       self.buf, ofproto.OFP_HEADER_SIZE, self.bundle_id,
5830                       self.flags)
5831
5832         # Finish
5833         self.buf += tail_buf
5834
5835
5836 nx_actions.generate(
5837     'ryu.ofproto.ofproto_v1_4',
5838     'ryu.ofproto.ofproto_v1_4_parser'
5839 )