Exemplo n.º 1
0
def ParseBmpHeaderV3(header, verbose=False):
    """Parse a BMP V3 header.

  Args:
    header: array containing BMP message header.
    verbose: be chatty, or not.

  Returns:
    An int indicating the type of message that follows the header,
    and a list of strings to print.

  Raises:
    ValueError: an unexpected value was found in the message
  """

    indent_str = indent.IndentLevel(indent.BMP_HEADER_INDENT)
    print_msg = []

    version = 3
    msg_length = struct.unpack(">L", header[0:4])
    msg_type = header[4]

    # Decide what to format as text
    #
    print_msg.append(
        "%sBMP version %d type %s length %d\n" %
        (indent_str, version, MSG_TYPE_STR[msg_type], msg_length[0]))

    # Return the message type so the caller can decide what to do next,
    # and the list of strings representing the collected message.
    #
    return msg_type, msg_length[0], print_msg
Exemplo n.º 2
0
def ParseBmpPeerUp(message, peer_flags, verbose=False):
    """Parse a BMP V3 Peer Up message.

  Args:
    header: array containing BMP peer up message.
    peer_flags: from the per-peer header.
    verbose: be chatty, or not.

  Returns:
    A list of strings to print.

  Raises:
    ValueError: an unexpected value was found in the message
  """

    indent_str = indent.IndentLevel(indent.BMP_CONTENT_INDENT)
    print_msg = []
    offset = 0

    if peer_flags & PEER_FLAG_IPV6:
        loc_addr = socket.inet_ntop(socket.AF_INET6,
                                    message[offset:offset + 16])
    else:
        loc_addr = socket.inet_ntop(socket.AF_INET,
                                    message[offset + 12:offset + 16])
    offset += 16
    loc_port, rem_port = struct.unpack_from(">HH", message, offset)

    print_msg.append("%sloc_addr %s, loc_port %d, rem_port %d\n" %
                     (indent_str, loc_addr, loc_port, rem_port))
    return print_msg
Exemplo n.º 3
0
def CollectBmpPeerUp(sock, verbose=False):
    """Collect a BMP Peer Up message.

  Args:
    sock: socket from which to read.
    verbose: be chatty, or not.

  Returns:
    nothing

  Raises:
    ValueError: an unexpected value was found in the message
  """

    indent_str = indent.IndentLevel(indent.BMP_CONTENT_INDENT)
    print_msg = []

    # collect a per peer header
    #
    per_peer_header = CollectBytes(sock, BMP.PER_PEER_HEADER_LEN_V3)
    peer_flags, msg_text = BMP.ParseBmpPerPeerHeaderV3(per_peer_header,
                                                       verbose=verbose)
    print_msg += "".join(msg_text)

    # collect local address, local and remote ports
    #
    peer_up_msg = CollectBytes(sock, BMP.PEER_UP_LEN)
    if verbose:
        msg_text = BMP.ParseBmpPeerUp(peer_up_msg, peer_flags, verbose=verbose)
        print_msg += "".join(msg_text)

    # sent BGP OPEN message
    #
    sent_header = CollectBytes(sock, BGP.HEADER_LEN)
    length, msg_type, hdr_text = BGP.ParseBgpHeader(sent_header,
                                                    verbose=verbose)
    assert msg_type == BGP.OPEN
    print_msg += "".join(hdr_text)
    sent_open = CollectBytes(sock, length)
    sent_text = BGP.ParseBgpOpen(sent_open, length)
    print_msg += "".join(sent_text)

    # received BGP OPEN message
    #
    recv_header = CollectBytes(sock, BGP.HEADER_LEN)
    length, msg_type, hdr_text = BGP.ParseBgpHeader(recv_header,
                                                    verbose=verbose)
    assert msg_type == BGP.OPEN
    print_msg += "".join(hdr_text)
    recv_open = CollectBytes(sock, length)
    recv_text = BGP.ParseBgpOpen(recv_open, length)
    print_msg += "".join(recv_text)

    # Return list of strings representing collected message.
    #
    return print_msg
