Construct update message with Outgoing-routes path attribute
        appropriately cloned/copied/updated.

def _construct_update(self, outgoing_route):
        """Construct update message with Outgoing-routes path attribute
        appropriately cloned/copied/updated.
        """
        update = None
        path = outgoing_route.path
        # Get copy of path's path attributes.
        pathattr_map = path.pathattr_map
        new_pathattr = []

        if path.is_withdraw:
            if isinstance(path, Ipv4Path):
                update = BGPUpdate(withdrawn_routes=[path.nlri])
                return update
            else:
                mpunreach_attr = BGPPathAttributeMpUnreachNLRI(
                    path.route_family.afi, path.route_family.safi, [path.nlri]
                )
                new_pathattr.append(mpunreach_attr)
        elif self.is_route_server_client:
            nlri_list = [path.nlri]
            new_pathattr.extend(pathattr_map.values())
        else:
            if self.is_route_reflector_client:
                # Append ORIGINATOR_ID attribute if not already exist.
                if BGP_ATTR_TYPE_ORIGINATOR_ID not in pathattr_map:
                    originator_id = path.source
                    if originator_id is None:
                        originator_id = self._common_conf.router_id
                    elif isinstance(path.source, Peer):
                        originator_id = path.source.ip_address
                    new_pathattr.append(
                        BGPPathAttributeOriginatorId(value=originator_id))

                # Preppend own CLUSTER_ID into CLUSTER_LIST attribute if exist.
                # Otherwise append CLUSTER_LIST attribute.
                cluster_lst_attr = pathattr_map.get(BGP_ATTR_TYPE_CLUSTER_LIST)
                if cluster_lst_attr:
                    cluster_list = list(cluster_lst_attr.value)
                    if self._common_conf.cluster_id not in cluster_list:
                        cluster_list.insert(0, self._common_conf.cluster_id)
                    new_pathattr.append(
                        BGPPathAttributeClusterList(cluster_list))
                else:
                    new_pathattr.append(
                        BGPPathAttributeClusterList(
                            [self._common_conf.cluster_id]))

            # Supported and un-supported/unknown attributes.
            origin_attr = None
            nexthop_attr = None
            as_path_attr = None
            as4_path_attr = None
            aggregator_attr = None
            as4_aggregator_attr = None
            extcomm_attr = None
            community_attr = None
            localpref_attr = None
            pmsi_tunnel_attr = None
            unknown_opttrans_attrs = None
            nlri_list = [path.nlri]

            if path.route_family.safi in (subaddr_family.IP_FLOWSPEC,
                                          subaddr_family.VPN_FLOWSPEC):
                # Flow Specification does not have next_hop.
                next_hop = []
            elif self.is_ebgp_peer():
                next_hop = self._session_next_hop(path)
                if path.is_local() and path.has_nexthop():
                    next_hop = path.nexthop
            else:
                next_hop = path.nexthop
                # RFC 4271 allows us to change next_hop
                # if configured to announce its own ip address.
                # Also if the BGP route is configured without next_hop,
                # we use path._session_next_hop() as next_hop.
                if (self._neigh_conf.is_next_hop_self
                        or (path.is_local() and not path.has_nexthop())):
                    next_hop = self._session_next_hop(path)
                    LOG.debug('using %s as a next_hop address instead'
                              ' of path.nexthop %s', next_hop, path.nexthop)

            nexthop_attr = BGPPathAttributeNextHop(next_hop)
            assert nexthop_attr, 'Missing NEXTHOP mandatory attribute.'

            if not isinstance(path, Ipv4Path):
                # We construct mpreach-nlri attribute.
                mpnlri_attr = BGPPathAttributeMpReachNLRI(
                    path.route_family.afi,
                    path.route_family.safi,
                    next_hop,
                    nlri_list
                )

            # ORIGIN Attribute.
            # According to RFC this attribute value SHOULD NOT be changed by
            # any other speaker.
            origin_attr = pathattr_map.get(BGP_ATTR_TYPE_ORIGIN)
            assert origin_attr, 'Missing ORIGIN mandatory attribute.'

            # AS_PATH Attribute.
            # Construct AS-path-attr using paths AS_PATH attr. with local AS as
            # first item.
            path_aspath = pathattr_map.get(BGP_ATTR_TYPE_AS_PATH)
            assert path_aspath, 'Missing AS_PATH mandatory attribute.'
            # Deep copy AS_PATH attr value
            as_path_list = path_aspath.path_seg_list
            # If this is a iBGP peer.
            if not self.is_ebgp_peer():
                # When a given BGP speaker advertises the route to an internal
                # peer, the advertising speaker SHALL NOT modify the AS_PATH
                # attribute associated with the route.
                pass
            else:
                # When a given BGP speaker advertises the route to an external
                # peer, the advertising speaker updates the AS_PATH attribute
                # as follows:
                # 1) if the first path segment of the AS_PATH is of type
                #    AS_SEQUENCE, the local system prepends its own AS num as
                #    the last element of the sequence (put it in the left-most
                #    position with respect to the position of  octets in the
                #    protocol message).  If the act of prepending will cause an
                #    overflow in the AS_PATH segment (i.e.,  more than 255
                #    ASes), it SHOULD prepend a new segment of type AS_SEQUENCE
                #    and prepend its own AS number to this new segment.
                #
                # 2) if the first path segment of the AS_PATH is of type AS_SET
                #    , the local system prepends a new path segment of type
                #    AS_SEQUENCE to the AS_PATH, including its own AS number in
                #    that segment.
                #
                # 3) if the AS_PATH is empty, the local system creates a path
                #    segment of type AS_SEQUENCE, places its own AS into that
                #    segment, and places that segment into the AS_PATH.
                if (len(as_path_list) > 0 and
                        isinstance(as_path_list[0], list) and
                        len(as_path_list[0]) < 255):
                    as_path_list[0].insert(0, self.local_as)
                else:
                    as_path_list.insert(0, [self.local_as])
            # Construct AS4_PATH list from AS_PATH list and swap
            # non-mappable AS number with AS_TRANS in AS_PATH.
            as_path_list, as4_path_list = self._trans_as_path(
                as_path_list)
            # If the neighbor supports Four-Octet AS number, send AS_PATH
            # in Four-Octet.
            if self.is_four_octet_as_number_cap_valid():
                as_path_attr = BGPPathAttributeAsPath(
                    as_path_list, as_pack_str='!I')  # specify Four-Octet.
            # Otherwise, send AS_PATH in Two-Octet.
            else:
                as_path_attr = BGPPathAttributeAsPath(as_path_list)
            # If needed, send AS4_PATH attribute.
            if as4_path_list:
                as4_path_attr = BGPPathAttributeAs4Path(as4_path_list)

            # AGGREGATOR Attribute.
            aggregator_attr = pathattr_map.get(BGP_ATTR_TYPE_AGGREGATOR)
            # If the neighbor does not support Four-Octet AS number,
            # swap non-mappable AS number with AS_TRANS.
            if (aggregator_attr and
                    not self.is_four_octet_as_number_cap_valid()):
                # If AS number of AGGREGATOR is Four-Octet AS number,
                # swap with AS_TRANS, else do not.
                aggregator_as_number = aggregator_attr.as_number
                if not is_valid_old_asn(aggregator_as_number):
                    aggregator_attr = bgp.BGPPathAttributeAggregator(
                        bgp.AS_TRANS, aggregator_attr.addr)
                    as4_aggregator_attr = bgp.BGPPathAttributeAs4Aggregator(
                        aggregator_as_number, aggregator_attr.addr)

            # MULTI_EXIT_DISC Attribute.
            # For eBGP session we can send multi-exit-disc if configured.
            multi_exit_disc = None
            if self.is_ebgp_peer():
                if self._neigh_conf.multi_exit_disc:
                    multi_exit_disc = BGPPathAttributeMultiExitDisc(
                        self._neigh_conf.multi_exit_disc
                    )
                else:
                    pass
            if not self.is_ebgp_peer():
                multi_exit_disc = pathattr_map.get(
                    BGP_ATTR_TYPE_MULTI_EXIT_DISC)

            # LOCAL_PREF Attribute.
            if not self.is_ebgp_peer():
                # For iBGP peers we are required to send local-pref attribute
                # for connected or local prefixes. We check if the path matches
                # attribute_maps and set local-pref value.
                # If the path doesn't match, we set default local-pref given
                # from the user. The default value is 100.
                localpref_attr = BGPPathAttributeLocalPref(
                    self._common_conf.local_pref)
                key = const.ATTR_MAPS_LABEL_DEFAULT

                if isinstance(path, (Vpnv4Path, Vpnv6Path)):
                    nlri = nlri_list[0]
                    rf = VRF_RF_IPV4 if isinstance(path, Vpnv4Path)\
                        else VRF_RF_IPV6
                    key = ':'.join([nlri.route_dist, rf])

                attr_type = AttributeMap.ATTR_LOCAL_PREF
                at_maps = self._attribute_maps.get(key, {})
                result = self._lookup_attribute_map(at_maps, attr_type, path)
                if result:
                    localpref_attr = result

            # COMMUNITY Attribute.
            community_attr = pathattr_map.get(BGP_ATTR_TYPE_COMMUNITIES)

            # EXTENDED COMMUNITY Attribute.
            # Construct ExtCommunity path-attr based on given.
            path_extcomm_attr = pathattr_map.get(
                BGP_ATTR_TYPE_EXTENDED_COMMUNITIES
            )
            if path_extcomm_attr:
                # SOO list can be configured per VRF and/or per Neighbor.
                # NeighborConf has this setting we add this to existing list.
                communities = path_extcomm_attr.communities
                if self._neigh_conf.soo_list:
                    # construct extended community
                    soo_list = self._neigh_conf.soo_list
                    subtype = 0x03
                    for soo in soo_list:
                        first, second = soo.split(':')
                        if '.' in first:
                            c = BGPIPv4AddressSpecificExtendedCommunity(
                                subtype=subtype,
                                ipv4_address=first,
                                local_administrator=int(second))
                        else:
                            c = BGPTwoOctetAsSpecificExtendedCommunity(
                                subtype=subtype,
                                as_number=int(first),
                                local_administrator=int(second))
                        communities.append(c)

                extcomm_attr = BGPPathAttributeExtendedCommunities(
                    communities=communities
                )

                pmsi_tunnel_attr = pathattr_map.get(
                    BGP_ATTR_TYEP_PMSI_TUNNEL_ATTRIBUTE
                )

            # UNKNOWN Attributes.
            # Get optional transitive path attributes
            unknown_opttrans_attrs = bgp_utils.get_unknown_opttrans_attr(path)

            # Ordering path attributes according to type as RFC says. We set
            # MPReachNLRI first as advised by experts as a new trend in BGP
            # implementation.
            if isinstance(path, Ipv4Path):
                new_pathattr.append(nexthop_attr)
            else:
                new_pathattr.append(mpnlri_attr)

            new_pathattr.append(origin_attr)
            new_pathattr.append(as_path_attr)
            if as4_path_attr:
                new_pathattr.append(as4_path_attr)
            if aggregator_attr:
                new_pathattr.append(aggregator_attr)
            if as4_aggregator_attr:
                new_pathattr.append(as4_aggregator_attr)
            if multi_exit_disc:
                new_pathattr.append(multi_exit_disc)
            if localpref_attr:
                new_pathattr.append(localpref_attr)
            if community_attr:
                new_pathattr.append(community_attr)
            if extcomm_attr:
                new_pathattr.append(extcomm_attr)
            if pmsi_tunnel_attr:
                new_pathattr.append(pmsi_tunnel_attr)
            if unknown_opttrans_attrs:
                new_pathattr.extend(unknown_opttrans_attrs.values())

        if isinstance(path, Ipv4Path):
            update = BGPUpdate(path_attributes=new_pathattr,
                               nlri=nlri_list)
        else:
            update = BGPUpdate(path_attributes=new_pathattr)
        return update