backing up
[vsorcdistro/.git] / ryu / build / lib.linux-armv7l-2.7 / ryu / lib / packet / cfm.py
1 # Copyright (C) 2013 Nippon Telegraph and Telephone Corporation.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #    http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12 # implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 import abc
17 import six
18 import struct
19 from ryu.lib import addrconv
20 from ryu.lib import stringify
21 from ryu.lib.packet import packet_base
22
23 # IEEE 802.1ag OpCode
24 CFM_CC_MESSAGE = 0x01
25 CFM_LOOPBACK_REPLY = 0x02
26 CFM_LOOPBACK_MESSAGE = 0x03
27 CFM_LINK_TRACE_REPLY = 0x04
28 CFM_LINK_TRACE_MESSAGE = 0x05
29
30 # IEEE 802.1ag TLV type
31 CFM_END_TLV = 0x00
32 CFM_SENDER_ID_TLV = 0x01
33 CFM_PORT_STATUS_TLV = 0x02
34 CFM_DATA_TLV = 0x03
35 CFM_INTERFACE_STATUS_TLV = 0x04
36 CFM_REPLY_INGRESS_TLV = 0x05
37 CFM_REPLY_EGRESS_TLV = 0x06
38 CFM_LTM_EGRESS_IDENTIFIER_TLV = 0x07
39 CFM_LTR_EGRESS_IDENTIFIER_TLV = 0x08
40 CFM_ORGANIZATION_SPECIFIC_TLV = 0x1f
41
42 # IEEE 802.1ag CFM version
43 CFM_VERSION = 0
44
45
46 class cfm(packet_base.PacketBase):
47     """CFM (Connectivity Fault Management) Protocol header class.
48
49     http://standards.ieee.org/getieee802/download/802.1ag-2007.pdf
50
51     OpCode Field range assignments
52
53     +---------------+--------------------------------------------------+
54     | OpCode range  | CFM PDU or organization                          |
55     +===============+==================================================+
56     | 0             | Reserved for IEEE 802.1                          |
57     +---------------+--------------------------------------------------+
58     | 1             | Continuity Check Message (CCM)                   |
59     +---------------+--------------------------------------------------+
60     | 2             | Loopback Reply (LBR)                             |
61     +---------------+--------------------------------------------------+
62     | 3             | Loopback Message (LBM)                           |
63     +---------------+--------------------------------------------------+
64     | 4             | Linktrace Reply (LTR)                            |
65     +---------------+--------------------------------------------------+
66     | 5             | Linktrace Message (LTM)                          |
67     +---------------+--------------------------------------------------+
68     | 06 - 31       | Reserved for IEEE 802.1                          |
69     +---------------+--------------------------------------------------+
70     | 32 - 63       | Defined by ITU-T Y.1731                          |
71     +---------------+--------------------------------------------------+
72     | 64 - 255      | Reserved for IEEE 802.1.                         |
73     +---------------+--------------------------------------------------+
74
75     An instance has the following attributes at least.
76     Most of them are same to the on-wire counterparts but in host byte order.
77     __init__ takes the corresponding args in this order.
78
79     .. tabularcolumns:: |l|L|
80
81     ============== ========================================
82     Attribute      Description
83     ============== ========================================
84     op             CFM PDU
85     ============== ========================================
86
87     """
88     _PACK_STR = '!B'
89     _MIN_LEN = struct.calcsize(_PACK_STR)
90     _CFM_OPCODE = {}
91     _TYPE = {
92         'ascii': [
93             'ltm_orig_addr', 'ltm_targ_addr'
94         ]
95     }
96
97     @staticmethod
98     def register_cfm_opcode(type_):
99         def _register_cfm_opcode(cls):
100             cfm._CFM_OPCODE[type_] = cls
101             return cls
102         return _register_cfm_opcode
103
104     def __init__(self, op=None):
105         super(cfm, self).__init__()
106         assert isinstance(op, operation)
107         self.op = op
108
109     @classmethod
110     def parser(cls, buf):
111         (opcode, ) = struct.unpack_from(cls._PACK_STR, buf, cls._MIN_LEN)
112         cls_ = cls._CFM_OPCODE.get(opcode)
113         op = cls_.parser(buf)
114         instance = cls(op)
115         rest = buf[len(instance):]
116         return instance, None, rest
117
118     def serialize(self, payload, prev):
119         buf = self.op.serialize()
120         return buf
121
122     def __len__(self):
123         return len(self.op)
124
125
126 @six.add_metaclass(abc.ABCMeta)
127 class operation(stringify.StringifyMixin):
128
129     _TLV_TYPES = {}
130     _END_TLV_LEN = 1
131
132     @staticmethod
133     def register_tlv_types(type_):
134         def _register_tlv_types(cls):
135             operation._TLV_TYPES[type_] = cls
136             return cls
137         return _register_tlv_types
138
139     def __init__(self, md_lv, version, tlvs):
140         self.md_lv = md_lv
141         self.version = version
142         tlvs = tlvs or []
143         assert isinstance(tlvs, list)
144         for tlv_ in tlvs:
145             assert isinstance(tlv_, tlv)
146         self.tlvs = tlvs
147
148     @classmethod
149     @abc.abstractmethod
150     def parser(cls, buf):
151         pass
152
153     @abc.abstractmethod
154     def serialize(self):
155         pass
156
157     @abc.abstractmethod
158     def __len__(self):
159         pass
160
161     @classmethod
162     def _parser_tlvs(cls, buf):
163         offset = 0
164         tlvs = []
165         while True:
166             (type_, ) = struct.unpack_from('!B', buf, offset)
167             cls_ = cls._TLV_TYPES.get(type_)
168             if not cls_:
169                 assert type_ is CFM_END_TLV
170                 break
171             tlv_ = cls_.parser(buf[offset:])
172             tlvs.append(tlv_)
173             offset += len(tlv_)
174         return tlvs
175
176     @staticmethod
177     def _serialize_tlvs(tlvs):
178         buf = bytearray()
179         for tlv_ in tlvs:
180             buf.extend(tlv_.serialize())
181         return buf
182
183     def _calc_len(self, len_):
184         for tlv_ in self.tlvs:
185             len_ += len(tlv_)
186         len_ += self._END_TLV_LEN
187         return len_
188
189
190 @cfm.register_cfm_opcode(CFM_CC_MESSAGE)
191 class cc_message(operation):
192
193     """CFM (IEEE Std 802.1ag-2007) Continuity Check Message (CCM)
194     encoder/decoder class.
195
196     This is used with ryu.lib.packet.cfm.cfm.
197
198     An instance has the following attributes at least.
199     Most of them are same to the on-wire counterparts but in host byte order.
200     __init__ takes the corresponding args in this order.
201
202     .. tabularcolumns:: |l|L|
203
204     ==================== =======================================
205     Attribute            Description
206     ==================== =======================================
207     md_lv                Maintenance Domain Level.
208     version              The protocol version number.
209     rdi                  RDI bit.
210     interval             CCM Interval.The default is 4 (1 frame/s)
211     seq_num              Sequence Number.
212     mep_id               Maintenance association End Point Identifier.
213     md_name_format       Maintenance Domain Name Format.
214                          The default is 4 (Character string)
215     md_name_length       Maintenance Domain Name Length.
216                          (0 means automatically-calculate
217                          when encoding.)
218     md_name              Maintenance Domain Name.
219     short_ma_name_format Short MA Name Format.
220                          The default is 2 (Character string)
221     short_ma_name_length Short MA Name Format Length.
222                          (0 means automatically-calculate
223                          when encoding.)
224     short_ma_name        Short MA Name.
225     tlvs                 TLVs.
226     ==================== =======================================
227     """
228
229     _PACK_STR = '!4BIHB'
230
231     _MIN_LEN = struct.calcsize(_PACK_STR)
232     _TLV_OFFSET = 70
233     _MD_NAME_FORMAT_LEN = 1
234     _MD_NAME_LENGTH_LEN = 1
235     _SHORT_MA_NAME_FORMAT_LEN = 1
236     _SHORT_MA_NAME_LENGTH_LEN = 1
237     _MA_ID_LEN = 64
238
239     # Maintenance Domain Name Format
240     _MD_FMT_NO_MD_NAME_PRESENT = 1
241     _MD_FMT_DOMAIN_NAME_BASED_STRING = 2
242     _MD_FMT_MAC_ADDRESS_TWO_OCTET_INTEGER = 3
243     _MD_FMT_CHARACTER_STRING = 4
244
245     # Short MA Name Format
246     _SHORT_MA_FMT_PRIMARY_VID = 1
247     _SHORT_MA_FMT_CHARACTER_STRING = 2
248     _SHORT_MA_FMT_TWO_OCTET_INTEGER = 3
249     _SHORT_MA_FMT_RFC_2685_VPN_ID = 4
250
251     # CCM Transmission Interval
252     _INTERVAL_300_HZ = 1
253     _INTERVAL_10_MSEC = 2
254     _INTERVAL_100_MSEC = 3
255     _INTERVAL_1_SEC = 4
256     _INTERVAL_10_SEC = 5
257     _INTERVAL_1_MIN = 6
258     _INTERVAL_10_MIN = 6
259
260     def __init__(self, md_lv=0, version=CFM_VERSION,
261                  rdi=0, interval=_INTERVAL_1_SEC, seq_num=0, mep_id=1,
262                  md_name_format=_MD_FMT_CHARACTER_STRING,
263                  md_name_length=0, md_name=b"0",
264                  short_ma_name_format=_SHORT_MA_FMT_CHARACTER_STRING,
265                  short_ma_name_length=0, short_ma_name=b"1",
266                  tlvs=None):
267         super(cc_message, self).__init__(md_lv, version, tlvs)
268         self._opcode = CFM_CC_MESSAGE
269         assert rdi in [0, 1]
270         self.rdi = rdi
271         assert interval is not 0
272         self.interval = interval
273         self.seq_num = seq_num
274         assert 1 <= mep_id <= 8191
275         self.mep_id = mep_id
276         self.md_name_format = md_name_format
277         self.md_name_length = md_name_length
278         self.md_name = md_name
279         self.short_ma_name_format = short_ma_name_format
280         self.short_ma_name_length = short_ma_name_length
281         self.short_ma_name = short_ma_name
282
283     @classmethod
284     def parser(cls, buf):
285         (md_lv_version, opcode, flags, tlv_offset, seq_num, mep_id,
286          md_name_format) = struct.unpack_from(cls._PACK_STR, buf)
287         md_name_length = 0
288         md_name = b""
289         md_lv = int(md_lv_version >> 5)
290         version = int(md_lv_version & 0x1f)
291         rdi = int(flags >> 7)
292         interval = int(flags & 0x07)
293         offset = cls._MIN_LEN
294         # parse md_name
295         if md_name_format != cls._MD_FMT_NO_MD_NAME_PRESENT:
296             (md_name_length, ) = struct.unpack_from("!B", buf, offset)
297             offset += cls._MD_NAME_LENGTH_LEN
298             form = "%dB" % md_name_length
299             md_name = struct.unpack_from(form, buf, offset)
300             offset += md_name_length
301         # parse short_ma_name
302         (short_ma_name_format,
303          short_ma_name_length) = struct.unpack_from("!2B", buf, offset)
304         offset += (cls._SHORT_MA_NAME_FORMAT_LEN +
305                    cls._SHORT_MA_NAME_LENGTH_LEN)
306         form = "%dB" % short_ma_name_length
307         short_ma_name = struct.unpack_from(form, buf, offset)
308         offset = cls._MIN_LEN + (cls._MA_ID_LEN - cls._MD_NAME_FORMAT_LEN)
309         tlvs = cls._parser_tlvs(buf[offset:])
310         # ascii to text
311         if md_name_format == cls._MD_FMT_DOMAIN_NAME_BASED_STRING or \
312            md_name_format == cls._MD_FMT_CHARACTER_STRING:
313             md_name = b"".join(map(six.int2byte, md_name))
314         if short_ma_name_format == cls._SHORT_MA_FMT_CHARACTER_STRING:
315             short_ma_name = b"".join(map(six.int2byte, short_ma_name))
316         return cls(md_lv, version, rdi, interval, seq_num, mep_id,
317                    md_name_format, md_name_length,
318                    md_name,
319                    short_ma_name_format, short_ma_name_length,
320                    short_ma_name,
321                    tlvs)
322
323     def serialize(self):
324         buf = struct.pack(self._PACK_STR,
325                           (self.md_lv << 5) | self.version,
326                           self._opcode,
327                           (self.rdi << 7) | self.interval,
328                           self._TLV_OFFSET,
329                           self.seq_num, self.mep_id, self.md_name_format)
330         buf = bytearray(buf)
331         # Maintenance Domain Name
332         if self.md_name_format != self._MD_FMT_NO_MD_NAME_PRESENT:
333             if self.md_name_length == 0:
334                 self.md_name_length = len(self.md_name)
335             buf.extend(struct.pack('!B%ds' % self.md_name_length,
336                                    self.md_name_length, self.md_name))
337         # Short MA Name
338         if self.short_ma_name_length == 0:
339             self.short_ma_name_length = len(self.short_ma_name)
340         buf.extend(struct.pack('!2B%ds' % self.short_ma_name_length,
341                                self.short_ma_name_format,
342                                self.short_ma_name_length,
343                                self.short_ma_name
344                                ))
345         # 0 pad
346         maid_length = (self._MD_NAME_FORMAT_LEN +
347                        self._SHORT_MA_NAME_FORMAT_LEN +
348                        self._SHORT_MA_NAME_LENGTH_LEN +
349                        self.short_ma_name_length)
350         if self.md_name_format != self._MD_FMT_NO_MD_NAME_PRESENT:
351             maid_length += self._MD_NAME_LENGTH_LEN + self.md_name_length
352         buf.extend(bytearray(self._MA_ID_LEN - maid_length))
353         # tlvs
354         if self.tlvs:
355             buf.extend(self._serialize_tlvs(self.tlvs))
356         buf.extend(struct.pack("!B", CFM_END_TLV))
357         return buf
358
359     def __len__(self):
360         return self._calc_len(
361             (self._MIN_LEN - self._MD_NAME_FORMAT_LEN) + self._MA_ID_LEN)
362
363
364 class loopback(operation):
365
366     _PACK_STR = '!4BI'
367     _MIN_LEN = struct.calcsize(_PACK_STR)
368     _TLV_OFFSET = 4
369
370     @abc.abstractmethod
371     def __init__(self, md_lv, version, transaction_id, tlvs):
372         super(loopback, self).__init__(md_lv, version, tlvs)
373         self._flags = 0
374         self.transaction_id = transaction_id
375
376     @classmethod
377     def parser(cls, buf):
378         (md_lv_version, opcode, flags, tlv_offset,
379          transaction_id) = struct.unpack_from(cls._PACK_STR, buf)
380         md_lv = int(md_lv_version >> 5)
381         version = int(md_lv_version & 0x1f)
382         tlvs = cls._parser_tlvs(buf[cls._MIN_LEN:])
383         return cls(md_lv, version, transaction_id, tlvs)
384
385     def serialize(self):
386         buf = struct.pack(self._PACK_STR,
387                           (self.md_lv << 5) | self.version,
388                           self._opcode,
389                           self._flags,
390                           self._TLV_OFFSET,
391                           self.transaction_id,
392                           )
393         buf = bytearray(buf)
394         # tlvs
395         if self.tlvs:
396             buf.extend(self._serialize_tlvs(self.tlvs))
397         buf.extend(struct.pack("!B", CFM_END_TLV))
398
399         return buf
400
401     def __len__(self):
402         return self._calc_len(self._MIN_LEN)
403
404
405 @cfm.register_cfm_opcode(CFM_LOOPBACK_MESSAGE)
406 class loopback_message(loopback):
407
408     """CFM (IEEE Std 802.1ag-2007) Loopback Message (LBM) encoder/decoder class.
409
410     This is used with ryu.lib.packet.cfm.cfm.
411
412     An instance has the following attributes at least.
413     Most of them are same to the on-wire counterparts but in host byte order.
414     __init__ takes the corresponding args in this order.
415
416     .. tabularcolumns:: |l|L|
417
418     ================= =======================================
419     Attribute         Description
420     ================= =======================================
421     md_lv             Maintenance Domain Level.
422     version           The protocol version number.
423     transaction_id    Loopback Transaction Identifier.
424     tlvs              TLVs.
425     ================= =======================================
426     """
427
428     def __init__(self, md_lv=0, version=CFM_VERSION,
429                  transaction_id=0,
430                  tlvs=None,
431                  ):
432         super(loopback_message, self).__init__(md_lv, version,
433                                                transaction_id,
434                                                tlvs)
435         self._opcode = CFM_LOOPBACK_MESSAGE
436
437
438 @cfm.register_cfm_opcode(CFM_LOOPBACK_REPLY)
439 class loopback_reply(loopback):
440
441     """CFM (IEEE Std 802.1ag-2007) Loopback Reply (LBR) encoder/decoder class.
442
443     This is used with ryu.lib.packet.cfm.cfm.
444
445     An instance has the following attributes at least.
446     Most of them are same to the on-wire counterparts but in host byte order.
447     __init__ takes the corresponding args in this order.
448
449     .. tabularcolumns:: |l|L|
450
451     ==================== =======================================
452     Attribute            Description
453     ==================== =======================================
454     md_lv                Maintenance Domain Level.
455     version              The protocol version number.
456     transaction_id       Loopback Transaction Identifier.
457     tlvs                 TLVs.
458     ==================== =======================================
459     """
460
461     def __init__(self, md_lv=0, version=CFM_VERSION,
462                  transaction_id=0,
463                  tlvs=None,
464                  ):
465         super(loopback_reply, self).__init__(md_lv, version,
466                                              transaction_id,
467                                              tlvs)
468         self._opcode = CFM_LOOPBACK_REPLY
469
470
471 class link_trace(operation):
472
473     @abc.abstractmethod
474     def __init__(self, md_lv, version, use_fdb_only,
475                  transaction_id, ttl, tlvs):
476         super(link_trace, self).__init__(md_lv, version, tlvs)
477         assert use_fdb_only in [0, 1]
478         self.use_fdb_only = use_fdb_only
479         self.transaction_id = transaction_id
480         self.ttl = ttl
481
482     @classmethod
483     @abc.abstractmethod
484     def parser(cls, buf):
485         pass
486
487     @abc.abstractmethod
488     def serialize(self):
489         pass
490
491     def __len__(self):
492         return self._calc_len(self._MIN_LEN)
493
494
495 @cfm.register_cfm_opcode(CFM_LINK_TRACE_MESSAGE)
496 class link_trace_message(link_trace):
497
498     """CFM (IEEE Std 802.1ag-2007) Linktrace Message (LTM)
499     encoder/decoder class.
500
501     This is used with ryu.lib.packet.cfm.cfm.
502
503     An instance has the following attributes at least.
504     Most of them are same to the on-wire counterparts but in host byte order.
505     __init__ takes the corresponding args in this order.
506
507     .. tabularcolumns:: |l|L|
508
509     ==================== =======================================
510     Attribute            Description
511     ==================== =======================================
512     md_lv                Maintenance Domain Level.
513     version              The protocol version number.
514     use_fdb_only         UseFDBonly bit.
515     transaction_id       LTM Transaction Identifier.
516     ttl                  LTM TTL.
517     ltm_orig_addr        Original MAC Address.
518     ltm_targ_addr        Target MAC Address.
519     tlvs                 TLVs.
520     ==================== =======================================
521     """
522
523     _PACK_STR = '!4BIB6s6s'
524     _ALL_PACK_LEN = struct.calcsize(_PACK_STR)
525     _MIN_LEN = _ALL_PACK_LEN
526     _TLV_OFFSET = 17
527     _TYPE = {
528         'ascii': [
529             'ltm_orig_addr', 'ltm_targ_addr'
530         ]
531     }
532
533     def __init__(self, md_lv=0, version=CFM_VERSION,
534                  use_fdb_only=1,
535                  transaction_id=0,
536                  ttl=64,
537                  ltm_orig_addr='00:00:00:00:00:00',
538                  ltm_targ_addr='00:00:00:00:00:00',
539                  tlvs=None
540                  ):
541         super(link_trace_message, self).__init__(md_lv, version,
542                                                  use_fdb_only,
543                                                  transaction_id,
544                                                  ttl,
545                                                  tlvs)
546         self._opcode = CFM_LINK_TRACE_MESSAGE
547         self.ltm_orig_addr = ltm_orig_addr
548         self.ltm_targ_addr = ltm_targ_addr
549
550     @classmethod
551     def parser(cls, buf):
552         (md_lv_version, opcode, flags, tlv_offset, transaction_id, ttl,
553          ltm_orig_addr, ltm_targ_addr) = struct.unpack_from(cls._PACK_STR, buf)
554         md_lv = int(md_lv_version >> 5)
555         version = int(md_lv_version & 0x1f)
556         use_fdb_only = int(flags >> 7)
557         tlvs = cls._parser_tlvs(buf[cls._MIN_LEN:])
558         return cls(md_lv, version, use_fdb_only,
559                    transaction_id, ttl,
560                    addrconv.mac.bin_to_text(ltm_orig_addr),
561                    addrconv.mac.bin_to_text(ltm_targ_addr),
562                    tlvs)
563
564     def serialize(self):
565         buf = struct.pack(self._PACK_STR,
566                           (self.md_lv << 5) | self.version,
567                           self._opcode,
568                           self.use_fdb_only << 7,
569                           self._TLV_OFFSET,
570                           self.transaction_id,
571                           self.ttl,
572                           addrconv.mac.text_to_bin(self.ltm_orig_addr),
573                           addrconv.mac.text_to_bin(self.ltm_targ_addr),
574                           )
575         buf = bytearray(buf)
576         if self.tlvs:
577             buf.extend(self._serialize_tlvs(self.tlvs))
578         buf.extend(struct.pack("!B", CFM_END_TLV))
579         return buf
580
581
582 @cfm.register_cfm_opcode(CFM_LINK_TRACE_REPLY)
583 class link_trace_reply(link_trace):
584
585     """CFM (IEEE Std 802.1ag-2007) Linktrace Reply (LTR) encoder/decoder class.
586
587     This is used with ryu.lib.packet.cfm.cfm.
588
589     An instance has the following attributes at least.
590     Most of them are same to the on-wire counterparts but in host byte order.
591     __init__ takes the corresponding args in this order.
592
593     .. tabularcolumns:: |l|L|
594
595     ==================== =======================================
596     Attribute            Description
597     ==================== =======================================
598     version              The protocol version number.
599     use_fdb_only         UseFDBonly bit.
600     fwd_yes              FwdYes bit.
601     terminal_mep         TerminalMep bit.
602     transaction_id       LTR Transaction Identifier.
603     ttl                  Reply TTL.
604     relay_action         Relay Action.The default is 1 (RlyHit)
605     tlvs                 TLVs.
606     ==================== =======================================
607     """
608     _PACK_STR = '!4BIBB'
609     _ALL_PACK_LEN = struct.calcsize(_PACK_STR)
610     _MIN_LEN = _ALL_PACK_LEN
611     _TLV_OFFSET = 6
612
613     # Relay Action field values
614     _RLY_HIT = 1
615     _RLY_FDB = 2
616     _RLY_MPDB = 3
617
618     def __init__(self, md_lv=0, version=CFM_VERSION, use_fdb_only=1,
619                  fwd_yes=0, terminal_mep=1, transaction_id=0,
620                  ttl=64, relay_action=_RLY_HIT, tlvs=None
621                  ):
622         super(link_trace_reply, self).__init__(md_lv, version,
623                                                use_fdb_only,
624                                                transaction_id,
625                                                ttl,
626                                                tlvs)
627         self._opcode = CFM_LINK_TRACE_REPLY
628         assert fwd_yes in [0, 1]
629         self.fwd_yes = fwd_yes
630         assert terminal_mep in [0, 1]
631         self.terminal_mep = terminal_mep
632         assert relay_action in [self._RLY_HIT, self._RLY_FDB, self._RLY_MPDB]
633         self.relay_action = relay_action
634
635     @classmethod
636     def parser(cls, buf):
637         (md_lv_version, opcode, flags, tlv_offset, transaction_id, ttl,
638          relay_action) = struct.unpack_from(cls._PACK_STR, buf)
639         md_lv = int(md_lv_version >> 5)
640         version = int(md_lv_version & 0x1f)
641         use_fdb_only = int(flags >> 7)
642         fwd_yes = int(flags >> 6 & 0x01)
643         terminal_mep = int(flags >> 5 & 0x01)
644         tlvs = cls._parser_tlvs(buf[cls._MIN_LEN:])
645         return cls(md_lv, version, use_fdb_only, fwd_yes, terminal_mep,
646                    transaction_id, ttl, relay_action, tlvs)
647
648     def serialize(self):
649         buf = struct.pack(self._PACK_STR,
650                           (self.md_lv << 5) | self.version,
651                           self._opcode,
652                           (self.use_fdb_only << 7) |
653                           (self.fwd_yes << 6) |
654                           (self.terminal_mep << 5),
655                           self._TLV_OFFSET,
656                           self.transaction_id,
657                           self.ttl,
658                           self.relay_action,
659                           )
660         buf = bytearray(buf)
661         if self.tlvs:
662             buf.extend(self._serialize_tlvs(self.tlvs))
663         buf.extend(struct.pack("!B", CFM_END_TLV))
664         return buf
665
666
667 cfm.set_classes(cfm._CFM_OPCODE)
668
669
670 @six.add_metaclass(abc.ABCMeta)
671 class tlv(stringify.StringifyMixin):
672
673     _TYPE_LEN = 1
674     _LENGTH_LEN = 2
675     _TYPE = {
676         'ascii': [
677             'egress_id_mac', 'last_egress_id_mac',
678             'next_egress_id_mac', 'mac_address'
679         ]
680     }
681
682     def __init__(self, length):
683         self.length = length
684
685     @classmethod
686     @abc.abstractmethod
687     def parser(cls, buf):
688         pass
689
690     @abc.abstractmethod
691     def serialize(self):
692         pass
693
694     def __len__(self):
695         return self.length + self._TYPE_LEN + self._LENGTH_LEN
696
697
698 @operation.register_tlv_types(CFM_SENDER_ID_TLV)
699 class sender_id_tlv(tlv):
700
701     """CFM (IEEE Std 802.1ag-2007) Sender ID TLV encoder/decoder class.
702
703     This is used with ryu.lib.packet.cfm.cfm.
704
705     An instance has the following attributes at least.
706     Most of them are same to the on-wire counterparts but in host byte order.
707     __init__ takes the corresponding args in this order.
708
709     .. tabularcolumns:: |l|L|
710
711     ==================== =======================================
712     Attribute            Description
713     ==================== =======================================
714     length               Length of Value field.
715                          (0 means automatically-calculate when encoding.)
716     chassis_id_length    Chassis ID Length.
717                          (0 means automatically-calculate when encoding.)
718     chassis_id_subtype   Chassis ID Subtype.
719                          The default is 4 (Mac Address)
720     chassis_id           Chassis ID.
721     ma_domain_length     Management Address Domain Length.
722                          (0 means automatically-calculate when encoding.)
723     ma_domain            Management Address Domain.
724     ma_length            Management Address Length.
725                          (0 means automatically-calculate when encoding.)
726     ma                   Management Address.
727     ==================== =======================================
728     """
729
730     _PACK_STR = '!BHB'
731     _MIN_LEN = struct.calcsize(_PACK_STR)
732     _CHASSIS_ID_LENGTH_LEN = 1
733     _CHASSIS_ID_SUBTYPE_LEN = 1
734     _MA_DOMAIN_LENGTH_LEN = 1
735     _MA_LENGTH_LEN = 1
736
737     # Chassis ID subtype enumeration
738     _CHASSIS_ID_CHASSIS_COMPONENT = 1
739     _CHASSIS_ID_INTERFACE_ALIAS = 2
740     _CHASSIS_ID_PORT_COMPONENT = 3
741     _CHASSIS_ID_MAC_ADDRESS = 4
742     _CHASSIS_ID_NETWORK_ADDRESS = 5
743     _CHASSIS_ID_INTERFACE_NAME = 6
744     _CHASSIS_ID_LOCALLY_ASSIGNED = 7
745
746     def __init__(self,
747                  length=0,
748                  chassis_id_length=0,
749                  chassis_id_subtype=_CHASSIS_ID_MAC_ADDRESS,
750                  chassis_id=b'',
751                  ma_domain_length=0,
752                  ma_domain=b'',
753                  ma_length=0,
754                  ma=b''
755                  ):
756         super(sender_id_tlv, self).__init__(length)
757         self._type = CFM_SENDER_ID_TLV
758         self.chassis_id_length = chassis_id_length
759         assert chassis_id_subtype in [
760             self._CHASSIS_ID_CHASSIS_COMPONENT,
761             self._CHASSIS_ID_INTERFACE_ALIAS,
762             self._CHASSIS_ID_PORT_COMPONENT,
763             self._CHASSIS_ID_MAC_ADDRESS,
764             self._CHASSIS_ID_NETWORK_ADDRESS,
765             self._CHASSIS_ID_INTERFACE_NAME,
766             self._CHASSIS_ID_LOCALLY_ASSIGNED]
767         self.chassis_id_subtype = chassis_id_subtype
768         self.chassis_id = chassis_id
769         self.ma_domain_length = ma_domain_length
770         self.ma_domain = ma_domain
771         self.ma_length = ma_length
772         self.ma = ma
773
774     @classmethod
775     def parser(cls, buf):
776         (type_, length, chassis_id_length) = struct.unpack_from(cls._PACK_STR,
777                                                                 buf)
778         chassis_id_subtype = 4
779         chassis_id = b''
780         ma_domain_length = 0
781         ma_domain = b''
782         ma_length = 0
783         ma = b''
784         offset = cls._MIN_LEN
785         if chassis_id_length != 0:
786             (chassis_id_subtype, ) = struct.unpack_from("!B", buf, offset)
787             offset += cls._CHASSIS_ID_SUBTYPE_LEN
788             form = "%ds" % chassis_id_length
789             (chassis_id,) = struct.unpack_from(form, buf, offset)
790             offset += chassis_id_length
791         if length + (cls._TYPE_LEN + cls._LENGTH_LEN) > offset:
792             (ma_domain_length, ) = struct.unpack_from("!B", buf, offset)
793             offset += cls._MA_DOMAIN_LENGTH_LEN
794             form = "%ds" % ma_domain_length
795             (ma_domain, ) = struct.unpack_from(form, buf, offset)
796             offset += ma_domain_length
797             if length + (cls._TYPE_LEN + cls._LENGTH_LEN) > offset:
798                 (ma_length, ) = struct.unpack_from("!B", buf, offset)
799                 offset += cls._MA_LENGTH_LEN
800                 form = "%ds" % ma_length
801                 (ma, ) = struct.unpack_from(form, buf, offset)
802         return cls(length, chassis_id_length, chassis_id_subtype,
803                    chassis_id, ma_domain_length, ma_domain, ma_length, ma)
804
805     def serialize(self):
806         # calculate length when it contains 0
807         if self.chassis_id_length == 0:
808             self.chassis_id_length = len(self.chassis_id)
809         if self.ma_domain_length == 0:
810             self.ma_domain_length = len(self.ma_domain)
811         if self.ma_length == 0:
812             self.ma_length = len(self.ma)
813         if self.length == 0:
814             self.length += self._CHASSIS_ID_LENGTH_LEN
815             if self.chassis_id_length != 0:
816                 self.length += (self._CHASSIS_ID_SUBTYPE_LEN +
817                                 self.chassis_id_length)
818             if self.chassis_id_length != 0 or self.ma_domain_length != 0:
819                 self.length += self._MA_DOMAIN_LENGTH_LEN
820             if self.ma_domain_length != 0:
821                 self.length += (self.ma_domain_length +
822                                 self._MA_LENGTH_LEN + self.ma_length)
823         # start serialize
824         buf = struct.pack(self._PACK_STR,
825                           self._type,
826                           self.length,
827                           self.chassis_id_length
828                           )
829         buf = bytearray(buf)
830         # Chassis ID Subtype and Chassis ID present
831         # if the Chassis ID Length field contains not 0.
832         if self.chassis_id_length != 0:
833             buf.extend(struct.pack("!B", self.chassis_id_subtype))
834             form = "%ds" % self.chassis_id_length
835             buf.extend(struct.pack(form, self.chassis_id))
836         # Management Address Domain Length present
837         # if the Chassis ID Length field or Management Address Length field
838         # contains not 0.
839         if self.chassis_id_length != 0 or self.ma_domain_length != 0:
840             buf.extend(struct.pack("!B", self.ma_domain_length))
841         # Management Address Domain present
842         # Management Address Domain Length field contains not 0.
843         if self.ma_domain_length != 0:
844             form = "%ds" % self.ma_domain_length
845             buf.extend(struct.pack(form, self.ma_domain))
846             buf.extend(struct.pack("!B", self.ma_length))
847             # Management Address present
848             # Management Address Length field contains not 0.
849             if self.ma_length != 0:
850                 form = "%ds" % self.ma_length
851                 buf.extend(struct.pack(form, self.ma))
852         return buf
853
854
855 @operation.register_tlv_types(CFM_PORT_STATUS_TLV)
856 class port_status_tlv(tlv):
857
858     """CFM (IEEE Std 802.1ag-2007) Port Status TLV encoder/decoder class.
859
860     This is used with ryu.lib.packet.cfm.cfm.
861
862     An instance has the following attributes at least.
863     Most of them are same to the on-wire counterparts but in host byte order.
864     __init__ takes the corresponding args in this order.
865
866     .. tabularcolumns:: |l|L|
867
868     ==================== =======================================
869     Attribute            Description
870     ==================== =======================================
871     length               Length of Value field.
872                          (0 means automatically-calculate when encoding.)
873     port_status          Port Status.The default is 1 (psUp)
874     ==================== =======================================
875     """
876
877     _PACK_STR = '!BHB'
878     _MIN_LEN = struct.calcsize(_PACK_STR)
879
880     # Port Status TLV values
881     _PS_BLOCKED = 1
882     _PS_UP = 2
883
884     def __init__(self, length=0, port_status=_PS_UP):
885         super(port_status_tlv, self).__init__(length)
886         self._type = CFM_PORT_STATUS_TLV
887         assert port_status in [self._PS_BLOCKED, self._PS_UP]
888         self.port_status = port_status
889
890     @classmethod
891     def parser(cls, buf):
892         (type_, length,
893          port_status) = struct.unpack_from(cls._PACK_STR, buf)
894         return cls(length, port_status)
895
896     def serialize(self):
897         # calculate length when it contains 0
898         if self.length == 0:
899             self.length = 1
900         # start serialize
901         buf = struct.pack(self._PACK_STR,
902                           self._type,
903                           self.length,
904                           self.port_status)
905         return bytearray(buf)
906
907
908 @operation.register_tlv_types(CFM_DATA_TLV)
909 class data_tlv(tlv):
910
911     """CFM (IEEE Std 802.1ag-2007) Data TLV encoder/decoder class.
912
913     This is used with ryu.lib.packet.cfm.cfm.
914
915     An instance has the following attributes at least.
916     Most of them are same to the on-wire counterparts but in host byte order.
917     __init__ takes the corresponding args in this order.
918
919     .. tabularcolumns:: |l|L|
920
921     ============== =======================================
922     Attribute      Description
923     ============== =======================================
924     length         Length of Value field.
925                    (0 means automatically-calculate when encoding)
926     data_value     Bit pattern of any of n octets.(n = length)
927     ============== =======================================
928     """
929
930     _PACK_STR = '!BH'
931     _MIN_LEN = struct.calcsize(_PACK_STR)
932
933     def __init__(self, length=0, data_value=b""
934                  ):
935         super(data_tlv, self).__init__(length)
936         self._type = CFM_DATA_TLV
937         self.data_value = data_value
938
939     @classmethod
940     def parser(cls, buf):
941         (type_, length) = struct.unpack_from(cls._PACK_STR, buf)
942         form = "%ds" % length
943         (data_value, ) = struct.unpack_from(form, buf, cls._MIN_LEN)
944         return cls(length, data_value)
945
946     def serialize(self):
947         # calculate length when it contains 0
948         if self.length == 0:
949             self.length = len(self.data_value)
950         # start serialize
951         buf = struct.pack(self._PACK_STR,
952                           self._type,
953                           self.length)
954         buf = bytearray(buf)
955         form = "%ds" % self.length
956         buf.extend(struct.pack(form, self.data_value))
957         return buf
958
959
960 @operation.register_tlv_types(CFM_INTERFACE_STATUS_TLV)
961 class interface_status_tlv(tlv):
962
963     """CFM (IEEE Std 802.1ag-2007) Interface Status TLV encoder/decoder class.
964
965     This is used with ryu.lib.packet.cfm.cfm.
966
967     An instance has the following attributes at least.
968     Most of them are same to the on-wire counterparts but in host byte order.
969     __init__ takes the corresponding args in this order.
970
971     .. tabularcolumns:: |l|L|
972
973     ==================== =======================================
974     Attribute            Description
975     ==================== =======================================
976     length               Length of Value field.
977                          (0 means automatically-calculate when encoding.)
978     interface_status     Interface Status.The default is 1 (isUp)
979     ==================== =======================================
980     """
981
982     _PACK_STR = '!BHB'
983     _MIN_LEN = struct.calcsize(_PACK_STR)
984
985     # Interface Status TLV values
986     _IS_UP = 1
987     _IS_DOWN = 2
988     _IS_TESTING = 3
989     _IS_UNKNOWN = 4
990     _IS_DORMANT = 5
991     _IS_NOT_PRESENT = 6
992     _IS_LOWER_LAYER_DOWN = 7
993
994     def __init__(self, length=0, interface_status=_IS_UP):
995         super(interface_status_tlv, self).__init__(length)
996         self._type = CFM_INTERFACE_STATUS_TLV
997         assert interface_status in [
998             self._IS_UP, self._IS_DOWN, self._IS_TESTING,
999             self._IS_UNKNOWN, self._IS_DORMANT, self._IS_NOT_PRESENT,
1000             self._IS_LOWER_LAYER_DOWN]
1001         self.interface_status = interface_status
1002
1003     @classmethod
1004     def parser(cls, buf):
1005         (type_, length,
1006          interface_status) = struct.unpack_from(cls._PACK_STR, buf)
1007         return cls(length, interface_status)
1008
1009     def serialize(self):
1010         # calculate length when it contains 0
1011         if self.length == 0:
1012             self.length = 1
1013         # start serialize
1014         buf = struct.pack(self._PACK_STR,
1015                           self._type,
1016                           self.length,
1017                           self.interface_status)
1018         return bytearray(buf)
1019
1020
1021 @operation.register_tlv_types(CFM_LTM_EGRESS_IDENTIFIER_TLV)
1022 class ltm_egress_identifier_tlv(tlv):
1023
1024     """CFM (IEEE Std 802.1ag-2007) LTM EGRESS TLV encoder/decoder class.
1025
1026     This is used with ryu.lib.packet.cfm.cfm.
1027
1028     An instance has the following attributes at least.
1029     Most of them are same to the on-wire counterparts but in host byte order.
1030     __init__ takes the corresponding args in this order.
1031
1032     .. tabularcolumns:: |l|L|
1033
1034     ============== =======================================
1035     Attribute      Description
1036     ============== =======================================
1037     length         Length of Value field.
1038                    (0 means automatically-calculate when encoding.)
1039     egress_id_ui   Egress Identifier of Unique ID.
1040     egress_id_mac  Egress Identifier of MAC address.
1041     ============== =======================================
1042     """
1043
1044     _PACK_STR = '!BHH6s'
1045     _MIN_LEN = struct.calcsize(_PACK_STR)
1046
1047     def __init__(self,
1048                  length=0,
1049                  egress_id_ui=0,
1050                  egress_id_mac='00:00:00:00:00:00'
1051                  ):
1052         super(ltm_egress_identifier_tlv, self).__init__(length)
1053         self._type = CFM_LTM_EGRESS_IDENTIFIER_TLV
1054         self.egress_id_ui = egress_id_ui
1055         self.egress_id_mac = egress_id_mac
1056
1057     @classmethod
1058     def parser(cls, buf):
1059         (type_, length, egress_id_ui,
1060          egress_id_mac) = struct.unpack_from(cls._PACK_STR, buf)
1061         return cls(length, egress_id_ui,
1062                    addrconv.mac.bin_to_text(egress_id_mac))
1063
1064     def serialize(self):
1065         # calculate length when it contains 0
1066         if self.length == 0:
1067             self.length = 8
1068         # start serialize
1069         buf = struct.pack(self._PACK_STR,
1070                           self._type,
1071                           self.length,
1072                           self.egress_id_ui,
1073                           addrconv.mac.text_to_bin(self.egress_id_mac)
1074                           )
1075         return bytearray(buf)
1076
1077
1078 @operation.register_tlv_types(CFM_LTR_EGRESS_IDENTIFIER_TLV)
1079 class ltr_egress_identifier_tlv(tlv):
1080
1081     """CFM (IEEE Std 802.1ag-2007) LTR EGRESS TLV encoder/decoder class.
1082
1083     This is used with ryu.lib.packet.cfm.cfm.
1084
1085     An instance has the following attributes at least.
1086     Most of them are same to the on-wire counterparts but in host byte order.
1087     __init__ takes the corresponding args in this order.
1088
1089     .. tabularcolumns:: |l|L|
1090
1091     ==================== =======================================
1092     Attribute            Description
1093     ==================== =======================================
1094     length               Length of Value field.
1095                          (0 means automatically-calculate when encoding.)
1096     last_egress_id_ui    Last Egress Identifier of Unique ID.
1097     last_egress_id_mac   Last Egress Identifier of MAC address.
1098     next_egress_id_ui    Next Egress Identifier of Unique ID.
1099     next_egress_id_mac   Next Egress Identifier of MAC address.
1100     ==================== =======================================
1101     """
1102
1103     _PACK_STR = '!BHH6sH6s'
1104     _MIN_LEN = struct.calcsize(_PACK_STR)
1105
1106     def __init__(self,
1107                  length=0,
1108                  last_egress_id_ui=0,
1109                  last_egress_id_mac='00:00:00:00:00:00',
1110                  next_egress_id_ui=0,
1111                  next_egress_id_mac='00:00:00:00:00:00'
1112                  ):
1113         super(ltr_egress_identifier_tlv, self).__init__(length)
1114         self._type = CFM_LTR_EGRESS_IDENTIFIER_TLV
1115         self.last_egress_id_ui = last_egress_id_ui
1116         self.last_egress_id_mac = last_egress_id_mac
1117         self.next_egress_id_ui = next_egress_id_ui
1118         self.next_egress_id_mac = next_egress_id_mac
1119
1120     @classmethod
1121     def parser(cls, buf):
1122         (type_, length,
1123          last_egress_id_ui, last_egress_id_mac,
1124          next_egress_id_ui, next_egress_id_mac
1125          ) = struct.unpack_from(cls._PACK_STR, buf)
1126         return cls(length,
1127                    last_egress_id_ui,
1128                    addrconv.mac.bin_to_text(last_egress_id_mac),
1129                    next_egress_id_ui,
1130                    addrconv.mac.bin_to_text(next_egress_id_mac))
1131
1132     def serialize(self):
1133         # calculate length when it contains 0
1134         if self.length == 0:
1135             self.length = 16
1136         # start serialize
1137         buf = struct.pack(self._PACK_STR,
1138                           self._type,
1139                           self.length,
1140                           self.last_egress_id_ui,
1141                           addrconv.mac.text_to_bin(self.last_egress_id_mac),
1142                           self.next_egress_id_ui,
1143                           addrconv.mac.text_to_bin(self.next_egress_id_mac)
1144                           )
1145         return bytearray(buf)
1146
1147
1148 @operation.register_tlv_types(CFM_ORGANIZATION_SPECIFIC_TLV)
1149 class organization_specific_tlv(tlv):
1150
1151     """CFM (IEEE Std 802.1ag-2007) Organization Specific TLV
1152        encoder/decoder class.
1153
1154     This is used with ryu.lib.packet.cfm.cfm.
1155
1156     An instance has the following attributes at least.
1157     Most of them are same to the on-wire counterparts but in host byte order.
1158     __init__ takes the corresponding args in this order.
1159
1160     .. tabularcolumns:: |l|L|
1161
1162     ============== =======================================
1163     Attribute      Description
1164     ============== =======================================
1165     length         Length of Value field.
1166                    (0 means automatically-calculate when encoding.)
1167     oui            Organizationally Unique Identifier.
1168     subtype        Subtype.
1169     value          Value.(optional)
1170     ============== =======================================
1171     """
1172
1173     _PACK_STR = '!BH3sB'
1174     _MIN_LEN = struct.calcsize(_PACK_STR)
1175     _OUI_AND_SUBTYPE_LEN = 4
1176
1177     def __init__(self,
1178                  length=0,
1179                  oui=b"\x00\x00\x00",
1180                  subtype=0,
1181                  value=b""
1182                  ):
1183         super(organization_specific_tlv, self).__init__(length)
1184         self._type = CFM_ORGANIZATION_SPECIFIC_TLV
1185         self.oui = oui
1186         self.subtype = subtype
1187         self.value = value
1188
1189     @classmethod
1190     def parser(cls, buf):
1191         (type_, length, oui, subtype) = struct.unpack_from(cls._PACK_STR, buf)
1192         value = b""
1193         if length > cls._OUI_AND_SUBTYPE_LEN:
1194             form = "%ds" % (length - cls._OUI_AND_SUBTYPE_LEN)
1195             (value,) = struct.unpack_from(form, buf, cls._MIN_LEN)
1196         return cls(length, oui, subtype, value)
1197
1198     def serialize(self):
1199         # calculate length when it contains 0
1200         if self.length == 0:
1201             self.length = len(self.value) + self._OUI_AND_SUBTYPE_LEN
1202         # start serialize
1203         buf = struct.pack(self._PACK_STR,
1204                           self._type,
1205                           self.length,
1206                           self.oui,
1207                           self.subtype,
1208                           )
1209         buf = bytearray(buf)
1210         form = "%ds" % (self.length - self._OUI_AND_SUBTYPE_LEN)
1211         buf.extend(struct.pack(form, self.value))
1212         return buf
1213
1214
1215 class reply_tlv(tlv):
1216
1217     _PACK_STR = '!BHB6s'
1218     _MIN_LEN = struct.calcsize(_PACK_STR)
1219     _MIN_VALUE_LEN = _MIN_LEN - struct.calcsize('!BH')
1220     _PORT_ID_LENGTH_LEN = 1
1221     _PORT_ID_SUBTYPE_LEN = 1
1222
1223     def __init__(self, length, action, mac_address, port_id_length,
1224                  port_id_subtype, port_id):
1225         super(reply_tlv, self).__init__(length)
1226         self.action = action
1227         self.mac_address = mac_address
1228         self.port_id_length = port_id_length
1229         self.port_id_subtype = port_id_subtype
1230         self.port_id = port_id
1231
1232     @classmethod
1233     def parser(cls, buf):
1234         (type_, length, action,
1235          mac_address) = struct.unpack_from(cls._PACK_STR, buf)
1236         port_id_length = 0
1237         port_id_subtype = 0
1238         port_id = b''
1239         if length > cls._MIN_VALUE_LEN:
1240             (port_id_length,
1241              port_id_subtype) = struct.unpack_from('!2B', buf, cls._MIN_LEN)
1242             form = "%ds" % port_id_length
1243             (port_id,) = struct.unpack_from(form, buf,
1244                                             cls._MIN_LEN +
1245                                             cls._PORT_ID_LENGTH_LEN +
1246                                             cls._PORT_ID_SUBTYPE_LEN)
1247         return cls(length, action,
1248                    addrconv.mac.bin_to_text(mac_address),
1249                    port_id_length, port_id_subtype, port_id)
1250
1251     def serialize(self):
1252         # calculate length when it contains 0
1253         if self.port_id_length == 0:
1254             self.port_id_length = len(self.port_id)
1255         if self.length == 0:
1256             self.length = self._MIN_VALUE_LEN
1257             if self.port_id_length != 0:
1258                 self.length += (self.port_id_length +
1259                                 self._PORT_ID_LENGTH_LEN +
1260                                 self._PORT_ID_SUBTYPE_LEN)
1261         # start serialize
1262         buf = struct.pack(self._PACK_STR,
1263                           self._type,
1264                           self.length,
1265                           self.action,
1266                           addrconv.mac.text_to_bin(self.mac_address),
1267                           )
1268         buf = bytearray(buf)
1269         if self.port_id_length != 0:
1270             buf.extend(struct.pack("!BB",
1271                                    self.port_id_length,
1272                                    self.port_id_subtype))
1273             form = "%ds" % self.port_id_length
1274             buf.extend(struct.pack(form, self.port_id))
1275         return buf
1276
1277
1278 @operation.register_tlv_types(CFM_REPLY_INGRESS_TLV)
1279 class reply_ingress_tlv(reply_tlv):
1280
1281     """CFM (IEEE Std 802.1ag-2007) Reply Ingress TLV encoder/decoder class.
1282
1283     This is used with ryu.lib.packet.cfm.cfm.
1284
1285     An instance has the following attributes at least.
1286     Most of them are same to the on-wire counterparts but in host byte order.
1287     __init__ takes the corresponding args in this order.
1288
1289     .. tabularcolumns:: |l|L|
1290
1291     ================= =======================================
1292     Attribute         Description
1293     ================= =======================================
1294     length            Length of Value field.
1295                       (0 means automatically-calculate when encoding.)
1296     action            Ingress Action.The default is 1 (IngOK)
1297     mac_address       Ingress MAC Address.
1298     port_id_length    Ingress PortID Length.
1299                       (0 means automatically-calculate when encoding.)
1300     port_id_subtype   Ingress PortID Subtype.
1301     port_id           Ingress PortID.
1302     ================= =======================================
1303     """
1304
1305     # Ingress Action field values
1306     _ING_OK = 1
1307     _ING_DOWN = 2
1308     _ING_BLOCKED = 3
1309     _ING_VID = 4
1310
1311     def __init__(self,
1312                  length=0,
1313                  action=_ING_OK,
1314                  mac_address='00:00:00:00:00:00',
1315                  port_id_length=0,
1316                  port_id_subtype=0,
1317                  port_id=b''
1318                  ):
1319         super(reply_ingress_tlv, self).__init__(length, action,
1320                                                 mac_address, port_id_length,
1321                                                 port_id_subtype, port_id)
1322         assert action in [self._ING_OK, self._ING_DOWN,
1323                           self._ING_BLOCKED, self._ING_VID]
1324         self._type = CFM_REPLY_INGRESS_TLV
1325
1326
1327 @operation.register_tlv_types(CFM_REPLY_EGRESS_TLV)
1328 class reply_egress_tlv(reply_tlv):
1329
1330     """CFM (IEEE Std 802.1ag-2007) Reply Egress TLV encoder/decoder class.
1331
1332     This is used with ryu.lib.packet.cfm.cfm.
1333
1334     An instance has the following attributes at least.
1335     Most of them are same to the on-wire counterparts but in host byte order.
1336     __init__ takes the corresponding args in this order.
1337
1338     .. tabularcolumns:: |l|L|
1339
1340     ================= =======================================
1341     Attribute         Description
1342     ================= =======================================
1343     length            Length of Value field.
1344                       (0 means automatically-calculate when encoding.)
1345     action            Egress Action.The default is 1 (EgrOK)
1346     mac_address       Egress MAC Address.
1347     port_id_length    Egress PortID Length.
1348                       (0 means automatically-calculate when encoding.)
1349     port_id_subtype   Egress PortID Subtype.
1350     port_id           Egress PortID.
1351     ================= =======================================
1352     """
1353
1354     # Egress Action field values
1355     _EGR_OK = 1
1356     _EGR_DOWN = 2
1357     _EGR_BLOCKED = 3
1358     _EGR_VID = 4
1359
1360     def __init__(self,
1361                  length=0,
1362                  action=_EGR_OK,
1363                  mac_address='00:00:00:00:00:00',
1364                  port_id_length=0,
1365                  port_id_subtype=0,
1366                  port_id=b''
1367                  ):
1368         super(reply_egress_tlv, self).__init__(length, action,
1369                                                mac_address, port_id_length,
1370                                                port_id_subtype, port_id)
1371         assert action in [self._EGR_OK, self._EGR_DOWN,
1372                           self._EGR_BLOCKED, self._EGR_VID]
1373         self._type = CFM_REPLY_EGRESS_TLV
1374
1375
1376 operation.set_classes(operation._TLV_TYPES)