Exemplo n.º 4
0
def ParseBgpHeader(header, verbose=False):
    """Parse a BGP header into text, see RFC4271 section 4.1.

  Args:
    header: a buffer containing a BGP message header.
    verbose: be chatty, or not.

  Returns:
    An int indicating the length of the rest of the BGP message,
    an int indication the type of the message,
    a list of strings to print.

  Raises:
    ValueError: an invalid value was found in the message.
  """

    print_msg = []
    indent_str = indent.IndentLevel(indent.BGP_HEADER_INDENT)

    try:

        # Verify that the marker is correct, raise a ValueError exception if
        # it is not.
        #
        for x in range(0, 15):
            if header[x] != 255:
                raise ValueError("BGP marker octet %d != 255" % x)

        # Unpack the length and type.
        #
        length, msg_type = struct.unpack(">HB", header[16:19])
        if length < MIN_LENGTH or length > MAX_LENGTH:
            raise ValueError("BGP message length %d incorrect" % length)
        if msg_type not in MSG_TYPE_STR:
            raise ValueError("BGP message type %d unknown" % msg_type)
        print_msg.append("%sBGP %s" % (indent_str, MSG_TYPE_STR[msg_type]))
        if verbose:
            print_msg.append(" length %d\n" % (length - HEADER_LEN))
        else:
            print_msg.append("\n")

        # Return the length of the rest of the PDU, its type, and the list
        # of strings representing the collected message
        #
        return length - HEADER_LEN, msg_type, print_msg

    # In case of any exception, dump the hex of the message to help
    # debug what's wrong with the message, and re-raise the exception.
    #
    except Exception, esc:
        if verbose:
            print str(esc)
            print DumpHexString(header, 0, HEADER_LEN)
        raise esc
Exemplo n.º 5
0
def CollectBmpInitiation(sock, msg_length, verbose=False):
    """Collect a BMP Initiation message.

  Args:
    sock: socket from which to read.

  Returns:
    A list of strings.

  Raises:
    ValueError: an unexpected value was found in the message
  """

    print_msg = []
    indent_str = indent.IndentLevel(indent.BMP_CONTENT_INDENT)

    # get the remainder of the message
    #
    init_msg_len = msg_length - BMP.HEADER_LEN_V3
    init_msg_buf = CollectBytes(sock, init_msg_len)
    init_msg_pos = 0

    while init_msg_pos < init_msg_len:

        info_type, info_len = struct.unpack_from(">HH", init_msg_buf,
                                                 init_msg_pos)
        init_msg_pos += 4
        info_str = init_msg_buf[init_msg_pos:init_msg_pos + info_len]
        init_msg_pos += info_len

        if info_type == BMP.INIT_INFO_TYPE_STRING:
            print_msg.append("%s%s: %s\n" %
                             (indent_str, BMP.INIT_INFO_TYPE_STR[info_type],
                              info_str.tostring()))

        elif info_type == BMP.INIT_INFO_TYPE_SYSDESCR:
            print_msg.append("%s%s: %s\n" %
                             (indent_str, BMP.INIT_INFO_TYPE_STR[info_type],
                              info_str.tostring()))

        elif info_type == BMP.INIT_INFO_TYPE_SYSNAME:
            print_msg.append("%s%s: %s\n" %
                             (indent_str, BMP.INIT_INFO_TYPE_STR[info_type],
                              info_str.tostring()))

        else:
            raise ValueError("Found unexpected Init Msg Info Type %d",
                             info_type)

    # Return list of strings representing collected message.
    #
    return print_msg
Exemplo n.º 6
0
def CollectBmpPeerDown(sock, verbose=False):
    """Collect a BMP Peer Down message.

  Args:
    sock: socket from which to read.
    verbose: be chatty, or not.

  Returns:
    nothing

  Raises:
    ValueError: an unexpected value was found in the message
  """

    indent_str = indent.IndentLevel(indent.BMP_CONTENT_INDENT)
    print_msg = []

    reason_code = CollectBytes(sock, 1)[0]
    if reason_code in BMP.PEER_DOWN_REASON_STR:
        print_msg.append("%s%s\n" %
                         (indent_str, BMP.PEER_DOWN_REASON_STR[reason_code]))

        # If the BMP message contains a BGP NOTIFICATION message, collect
        # and parse it.
        #
        if BMP.PeerDownHasBgpNotification(reason_code):

            # Collect and parse the BGP message header
            #
            header = CollectBytes(sock, BGP.HEADER_LEN)
            length, msg_type, msg_text = BGP.ParseBgpHeader(header,
                                                            verbose=verbose)
            assert msg_type == BGP.NOTIFICATION
            print_msg.append("".join(msg_text))

            # collect and parse the BGP message body
            #
            notification = CollectBytes(sock, length)
            msg_text = BGP.ParseBgpNotification(notification,
                                                length,
                                                verbose=verbose)
            print_msg.append("".join(msg_text))

    elif DEBUG_FLAG:
        raise ValueError("Unknown BMP Peer Down reason %d" % reason_code)
    else:
        print_msg.append("Unknown BMP Peer Down reason %d\n" % reason_code)

    # Return list of strings representing collected message.
    #
    return print_msg
