backing up
[vsorcdistro/.git] / ryu / build / lib.linux-armv7l-2.7 / ryu / ofproto / ofproto_v1_5_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.5.
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 exception
30 from ryu import utils
31 from ryu.ofproto.ofproto_parser import StringifyMixin, MsgBase, MsgInMsgBase
32 from ryu.ofproto import ether
33 from ryu.ofproto import nx_actions
34 from ryu.ofproto import ofproto_parser
35 from ryu.ofproto import ofproto_common
36 from ryu.ofproto import ofproto_v1_5 as ofproto
37
38 _MSG_PARSERS = {}
39
40
41 def _set_msg_type(msg_type):
42     def _set_cls_msg_type(cls):
43         cls.cls_msg_type = msg_type
44         return cls
45     return _set_cls_msg_type
46
47
48 def _register_parser(cls):
49     '''class decorator to register msg parser'''
50     assert cls.cls_msg_type is not None
51     assert cls.cls_msg_type not in _MSG_PARSERS
52     _MSG_PARSERS[cls.cls_msg_type] = cls.parser
53     return cls
54
55
56 @ofproto_parser.register_msg_parser(ofproto.OFP_VERSION)
57 def msg_parser(datapath, version, msg_type, msg_len, xid, buf):
58     parser = _MSG_PARSERS.get(msg_type)
59     return parser(datapath, version, msg_type, msg_len, xid, buf)
60
61
62 @_register_parser
63 @_set_msg_type(ofproto.OFPT_HELLO)
64 class OFPHello(MsgBase):
65     """
66     Hello message
67
68     When connection is started, the hello message is exchanged between a
69     switch and a controller.
70
71     This message is handled by the Ryu framework, so the Ryu application
72     do not need to process this typically.
73
74     ========== =========================================================
75     Attribute  Description
76     ========== =========================================================
77     elements   list of ``OFPHelloElemVersionBitmap`` instance
78     ========== =========================================================
79     """
80
81     def __init__(self, datapath, elements=None):
82         elements = elements if elements else []
83         super(OFPHello, self).__init__(datapath)
84         self.elements = elements
85
86     @classmethod
87     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
88         msg = super(OFPHello, cls).parser(datapath, version, msg_type,
89                                           msg_len, xid, buf)
90
91         offset = ofproto.OFP_HELLO_HEADER_SIZE
92         elems = []
93         while offset < msg.msg_len:
94             type_, length = struct.unpack_from(
95                 ofproto.OFP_HELLO_ELEM_HEADER_PACK_STR, msg.buf, offset)
96
97             # better to register Hello Element classes but currently
98             # Only VerisonBitmap is supported so let's be simple.
99
100             if type_ == ofproto.OFPHET_VERSIONBITMAP:
101                 elem = OFPHelloElemVersionBitmap.parser(msg.buf, offset)
102                 elems.append(elem)
103
104             offset += length
105         msg.elements = elems
106         return msg
107
108
109 class OFPHelloElemVersionBitmap(StringifyMixin):
110     """
111     Version bitmap Hello Element
112
113     ========== =========================================================
114     Attribute  Description
115     ========== =========================================================
116     versions   list of versions of OpenFlow protocol a device supports
117     ========== =========================================================
118     """
119
120     def __init__(self, versions, type_=None, length=None):
121         super(OFPHelloElemVersionBitmap, self).__init__()
122         self.type = ofproto.OFPHET_VERSIONBITMAP
123         self.length = None
124         self._bitmaps = None
125         self.versions = versions
126
127     @classmethod
128     def parser(cls, buf, offset):
129         type_, length = struct.unpack_from(
130             ofproto.OFP_HELLO_ELEM_VERSIONBITMAP_HEADER_PACK_STR,
131             buf, offset)
132         assert type_ == ofproto.OFPHET_VERSIONBITMAP
133
134         bitmaps_len = (length -
135                        ofproto.OFP_HELLO_ELEM_VERSIONBITMAP_HEADER_SIZE)
136         offset += ofproto.OFP_HELLO_ELEM_VERSIONBITMAP_HEADER_SIZE
137         bitmaps = []
138         while bitmaps_len >= 4:
139             bitmap = struct.unpack_from('!I', buf, offset)
140             bitmaps.append(bitmap[0])
141             offset += 4
142             bitmaps_len -= 4
143
144         versions = [i * 32 + shift
145                     for i, bitmap in enumerate(bitmaps)
146                     for shift in range(31) if bitmap & (1 << shift)]
147         elem = cls(versions)
148         elem.length = length
149         elem._bitmaps = bitmaps
150         return elem
151
152
153 @_register_parser
154 @_set_msg_type(ofproto.OFPT_ECHO_REQUEST)
155 class OFPEchoRequest(MsgBase):
156     """
157     Echo request message
158
159     This message is handled by the Ryu framework, so the Ryu application
160     do not need to process this typically.
161
162     ========== =========================================================
163     Attribute  Description
164     ========== =========================================================
165     data       An arbitrary length data
166     ========== =========================================================
167
168     Example::
169
170         def send_echo_request(self, datapath, data):
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     actset_output    Integer 32bit   Output port from action set metadata
663     packet_type      Integer 32bit   Packet type value
664     ================ =============== ==================================
665
666     Example::
667
668         >>> # compose
669         >>> match = parser.OFPMatch(
670         ...     in_port=1,
671         ...     eth_type=0x86dd,
672         ...     ipv6_src=('2001:db8:bd05:1d2:288a:1fc0:1:10ee',
673         ...               'ffff:ffff:ffff:ffff::'),
674         ...     ipv6_dst='2001:db8:bd05:1d2:288a:1fc0:1:10ee')
675         >>> # query
676         >>> if 'ipv6_src' in match:
677         ...     print match['ipv6_src']
678         ...
679         ('2001:db8:bd05:1d2:288a:1fc0:1:10ee', 'ffff:ffff:ffff:ffff::')
680
681     .. Note::
682
683         For the list of the supported Nicira experimenter matches,
684         please refer to :ref:`ryu.ofproto.nx_match <nx_match_structures>`.
685
686     .. Note::
687
688         For VLAN id match field, special values are defined in OpenFlow Spec.
689
690         1) Packets with and without a VLAN tag
691
692             - Example::
693
694                 match = parser.OFPMatch()
695
696             - Packet Matching
697
698                 ====================== =====
699                 non-VLAN-tagged        MATCH
700                 VLAN-tagged(vlan_id=3) MATCH
701                 VLAN-tagged(vlan_id=5) MATCH
702                 ====================== =====
703
704         2) Only packets without a VLAN tag
705
706             - Example::
707
708                 match = parser.OFPMatch(vlan_vid=0x0000)
709
710             - Packet Matching
711
712                 ====================== =====
713                 non-VLAN-tagged        MATCH
714                 VLAN-tagged(vlan_id=3)   x
715                 VLAN-tagged(vlan_id=5)   x
716                 ====================== =====
717
718         3) Only packets with a VLAN tag regardless of its value
719
720             - Example::
721
722                 match = parser.OFPMatch(vlan_vid=(0x1000, 0x1000))
723
724             - Packet Matching
725
726                 ====================== =====
727                 non-VLAN-tagged          x
728                 VLAN-tagged(vlan_id=3) MATCH
729                 VLAN-tagged(vlan_id=5) MATCH
730                 ====================== =====
731
732         4) Only packets with VLAN tag and VID equal
733
734             - Example::
735
736                 match = parser.OFPMatch(vlan_vid=(0x1000 | 3))
737
738             - Packet Matching
739
740                 ====================== =====
741                 non-VLAN-tagged          x
742                 VLAN-tagged(vlan_id=3) MATCH
743                 VLAN-tagged(vlan_id=5)   x
744                 ====================== =====
745     """
746
747     def __init__(self, type_=None, length=None, _ordered_fields=None,
748                  **kwargs):
749         super(OFPMatch, self).__init__()
750         self.type = ofproto.OFPMT_OXM
751         self.length = length
752
753         if _ordered_fields is not None:
754             assert not kwargs
755             self._fields2 = _ordered_fields
756         else:
757             kwargs = dict(ofproto.oxm_normalize_user(k, v) for
758                           (k, v) in kwargs.items())
759             fields = [ofproto.oxm_from_user(k, v) for (k, v)
760                       in kwargs.items()]
761             # assumption: sorting by OXM type values makes fields
762             # meet ordering requirements (eg. eth_type before ipv4_src)
763             fields.sort(
764                 key=lambda x: x[0][0] if isinstance(x[0], tuple) else x[0])
765             self._fields2 = [ofproto.oxm_to_user(n, v, m) for (n, v, m)
766                              in fields]
767
768     @classmethod
769     def parser(cls, buf, offset):
770         """
771         Returns an object which is generated from a buffer including the
772         expression of the wire protocol of the flow match.
773         """
774         match = OFPMatch()
775         type_, length = struct.unpack_from('!HH', buf, offset)
776
777         match.type = type_
778         match.length = length
779
780         # ofp_match adjustment
781         offset += 4
782         length -= 4
783
784         fields = []
785         while length > 0:
786             n, value, mask, field_len = ofproto.oxm_parse(buf, offset)
787             k, uv = ofproto.oxm_to_user(n, value, mask)
788             fields.append((k, uv))
789             offset += field_len
790             length -= field_len
791         match._fields2 = fields
792         return match
793
794     def serialize(self, buf, offset):
795         """
796         Outputs the expression of the wire protocol of the flow match into
797         the buf.
798         Returns the output length.
799         """
800         fields = [ofproto.oxm_from_user(k, uv) for (k, uv)
801                   in self._fields2]
802
803         hdr_pack_str = '!HH'
804         field_offset = offset + struct.calcsize(hdr_pack_str)
805         for (n, value, mask) in fields:
806             field_offset += ofproto.oxm_serialize(n, value, mask, buf,
807                                                   field_offset)
808
809         length = field_offset - offset
810         msg_pack_into(hdr_pack_str, buf, offset, ofproto.OFPMT_OXM, length)
811         self.length = length
812
813         pad_len = utils.round_up(length, 8) - length
814         msg_pack_into("%dx" % pad_len, buf, field_offset)
815
816         return length + pad_len
817
818     def __getitem__(self, key):
819         return dict(self._fields2)[key]
820
821     def __contains__(self, key):
822         return key in dict(self._fields2)
823
824     def iteritems(self):
825         return iter(dict(self._fields2).items())
826
827     def items(self):
828         return self._fields2
829
830     def get(self, key, default=None):
831         return dict(self._fields2).get(key, default)
832
833     def stringify_attrs(self):
834         yield "oxm_fields", dict(self._fields2)
835
836     def to_jsondict(self):
837         """
838         Returns a dict expressing the flow match.
839         """
840         body = {"oxm_fields": [ofproto.oxm_to_jsondict(k, uv) for k, uv
841                                in self._fields2],
842                 "length": self.length,
843                 "type": self.type}
844         return {self.__class__.__name__: body}
845
846     @classmethod
847     def from_jsondict(cls, dict_):
848         """
849         Returns an object which is generated from a dict.
850
851         Exception raises:
852         KeyError -- Unknown match field is defined in dict
853         """
854         fields = [ofproto.oxm_from_jsondict(f) for f
855                   in dict_['oxm_fields']]
856         return OFPMatch(_ordered_fields=fields)
857
858
859 class OFPStats(StringifyMixin):
860     """
861     Flow Stats Structure
862
863     This class is implementation of the flow stats structure having
864     compose/query API.
865
866     You can define the flow stats by the keyword arguments.
867     The following arguments are available.
868
869     ============= ================ ============================================
870     Argument      Value            Description
871     ============= ================ ============================================
872     duration      Integer 32bit*2  Time flow entry has been alive. This field
873                                    is a tuple of two Integer 32bit. The first
874                                    value is duration_sec and the second is
875                                    duration_nsec.
876     idle_time     Integer 32bit*2  Time flow entry has been idle.
877     flow_count    Integer 32bit    Number of aggregated flow entries.
878     packet_count  Integer 64bit    Number of packets matched by a flow entry.
879     byte_count    Integer 64bit    Number of bytes matched by a flow entry.
880     ============= ================ ============================================
881
882     Example::
883
884         >>> # compose
885         >>> stats = parser.OFPStats(
886         ...     packet_count=100,
887         ...     duration=(100, 200)
888         >>> # query
889         >>> if 'duration' in stats:
890         ...     print stats['duration']
891         ...
892         (100, 200)
893     """
894
895     def __init__(self, length=None, _ordered_fields=None, **kwargs):
896         super(OFPStats, self).__init__()
897         self.length = length
898
899         if _ordered_fields is not None:
900             assert not kwargs
901             self.fields = _ordered_fields
902         else:
903             fields = [ofproto.oxs_from_user(k, v) for (k, v)
904                       in kwargs.items()]
905             # sort by OXS type values
906             fields.sort(
907                 key=lambda x: x[0][0] if isinstance(x[0], tuple) else x[0])
908             # No mask
909             self.fields = [ofproto.oxs_to_user(n, v, None) for (n, v, _)
910                            in fields]
911
912     @classmethod
913     def parser(cls, buf, offset):
914         """
915         Returns an object which is generated from a buffer including the
916         expression of the wire protocol of the flow stats.
917         """
918         stats = OFPStats()
919         reserved, length = struct.unpack_from('!HH', buf, offset)
920
921         stats.length = length
922
923         # ofp_stats adjustment
924         offset += 4
925         length -= 4
926
927         fields = []
928         while length > 0:
929             n, value, _, field_len = ofproto.oxs_parse(buf, offset)
930             k, uv = ofproto.oxs_to_user(n, value, None)  # No mask
931             fields.append((k, uv))
932             offset += field_len
933             length -= field_len
934         stats.fields = fields
935         return stats
936
937     def serialize(self, buf, offset):
938         """
939         Outputs the expression of the wire protocol of the flow stats into
940         the buf.
941         Returns the output length.
942         """
943         fields = [ofproto.oxs_from_user(k, uv) for (k, uv)
944                   in self.fields]
945
946         hdr_pack_str = '!HH'
947         field_offset = offset + struct.calcsize(hdr_pack_str)
948         for (n, value, _) in fields:
949             # No mask
950             field_offset += ofproto.oxs_serialize(n, value, None, buf,
951                                                   field_offset)
952
953         reserved = 0
954         length = field_offset - offset
955         msg_pack_into(hdr_pack_str, buf, offset, reserved, length)
956         self.length = length
957
958         pad_len = utils.round_up(length, 8) - length
959         msg_pack_into("%dx" % pad_len, buf, field_offset)
960
961         return length + pad_len
962
963     def __getitem__(self, key):
964         return dict(self.fields)[key]
965
966     def __contains__(self, key):
967         return key in dict(self.fields)
968
969     def iteritems(self):
970         return dict(self.fields).items()
971
972     def items(self):
973         return self.fields
974
975     def get(self, key, default=None):
976         return dict(self.fields).get(key, default)
977
978     def stringify_attrs(self):
979         yield "oxs_fields", dict(self.fields)
980
981     def to_jsondict(self):
982         """
983         Returns a dict expressing the flow stats.
984         """
985         body = {"oxs_fields": [ofproto.oxs_to_jsondict(k, uv) for k, uv
986                                in self.fields],
987                 "length": self.length}
988         return {self.__class__.__name__: body}
989
990     @classmethod
991     def from_jsondict(cls, dict_):
992         """
993         Returns an object which is generated from a dict.
994
995         Exception raises:
996         KeyError -- Unknown stats field is defined in dict
997         """
998         fields = [ofproto.oxs_from_jsondict(f) for f
999                   in dict_['oxs_fields']]
1000         return OFPStats(_ordered_fields=fields)
1001
1002
1003 class OFPPropUnknown(StringifyMixin):
1004     def __init__(self, type_=None, length=None, buf=None):
1005         self.buf = buf
1006
1007     @classmethod
1008     def parser(cls, buf):
1009         return cls(buf=buf)
1010
1011
1012 class OFPPropBase(StringifyMixin):
1013     _PACK_STR = '!HH'
1014     # _TYPES = {} must be an attribute of subclass
1015
1016     def __init__(self, type_, length=None):
1017         self.type = type_
1018         self.length = length
1019
1020     @classmethod
1021     def register_type(cls, type_):
1022         def _register_type(subcls):
1023             cls._TYPES[type_] = subcls
1024             return subcls
1025         return _register_type
1026
1027     @classmethod
1028     def parse(cls, buf):
1029         (type_, length) = struct.unpack_from(cls._PACK_STR, buf, 0)
1030         rest = buf[utils.round_up(length, 8):]
1031         try:
1032             subcls = cls._TYPES[type_]
1033         except KeyError:
1034             subcls = OFPPropUnknown
1035         prop = subcls.parser(buf)
1036         prop.type = type_
1037         prop.length = length
1038         return prop, rest
1039
1040     @classmethod
1041     def get_rest(cls, buf):
1042         (type_, length) = struct.unpack_from(cls._PACK_STR, buf, 0)
1043         offset = struct.calcsize(cls._PACK_STR)
1044         return buf[offset:length]
1045
1046     def serialize(self):
1047         # Body
1048         # serialize_body should be implemented by subclass
1049         body = bytearray()
1050         body += self.serialize_body()
1051
1052         # fixup
1053         self.length = len(body) + struct.calcsize(self._PACK_STR)
1054
1055         # Header
1056         buf = bytearray()
1057         msg_pack_into(self._PACK_STR, buf, 0, self.type, self.length)
1058         buf += body
1059
1060         # Pad
1061         pad_len = utils.round_up(self.length, 8) - self.length
1062         msg_pack_into("%dx" % pad_len, buf, len(buf))
1063
1064         return buf
1065
1066
1067 class OFPPropCommonExperimenter4ByteData(StringifyMixin):
1068     _PACK_STR = '!HHII'
1069     _EXPERIMENTER_DATA_PACK_STR = '!I'
1070     _EXPERIMENTER_DATA_SIZE = 4
1071
1072     def __init__(self, type_=None, length=None, experimenter=None,
1073                  exp_type=None, data=bytearray()):
1074         self.type = type_
1075         self.length = length
1076         self.experimenter = experimenter
1077         self.exp_type = exp_type
1078         self.data = data
1079
1080     @classmethod
1081     def parser(cls, buf):
1082         (type_, length, experimenter, exp_type) = struct.unpack_from(
1083             ofproto.OFP_PROP_EXPERIMENTER_PACK_STR, buf, 0)
1084
1085         rest = buf[ofproto.OFP_PROP_EXPERIMENTER_SIZE:length]
1086         data = []
1087         while rest:
1088             (d,) = struct.unpack_from(
1089                 cls._EXPERIMENTER_DATA_PACK_STR, rest, 0)
1090             data.append(d)
1091             rest = rest[cls._EXPERIMENTER_DATA_SIZE:]
1092
1093         return cls(type_, length, experimenter, exp_type, data)
1094
1095     def serialize(self):
1096         offset = 0
1097         bin_data = bytearray()
1098         for d in self.data:
1099             msg_pack_into(self._EXPERIMENTER_DATA_PACK_STR,
1100                           bin_data, offset, d)
1101             offset += self._EXPERIMENTER_DATA_SIZE
1102
1103         # fixup
1104         self.length = struct.calcsize(self._PACK_STR)
1105         self.length += len(bin_data)
1106
1107         buf = bytearray()
1108         msg_pack_into(self._PACK_STR, buf,
1109                       0, self.type, self.length, self.experimenter,
1110                       self.exp_type)
1111         buf += bin_data
1112
1113         # Pad
1114         pad_len = utils.round_up(self.length, 8) - self.length
1115         msg_pack_into("%dx" % pad_len, buf, len(buf))
1116
1117         return buf
1118
1119
1120 class OFPPortDescProp(OFPPropBase):
1121     _TYPES = {}
1122
1123
1124 @OFPPortDescProp.register_type(ofproto.OFPPDPT_ETHERNET)
1125 class OFPPortDescPropEthernet(OFPPortDescProp):
1126     def __init__(self, type_=None, length=None, curr=None, advertised=None,
1127                  supported=None, peer=None, curr_speed=None, max_speed=None):
1128         self.type = type_
1129         self.length = length
1130         self.curr = curr
1131         self.advertised = advertised
1132         self.supported = supported
1133         self.peer = peer
1134         self.curr_speed = curr_speed
1135         self.max_speed = max_speed
1136
1137     @classmethod
1138     def parser(cls, buf):
1139         ether = cls()
1140         (ether.type, ether.length, ether.curr,
1141          ether.advertised, ether.supported,
1142          ether.peer, ether.curr_speed, ether.max_speed) = struct.unpack_from(
1143             ofproto.OFP_PORT_DESC_PROP_ETHERNET_PACK_STR, buf, 0)
1144         return ether
1145
1146
1147 @OFPPortDescProp.register_type(ofproto.OFPPDPT_OPTICAL)
1148 class OFPPortDescPropOptical(OFPPortDescProp):
1149     def __init__(self, type_=None, length=None, supported=None,
1150                  tx_min_freq_lmda=None, tx_max_freq_lmda=None,
1151                  tx_grid_freq_lmda=None, rx_min_freq_lmda=None,
1152                  rx_max_freq_lmda=None, rx_grid_freq_lmda=None,
1153                  tx_pwr_min=None, tx_pwr_max=None):
1154         self.type = type_
1155         self.length = length
1156         self.supported = supported
1157         self.tx_min_freq_lmda = tx_min_freq_lmda
1158         self.tx_max_freq_lmda = tx_max_freq_lmda
1159         self.tx_grid_freq_lmda = tx_grid_freq_lmda
1160         self.rx_min_freq_lmda = rx_min_freq_lmda
1161         self.rx_max_freq_lmda = rx_max_freq_lmda
1162         self.rx_grid_freq_lmda = rx_grid_freq_lmda
1163         self.tx_pwr_min = tx_pwr_min
1164         self.tx_pwr_max = tx_pwr_max
1165
1166     @classmethod
1167     def parser(cls, buf):
1168         optical = cls()
1169         (optical.type, optical.length, optical.supported,
1170          optical.tx_min_freq_lmda, optical.tx_max_freq_lmda,
1171          optical.tx_grid_freq_lmda, optical.rx_min_freq_lmda,
1172          optical.rx_max_freq_lmda, optical.rx_grid_freq_lmda,
1173          optical.tx_pwr_min, optical.tx_pwr_max) = struct.unpack_from(
1174             ofproto.OFP_PORT_DESC_PROP_OPTICAL_PACK_STR, buf, 0)
1175         return optical
1176
1177
1178 @OFPPortDescProp.register_type(ofproto.OFPPDPT_PIPELINE_INPUT)
1179 @OFPPortDescProp.register_type(ofproto.OFPPDPT_PIPELINE_OUTPUT)
1180 class OFPPortDescPropOxm(OFPPortDescProp):
1181     def __init__(self, type_=None, length=None, oxm_ids=None):
1182         oxm_ids = oxm_ids if oxm_ids else []
1183         super(OFPPortDescPropOxm, self).__init__(type_, length)
1184         self.oxm_ids = oxm_ids
1185
1186     @classmethod
1187     def parser(cls, buf):
1188         rest = cls.get_rest(buf)
1189         ids = []
1190         while rest:
1191             i, rest = OFPOxmId.parse(rest)
1192             ids.append(i)
1193         return cls(oxm_ids=ids)
1194
1195     def serialize_body(self):
1196         bin_ids = bytearray()
1197         for i in self.oxm_ids:
1198             bin_ids += i.serialize()
1199         return bin_ids
1200
1201
1202 @OFPPortDescProp.register_type(ofproto.OFPPDPT_RECIRCULATE)
1203 class OFPPortDescPropRecirculate(OFPPortDescProp):
1204     _PORT_NO_PACK_STR = '!I'
1205
1206     def __init__(self, type_=None, length=None, port_nos=None):
1207         port_nos = port_nos if port_nos else []
1208         super(OFPPortDescPropRecirculate, self).__init__(type_, length)
1209         self.port_nos = port_nos
1210
1211     @classmethod
1212     def parser(cls, buf):
1213         rest = cls.get_rest(buf)
1214         nos = []
1215         while rest:
1216             (n,) = struct.unpack_from(cls._PORT_NO_PACK_STR,
1217                                       six.binary_type(rest), 0)
1218             rest = rest[struct.calcsize(cls._PORT_NO_PACK_STR):]
1219             nos.append(n)
1220         return cls(port_nos=nos)
1221
1222     def serialize_body(self):
1223         bin_nos = bytearray()
1224         for n in self.port_nos:
1225             bin_no = bytearray()
1226             msg_pack_into(self._PORT_NO_PACK_STR, bin_no, 0, n)
1227             bin_nos += bin_no
1228         return bin_nos
1229
1230
1231 @OFPPortDescProp.register_type(ofproto.OFPPDPT_EXPERIMENTER)
1232 class OFPPortDescPropExperimenter(OFPPropCommonExperimenter4ByteData):
1233     pass
1234
1235
1236 class OFPTableModProp(OFPPropBase):
1237     _TYPES = {}
1238
1239
1240 @OFPTableModProp.register_type(ofproto.OFPTMPT_EVICTION)
1241 class OFPTableModPropEviction(OFPTableModProp):
1242     def __init__(self, type_=None, length=None, flags=None):
1243         self.type = type_
1244         self.length = length
1245         self.flags = flags
1246
1247     @classmethod
1248     def parser(cls, buf):
1249         eviction = cls()
1250         (eviction.type, eviction.length, eviction.flags) = struct.unpack_from(
1251             ofproto.OFP_TABLE_MOD_PROP_EVICTION_PACK_STR, buf, 0)
1252         return eviction
1253
1254     def serialize(self):
1255         # fixup
1256         self.length = ofproto.OFP_TABLE_MOD_PROP_EVICTION_SIZE
1257
1258         buf = bytearray()
1259         msg_pack_into(ofproto.OFP_TABLE_MOD_PROP_EVICTION_PACK_STR, buf, 0,
1260                       self.type, self.length, self.flags)
1261         return buf
1262
1263
1264 @OFPTableModProp.register_type(ofproto.OFPTMPT_VACANCY)
1265 class OFPTableModPropVacancy(OFPTableModProp):
1266     def __init__(self, type_=None, length=None, vacancy_down=None,
1267                  vacancy_up=None, vacancy=None):
1268         self.type = type_
1269         self.length = length
1270         self.vacancy_down = vacancy_down
1271         self.vacancy_up = vacancy_up
1272         self.vacancy = vacancy
1273
1274     @classmethod
1275     def parser(cls, buf):
1276         vacancy = cls()
1277         (vacancy.type, vacancy.length, vacancy.vacancy_down,
1278          vacancy.vacancy_up, vacancy.vacancy) = struct.unpack_from(
1279             ofproto.OFP_TABLE_MOD_PROP_VACANCY_PACK_STR, buf, 0)
1280         return vacancy
1281
1282     def serialize(self):
1283         # fixup
1284         self.length = ofproto.OFP_TABLE_MOD_PROP_VACANCY_SIZE
1285
1286         buf = bytearray()
1287         msg_pack_into(ofproto.OFP_TABLE_MOD_PROP_VACANCY_PACK_STR, buf, 0,
1288                       self.type, self.length, self.vacancy_down,
1289                       self.vacancy_up, self.vacancy)
1290         return buf
1291
1292
1293 @OFPTableModProp.register_type(ofproto.OFPTMPT_EXPERIMENTER)
1294 class OFPTableModPropExperimenter(OFPPropCommonExperimenter4ByteData):
1295     pass
1296
1297
1298 class OFPQueueDescProp(OFPPropBase):
1299     _TYPES = {}
1300
1301
1302 @OFPQueueDescProp.register_type(ofproto.OFPQDPT_MIN_RATE)
1303 class OFPQueueDescPropMinRate(OFPQueueDescProp):
1304     def __init__(self, type_=None, length=None, rate=None):
1305         self.type = type_
1306         self.length = length
1307         self.rate = rate
1308
1309     @classmethod
1310     def parser(cls, buf):
1311         minrate = cls()
1312         (minrate.type, minrate.length, minrate.rate) = struct.unpack_from(
1313             ofproto.OFP_QUEUE_DESC_PROP_MIN_RATE_PACK_STR, buf, 0)
1314         return minrate
1315
1316
1317 @OFPQueueDescProp.register_type(ofproto.OFPQDPT_MAX_RATE)
1318 class OFPQueueDescPropMaxRate(OFPQueueDescProp):
1319     def __init__(self, type_=None, length=None, rate=None):
1320         self.type = type_
1321         self.length = length
1322         self.rate = rate
1323
1324     @classmethod
1325     def parser(cls, buf):
1326         maxrate = cls()
1327         (maxrate.type, maxrate.length, maxrate.rate) = struct.unpack_from(
1328             ofproto.OFP_QUEUE_DESC_PROP_MAX_RATE_PACK_STR, buf, 0)
1329         return maxrate
1330
1331
1332 @OFPQueueDescProp.register_type(ofproto.OFPQDPT_EXPERIMENTER)
1333 class OFPQueueDescPropExperimenter(OFPPropCommonExperimenter4ByteData):
1334     pass
1335
1336
1337 class OFPRoleProp(OFPPropBase):
1338     _TYPES = {}
1339
1340
1341 @OFPRoleProp.register_type(ofproto.OFPRPT_EXPERIMENTER)
1342 class OFPRolePropExperimenter(OFPPropCommonExperimenter4ByteData):
1343     pass
1344
1345
1346 class OFPTime(StringifyMixin):
1347     def __init__(self, seconds=None, nanoseconds=None):
1348         self.seconds = seconds
1349         self.nanoseconds = nanoseconds
1350
1351     @classmethod
1352     def parser(cls, buf, offset):
1353         cls_ = cls()
1354         (cls_.seconds, cls_.nanoseconds) = struct.unpack_from(
1355             ofproto.OFP_TIME_PACK_STR, buf, offset)
1356         return cls_
1357
1358     def serialize(self, buf, offset):
1359         msg_pack_into(ofproto.OFP_TIME_PACK_STR, buf, offset,
1360                       self.seconds, self.nanoseconds)
1361         return ofproto.OFP_TIME_SIZE
1362
1363
1364 class OFPBundleProp(OFPPropBase):
1365     _TYPES = {}
1366
1367
1368 @OFPBundleProp.register_type(ofproto.OFPBPT_TIME)
1369 class OFPBundlePropTime(OFPBundleProp):
1370     def __init__(self, type_=None, length=None, scheduled_time=None):
1371         super(OFPBundlePropTime, self).__init__(type_, length)
1372         self.scheduled_time = scheduled_time
1373
1374     @classmethod
1375     def parser(cls, buf):
1376         prop = cls()
1377         offset = ofproto.OFP_BUNDLE_PROP_TIME_PACK_STR0_SIZE
1378         prop.scheduled_time = OFPTime.parser(buf, offset)
1379         return prop
1380
1381     def serialize(self):
1382         # fixup
1383         self.length = ofproto.OFP_BUNDLE_PROP_TIME_PACK_STR_SIZE
1384
1385         buf = bytearray()
1386         msg_pack_into(ofproto.OFP_BUNDLE_PROP_TIME_PACK_STR0, buf, 0,
1387                       self.type, self.length)
1388         offset = ofproto.OFP_BUNDLE_PROP_TIME_PACK_STR0_SIZE
1389         self.scheduled_time.serialize(buf, offset)
1390         return buf
1391
1392
1393 @OFPBundleProp.register_type(ofproto.OFPRPT_EXPERIMENTER)
1394 class OFPBundlePropExperimenter(OFPPropCommonExperimenter4ByteData):
1395     pass
1396
1397
1398 @_register_parser
1399 @_set_msg_type(ofproto.OFPT_PACKET_IN)
1400 class OFPPacketIn(MsgBase):
1401     """
1402     Packet-In message
1403
1404     The switch sends the packet that received to the controller by this
1405     message.
1406
1407     ============= =========================================================
1408     Attribute     Description
1409     ============= =========================================================
1410     buffer_id     ID assigned by datapath
1411     total_len     Full length of frame
1412     reason        Reason packet is being sent.
1413
1414                   | OFPR_TABLE_MISS
1415                   | OFPR_APPLY_ACTION
1416                   | OFPR_INVALID_TTL
1417                   | OFPR_ACTION_SET
1418                   | OFPR_GROUP
1419                   | OFPR_PACKET_OUT
1420     table_id      ID of the table that was looked up
1421     cookie        Cookie of the flow entry that was looked up
1422     match         Instance of ``OFPMatch``
1423     data          Ethernet frame
1424     ============= =========================================================
1425
1426     Example::
1427
1428         @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
1429         def packet_in_handler(self, ev):
1430             msg = ev.msg
1431             dp = msg.datapath
1432             ofp = dp.ofproto
1433
1434             if msg.reason == ofp.TABLE_MISS:
1435                 reason = 'TABLE MISS'
1436             elif msg.reason == ofp.OFPR_APPLY_ACTION:
1437                 reason = 'APPLY ACTION'
1438             elif msg.reason == ofp.OFPR_INVALID_TTL:
1439                 reason = 'INVALID TTL'
1440             elif msg.reason == ofp.OFPR_ACTION_SET:
1441                 reason = 'ACTION SET'
1442             elif msg.reason == ofp.OFPR_GROUP:
1443                 reason = 'GROUP'
1444             elif msg.reason == ofp.OFPR_PACKET_OUT:
1445                 reason = 'PACKET OUT'
1446             else:
1447                 reason = 'unknown'
1448
1449             self.logger.debug('OFPPacketIn received: '
1450                               'buffer_id=%x total_len=%d reason=%s '
1451                               'table_id=%d cookie=%d match=%s data=%s',
1452                               msg.buffer_id, msg.total_len, reason,
1453                               msg.table_id, msg.cookie, msg.match,
1454                               utils.hex_array(msg.data))
1455     """
1456
1457     def __init__(self, datapath, buffer_id=None, total_len=None, reason=None,
1458                  table_id=None, cookie=None, match=None, data=None):
1459         super(OFPPacketIn, self).__init__(datapath)
1460         self.buffer_id = buffer_id
1461         self.total_len = total_len
1462         self.reason = reason
1463         self.table_id = table_id
1464         self.cookie = cookie
1465         self.match = match
1466         self.data = data
1467
1468     @classmethod
1469     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
1470         msg = super(OFPPacketIn, cls).parser(datapath, version, msg_type,
1471                                              msg_len, xid, buf)
1472         (msg.buffer_id, msg.total_len, msg.reason,
1473          msg.table_id, msg.cookie) = struct.unpack_from(
1474             ofproto.OFP_PACKET_IN_PACK_STR,
1475             msg.buf, ofproto.OFP_HEADER_SIZE)
1476
1477         msg.match = OFPMatch.parser(msg.buf, ofproto.OFP_PACKET_IN_SIZE -
1478                                     ofproto.OFP_MATCH_SIZE)
1479
1480         match_len = utils.round_up(msg.match.length, 8)
1481         msg.data = msg.buf[(ofproto.OFP_PACKET_IN_SIZE -
1482                             ofproto.OFP_MATCH_SIZE + match_len + 2):]
1483
1484         if msg.total_len < len(msg.data):
1485             # discard padding for 8-byte alignment of OFP packet
1486             msg.data = msg.data[:msg.total_len]
1487
1488         return msg
1489
1490
1491 @_register_parser
1492 @_set_msg_type(ofproto.OFPT_FLOW_REMOVED)
1493 class OFPFlowRemoved(MsgBase):
1494     """
1495     Flow removed message
1496
1497     When flow entries time out or are deleted, the switch notifies controller
1498     with this message.
1499
1500     ================ ======================================================
1501     Attribute        Description
1502     ================ ======================================================
1503     table_id         ID of the table
1504     reason           One of the following values.
1505
1506                      | OFPRR_IDLE_TIMEOUT
1507                      | OFPRR_HARD_TIMEOUT
1508                      | OFPRR_DELETE
1509                      | OFPRR_GROUP_DELETE
1510                      | OFPRR_METER_DELETE
1511                      | OFPRR_EVICTION
1512     priority         Priority level of flow entry
1513     idle_timeout     Idle timeout from original flow mod
1514     hard_timeout     Hard timeout from original flow mod
1515     cookie           Opaque controller-issued identifier
1516     match            Instance of ``OFPMatch``
1517     stats            Instance of ``OFPStats``
1518     ================ ======================================================
1519
1520     Example::
1521
1522         @set_ev_cls(ofp_event.EventOFPFlowRemoved, MAIN_DISPATCHER)
1523         def flow_removed_handler(self, ev):
1524             msg = ev.msg
1525             dp = msg.datapath
1526             ofp = dp.ofproto
1527
1528             if msg.reason == ofp.OFPRR_IDLE_TIMEOUT:
1529                 reason = 'IDLE TIMEOUT'
1530             elif msg.reason == ofp.OFPRR_HARD_TIMEOUT:
1531                 reason = 'HARD TIMEOUT'
1532             elif msg.reason == ofp.OFPRR_DELETE:
1533                 reason = 'DELETE'
1534             elif msg.reason == ofp.OFPRR_GROUP_DELETE:
1535                 reason = 'GROUP DELETE'
1536             elif msg.reason == ofp.OFPRR_METER_DELETE:
1537                 reason = 'METER DELETE'
1538             elif msg.reason == ofp.OFPRR_EVICTION:
1539                 reason = 'EVICTION'
1540             else:
1541                 reason = 'unknown'
1542
1543             self.logger.debug('OFPFlowRemoved received: '
1544                               'table_id=%d reason=%s priority=%d '
1545                               'idle_timeout=%d hard_timeout=%d cookie=%d '
1546                               'match=%s stats=%s',
1547                               msg.table_id, reason, msg.priority,
1548                               msg.idle_timeout, msg.hard_timeout, msg.cookie,
1549                               msg.match, msg.stats)
1550     """
1551
1552     def __init__(self, datapath, table_id=None, reason=None, priority=None,
1553                  idle_timeout=None, hard_timeout=None, cookie=None,
1554                  match=None, stats=None):
1555         super(OFPFlowRemoved, self).__init__(datapath)
1556         self.table_id = table_id
1557         self.reason = reason
1558         self.priority = priority
1559         self.idle_timeout = idle_timeout
1560         self.hard_timeout = hard_timeout
1561         self.cookie = cookie
1562         self.match = match
1563         self.stats = stats
1564
1565     @classmethod
1566     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
1567         msg = super(OFPFlowRemoved, cls).parser(datapath, version, msg_type,
1568                                                 msg_len, xid, buf)
1569
1570         (msg.table_id, msg.reason, msg.priority, msg.idle_timeout,
1571          msg.hard_timeout, msg.cookie) = struct.unpack_from(
1572             ofproto.OFP_FLOW_REMOVED_PACK_STR0,
1573             msg.buf, ofproto.OFP_HEADER_SIZE)
1574         offset = (ofproto.OFP_FLOW_REMOVED_SIZE - ofproto.OFP_MATCH_SIZE)
1575
1576         msg.match = OFPMatch.parser(msg.buf, offset)
1577         offset += utils.round_up(msg.match.length, 8)
1578
1579         stats_length = msg.msg_len - offset
1580         if stats_length > 0:
1581             msg.stats = OFPStats.parser(buf, offset)
1582
1583         return msg
1584
1585
1586 class OFPPort(StringifyMixin):
1587
1588     """
1589     Description of a port
1590
1591     ========== =========================================================
1592     Attribute  Description
1593     ========== =========================================================
1594     port_no    Port number and it uniquely identifies a port within
1595                a switch.
1596     length     Length of ofp_port (excluding padding).
1597     hw_addr    MAC address for the port.
1598     name       Null-terminated string containing a human-readable name
1599                for the interface.
1600     config     Bitmap of port configration flags.
1601
1602                | OFPPC_PORT_DOWN
1603                | OFPPC_NO_RECV
1604                | OFPPC_NO_FWD
1605                | OFPPC_NO_PACKET_IN
1606     state      Bitmap of port state flags.
1607
1608                | OFPPS_LINK_DOWN
1609                | OFPPS_BLOCKED
1610                | OFPPS_LIVE
1611     properties List of ``OFPPortDescProp`` subclass instance
1612     ========== =========================================================
1613     """
1614
1615     _TYPE = {
1616         'ascii': [
1617             'hw_addr',
1618         ],
1619         'utf-8': [
1620             # OF spec is unclear about the encoding of name.
1621             # we assumes UTF-8, which is used by OVS.
1622             'name',
1623         ]
1624     }
1625
1626     def __init__(self, port_no=None, length=None, hw_addr=None, name=None,
1627                  config=None, state=None, properties=None):
1628         super(OFPPort, self).__init__()
1629         self.port_no = port_no
1630         self.length = length
1631         self.hw_addr = hw_addr
1632         self.name = name
1633         self.config = config
1634         self.state = state
1635         self.properties = properties
1636
1637     @classmethod
1638     def parser(cls, buf, offset):
1639         (port_no, length, hw_addr, name, config, state) = struct.unpack_from(
1640             ofproto.OFP_PORT_PACK_STR, buf, offset)
1641         hw_addr = addrconv.mac.bin_to_text(hw_addr)
1642         name = name.rstrip(b'\0')
1643         props = []
1644         rest = buf[offset + ofproto.OFP_PORT_SIZE:offset + length]
1645         while rest:
1646             p, rest = OFPPortDescProp.parse(rest)
1647             props.append(p)
1648         ofpport = cls(port_no, length, hw_addr, name, config, state, props)
1649         return ofpport
1650
1651
1652 class OFPTableDesc(StringifyMixin):
1653     def __init__(self, length=None, table_id=None, config=None,
1654                  properties=None):
1655         super(OFPTableDesc, self).__init__()
1656         self.table_id = table_id
1657         self.length = length
1658         self.config = config
1659         self.properties = properties
1660
1661     @classmethod
1662     def parser(cls, buf, offset):
1663         (length, table_id, config) = struct.unpack_from(
1664             ofproto.OFP_TABLE_DESC_PACK_STR, buf, offset)
1665         props = []
1666         rest = buf[offset + ofproto.OFP_TABLE_DESC_SIZE:offset + length]
1667         while rest:
1668             p, rest = OFPTableModProp.parse(rest)
1669             props.append(p)
1670         ofptabledesc = cls(length, table_id, config, props)
1671         return ofptabledesc
1672
1673
1674 class OFPQueueDesc(StringifyMixin):
1675     def __init__(self, port_no=None, queue_id=None, len_=None,
1676                  properties=None):
1677         super(OFPQueueDesc, self).__init__()
1678         self.port_no = port_no
1679         self.queue_id = queue_id
1680         self.len = len_
1681         self.properties = properties
1682
1683     @classmethod
1684     def parser(cls, buf, offset):
1685         (port_no, queue_id, len_) = struct.unpack_from(
1686             ofproto.OFP_QUEUE_DESC_PACK_STR, buf, offset)
1687         props = []
1688         rest = buf[offset + ofproto.OFP_QUEUE_DESC_SIZE:offset + len_]
1689         while rest:
1690             p, rest = OFPQueueDescProp.parse(rest)
1691             props.append(p)
1692         ofpqueuedesc = cls(port_no, queue_id, len_, props)
1693         return ofpqueuedesc
1694
1695
1696 def _set_stats_type(stats_type, stats_body_cls):
1697     def _set_cls_stats_type(cls):
1698         cls.cls_stats_type = stats_type
1699         cls.cls_stats_body_cls = stats_body_cls
1700         return cls
1701     return _set_cls_stats_type
1702
1703
1704 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
1705 class OFPMultipartRequest(MsgBase):
1706     def __init__(self, datapath, flags):
1707         super(OFPMultipartRequest, self).__init__(datapath)
1708         self.type = self.__class__.cls_stats_type
1709         self.flags = flags
1710
1711     def _serialize_stats_body(self):
1712         pass
1713
1714     def _serialize_body(self):
1715         msg_pack_into(ofproto.OFP_MULTIPART_REQUEST_PACK_STR,
1716                       self.buf, ofproto.OFP_HEADER_SIZE,
1717                       self.type, self.flags)
1718         self._serialize_stats_body()
1719
1720
1721 @_register_parser
1722 @_set_msg_type(ofproto.OFPT_METER_MOD)
1723 class OFPMeterMod(MsgBase):
1724     """
1725     Meter modification message
1726
1727     The controller sends this message to modify the meter.
1728
1729     ================ ======================================================
1730     Attribute        Description
1731     ================ ======================================================
1732     command          One of the following values.
1733
1734                      | OFPMC_ADD
1735                      | OFPMC_MODIFY
1736                      | OFPMC_DELETE
1737     flags            Bitmap of the following flags.
1738
1739                      | OFPMF_KBPS
1740                      | OFPMF_PKTPS
1741                      | OFPMF_BURST
1742                      | OFPMF_STATS
1743     meter_id         Meter instance
1744     bands            list of the following class instance.
1745
1746                      | OFPMeterBandDrop
1747                      | OFPMeterBandDscpRemark
1748                      | OFPMeterBandExperimenter
1749     ================ ======================================================
1750     """
1751
1752     def __init__(self, datapath, command=ofproto.OFPMC_ADD,
1753                  flags=ofproto.OFPMF_KBPS, meter_id=1, bands=None):
1754         bands = bands if bands else []
1755         super(OFPMeterMod, self).__init__(datapath)
1756         self.command = command
1757         self.flags = flags
1758         self.meter_id = meter_id
1759         self.bands = bands
1760
1761     @classmethod
1762     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
1763         msg = super(OFPMeterMod, cls).parser(
1764             datapath, version, msg_type, msg_len, xid, buf)
1765
1766         (msg.command, msg.flags, msg.meter_id) = struct.unpack_from(
1767             ofproto.OFP_METER_MOD_PACK_STR, buf, ofproto.OFP_HEADER_SIZE)
1768         offset = ofproto.OFP_METER_MOD_SIZE
1769
1770         msg.bands = []
1771         while offset < msg.msg_len:
1772             band = OFPMeterBandHeader.parser(buf, offset)
1773             msg.bands.append(band)
1774             offset += band.len
1775
1776         return msg
1777
1778     def _serialize_body(self):
1779         msg_pack_into(ofproto.OFP_METER_MOD_PACK_STR, self.buf,
1780                       ofproto.OFP_HEADER_SIZE,
1781                       self.command, self.flags, self.meter_id)
1782
1783         offset = ofproto.OFP_METER_MOD_SIZE
1784         for b in self.bands:
1785             b.serialize(self.buf, offset)
1786             offset += b.len
1787
1788
1789 @_set_msg_type(ofproto.OFPT_TABLE_MOD)
1790 class OFPTableMod(MsgBase):
1791     """
1792     Flow table configuration message
1793
1794     The controller sends this message to configure table state.
1795
1796     ================ ======================================================
1797     Attribute        Description
1798     ================ ======================================================
1799     table_id         ID of the table (OFPTT_ALL indicates all tables)
1800     config           Bitmap of configuration flags.
1801
1802                      | OFPTC_EVICTION
1803                      | OFPTC_VACANCY_EVENTS
1804     properties       List of ``OFPTableModProp`` subclass instance
1805     ================ ======================================================
1806
1807     Example::
1808
1809         def send_table_mod(self, datapath):
1810             ofp = datapath.ofproto
1811             ofp_parser = datapath.ofproto_parser
1812
1813             req = ofp_parser.OFPTableMod(datapath, 1, 3)
1814             flags = ofp.OFPTC_VACANCY_EVENTS
1815             properties = [ofp_parser.OFPTableModPropEviction(flags)]
1816             req = ofp_parser.OFPTableMod(datapath, 1, 3, properties)
1817             datapath.send_msg(req)
1818     """
1819
1820     def __init__(self, datapath, table_id, config, properties):
1821         super(OFPTableMod, self).__init__(datapath)
1822         self.table_id = table_id
1823         self.config = config
1824         self.properties = properties
1825
1826     def _serialize_body(self):
1827         props_buf = bytearray()
1828         for p in self.properties:
1829             props_buf += p.serialize()
1830
1831         msg_pack_into(ofproto.OFP_TABLE_MOD_PACK_STR, self.buf,
1832                       ofproto.OFP_HEADER_SIZE,
1833                       self.table_id, self.config)
1834
1835         self.buf += props_buf
1836
1837
1838 @_register_parser
1839 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
1840 class OFPMultipartReply(MsgBase):
1841     _STATS_MSG_TYPES = {}
1842
1843     @staticmethod
1844     def register_stats_type(body_single_struct=False):
1845         def _register_stats_type(cls):
1846             assert cls.cls_stats_type is not None
1847             assert cls.cls_stats_type not in OFPMultipartReply._STATS_MSG_TYPES
1848             assert cls.cls_stats_body_cls is not None
1849             cls.cls_body_single_struct = body_single_struct
1850             OFPMultipartReply._STATS_MSG_TYPES[cls.cls_stats_type] = cls
1851             return cls
1852         return _register_stats_type
1853
1854     def __init__(self, datapath, body=None, flags=None):
1855         super(OFPMultipartReply, self).__init__(datapath)
1856         self.body = body
1857         self.flags = flags
1858
1859     @classmethod
1860     def parser_stats_body(cls, buf, msg_len, offset):
1861         body_cls = cls.cls_stats_body_cls
1862         body = []
1863         while offset < msg_len:
1864             entry = body_cls.parser(buf, offset)
1865             body.append(entry)
1866             offset += entry.length
1867
1868         if cls.cls_body_single_struct:
1869             return body[0]
1870         return body
1871
1872     @classmethod
1873     def parser_stats(cls, datapath, version, msg_type, msg_len, xid, buf):
1874         msg = MsgBase.parser.__func__(
1875             cls, datapath, version, msg_type, msg_len, xid, buf)
1876         msg.body = msg.parser_stats_body(msg.buf, msg.msg_len,
1877                                          ofproto.OFP_MULTIPART_REPLY_SIZE)
1878         return msg
1879
1880     @classmethod
1881     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
1882         type_, flags = struct.unpack_from(
1883             ofproto.OFP_MULTIPART_REPLY_PACK_STR, six.binary_type(buf),
1884             ofproto.OFP_HEADER_SIZE)
1885         stats_type_cls = cls._STATS_MSG_TYPES.get(type_)
1886         msg = super(OFPMultipartReply, stats_type_cls).parser(
1887             datapath, version, msg_type, msg_len, xid, buf)
1888         msg.type = type_
1889         msg.flags = flags
1890
1891         offset = ofproto.OFP_MULTIPART_REPLY_SIZE
1892         body = []
1893         while offset < msg_len:
1894             b = stats_type_cls.cls_stats_body_cls.parser(msg.buf, offset)
1895             offset_step = b.length if hasattr(b, 'length') else b.len
1896             if offset_step < 1:
1897                 raise exception.OFPMalformedMessage()
1898             body.append(b)
1899             offset += offset_step
1900
1901         if stats_type_cls.cls_body_single_struct:
1902             msg.body = body[0]
1903         else:
1904             msg.body = body
1905         return msg
1906
1907
1908 class OFPDescStats(ofproto_parser.namedtuple('OFPDescStats', (
1909         'mfr_desc', 'hw_desc', 'sw_desc', 'serial_num', 'dp_desc'))):
1910
1911     _TYPE = {
1912         'ascii': [
1913             'mfr_desc',
1914             'hw_desc',
1915             'sw_desc',
1916             'serial_num',
1917             'dp_desc',
1918         ]
1919     }
1920
1921     @classmethod
1922     def parser(cls, buf, offset):
1923         desc = struct.unpack_from(ofproto.OFP_DESC_PACK_STR,
1924                                   buf, offset)
1925         desc = list(desc)
1926         desc = [x.rstrip(b'\0') for x in desc]
1927         stats = cls(*desc)
1928         stats.length = ofproto.OFP_DESC_SIZE
1929         return stats
1930
1931
1932 @_set_stats_type(ofproto.OFPMP_DESC, OFPDescStats)
1933 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
1934 class OFPDescStatsRequest(OFPMultipartRequest):
1935     """
1936     Description statistics request message
1937
1938     The controller uses this message to query description of the switch.
1939
1940     ================ ======================================================
1941     Attribute        Description
1942     ================ ======================================================
1943     flags            Zero or ``OFPMPF_REQ_MORE``
1944     ================ ======================================================
1945
1946     Example::
1947
1948         def send_desc_stats_request(self, datapath):
1949             ofp_parser = datapath.ofproto_parser
1950
1951             req = ofp_parser.OFPDescStatsRequest(datapath, 0)
1952             datapath.send_msg(req)
1953     """
1954
1955     def __init__(self, datapath, flags=0, type_=None):
1956         super(OFPDescStatsRequest, self).__init__(datapath, flags)
1957
1958
1959 @OFPMultipartReply.register_stats_type(body_single_struct=True)
1960 @_set_stats_type(ofproto.OFPMP_DESC, OFPDescStats)
1961 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
1962 class OFPDescStatsReply(OFPMultipartReply):
1963     """
1964     Description statistics reply message
1965
1966     The switch responds with this message to a description statistics
1967     request.
1968
1969     ================ ======================================================
1970     Attribute        Description
1971     ================ ======================================================
1972     body             Instance of ``OFPDescStats``
1973     ================ ======================================================
1974
1975     Example::
1976
1977         @set_ev_cls(ofp_event.EventOFPDescStatsReply, MAIN_DISPATCHER)
1978         def desc_stats_reply_handler(self, ev):
1979             body = ev.msg.body
1980
1981             self.logger.debug('DescStats: mfr_desc=%s hw_desc=%s sw_desc=%s '
1982                               'serial_num=%s dp_desc=%s',
1983                               body.mfr_desc, body.hw_desc, body.sw_desc,
1984                               body.serial_num, body.dp_desc)
1985     """
1986
1987     def __init__(self, datapath, type_=None, **kwargs):
1988         super(OFPDescStatsReply, self).__init__(datapath, **kwargs)
1989
1990
1991 class OFPTableFeaturesStats(StringifyMixin):
1992
1993     _TYPE = {
1994         'utf-8': [
1995             # OF spec is unclear about the encoding of name.
1996             # we assumes UTF-8.
1997             'name',
1998         ]
1999     }
2000
2001     def __init__(self, table_id=None, command=None, features=None, name=None,
2002                  metadata_match=None, metadata_write=None, capabilities=None,
2003                  max_entries=None, properties=None, length=None):
2004         super(OFPTableFeaturesStats, self).__init__()
2005         self.length = length
2006         self.table_id = table_id
2007         self.command = command
2008         self.features = features
2009         self.name = name
2010         self.metadata_match = metadata_match
2011         self.metadata_write = metadata_write
2012         self.capabilities = capabilities
2013         self.max_entries = max_entries
2014         self.properties = properties
2015
2016     @classmethod
2017     def parser(cls, buf, offset):
2018         tbl = cls()
2019         (tbl.length, tbl.table_id, tbl.command, tbl.features,
2020          name, tbl.metadata_match, tbl.metadata_write,
2021          tbl.capabilities, tbl.max_entries
2022          ) = struct.unpack_from(ofproto.OFP_TABLE_FEATURES_PACK_STR,
2023                                 buf, offset)
2024         tbl.name = name.rstrip(b'\0')
2025
2026         props = []
2027         rest = buf[offset + ofproto.OFP_TABLE_FEATURES_SIZE:
2028                    offset + tbl.length]
2029         while rest:
2030             p, rest = OFPTableFeatureProp.parse(rest)
2031             props.append(p)
2032         tbl.properties = props
2033
2034         return tbl
2035
2036     def serialize(self):
2037         # fixup
2038         bin_props = bytearray()
2039         for p in self.properties:
2040             bin_props += p.serialize()
2041         self.length = ofproto.OFP_TABLE_FEATURES_SIZE + len(bin_props)
2042
2043         buf = bytearray()
2044         msg_pack_into(ofproto.OFP_TABLE_FEATURES_PACK_STR, buf, 0,
2045                       self.length, self.table_id, self.command, self.features,
2046                       self.name, self.metadata_match, self.metadata_write,
2047                       self.capabilities, self.max_entries)
2048         return buf + bin_props
2049
2050
2051 class OFPTableFeatureProp(OFPPropBase):
2052     _TYPES = {}
2053
2054
2055 class OFPInstructionId(StringifyMixin):
2056     _PACK_STR = '!HH'  # type, len
2057
2058     def __init__(self, type_, len_=None):
2059         self.type = type_
2060         self.len = len_
2061         # XXX experimenter
2062
2063     @classmethod
2064     def parse(cls, buf):
2065         (type_, len_,) = struct.unpack_from(cls._PACK_STR, six.binary_type(buf), 0)
2066         rest = buf[len_:]
2067         return cls(type_=type_, len_=len_), rest
2068
2069     def serialize(self):
2070         # fixup
2071         self.len = struct.calcsize(self._PACK_STR)
2072
2073         buf = bytearray()
2074         msg_pack_into(self._PACK_STR, buf, 0, self.type, self.len)
2075         return buf
2076
2077
2078 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_INSTRUCTIONS)
2079 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_INSTRUCTIONS_MISS)
2080 class OFPTableFeaturePropInstructions(OFPTableFeatureProp):
2081     def __init__(self, type_=None, length=None, instruction_ids=None):
2082         instruction_ids = instruction_ids if instruction_ids else []
2083         super(OFPTableFeaturePropInstructions, self).__init__(type_, length)
2084         self.instruction_ids = instruction_ids
2085
2086     @classmethod
2087     def parser(cls, buf):
2088         rest = cls.get_rest(buf)
2089         ids = []
2090         while rest:
2091             i, rest = OFPInstructionId.parse(rest)
2092             ids.append(i)
2093         return cls(instruction_ids=ids)
2094
2095     def serialize_body(self):
2096         bin_ids = bytearray()
2097         for i in self.instruction_ids:
2098             bin_ids += i.serialize()
2099
2100         return bin_ids
2101
2102
2103 # Implementation note: While OpenFlow 1.3.2 shares the same ofp_action_header
2104 # for flow_mod and table_features, we have separate classes.  We named this
2105 # class to match with OpenFlow 1.4's name.  (ofp_action_id)
2106 class OFPActionId(StringifyMixin):
2107     _PACK_STR = '!HH'  # type, len
2108
2109     def __init__(self, type_, len_=None):
2110         self.type = type_
2111         self.len = len_
2112         # XXX experimenter
2113
2114     @classmethod
2115     def parse(cls, buf):
2116         (type_, len_,) = struct.unpack_from(cls._PACK_STR, six.binary_type(buf), 0)
2117         rest = buf[len_:]
2118         return cls(type_=type_, len_=len_), rest
2119
2120     def serialize(self):
2121         # fixup
2122         self.len = struct.calcsize(self._PACK_STR)
2123
2124         buf = bytearray()
2125         msg_pack_into(self._PACK_STR, buf, 0, self.type, self.len)
2126         return buf
2127
2128
2129 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_WRITE_ACTIONS)
2130 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_WRITE_ACTIONS_MISS)
2131 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_APPLY_ACTIONS)
2132 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_APPLY_ACTIONS_MISS)
2133 class OFPTableFeaturePropActions(OFPTableFeatureProp):
2134     def __init__(self, type_=None, length=None, action_ids=None):
2135         action_ids = action_ids if action_ids else []
2136         super(OFPTableFeaturePropActions, self).__init__(type_, length)
2137         self.action_ids = action_ids
2138
2139     @classmethod
2140     def parser(cls, buf):
2141         rest = cls.get_rest(buf)
2142         ids = []
2143         while rest:
2144             i, rest = OFPActionId.parse(rest)
2145             ids.append(i)
2146         return cls(action_ids=ids)
2147
2148     def serialize_body(self):
2149         bin_ids = bytearray()
2150         for i in self.action_ids:
2151             bin_ids += i.serialize()
2152         return bin_ids
2153
2154
2155 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_NEXT_TABLES)
2156 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_NEXT_TABLES_MISS)
2157 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_TABLE_SYNC_FROM)
2158 class OFPTableFeaturePropNextTables(OFPTableFeatureProp):
2159     _TABLE_ID_PACK_STR = '!B'
2160
2161     def __init__(self, type_=None, length=None, table_ids=None):
2162         table_ids = table_ids if table_ids else []
2163         super(OFPTableFeaturePropNextTables, self).__init__(type_, length)
2164         self.table_ids = table_ids
2165
2166     @classmethod
2167     def parser(cls, buf):
2168         rest = cls.get_rest(buf)
2169         ids = []
2170         while rest:
2171             (i,) = struct.unpack_from(cls._TABLE_ID_PACK_STR, six.binary_type(rest), 0)
2172             rest = rest[struct.calcsize(cls._TABLE_ID_PACK_STR):]
2173             ids.append(i)
2174         return cls(table_ids=ids)
2175
2176     def serialize_body(self):
2177         bin_ids = bytearray()
2178         for i in self.table_ids:
2179             bin_id = bytearray()
2180             msg_pack_into(self._TABLE_ID_PACK_STR, bin_id, 0, i)
2181             bin_ids += bin_id
2182         return bin_ids
2183
2184
2185 # Implementation note: OFPOxmId is specific to this implementation.
2186 # It does not have a corresponding structure in the specification.
2187 # (the specification uses plain uint32_t for non-experimenter OXMs
2188 # and uint64_t for experimenter OXMs.)
2189 #
2190 # i have taken a look at some of software switch implementations
2191 # but they all look broken or incomplete.  according to the spec,
2192 # oxm_hasmask should be 1 if a switch supports masking for the type.
2193 # the right value for oxm_length is not clear from the spec.
2194 # update: OpenFlow 1.3.3 "clarified" that oxm_length here is the payload
2195 # length.  it's still unclear if it should be doubled for hasmask or not,
2196 # though.
2197 #   ofsoftswitch13
2198 #     oxm_hasmask  always 0
2199 #     oxm_length   same as ofp_match etc (as without mask)
2200 #   linc/of_protocol
2201 #     oxm_hasmask  always 0
2202 #     oxm_length   always 0
2203 #   ovs:
2204 #     seems in flux as of writing this [20141003]
2205 # updtate: OVS checks the oxm_length strictly which contained in
2206 # the OFPAT_COPY_FIELD action when using OpenFlow 1.5, so here composes the
2207 # payload length as the oxm_length (if has mask, it will be doubled, still
2208 # unclear though).
2209 class OFPOxmId(StringifyMixin):
2210     _PACK_STR = '!I'  # oxm header
2211     _EXPERIMENTER_ID_PACK_STR = '!I'
2212
2213     _TYPE = {
2214         'ascii': [
2215             'type',
2216         ],
2217     }
2218
2219     def __init__(self, type_, hasmask=False, length=None):
2220         self.type = type_
2221         self.hasmask = hasmask
2222         self.length = length
2223
2224     @classmethod
2225     def parse(cls, buf):
2226         (oxm,) = struct.unpack_from(cls._PACK_STR, six.binary_type(buf), 0)
2227         # oxm (32 bit) == class (16) | field (7) | hasmask (1) | length (8)
2228         # in case of experimenter OXMs, another 32 bit value
2229         # (experimenter id) follows.
2230         (type_, _v) = ofproto.oxm_to_user(oxm >> (1 + 8), None, None)
2231         rest = buf[struct.calcsize(cls._PACK_STR):]
2232         hasmask = ofproto.oxm_tlv_header_extract_hasmask(oxm)
2233         length = oxm & 0xff  # XXX see the comment on OFPOxmId
2234         class_ = oxm >> (7 + 1 + 8)
2235         if class_ == ofproto.OFPXMC_EXPERIMENTER:
2236             (exp_id,) = struct.unpack_from(cls._EXPERIMENTER_ID_PACK_STR,
2237                                            six.binary_type(rest), 0)
2238             rest = rest[struct.calcsize(cls._EXPERIMENTER_ID_PACK_STR):]
2239             subcls = OFPExperimenterOxmId
2240             return subcls(type_=type_, exp_id=exp_id, hasmask=hasmask,
2241                           length=length), rest
2242         else:
2243             return cls(type_=type_, hasmask=hasmask, length=length), rest
2244
2245     def serialize(self):
2246         n, t = ofproto.oxm_get_field_info_by_name(self.type)
2247         if not self.length:
2248             # XXX see the comment on OFPOxmId
2249             self.length = t.size * 2 if self.hasmask else t.size
2250         oxm = (n << (1 + 8)) | (self.hasmask << 8) | self.length
2251         buf = bytearray()
2252         msg_pack_into(self._PACK_STR, buf, 0, oxm)
2253         assert n >> 7 != ofproto.OFPXMC_EXPERIMENTER
2254         return buf
2255
2256
2257 class OFPExperimenterOxmId(OFPOxmId):
2258     def __init__(self, type_, exp_id, hasmask=False, length=None):
2259         super(OFPExperimenterOxmId, self).__init__(type_=type_,
2260                                                    hasmask=hasmask,
2261                                                    length=length)
2262         self.exp_id = exp_id
2263
2264     def serialize(self):
2265         buf = super(OFPExperimenterOxmId, self).serialize()
2266         msg_pack_into(self._EXPERIMENTER_ID_PACK_STR, buf,
2267                       struct.calcsize(self._PACK_STR), self.exp_id)
2268
2269
2270 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_MATCH)
2271 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_WILDCARDS)
2272 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_WRITE_SETFIELD)
2273 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_WRITE_SETFIELD_MISS)
2274 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_APPLY_SETFIELD)
2275 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_APPLY_SETFIELD_MISS)
2276 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_WRITE_COPYFIELD)
2277 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_WRITE_COPYFIELD_MISS)
2278 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_APPLY_COPYFIELD)
2279 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_APPLY_COPYFIELD_MISS)
2280 class OFPTableFeaturePropOxm(OFPTableFeatureProp):
2281     def __init__(self, type_=None, length=None, oxm_ids=None):
2282         oxm_ids = oxm_ids if oxm_ids else []
2283         super(OFPTableFeaturePropOxm, self).__init__(type_, length)
2284         self.oxm_ids = oxm_ids
2285
2286     @classmethod
2287     def parser(cls, buf):
2288         rest = cls.get_rest(buf)
2289         ids = []
2290         while rest:
2291             i, rest = OFPOxmId.parse(rest)
2292             ids.append(i)
2293         return cls(oxm_ids=ids)
2294
2295     def serialize_body(self):
2296         bin_ids = bytearray()
2297         for i in self.oxm_ids:
2298             bin_ids += i.serialize()
2299         return bin_ids
2300
2301
2302 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_PACKET_TYPES)
2303 class OFPTableFeaturePropOxmValues(OFPTableFeatureProp):
2304     def __init__(self, type_=None, length=None, _ordered_values=None,
2305                  **kwargs):
2306         super(OFPTableFeaturePropOxmValues, self).__init__(type_, length)
2307         if _ordered_values is not None:
2308             assert not kwargs
2309             self.oxm_values = _ordered_values
2310         else:
2311             kwargs = dict(ofproto.oxm_normalize_user(k, v) for
2312                           (k, v) in kwargs.items())
2313             values = [ofproto.oxm_from_user(k, v) for (k, v)
2314                       in kwargs.items()]
2315             # assumption: sorting by OXM type values makes fields
2316             # meet ordering requirements (eg. eth_type before ipv4_src)
2317             values.sort(
2318                 key=lambda x: x[0][0] if isinstance(x[0], tuple) else x[0])
2319             self.oxm_values = [ofproto.oxm_to_user(n, v, m) for (n, v, m)
2320                                in values]
2321
2322     @classmethod
2323     def parser(cls, buf):
2324         rest = cls.get_rest(buf)
2325         values = []
2326         while rest:
2327             n, value, mask, field_len = ofproto.oxm_parse(rest, 0)
2328             k, uv = ofproto.oxm_to_user(n, value, mask)
2329             values.append((k, uv))
2330             rest = rest[field_len:]
2331         return cls(_ordered_values=values)
2332
2333     def serialize_body(self):
2334         values = [ofproto.oxm_from_user(k, uv) for (k, uv)
2335                   in self.oxm_values]
2336         offset = 0
2337         buf = bytearray()
2338         for (n, value, mask) in values:
2339             offset += ofproto.oxm_serialize(n, value, mask, buf, offset)
2340         return buf
2341
2342     def __getitem__(self, key):
2343         return dict(self.oxm_values)[key]
2344
2345     def __contains__(self, key):
2346         return key in dict(self.oxm_values)
2347
2348     def iteritems(self):
2349         return iter(dict(self.oxm_values).items())
2350
2351     def items(self):
2352         return self.oxm_values
2353
2354     def get(self, key, default=None):
2355         return dict(self.oxm_values).get(key, default)
2356
2357     def stringify_attrs(self):
2358         yield "oxm_values", dict(self.oxm_values)
2359
2360     def to_jsondict(self):
2361         """
2362         Returns a dict expressing the OXM values.
2363         """
2364         body = {"oxm_values": [ofproto.oxm_to_jsondict(k, uv) for k, uv
2365                                in self.oxm_values],
2366                 "length": self.length,
2367                 "type": self.type}
2368         return {self.__class__.__name__: body}
2369
2370     @classmethod
2371     def from_jsondict(cls, dict_):
2372         """
2373         Returns an object which is generated from a dict.
2374         Exception raises:
2375         KeyError -- Unknown OXM value is defined in dict
2376         """
2377         type_ = dict_['type']
2378         values = [ofproto.oxm_from_jsondict(f) for f
2379                   in dict_['oxm_values']]
2380         return cls(type_=type_, _ordered_values=values)
2381
2382
2383 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_EXPERIMENTER)
2384 @OFPTableFeatureProp.register_type(ofproto.OFPTFPT_EXPERIMENTER_MISS)
2385 class OFPTableFeaturePropExperimenter(OFPPropCommonExperimenter4ByteData):
2386     pass
2387
2388
2389 @_set_stats_type(ofproto.OFPMP_TABLE_FEATURES, OFPTableFeaturesStats)
2390 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
2391 class OFPTableFeaturesStatsRequest(OFPMultipartRequest):
2392     """
2393     Table features statistics request message
2394
2395     The controller uses this message to query table features.
2396
2397     ================ ======================================================
2398     Attribute        Description
2399     ================ ======================================================
2400     body             List of ``OFPTableFeaturesStats`` instances.
2401                      The default is [].
2402     ================ ======================================================
2403     """
2404
2405     def __init__(self, datapath, flags=0, body=None, type_=None):
2406         body = body if body else []
2407         super(OFPTableFeaturesStatsRequest, self).__init__(datapath, flags)
2408         self.body = body
2409
2410     def _serialize_stats_body(self):
2411         bin_body = bytearray()
2412         for p in self.body:
2413             bin_body += p.serialize()
2414         self.buf += bin_body
2415
2416
2417 @OFPMultipartReply.register_stats_type()
2418 @_set_stats_type(ofproto.OFPMP_TABLE_FEATURES, OFPTableFeaturesStats)
2419 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
2420 class OFPTableFeaturesStatsReply(OFPMultipartReply):
2421     """
2422     Table features statistics reply message
2423
2424     The switch responds with this message to a table features statistics
2425     request.
2426
2427     ================ ======================================================
2428     Attribute        Description
2429     ================ ======================================================
2430     body             List of ``OFPTableFeaturesStats`` instance
2431     ================ ======================================================
2432     """
2433
2434     def __init__(self, datapath, type_=None, **kwargs):
2435         super(OFPTableFeaturesStatsReply, self).__init__(datapath, **kwargs)
2436
2437
2438 @_set_stats_type(ofproto.OFPMP_PORT_DESC, OFPPort)
2439 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
2440 class OFPPortDescStatsRequest(OFPMultipartRequest):
2441     """
2442     Port description request message
2443
2444     The controller uses this message to query description of one or all the ports.
2445
2446     ================ ======================================================
2447     Attribute        Description
2448     ================ ======================================================
2449     flags            Zero or ``OFPMPF_REQ_MORE``
2450     port_no          Port number to read (OFPP_ANY to all ports)
2451     ================ ======================================================
2452
2453     Example::
2454
2455         def send_port_desc_stats_request(self, datapath):
2456             ofp = datapath.ofproto
2457             ofp_parser = datapath.ofproto_parser
2458
2459             req = ofp_parser.OFPPortDescStatsRequest(datapath, 0, ofp.OFPP_ANY)
2460             datapath.send_msg(req)
2461     """
2462
2463     def __init__(self, datapath, flags=0, port_no=ofproto.OFPP_ANY, type_=None):
2464         super(OFPPortDescStatsRequest, self).__init__(datapath, flags)
2465         self.port_no = port_no
2466
2467     def _serialize_stats_body(self):
2468         msg_pack_into(ofproto.OFP_PORT_MULTIPART_REQUEST_PACK_STR,
2469                       self.buf,
2470                       ofproto.OFP_MULTIPART_REQUEST_SIZE,
2471                       self.port_no)
2472
2473
2474 @OFPMultipartReply.register_stats_type()
2475 @_set_stats_type(ofproto.OFPMP_PORT_DESC, OFPPort)
2476 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
2477 class OFPPortDescStatsReply(OFPMultipartReply):
2478     """
2479     Port description reply message
2480
2481     The switch responds with this message to a port description request.
2482
2483     ================ ======================================================
2484     Attribute        Description
2485     ================ ======================================================
2486     body             List of ``OFPPort`` instance
2487     ================ ======================================================
2488
2489     Example::
2490
2491         @set_ev_cls(ofp_event.EventOFPPortDescStatsReply, MAIN_DISPATCHER)
2492         def port_desc_stats_reply_handler(self, ev):
2493             ports = []
2494             for p in ev.msg.body:
2495                 ports.append('port_no=%d hw_addr=%s name=%s config=0x%08x '
2496                              'state=0x%08x properties=%s' %
2497                              (p.port_no, p.hw_addr,
2498                               p.name, p.config, p.state, repr(p.properties)))
2499             self.logger.debug('OFPPortDescStatsReply received: %s', ports)
2500     """
2501
2502     def __init__(self, datapath, type_=None, **kwargs):
2503         super(OFPPortDescStatsReply, self).__init__(datapath, **kwargs)
2504
2505
2506 @_set_stats_type(ofproto.OFPMP_TABLE_DESC, OFPTableDesc)
2507 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
2508 class OFPTableDescStatsRequest(OFPMultipartRequest):
2509     """
2510     Table description request message
2511
2512     The controller uses this message to query description of all the tables.
2513
2514     ================ ======================================================
2515     Attribute        Description
2516     ================ ======================================================
2517     flags            Zero or ``OFPMPF_REQ_MORE``
2518     ================ ======================================================
2519
2520     Example::
2521
2522         def send_table_desc_stats_request(self, datapath):
2523             ofp_parser = datapath.ofproto_parser
2524
2525             req = ofp_parser.OFPTableDescStatsRequest(datapath, 0)
2526             datapath.send_msg(req)
2527     """
2528
2529     def __init__(self, datapath, flags=0, type_=None):
2530         super(OFPTableDescStatsRequest, self).__init__(datapath, flags)
2531
2532
2533 @OFPMultipartReply.register_stats_type()
2534 @_set_stats_type(ofproto.OFPMP_TABLE_DESC, OFPTableDesc)
2535 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
2536 class OFPTableDescStatsReply(OFPMultipartReply):
2537     """
2538     Table description reply message
2539
2540     The switch responds with this message to a table description request.
2541
2542     ================ ======================================================
2543     Attribute        Description
2544     ================ ======================================================
2545     body             List of ``OFPTableDesc`` instance
2546     ================ ======================================================
2547
2548     Example::
2549
2550         @set_ev_cls(ofp_event.EventOFPTableDescStatsReply, MAIN_DISPATCHER)
2551         def table_desc_stats_reply_handler(self, ev):
2552             tables = []
2553             for p in ev.msg.body:
2554                 tables.append('table_id=%d config=0x%08x properties=%s' %
2555                              (p.table_id, p.config, repr(p.properties)))
2556             self.logger.debug('OFPTableDescStatsReply received: %s', tables)
2557     """
2558
2559     def __init__(self, datapath, type_=None, **kwargs):
2560         super(OFPTableDescStatsReply, self).__init__(datapath, **kwargs)
2561
2562
2563 @_set_stats_type(ofproto.OFPMP_QUEUE_DESC, OFPQueueDesc)
2564 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
2565 class OFPQueueDescStatsRequest(OFPMultipartRequest):
2566     """
2567     Queue description request message
2568
2569     The controller uses this message to query description of all the queues.
2570
2571     ================ ======================================================
2572     Attribute        Description
2573     ================ ======================================================
2574     flags            Zero or ``OFPMPF_REQ_MORE``
2575     port_no          Port number to read (OFPP_ANY for all ports)
2576     queue_id         ID of queue to read (OFPQ_ALL for all queues)
2577     ================ ======================================================
2578
2579     Example::
2580
2581         def send_queue_desc_stats_request(self, datapath):
2582             ofp = datapath.ofproto
2583             ofp_parser = datapath.ofproto_parser
2584
2585             req = ofp_parser.OFPQueueDescStatsRequest(datapath, 0,
2586                                                       ofp.OFPP_ANY,
2587                                                       ofp.OFPQ_ALL)
2588             datapath.send_msg(req)
2589     """
2590
2591     def __init__(self, datapath, flags=0, port_no=ofproto.OFPP_ANY,
2592                  queue_id=ofproto.OFPQ_ALL, type_=None):
2593         super(OFPQueueDescStatsRequest, self).__init__(datapath, flags)
2594         self.port_no = port_no
2595         self.queue_id = queue_id
2596
2597     def _serialize_stats_body(self):
2598         msg_pack_into(ofproto.OFP_QUEUE_MULTIPART_REQUEST_PACK_STR,
2599                       self.buf,
2600                       ofproto.OFP_MULTIPART_REQUEST_SIZE,
2601                       self.port_no, self.queue_id)
2602
2603
2604 @OFPMultipartReply.register_stats_type()
2605 @_set_stats_type(ofproto.OFPMP_QUEUE_DESC, OFPQueueDesc)
2606 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
2607 class OFPQueueDescStatsReply(OFPMultipartReply):
2608     """
2609     Queue description reply message
2610
2611     The switch responds with this message to a queue description request.
2612
2613     ================ ======================================================
2614     Attribute        Description
2615     ================ ======================================================
2616     body             List of ``OFPQueueDesc`` instance
2617     ================ ======================================================
2618
2619     Example::
2620
2621         @set_ev_cls(ofp_event.EventOFPQueueDescStatsReply, MAIN_DISPATCHER)
2622         def queue_desc_stats_reply_handler(self, ev):
2623             queues = []
2624             for q in ev.msg.body:
2625                 queues.append('port_no=%d queue_id=0x%08x properties=%s' %
2626                              (q.port_no, q.queue_id, repr(q.properties)))
2627             self.logger.debug('OFPQueueDescStatsReply received: %s', queues)
2628     """
2629
2630     def __init__(self, datapath, type_=None, **kwargs):
2631         super(OFPQueueDescStatsReply, self).__init__(datapath, **kwargs)
2632
2633
2634 class OFPQueueStatsProp(OFPPropBase):
2635     _TYPES = {}
2636
2637
2638 @OFPQueueStatsProp.register_type(ofproto.OFPQSPT_EXPERIMENTER)
2639 class OFPQueueStatsPropExperimenter(OFPPropCommonExperimenter4ByteData):
2640     pass
2641
2642
2643 class OFPQueueStats(StringifyMixin):
2644     def __init__(self, length=None, port_no=None, queue_id=None,
2645                  tx_bytes=None, tx_packets=None, tx_errors=None,
2646                  duration_sec=None, duration_nsec=None, properties=None):
2647         super(OFPQueueStats, self).__init__()
2648         self.length = length
2649         self.port_no = port_no
2650         self.queue_id = queue_id
2651         self.tx_bytes = tx_bytes
2652         self.tx_packets = tx_packets
2653         self.tx_errors = tx_errors
2654         self.duration_sec = duration_sec
2655         self.duration_nsec = duration_nsec
2656         self.properties = properties
2657
2658     @classmethod
2659     def parser(cls, buf, offset):
2660         (length, port_no, queue_id, tx_bytes, tx_packets, tx_errors,
2661          duration_sec, duration_nsec) = struct.unpack_from(
2662             ofproto.OFP_QUEUE_STATS_PACK_STR, buf, offset)
2663         props = []
2664         rest = buf[offset + ofproto.OFP_QUEUE_STATS_SIZE:offset + length]
2665         while rest:
2666             p, rest = OFPQueueStatsProp.parse(rest)
2667             props.append(p)
2668         stats = cls(length, port_no, queue_id, tx_bytes, tx_packets, tx_errors,
2669                     duration_sec, duration_nsec, props)
2670         return stats
2671
2672
2673 @_set_stats_type(ofproto.OFPMP_QUEUE_STATS, OFPQueueStats)
2674 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
2675 class OFPQueueStatsRequest(OFPMultipartRequest):
2676     """
2677     Queue statistics request message
2678
2679     The controller uses this message to query queue statictics.
2680
2681     ================ ======================================================
2682     Attribute        Description
2683     ================ ======================================================
2684     flags            Zero or ``OFPMPF_REQ_MORE``
2685     port_no          Port number to read
2686     queue_id         ID of queue to read
2687     ================ ======================================================
2688
2689     Example::
2690
2691         def send_queue_stats_request(self, datapath):
2692             ofp = datapath.ofproto
2693             ofp_parser = datapath.ofproto_parser
2694
2695             req = ofp_parser.OFPQueueStatsRequest(datapath, 0, ofp.OFPP_ANY,
2696                                                   ofp.OFPQ_ALL)
2697             datapath.send_msg(req)
2698     """
2699
2700     def __init__(self, datapath, flags=0, port_no=ofproto.OFPP_ANY,
2701                  queue_id=ofproto.OFPQ_ALL, type_=None):
2702         super(OFPQueueStatsRequest, self).__init__(datapath, flags)
2703         self.port_no = port_no
2704         self.queue_id = queue_id
2705
2706     def _serialize_stats_body(self):
2707         msg_pack_into(ofproto.OFP_QUEUE_MULTIPART_REQUEST_PACK_STR,
2708                       self.buf,
2709                       ofproto.OFP_MULTIPART_REQUEST_SIZE,
2710                       self.port_no, self.queue_id)
2711
2712
2713 @OFPMultipartReply.register_stats_type()
2714 @_set_stats_type(ofproto.OFPMP_QUEUE_STATS, OFPQueueStats)
2715 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
2716 class OFPQueueStatsReply(OFPMultipartReply):
2717     """
2718     Queue statistics reply message
2719
2720     The switch responds with this message to an aggregate flow statistics
2721     request.
2722
2723     ================ ======================================================
2724     Attribute        Description
2725     ================ ======================================================
2726     body             List of ``OFPQueueStats`` instance
2727     ================ ======================================================
2728
2729     Example::
2730
2731         @set_ev_cls(ofp_event.EventOFPQueueStatsReply, MAIN_DISPATCHER)
2732         def queue_stats_reply_handler(self, ev):
2733             queues = []
2734             for stat in ev.msg.body:
2735                 queues.append('port_no=%d queue_id=%d '
2736                               'tx_bytes=%d tx_packets=%d tx_errors=%d '
2737                               'duration_sec=%d duration_nsec=%d'
2738                               'properties=%s' %
2739                               (stat.port_no, stat.queue_id,
2740                                stat.tx_bytes, stat.tx_packets, stat.tx_errors,
2741                                stat.duration_sec, stat.duration_nsec,
2742                                repr(stat.properties)))
2743             self.logger.debug('QueueStats: %s', queues)
2744     """
2745
2746     def __init__(self, datapath, type_=None, **kwargs):
2747         super(OFPQueueStatsReply, self).__init__(datapath, **kwargs)
2748
2749
2750 class OFPBucketCounter(StringifyMixin):
2751     def __init__(self, packet_count, byte_count):
2752         super(OFPBucketCounter, self).__init__()
2753         self.packet_count = packet_count
2754         self.byte_count = byte_count
2755
2756     @classmethod
2757     def parser(cls, buf, offset):
2758         packet_count, byte_count = struct.unpack_from(
2759             ofproto.OFP_BUCKET_COUNTER_PACK_STR, buf, offset)
2760         return cls(packet_count, byte_count)
2761
2762
2763 class OFPGroupStats(StringifyMixin):
2764     def __init__(self, length=None, group_id=None, ref_count=None,
2765                  packet_count=None, byte_count=None, duration_sec=None,
2766                  duration_nsec=None, bucket_stats=None):
2767         super(OFPGroupStats, self).__init__()
2768         self.length = length
2769         self.group_id = group_id
2770         self.ref_count = ref_count
2771         self.packet_count = packet_count
2772         self.byte_count = byte_count
2773         self.duration_sec = duration_sec
2774         self.duration_nsec = duration_nsec
2775         self.bucket_stats = bucket_stats
2776
2777     @classmethod
2778     def parser(cls, buf, offset):
2779         group = struct.unpack_from(ofproto.OFP_GROUP_STATS_PACK_STR,
2780                                    buf, offset)
2781         group_stats = cls(*group)
2782
2783         group_stats.bucket_stats = []
2784         total_len = group_stats.length + offset
2785         offset += ofproto.OFP_GROUP_STATS_SIZE
2786         while total_len > offset:
2787             b = OFPBucketCounter.parser(buf, offset)
2788             group_stats.bucket_stats.append(b)
2789             offset += ofproto.OFP_BUCKET_COUNTER_SIZE
2790
2791         return group_stats
2792
2793
2794 @_set_stats_type(ofproto.OFPMP_GROUP_STATS, OFPGroupStats)
2795 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
2796 class OFPGroupStatsRequest(OFPMultipartRequest):
2797     """
2798     Group statistics request message
2799
2800     The controller uses this message to query statistics of one or more
2801     groups.
2802
2803     ================ ======================================================
2804     Attribute        Description
2805     ================ ======================================================
2806     flags            Zero or ``OFPMPF_REQ_MORE``
2807     group_id         ID of group to read (OFPG_ALL to all groups)
2808     ================ ======================================================
2809
2810     Example::
2811
2812         def send_group_stats_request(self, datapath):
2813             ofp = datapath.ofproto
2814             ofp_parser = datapath.ofproto_parser
2815
2816             req = ofp_parser.OFPGroupStatsRequest(datapath, 0, ofp.OFPG_ALL)
2817             datapath.send_msg(req)
2818     """
2819
2820     def __init__(self, datapath, flags=0, group_id=ofproto.OFPG_ALL,
2821                  type_=None):
2822         super(OFPGroupStatsRequest, self).__init__(datapath, flags)
2823         self.group_id = group_id
2824
2825     def _serialize_stats_body(self):
2826         msg_pack_into(ofproto.OFP_GROUP_MULTIPART_REQUEST_PACK_STR,
2827                       self.buf,
2828                       ofproto.OFP_MULTIPART_REQUEST_SIZE,
2829                       self.group_id)
2830
2831
2832 @OFPMultipartReply.register_stats_type()
2833 @_set_stats_type(ofproto.OFPMP_GROUP_STATS, OFPGroupStats)
2834 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
2835 class OFPGroupStatsReply(OFPMultipartReply):
2836     """
2837     Group statistics reply message
2838
2839     The switch responds with this message to a group statistics request.
2840
2841     ================ ======================================================
2842     Attribute        Description
2843     ================ ======================================================
2844     body             List of ``OFPGroupStats`` instance
2845     ================ ======================================================
2846
2847     Example::
2848
2849         @set_ev_cls(ofp_event.EventOFPGroupStatsReply, MAIN_DISPATCHER)
2850         def group_stats_reply_handler(self, ev):
2851             groups = []
2852             for stat in ev.msg.body:
2853                 groups.append('length=%d group_id=%d '
2854                               'ref_count=%d packet_count=%d byte_count=%d '
2855                               'duration_sec=%d duration_nsec=%d' %
2856                               (stat.length, stat.group_id,
2857                                stat.ref_count, stat.packet_count,
2858                                stat.byte_count, stat.duration_sec,
2859                                stat.duration_nsec))
2860             self.logger.debug('GroupStats: %s', groups)
2861     """
2862
2863     def __init__(self, datapath, type_=None, **kwargs):
2864         super(OFPGroupStatsReply, self).__init__(datapath, **kwargs)
2865
2866
2867 class OFPGroupDescStats(StringifyMixin):
2868     def __init__(self, type_=None, group_id=None, buckets=None, properties=None,
2869                  length=None, bucket_array_len=None):
2870         buckets = buckets if buckets else []
2871         properties = properties if properties else []
2872         super(OFPGroupDescStats, self).__init__()
2873         self.length = length
2874         self.type = type_
2875         self.group_id = group_id
2876         self.buckets = buckets
2877         self.properties = properties
2878
2879     @classmethod
2880     def parser(cls, buf, offset):
2881         stats = cls()
2882
2883         (stats.length, stats.type, stats.group_id,
2884          stats.bucket_array_len) = struct.unpack_from(
2885             ofproto.OFP_GROUP_DESC_STATS_PACK_STR, buf, offset)
2886         offset += ofproto.OFP_GROUP_DESC_STATS_SIZE
2887
2888         bucket_buf = buf[offset:offset + stats.bucket_array_len]
2889         stats.buckets = []
2890         while bucket_buf:
2891             bucket = OFPBucket.parser(bucket_buf, 0)
2892             stats.buckets.append(bucket)
2893             bucket_buf = bucket_buf[bucket.len:]
2894         offset += stats.bucket_array_len
2895
2896         rest = buf[offset:offset + stats.length]
2897         while rest:
2898             p, rest = OFPGroupProp.parse(rest)
2899             stats.properties.append(p)
2900
2901         return stats
2902
2903
2904 @_set_stats_type(ofproto.OFPMP_GROUP_DESC, OFPGroupDescStats)
2905 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
2906 class OFPGroupDescStatsRequest(OFPMultipartRequest):
2907     """
2908     Group description request message
2909
2910     The controller uses this message to list the set of groups on a switch.
2911
2912     ================ ======================================================
2913     Attribute        Description
2914     ================ ======================================================
2915     flags            Zero or ``OFPMPF_REQ_MORE``
2916     group_id         ID of group to read (OFPG_ALL to all groups)
2917     ================ ======================================================
2918
2919     Example::
2920
2921         def send_group_desc_stats_request(self, datapath):
2922             ofp = datapath.ofproto
2923             ofp_parser = datapath.ofproto_parser
2924
2925             req = ofp_parser.OFPGroupDescStatsRequest(datapath, 0, ofp.OFPG_ALL)
2926             datapath.send_msg(req)
2927     """
2928
2929     def __init__(self, datapath, flags=0, group_id=ofproto.OFPG_ALL,
2930                  type_=None):
2931         super(OFPGroupDescStatsRequest, self).__init__(datapath, flags)
2932         self.group_id = group_id
2933
2934     def _serialize_stats_body(self):
2935         msg_pack_into(ofproto.OFP_GROUP_MULTIPART_REQUEST_PACK_STR,
2936                       self.buf,
2937                       ofproto.OFP_MULTIPART_REQUEST_SIZE,
2938                       self.group_id)
2939
2940
2941 @OFPMultipartReply.register_stats_type()
2942 @_set_stats_type(ofproto.OFPMP_GROUP_DESC, OFPGroupDescStats)
2943 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
2944 class OFPGroupDescStatsReply(OFPMultipartReply):
2945     """
2946     Group description reply message
2947
2948     The switch responds with this message to a group description request.
2949
2950     ================ ======================================================
2951     Attribute        Description
2952     ================ ======================================================
2953     body             List of ``OFPGroupDescStats`` instance
2954     ================ ======================================================
2955
2956     Example::
2957
2958         @set_ev_cls(ofp_event.EventOFPGroupDescStatsReply, MAIN_DISPATCHER)
2959         def group_desc_stats_reply_handler(self, ev):
2960             descs = []
2961             for stat in ev.msg.body:
2962                 descs.append('length=%d type=%d group_id=%d '
2963                              'buckets=%s properties=%s' %
2964                              (stat.length, stat.type, stat.group_id,
2965                               stat.bucket, repr(stat.properties)))
2966             self.logger.debug('GroupDescStats: %s', descs)
2967     """
2968
2969     def __init__(self, datapath, type_=None, **kwargs):
2970         super(OFPGroupDescStatsReply, self).__init__(datapath, **kwargs)
2971
2972
2973 class OFPGroupFeaturesStats(ofproto_parser.namedtuple('OFPGroupFeaturesStats',
2974                                                       ('types', 'capabilities', 'max_groups',
2975                                                        'actions'))):
2976     @classmethod
2977     def parser(cls, buf, offset):
2978         group_features = struct.unpack_from(
2979             ofproto.OFP_GROUP_FEATURES_PACK_STR, buf, offset)
2980         types = group_features[0]
2981         capabilities = group_features[1]
2982         max_groups = list(group_features[2:6])
2983         actions = list(group_features[6:10])
2984         stats = cls(types, capabilities, max_groups, actions)
2985         stats.length = ofproto.OFP_GROUP_FEATURES_SIZE
2986         return stats
2987
2988
2989 @_set_stats_type(ofproto.OFPMP_GROUP_FEATURES, OFPGroupFeaturesStats)
2990 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
2991 class OFPGroupFeaturesStatsRequest(OFPMultipartRequest):
2992     """
2993     Group features request message
2994
2995     The controller uses this message to list the capabilities of groups on
2996     a switch.
2997
2998     ================ ======================================================
2999     Attribute        Description
3000     ================ ======================================================
3001     flags            Zero or ``OFPMPF_REQ_MORE``
3002     ================ ======================================================
3003
3004     Example::
3005
3006         def send_group_features_stats_request(self, datapath):
3007             ofp_parser = datapath.ofproto_parser
3008
3009             req = ofp_parser.OFPGroupFeaturesStatsRequest(datapath, 0)
3010             datapath.send_msg(req)
3011     """
3012
3013     def __init__(self, datapath, flags=0, type_=None):
3014         super(OFPGroupFeaturesStatsRequest, self).__init__(datapath, flags)
3015
3016
3017 @OFPMultipartReply.register_stats_type(body_single_struct=True)
3018 @_set_stats_type(ofproto.OFPMP_GROUP_FEATURES, OFPGroupFeaturesStats)
3019 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
3020 class OFPGroupFeaturesStatsReply(OFPMultipartReply):
3021     """
3022     Group features reply message
3023
3024     The switch responds with this message to a group features request.
3025
3026     ================ ======================================================
3027     Attribute        Description
3028     ================ ======================================================
3029     body             Instance of ``OFPGroupFeaturesStats``
3030     ================ ======================================================
3031
3032     Example::
3033
3034         @set_ev_cls(ofp_event.EventOFPGroupFeaturesStatsReply, MAIN_DISPATCHER)
3035         def group_features_stats_reply_handler(self, ev):
3036             body = ev.msg.body
3037
3038             self.logger.debug('GroupFeaturesStats: types=%d '
3039                               'capabilities=0x%08x max_groups=%s '
3040                               'actions=%s',
3041                               body.types, body.capabilities,
3042                               body.max_groups, body.actions)
3043     """
3044
3045     def __init__(self, datapath, type_=None, **kwargs):
3046         super(OFPGroupFeaturesStatsReply, self).__init__(datapath, **kwargs)
3047
3048
3049 class OFPMeterBandStats(StringifyMixin):
3050     def __init__(self, packet_band_count, byte_band_count):
3051         super(OFPMeterBandStats, self).__init__()
3052         self.packet_band_count = packet_band_count
3053         self.byte_band_count = byte_band_count
3054
3055     @classmethod
3056     def parser(cls, buf, offset):
3057         band_stats = struct.unpack_from(
3058             ofproto.OFP_METER_BAND_STATS_PACK_STR, buf, offset)
3059         return cls(*band_stats)
3060
3061
3062 class OFPMeterStats(StringifyMixin):
3063     def __init__(self, meter_id=None, ref_count=None, packet_in_count=None,
3064                  byte_in_count=None, duration_sec=None, duration_nsec=None,
3065                  band_stats=None, len_=None):
3066         super(OFPMeterStats, self).__init__()
3067         self.meter_id = meter_id
3068         self.len = 0
3069         self.ref_count = ref_count
3070         self.packet_in_count = packet_in_count
3071         self.byte_in_count = byte_in_count
3072         self.duration_sec = duration_sec
3073         self.duration_nsec = duration_nsec
3074         self.band_stats = band_stats
3075
3076     @classmethod
3077     def parser(cls, buf, offset):
3078         meter_stats = cls()
3079
3080         (meter_stats.meter_id, meter_stats.len,
3081          meter_stats.ref_count, meter_stats.packet_in_count,
3082          meter_stats.byte_in_count, meter_stats.duration_sec,
3083          meter_stats.duration_nsec) = struct.unpack_from(
3084             ofproto.OFP_METER_STATS_PACK_STR, buf, offset)
3085         offset += ofproto.OFP_METER_STATS_SIZE
3086
3087         meter_stats.band_stats = []
3088         length = ofproto.OFP_METER_STATS_SIZE
3089         while length < meter_stats.len:
3090             band_stats = OFPMeterBandStats.parser(buf, offset)
3091             meter_stats.band_stats.append(band_stats)
3092             offset += ofproto.OFP_METER_BAND_STATS_SIZE
3093             length += ofproto.OFP_METER_BAND_STATS_SIZE
3094
3095         return meter_stats
3096
3097
3098 @_set_stats_type(ofproto.OFPMP_METER_STATS, OFPMeterStats)
3099 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
3100 class OFPMeterStatsRequest(OFPMultipartRequest):
3101     """
3102     Meter statistics request message
3103
3104     The controller uses this message to query statistics for one or more
3105     meters.
3106
3107     ================ ======================================================
3108     Attribute        Description
3109     ================ ======================================================
3110     flags            Zero or ``OFPMPF_REQ_MORE``
3111     meter_id         ID of meter to read (OFPM_ALL to all meters)
3112     ================ ======================================================
3113
3114     Example::
3115
3116         def send_meter_stats_request(self, datapath):
3117             ofp = datapath.ofproto
3118             ofp_parser = datapath.ofproto_parser
3119
3120             req = ofp_parser.OFPMeterStatsRequest(datapath, 0, ofp.OFPM_ALL)
3121             datapath.send_msg(req)
3122     """
3123
3124     def __init__(self, datapath, flags=0, meter_id=ofproto.OFPM_ALL,
3125                  type_=None):
3126         super(OFPMeterStatsRequest, self).__init__(datapath, flags)
3127         self.meter_id = meter_id
3128
3129     def _serialize_stats_body(self):
3130         msg_pack_into(ofproto.OFP_METER_MULTIPART_REQUEST_PACK_STR,
3131                       self.buf,
3132                       ofproto.OFP_MULTIPART_REQUEST_SIZE,
3133                       self.meter_id)
3134
3135
3136 @OFPMultipartReply.register_stats_type()
3137 @_set_stats_type(ofproto.OFPMP_METER_STATS, OFPMeterStats)
3138 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
3139 class OFPMeterStatsReply(OFPMultipartReply):
3140     """
3141     Meter statistics reply message
3142
3143     The switch responds with this message to a meter statistics request.
3144
3145     ================ ======================================================
3146     Attribute        Description
3147     ================ ======================================================
3148     body             List of ``OFPMeterStats`` instance
3149     ================ ======================================================
3150
3151     Example::
3152
3153         @set_ev_cls(ofp_event.EventOFPMeterStatsReply, MAIN_DISPATCHER)
3154         def meter_stats_reply_handler(self, ev):
3155             meters = []
3156             for stat in ev.msg.body:
3157                 meters.append('meter_id=0x%08x len=%d ref_count=%d '
3158                               'packet_in_count=%d byte_in_count=%d '
3159                               'duration_sec=%d duration_nsec=%d '
3160                               'band_stats=%s' %
3161                               (stat.meter_id, stat.len, stat.ref_count,
3162                                stat.packet_in_count, stat.byte_in_count,
3163                                stat.duration_sec, stat.duration_nsec,
3164                                stat.band_stats))
3165             self.logger.debug('MeterStats: %s', meters)
3166     """
3167
3168     def __init__(self, datapath, type_=None, **kwargs):
3169         super(OFPMeterStatsReply, self).__init__(datapath, **kwargs)
3170
3171
3172 class OFPMeterBand(StringifyMixin):
3173     def __init__(self, type_, len_):
3174         super(OFPMeterBand, self).__init__()
3175         self.type = type_
3176         self.len = len_
3177
3178
3179 class OFPMeterBandHeader(OFPMeterBand):
3180     _METER_BAND = {}
3181
3182     @staticmethod
3183     def register_meter_band_type(type_, len_):
3184         def _register_meter_band_type(cls):
3185             OFPMeterBandHeader._METER_BAND[type_] = cls
3186             cls.cls_meter_band_type = type_
3187             cls.cls_meter_band_len = len_
3188             return cls
3189         return _register_meter_band_type
3190
3191     def __init__(self):
3192         cls = self.__class__
3193         super(OFPMeterBandHeader, self).__init__(cls.cls_meter_band_type,
3194                                                  cls.cls_meter_band_len)
3195
3196     @classmethod
3197     def parser(cls, buf, offset):
3198         type_, len_, _rate, _burst_size = struct.unpack_from(
3199             ofproto.OFP_METER_BAND_HEADER_PACK_STR, buf, offset)
3200         cls_ = cls._METER_BAND[type_]
3201         assert cls_.cls_meter_band_len == len_
3202         return cls_.parser(buf, offset)
3203
3204
3205 @OFPMeterBandHeader.register_meter_band_type(
3206     ofproto.OFPMBT_DROP, ofproto.OFP_METER_BAND_DROP_SIZE)
3207 class OFPMeterBandDrop(OFPMeterBandHeader):
3208     def __init__(self, rate=0, burst_size=0, type_=None, len_=None):
3209         super(OFPMeterBandDrop, self).__init__()
3210         self.rate = rate
3211         self.burst_size = burst_size
3212
3213     def serialize(self, buf, offset):
3214         msg_pack_into(ofproto.OFP_METER_BAND_DROP_PACK_STR, buf, offset,
3215                       self.type, self.len, self.rate, self.burst_size)
3216
3217     @classmethod
3218     def parser(cls, buf, offset):
3219         type_, len_, rate, burst_size = struct.unpack_from(
3220             ofproto.OFP_METER_BAND_DROP_PACK_STR, buf, offset)
3221         assert cls.cls_meter_band_type == type_
3222         assert cls.cls_meter_band_len == len_
3223         return cls(rate, burst_size)
3224
3225
3226 @OFPMeterBandHeader.register_meter_band_type(
3227     ofproto.OFPMBT_DSCP_REMARK,
3228     ofproto.OFP_METER_BAND_DSCP_REMARK_SIZE)
3229 class OFPMeterBandDscpRemark(OFPMeterBandHeader):
3230     def __init__(self, rate=0, burst_size=0, prec_level=0,
3231                  type_=None, len_=None):
3232         super(OFPMeterBandDscpRemark, self).__init__()
3233         self.rate = rate
3234         self.burst_size = burst_size
3235         self.prec_level = prec_level
3236
3237     def serialize(self, buf, offset):
3238         msg_pack_into(ofproto.OFP_METER_BAND_DSCP_REMARK_PACK_STR, buf,
3239                       offset, self.type, self.len, self.rate,
3240                       self.burst_size, self.prec_level)
3241
3242     @classmethod
3243     def parser(cls, buf, offset):
3244         type_, len_, rate, burst_size, prec_level = struct.unpack_from(
3245             ofproto.OFP_METER_BAND_DSCP_REMARK_PACK_STR, buf, offset)
3246         assert cls.cls_meter_band_type == type_
3247         assert cls.cls_meter_band_len == len_
3248         return cls(rate, burst_size, prec_level)
3249
3250
3251 @OFPMeterBandHeader.register_meter_band_type(
3252     ofproto.OFPMBT_EXPERIMENTER,
3253     ofproto.OFP_METER_BAND_EXPERIMENTER_SIZE)
3254 class OFPMeterBandExperimenter(OFPMeterBandHeader):
3255     def __init__(self, rate=0, burst_size=0, experimenter=None,
3256                  type_=None, len_=None):
3257         super(OFPMeterBandExperimenter, self).__init__()
3258         self.rate = rate
3259         self.burst_size = burst_size
3260         self.experimenter = experimenter
3261
3262     def serialize(self, buf, offset):
3263         msg_pack_into(ofproto.OFP_METER_BAND_EXPERIMENTER_PACK_STR, buf,
3264                       offset, self.type, self.len, self.rate,
3265                       self.burst_size, self.experimenter)
3266
3267     @classmethod
3268     def parser(cls, buf, offset):
3269         type_, len_, rate, burst_size, experimenter = struct.unpack_from(
3270             ofproto.OFP_METER_BAND_EXPERIMENTER_PACK_STR, buf, offset)
3271         assert cls.cls_meter_band_type == type_
3272         assert cls.cls_meter_band_len == len_
3273         return cls(rate, burst_size, experimenter)
3274
3275
3276 class OFPMeterDescStats(StringifyMixin):
3277     def __init__(self, flags=None, meter_id=None, bands=None, length=None):
3278         super(OFPMeterDescStats, self).__init__()
3279         self.length = None
3280         self.flags = flags
3281         self.meter_id = meter_id
3282         self.bands = bands
3283
3284     @classmethod
3285     def parser(cls, buf, offset):
3286         meter_config = cls()
3287
3288         (meter_config.length, meter_config.flags,
3289          meter_config.meter_id) = struct.unpack_from(
3290             ofproto.OFP_METER_DESC_PACK_STR, buf, offset)
3291         offset += ofproto.OFP_METER_DESC_SIZE
3292
3293         meter_config.bands = []
3294         length = ofproto.OFP_METER_DESC_SIZE
3295         while length < meter_config.length:
3296             band = OFPMeterBandHeader.parser(buf, offset)
3297             meter_config.bands.append(band)
3298             offset += band.len
3299             length += band.len
3300
3301         return meter_config
3302
3303
3304 @_set_stats_type(ofproto.OFPMP_METER_DESC, OFPMeterDescStats)
3305 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
3306 class OFPMeterDescStatsRequest(OFPMultipartRequest):
3307     """
3308     Meter description statistics request message
3309
3310     The controller uses this message to query configuration for one or more
3311     meters.
3312
3313     ================ ======================================================
3314     Attribute        Description
3315     ================ ======================================================
3316     flags            Zero or ``OFPMPF_REQ_MORE``
3317     meter_id         ID of meter to read (OFPM_ALL to all meters)
3318     ================ ======================================================
3319
3320     Example::
3321
3322         def send_meter_desc_stats_request(self, datapath):
3323             ofp = datapath.ofproto
3324             ofp_parser = datapath.ofproto_parser
3325
3326             req = ofp_parser.OFPMeterDescStatsRequest(datapath, 0,
3327                                                         ofp.OFPM_ALL)
3328             datapath.send_msg(req)
3329     """
3330
3331     def __init__(self, datapath, flags=0, meter_id=ofproto.OFPM_ALL,
3332                  type_=None):
3333         super(OFPMeterDescStatsRequest, self).__init__(datapath, flags)
3334         self.meter_id = meter_id
3335
3336     def _serialize_stats_body(self):
3337         msg_pack_into(ofproto.OFP_METER_MULTIPART_REQUEST_PACK_STR,
3338                       self.buf,
3339                       ofproto.OFP_MULTIPART_REQUEST_SIZE,
3340                       self.meter_id)
3341
3342
3343 @OFPMultipartReply.register_stats_type()
3344 @_set_stats_type(ofproto.OFPMP_METER_DESC, OFPMeterDescStats)
3345 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
3346 class OFPMeterDescStatsReply(OFPMultipartReply):
3347     """
3348     Meter description statistics reply message
3349
3350     The switch responds with this message to a meter description
3351     statistics request.
3352
3353     ================ ======================================================
3354     Attribute        Description
3355     ================ ======================================================
3356     body             List of ``OFPMeterDescStats`` instance
3357     ================ ======================================================
3358
3359     Example::
3360
3361         @set_ev_cls(ofp_event.EventOFPMeterDescStatsReply, MAIN_DISPATCHER)
3362         def meter_desc_stats_reply_handler(self, ev):
3363             configs = []
3364             for stat in ev.msg.body:
3365                 configs.append('length=%d flags=0x%04x meter_id=0x%08x '
3366                                'bands=%s' %
3367                                (stat.length, stat.flags, stat.meter_id,
3368                                 stat.bands))
3369             self.logger.debug('MeterDescStats: %s', configs)
3370     """
3371
3372     def __init__(self, datapath, type_=None, **kwargs):
3373         super(OFPMeterDescStatsReply, self).__init__(datapath, **kwargs)
3374
3375
3376 class OFPMeterFeaturesStats(ofproto_parser.namedtuple('OFPMeterFeaturesStats',
3377                                                       ('max_meter', 'band_types', 'capabilities',
3378                                                        'max_bands', 'max_color', 'features'))):
3379     @classmethod
3380     def parser(cls, buf, offset):
3381         meter_features = struct.unpack_from(
3382             ofproto.OFP_METER_FEATURES_PACK_STR, buf, offset)
3383         stats = cls(*meter_features)
3384         stats.length = ofproto.OFP_METER_FEATURES_SIZE
3385         return stats
3386
3387
3388 @_set_stats_type(ofproto.OFPMP_METER_FEATURES, OFPMeterFeaturesStats)
3389 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
3390 class OFPMeterFeaturesStatsRequest(OFPMultipartRequest):
3391     """
3392     Meter features statistics request message
3393
3394     The controller uses this message to query the set of features of the
3395     metering subsystem.
3396
3397     ================ ======================================================
3398     Attribute        Description
3399     ================ ======================================================
3400     flags            Zero or ``OFPMPF_REQ_MORE``
3401     ================ ======================================================
3402
3403     Example::
3404
3405         def send_meter_features_stats_request(self, datapath):
3406             ofp_parser = datapath.ofproto_parser
3407
3408             req = ofp_parser.OFPMeterFeaturesStatsRequest(datapath, 0)
3409             datapath.send_msg(req)
3410     """
3411
3412     def __init__(self, datapath, flags=0, type_=None):
3413         super(OFPMeterFeaturesStatsRequest, self).__init__(datapath, flags)
3414
3415
3416 @OFPMultipartReply.register_stats_type()
3417 @_set_stats_type(ofproto.OFPMP_METER_FEATURES, OFPMeterFeaturesStats)
3418 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
3419 class OFPMeterFeaturesStatsReply(OFPMultipartReply):
3420     """
3421     Meter features statistics reply message
3422
3423     The switch responds with this message to a meter features statistics
3424     request.
3425
3426     ================ ======================================================
3427     Attribute        Description
3428     ================ ======================================================
3429     body             List of ``OFPMeterFeaturesStats`` instance
3430     ================ ======================================================
3431
3432     Example::
3433
3434         @set_ev_cls(ofp_event.EventOFPMeterFeaturesStatsReply, MAIN_DISPATCHER)
3435         def meter_features_stats_reply_handler(self, ev):
3436             features = []
3437             for stat in ev.msg.body:
3438                 features.append('max_meter=%d band_types=0x%08x '
3439                                 'capabilities=0x%08x max_bands=%d '
3440                                 'max_color=%d' %
3441                                 (stat.max_meter, stat.band_types,
3442                                  stat.capabilities, stat.max_bands,
3443                                  stat.max_color))
3444             self.logger.debug('MeterFeaturesStats: %s', features)
3445     """
3446
3447     def __init__(self, datapath, type_=None, **kwargs):
3448         super(OFPMeterFeaturesStatsReply, self).__init__(datapath, **kwargs)
3449
3450
3451 class OFPFlowUpdate(StringifyMixin):
3452     def __init__(self, length, event):
3453         super(OFPFlowUpdate, self).__init__()
3454         self.length = length
3455         self.event = event
3456
3457
3458 class OFPFlowUpdateHeader(OFPFlowUpdate):
3459     _EVENT = {}
3460
3461     @staticmethod
3462     def register_flow_update_event(event, length):
3463         def _register_flow_update_event(cls):
3464             OFPFlowUpdateHeader._EVENT[event] = cls
3465             cls.cls_flow_update_event = event
3466             cls.cls_flow_update_length = length
3467             return cls
3468         return _register_flow_update_event
3469
3470     def __init__(self, length=None, event=None):
3471         cls = self.__class__
3472         super(OFPFlowUpdateHeader, self).__init__(length,
3473                                                   cls.cls_flow_update_event)
3474         self.length = length
3475
3476     @classmethod
3477     def parser(cls, buf, offset):
3478         length, event = struct.unpack_from(
3479             ofproto.OFP_FLOW_UPDATE_HEADER_PACK_STR, buf, offset)
3480         cls_ = cls._EVENT[event]
3481         return cls_.parser(buf, offset)
3482
3483
3484 @OFPFlowUpdateHeader.register_flow_update_event(
3485     ofproto.OFPFME_INITIAL, ofproto.OFP_FLOW_UPDATE_FULL_SIZE)
3486 @OFPFlowUpdateHeader.register_flow_update_event(
3487     ofproto.OFPFME_ADDED, ofproto.OFP_FLOW_UPDATE_FULL_SIZE)
3488 @OFPFlowUpdateHeader.register_flow_update_event(
3489     ofproto.OFPFME_REMOVED, ofproto.OFP_FLOW_UPDATE_FULL_SIZE)
3490 @OFPFlowUpdateHeader.register_flow_update_event(
3491     ofproto.OFPFME_MODIFIED, ofproto.OFP_FLOW_UPDATE_FULL_SIZE)
3492 class OFPFlowUpdateFull(OFPFlowUpdateHeader):
3493     def __init__(self, length=None, event=None, table_id=None, reason=None,
3494                  idle_timeout=None, hard_timeout=None, priority=None,
3495                  cookie=None, match=None, instructions=None):
3496         instructions = instructions if instructions else []
3497         super(OFPFlowUpdateFull, self).__init__(length, event)
3498         self.table_id = table_id
3499         self.reason = reason
3500         self.idle_timeout = idle_timeout
3501         self.hard_timeout = hard_timeout
3502         self.priority = priority
3503         self.cookie = cookie
3504         self.match = match
3505         assert (event != ofproto.OFPFME_REMOVED or len(instructions) == 0)
3506         for i in instructions:
3507             assert isinstance(i, OFPInstruction)
3508         self.instructions = instructions
3509
3510     @classmethod
3511     def parser(cls, buf, offset):
3512         (length, event, table_id, reason, idle_timeout, hard_timeout, priority,
3513          cookie) = struct.unpack_from(ofproto.OFP_FLOW_UPDATE_FULL_0_PACK_STR,
3514                                       buf, offset)
3515         offset += ofproto.OFP_FLOW_UPDATE_FULL_0_SIZE
3516         assert cls.cls_flow_update_length <= length
3517         assert cls.cls_flow_update_event == event
3518
3519         match = OFPMatch.parser(buf, offset)
3520         match_length = utils.round_up(match.length, 8)
3521         offset += match_length
3522
3523         inst_length = (length - ofproto.OFP_FLOW_UPDATE_FULL_0_SIZE -
3524                        match_length)
3525         instructions = []
3526         while inst_length > 0:
3527             inst = OFPInstruction.parser(buf, offset)
3528             instructions.append(inst)
3529             offset += inst.len
3530             inst_length -= inst.len
3531
3532         return cls(length, event, table_id, reason, idle_timeout,
3533                    hard_timeout, priority, cookie, match, instructions)
3534
3535
3536 @OFPFlowUpdateHeader.register_flow_update_event(
3537     ofproto.OFPFME_ABBREV, ofproto.OFP_FLOW_UPDATE_ABBREV_SIZE)
3538 class OFPFlowUpdateAbbrev(OFPFlowUpdateHeader):
3539     def __init__(self, length=None, event=None, xid=None):
3540         super(OFPFlowUpdateAbbrev, self).__init__(length, event)
3541         self.xid = xid
3542
3543     @classmethod
3544     def parser(cls, buf, offset):
3545         length, event, xid = struct.unpack_from(
3546             ofproto.OFP_FLOW_UPDATE_ABBREV_PACK_STR, buf, offset)
3547         assert cls.cls_flow_update_length == length
3548         assert cls.cls_flow_update_event == event
3549
3550         return cls(length, event, xid)
3551
3552
3553 @OFPFlowUpdateHeader.register_flow_update_event(
3554     ofproto.OFPFME_PAUSED, ofproto.OFP_FLOW_UPDATE_PAUSED_SIZE)
3555 @OFPFlowUpdateHeader.register_flow_update_event(
3556     ofproto.OFPFME_RESUMED, ofproto.OFP_FLOW_UPDATE_PAUSED_SIZE)
3557 class OFPFlowUpdatePaused(OFPFlowUpdateHeader):
3558     @classmethod
3559     def parser(cls, buf, offset):
3560         length, event = struct.unpack_from(
3561             ofproto.OFP_FLOW_UPDATE_PAUSED_PACK_STR, buf, offset)
3562         assert cls.cls_flow_update_length == length
3563         assert cls.cls_flow_update_event == event
3564
3565         return cls(length, event)
3566
3567
3568 class OFPFlowMonitorRequestBase(OFPMultipartRequest):
3569     def __init__(self, datapath, flags, monitor_id, out_port, out_group,
3570                  monitor_flags, table_id, command, match):
3571         super(OFPFlowMonitorRequestBase, self).__init__(datapath, flags)
3572         self.monitor_id = monitor_id
3573         self.out_port = out_port
3574         self.out_group = out_group
3575         self.monitor_flags = monitor_flags
3576         self.table_id = table_id
3577         self.command = command
3578         self.match = match
3579
3580     def _serialize_stats_body(self):
3581         offset = ofproto.OFP_MULTIPART_REQUEST_SIZE
3582         msg_pack_into(ofproto.OFP_FLOW_MONITOR_REQUEST_0_PACK_STR, self.buf,
3583                       offset, self.monitor_id, self.out_port, self.out_group,
3584                       self.monitor_flags, self.table_id, self.command)
3585
3586         offset += ofproto.OFP_FLOW_MONITOR_REQUEST_0_SIZE
3587         self.match.serialize(self.buf, offset)
3588
3589
3590 @_set_stats_type(ofproto.OFPMP_FLOW_MONITOR, OFPFlowUpdateHeader)
3591 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
3592 class OFPFlowMonitorRequest(OFPFlowMonitorRequestBase):
3593     """
3594     Flow monitor request message
3595
3596     The controller uses this message to query flow monitors.
3597
3598     ================ ======================================================
3599     Attribute        Description
3600     ================ ======================================================
3601     flags            Zero or ``OFPMPF_REQ_MORE``
3602     monitor_id       Controller-assigned ID for this monitor
3603     out_port         Require matching entries to include this as an output
3604                      port
3605     out_group        Require matching entries to include this as an output
3606                      group
3607     monitor_flags    Bitmap of the following flags.
3608
3609                      | OFPFMF_INITIAL
3610                      | OFPFMF_ADD
3611                      | OFPFMF_REMOVED
3612                      | OFPFMF_MODIFY
3613                      | OFPFMF_INSTRUCTIONS
3614                      | OFPFMF_NO_ABBREV
3615                      | OFPFMF_ONLY_OWN
3616     table_id         ID of table to monitor
3617     command          One of the following values.
3618
3619                      | OFPFMC_ADD
3620                      | OFPFMC_MODIFY
3621                      | OFPFMC_DELETE
3622     match            Instance of ``OFPMatch``
3623     ================ ======================================================
3624
3625     Example::
3626
3627         def send_flow_monitor_request(self, datapath):
3628             ofp = datapath.ofproto
3629             ofp_parser = datapath.ofproto_parser
3630
3631             monitor_flags = [ofp.OFPFMF_INITIAL, ofp.OFPFMF_ONLY_OWN]
3632             match = ofp_parser.OFPMatch(in_port=1)
3633             req = ofp_parser.OFPFlowMonitorRequest(datapath, 0, 10000,
3634                                                    ofp.OFPP_ANY, ofp.OFPG_ANY,
3635                                                    monitor_flags,
3636                                                    ofp.OFPTT_ALL,
3637                                                    ofp.OFPFMC_ADD, match)
3638             datapath.send_msg(req)
3639     """
3640
3641     def __init__(self, datapath, flags=0, monitor_id=0,
3642                  out_port=ofproto.OFPP_ANY, out_group=ofproto.OFPG_ANY,
3643                  monitor_flags=0, table_id=ofproto.OFPTT_ALL,
3644                  command=ofproto.OFPFMC_ADD, match=None, type_=None):
3645         if match is None:
3646             match = OFPMatch()
3647         super(OFPFlowMonitorRequest, self).__init__(datapath, flags,
3648                                                     monitor_id, out_port,
3649                                                     out_group, monitor_flags,
3650                                                     table_id, command, match)
3651
3652
3653 @OFPMultipartReply.register_stats_type()
3654 @_set_stats_type(ofproto.OFPMP_FLOW_MONITOR, OFPFlowUpdateHeader)
3655 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
3656 class OFPFlowMonitorReply(OFPMultipartReply):
3657     """
3658     Flow monitor reply message
3659
3660     The switch responds with this message to a flow monitor request.
3661
3662     ================ ======================================================
3663     Attribute        Description
3664     ================ ======================================================
3665     body             List of list of the following class instance.
3666
3667                      | OFPFlowMonitorFull
3668                      | OFPFlowMonitorAbbrev
3669                      | OFPFlowMonitorPaused
3670     ================ ======================================================
3671
3672     Example::
3673
3674         @set_ev_cls(ofp_event.EventOFPFlowMonitorReply, MAIN_DISPATCHER)
3675         def flow_monitor_reply_handler(self, ev):
3676             msg = ev.msg
3677             dp = msg.datapath
3678             ofp = dp.ofproto
3679             flow_updates = []
3680
3681             for update in msg.body:
3682                 update_str = 'length=%d event=%d' %
3683                              (update.length, update.event)
3684                 if (update.event == ofp.OFPFME_INITIAL or
3685                     update.event == ofp.OFPFME_ADDED or
3686                     update.event == ofp.OFPFME_REMOVED or
3687                     update.event == ofp.OFPFME_MODIFIED):
3688                     update_str += 'table_id=%d reason=%d idle_timeout=%d '
3689                                   'hard_timeout=%d priority=%d cookie=%d '
3690                                   'match=%d instructions=%s' %
3691                                   (update.table_id, update.reason,
3692                                    update.idle_timeout, update.hard_timeout,
3693                                    update.priority, update.cookie,
3694                                    update.match, update.instructions)
3695                 elif update.event == ofp.OFPFME_ABBREV:
3696                     update_str += 'xid=%d' % (update.xid)
3697                 flow_updates.append(update_str)
3698             self.logger.debug('FlowUpdates: %s', flow_updates)
3699     """
3700
3701     def __init__(self, datapath, type_=None, **kwargs):
3702         super(OFPFlowMonitorReply, self).__init__(datapath, **kwargs)
3703
3704
3705 class OFPBundleFeaturesProp(OFPPropBase):
3706     _TYPES = {}
3707
3708
3709 @OFPBundleFeaturesProp.register_type(ofproto.OFPTMPBF_TIME_CAPABILITY)
3710 class OFPBundleFeaturesPropTime(OFPBundleFeaturesProp):
3711     def __init__(self, type_=None, length=None, sched_accuracy=None,
3712                  sched_max_future=None, sched_max_past=None, timestamp=None):
3713         super(OFPBundleFeaturesPropTime, self).__init__(type_, length)
3714         self.sched_accuracy = sched_accuracy
3715         self.sched_max_future = sched_max_future
3716         self.sched_max_past = sched_max_past
3717         self.timestamp = timestamp
3718
3719     @classmethod
3720     def parser(cls, buf):
3721         prop = cls()
3722         (prop.type, prop.length) = struct.unpack_from(
3723             ofproto.OFP_BUNDLE_FEATURES_PROP_TIME_0_PACK_STR, buf)
3724         offset = ofproto.OFP_BUNDLE_FEATURES_PROP_TIME_0_SIZE
3725
3726         for f in ['sched_accuracy', 'sched_max_future', 'sched_max_past',
3727                   'timestamp']:
3728             t = OFPTime.parser(buf, offset)
3729             setattr(prop, f, t)
3730             offset += ofproto.OFP_TIME_SIZE
3731
3732         return prop
3733
3734     def serialize(self):
3735         # fixup
3736         self.length = ofproto.OFP_BUNDLE_FEATURES_PROP_TIME_SIZE
3737
3738         buf = bytearray()
3739         msg_pack_into(ofproto.OFP_BUNDLE_FEATURES_PROP_TIME_0_PACK_STR, buf, 0,
3740                       self.type, self.length)
3741         offset = ofproto.OFP_BUNDLE_FEATURES_PROP_TIME_0_SIZE
3742
3743         for f in [self.sched_accuracy, self.sched_max_future,
3744                   self.sched_max_past, self.timestamp]:
3745             f.serialize(buf, offset)
3746             offset += ofproto.OFP_TIME_SIZE
3747
3748         return buf
3749
3750
3751 @OFPBundleFeaturesProp.register_type(ofproto.OFPTMPBF_EXPERIMENTER)
3752 class OFPBundleFeaturesPropExperimenter(OFPPropCommonExperimenter4ByteData):
3753     pass
3754
3755
3756 class OFPBundleFeaturesStats(ofproto_parser.namedtuple(
3757         'OFPBundleFeaturesStats', ('capabilities', 'properties'))):
3758     @classmethod
3759     def parser(cls, buf, offset):
3760         (capabilities, ) = struct.unpack_from(
3761             ofproto.OFP_BUNDLE_FEATURES_PACK_STR, buf, offset)
3762
3763         properties = []
3764         length = ofproto.OFP_BUNDLE_FEATURES_SIZE
3765         rest = buf[offset + length:]
3766         while rest:
3767             p, rest = OFPBundleFeaturesProp.parse(rest)
3768             properties.append(p)
3769             length += p.length
3770
3771         bndl = cls(capabilities, properties)
3772         # Note: length field is not defined in the specification and
3773         # is specific to this implementation.
3774         bndl.length = length
3775         return bndl
3776
3777
3778 @_set_stats_type(ofproto.OFPMP_BUNDLE_FEATURES, OFPBundleFeaturesStats)
3779 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
3780 class OFPBundleFeaturesStatsRequest(OFPMultipartRequest):
3781     """
3782     Bundle features request message
3783
3784     The controller uses this message to query a switch about its bundle
3785     capabilities, including whether it supports atomic bundles, ordered
3786     bundles, and scheduled bundles.
3787
3788     ====================== ====================================================
3789     Attribute              Description
3790     ====================== ====================================================
3791     flags                  Zero or ``OFPMPF_REQ_MORE``
3792     feature_request_flags  Bitmap of the following flags.
3793
3794                            | OFPBF_TIMESTAMP
3795                            | OFPBF_TIME_SET_SCHED
3796     properties             List of ``OFPBundleFeaturesProp`` subclass instance
3797     ====================== ====================================================
3798
3799     Example::
3800
3801         def send_bundle_features_stats_request(self, datapath):
3802             ofp = datapath.ofproto
3803             ofp_parser = datapath.ofproto_parser
3804
3805             req = ofp_parser.OFPBundleFeaturesStatsRequest(datapath, 0)
3806             datapath.send_msg(req)
3807     """
3808
3809     def __init__(self, datapath, flags=0, feature_request_flags=0,
3810                  properties=None, type_=None):
3811         properties = properties if properties else []
3812         super(OFPBundleFeaturesStatsRequest, self).__init__(datapath, flags)
3813         self.feature_request_flags = feature_request_flags
3814         self.properties = properties
3815
3816     def _serialize_stats_body(self):
3817         bin_props = bytearray()
3818         for p in self.properties:
3819             bin_props += p.serialize()
3820
3821         msg_pack_into(ofproto.OFP_BUNDLE_FEATURES_REQUEST_PACK_STR,
3822                       self.buf, ofproto.OFP_MULTIPART_REQUEST_SIZE,
3823                       self.feature_request_flags)
3824         self.buf += bin_props
3825
3826
3827 @OFPMultipartReply.register_stats_type(body_single_struct=True)
3828 @_set_stats_type(ofproto.OFPMP_BUNDLE_FEATURES, OFPBundleFeaturesStats)
3829 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
3830 class OFPBundleFeaturesStatsReply(OFPMultipartReply):
3831     """
3832     Bundle features reply message
3833
3834     The switch responds with this message to a bundle features request.
3835
3836     ================ ======================================================
3837     Attribute        Description
3838     ================ ======================================================
3839     body             Instance of ``OFPBundleFeaturesStats``
3840     ================ ======================================================
3841
3842     Example::
3843
3844         @set_ev_cls(ofp_event.EventOFPBundleFeaturesStatsReply, MAIN_DISPATCHER)
3845         def bundle_features_stats_reply_handler(self, ev):
3846             body = ev.msg.body
3847
3848             self.logger.debug('OFPBundleFeaturesStats: capabilities=%0x%08x '
3849                               'properties=%s',
3850                               body.capabilities, repr(body.properties))
3851     """
3852
3853     def __init__(self, datapath, type_=None, **kwargs):
3854         super(OFPBundleFeaturesStatsReply, self).__init__(datapath, **kwargs)
3855
3856
3857 class OFPExperimenterMultipart(ofproto_parser.namedtuple(
3858                                'OFPExperimenterMultipart',
3859                                ('experimenter', 'exp_type', 'data'))):
3860     """
3861     The body of OFPExperimenterStatsReply multipart messages.
3862
3863     ================ ======================================================
3864     Attribute        Description
3865     ================ ======================================================
3866     experimenter     Experimenter ID
3867     exp_type         Experimenter defined
3868     data             Experimenter defined additional data
3869     ================ ======================================================
3870     """
3871
3872     @classmethod
3873     def parser(cls, buf, offset):
3874         args = struct.unpack_from(
3875             ofproto.OFP_EXPERIMENTER_MULTIPART_HEADER_PACK_STR, buf,
3876             offset)
3877         args = list(args)
3878         args.append(buf[offset +
3879                         ofproto.OFP_EXPERIMENTER_MULTIPART_HEADER_SIZE:])
3880         stats = cls(*args)
3881         stats.length = ofproto.OFP_METER_FEATURES_SIZE
3882         return stats
3883
3884     def serialize(self):
3885         buf = bytearray()
3886         msg_pack_into(ofproto.OFP_EXPERIMENTER_MULTIPART_HEADER_PACK_STR,
3887                       buf, 0,
3888                       self.experimenter, self.exp_type)
3889         return buf + self.data
3890
3891
3892 class OFPExperimenterStatsRequestBase(OFPMultipartRequest):
3893     def __init__(self, datapath, flags,
3894                  experimenter, exp_type,
3895                  type_=None):
3896         super(OFPExperimenterStatsRequestBase, self).__init__(datapath, flags)
3897         self.experimenter = experimenter
3898         self.exp_type = exp_type
3899
3900
3901 @_set_stats_type(ofproto.OFPMP_EXPERIMENTER, OFPExperimenterMultipart)
3902 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
3903 class OFPExperimenterStatsRequest(OFPExperimenterStatsRequestBase):
3904     """
3905     Experimenter multipart request message
3906
3907     ================ ======================================================
3908     Attribute        Description
3909     ================ ======================================================
3910     flags            Zero or ``OFPMPF_REQ_MORE``
3911     experimenter     Experimenter ID
3912     exp_type         Experimenter defined
3913     data             Experimenter defined additional data
3914     ================ ======================================================
3915     """
3916
3917     def __init__(self, datapath, flags,
3918                  experimenter, exp_type, data,
3919                  type_=None):
3920         super(OFPExperimenterStatsRequest, self).__init__(datapath, flags,
3921                                                           experimenter,
3922                                                           exp_type, type_)
3923         self.data = data
3924
3925     def _serialize_stats_body(self):
3926         body = OFPExperimenterMultipart(experimenter=self.experimenter,
3927                                         exp_type=self.exp_type,
3928                                         data=self.data)
3929         self.buf += body.serialize()
3930
3931
3932 @OFPMultipartReply.register_stats_type(body_single_struct=True)
3933 @_set_stats_type(ofproto.OFPMP_EXPERIMENTER, OFPExperimenterMultipart)
3934 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
3935 class OFPExperimenterStatsReply(OFPMultipartReply):
3936     """
3937     Experimenter multipart reply message
3938
3939     ================ ======================================================
3940     Attribute        Description
3941     ================ ======================================================
3942     body             An ``OFPExperimenterMultipart`` instance
3943     ================ ======================================================
3944     """
3945
3946     def __init__(self, datapath, type_=None, **kwargs):
3947         super(OFPExperimenterStatsReply, self).__init__(datapath, **kwargs)
3948
3949
3950 class OFPFlowDesc(StringifyMixin):
3951     def __init__(self, table_id=None, priority=None,
3952                  idle_timeout=None, hard_timeout=None, flags=None,
3953                  importance=None, cookie=None, match=None, stats=None,
3954                  instructions=None, length=None):
3955         super(OFPFlowDesc, self).__init__()
3956         self.length = length
3957         self.table_id = table_id
3958         self.priority = priority
3959         self.idle_timeout = idle_timeout
3960         self.hard_timeout = hard_timeout
3961         self.flags = flags
3962         self.importance = importance
3963         self.cookie = cookie
3964         self.match = match
3965         self.stats = stats
3966         self.instructions = instructions
3967
3968     @classmethod
3969     def parser(cls, buf, offset):
3970         flow_desc = cls()
3971
3972         (flow_desc.length, flow_desc.table_id,
3973          flow_desc.priority, flow_desc.idle_timeout,
3974          flow_desc.hard_timeout, flow_desc.flags,
3975          flow_desc.importance,
3976          flow_desc.cookie) = struct.unpack_from(
3977             ofproto.OFP_FLOW_DESC_0_PACK_STR, buf, offset)
3978         offset += ofproto.OFP_FLOW_DESC_0_SIZE
3979
3980         flow_desc.match = OFPMatch.parser(buf, offset)
3981         match_length = utils.round_up(flow_desc.match.length, 8)
3982         offset += match_length
3983
3984         flow_desc.stats = OFPStats.parser(buf, offset)
3985         stats_length = utils.round_up(flow_desc.stats.length, 8)
3986         offset += stats_length
3987
3988         instructions = []
3989         inst_length = (flow_desc.length - (ofproto.OFP_FLOW_DESC_0_SIZE +
3990                                            match_length + stats_length))
3991         while inst_length > 0:
3992             inst = OFPInstruction.parser(buf, offset)
3993             instructions.append(inst)
3994             offset += inst.len
3995             inst_length -= inst.len
3996
3997         flow_desc.instructions = instructions
3998         return flow_desc
3999
4000
4001 class OFPFlowStats(StringifyMixin):
4002     def __init__(self, table_id=None, reason=None, priority=None,
4003                  match=None, stats=None, length=None):
4004         super(OFPFlowStats, self).__init__()
4005         self.table_id = table_id
4006         self.reason = reason
4007         self.priority = priority
4008         self.match = match
4009         self.stats = stats
4010         self.length = length
4011
4012     @classmethod
4013     def parser(cls, buf, offset):
4014         flow_stats = cls()
4015
4016         (flow_stats.length, flow_stats.table_id, flow_stats.reason,
4017          flow_stats.priority) = struct.unpack_from(
4018             ofproto.OFP_FLOW_STATS_0_PACK_STR, buf, offset)
4019         offset += ofproto.OFP_FLOW_STATS_0_SIZE
4020
4021         flow_stats.match = OFPMatch.parser(buf, offset)
4022         match_length = utils.round_up(flow_stats.match.length, 8)
4023         offset += match_length
4024
4025         stats_length = (flow_stats.length - (ofproto.OFP_FLOW_STATS_0_SIZE +
4026                                              match_length))
4027         if stats_length > 0:
4028             flow_stats.stats = OFPStats.parser(buf, offset)
4029
4030         return flow_stats
4031
4032
4033 class OFPFlowStatsRequestBase(OFPMultipartRequest):
4034     def __init__(self, datapath, flags, table_id, out_port, out_group,
4035                  cookie, cookie_mask, match):
4036         super(OFPFlowStatsRequestBase, self).__init__(datapath, flags)
4037         self.table_id = table_id
4038         self.out_port = out_port
4039         self.out_group = out_group
4040         self.cookie = cookie
4041         self.cookie_mask = cookie_mask
4042         self.match = match
4043
4044     def _serialize_stats_body(self):
4045         offset = ofproto.OFP_MULTIPART_REQUEST_SIZE
4046         msg_pack_into(ofproto.OFP_FLOW_STATS_REQUEST_0_PACK_STR,
4047                       self.buf, offset, self.table_id, self.out_port,
4048                       self.out_group, self.cookie, self.cookie_mask)
4049
4050         offset += ofproto.OFP_FLOW_STATS_REQUEST_0_SIZE
4051         self.match.serialize(self.buf, offset)
4052
4053
4054 @_set_stats_type(ofproto.OFPMP_FLOW_DESC, OFPFlowDesc)
4055 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
4056 class OFPFlowDescStatsRequest(OFPFlowStatsRequestBase):
4057     """
4058     Individual flow descriptions request message
4059
4060     The controller uses this message to query individual flow descriptions.
4061
4062     ================ ======================================================
4063     Attribute        Description
4064     ================ ======================================================
4065     flags            Zero or ``OFPMPF_REQ_MORE``
4066     table_id         ID of table to read
4067     out_port         Require matching entries to include this as an output
4068                      port
4069     out_group        Require matching entries to include this as an output
4070                      group
4071     cookie           Require matching entries to contain this cookie value
4072     cookie_mask      Mask used to restrict the cookie bits that must match
4073     match            Instance of ``OFPMatch``
4074     ================ ======================================================
4075
4076     Example::
4077
4078         def send_flow_desc_request(self, datapath):
4079             ofp = datapath.ofproto
4080             ofp_parser = datapath.ofproto_parser
4081
4082             cookie = cookie_mask = 0
4083             match = ofp_parser.OFPMatch(in_port=1)
4084             req = ofp_parser.OFPFlowDescStatsRequest(datapath, 0,
4085                                                      ofp.OFPTT_ALL,
4086                                                      ofp.OFPP_ANY,
4087                                                      ofp.OFPG_ANY,
4088                                                      cookie, cookie_mask,
4089                                                      match)
4090             datapath.send_msg(req)
4091     """
4092
4093     def __init__(self, datapath, flags=0, table_id=ofproto.OFPTT_ALL,
4094                  out_port=ofproto.OFPP_ANY,
4095                  out_group=ofproto.OFPG_ANY,
4096                  cookie=0, cookie_mask=0, match=None, type_=None):
4097         if match is None:
4098             match = OFPMatch()
4099         super(OFPFlowDescStatsRequest, self).__init__(
4100             datapath, flags, table_id, out_port, out_group, cookie,
4101             cookie_mask, match)
4102
4103
4104 @OFPMultipartReply.register_stats_type()
4105 @_set_stats_type(ofproto.OFPMP_FLOW_DESC, OFPFlowDesc)
4106 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
4107 class OFPFlowDescStatsReply(OFPMultipartReply):
4108     """
4109     Individual flow descriptions reply message
4110
4111     The switch responds with this message to an individual flow descriptions
4112     request.
4113
4114     ================ ======================================================
4115     Attribute        Description
4116     ================ ======================================================
4117     body             List of ``OFPFlowDesc`` instance
4118     ================ ======================================================
4119
4120     Example::
4121
4122         @set_ev_cls(ofp_event.EventOFPFlowDescStatsReply, MAIN_DISPATCHER)
4123         def flow_desc_reply_handler(self, ev):
4124             flows = []
4125             for stat in ev.msg.body:
4126                 flows.append('table_id=%s priority=%d '
4127                              'idle_timeout=%d hard_timeout=%d flags=0x%04x '
4128                              'importance=%d cookie=%d match=%s '
4129                              'stats=%s instructions=%s' %
4130                              (stat.table_id, stat.priority,
4131                               stat.idle_timeout, stat.hard_timeout,
4132                               stat.flags, stat.importance,
4133                               stat.cookie, stat.match,
4134                               stat.stats, stat.instructions))
4135             self.logger.debug('FlowDesc: %s', flows)
4136     """
4137
4138     def __init__(self, datapath, type_=None, **kwargs):
4139         super(OFPFlowDescStatsReply, self).__init__(datapath, **kwargs)
4140
4141
4142 @_set_stats_type(ofproto.OFPMP_FLOW_STATS, OFPFlowStats)
4143 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
4144 class OFPFlowStatsRequest(OFPFlowStatsRequestBase):
4145     """
4146     Individual flow statistics request message
4147
4148     The controller uses this message to query individual flow statistics.
4149
4150     ================ ======================================================
4151     Attribute        Description
4152     ================ ======================================================
4153     flags            Zero or ``OFPMPF_REQ_MORE``
4154     table_id         ID of table to read
4155     out_port         Require matching entries to include this as an output
4156                      port
4157     out_group        Require matching entries to include this as an output
4158                      group
4159     cookie           Require matching entries to contain this cookie value
4160     cookie_mask      Mask used to restrict the cookie bits that must match
4161     match            Instance of ``OFPMatch``
4162     ================ ======================================================
4163
4164     Example::
4165
4166         def send_flow_stats_request(self, datapath):
4167             ofp = datapath.ofproto
4168             ofp_parser = datapath.ofproto_parser
4169
4170             cookie = cookie_mask = 0
4171             match = ofp_parser.OFPMatch(in_port=1)
4172             req = ofp_parser.OFPFlowStatsRequest(datapath, 0,
4173                                                  ofp.OFPTT_ALL,
4174                                                  ofp.OFPP_ANY, ofp.OFPG_ANY,
4175                                                  cookie, cookie_mask,
4176                                                  match)
4177             datapath.send_msg(req)
4178     """
4179
4180     def __init__(self, datapath, flags=0, table_id=ofproto.OFPTT_ALL,
4181                  out_port=ofproto.OFPP_ANY,
4182                  out_group=ofproto.OFPG_ANY,
4183                  cookie=0, cookie_mask=0, match=None, type_=None):
4184         if match is None:
4185             match = OFPMatch()
4186         super(OFPFlowStatsRequest, self).__init__(datapath, flags, table_id,
4187                                                   out_port, out_group,
4188                                                   cookie, cookie_mask, match)
4189
4190
4191 @OFPMultipartReply.register_stats_type()
4192 @_set_stats_type(ofproto.OFPMP_FLOW_STATS, OFPFlowStats)
4193 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
4194 class OFPFlowStatsReply(OFPMultipartReply):
4195     """
4196     Individual flow statistics reply message
4197
4198     The switch responds with this message to an individual flow statistics
4199     request.
4200
4201     ================ ======================================================
4202     Attribute        Description
4203     ================ ======================================================
4204     body             List of ``OFPFlowStats`` instance
4205     ================ ======================================================
4206
4207     Example::
4208
4209         @set_ev_cls(ofp_event.EventOFPFlowStatsReply, MAIN_DISPATCHER)
4210         def flow_stats_reply_handler(self, ev):
4211             flows = []
4212             for stat in ev.msg.body:
4213                 flows.append('table_id=%s reason=%d priority=%d '
4214                              'match=%s stats=%s' %
4215                              (stat.table_id, stat.reason, stat.priority,
4216                               stat.match, stat.stats))
4217             self.logger.debug('FlowStats: %s', flows)
4218     """
4219
4220     def __init__(self, datapath, type_=None, **kwargs):
4221         super(OFPFlowStatsReply, self).__init__(datapath, **kwargs)
4222
4223
4224 class OFPAggregateStats(StringifyMixin):
4225     def __init__(self, stats=None, length=None):
4226         super(OFPAggregateStats, self).__init__()
4227         self.stats = stats
4228         # Note: length field is specific to this implementation.
4229         # It does not have a corresponding field in the specification.
4230         self.length = length
4231
4232     @classmethod
4233     def parser(cls, buf, offset):
4234         stats = OFPStats.parser(buf, offset)
4235         agg = cls(stats)
4236         agg.length = utils.round_up(stats.length, 8)
4237         return agg
4238
4239
4240 @_set_stats_type(ofproto.OFPMP_AGGREGATE_STATS, OFPAggregateStats)
4241 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
4242 class OFPAggregateStatsRequest(OFPFlowStatsRequestBase):
4243     """
4244     Aggregate flow statistics request message
4245
4246     The controller uses this message to query aggregate flow statictics.
4247
4248     ================ ======================================================
4249     Attribute        Description
4250     ================ ======================================================
4251     flags            Zero or ``OFPMPF_REQ_MORE``
4252     table_id         ID of table to read
4253     out_port         Require matching entries to include this as an output
4254                      port
4255     out_group        Require matching entries to include this as an output
4256                      group
4257     cookie           Require matching entries to contain this cookie value
4258     cookie_mask      Mask used to restrict the cookie bits that must match
4259     match            Instance of ``OFPMatch``
4260     ================ ======================================================
4261
4262     Example::
4263
4264         def send_aggregate_stats_request(self, datapath):
4265             ofp = datapath.ofproto
4266             ofp_parser = datapath.ofproto_parser
4267
4268             cookie = cookie_mask = 0
4269             match = ofp_parser.OFPMatch(in_port=1)
4270             req = ofp_parser.OFPAggregateStatsRequest(datapath, 0,
4271                                                       ofp.OFPTT_ALL,
4272                                                       ofp.OFPP_ANY,
4273                                                       ofp.OFPG_ANY,
4274                                                       cookie, cookie_mask,
4275                                                       match)
4276             datapath.send_msg(req)
4277     """
4278
4279     def __init__(self, datapath, flags, table_id, out_port, out_group,
4280                  cookie, cookie_mask, match, type_=None):
4281         super(OFPAggregateStatsRequest, self).__init__(datapath,
4282                                                        flags,
4283                                                        table_id,
4284                                                        out_port,
4285                                                        out_group,
4286                                                        cookie,
4287                                                        cookie_mask,
4288                                                        match)
4289
4290
4291 @OFPMultipartReply.register_stats_type(body_single_struct=True)
4292 @_set_stats_type(ofproto.OFPMP_AGGREGATE_STATS, OFPAggregateStats)
4293 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
4294 class OFPAggregateStatsReply(OFPMultipartReply):
4295     """
4296     Aggregate flow statistics reply message
4297
4298     The switch responds with this message to an aggregate flow statistics
4299     request.
4300
4301     ================ ======================================================
4302     Attribute        Description
4303     ================ ======================================================
4304     body             Instance of ``OFPAggregateStats``
4305     ================ ======================================================
4306
4307     Example::
4308
4309         @set_ev_cls(ofp_event.EventOFPAggregateStatsReply, MAIN_DISPATCHER)
4310         def aggregate_stats_reply_handler(self, ev):
4311             body = ev.msg.body
4312
4313             self.logger.debug('AggregateStats: stats=%s', body.stats)
4314     """
4315
4316     def __init__(self, datapath, type_=None, **kwargs):
4317         super(OFPAggregateStatsReply, self).__init__(datapath, **kwargs)
4318
4319
4320 class OFPTableStats(ofproto_parser.namedtuple('OFPTableStats', (
4321         'table_id', 'active_count', 'lookup_count',
4322         'matched_count'))):
4323     @classmethod
4324     def parser(cls, buf, offset):
4325         tbl = struct.unpack_from(ofproto.OFP_TABLE_STATS_PACK_STR,
4326                                  buf, offset)
4327         stats = cls(*tbl)
4328         stats.length = ofproto.OFP_TABLE_STATS_SIZE
4329         return stats
4330
4331
4332 @_set_stats_type(ofproto.OFPMP_TABLE_STATS, OFPTableStats)
4333 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
4334 class OFPTableStatsRequest(OFPMultipartRequest):
4335     """
4336     Table statistics request message
4337
4338     The controller uses this message to query flow table statictics.
4339
4340     ================ ======================================================
4341     Attribute        Description
4342     ================ ======================================================
4343     flags            Zero or ``OFPMPF_REQ_MORE``
4344     ================ ======================================================
4345
4346     Example::
4347
4348         def send_table_stats_request(self, datapath):
4349             ofp_parser = datapath.ofproto_parser
4350
4351             req = ofp_parser.OFPTableStatsRequest(datapath, 0)
4352             datapath.send_msg(req)
4353     """
4354
4355     def __init__(self, datapath, flags, type_=None):
4356         super(OFPTableStatsRequest, self).__init__(datapath, flags)
4357
4358
4359 @OFPMultipartReply.register_stats_type()
4360 @_set_stats_type(ofproto.OFPMP_TABLE_STATS, OFPTableStats)
4361 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
4362 class OFPTableStatsReply(OFPMultipartReply):
4363     """
4364     Table statistics reply message
4365
4366     The switch responds with this message to a table statistics request.
4367
4368     ================ ======================================================
4369     Attribute        Description
4370     ================ ======================================================
4371     body             List of ``OFPTableStats`` instance
4372     ================ ======================================================
4373
4374     Example::
4375
4376         @set_ev_cls(ofp_event.EventOFPTableStatsReply, MAIN_DISPATCHER)
4377         def table_stats_reply_handler(self, ev):
4378             tables = []
4379             for stat in ev.msg.body:
4380                 tables.append('table_id=%d active_count=%d lookup_count=%d '
4381                               ' matched_count=%d' %
4382                               (stat.table_id, stat.active_count,
4383                                stat.lookup_count, stat.matched_count))
4384             self.logger.debug('TableStats: %s', tables)
4385     """
4386
4387     def __init__(self, datapath, type_=None, **kwargs):
4388         super(OFPTableStatsReply, self).__init__(datapath, **kwargs)
4389
4390
4391 class OFPPortStatsProp(OFPPropBase):
4392     _TYPES = {}
4393
4394
4395 @OFPPortStatsProp.register_type(ofproto.OFPPSPT_ETHERNET)
4396 class OFPPortStatsPropEthernet(OFPPortStatsProp):
4397     def __init__(self, type_=None, length=None, rx_frame_err=None,
4398                  rx_over_err=None, rx_crc_err=None, collisions=None):
4399         self.type = type_
4400         self.length = length
4401         self.rx_frame_err = rx_frame_err
4402         self.rx_over_err = rx_over_err
4403         self.rx_crc_err = rx_crc_err
4404         self.collisions = collisions
4405
4406     @classmethod
4407     def parser(cls, buf):
4408         ether = cls()
4409         (ether.type, ether.length, ether.rx_frame_err, ether.rx_over_err,
4410          ether.rx_crc_err, ether.collisions) = struct.unpack_from(
4411             ofproto.OFP_PORT_STATS_PROP_ETHERNET_PACK_STR, buf, 0)
4412         return ether
4413
4414
4415 @OFPPortStatsProp.register_type(ofproto.OFPPSPT_OPTICAL)
4416 class OFPPortStatsPropOptical(OFPPortStatsProp):
4417     def __init__(self, type_=None, length=None, flags=None,
4418                  tx_freq_lmda=None, tx_offset=None, tx_grid_span=None,
4419                  rx_freq_lmda=None, rx_offset=None, rx_grid_span=None,
4420                  tx_pwr=None, rx_pwr=None, bias_current=None,
4421                  temperature=None):
4422         self.type = type_
4423         self.length = length
4424         self.flags = flags
4425         self.tx_freq_lmda = tx_freq_lmda
4426         self.tx_offset = tx_offset
4427         self.tx_grid_span = tx_grid_span
4428         self.rx_freq_lmda = rx_freq_lmda
4429         self.rx_offset = rx_offset
4430         self.rx_grid_span = rx_grid_span
4431         self.tx_pwr = tx_pwr
4432         self.rx_pwr = rx_pwr
4433         self.bias_current = bias_current
4434         self.temperature = temperature
4435
4436     @classmethod
4437     def parser(cls, buf):
4438         optical = cls()
4439         (optical.type, optical.length, optical.flags,
4440          optical.tx_freq_lmda, optical.tx_offset, optical.tx_grid_span,
4441          optical.rx_freq_lmda, optical.rx_offset, optical.rx_grid_span,
4442          optical.tx_pwr, optical.rx_pwr, optical.bias_current,
4443          optical.temperature) = struct.unpack_from(
4444             ofproto.OFP_PORT_STATS_PROP_OPTICAL_PACK_STR, buf, 0)
4445         return optical
4446
4447
4448 @OFPPortStatsProp.register_type(ofproto.OFPPSPT_EXPERIMENTER)
4449 class OFPPortStatsPropExperimenter(OFPPropCommonExperimenter4ByteData):
4450     pass
4451
4452
4453 class OFPPortStats(StringifyMixin):
4454     def __init__(self, length=None, port_no=None, duration_sec=None,
4455                  duration_nsec=None, rx_packets=None, tx_packets=None,
4456                  rx_bytes=None, tx_bytes=None, rx_dropped=None,
4457                  tx_dropped=None, rx_errors=None, tx_errors=None,
4458                  properties=None):
4459         super(OFPPortStats, self).__init__()
4460         self.length = length
4461         self.port_no = port_no
4462         self.duration_sec = duration_sec
4463         self.duration_nsec = duration_nsec
4464         self.rx_packets = rx_packets
4465         self.tx_packets = tx_packets
4466         self.rx_bytes = rx_bytes
4467         self.tx_bytes = tx_bytes
4468         self.rx_dropped = rx_dropped
4469         self.tx_dropped = tx_dropped
4470         self.rx_errors = rx_errors
4471         self.tx_errors = tx_errors
4472         self.properties = properties
4473
4474     @classmethod
4475     def parser(cls, buf, offset):
4476         (length, port_no, duration_sec, duration_nsec, rx_packets,
4477          tx_packets, rx_bytes, tx_bytes, rx_dropped, tx_dropped,
4478          rx_errors, tx_errors) = struct.unpack_from(
4479             ofproto.OFP_PORT_STATS_PACK_STR, buf, offset)
4480         props = []
4481         rest = buf[offset + ofproto.OFP_PORT_STATS_SIZE:offset + length]
4482         while rest:
4483             p, rest = OFPPortStatsProp.parse(rest)
4484             props.append(p)
4485         stats = cls(length, port_no, duration_sec, duration_nsec, rx_packets,
4486                     tx_packets, rx_bytes, tx_bytes, rx_dropped, tx_dropped,
4487                     rx_errors, tx_errors, props)
4488         return stats
4489
4490
4491 @_set_stats_type(ofproto.OFPMP_PORT_STATS, OFPPortStats)
4492 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
4493 class OFPPortStatsRequest(OFPMultipartRequest):
4494     """
4495     Port statistics request message
4496
4497     The controller uses this message to query information about ports
4498     statistics.
4499
4500     ================ ======================================================
4501     Attribute        Description
4502     ================ ======================================================
4503     flags            Zero or ``OFPMPF_REQ_MORE``
4504     port_no          Port number to read (OFPP_ANY to all ports)
4505     ================ ======================================================
4506
4507     Example::
4508
4509         def send_port_stats_request(self, datapath):
4510             ofp = datapath.ofproto
4511             ofp_parser = datapath.ofproto_parser
4512
4513             req = ofp_parser.OFPPortStatsRequest(datapath, 0, ofp.OFPP_ANY)
4514             datapath.send_msg(req)
4515     """
4516
4517     def __init__(self, datapath, flags, port_no, type_=None):
4518         super(OFPPortStatsRequest, self).__init__(datapath, flags)
4519         self.port_no = port_no
4520
4521     def _serialize_stats_body(self):
4522         msg_pack_into(ofproto.OFP_PORT_MULTIPART_REQUEST_PACK_STR,
4523                       self.buf,
4524                       ofproto.OFP_MULTIPART_REQUEST_SIZE,
4525                       self.port_no)
4526
4527
4528 @OFPMultipartReply.register_stats_type()
4529 @_set_stats_type(ofproto.OFPMP_PORT_STATS, OFPPortStats)
4530 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
4531 class OFPPortStatsReply(OFPMultipartReply):
4532     """
4533     Port statistics reply message
4534
4535     The switch responds with this message to a port statistics request.
4536
4537     ================ ======================================================
4538     Attribute        Description
4539     ================ ======================================================
4540     body             List of ``OFPPortStats`` instance
4541     ================ ======================================================
4542
4543     Example::
4544
4545         @set_ev_cls(ofp_event.EventOFPPortStatsReply, MAIN_DISPATCHER)
4546         def port_stats_reply_handler(self, ev):
4547             ports = []
4548             for stat in ev.msg.body:
4549                 ports.append(stat.length, stat.port_no,
4550                              stat.duration_sec, stat.duration_nsec,
4551                              stat.rx_packets, stat.tx_packets,
4552                              stat.rx_bytes, stat.tx_bytes,
4553                              stat.rx_dropped, stat.tx_dropped,
4554                              stat.rx_errors, stat.tx_errors,
4555                              repr(stat.properties))
4556             self.logger.debug('PortStats: %s', ports)
4557     """
4558
4559     def __init__(self, datapath, type_=None, **kwargs):
4560         super(OFPPortStatsReply, self).__init__(datapath, **kwargs)
4561
4562
4563 @_set_msg_type(ofproto.OFPT_BARRIER_REQUEST)
4564 class OFPBarrierRequest(MsgBase):
4565     """
4566     Barrier request message
4567
4568     The controller sends this message to ensure message dependencies have
4569     been met or receive notifications for completed operations.
4570
4571     Example::
4572
4573         def send_barrier_request(self, datapath):
4574             ofp_parser = datapath.ofproto_parser
4575
4576             req = ofp_parser.OFPBarrierRequest(datapath)
4577             datapath.send_msg(req)
4578     """
4579
4580     def __init__(self, datapath):
4581         super(OFPBarrierRequest, self).__init__(datapath)
4582
4583
4584 @_register_parser
4585 @_set_msg_type(ofproto.OFPT_BARRIER_REPLY)
4586 class OFPBarrierReply(MsgBase):
4587     """
4588     Barrier reply message
4589
4590     The switch responds with this message to a barrier request.
4591
4592     Example::
4593
4594         @set_ev_cls(ofp_event.EventOFPBarrierReply, MAIN_DISPATCHER)
4595         def barrier_reply_handler(self, ev):
4596             self.logger.debug('OFPBarrierReply received')
4597     """
4598
4599     def __init__(self, datapath):
4600         super(OFPBarrierReply, self).__init__(datapath)
4601
4602
4603 @_register_parser
4604 @_set_msg_type(ofproto.OFPT_PORT_STATUS)
4605 class OFPPortStatus(MsgBase):
4606     """
4607     Port status message
4608
4609     The switch notifies controller of change of ports.
4610
4611     ================ ======================================================
4612     Attribute        Description
4613     ================ ======================================================
4614     reason           One of the following values.
4615
4616                      | OFPPR_ADD
4617                      | OFPPR_DELETE
4618                      | OFPPR_MODIFY
4619     desc             instance of ``OFPPort``
4620     ================ ======================================================
4621
4622     Example::
4623
4624         @set_ev_cls(ofp_event.EventOFPPortStatus, MAIN_DISPATCHER)
4625         def port_status_handler(self, ev):
4626             msg = ev.msg
4627             dp = msg.datapath
4628             ofp = dp.ofproto
4629
4630             if msg.reason == ofp.OFPPR_ADD:
4631                 reason = 'ADD'
4632             elif msg.reason == ofp.OFPPR_DELETE:
4633                 reason = 'DELETE'
4634             elif msg.reason == ofp.OFPPR_MODIFY:
4635                 reason = 'MODIFY'
4636             else:
4637                 reason = 'unknown'
4638
4639             self.logger.debug('OFPPortStatus received: reason=%s desc=%s',
4640                               reason, msg.desc)
4641     """
4642
4643     def __init__(self, datapath, reason=None, desc=None):
4644         super(OFPPortStatus, self).__init__(datapath)
4645         self.reason = reason
4646         self.desc = desc
4647
4648     @classmethod
4649     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
4650         msg = super(OFPPortStatus, cls).parser(datapath, version, msg_type,
4651                                                msg_len, xid, buf)
4652         msg.reason = struct.unpack_from(
4653             ofproto.OFP_PORT_STATUS_PACK_STR, msg.buf,
4654             ofproto.OFP_HEADER_SIZE)[0]
4655         msg.desc = OFPPort.parser(msg.buf, ofproto.OFP_PORT_STATUS_DESC_OFFSET)
4656         return msg
4657
4658
4659 @_register_parser
4660 @_set_msg_type(ofproto.OFPT_ROLE_STATUS)
4661 class OFPRoleStatus(MsgBase):
4662     """
4663     Role status message
4664
4665     The switch notifies controller of change of role.
4666
4667     ================ ======================================================
4668     Attribute        Description
4669     ================ ======================================================
4670     role             One of the following values.
4671
4672                      | OFPCR_ROLE_NOCHANGE
4673                      | OFPCR_ROLE_EQUAL
4674                      | OFPCR_ROLE_MASTER
4675     reason           One of the following values.
4676
4677                      | OFPCRR_MASTER_REQUEST
4678                      | OFPCRR_CONFIG
4679                      | OFPCRR_EXPERIMENTER
4680     generation_id    Master Election Generation ID
4681     properties       List of ``OFPRoleProp`` subclass instance
4682     ================ ======================================================
4683
4684     Example::
4685
4686         @set_ev_cls(ofp_event.EventOFPRoleStatus, MAIN_DISPATCHER)
4687         def role_status_handler(self, ev):
4688             msg = ev.msg
4689             dp = msg.datapath
4690             ofp = dp.ofproto
4691
4692             if msg.role == ofp.OFPCR_ROLE_NOCHANGE:
4693                 role = 'ROLE NOCHANGE'
4694             elif msg.role == ofp.OFPCR_ROLE_EQUAL:
4695                 role = 'ROLE EQUAL'
4696             elif msg.role == ofp.OFPCR_ROLE_MASTER:
4697                 role = 'ROLE MASTER'
4698             else:
4699                 role = 'unknown'
4700
4701             if msg.reason == ofp.OFPCRR_MASTER_REQUEST:
4702                 reason = 'MASTER REQUEST'
4703             elif msg.reason == ofp.OFPCRR_CONFIG:
4704                 reason = 'CONFIG'
4705             elif msg.reason == ofp.OFPCRR_EXPERIMENTER:
4706                 reason = 'EXPERIMENTER'
4707             else:
4708                 reason = 'unknown'
4709
4710             self.logger.debug('OFPRoleStatus received: role=%s reason=%s '
4711                               'generation_id=%d properties=%s', role, reason,
4712                               msg.generation_id, repr(msg.properties))
4713     """
4714
4715     def __init__(self, datapath, role=None, reason=None,
4716                  generation_id=None, properties=None):
4717         super(OFPRoleStatus, self).__init__(datapath)
4718         self.role = role
4719         self.reason = reason
4720         self.generation_id = generation_id
4721         self.properties = properties
4722
4723     @classmethod
4724     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
4725         msg = super(OFPRoleStatus, cls).parser(datapath, version, msg_type,
4726                                                msg_len, xid, buf)
4727         (msg.role, msg.reason, msg.generation_id) = struct.unpack_from(
4728             ofproto.OFP_ROLE_STATUS_PACK_STR, msg.buf,
4729             ofproto.OFP_HEADER_SIZE)
4730
4731         msg.properties = []
4732         rest = msg.buf[ofproto.OFP_ROLE_STATUS_SIZE:]
4733         while rest:
4734             p, rest = OFPRoleProp.parse(rest)
4735             msg.properties.append(p)
4736
4737         return msg
4738
4739
4740 @_register_parser
4741 @_set_msg_type(ofproto.OFPT_TABLE_STATUS)
4742 class OFPTableStatus(MsgBase):
4743     """
4744     Table status message
4745
4746     The switch notifies controller of change of table status.
4747
4748     ================ ======================================================
4749     Attribute        Description
4750     ================ ======================================================
4751     reason           One of the following values.
4752
4753                      | OFPTR_VACANCY_DOWN
4754                      | OFPTR_VACANCY_UP
4755     table            ``OFPTableDesc`` instance
4756     ================ ======================================================
4757
4758     Example::
4759
4760         @set_ev_cls(ofp_event.EventOFPTableStatus, MAIN_DISPATCHER)
4761         def table(self, ev):
4762             msg = ev.msg
4763             dp = msg.datapath
4764             ofp = dp.ofproto
4765
4766             if msg.reason == ofp.OFPTR_VACANCY_DOWN:
4767                 reason = 'VACANCY_DOWN'
4768             elif msg.reason == ofp.OFPTR_VACANCY_UP:
4769                 reason = 'VACANCY_UP'
4770             else:
4771                 reason = 'unknown'
4772
4773             self.logger.debug('OFPTableStatus received: reason=%s '
4774                               'table_id=%d config=0x%08x properties=%s',
4775                               reason, msg.table.table_id, msg.table.config,
4776                               repr(msg.table.properties))
4777     """
4778
4779     def __init__(self, datapath, reason=None, table=None):
4780         super(OFPTableStatus, self).__init__(datapath)
4781         self.reason = reason
4782         self.table = table
4783
4784     @classmethod
4785     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
4786         msg = super(OFPTableStatus, cls).parser(datapath, version, msg_type,
4787                                                 msg_len, xid, buf)
4788         (msg.reason,) = struct.unpack_from(ofproto.OFP_TABLE_STATUS_0_PACK_STR,
4789                                            msg.buf, ofproto.OFP_HEADER_SIZE)
4790
4791         msg.table = OFPTableDesc.parser(msg.buf,
4792                                         ofproto.OFP_TABLE_STATUS_0_SIZE)
4793
4794         return msg
4795
4796
4797 @_register_parser
4798 @_set_msg_type(ofproto.OFPT_REQUESTFORWARD)
4799 class OFPRequestForward(MsgInMsgBase):
4800     """
4801     Forwarded request message
4802
4803     The swtich forwards request messages from one controller to other
4804     controllers.
4805
4806     ================ ======================================================
4807     Attribute        Description
4808     ================ ======================================================
4809     request          ``OFPGroupMod`` or ``OFPMeterMod`` instance
4810     ================ ======================================================
4811
4812     Example::
4813
4814         @set_ev_cls(ofp_event.EventOFPRequestForward, MAIN_DISPATCHER)
4815         def request_forward_handler(self, ev):
4816             msg = ev.msg
4817             dp = msg.datapath
4818             ofp = dp.ofproto
4819
4820             if msg.request.msg_type == ofp.OFPT_GROUP_MOD:
4821                 self.logger.debug(
4822                     'OFPRequestForward received: request=OFPGroupMod('
4823                     'command=%d, type=%d, group_id=%d, command_bucket_id=%d, '
4824                     'buckets=%s, properties=%s)',
4825                     msg.request.command, msg.request.type,
4826                     msg.request.group_id, msg.request.command_bucket_id,
4827                     msg.request.buckets, repr(msg.request.properties))
4828             elif msg.request.msg_type == ofp.OFPT_METER_MOD:
4829                 self.logger.debug(
4830                     'OFPRequestForward received: request=OFPMeterMod('
4831                     'command=%d, flags=%d, meter_id=%d, bands=%s)',
4832                     msg.request.command, msg.request.flags,
4833                     msg.request.meter_id, msg.request.bands)
4834             else:
4835                 self.logger.debug(
4836                     'OFPRequestForward received: request=Unknown')
4837     """
4838
4839     def __init__(self, datapath, request=None):
4840         super(OFPRequestForward, self).__init__(datapath)
4841         self.request = request
4842
4843     @classmethod
4844     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
4845         msg = super(OFPRequestForward, cls).parser(
4846             datapath, version, msg_type, msg_len, xid, buf)
4847         req_buf = buf[ofproto.OFP_HEADER_SIZE:]
4848         (_ver, _type, _len, _xid) = ofproto_parser.header(req_buf)
4849         msg.request = ofproto_parser.msg(
4850             datapath, _ver, _type, _len, _xid, req_buf)
4851         return msg
4852
4853     def _serialize_body(self):
4854         assert isinstance(self.request, (OFPGroupMod, OFPMeterMod))
4855         self.request.serialize()
4856         self.buf += self.request.buf
4857
4858
4859 class OFPControllerStatusProp(OFPPropBase):
4860     _TYPES = {}
4861
4862
4863 @OFPControllerStatusProp.register_type(ofproto.OFPCSPT_URI)
4864 class OFPControllerStatusPropUri(OFPControllerStatusProp):
4865     _TYPE = {
4866         'ascii': [
4867             'uri',
4868         ]
4869     }
4870
4871     def __init__(self, type_=None, length=None, uri=None):
4872         super(OFPControllerStatusPropUri, self).__init__(type_, length)
4873         self.uri = uri
4874
4875     @classmethod
4876     def parser(cls, buf):
4877         rest = cls.get_rest(buf)
4878         pack_str = '!%ds' % len(rest)
4879         (uri, ) = struct.unpack_from(pack_str, rest, 0)
4880         return cls(uri=uri)
4881
4882
4883 @OFPControllerStatusProp.register_type(ofproto.OFPCSPT_EXPERIMENTER)
4884 class OFPControllerStatusPropExperimenter(OFPPropCommonExperimenter4ByteData):
4885     pass
4886
4887
4888 class OFPControllerStatusStats(StringifyMixin):
4889
4890     """
4891     Controller status structure
4892
4893     ============== =========================================================
4894     Attribute      Description
4895     ============== =========================================================
4896     length         Length of this entry.
4897     short_id       ID number which identifies the controller.
4898     role           Bitmap of controller's role flags.
4899
4900                    | OFPCR_ROLE_NOCHANGE
4901                    | OFPCR_ROLE_EQUAL
4902                    | OFPCR_ROLE_MASTER
4903                    | OFPCR_ROLE_SLAVE
4904     reason         Bitmap of controller status reason flags.
4905
4906                    | OFPCSR_REQUEST
4907                    | OFPCSR_CHANNEL_STATUS
4908                    | OFPCSR_ROLE
4909                    | OFPCSR_CONTROLLER_ADDED
4910                    | OFPCSR_CONTROLLER_REMOVED
4911                    | OFPCSR_SHORT_ID
4912                    | OFPCSR_EXPERIMENTER
4913     channel_status Bitmap of control channel status flags.
4914
4915                    | OFPCT_STATUS_UP
4916                    | OFPCT_STATUS_DOWN
4917     properties     List of ``OFPControllerStatusProp`` subclass instance
4918     ============== =========================================================
4919     """
4920
4921     def __init__(self, short_id=None, role=None, reason=None,
4922                  channel_status=None, properties=None, length=None):
4923         super(OFPControllerStatusStats, self).__init__()
4924         self.length = length
4925         self.short_id = short_id
4926         self.role = role
4927         self.reason = reason
4928         self.channel_status = channel_status
4929         self.properties = properties
4930
4931     @classmethod
4932     def parser(cls, buf, offset):
4933         status = cls()
4934
4935         (status.length, status.short_id,
4936          status.role, status.reason,
4937          status.channel_status) = struct.unpack_from(
4938             ofproto.OFP_CONTROLLER_STATUS_PACK_STR, buf, offset)
4939         offset += ofproto.OFP_CONTROLLER_STATUS_SIZE
4940
4941         status.properties = []
4942         rest = buf[offset:offset + status.length]
4943         while rest:
4944             p, rest = OFPControllerStatusProp.parse(rest)
4945             status.properties.append(p)
4946
4947         return status
4948
4949
4950 @_set_stats_type(ofproto.OFPMP_CONTROLLER_STATUS, OFPControllerStatusStats)
4951 @_set_msg_type(ofproto.OFPT_MULTIPART_REQUEST)
4952 class OFPControllerStatusStatsRequest(OFPMultipartRequest):
4953     """
4954     Controller status multipart request message
4955
4956     The controller uses this message to request the status, the roles
4957     and the control channels of other controllers configured on the switch.
4958
4959     ================ ======================================================
4960     Attribute        Description
4961     ================ ======================================================
4962     flags            Zero or ``OFPMPF_REQ_MORE``
4963     ================ ======================================================
4964
4965     Example::
4966
4967         def send_controller_status_multipart_request(self, datapath):
4968             ofp_parser = datapath.ofproto_parser
4969
4970             req = ofp_parser.OFPPortDescStatsRequest(datapath, 0)
4971             datapath.send_msg(req)
4972     """
4973
4974     def __init__(self, datapath, flags=0, type_=None):
4975         super(OFPControllerStatusStatsRequest,
4976               self).__init__(datapath, flags)
4977
4978
4979 @OFPMultipartReply.register_stats_type()
4980 @_set_stats_type(ofproto.OFPMP_CONTROLLER_STATUS, OFPControllerStatusStats)
4981 @_set_msg_type(ofproto.OFPT_MULTIPART_REPLY)
4982 class OFPControllerStatusStatsReply(OFPMultipartReply):
4983     """
4984      Controller status multipart reply message
4985
4986     The switch responds with this message to a controller status
4987     multipart request.
4988
4989     ================ ======================================================
4990     Attribute        Description
4991     ================ ======================================================
4992     body             List of ``OFPControllerStatus`` instance
4993     ================ ======================================================
4994
4995     Example::
4996
4997         @set_ev_cls(ofp_event.EventOFPControllerStatusStatsReply,
4998                     MAIN_DISPATCHER)
4999         def controller_status_multipart_reply_handler(self, ev):
5000             status = []
5001             for s in ev.msg.body:
5002                 status.append('short_id=%d role=%d reason=%d '
5003                               'channel_status=%d properties=%s' %
5004                               (s.short_id, s.role, s.reason,
5005                                s.channel_status, repr(s.properties)))
5006             self.logger.debug('OFPControllerStatusStatsReply received: %s',
5007                               status)
5008     """
5009
5010     def __init__(self, datapath, type_=None, **kwargs):
5011         super(OFPControllerStatusStatsReply, self).__init__(datapath,
5012                                                             **kwargs)
5013
5014
5015 @_register_parser
5016 @_set_msg_type(ofproto.OFPT_CONTROLLER_STATUS)
5017 class OFPControllerStatus(MsgBase):
5018     """
5019     Controller status message
5020
5021     The switch informs the controller about the status of the control
5022     channel it maintains with each controller.
5023
5024     ================ ======================================================
5025     Attribute        Description
5026     ================ ======================================================
5027     status           ``OFPControllerStatusStats`` instance
5028     ================ ======================================================
5029
5030     Example::
5031
5032         @set_ev_cls(ofp_event.EventOFPControllerStatus, MAIN_DISPATCHER)
5033         def table(self, ev):
5034             msg = ev.msg
5035             dp = msg.datapath
5036             ofp = dp.ofproto
5037             status = msg.status
5038
5039             if status.role == ofp.OFPCR_ROLE_NOCHANGE:
5040                 role = 'NOCHANGE'
5041             elif status.role == ofp.OFPCR_ROLE_EQUAL:
5042                 role = 'EQUAL'
5043             elif status.role == ofp.OFPCR_ROLE_MASTER:
5044                 role = 'MASTER'
5045             elif status.role == ofp.OFPCR_ROLE_SLAVE:
5046                 role = 'SLAVE'
5047             else:
5048                 role = 'unknown'
5049
5050             if status.reason == ofp.OFPCSR_REQUEST:
5051                 reason = 'REQUEST'
5052             elif status.reason == ofp.OFPCSR_CHANNEL_STATUS:
5053                 reason = 'CHANNEL_STATUS'
5054             elif status.reason == ofp.OFPCSR_ROLE:
5055                 reason = 'ROLE'
5056             elif status.reason == ofp.OFPCSR_CONTROLLER_ADDED:
5057                 reason = 'CONTROLLER_ADDED'
5058             elif status.reason == ofp.OFPCSR_CONTROLLER_REMOVED:
5059                 reason = 'CONTROLLER_REMOVED'
5060             elif status.reason == ofp.OFPCSR_SHORT_ID:
5061                 reason = 'SHORT_ID'
5062             elif status.reason == ofp.OFPCSR_EXPERIMENTER:
5063                 reason = 'EXPERIMENTER'
5064             else:
5065                 reason = 'unknown'
5066
5067             if status.channel_status == OFPCT_STATUS_UP:
5068                 channel_status = 'UP'
5069             if status.channel_status == OFPCT_STATUS_DOWN:
5070                 channel_status = 'DOWN'
5071             else:
5072                 channel_status = 'unknown'
5073
5074             self.logger.debug('OFPControllerStatus received: short_id=%d'
5075                               'role=%s reason=%s channel_status=%s '
5076                               'properties=%s',
5077                               status.short_id, role, reason, channel_status,
5078                               repr(status.properties))
5079     """
5080
5081     def __init__(self, datapath, status=None):
5082         super(OFPControllerStatus, self).__init__(datapath)
5083         self.status = status
5084
5085     @classmethod
5086     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
5087         msg = super(OFPControllerStatus, cls).parser(datapath, version,
5088                                                      msg_type, msg_len,
5089                                                      xid, buf)
5090
5091         msg.status = OFPControllerStatusStats.parser(msg.buf,
5092                                                      ofproto.OFP_HEADER_SIZE)
5093
5094         return msg
5095
5096
5097 @_set_msg_type(ofproto.OFPT_PACKET_OUT)
5098 class OFPPacketOut(MsgBase):
5099     """
5100     Packet-Out message
5101
5102     The controller uses this message to send a packet out throught the
5103     switch.
5104
5105     ================ ======================================================
5106     Attribute        Description
5107     ================ ======================================================
5108     buffer_id        ID assigned by datapath (OFP_NO_BUFFER if none)
5109     match            Instance of ``OFPMatch``
5110                      (``in_port`` is mandatory in the match field)
5111     actions          list of OpenFlow action class
5112     data             Packet data of a binary type value or
5113                      an instances of packet.Packet.
5114     ================ ======================================================
5115
5116     Example::
5117
5118         def send_packet_out(self, datapath, buffer_id, in_port):
5119             ofp = datapath.ofproto
5120             ofp_parser = datapath.ofproto_parser
5121
5122             match = OFPMatch(in_port=in_port)
5123             actions = [ofp_parser.OFPActionOutput(ofp.OFPP_FLOOD, 0)]
5124             req = ofp_parser.OFPPacketOut(datapath, buffer_id,
5125                                           match, actions)
5126             datapath.send_msg(req)
5127     """
5128
5129     def __init__(self, datapath, buffer_id=None, match=None, actions=None,
5130                  data=None, actions_len=None):
5131         super(OFPPacketOut, self).__init__(datapath)
5132         if buffer_id is None:
5133             self.buffer_id = ofproto.OFP_NO_BUFFER
5134         else:
5135             self.buffer_id = buffer_id
5136         self.actions_len = 0
5137         assert 'in_port' in match
5138         self.match = match
5139         self.actions = actions
5140         self.data = data
5141
5142     def _serialize_body(self):
5143         # adjustment
5144         offset = ofproto.OFP_PACKET_OUT_0_SIZE
5145         match_len = self.match.serialize(self.buf, offset)
5146         offset += match_len
5147
5148         self.actions_len = 0
5149         for a in self.actions:
5150             a.serialize(self.buf, offset)
5151             offset += a.len
5152             self.actions_len += a.len
5153
5154         if self.buffer_id == ofproto.OFP_NO_BUFFER:
5155             assert self.data is not None
5156             if isinstance(self.data, packet.Packet):
5157                 self.data.serialize()
5158                 self.buf += self.data.data
5159             else:
5160                 self.buf += self.data
5161         else:
5162             assert self.data is None
5163
5164         msg_pack_into(ofproto.OFP_PACKET_OUT_0_PACK_STR,
5165                       self.buf, ofproto.OFP_HEADER_SIZE,
5166                       self.buffer_id, self.actions_len)
5167
5168     @classmethod
5169     def from_jsondict(cls, dict_, decode_string=base64.b64decode,
5170                       **additional_args):
5171         if isinstance(dict_['data'], dict):
5172             data = dict_.pop('data')
5173             ins = super(OFPPacketOut, cls).from_jsondict(dict_,
5174                                                          decode_string,
5175                                                          **additional_args)
5176             ins.data = packet.Packet.from_jsondict(data['Packet'])
5177             dict_['data'] = data
5178         else:
5179             ins = super(OFPPacketOut, cls).from_jsondict(dict_,
5180                                                          decode_string,
5181                                                          **additional_args)
5182
5183         return ins
5184
5185
5186 @_register_parser
5187 @_set_msg_type(ofproto.OFPT_FLOW_MOD)
5188 class OFPFlowMod(MsgBase):
5189     """
5190     Modify Flow entry message
5191
5192     The controller sends this message to modify the flow table.
5193
5194     ================ ======================================================
5195     Attribute        Description
5196     ================ ======================================================
5197     cookie           Opaque controller-issued identifier
5198     cookie_mask      Mask used to restrict the cookie bits that must match
5199                      when the command is ``OPFFC_MODIFY*`` or
5200                      ``OFPFC_DELETE*``
5201     table_id         ID of the table to put the flow in
5202     command          One of the following values.
5203
5204                      | OFPFC_ADD
5205                      | OFPFC_MODIFY
5206                      | OFPFC_MODIFY_STRICT
5207                      | OFPFC_DELETE
5208                      | OFPFC_DELETE_STRICT
5209     idle_timeout     Idle time before discarding (seconds)
5210     hard_timeout     Max time before discarding (seconds)
5211     priority         Priority level of flow entry
5212     buffer_id        Buffered packet to apply to (or OFP_NO_BUFFER)
5213     out_port         For ``OFPFC_DELETE*`` commands, require matching
5214                      entries to include this as an output port
5215     out_group        For ``OFPFC_DELETE*`` commands, require matching
5216                      entries to include this as an output group
5217     flags            Bitmap of the following flags.
5218
5219                      | OFPFF_SEND_FLOW_REM
5220                      | OFPFF_CHECK_OVERLAP
5221                      | OFPFF_RESET_COUNTS
5222                      | OFPFF_NO_PKT_COUNTS
5223                      | OFPFF_NO_BYT_COUNTS
5224     importance       Eviction precedence
5225     match            Instance of ``OFPMatch``
5226     instructions     list of ``OFPInstruction*`` instance
5227     ================ ======================================================
5228
5229     Example::
5230
5231         def send_flow_mod(self, datapath):
5232             ofp = datapath.ofproto
5233             ofp_parser = datapath.ofproto_parser
5234
5235             cookie = cookie_mask = 0
5236             table_id = 0
5237             idle_timeout = hard_timeout = 0
5238             priority = 32768
5239             buffer_id = ofp.OFP_NO_BUFFER
5240             importance = 0
5241             match = ofp_parser.OFPMatch(in_port=1, eth_dst='ff:ff:ff:ff:ff:ff')
5242             actions = [ofp_parser.OFPActionOutput(ofp.OFPP_NORMAL, 0)]
5243             inst = [ofp_parser.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS,
5244                                                      actions)]
5245             req = ofp_parser.OFPFlowMod(datapath, cookie, cookie_mask,
5246                                         table_id, ofp.OFPFC_ADD,
5247                                         idle_timeout, hard_timeout,
5248                                         priority, buffer_id,
5249                                         ofp.OFPP_ANY, ofp.OFPG_ANY,
5250                                         ofp.OFPFF_SEND_FLOW_REM,
5251                                         importance,
5252                                         match, inst)
5253             datapath.send_msg(req)
5254     """
5255
5256     def __init__(self, datapath, cookie=0, cookie_mask=0, table_id=0,
5257                  command=ofproto.OFPFC_ADD,
5258                  idle_timeout=0, hard_timeout=0,
5259                  priority=ofproto.OFP_DEFAULT_PRIORITY,
5260                  buffer_id=ofproto.OFP_NO_BUFFER,
5261                  out_port=0, out_group=0, flags=0, importance=0,
5262                  match=None,
5263                  instructions=None):
5264         instructions = instructions if instructions else []
5265         super(OFPFlowMod, self).__init__(datapath)
5266         self.cookie = cookie
5267         self.cookie_mask = cookie_mask
5268         self.table_id = table_id
5269         self.command = command
5270         self.idle_timeout = idle_timeout
5271         self.hard_timeout = hard_timeout
5272         self.priority = priority
5273         self.buffer_id = buffer_id
5274         self.out_port = out_port
5275         self.out_group = out_group
5276         self.flags = flags
5277         self.importance = importance
5278         if match is None:
5279             match = OFPMatch()
5280         assert isinstance(match, OFPMatch)
5281         self.match = match
5282         for i in instructions:
5283             assert isinstance(i, OFPInstruction)
5284         self.instructions = instructions
5285
5286     def _serialize_body(self):
5287         msg_pack_into(ofproto.OFP_FLOW_MOD_PACK_STR0, self.buf,
5288                       ofproto.OFP_HEADER_SIZE,
5289                       self.cookie, self.cookie_mask, self.table_id,
5290                       self.command, self.idle_timeout, self.hard_timeout,
5291                       self.priority, self.buffer_id, self.out_port,
5292                       self.out_group, self.flags, self.importance)
5293
5294         offset = (ofproto.OFP_FLOW_MOD_SIZE -
5295                   ofproto.OFP_MATCH_SIZE)
5296
5297         match_len = self.match.serialize(self.buf, offset)
5298         offset += match_len
5299
5300         for inst in self.instructions:
5301             inst.serialize(self.buf, offset)
5302             offset += inst.len
5303
5304     @classmethod
5305     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
5306         msg = super(OFPFlowMod, cls).parser(
5307             datapath, version, msg_type, msg_len, xid, buf)
5308
5309         (msg.cookie, msg.cookie_mask, msg.table_id,
5310          msg.command, msg.idle_timeout, msg.hard_timeout,
5311          msg.priority, msg.buffer_id, msg.out_port,
5312          msg.out_group, msg.flags, msg.importance) = struct.unpack_from(
5313             ofproto.OFP_FLOW_MOD_PACK_STR0, msg.buf,
5314             ofproto.OFP_HEADER_SIZE)
5315         offset = ofproto.OFP_FLOW_MOD_SIZE - ofproto.OFP_HEADER_SIZE
5316
5317         msg.match = OFPMatch.parser(buf, offset)
5318         offset += utils.round_up(msg.match.length, 8)
5319
5320         instructions = []
5321         while offset < msg_len:
5322             i = OFPInstruction.parser(buf, offset)
5323             instructions.append(i)
5324             offset += i.len
5325         msg.instructions = instructions
5326
5327         return msg
5328
5329
5330 class OFPInstruction(StringifyMixin):
5331     _INSTRUCTION_TYPES = {}
5332
5333     @staticmethod
5334     def register_instruction_type(types):
5335         def _register_instruction_type(cls):
5336             for type_ in types:
5337                 OFPInstruction._INSTRUCTION_TYPES[type_] = cls
5338             return cls
5339         return _register_instruction_type
5340
5341     @classmethod
5342     def parser(cls, buf, offset):
5343         (type_, len_) = struct.unpack_from('!HH', buf, offset)
5344         cls_ = cls._INSTRUCTION_TYPES.get(type_)
5345         return cls_.parser(buf, offset)
5346
5347
5348 @OFPInstruction.register_instruction_type([ofproto.OFPIT_GOTO_TABLE])
5349 class OFPInstructionGotoTable(OFPInstruction):
5350     """
5351     Goto table instruction
5352
5353     This instruction indicates the next table in the processing pipeline.
5354
5355     ================ ======================================================
5356     Attribute        Description
5357     ================ ======================================================
5358     table_id         Next table
5359     ================ ======================================================
5360     """
5361
5362     def __init__(self, table_id, type_=None, len_=None):
5363         super(OFPInstructionGotoTable, self).__init__()
5364         self.type = ofproto.OFPIT_GOTO_TABLE
5365         self.len = ofproto.OFP_INSTRUCTION_GOTO_TABLE_SIZE
5366         self.table_id = table_id
5367
5368     @classmethod
5369     def parser(cls, buf, offset):
5370         (type_, len_, table_id) = struct.unpack_from(
5371             ofproto.OFP_INSTRUCTION_GOTO_TABLE_PACK_STR,
5372             buf, offset)
5373         return cls(table_id)
5374
5375     def serialize(self, buf, offset):
5376         msg_pack_into(ofproto.OFP_INSTRUCTION_GOTO_TABLE_PACK_STR,
5377                       buf, offset, self.type, self.len, self.table_id)
5378
5379
5380 @OFPInstruction.register_instruction_type([ofproto.OFPIT_WRITE_METADATA])
5381 class OFPInstructionWriteMetadata(OFPInstruction):
5382     """
5383     Write metadata instruction
5384
5385     This instruction writes the masked metadata value into the metadata field.
5386
5387     ================ ======================================================
5388     Attribute        Description
5389     ================ ======================================================
5390     metadata         Metadata value to write
5391     metadata_mask    Metadata write bitmask
5392     ================ ======================================================
5393     """
5394
5395     def __init__(self, metadata, metadata_mask, type_=None, len_=None):
5396         super(OFPInstructionWriteMetadata, self).__init__()
5397         self.type = ofproto.OFPIT_WRITE_METADATA
5398         self.len = ofproto.OFP_INSTRUCTION_WRITE_METADATA_SIZE
5399         self.metadata = metadata
5400         self.metadata_mask = metadata_mask
5401
5402     @classmethod
5403     def parser(cls, buf, offset):
5404         (type_, len_, metadata, metadata_mask) = struct.unpack_from(
5405             ofproto.OFP_INSTRUCTION_WRITE_METADATA_PACK_STR,
5406             buf, offset)
5407         return cls(metadata, metadata_mask)
5408
5409     def serialize(self, buf, offset):
5410         msg_pack_into(ofproto.OFP_INSTRUCTION_WRITE_METADATA_PACK_STR,
5411                       buf, offset, self.type, self.len, self.metadata,
5412                       self.metadata_mask)
5413
5414
5415 @OFPInstruction.register_instruction_type([ofproto.OFPIT_WRITE_ACTIONS,
5416                                            ofproto.OFPIT_APPLY_ACTIONS,
5417                                            ofproto.OFPIT_CLEAR_ACTIONS])
5418 class OFPInstructionActions(OFPInstruction):
5419     """
5420     Actions instruction
5421
5422     This instruction writes/applies/clears the actions.
5423
5424     ================ ======================================================
5425     Attribute        Description
5426     ================ ======================================================
5427     type             One of following values.
5428
5429                      | OFPIT_WRITE_ACTIONS
5430                      | OFPIT_APPLY_ACTIONS
5431                      | OFPIT_CLEAR_ACTIONS
5432     actions          list of OpenFlow action class
5433     ================ ======================================================
5434
5435     ``type`` attribute corresponds to ``type_`` parameter of __init__.
5436     """
5437
5438     def __init__(self, type_, actions=None, len_=None):
5439         super(OFPInstructionActions, self).__init__()
5440         self.type = type_
5441         for a in actions:
5442             assert isinstance(a, OFPAction)
5443         self.actions = actions
5444
5445     @classmethod
5446     def parser(cls, buf, offset):
5447         (type_, len_) = struct.unpack_from(
5448             ofproto.OFP_INSTRUCTION_ACTIONS_PACK_STR,
5449             buf, offset)
5450
5451         offset += ofproto.OFP_INSTRUCTION_ACTIONS_SIZE
5452         actions = []
5453         actions_len = len_ - ofproto.OFP_INSTRUCTION_ACTIONS_SIZE
5454         while actions_len > 0:
5455             a = OFPAction.parser(buf, offset)
5456             actions.append(a)
5457             actions_len -= a.len
5458             offset += a.len
5459
5460         inst = cls(type_, actions)
5461         inst.len = len_
5462         return inst
5463
5464     def serialize(self, buf, offset):
5465         action_offset = offset + ofproto.OFP_INSTRUCTION_ACTIONS_SIZE
5466         if self.actions:
5467             for a in self.actions:
5468                 a.serialize(buf, action_offset)
5469                 action_offset += a.len
5470
5471         self.len = action_offset - offset
5472         pad_len = utils.round_up(self.len, 8) - self.len
5473         msg_pack_into("%dx" % pad_len, buf, action_offset)
5474         self.len += pad_len
5475
5476         msg_pack_into(ofproto.OFP_INSTRUCTION_ACTIONS_PACK_STR,
5477                       buf, offset, self.type, self.len)
5478
5479
5480 @OFPInstruction.register_instruction_type([ofproto.OFPIT_STAT_TRIGGER])
5481 class OFPInstructionStatTrigger(OFPInstruction):
5482     """
5483     Statistics triggers instruction
5484
5485     This instruction defines a set of statistics thresholds using OXS.
5486
5487     ================ ======================================================
5488     Attribute        Description
5489     ================ ======================================================
5490     flags            Bitmap of the following flags.
5491
5492                      | OFPSTF_PERIODIC
5493                      | OFPSTF_ONLY_FIRST
5494     thresholds       Instance of ``OFPStats``
5495     ================ ======================================================
5496     """
5497
5498     def __init__(self, flags, thresholds, type_=None, len_=None):
5499         super(OFPInstructionStatTrigger, self).__init__()
5500         self.type = ofproto.OFPIT_STAT_TRIGGER
5501         self.len = len_
5502         self.flags = flags
5503         self.thresholds = thresholds
5504
5505     @classmethod
5506     def parser(cls, buf, offset):
5507         (type_, len_, flags) = struct.unpack_from(
5508             ofproto.OFP_INSTRUCTION_STAT_TRIGGER_PACK_STR0, buf, offset)
5509
5510         # adjustment
5511         offset += 8
5512         thresholds = OFPStats.parser(buf, offset)
5513
5514         inst = cls(flags, thresholds)
5515         inst.len = len_
5516         return inst
5517
5518     def serialize(self, buf, offset):
5519         stats_len = self.thresholds.serialize(buf, offset + 8)
5520
5521         self.len = 8 + stats_len
5522         msg_pack_into(ofproto.OFP_INSTRUCTION_STAT_TRIGGER_PACK_STR0,
5523                       buf, offset, self.type, self.len, self.flags)
5524
5525
5526 class OFPActionHeader(StringifyMixin):
5527     def __init__(self, type_, len_):
5528         self.type = type_
5529         self.len = len_
5530
5531     def serialize(self, buf, offset):
5532         msg_pack_into(ofproto.OFP_ACTION_HEADER_PACK_STR,
5533                       buf, offset, self.type, self.len)
5534
5535
5536 class OFPAction(OFPActionHeader):
5537     _ACTION_TYPES = {}
5538
5539     @staticmethod
5540     def register_action_type(type_, len_):
5541         def _register_action_type(cls):
5542             cls.cls_action_type = type_
5543             cls.cls_action_len = len_
5544             OFPAction._ACTION_TYPES[cls.cls_action_type] = cls
5545             return cls
5546         return _register_action_type
5547
5548     def __init__(self):
5549         cls = self.__class__
5550         super(OFPAction, self).__init__(cls.cls_action_type,
5551                                         cls.cls_action_len)
5552
5553     @classmethod
5554     def parser(cls, buf, offset):
5555         type_, len_ = struct.unpack_from(
5556             ofproto.OFP_ACTION_HEADER_PACK_STR, buf, offset)
5557         cls_ = cls._ACTION_TYPES.get(type_)
5558         assert cls_ is not None
5559         return cls_.parser(buf, offset)
5560
5561
5562 @OFPAction.register_action_type(ofproto.OFPAT_OUTPUT,
5563                                 ofproto.OFP_ACTION_OUTPUT_SIZE)
5564 class OFPActionOutput(OFPAction):
5565     """
5566     Output action
5567
5568     This action indicates output a packet to the switch port.
5569
5570     ================ ======================================================
5571     Attribute        Description
5572     ================ ======================================================
5573     port             Output port
5574     max_len          Max length to send to controller
5575     ================ ======================================================
5576     """
5577
5578     def __init__(self, port, max_len=ofproto.OFPCML_MAX,
5579                  type_=None, len_=None):
5580         super(OFPActionOutput, self).__init__()
5581         self.port = port
5582         self.max_len = max_len
5583
5584     @classmethod
5585     def parser(cls, buf, offset):
5586         type_, len_, port, max_len = struct.unpack_from(
5587             ofproto.OFP_ACTION_OUTPUT_PACK_STR, buf, offset)
5588         return cls(port, max_len)
5589
5590     def serialize(self, buf, offset):
5591         msg_pack_into(ofproto.OFP_ACTION_OUTPUT_PACK_STR, buf,
5592                       offset, self.type, self.len, self.port, self.max_len)
5593
5594
5595 @OFPAction.register_action_type(ofproto.OFPAT_GROUP,
5596                                 ofproto.OFP_ACTION_GROUP_SIZE)
5597 class OFPActionGroup(OFPAction):
5598     """
5599     Group action
5600
5601     This action indicates the group used to process the packet.
5602
5603     ================ ======================================================
5604     Attribute        Description
5605     ================ ======================================================
5606     group_id         Group identifier
5607     ================ ======================================================
5608     """
5609
5610     def __init__(self, group_id=0, type_=None, len_=None):
5611         super(OFPActionGroup, self).__init__()
5612         self.group_id = group_id
5613
5614     @classmethod
5615     def parser(cls, buf, offset):
5616         (type_, len_, group_id) = struct.unpack_from(
5617             ofproto.OFP_ACTION_GROUP_PACK_STR, buf, offset)
5618         return cls(group_id)
5619
5620     def serialize(self, buf, offset):
5621         msg_pack_into(ofproto.OFP_ACTION_GROUP_PACK_STR, buf,
5622                       offset, self.type, self.len, self.group_id)
5623
5624
5625 @OFPAction.register_action_type(ofproto.OFPAT_SET_QUEUE,
5626                                 ofproto.OFP_ACTION_SET_QUEUE_SIZE)
5627 class OFPActionSetQueue(OFPAction):
5628     """
5629     Set queue action
5630
5631     This action sets the queue id that will be used to map a flow to an
5632     already-configured queue on a port.
5633
5634     ================ ======================================================
5635     Attribute        Description
5636     ================ ======================================================
5637     queue_id         Queue ID for the packets
5638     ================ ======================================================
5639     """
5640
5641     def __init__(self, queue_id, type_=None, len_=None):
5642         super(OFPActionSetQueue, self).__init__()
5643         self.queue_id = queue_id
5644
5645     @classmethod
5646     def parser(cls, buf, offset):
5647         (type_, len_, queue_id) = struct.unpack_from(
5648             ofproto.OFP_ACTION_SET_QUEUE_PACK_STR, buf, offset)
5649         return cls(queue_id)
5650
5651     def serialize(self, buf, offset):
5652         msg_pack_into(ofproto.OFP_ACTION_SET_QUEUE_PACK_STR, buf,
5653                       offset, self.type, self.len, self.queue_id)
5654
5655
5656 @OFPAction.register_action_type(ofproto.OFPAT_SET_MPLS_TTL,
5657                                 ofproto.OFP_ACTION_MPLS_TTL_SIZE)
5658 class OFPActionSetMplsTtl(OFPAction):
5659     """
5660     Set MPLS TTL action
5661
5662     This action sets the MPLS TTL.
5663
5664     ================ ======================================================
5665     Attribute        Description
5666     ================ ======================================================
5667     mpls_ttl         MPLS TTL
5668     ================ ======================================================
5669     """
5670
5671     def __init__(self, mpls_ttl, type_=None, len_=None):
5672         super(OFPActionSetMplsTtl, self).__init__()
5673         self.mpls_ttl = mpls_ttl
5674
5675     @classmethod
5676     def parser(cls, buf, offset):
5677         (type_, len_, mpls_ttl) = struct.unpack_from(
5678             ofproto.OFP_ACTION_MPLS_TTL_PACK_STR, buf, offset)
5679         return cls(mpls_ttl)
5680
5681     def serialize(self, buf, offset):
5682         msg_pack_into(ofproto.OFP_ACTION_MPLS_TTL_PACK_STR, buf,
5683                       offset, self.type, self.len, self.mpls_ttl)
5684
5685
5686 @OFPAction.register_action_type(ofproto.OFPAT_DEC_MPLS_TTL,
5687                                 ofproto.OFP_ACTION_HEADER_SIZE)
5688 class OFPActionDecMplsTtl(OFPAction):
5689     """
5690     Decrement MPLS TTL action
5691
5692     This action decrements the MPLS TTL.
5693     """
5694
5695     def __init__(self, type_=None, len_=None):
5696         super(OFPActionDecMplsTtl, self).__init__()
5697
5698     @classmethod
5699     def parser(cls, buf, offset):
5700         (type_, len_) = struct.unpack_from(
5701             ofproto.OFP_ACTION_HEADER_PACK_STR, buf, offset)
5702         return cls()
5703
5704
5705 @OFPAction.register_action_type(ofproto.OFPAT_SET_NW_TTL,
5706                                 ofproto.OFP_ACTION_NW_TTL_SIZE)
5707 class OFPActionSetNwTtl(OFPAction):
5708     """
5709     Set IP TTL action
5710
5711     This action sets the IP TTL.
5712
5713     ================ ======================================================
5714     Attribute        Description
5715     ================ ======================================================
5716     nw_ttl           IP TTL
5717     ================ ======================================================
5718     """
5719
5720     def __init__(self, nw_ttl, type_=None, len_=None):
5721         super(OFPActionSetNwTtl, self).__init__()
5722         self.nw_ttl = nw_ttl
5723
5724     @classmethod
5725     def parser(cls, buf, offset):
5726         (type_, len_, nw_ttl) = struct.unpack_from(
5727             ofproto.OFP_ACTION_NW_TTL_PACK_STR, buf, offset)
5728         return cls(nw_ttl)
5729
5730     def serialize(self, buf, offset):
5731         msg_pack_into(ofproto.OFP_ACTION_NW_TTL_PACK_STR, buf, offset,
5732                       self.type, self.len, self.nw_ttl)
5733
5734
5735 @OFPAction.register_action_type(ofproto.OFPAT_DEC_NW_TTL,
5736                                 ofproto.OFP_ACTION_HEADER_SIZE)
5737 class OFPActionDecNwTtl(OFPAction):
5738     """
5739     Decrement IP TTL action
5740
5741     This action decrements the IP TTL.
5742     """
5743
5744     def __init__(self, type_=None, len_=None):
5745         super(OFPActionDecNwTtl, self).__init__()
5746
5747     @classmethod
5748     def parser(cls, buf, offset):
5749         (type_, len_) = struct.unpack_from(
5750             ofproto.OFP_ACTION_HEADER_PACK_STR, buf, offset)
5751         return cls()
5752
5753
5754 @OFPAction.register_action_type(ofproto.OFPAT_COPY_TTL_OUT,
5755                                 ofproto.OFP_ACTION_HEADER_SIZE)
5756 class OFPActionCopyTtlOut(OFPAction):
5757     """
5758     Copy TTL Out action
5759
5760     This action copies the TTL from the next-to-outermost header with TTL to
5761     the outermost header with TTL.
5762     """
5763
5764     def __init__(self, type_=None, len_=None):
5765         super(OFPActionCopyTtlOut, self).__init__()
5766
5767     @classmethod
5768     def parser(cls, buf, offset):
5769         (type_, len_) = struct.unpack_from(
5770             ofproto.OFP_ACTION_HEADER_PACK_STR, buf, offset)
5771         return cls()
5772
5773
5774 @OFPAction.register_action_type(ofproto.OFPAT_COPY_TTL_IN,
5775                                 ofproto.OFP_ACTION_HEADER_SIZE)
5776 class OFPActionCopyTtlIn(OFPAction):
5777     """
5778     Copy TTL In action
5779
5780     This action copies the TTL from the outermost header with TTL to the
5781     next-to-outermost header with TTL.
5782     """
5783
5784     def __init__(self, type_=None, len_=None):
5785         super(OFPActionCopyTtlIn, self).__init__()
5786
5787     @classmethod
5788     def parser(cls, buf, offset):
5789         (type_, len_) = struct.unpack_from(
5790             ofproto.OFP_ACTION_HEADER_PACK_STR, buf, offset)
5791         return cls()
5792
5793
5794 @OFPAction.register_action_type(ofproto.OFPAT_PUSH_VLAN,
5795                                 ofproto.OFP_ACTION_PUSH_SIZE)
5796 class OFPActionPushVlan(OFPAction):
5797     """
5798     Push VLAN action
5799
5800     This action pushes a new VLAN tag to the packet.
5801
5802     ================ ======================================================
5803     Attribute        Description
5804     ================ ======================================================
5805     ethertype        Ether type.  The default is 802.1Q. (0x8100)
5806     ================ ======================================================
5807     """
5808
5809     def __init__(self, ethertype=ether.ETH_TYPE_8021Q, type_=None, len_=None):
5810         super(OFPActionPushVlan, self).__init__()
5811         self.ethertype = ethertype
5812
5813     @classmethod
5814     def parser(cls, buf, offset):
5815         (type_, len_, ethertype) = struct.unpack_from(
5816             ofproto.OFP_ACTION_PUSH_PACK_STR, buf, offset)
5817         return cls(ethertype)
5818
5819     def serialize(self, buf, offset):
5820         msg_pack_into(ofproto.OFP_ACTION_PUSH_PACK_STR, buf, offset,
5821                       self.type, self.len, self.ethertype)
5822
5823
5824 @OFPAction.register_action_type(ofproto.OFPAT_PUSH_MPLS,
5825                                 ofproto.OFP_ACTION_PUSH_SIZE)
5826 class OFPActionPushMpls(OFPAction):
5827     """
5828     Push MPLS action
5829
5830     This action pushes a new MPLS header to the packet.
5831
5832     ================ ======================================================
5833     Attribute        Description
5834     ================ ======================================================
5835     ethertype        Ether type
5836     ================ ======================================================
5837     """
5838
5839     def __init__(self, ethertype=ether.ETH_TYPE_MPLS, type_=None, len_=None):
5840         super(OFPActionPushMpls, self).__init__()
5841         self.ethertype = ethertype
5842
5843     @classmethod
5844     def parser(cls, buf, offset):
5845         (type_, len_, ethertype) = struct.unpack_from(
5846             ofproto.OFP_ACTION_PUSH_PACK_STR, buf, offset)
5847         return cls(ethertype)
5848
5849     def serialize(self, buf, offset):
5850         msg_pack_into(ofproto.OFP_ACTION_PUSH_PACK_STR, buf, offset,
5851                       self.type, self.len, self.ethertype)
5852
5853
5854 @OFPAction.register_action_type(ofproto.OFPAT_POP_VLAN,
5855                                 ofproto.OFP_ACTION_HEADER_SIZE)
5856 class OFPActionPopVlan(OFPAction):
5857     """
5858     Pop VLAN action
5859
5860     This action pops the outermost VLAN tag from the packet.
5861     """
5862
5863     def __init__(self, type_=None, len_=None):
5864         super(OFPActionPopVlan, self).__init__()
5865
5866     @classmethod
5867     def parser(cls, buf, offset):
5868         (type_, len_) = struct.unpack_from(
5869             ofproto.OFP_ACTION_HEADER_PACK_STR, buf, offset)
5870         return cls()
5871
5872
5873 @OFPAction.register_action_type(ofproto.OFPAT_POP_MPLS,
5874                                 ofproto.OFP_ACTION_POP_MPLS_SIZE)
5875 class OFPActionPopMpls(OFPAction):
5876     """
5877     Pop MPLS action
5878
5879     This action pops the MPLS header from the packet.
5880     """
5881
5882     def __init__(self, ethertype=ether.ETH_TYPE_IP, type_=None, len_=None):
5883         super(OFPActionPopMpls, self).__init__()
5884         self.ethertype = ethertype
5885
5886     @classmethod
5887     def parser(cls, buf, offset):
5888         (type_, len_, ethertype) = struct.unpack_from(
5889             ofproto.OFP_ACTION_POP_MPLS_PACK_STR, buf, offset)
5890         return cls(ethertype)
5891
5892     def serialize(self, buf, offset):
5893         msg_pack_into(ofproto.OFP_ACTION_POP_MPLS_PACK_STR, buf, offset,
5894                       self.type, self.len, self.ethertype)
5895
5896
5897 @OFPAction.register_action_type(ofproto.OFPAT_SET_FIELD,
5898                                 ofproto.OFP_ACTION_SET_FIELD_SIZE)
5899 class OFPActionSetField(OFPAction):
5900     """
5901     Set field action
5902
5903     This action modifies a header field in the packet.
5904
5905     The set of keywords available for this is same as OFPMatch
5906     which including with/without mask.
5907
5908     Example::
5909
5910         set_field = OFPActionSetField(eth_src="00:00:00:00:00:00")
5911         set_field = OFPActionSetField(ipv4_src=("192.168.100.0",
5912                                                 "255.255.255.0"))
5913     """
5914
5915     def __init__(self, field=None, **kwargs):
5916         super(OFPActionSetField, self).__init__()
5917         assert len(kwargs) == 1
5918         key = list(kwargs.keys())[0]
5919         value = kwargs[key]
5920         assert isinstance(key, (str, six.text_type))
5921         self.key = key
5922         self.value = value
5923
5924     @classmethod
5925     def parser(cls, buf, offset):
5926         (type_, len_) = struct.unpack_from(
5927             ofproto.OFP_ACTION_SET_FIELD_PACK_STR, buf, offset)
5928         (n, value, mask, _len) = ofproto.oxm_parse(buf, offset + 4)
5929         k, uv = ofproto.oxm_to_user(n, value, mask)
5930         action = cls(**{k: uv})
5931         action.len = len_
5932         return action
5933
5934     def serialize(self, buf, offset):
5935         n, value, mask = ofproto.oxm_from_user(self.key, self.value)
5936         len_ = ofproto.oxm_serialize(n, value, mask, buf, offset + 4)
5937         self.len = utils.round_up(4 + len_, 8)
5938         msg_pack_into('!HH', buf, offset, self.type, self.len)
5939         pad_len = self.len - (4 + len_)
5940         msg_pack_into("%dx" % pad_len, buf, offset + 4 + len_)
5941
5942     def to_jsondict(self):
5943         return {
5944             self.__class__.__name__: {
5945                 'field': ofproto.oxm_to_jsondict(self.key, self.value),
5946                 "len": self.len,
5947                 "type": self.type
5948             }
5949         }
5950
5951     @classmethod
5952     def from_jsondict(cls, dict_):
5953         k, v = ofproto.oxm_from_jsondict(dict_['field'])
5954         return OFPActionSetField(**{k: v})
5955
5956     def stringify_attrs(self):
5957         yield (self.key, self.value)
5958
5959
5960 @OFPAction.register_action_type(ofproto.OFPAT_PUSH_PBB,
5961                                 ofproto.OFP_ACTION_PUSH_SIZE)
5962 class OFPActionPushPbb(OFPAction):
5963     """
5964     Push PBB action
5965
5966     This action pushes a new PBB header to the packet.
5967
5968     ================ ======================================================
5969     Attribute        Description
5970     ================ ======================================================
5971     ethertype        Ether type
5972     ================ ======================================================
5973     """
5974
5975     def __init__(self, ethertype, type_=None, len_=None):
5976         super(OFPActionPushPbb, self).__init__()
5977         self.ethertype = ethertype
5978
5979     @classmethod
5980     def parser(cls, buf, offset):
5981         (type_, len_, ethertype) = struct.unpack_from(
5982             ofproto.OFP_ACTION_PUSH_PACK_STR, buf, offset)
5983         return cls(ethertype)
5984
5985     def serialize(self, buf, offset):
5986         msg_pack_into(ofproto.OFP_ACTION_PUSH_PACK_STR, buf, offset,
5987                       self.type, self.len, self.ethertype)
5988
5989
5990 @OFPAction.register_action_type(ofproto.OFPAT_POP_PBB,
5991                                 ofproto.OFP_ACTION_HEADER_SIZE)
5992 class OFPActionPopPbb(OFPAction):
5993     """
5994     Pop PBB action
5995
5996     This action pops the outermost PBB service instance header from
5997     the packet.
5998     """
5999
6000     def __init__(self, type_=None, len_=None):
6001         super(OFPActionPopPbb, self).__init__()
6002
6003     @classmethod
6004     def parser(cls, buf, offset):
6005         (type_, len_) = struct.unpack_from(
6006             ofproto.OFP_ACTION_HEADER_PACK_STR, buf, offset)
6007         return cls()
6008
6009
6010 @OFPAction.register_action_type(ofproto.OFPAT_COPY_FIELD,
6011                                 ofproto.OFP_ACTION_COPY_FIELD_SIZE)
6012 class OFPActionCopyField(OFPAction):
6013     """
6014     Copy Field action
6015
6016     This action copy value between header and register.
6017
6018     ================ ======================================================
6019     Attribute        Description
6020     ================ ======================================================
6021     n_bits           Number of bits to copy.
6022     src_offset       Starting bit offset in source.
6023     dst_offset       Starting bit offset in destination.
6024     oxm_ids          List of ``OFPOxmId`` instances.
6025                      The first element of this list, src_oxm_id,
6026                      identifies the field where the value is copied from.
6027                      The second element of this list, dst_oxm_id,
6028                      identifies the field where the value is copied to.
6029                      The default is [].
6030     ================ ======================================================
6031     """
6032
6033     def __init__(self, n_bits=0, src_offset=0, dst_offset=0, oxm_ids=None,
6034                  type_=None, len_=None):
6035         oxm_ids = oxm_ids if oxm_ids else []
6036         super(OFPActionCopyField, self).__init__()
6037         self.n_bits = n_bits
6038         self.src_offset = src_offset
6039         self.dst_offset = dst_offset
6040         assert len(oxm_ids) == 2
6041         self.oxm_ids = []
6042         for i in oxm_ids:
6043             if isinstance(i, OFPOxmId):
6044                 i.hasmask = False  # fixup
6045                 self.oxm_ids.append(i)
6046             elif isinstance(i, six.text_type):
6047                 self.oxm_ids.append(OFPOxmId(i, hasmask=False))
6048             else:
6049                 raise ValueError('invalid value for oxm_ids: %s' % oxm_ids)
6050
6051     @classmethod
6052     def parser(cls, buf, offset):
6053         (type_, len_, n_bits, src_offset, dst_offset) = struct.unpack_from(
6054             ofproto.OFP_ACTION_COPY_FIELD_PACK_STR, buf, offset)
6055         offset += ofproto.OFP_ACTION_COPY_FIELD_SIZE
6056
6057         rest = buf[offset:offset + len_]
6058         oxm_ids = []
6059         while rest:
6060             i, rest = OFPOxmId.parse(rest)
6061             oxm_ids.append(i)
6062         return cls(n_bits, src_offset, dst_offset, oxm_ids, type_, len_)
6063
6064     def serialize(self, buf, offset):
6065         oxm_ids_buf = b''
6066         for i in self.oxm_ids:
6067             oxm_ids_buf += i.serialize()
6068         action_len = ofproto.OFP_ACTION_COPY_FIELD_SIZE + len(oxm_ids_buf)
6069         self.len = utils.round_up(action_len, 8)
6070         pad_len = self.len - action_len
6071         msg_pack_into(ofproto.OFP_ACTION_COPY_FIELD_PACK_STR, buf,
6072                       offset, self.type, self.len,
6073                       self.n_bits, self.src_offset, self.dst_offset)
6074         buf += oxm_ids_buf + b'\x00' * pad_len
6075
6076
6077 @OFPAction.register_action_type(ofproto.OFPAT_METER,
6078                                 ofproto.OFP_ACTION_METER_SIZE)
6079 class OFPActionMeter(OFPAction):
6080     """
6081     Meter action
6082
6083     This action applies meter (rate limiter)
6084
6085     ================ ======================================================
6086     Attribute        Description
6087     ================ ======================================================
6088     meter_id         Meter instance
6089     ================ ======================================================
6090     """
6091
6092     def __init__(self, meter_id,
6093                  type_=None, len_=None):
6094         super(OFPActionMeter, self).__init__()
6095         self.meter_id = meter_id
6096
6097     @classmethod
6098     def parser(cls, buf, offset):
6099         type_, len_, meter_id = struct.unpack_from(
6100             ofproto.OFP_ACTION_METER_PACK_STR, buf, offset)
6101         return cls(meter_id)
6102
6103     def serialize(self, buf, offset):
6104         msg_pack_into(ofproto.OFP_ACTION_METER_PACK_STR, buf,
6105                       offset, self.type, self.len, self.meter_id)
6106
6107
6108 @OFPAction.register_action_type(
6109     ofproto.OFPAT_EXPERIMENTER,
6110     ofproto.OFP_ACTION_EXPERIMENTER_HEADER_SIZE)
6111 class OFPActionExperimenter(OFPAction):
6112     """
6113     Experimenter action
6114
6115     This action is an extensible action for the experimenter.
6116
6117     ================ ======================================================
6118     Attribute        Description
6119     ================ ======================================================
6120     experimenter     Experimenter ID
6121     ================ ======================================================
6122
6123     .. Note::
6124
6125         For the list of the supported Nicira experimenter actions,
6126         please refer to :ref:`ryu.ofproto.nx_actions <nx_actions_structures>`.
6127     """
6128
6129     def __init__(self, experimenter):
6130         super(OFPActionExperimenter, self).__init__()
6131         self.type = ofproto.OFPAT_EXPERIMENTER
6132         self.experimenter = experimenter
6133         self.len = None
6134
6135     @classmethod
6136     def parser(cls, buf, offset):
6137         (type_, len_, experimenter) = struct.unpack_from(
6138             ofproto.OFP_ACTION_EXPERIMENTER_HEADER_PACK_STR, buf, offset)
6139         data = buf[(offset + ofproto.OFP_ACTION_EXPERIMENTER_HEADER_SIZE
6140                     ): offset + len_]
6141         if experimenter == ofproto_common.NX_EXPERIMENTER_ID:
6142             obj = NXAction.parse(data)
6143         else:
6144             obj = OFPActionExperimenterUnknown(experimenter, data)
6145         obj.len = len_
6146         return obj
6147
6148     def serialize(self, buf, offset):
6149         msg_pack_into(ofproto.OFP_ACTION_EXPERIMENTER_HEADER_PACK_STR,
6150                       buf, offset, self.type, self.len, self.experimenter)
6151
6152
6153 class OFPActionExperimenterUnknown(OFPActionExperimenter):
6154     def __init__(self, experimenter, data=None, type_=None, len_=None):
6155         super(OFPActionExperimenterUnknown,
6156               self).__init__(experimenter=experimenter)
6157         self.data = data
6158
6159     def serialize(self, buf, offset):
6160         # fixup
6161         data = self.data
6162         if data is None:
6163             data = bytearray()
6164         self.len = (utils.round_up(len(data), 8) +
6165                     ofproto.OFP_ACTION_EXPERIMENTER_HEADER_SIZE)
6166         super(OFPActionExperimenterUnknown, self).serialize(buf, offset)
6167         msg_pack_into('!%ds' % len(self.data),
6168                       buf,
6169                       offset + ofproto.OFP_ACTION_EXPERIMENTER_HEADER_SIZE,
6170                       self.data)
6171
6172
6173 class OFPGroupProp(OFPPropBase):
6174     _TYPES = {}
6175
6176
6177 @OFPGroupProp.register_type(ofproto.OFPGPT_EXPERIMENTER)
6178 class OFPGroupPropExperimenter(OFPPropCommonExperimenter4ByteData):
6179     pass
6180
6181
6182 @_register_parser
6183 @_set_msg_type(ofproto.OFPT_GROUP_MOD)
6184 class OFPGroupMod(MsgBase):
6185     """
6186     Modify group entry message
6187
6188     The controller sends this message to modify the group table.
6189
6190     ================== ======================================================
6191     Attribute          Description
6192     ================== ======================================================
6193     command            One of the following values.
6194
6195                        | OFPGC_ADD
6196                        | OFPGC_MODIFY
6197                        | OFPGC_DELETE
6198                        | OFPGC_INSERT_BUCKET
6199                        | OFPGC_REMOVE_BUCKET
6200     type               One of the following values.
6201
6202                        | OFPGT_ALL
6203                        | OFPGT_SELECT
6204                        | OFPGT_INDIRECT
6205                        | OFPGT_FF
6206     group_id           Group identifier.
6207     command_bucket_id  Bucket Id used as part of OFPGC_INSERT_BUCKET and
6208                        OFPGC_REMOVE_BUCKET commands execution.
6209     buckets            List of ``OFPBucket`` instance
6210     properties         List of ``OFPGroupProp`` instance
6211     ================== ======================================================
6212
6213     ``type`` attribute corresponds to ``type_`` parameter of __init__.
6214
6215     Example::
6216
6217         def send_group_mod(self, datapath):
6218             ofp = datapath.ofproto
6219             ofp_parser = datapath.ofproto_parser
6220
6221             port = 1
6222             max_len = 2000
6223             actions = [ofp_parser.OFPActionOutput(port, max_len)]
6224
6225             weight = 100
6226             watch_port = 0
6227             watch_group = 0
6228             buckets = [ofp_parser.OFPBucket(weight, watch_port, watch_group,
6229                                             actions)]
6230
6231             group_id = 1
6232             command_bucket_id=1
6233             req = ofp_parser.OFPGroupMod(datapath, ofp.OFPGC_ADD,
6234                                          ofp.OFPGT_SELECT, group_id,
6235                                          command_bucket_id, buckets)
6236             datapath.send_msg(req)
6237     """
6238
6239     def __init__(self, datapath, command=ofproto.OFPGC_ADD,
6240                  type_=ofproto.OFPGT_ALL, group_id=0,
6241                  command_bucket_id=ofproto.OFPG_BUCKET_ALL,
6242                  buckets=None, properties=None, bucket_array_len=None):
6243         buckets = buckets if buckets else []
6244         properties = properties if properties else []
6245         super(OFPGroupMod, self).__init__(datapath)
6246         self.command = command
6247         self.type = type_
6248         self.group_id = group_id
6249         self.command_bucket_id = command_bucket_id
6250         self.buckets = buckets
6251         self.properties = properties
6252
6253     @classmethod
6254     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
6255         msg = super(OFPGroupMod, cls).parser(
6256             datapath, version, msg_type, msg_len, xid, buf)
6257         (msg.command, msg.type, msg.group_id, msg.bucket_array_len,
6258          msg.command_bucket_id) = struct.unpack_from(
6259             ofproto.OFP_GROUP_MOD_PACK_STR, buf, ofproto.OFP_HEADER_SIZE)
6260         offset = ofproto.OFP_GROUP_MOD_SIZE
6261
6262         bucket_buf = buf[offset:offset + msg.bucket_array_len]
6263         msg.buckets = []
6264         while bucket_buf:
6265             bucket = OFPBucket.parser(bucket_buf, 0)
6266             msg.buckets.append(bucket)
6267             bucket_buf = bucket_buf[bucket.len:]
6268         offset += msg.bucket_array_len
6269
6270         rest = buf[offset:offset + msg.msg_len]
6271         while rest:
6272             p, rest = OFPGroupProp.parse(rest)
6273             msg.properties.append(p)
6274
6275         return msg
6276
6277     def _serialize_body(self):
6278         offset = ofproto.OFP_GROUP_MOD_SIZE
6279         self.bucket_array_len = 0
6280         for b in self.buckets:
6281             b.serialize(self.buf, offset)
6282             offset += b.len
6283             self.bucket_array_len += b.len
6284
6285         msg_pack_into(ofproto.OFP_GROUP_MOD_PACK_STR, self.buf,
6286                       ofproto.OFP_HEADER_SIZE,
6287                       self.command, self.type, self.group_id,
6288                       self.bucket_array_len, self.command_bucket_id)
6289
6290         bin_props = bytearray()
6291         for p in self.properties:
6292             bin_props += p.serialize()
6293         self.buf += bin_props
6294
6295
6296 class OFPPortModProp(OFPPropBase):
6297     _TYPES = {}
6298
6299
6300 class OFPPortModPropEthernet(OFPPortModProp):
6301     def __init__(self, type_=None, length=None, advertise=None):
6302         self.type = type_
6303         self.advertise = advertise
6304
6305     def serialize(self):
6306         # fixup
6307         self.length = struct.calcsize(
6308             ofproto.OFP_PORT_MOD_PROP_ETHERNET_PACK_STR)
6309
6310         buf = bytearray()
6311         msg_pack_into(ofproto.OFP_PORT_MOD_PROP_ETHERNET_PACK_STR,
6312                       buf, 0, self.type, self.length, self.advertise)
6313         return buf
6314
6315
6316 class OFPPortModPropOptical(OFPPortModProp):
6317     def __init__(self, type_=None, length=None, configure=None,
6318                  freq_lmda=None, fl_offset=None, grid_span=None,
6319                  tx_pwr=None):
6320         self.type = type_
6321         self.length = length
6322         self.configure = configure
6323         self.freq_lmda = freq_lmda
6324         self.fl_offset = fl_offset
6325         self.grid_span = grid_span
6326         self.tx_pwr = tx_pwr
6327
6328     def serialize(self):
6329         # fixup
6330         self.length = struct.calcsize(
6331             ofproto.OFP_PORT_MOD_PROP_OPTICAL_PACK_STR)
6332
6333         buf = bytearray()
6334         msg_pack_into(ofproto.OFP_PORT_MOD_PROP_OPTICAL_PACK_STR, buf, 0,
6335                       self.type, self.length, self.configure, self.freq_lmda,
6336                       self.fl_offset, self.grid_span, self.tx_pwr)
6337         return buf
6338
6339
6340 class OFPPortModPropExperimenter(OFPPropCommonExperimenter4ByteData):
6341     pass
6342
6343
6344 @_set_msg_type(ofproto.OFPT_PORT_MOD)
6345 class OFPPortMod(MsgBase):
6346     """
6347     Port modification message
6348
6349     The controller sneds this message to modify the behavior of the port.
6350
6351     ================ ======================================================
6352     Attribute        Description
6353     ================ ======================================================
6354     port_no          Port number to modify
6355     hw_addr          The hardware address that must be the same as hw_addr
6356                      of ``OFPPort`` of ``OFPSwitchFeatures``
6357     config           Bitmap of configuration flags.
6358
6359                      | OFPPC_PORT_DOWN
6360                      | OFPPC_NO_RECV
6361                      | OFPPC_NO_FWD
6362                      | OFPPC_NO_PACKET_IN
6363     mask             Bitmap of configuration flags above to be changed
6364     properties       List of ``OFPPortModProp`` subclass instance
6365     ================ ======================================================
6366
6367     Example::
6368
6369         def send_port_mod(self, datapath):
6370             ofp = datapath.ofproto
6371             ofp_parser = datapath.ofproto_parser
6372
6373             port_no = 3
6374             hw_addr = 'fa:c8:e8:76:1d:7e'
6375             config = 0
6376             mask = (ofp.OFPPC_PORT_DOWN | ofp.OFPPC_NO_RECV |
6377                     ofp.OFPPC_NO_FWD | ofp.OFPPC_NO_PACKET_IN)
6378             advertise = (ofp.OFPPF_10MB_HD | ofp.OFPPF_100MB_FD |
6379                          ofp.OFPPF_1GB_FD | ofp.OFPPF_COPPER |
6380                          ofp.OFPPF_AUTONEG | ofp.OFPPF_PAUSE |
6381                          ofp.OFPPF_PAUSE_ASYM)
6382             properties = [ofp_parser.OFPPortModPropEthernet(advertise)]
6383             req = ofp_parser.OFPPortMod(datapath, port_no, hw_addr, config,
6384                                         mask, properties)
6385             datapath.send_msg(req)
6386     """
6387
6388     _TYPE = {
6389         'ascii': [
6390             'hw_addr',
6391         ]
6392     }
6393
6394     def __init__(self, datapath, port_no=0, hw_addr='00:00:00:00:00:00',
6395                  config=0, mask=0, properties=None):
6396         super(OFPPortMod, self).__init__(datapath)
6397         self.port_no = port_no
6398         self.hw_addr = hw_addr
6399         self.config = config
6400         self.mask = mask
6401         self.properties = properties or []
6402
6403     def _serialize_body(self):
6404         bin_props = bytearray()
6405         for p in self.properties:
6406             bin_props += p.serialize()
6407
6408         msg_pack_into(ofproto.OFP_PORT_MOD_PACK_STR, self.buf,
6409                       ofproto.OFP_HEADER_SIZE,
6410                       self.port_no, addrconv.mac.text_to_bin(self.hw_addr),
6411                       self.config,
6412                       self.mask)
6413         self.buf += bin_props
6414
6415
6416 class OFPGroupBucketProp(OFPPropBase):
6417     _TYPES = {}
6418
6419
6420 @OFPGroupBucketProp.register_type(ofproto.OFPGBPT_WEIGHT)
6421 class OFPGroupBucketPropWeight(OFPGroupBucketProp):
6422     def __init__(self, type_=None, length=None, weight=None):
6423         super(OFPGroupBucketPropWeight, self).__init__(type_, length)
6424         self.weight = weight
6425
6426     @classmethod
6427     def parser(cls, buf):
6428         prop = cls()
6429         (prop.type, prop.length, prop.weight) = struct.unpack_from(
6430             ofproto.OFP_GROUP_BUCKET_PROP_WEIGHT_PACK_STR, buf, 0)
6431         return prop
6432
6433     def serialize(self):
6434         # fixup
6435         self.length = ofproto.OFP_GROUP_BUCKET_PROP_WEIGHT_SIZE
6436
6437         buf = bytearray()
6438         msg_pack_into(ofproto.OFP_GROUP_BUCKET_PROP_WEIGHT_PACK_STR, buf, 0,
6439                       self.type, self.length, self.weight)
6440         return buf
6441
6442
6443 @OFPGroupBucketProp.register_type(ofproto.OFPGBPT_WATCH_PORT)
6444 @OFPGroupBucketProp.register_type(ofproto.OFPGBPT_WATCH_GROUP)
6445 class OFPGroupBucketPropWatch(OFPGroupBucketProp):
6446     def __init__(self, type_=None, length=None, watch=None):
6447         super(OFPGroupBucketPropWatch, self).__init__(type_, length)
6448         self.watch = watch
6449
6450     @classmethod
6451     def parser(cls, buf):
6452         prop = cls()
6453         (prop.type, prop.length, prop.watch) = struct.unpack_from(
6454             ofproto.OFP_GROUP_BUCKET_PROP_WATCH_PACK_STR, buf, 0)
6455         return prop
6456
6457     def serialize(self):
6458         # fixup
6459         self.length = ofproto.OFP_GROUP_BUCKET_PROP_WATCH_SIZE
6460
6461         buf = bytearray()
6462         msg_pack_into(ofproto.OFP_GROUP_BUCKET_PROP_WATCH_PACK_STR, buf, 0,
6463                       self.type, self.length, self.watch)
6464         return buf
6465
6466
6467 @OFPGroupBucketProp.register_type(ofproto.OFPGBPT_EXPERIMENTER)
6468 class OFPGroupBucketPropExperimenter(OFPPropCommonExperimenter4ByteData):
6469     pass
6470
6471
6472 class OFPBucket(StringifyMixin):
6473     def __init__(self, bucket_id=0, actions=None, properties=None,
6474                  len_=None, action_array_len=None):
6475         actions = actions if actions else []
6476         properties = properties if properties else []
6477         super(OFPBucket, self).__init__()
6478         self.bucket_id = bucket_id
6479         self.actions = actions
6480         self.properties = properties
6481
6482     @classmethod
6483     def parser(cls, buf, offset):
6484         msg = cls()
6485         (msg.len, msg.action_array_len,
6486          msg.bucket_id) = struct.unpack_from(
6487             ofproto.OFP_BUCKET_PACK_STR, buf, offset)
6488         offset += ofproto.OFP_BUCKET_SIZE
6489
6490         action_buf = buf[offset:offset + msg.action_array_len]
6491         msg.actions = []
6492         while action_buf:
6493             action = OFPAction.parser(action_buf, 0)
6494             msg.actions.append(action)
6495             action_buf = action_buf[action.len:]
6496         offset += msg.action_array_len
6497
6498         rest = buf[offset:offset + msg.len]
6499         msg.properties = []
6500         while rest:
6501             p, rest = OFPGroupBucketProp.parse(rest)
6502             msg.properties.append(p)
6503
6504         return msg
6505
6506     def serialize(self, buf, offset):
6507         action_offset = offset + ofproto.OFP_BUCKET_SIZE
6508         self.action_array_len = 0
6509         for a in self.actions:
6510             a.serialize(buf, action_offset)
6511             action_offset += a.len
6512             self.action_array_len += a.len
6513
6514         bin_props = bytearray()
6515         for p in self.properties:
6516             bin_props += p.serialize()
6517         props_len = len(bin_props)
6518
6519         self.len = utils.round_up(ofproto.OFP_BUCKET_SIZE +
6520                                   self.action_array_len + props_len, 8)
6521         msg_pack_into(ofproto.OFP_BUCKET_PACK_STR, buf, offset,
6522                       self.len, self.action_array_len, self.bucket_id)
6523
6524         buf += bin_props
6525
6526
6527 @_set_msg_type(ofproto.OFPT_ROLE_REQUEST)
6528 class OFPRoleRequest(MsgBase):
6529     """
6530     Role request message
6531
6532     The controller uses this message to change its role.
6533
6534     ================ ======================================================
6535     Attribute        Description
6536     ================ ======================================================
6537     role             One of the following values.
6538
6539                      | OFPCR_ROLE_NOCHANGE
6540                      | OFPCR_ROLE_EQUAL
6541                      | OFPCR_ROLE_MASTER
6542                      | OFPCR_ROLE_SLAVE
6543     short_id         ID number for the controller.
6544                      The default is OFPCID_UNDEFINED.
6545     generation_id    Master Election Generation ID
6546     ================ ======================================================
6547
6548     Example::
6549
6550         def send_role_request(self, datapath):
6551             ofp = datapath.ofproto
6552             ofp_parser = datapath.ofproto_parser
6553
6554             req = ofp_parser.OFPRoleRequest(datapath, ofp.OFPCR_ROLE_EQUAL,
6555                                             ofp.OFPCID_UNDEFINED, 0)
6556             datapath.send_msg(req)
6557     """
6558
6559     def __init__(self, datapath, role=None, short_id=None,
6560                  generation_id=None):
6561         super(OFPRoleRequest, self).__init__(datapath)
6562         self.role = role
6563         self.short_id = short_id
6564         self.generation_id = generation_id
6565
6566     def _serialize_body(self):
6567         assert self.role is not None
6568         assert self.generation_id is not None
6569         if self.short_id is None:
6570             self.short_id = ofproto.OFPCID_UNDEFINED
6571         msg_pack_into(ofproto.OFP_ROLE_REQUEST_PACK_STR,
6572                       self.buf, ofproto.OFP_HEADER_SIZE,
6573                       self.role, self.short_id, self.generation_id)
6574
6575
6576 @_register_parser
6577 @_set_msg_type(ofproto.OFPT_ROLE_REPLY)
6578 class OFPRoleReply(MsgBase):
6579     """
6580     Role reply message
6581
6582     The switch responds with this message to a role request.
6583
6584     ================ ======================================================
6585     Attribute        Description
6586     ================ ======================================================
6587     role             One of the following values.
6588
6589                      | OFPCR_ROLE_NOCHANGE
6590                      | OFPCR_ROLE_EQUAL
6591                      | OFPCR_ROLE_MASTER
6592                      | OFPCR_ROLE_SLAVE
6593     short_id         ID number for the controller.
6594                      The default is OFPCID_UNDEFINED.
6595     generation_id    Master Election Generation ID
6596     ================ ======================================================
6597
6598     Example::
6599
6600         @set_ev_cls(ofp_event.EventOFPRoleReply, MAIN_DISPATCHER)
6601         def role_reply_handler(self, ev):
6602             msg = ev.msg
6603             dp = msg.datapath
6604             ofp = dp.ofproto
6605
6606             if msg.role == ofp.OFPCR_ROLE_NOCHANGE:
6607                 role = 'NOCHANGE'
6608             elif msg.role == ofp.OFPCR_ROLE_EQUAL:
6609                 role = 'EQUAL'
6610             elif msg.role == ofp.OFPCR_ROLE_MASTER:
6611                 role = 'MASTER'
6612             elif msg.role == ofp.OFPCR_ROLE_SLAVE:
6613                 role = 'SLAVE'
6614             else:
6615                 role = 'unknown'
6616
6617             self.logger.debug('OFPRoleReply received: '
6618                               'role=%s short_id=%d, generation_id=%d',
6619                               role, msg.short_id, msg.generation_id)
6620     """
6621
6622     def __init__(self, datapath, role=None, short_id=None,
6623                  generation_id=None):
6624         super(OFPRoleReply, self).__init__(datapath)
6625         self.role = role
6626         self.short_id = short_id
6627         self.generation_id = generation_id
6628
6629     @classmethod
6630     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
6631         msg = super(OFPRoleReply, cls).parser(datapath, version,
6632                                               msg_type, msg_len, xid,
6633                                               buf)
6634         (msg.role, msg.short_id, msg.generation_id) = struct.unpack_from(
6635             ofproto.OFP_ROLE_REQUEST_PACK_STR, msg.buf,
6636             ofproto.OFP_HEADER_SIZE)
6637         return msg
6638
6639
6640 class OFPAsyncConfigProp(OFPPropBase):
6641     _TYPES = {}
6642
6643
6644 @OFPAsyncConfigProp.register_type(ofproto.OFPACPT_PACKET_IN_SLAVE)
6645 @OFPAsyncConfigProp.register_type(ofproto.OFPACPT_PACKET_IN_MASTER)
6646 @OFPAsyncConfigProp.register_type(ofproto.OFPACPT_PORT_STATUS_SLAVE)
6647 @OFPAsyncConfigProp.register_type(ofproto.OFPACPT_PORT_STATUS_MASTER)
6648 @OFPAsyncConfigProp.register_type(ofproto.OFPACPT_FLOW_REMOVED_SLAVE)
6649 @OFPAsyncConfigProp.register_type(ofproto.OFPACPT_FLOW_REMOVED_MASTER)
6650 @OFPAsyncConfigProp.register_type(ofproto.OFPACPT_ROLE_STATUS_SLAVE)
6651 @OFPAsyncConfigProp.register_type(ofproto.OFPACPT_ROLE_STATUS_MASTER)
6652 @OFPAsyncConfigProp.register_type(ofproto.OFPACPT_TABLE_STATUS_SLAVE)
6653 @OFPAsyncConfigProp.register_type(ofproto.OFPACPT_TABLE_STATUS_MASTER)
6654 @OFPAsyncConfigProp.register_type(ofproto.OFPACPT_REQUESTFORWARD_SLAVE)
6655 @OFPAsyncConfigProp.register_type(ofproto.OFPACPT_REQUESTFORWARD_MASTER)
6656 class OFPAsyncConfigPropReasons(OFPAsyncConfigProp):
6657     def __init__(self, type_=None, length=None, mask=None):
6658         self.type = type_
6659         self.length = length
6660         self.mask = mask
6661
6662     @classmethod
6663     def parser(cls, buf):
6664         reasons = cls()
6665         (reasons.type, reasons.length, reasons.mask) = struct.unpack_from(
6666             ofproto.OFP_ASYNC_CONFIG_PROP_REASONS_PACK_STR, buf, 0)
6667         return reasons
6668
6669     def serialize(self):
6670         # fixup
6671         self.length = ofproto.OFP_ASYNC_CONFIG_PROP_REASONS_SIZE
6672
6673         buf = bytearray()
6674         msg_pack_into(ofproto.OFP_ASYNC_CONFIG_PROP_REASONS_PACK_STR, buf, 0,
6675                       self.type, self.length, self.mask)
6676         return buf
6677
6678
6679 @OFPAsyncConfigProp.register_type(ofproto.OFPACPT_EXPERIMENTER_SLAVE)
6680 @OFPAsyncConfigProp.register_type(ofproto.OFPACPT_EXPERIMENTER_MASTER)
6681 class OFPAsyncConfigPropExperimenter(OFPPropCommonExperimenter4ByteData):
6682     pass
6683
6684
6685 @_set_msg_type(ofproto.OFPT_GET_ASYNC_REQUEST)
6686 class OFPGetAsyncRequest(MsgBase):
6687     """
6688     Get asynchronous configuration request message
6689
6690     The controller uses this message to query the asynchronous message.
6691
6692     Example::
6693
6694         def send_get_async_request(self, datapath):
6695             ofp_parser = datapath.ofproto_parser
6696
6697             req = ofp_parser.OFPGetAsyncRequest(datapath)
6698             datapath.send_msg(req)
6699     """
6700
6701     def __init__(self, datapath):
6702         super(OFPGetAsyncRequest, self).__init__(datapath)
6703
6704
6705 @_register_parser
6706 @_set_msg_type(ofproto.OFPT_GET_ASYNC_REPLY)
6707 class OFPGetAsyncReply(MsgBase):
6708     """
6709     Get asynchronous configuration reply message
6710
6711     The switch responds with this message to a get asynchronous configuration
6712     request.
6713
6714     ================== ====================================================
6715     Attribute          Description
6716     ================== ====================================================
6717     properties         List of ``OFPAsyncConfigProp`` subclass instances
6718     ================== ====================================================
6719
6720     Example::
6721
6722         @set_ev_cls(ofp_event.EventOFPGetAsyncReply, MAIN_DISPATCHER)
6723         def get_async_reply_handler(self, ev):
6724             msg = ev.msg
6725
6726             self.logger.debug('OFPGetAsyncReply received: '
6727                               'properties=%s', repr(msg.properties))
6728     """
6729
6730     def __init__(self, datapath, properties=None):
6731         super(OFPGetAsyncReply, self).__init__(datapath)
6732         self.properties = properties
6733
6734     @classmethod
6735     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
6736         msg = super(OFPGetAsyncReply, cls).parser(datapath, version,
6737                                                   msg_type, msg_len,
6738                                                   xid, buf)
6739
6740         msg.properties = []
6741         rest = msg.buf[ofproto.OFP_HEADER_SIZE:]
6742         while rest:
6743             p, rest = OFPAsyncConfigProp.parse(rest)
6744             msg.properties.append(p)
6745
6746         return msg
6747
6748
6749 @_set_msg_type(ofproto.OFPT_SET_ASYNC)
6750 class OFPSetAsync(MsgBase):
6751     """
6752     Set asynchronous configuration message
6753
6754     The controller sends this message to set the asynchronous messages that
6755     it wants to receive on a given OpneFlow channel.
6756
6757     ================== ====================================================
6758     Attribute          Description
6759     ================== ====================================================
6760     properties         List of ``OFPAsyncConfigProp`` subclass instances
6761     ================== ====================================================
6762
6763     Example::
6764
6765         def send_set_async(self, datapath):
6766             ofp = datapath.ofproto
6767             ofp_parser = datapath.ofproto_parser
6768
6769             properties = [
6770                 ofp_parser.OFPAsyncConfigPropReasons(
6771                     ofp.OFPACPT_PACKET_IN_SLAVE, 8,
6772                     (1 << ofp.OFPR_APPLY_ACTION
6773                      | 1 << ofp.OFPR_INVALID_TTL))]
6774             req = ofp_parser.OFPSetAsync(datapath, properties)
6775             datapath.send_msg(req)
6776     """
6777
6778     def __init__(self, datapath, properties=None):
6779         super(OFPSetAsync, self).__init__(datapath)
6780         self.properties = properties
6781
6782     def _serialize_body(self):
6783         bin_props = bytearray()
6784         for p in self.properties:
6785             bin_props += p.serialize()
6786
6787         self.buf += bin_props
6788
6789
6790 @_register_parser
6791 @_set_msg_type(ofproto.OFPT_BUNDLE_CONTROL)
6792 class OFPBundleCtrlMsg(MsgBase):
6793     """
6794     Bundle control message
6795
6796     The controller uses this message to create, destroy and commit bundles
6797
6798     ================ ======================================================
6799     Attribute        Description
6800     ================ ======================================================
6801     bundle_id        Id of the bundle
6802     type             One of the following values.
6803
6804                      | OFPBCT_OPEN_REQUEST
6805                      | OFPBCT_OPEN_REPLY
6806                      | OFPBCT_CLOSE_REQUEST
6807                      | OFPBCT_CLOSE_REPLY
6808                      | OFPBCT_COMMIT_REQUEST
6809                      | OFPBCT_COMMIT_REPLY
6810                      | OFPBCT_DISCARD_REQUEST
6811                      | OFPBCT_DISCARD_REPLY
6812     flags            Bitmap of the following flags.
6813
6814                      | OFPBF_ATOMIC
6815                      | OFPBF_ORDERED
6816     properties       List of ``OFPBundleProp`` subclass instance
6817     ================ ======================================================
6818
6819     Example::
6820
6821         def send_bundle_control(self, datapath):
6822             ofp = datapath.ofproto
6823             ofp_parser = datapath.ofproto_parser
6824
6825             req = ofp_parser.OFPBundleCtrlMsg(datapath, 7,
6826                                               ofp.OFPBCT_OPEN_REQUEST,
6827                                               ofp.OFPBF_ATOMIC, [])
6828             datapath.send_msg(req)
6829     """
6830
6831     def __init__(self, datapath, bundle_id=None, type_=None, flags=None,
6832                  properties=None):
6833         super(OFPBundleCtrlMsg, self).__init__(datapath)
6834         self.bundle_id = bundle_id
6835         self.type = type_
6836         self.flags = flags
6837         self.properties = properties
6838
6839     def _serialize_body(self):
6840         bin_props = bytearray()
6841         for p in self.properties:
6842             bin_props += p.serialize()
6843
6844         msg_pack_into(ofproto.OFP_BUNDLE_CTRL_MSG_PACK_STR,
6845                       self.buf, ofproto.OFP_HEADER_SIZE, self.bundle_id,
6846                       self.type, self.flags)
6847         self.buf += bin_props
6848
6849     @classmethod
6850     def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
6851         msg = super(OFPBundleCtrlMsg, cls).parser(datapath, version,
6852                                                   msg_type, msg_len,
6853                                                   xid, buf)
6854         (bundle_id, type_, flags) = struct.unpack_from(
6855             ofproto.OFP_BUNDLE_CTRL_MSG_PACK_STR, buf,
6856             ofproto.OFP_HEADER_SIZE)
6857         msg.bundle_id = bundle_id
6858         msg.type = type_
6859         msg.flags = flags
6860         msg.properties = []
6861         rest = msg.buf[ofproto.OFP_BUNDLE_CTRL_MSG_SIZE:]
6862         while rest:
6863             p, rest = OFPBundleProp.parse(rest)
6864             msg.properties.append(p)
6865
6866         return msg
6867
6868
6869 @_set_msg_type(ofproto.OFPT_BUNDLE_ADD_MESSAGE)
6870 class OFPBundleAddMsg(MsgInMsgBase):
6871     """
6872     Bundle add message
6873
6874     The controller uses this message to add a message to a bundle
6875
6876     ================ ======================================================
6877     Attribute        Description
6878     ================ ======================================================
6879     bundle_id        Id of the bundle
6880     flags            Bitmap of the following flags.
6881
6882                      | OFPBF_ATOMIC
6883                      | OFPBF_ORDERED
6884     message          ``MsgBase`` subclass instance
6885     properties       List of ``OFPBundleProp`` subclass instance
6886     ================ ======================================================
6887
6888     Example::
6889
6890         def send_bundle_add_message(self, datapath):
6891             ofp = datapath.ofproto
6892             ofp_parser = datapath.ofproto_parser
6893
6894             msg = ofp_parser.OFPRoleRequest(datapath, ofp.OFPCR_ROLE_EQUAL, 0)
6895
6896             req = ofp_parser.OFPBundleAddMsg(datapath, 7, ofp.OFPBF_ATOMIC,
6897                                              msg, [])
6898             datapath.send_msg(req)
6899     """
6900
6901     def __init__(self, datapath, bundle_id, flags, message, properties):
6902         super(OFPBundleAddMsg, self).__init__(datapath)
6903         self.bundle_id = bundle_id
6904         self.flags = flags
6905         self.message = message
6906         self.properties = properties
6907
6908     def _serialize_body(self):
6909         # The xid of the inner message must be the same as
6910         # that of the outer message (OF1.4.0 7.3.9.2)
6911         if self.message.xid != self.xid:
6912             self.message.set_xid(self.xid)
6913
6914         # Message
6915         self.message.serialize()
6916         tail_buf = self.message.buf
6917
6918         # Pad
6919         if len(self.properties) > 0:
6920             message_len = len(tail_buf)
6921             pad_len = utils.round_up(message_len, 8) - message_len
6922             msg_pack_into("%dx" % pad_len, tail_buf, message_len)
6923
6924         # Properties
6925         for p in self.properties:
6926             tail_buf += p.serialize()
6927
6928         # Head
6929         msg_pack_into(ofproto.OFP_BUNDLE_ADD_MSG_0_PACK_STR,
6930                       self.buf, ofproto.OFP_HEADER_SIZE, self.bundle_id,
6931                       self.flags)
6932
6933         # Finish
6934         self.buf += tail_buf
6935
6936
6937 nx_actions.generate(
6938     'ryu.ofproto.ofproto_v1_5',
6939     'ryu.ofproto.ofproto_v1_5_parser'
6940 )