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