Exemplo n.º 7
0
def ParseBmpPerPeerHeaderV3(header, verbose=False):
    """Parse a BMP V3 per-peer header.

  Args:
    header: array containing BMP message header.
    verbose: be chatty, or not.

  Returns:
    An int indicating the peer flags
    and a list of strings to print.

  Raises:
    ValueError: an unexpected value was found in the message
  """

    indent_str = indent.IndentLevel(indent.BMP_CONTENT_INDENT)
    print_msg = []
    offset = 0

    # peer type, flags, and the rest
    #
    peer_type, peer_flags = struct.unpack_from(">BB", header, offset)
    offset += 2
    peer_dist = struct.unpack_from("8B", header, offset)
    offset += 8
    if peer_flags & PEER_FLAG_IPV6:
        peer_address = socket.inet_ntop(socket.AF_INET6,
                                        header[offset:offset + 16])
    else:
        peer_address = socket.inet_ntop(socket.AF_INET,
                                        header[offset + 12:offset + 16])
    offset += 16
    peer_as, peer_bgp_id, time_sec, time_usec = struct.unpack_from(
        ">LLLL", header, offset)

    # Decide what to format as text
    #
    print_msg.append("%sPeer Type %s, flags %d, address %s, AS %d\n" %
                     (indent_str, PEER_TYPE_STR[peer_type], peer_flags,
                      peer_address, peer_as))
    time_str = time.strftime("%Y-%m-%d %H:%M", time.gmtime(time_sec))
    time_frac = time_usec / 1000000.0

    print_msg.append("%sTime %s.%s\n" %
                     (indent_str, time_str, re.split('\.', str(time_frac))[1]))

    # Return the message type so the caller can decide what to do next,
    # and the list of strings representing the collected message.
    #
    return peer_flags, print_msg
Exemplo n.º 8
0
def CollectBmpTermination(sock, msg_length, verbose=False):
    """Collect a BMP Termination message.

  Args:
    sock: socket from which to read.

  Returns:
    A list of strings.

  Raises:
    ValueError: an unexpected value was found in the message
  """

    print_msg = []
    indent_str = indent.IndentLevel(indent.BMP_CONTENT_INDENT)

    # get the remainder of the message
    #
    term_msg_len = msg_length - BMP.HEADER_LEN_V3
    term_msg_buf = CollectBytes(sock, term_msg_len)
    term_msg_pos = 0

    while term_msg_pos < term_msg_len:

        info_type, info_len = struct.unpack_from(">HH", term_msg_buf,
                                                 term_msg_pos)
        term_msg_pos += 4
        info_str = term_msg_buf[term_msg_pos:term_msg_pos + info_len]
        term_msg_pos += info_len

        if info_type == BMP.TERM_INFO_TYPE_STRING:
            print_msg.append("%s%s: %s\n" %
                             (indent_str, BMP.TERM_INFO_TYPE_STR[info_type],
                              info_str.tostring()))

        elif info_type == BMP.TERM_INFO_TYPE_REASON:
            reason_code = struct.unpack(">H", info_str)[0]
            print_msg.append(
                "%s%s: %d (%s)\n" %
                (indent_str, BMP.TERM_INFO_TYPE_STR[info_type], reason_code,
                 BMP.TERM_INFO_REASON_STR[reason_code]))

        else:
            raise ValueError("Found unexpected Init Msg Info Type %d",
                             info_type)

    # Return list of strings representing collected message.
    #
    return print_msg
