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 16import abc 17import six 18import struct 19from ryu.lib import addrconv 20from ryu.lib import stringify 21from ryu.lib.packet import packet_base 22 23# IEEE 802.1ag OpCode 24CFM_CC_MESSAGE = 0x01 25CFM_LOOPBACK_REPLY = 0x02 26CFM_LOOPBACK_MESSAGE = 0x03 27CFM_LINK_TRACE_REPLY = 0x04 28CFM_LINK_TRACE_MESSAGE = 0x05 29 30# IEEE 802.1ag TLV type 31CFM_END_TLV = 0x00 32CFM_SENDER_ID_TLV = 0x01 33CFM_PORT_STATUS_TLV = 0x02 34CFM_DATA_TLV = 0x03 35CFM_INTERFACE_STATUS_TLV = 0x04 36CFM_REPLY_INGRESS_TLV = 0x05 37CFM_REPLY_EGRESS_TLV = 0x06 38CFM_LTM_EGRESS_IDENTIFIER_TLV = 0x07 39CFM_LTR_EGRESS_IDENTIFIER_TLV = 0x08 40CFM_ORGANIZATION_SPECIFIC_TLV = 0x1f 41 42# IEEE 802.1ag CFM version 43CFM_VERSION = 0 44 45 46class 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) 127class 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) 191class 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 364class 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) 406class 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) 439class 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 471class 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) 496class 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) 583class 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 667cfm.set_classes(cfm._CFM_OPCODE) 668 669 670@six.add_metaclass(abc.ABCMeta) 671class 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) 699class 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) 856class 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) 909class 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) 961class 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) 1022class 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) 1079class 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) 1149class 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 1215class 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) 1279class 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) 1328class 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 1376operation.set_classes(operation._TLV_TYPES) 1377