Exemplo n.º 9
0
def ParseBmpHeaderV1(header, verbose=False):
    """Parse a BMP V1 header.

  Args:
    header: array containing BMP message header.
    verbose: be chatty, or not.

  Returns:
    An int indicating the type of message that follows the header,
    and a list of strings to print.

  Raises:
    ValueError: an unexpected value was found in the message
  """

    indent_str = indent.IndentLevel(indent.BMP_HEADER_INDENT)
    print_msg = []

    version = 1
    msg_type, peer_type, peer_flags = struct.unpack(">BBB", header[0:3])
    if peer_flags & PEER_FLAG_IPV6:
        peer_address = socket.inet_ntop(socket.AF_INET6, header[11:27])
    else:
        peer_address = socket.inet_ntop(socket.AF_INET, header[23:27])
    peer_as, time_sec = struct.unpack(">LxxxxL", header[27:39])

    # If we have a version mismatch, we're pretty much done here.
    #
    if version != 1:
        raise ValueError("Found BMP version %d, expecting %d" % (version, 1))

    # Decide what to format as text
    #
    print_msg.append(
        "%sBMP version %d type %s peer %s AS %d\n" %
        (indent_str, version, MSG_TYPE_STR[msg_type], peer_address, peer_as))
    if verbose:
        print_msg.append("%speer_type %s" %
                         (indent_str, PEER_TYPE_STR[peer_type]))
        print_msg.append(" peer_flags 0x%x" % peer_flags)
        print_msg.append(" router_id %s\n" % socket.inet_ntoa(header[31:34]))
        print_msg.append("%stime %s\n" % (indent_str, time.ctime(time_sec)))

    # Return the message type so the caller can decide what to do next,
    # and the list of strings representing the collected message.
    #
    return msg_type, print_msg
Exemplo n.º 10
0
def ParseBgpNotification(notification, length, verbose=False):
    """Parse a BGP Notification message, see RFC4271 section 4.5.

  Args:
    notification: the body of a BGP Notification message.
    length: the length of the message body.
    verbose: be chatty, or not.

  Returns:
    A list of strings to print

  Raises:
    ValueError: a code or subcode value is invalid per RFC4271
  """

    print_msg = []
    indent_str = indent.IndentLevel(indent.BGP_CONTENT_INDENT)

    code, subcode = struct.unpack(">BB", notification[0:2])
    if code not in NOTIFICATION_CODE:
        raise ValueError("BGP NOTIFICATION code %d is invalid" % code)

    code_str = NOTIFICATION_CODE[code]
    if code in NOTIFICATION_SUBCODE:
        if subcode not in NOTIFICATION_SUBCODE[code]:
            raise ValueError("BGP NOTIFICATION code %d subcode %d is invalid" %
                             (code, subcode))
        else:
            subcode_str = NOTIFICATION_SUBCODE[code][subcode]
        print_msg.append("%sNOTIFICATION code %s subcode %s\n" %
                         (indent_str, code_str, subcode_str))
    else:
        print_msg.append("%sNOTIFICATION code %s\n" % (indent_str, code_str))

    # If there are data bytes, convert them to text as hex digits.
    #
    if length > 2 and verbose:
        print_msg.append("%sNOTIFICATION data " % indent_str)
        print_msg.append(DumpHexString(notification, 3, length - 1))
        print_msg.append("\n")

    # Return the list of strings representing collected message.
    #
    return print_msg
Exemplo n.º 11
0
def CollectBmpStatsMsg(sock):
    """Collect a BMP Statistics Report message.

  Args:
    sock: socket from which to read.

  Returns:
    A list of strings.
  """

    print_msg = []
    indent_str = indent.IndentLevel(indent.BMP_CONTENT_INDENT)

    # Find out many TLVs (Type-Length-Value) there are in the message.
    #
    stats_count_buf = CollectBytes(sock, 4)
    stats_count = struct.unpack(">L", stats_count_buf)[0]

    # Read all the TLVs.
    #
    for _ in xrange(stats_count):

        # Get the type and the length.
        #
        stat_type_len_buf = CollectBytes(sock, 4)
        stat_type, stat_len = struct.unpack(">HH", stat_type_len_buf)

        # Stat types through 6 are 32 bits, 7 and 8 are 64
        #
        assert stat_type in BMP.SR_TYPE_STR
        stat_val_buf = CollectBytes(sock, stat_len)
        if stat_len is 4:
            stat_val = struct.unpack(">L", stat_val_buf)[0]
        elif stat_len is 8:
            stat_val = struct.unpack(">Q", stat_val_buf)[0]
        else:
            raise ValueError("Found unexpected stat_len %d in SR message",
                             stat_len)
        print_msg.append("%s%d %s\n" %
                         (indent_str, stat_val, BMP.SR_TYPE_STR[stat_type]))

    # Return list of strings representing collected message.
    #
    return print_msg
Exemplo n.º 12
0
def ParseBgpRouteRefresh(message, length):
    """Parse a BGP ROUTE-REFRESH message; see RFC2918.

  Args:
    message: the body of a BGP ROUTE-REFRESH message.
    length: the length of the message.

  Returns:
    A list of strings to print

  Raises:
    ValueError: an unexpected value was found in the message
  """

    print_msg = []
    indent_str = indent.IndentLevel(indent.BGP_CONTENT_INDENT)
    offset = 0

    # the length is fixed, check it
    #
    if length is not 4:
        raise ValueError("unexpected length %d for ROUTE-REFRESH message" %
                         length)

    # ROUTE-REFRESH messages are very simple: AFI, reserved octet, SAFI.
    #
    afi, reserved, safi = struct.unpack_from(">HBB", message, offset)

    # validate the message parts
    #
    if afi not in AF_STR:
        raise ValueError("unknown AFI %d in ROUTE-REFRESH message" % afi)
    if reserved:
        raise ValueError("reserved not zero in ROUTE-REFRESH message")
    if safi not in MP_SAFI_STR:
        raise ValueError("unknown SAFI %d in ROUTE-REFRESH message" % safi)

    # construct and return a text representation of the message
    #
    print_msg.append("%sAFI %s SAFI %s\n" %
                     (indent_str, AF_STR[afi], MP_SAFI_STR[safi]))
    return print_msg
Exemplo n.º 13
0
def ParseBgpOpen(message, length):
    """Parse a BGP OPEN message; see RFC1771.

  Args:
    message: the body of a BGP OPEN message.
    length: the length of the message.

  Returns:
    A list of strings to print

  Raises:
    ValueError: an unexpected value was found in the message
  """

    print_msg = []
    indent_str = indent.IndentLevel(indent.BGP_CONTENT_INDENT)
    offset = 0

    print_msg.append("%sbgp open parsing tbd\n" % indent_str)

    return print_msg
Exemplo n.º 14
0
def ParseBgpUpdate(update, length, rfc4893_updates=False, verbose=False):
    """Parse a BGP Update message; see RFC1997, RFC2858, RFC4271 4.3, RFC4893.

  Args:
    update: the body of a BGP UPDATE message.
    length: the length of the message.
    rfc4893_updates: true if update conforms to RFC4893.
    verbose: be chatty, or not.

  Returns:
    A list of strings to print

  Raises:
    ValueError: an unexpected value was found in the message
  """

    print_msg = []
    indent_str = indent.IndentLevel(indent.BGP_CONTENT_INDENT)
    offset = 0

    # First section is withdrawn routes.
    #
    withdrawn_route_len = struct.unpack_from(">H", update[0:2], offset)[0]
    if verbose:
        print_msg.append("%swithdrawn at %d length %d\n" %
                         (indent_str, offset, withdrawn_route_len))
    offset += 2

    # If any withdrawn routes are present, process them.
    #
    if withdrawn_route_len:
        withdrawn_text = ParseBgpNlri(update, offset,
                                      offset + withdrawn_route_len, AF_IP,
                                      MP_SAFI_UNICAST)
        if withdrawn_text:
            prepend_str = "%swithdraw " % indent_str
            sep = "\n%s" % prepend_str
            print_msg.append("%s%s\n" %
                             (prepend_str, sep.join(withdrawn_text)))

        offset += withdrawn_route_len

    # Next section is path attributes
    #
    path_attr_len = struct.unpack_from(">H", update, offset)[0]
    if verbose:
        print_msg.append("%spath attributes at %d length %d\n" %
                         (indent_str, offset, path_attr_len))
    offset += 2

    # If there are path attributes present, process them.
    #
    path_attr_end = offset + path_attr_len
    while offset < path_attr_end:

        # Get flags and type code.
        #
        attr_flags, attr_type = struct.unpack_from(">BB", update, offset)

        # If we're being verbose, describe the details of the path attribute.
        # We haven't updated offset yet in order to be able to report the
        # offset of the path attribute section in the verbose text.
        #
        if verbose:
            print_msg.append("%spath attr %s at %d" %
                             (indent_str, ATTR_TYPE_STR[attr_type], offset))
            print_msg.append(" flags 0x%x (" % attr_flags)
            attr_list = []
            if (attr_flags & ATTR_FLAG_OPTIONAL) == ATTR_FLAG_OPTIONAL:
                attr_list.append("optional")
            if (attr_flags & ATTR_FLAG_TRANSITIVE) == ATTR_FLAG_TRANSITIVE:
                attr_list.append("transitive")
            if (attr_flags & ATTR_FLAG_PARTIAL) == ATTR_FLAG_PARTIAL:
                attr_list.append("partial")
            if (attr_flags & ATTR_FLAG_EXT_LEN) == ATTR_FLAG_EXT_LEN:
                attr_list.append("extended-length")
            print_msg.append(" ".join(attr_list))

        # Now increment the offset, check for extended length, and get the
        # length (whose size depends on the extended length flag).
        #
        offset += 2
        if (attr_flags & ATTR_FLAG_EXT_LEN) == ATTR_FLAG_EXT_LEN:
            attr_len = struct.unpack_from(">H", update, offset)[0]
            offset += 2
        else:
            attr_len = update[offset]
            offset += 1

        # Finish up the verbose processing of the path attribute's details.
        #
        if verbose:
            print_msg.append(") len %d\n" % attr_len)

        # Now we can process the specific types of path attribute, see:
        # RFC4271
        # RFC2858
        #
        # ORIGIN
        #
        if attr_type == ATTR_TYPE_ORIGIN:

            # we know both length and possible values of the ORIGIN attribute,
            # raise a ValueError exception if we find something unexpected
            #
            if attr_len != 1:
                raise ValueError("BGP ORIGIN attr_len %d wrong, expected 1" %
                                 attr_len)
            if update[offset] not in ORIGIN_STR:
                raise ValueError("BGP ORIGIN value %d wrong" % update[offset])
            print_msg.append("%s%s %s\n" %
                             (indent_str, ATTR_TYPE_STR[attr_type],
                              ORIGIN_STR[update[offset]]))

        # AS_PATH (Autonomous System path)
        #
        elif attr_type == ATTR_TYPE_AS_PATH:
            print_msg.append("%s%s " % (indent_str, ATTR_TYPE_STR[attr_type]))
            path_text = ParseBgpAsPath(update, offset, offset + attr_len,
                                       rfc4893_updates)
            print_msg.append("%s\n" % " ".join(path_text))

        # NEXT_HOP
        #
        elif attr_type == ATTR_TYPE_NEXT_HOP:
            next_hop = update[offset:offset + 4]
            print_msg.append("%s%s %s\n" %
                             (indent_str, ATTR_TYPE_STR[attr_type],
                              socket.inet_ntoa(next_hop)))

        # MED (Multi-Exit Discriminator)
        #
        elif attr_type == ATTR_TYPE_MULTI_EXIT_DISC:
            med_val = struct.unpack_from(">L", update, offset)[0]
            print_msg.append("%s%s %d\n" %
                             (indent_str, ATTR_TYPE_STR[attr_type], med_val))

        # LOCAL_PREF (Local Preference)
        #
        elif attr_type == ATTR_TYPE_LOCAL_PREF:
            pref_val = struct.unpack_from(">L", update, offset)[0]
            print_msg.append("%s%s %d\n" %
                             (indent_str, ATTR_TYPE_STR[attr_type], pref_val))

        # ATOMIC_AGGREGATE
        #
        elif attr_type == ATTR_TYPE_ATOMIC_AGGREGATE:
            if attr_len:
                raise ValueError(
                    "attr_len %d for ATOMIC_AGGREGATE must be zero" % attr_len)
            print_msg.append("%s%s\n" % (indent_str, ATTR_TYPE_STR[attr_type]))

        # COMMUNITIES
        #
        elif attr_type == ATTR_TYPE_COMMUNITIES:
            print_msg.append("%s%s " % (indent_str, ATTR_TYPE_STR[attr_type]))
            comm_text = ParseBgpCommunities(update, offset, offset + attr_len)
            print_msg.append("%s\n" % " ".join(comm_text))

        # MP_REACH
        #
        elif attr_type == ATTR_TYPE_MP_REACH_NLRI:
            print_msg.append("%s%s\n" % (indent_str, ATTR_TYPE_STR[attr_type]))
            mpattr_text = []
            try:
                mpattr_text = ParseBgpMpAttr(update, offset, offset + attr_len,
                                             True)
            except Exception, esc:
                if verbose:
                    print "".join(print_msg),
                    for x in range(offset, offset + attr_len):
                        print " %02x" % update[x],
            mp_indent = indent.IndentLevel(indent.BGP_MPATTR_INDENT)
            for mpattr in mpattr_text:
                print_msg.append("%s%s" % (mp_indent, mpattr))

        # MP_UNREACH
        #
        elif attr_type == ATTR_TYPE_MP_UNREACH_NLRI:
            print_msg.append("%s%s\n" % (indent_str, ATTR_TYPE_STR[attr_type]))
            mpattr_text = ParseBgpMpAttr(update, offset, offset + attr_len,
                                         False)
            mp_indent = indent.IndentLevel(indent.BGP_MPATTR_INDENT)
            for mpattr in mpattr_text:
                print_msg.append("%s%s" % (mp_indent, mpattr))