All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opendaylight.bgpcep.bgp.topology.provider.LinkstateTopologyBuilder Maven / Gradle / Ivy

There is a newer version: 0.22.6
Show newest version
/*
 * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */
package org.opendaylight.bgpcep.bgp.topology.provider;

import static java.util.Objects.requireNonNull;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.mdsal.binding.api.DataBroker;
import org.opendaylight.mdsal.binding.api.ReadWriteTransaction;
import org.opendaylight.mdsal.binding.api.WriteTransaction;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
import org.opendaylight.protocol.bgp.rib.RibReference;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.DomainName;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.Ipv4InterfaceIdentifier;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.Ipv6InterfaceIdentifier;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.LinkstateAddressFamily;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.LinkstateSubsequentAddressFamily;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.TopologyIdentifier;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.bgp.rib.rib.loc.rib.tables.routes.LinkstateRoutesCase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.ObjectType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.attribute.SrAdjIds;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.object.type.LinkCase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.object.type.NodeCase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.object.type.PrefixCase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.object.type.link._case.LinkDescriptors;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.LinkStateAttribute;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.link.state.attribute.LinkAttributesCase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.link.state.attribute.NodeAttributesCase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.link.state.attribute.PrefixAttributesCase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.link.state.attribute.link.attributes._case.LinkAttributes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.link.state.attribute.node.attributes._case.NodeAttributes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.link.state.attribute.prefix.attributes._case.PrefixAttributes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.routes.LinkstateRoutes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.routes.linkstate.routes.LinkstateRoute;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.routes.linkstate.routes.linkstate.route.Attributes1;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.prefix.state.SrPrefix;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.Attributes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.Tables;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.ext.rev200120.prefix.sid.tlv.Flags;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.ext.rev200120.prefix.sid.tlv.flags.IsisPrefixFlagsCase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.ext.rev200120.sid.label.index.SidLabelIndex;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.ext.rev200120.sid.label.index.sid.label.index.LocalLabelCase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.ext.rev200120.sid.label.index.sid.label.index.SidCase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.odl.bgp.topology.types.rev160524.TopologyTypes1Builder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.odl.bgp.topology.types.rev160524.bgp.linkstate.topology.type.BgpLinkstateTopologyBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.SegmentId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.sr.node.attributes.Segments;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.sr.node.attributes.SegmentsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.sr.node.attributes.SegmentsKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.sr.node.attributes.segments.segment.specification.AdjacencyCaseBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.sr.node.attributes.segments.segment.specification.PrefixCaseBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.sr.node.attributes.segments.segment.specification.adjacency._case.AdjacencyBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.topology.sr.type.TopologySrBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.LinkId;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.DestinationBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.SourceBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.LinkBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.LinkKey;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.TopologyTypes;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.TopologyTypesBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.Link1Builder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.Node1;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.Node1Builder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.TerminationPoint1Builder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.link.attributes.IgpLinkAttributesBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.node.attributes.IgpNodeAttributes;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.node.attributes.IgpNodeAttributesBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.node.attributes.igp.node.attributes.Prefix;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.node.attributes.igp.node.attributes.PrefixBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.node.attributes.igp.node.attributes.PrefixKey;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.termination.point.attributes.IgpTerminationPointAttributesBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.termination.point.attributes.igp.termination.point.attributes.TerminationPointType;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.termination.point.attributes.igp.termination.point.attributes.termination.point.type.IpBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.termination.point.attributes.igp.termination.point.attributes.termination.point.type.UnnumberedBuilder;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.util.BindingMap;
import org.opendaylight.yangtools.yang.common.Uint32;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LinkstateTopologyBuilder extends AbstractTopologyBuilder {
    @VisibleForTesting
    static final TopologyTypes LINKSTATE_TOPOLOGY_TYPE = new TopologyTypesBuilder()
            .addAugmentation(new TopologyTypes1Builder()
                    .setBgpLinkstateTopology(new BgpLinkstateTopologyBuilder().build()).build()).build();
    @VisibleForTesting
    static final TopologyTypes SR_AWARE_LINKSTATE_TOPOLOGY_TYPE = new TopologyTypesBuilder(LINKSTATE_TOPOLOGY_TYPE)
            .addAugmentation(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819
                .TopologyTypes1Builder().setTopologySr(new TopologySrBuilder().build()).build())
            .build();

    private static final String UNHANDLED_OBJECT_CLASS = "Unhandled object class {}";

    private static final class TpHolder {
        private final Set local = new HashSet<>();
        private final Set remote = new HashSet<>();

        private final TerminationPoint tp;

        TpHolder(final TerminationPoint tp) {
            this.tp = requireNonNull(tp);
        }

        synchronized void addLink(final LinkId id, final boolean isRemote) {
            if (isRemote) {
                remote.add(id);
            } else {
                local.add(id);
            }
        }

        synchronized boolean removeLink(final LinkId id, final boolean isRemote) {
            final boolean removed;
            if (isRemote) {
                removed = remote.remove(id);
            } else {
                removed = local.remove(id);
            }
            if (!removed) {
                LOG.warn("Removed non-reference link {} from TP {} isRemote {}", tp.getTpId().getValue(),
                        id.getValue(), isRemote);
            }

            return local.isEmpty() && remote.isEmpty();
        }

        TerminationPoint getTp() {
            return tp;
        }
    }

    private final class NodeHolder {
        private final Map prefixes = new HashMap<>();
        private final Map tps = new HashMap<>();
        private boolean advertized = false;
        private IgpNodeAttributesBuilder inab;
        private NodeBuilder nb;
        private NodeSrHolder sr;

        NodeHolder(final NodeId id) {
            inab = new IgpNodeAttributesBuilder();
            nb = new NodeBuilder().withKey(new NodeKey(id)).setNodeId(id);
        }

        /**
         * Synchronized in-core state of a node into the backing store using the transaction.
         *
         * @param trans data modification transaction which to use
         * @return True if the node has been purged, false otherwise.
         */
        boolean syncState(final WriteTransaction trans) {
            final InstanceIdentifier nid = getNodeInstanceIdentifier(nb.key());

            /*
             * Transaction's putOperationalData() does a merge. Force it onto a replace
             * by removing the data. If we decide to remove the node -- we just skip the put.
             */
            trans.delete(LogicalDatastoreType.OPERATIONAL, nid);

            if (!advertized) {
                if (tps.isEmpty() && prefixes.isEmpty()) {
                    LOG.trace("Removing unadvertized unused node {}", nb.getNodeId().getValue());
                    return true;
                }

                LOG.trace("Node {} is still implied by {} TPs and {} prefixes", nb.getNodeId().getValue(),
                        tps.size(), prefixes.size());
            }

            // Re-generate termination points
            nb.setTerminationPoint(BindingMap.ordered(Collections2.transform(tps.values(), TpHolder::getTp)));

            // Re-generate prefixes
            inab.setPrefix(BindingMap.ordered(prefixes.values()));

            // Write the node out
            if (sr != null && sr.getSegmentCount() > 0) {
                nb.addAugmentation(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr
                    .rev130819.Node1Builder().setSegments(BindingMap.ordered(sr.getSegments())).build());
            }
            final Node n = nb
                    .addAugmentation(new Node1Builder().setIgpNodeAttributes(inab.build()).build())
                    .build();
            trans.put(LogicalDatastoreType.OPERATIONAL, nid, n);
            LOG.trace("Created node {} at {}", n, nid);
            return false;
        }

        boolean checkForRemoval(final WriteTransaction trans) {
            final InstanceIdentifier nid = getNodeInstanceIdentifier(nb.key());

            if (!advertized) {
                if (tps.isEmpty() && prefixes.isEmpty()) {
                    trans.delete(LogicalDatastoreType.OPERATIONAL, nid);
                    LOG.trace("Removing unadvertized unused node {}", nb.getNodeId().getValue());
                    return true;
                }

                LOG.trace("Node {} is still implied by {} TPs and {} prefixes", nb.getNodeId().getValue(),
                        tps.size(), prefixes.size());
            }
            return false;
        }

        synchronized void removeTp(final TpId tp, final LinkId link, final boolean isRemote) {
            final TpHolder h = tps.get(tp);
            if (h != null) {
                if (h.removeLink(link, isRemote)) {
                    tps.remove(tp);
                    LOG.trace("Removed TP {}", tp.getValue());
                }
            } else {
                LOG.warn("Removed non-present TP {} by link {}", tp.getValue(), link.getValue());
            }
        }

        void addTp(final TerminationPoint tp, final LinkId link, final boolean isRemote) {
            final TpHolder h = tps.computeIfAbsent(tp.getTpId(), k -> new TpHolder(tp));
            h.addLink(link, isRemote);
        }

        void addPrefix(final Prefix pfx) {
            prefixes.put(pfx.key(), pfx);
        }

        void removePrefix(final PrefixCase prefixCase) {
            prefixes.remove(new PrefixKey(prefixCase.getPrefixDescriptors().getIpReachabilityInformation()));
        }

        void unadvertized() {
            inab = new IgpNodeAttributesBuilder();
            nb = new NodeBuilder().withKey(nb.key()).setNodeId(nb.getNodeId());
            advertized = false;
            LOG.debug("Node {} is unadvertized", nb.getNodeId().getValue());
        }

        void advertized(final NodeBuilder nodeBuilder, final IgpNodeAttributesBuilder igpNodeAttBuilder) {
            nb = requireNonNull(nodeBuilder);
            inab = requireNonNull(igpNodeAttBuilder);
            advertized = true;
            LOG.debug("Node {} is advertized", nodeBuilder.getNodeId().getValue());
        }

        NodeId getNodeId() {
            return nb.getNodeId();
        }

        NodeSrHolder getSrHolder() {
            return sr;
        }

        NodeSrHolder createSrHolderIfRequired() {
            if (sr == null) {
                sr = new NodeSrHolder(nb.getNodeId());
            }
            return sr;
        }
    }

    private final class NodeSrHolder {
        private final NodeId nodeId;
        private Long srgbFirstValue = null;
        private Integer srgbRangeSize = null;
        private final List segments = new ArrayList<>();
        private final Map srPrefixes = new HashMap<>();
        private final Map prefixSegments = new HashMap<>();
        private final Map adjSegments = new HashMap<>();

        NodeSrHolder(final NodeId nodeId) {
            this.nodeId = nodeId;
        }

        void addSrgb(final WriteTransaction trans, final boolean updateNode, final Long srgbFirstVal,
                final Integer srgbRangeSz) {
            srgbFirstValue = srgbFirstVal;
            srgbRangeSize = srgbRangeSz;
            srPrefixes.entrySet().forEach(entry -> {
                final IpPrefix ippfx = entry.getKey();
                final SrPrefix srPrefix = entry.getValue();
                final SidLabelIndex sidLabelIndex = srPrefix.getSidLabelIndex();
                if (sidLabelIndex instanceof SidCase) {
                    final Long sidIndex = ((SidCase) sidLabelIndex).getSid().longValue();
                    if (sidIndex >= srgbRangeSize) {
                        LOG.warn("Prefix SID index {} is outside the SRGB range of {} for node {}", sidIndex,
                                srgbRangeSize, nodeId.getValue());
                        return;
                    }
                    final Long prefixSid = srgbFirstValue + sidIndex;
                    final boolean isNodeSid = isAssociatedWithNodeSid(ippfx, srPrefix);
                    addPrefixSid(trans, updateNode, ippfx, prefixSid, isNodeSid);
                }
            });
        }

        void removeSrgb(final WriteTransaction trans) {
            srgbFirstValue = null;
            srgbRangeSize = null;
            srPrefixes.entrySet().forEach(entry -> {
                final IpPrefix ippfx = entry.getKey();
                final SrPrefix srPrefix = entry.getValue();
                final SidLabelIndex sidLabelIndex = srPrefix.getSidLabelIndex();
                if (sidLabelIndex instanceof SidCase) {
                    removePrefixSid(trans, false, ippfx);
                }
            });
        }

        void addSrPrefix(final WriteTransaction trans, final boolean updateNode, final IpPrefix ippfx,
                final SrPrefix srPrefix) {
            srPrefixes.put(ippfx, srPrefix);
            final SidLabelIndex sidLabelIndex = srPrefix.getSidLabelIndex();
            Long prefixSid = null;
            if (sidLabelIndex instanceof LocalLabelCase) {
                prefixSid = ((LocalLabelCase) sidLabelIndex).getLocalLabel().getValue().longValue();
            } else if (sidLabelIndex instanceof SidCase) {
                if (srgbFirstValue != null && srgbRangeSize != null) {
                    final Long sidIndex = ((SidCase) sidLabelIndex).getSid().longValue();
                    if (sidIndex >= srgbRangeSize) {
                        LOG.warn("Prefix SID index {} is outside the SRGB range of {} for node {}", sidIndex,
                                srgbRangeSize, nodeId.getValue());
                        return;
                    }
                    prefixSid = srgbFirstValue + sidIndex;
                }
            }
            if (prefixSid != null) {
                final boolean isNodeSid = isAssociatedWithNodeSid(ippfx, srPrefix);
                addPrefixSid(trans, updateNode, ippfx, prefixSid, isNodeSid);
            }
        }

        void removeSrPrefix(final WriteTransaction trans, final IpPrefix ippfx) {
            if (!srPrefixes.containsKey(ippfx)) {
                return;
            }
            removePrefixSid(trans, true, ippfx);
            srPrefixes.remove(ippfx);
        }

        void addPrefixSid(final WriteTransaction trans, final boolean updateNode, final IpPrefix ippfx,
                final Long prefixSid, final boolean isNodeSid) {
            LOG.trace("Adding prefix SID {} for prefix {} on node {}", prefixSid, ippfx.stringValue(),
                    nodeId.getValue());
            final SegmentId segmentId = new SegmentId(Uint32.valueOf(prefixSid));
            final Segments prefixSegment = new SegmentsBuilder()
                    .setSegmentId(segmentId)
                    .withKey(new SegmentsKey(segmentId))
                    .setSegmentSpecification(new PrefixCaseBuilder()
                        .setPrefix(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr
                            .rev130819.sr.node.attributes.segments.segment.specification.prefix._case.PrefixBuilder()
                                .setPrefix(ippfx).setNodeSid(isNodeSid ? isNodeSid : null).build())
                        .build())
                    .build();
            prefixSegments.put(ippfx, prefixSegment);
            segments.add(prefixSegment);
            addSegment(trans, updateNode, prefixSegment);
        }

        void removePrefixSid(final WriteTransaction trans, final boolean updateNode, final IpPrefix ippfx) {
            if (!prefixSegments.containsKey(ippfx)) {
                return;
            }
            LOG.trace("Removing prefix SID for prefix {} on node {}", ippfx.stringValue(),
                    nodeId.getValue());
            final Segments prefixSegment = prefixSegments.remove(ippfx);
            segments.remove(prefixSegment);
            removeSegment(trans, updateNode, prefixSegment);
        }

        void addAdjacencySid(final WriteTransaction trans, final boolean updateNode, final LinkId linkId,
                final Long adjSid) {
            LOG.trace("Adding adjacency SID {} for link {} on node {}", adjSid, linkId.getValue(),
                    nodeId.getValue());
            final SegmentId segmentId = new SegmentId(Uint32.valueOf(adjSid));
            final SegmentsBuilder sb = new SegmentsBuilder();
            sb.setSegmentId(segmentId);
            sb.withKey(new SegmentsKey(segmentId));
            sb.setSegmentSpecification(new AdjacencyCaseBuilder()
                    .setAdjacency(new AdjacencyBuilder().setAdjacency(linkId).build()).build());
            final Segments adjSegment = sb.build();
            adjSegments.put(linkId, adjSegment);
            segments.add(adjSegment);
            addSegment(trans, updateNode, adjSegment);
        }

        void removeAdjacencySid(final WriteTransaction trans, final LinkId linkId) {
            if (!adjSegments.containsKey(linkId)) {
                return;
            }
            LOG.trace("Removing adjacency SID for link {} on node {}", linkId.getValue(),
                    nodeId.getValue());
            final Segments adjSegment = adjSegments.remove(linkId);
            segments.remove(adjSegment);
            removeSegment(trans, true, adjSegment);
        }

        void addSegment(final WriteTransaction trans, final boolean updateNode, final Segments segment) {
            if (updateNode) {
                final InstanceIdentifier nodeIId = getNodeInstanceIdentifier(new NodeKey(nodeId));
                final InstanceIdentifier segmentIId = nodeIId.builder()
                        .augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr
                            .rev130819.Node1.class)
                        .child(Segments.class, segment.key()).build();
                trans.put(LogicalDatastoreType.OPERATIONAL, segmentIId, segment);
            }
            addSrAwareTopologyType(trans);
        }

        void removeSegment(final WriteTransaction trans, final boolean updateNode, final Segments segment) {
            if (updateNode) {
                final InstanceIdentifier nodeIId = getNodeInstanceIdentifier(new NodeKey(nodeId));
                final InstanceIdentifier segmentIId = nodeIId.builder()
                        .augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr
                            .rev130819.Node1.class)
                        .child(Segments.class, segment.key()).build();
                trans.delete(LogicalDatastoreType.OPERATIONAL, segmentIId);
            }
            removeSrAwareTopologyTypeIfRequired(trans);
        }

        boolean isAssociatedWithNodeSid(final IpPrefix ippfx, final SrPrefix srPrefix) {
            if (ippfx.getIpv4Prefix() != null && !ippfx.stringValue().endsWith("/32")
                    || ippfx.getIpv6Prefix() != null && !ippfx.stringValue().endsWith("/128")) {
                return false;
            }
            final Flags prefixFlags = srPrefix.getFlags();
            if (prefixFlags instanceof IsisPrefixFlagsCase) {
                return !Boolean.FALSE.equals(((IsisPrefixFlagsCase) prefixFlags).getIsisPrefixFlags().getNodeSid());
            }
            return true;
        }

        List getSegments() {
            return segments;
        }

        int getSegmentCount() {
            return segments.size();
        }
    }

    private static final Logger LOG = LoggerFactory.getLogger(LinkstateTopologyBuilder.class);
    private final Map nodes = new HashMap<>();
    private boolean srAwareTopologyTypeAdded;

    public LinkstateTopologyBuilder(final DataBroker dataProvider, final RibReference locRibReference,
            final TopologyId topologyId) {
        super(dataProvider, locRibReference, topologyId, LINKSTATE_TOPOLOGY_TYPE, LinkstateAddressFamily.VALUE,
                LinkstateSubsequentAddressFamily.VALUE);
    }

    @VisibleForTesting
    LinkstateTopologyBuilder(final DataBroker dataProvider, final RibReference locRibReference,
            final TopologyId topologyId, final long listenerResetLimitInMillsec,
            final int listenerResetEnforceCounter) {
        super(dataProvider, locRibReference, topologyId, LINKSTATE_TOPOLOGY_TYPE, LinkstateAddressFamily.VALUE,
                LinkstateSubsequentAddressFamily.VALUE,
                listenerResetLimitInMillsec, listenerResetEnforceCounter);
    }

    private static @NonNull LinkId buildLinkId(final UriBuilder base, final LinkCase link) {
        return new LinkId(new UriBuilder(base, "link").add(link).toString());
    }

    private static NodeId buildNodeId(final UriBuilder base, final org.opendaylight.yang.gen.v1.urn.opendaylight
            .params.xml.ns.yang.bgp.linkstate.rev200120.NodeIdentifier node) {
        return new NodeId(new UriBuilder(base, "node").addPrefix("", node).toString());
    }

    private static TpId buildTpId(final UriBuilder base, final TopologyIdentifier topologyIdentifier,
            final Ipv4InterfaceIdentifier ipv4InterfaceIdentifier,
            final Ipv6InterfaceIdentifier ipv6InterfaceIdentifier, final Uint32 id) {
        final UriBuilder b = new UriBuilder(base, "tp");
        if (topologyIdentifier != null) {
            b.add("mt", topologyIdentifier.getValue());
        }
        if (ipv4InterfaceIdentifier != null) {
            b.add("ipv4", ipv4InterfaceIdentifier.getValue());
        }
        if (ipv6InterfaceIdentifier != null) {
            b.add("ipv6", ipv6InterfaceIdentifier.getValue());
        }

        return new TpId(b.add("id", id).toString());
    }

    private static TpId buildLocalTpId(final UriBuilder base, final LinkDescriptors linkDescriptors) {
        return buildTpId(base, linkDescriptors.getMultiTopologyId(), linkDescriptors.getIpv4InterfaceAddress(),
                linkDescriptors.getIpv6InterfaceAddress(), linkDescriptors.getLinkLocalIdentifier());
    }

    private static TerminationPoint buildTp(final TpId id, final TerminationPointType type) {
        final TerminationPointBuilder stpb = new TerminationPointBuilder();
        stpb.withKey(new TerminationPointKey(id));
        stpb.setTpId(id);

        if (type != null) {
            stpb.addAugmentation(new TerminationPoint1Builder()
                    .setIgpTerminationPointAttributes(new IgpTerminationPointAttributesBuilder()
                        .setTerminationPointType(type)
                        .build())
                    .build());
        }

        return stpb.build();
    }

    private static TerminationPointType getTpType(final Ipv4InterfaceIdentifier ipv4InterfaceIdentifier,
            final Ipv6InterfaceIdentifier ipv6InterfaceIdentifier, final Uint32 id) {
        // Order of preference: Unnumbered first, then IP
        if (id != null) {
            LOG.debug("Unnumbered termination point type: {}", id);
            return new UnnumberedBuilder().setUnnumberedId(id).build();
        }

        final IpAddress ip;
        if (ipv6InterfaceIdentifier != null) {
            ip = new IpAddress(ipv6InterfaceIdentifier);
        } else if (ipv4InterfaceIdentifier != null) {
            ip = new IpAddress(ipv4InterfaceIdentifier);
        } else {
            ip = null;
        }

        if (ip != null) {
            LOG.debug("IP termination point type: {}", ip);
            return new IpBuilder().setIpAddress(Set.of(ip)).build();
        }

        return null;
    }

    private static TerminationPoint buildLocalTp(final UriBuilder base, final LinkDescriptors linkDescriptors) {
        final TpId id = buildLocalTpId(base, linkDescriptors);
        final TerminationPointType t = getTpType(linkDescriptors.getIpv4InterfaceAddress(),
                linkDescriptors.getIpv6InterfaceAddress(),
                linkDescriptors.getLinkLocalIdentifier());

        return buildTp(id, t);
    }

    private static TpId buildRemoteTpId(final UriBuilder base, final LinkDescriptors linkDescriptors) {
        return buildTpId(base, linkDescriptors.getMultiTopologyId(), linkDescriptors.getIpv4NeighborAddress(),
                linkDescriptors.getIpv6NeighborAddress(), linkDescriptors.getLinkRemoteIdentifier());
    }

    private static TerminationPoint buildRemoteTp(final UriBuilder base, final LinkDescriptors linkDescriptors) {
        final TpId id = buildRemoteTpId(base, linkDescriptors);
        final TerminationPointType t = getTpType(linkDescriptors.getIpv4NeighborAddress(),
                linkDescriptors.getIpv6NeighborAddress(),
                linkDescriptors.getLinkRemoteIdentifier());

        return buildTp(id, t);
    }

    private @NonNull InstanceIdentifier buildLinkIdentifier(final LinkId id) {
        return getInstanceIdentifier().child(
                org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology
                        .topology.Link.class, new LinkKey(id));
    }

    private NodeHolder getNode(final NodeId id) {
        return nodes.computeIfAbsent(id, NodeHolder::new);
    }

    private void putNode(final WriteTransaction trans, final NodeHolder holder) {
        if (holder.syncState(trans)) {
            nodes.remove(holder.getNodeId());
        }
    }

    private void checkNodeForRemoval(final WriteTransaction trans, final NodeHolder holder) {
        if (holder.checkForRemoval(trans)) {
            nodes.remove(holder.getNodeId());
        }
    }

    private void createLink(final WriteTransaction trans, final UriBuilder base,
            final LinkstateRoute value, final LinkCase linkCase, final Attributes attributes) {
        // defensive lookup
        final LinkAttributes la;
        final Attributes1 attr = attributes.augmentation(Attributes1.class);
        if (attr != null) {
            final LinkStateAttribute attrType = attr.getLinkStateAttribute();
            if (attrType != null) {
                la = ((LinkAttributesCase)attrType).getLinkAttributes();
            } else {
                LOG.debug("Missing attribute type in link {} route {}, skipping it", linkCase, value);
                la = null;
            }
        } else {
            LOG.debug("Missing attributes in link {} route {}, skipping it", linkCase, value);
            la = null;
        }

        final IgpLinkAttributesBuilder ilab = new IgpLinkAttributesBuilder();
        Long adjSid = null;
        if (la != null) {
            if (la.getMetric() != null) {
                ilab.setMetric(la.getMetric().getValue());
            }
            ilab.setName(la.getLinkName());
            if (la.getSrAdjIds() != null && !la.getSrAdjIds().isEmpty()) {
                final SrAdjIds srAdjIds = la.getSrAdjIds().get(0);
                if (srAdjIds != null) {
                    final SidLabelIndex sidLabelIndex = srAdjIds.getSidLabelIndex();
                    if (sidLabelIndex instanceof LocalLabelCase) {
                        adjSid = ((LocalLabelCase) sidLabelIndex).getLocalLabel().getValue().longValue();
                    }
                }
            }
        }
        ProtocolUtil.augmentProtocolId(value, ilab, la, linkCase.getLinkDescriptors());

        final LinkBuilder lb = new LinkBuilder()
                .setLinkId(buildLinkId(base, linkCase))
                .addAugmentation(new Link1Builder().setIgpLinkAttributes(ilab.build()).build());

        final NodeId srcNode = buildNodeId(base, linkCase.getLocalNodeDescriptors());
        LOG.trace("Link {} implies source node {}", linkCase, srcNode);

        final NodeId dstNode = buildNodeId(base, linkCase.getRemoteNodeDescriptors());
        LOG.trace("Link {} implies destination node {}", linkCase, dstNode);

        final TerminationPoint srcTp = buildLocalTp(base, linkCase.getLinkDescriptors());
        LOG.trace("Link {} implies source TP {}", linkCase, srcTp);

        final TerminationPoint dstTp = buildRemoteTp(base, linkCase.getLinkDescriptors());
        LOG.trace("Link {} implies destination TP {}", linkCase, dstTp);

        lb.setSource(new SourceBuilder().setSourceNode(srcNode).setSourceTp(srcTp.getTpId()).build());
        lb.setDestination(new DestinationBuilder().setDestNode(dstNode).setDestTp(dstTp.getTpId()).build());

        LOG.trace("Created TP {} as link source", srcTp);
        NodeHolder snh = nodes.get(srcNode);
        if (snh == null) {
            snh = getNode(srcNode);
            snh.addTp(srcTp, lb.getLinkId(), false);
            if (adjSid != null) {
                snh.createSrHolderIfRequired().addAdjacencySid(trans, false, lb.getLinkId(), adjSid);
            }
            putNode(trans, snh);
        } else {
            snh.addTp(srcTp, lb.getLinkId(), false);
            if (adjSid != null) {
                snh.createSrHolderIfRequired().addAdjacencySid(trans, true, lb.getLinkId(), adjSid);
            }
            final InstanceIdentifier nid = getNodeInstanceIdentifier(new NodeKey(snh.getNodeId()));
            trans.put(LogicalDatastoreType.OPERATIONAL, nid.child(TerminationPoint.class, srcTp.key()), srcTp);
        }
        if (adjSid != null) {
            lb.addAugmentation(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr
                .rev130819.Link1Builder().setSegment(new SegmentId(Uint32.valueOf(adjSid))).build());
        }

        LOG.debug("Created TP {} as link destination", dstTp);
        NodeHolder dnh = nodes.get(dstNode);
        if (dnh == null) {
            dnh = getNode(dstNode);
            dnh.addTp(dstTp, lb.getLinkId(), true);
            putNode(trans, dnh);
        } else {
            dnh.addTp(dstTp, lb.getLinkId(), true);
            final InstanceIdentifier nid = getInstanceIdentifier().child(
                    org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network
                            .topology.topology.Node.class, new NodeKey(dnh.getNodeId()));
            trans.put(LogicalDatastoreType.OPERATIONAL, nid.child(TerminationPoint.class, dstTp.key()), dstTp);
        }

        final InstanceIdentifier lid = buildLinkIdentifier(lb.getLinkId());
        final Link link = lb.build();

        trans.put(LogicalDatastoreType.OPERATIONAL, lid, link);
        LOG.debug("Created link {} at {} for {}", link, lid, linkCase);
    }

    private void removeTp(final WriteTransaction trans, final NodeId node, final TpId tp,
            final LinkId link, final boolean isRemote) {
        final NodeHolder nh = nodes.get(node);
        if (nh != null) {
            final InstanceIdentifier nid = getNodeInstanceIdentifier(new NodeKey(nh.getNodeId()));
            trans.delete(LogicalDatastoreType.OPERATIONAL, nid.child(TerminationPoint.class,
                    new TerminationPointKey(tp)));
            nh.removeTp(tp, link, isRemote);
            if (!isRemote) {
                nh.createSrHolderIfRequired().removeAdjacencySid(trans, link);
            }
            checkNodeForRemoval(trans, nh);
        } else {
            LOG.warn("Removed non-existent node {}", node.getValue());
        }
    }

    private void removeLink(final WriteTransaction trans, final UriBuilder base, final LinkCase linkCase) {
        final var id = buildLinkId(base, linkCase);
        final InstanceIdentifier lid = buildLinkIdentifier(id);
        trans.delete(LogicalDatastoreType.OPERATIONAL, lid);
        LOG.debug("Removed link {}", lid);

        removeTp(trans, buildNodeId(base, linkCase.getLocalNodeDescriptors()),
                buildLocalTpId(base, linkCase.getLinkDescriptors()), id, false);
        removeTp(trans, buildNodeId(base, linkCase.getRemoteNodeDescriptors()),
                buildRemoteTpId(base, linkCase.getLinkDescriptors()), id, true);
    }

    private void createNode(final WriteTransaction trans, final UriBuilder base,
            final LinkstateRoute value, final NodeCase nodeCase, final Attributes attributes) {
        final NodeAttributes na;
        //defensive lookup
        final Attributes1 attr = attributes.augmentation(Attributes1.class);
        if (attr != null) {
            final LinkStateAttribute attrType = attr.getLinkStateAttribute();
            if (attrType != null) {
                na = ((NodeAttributesCase)attrType).getNodeAttributes();
            } else {
                LOG.debug("Missing attribute type in node {} route {}, skipping it", nodeCase, value);
                na = null;
            }
        } else {
            LOG.debug("Missing attributes in node {} route {}, skipping it", nodeCase, value);
            na = null;
        }
        final IgpNodeAttributesBuilder inab = new IgpNodeAttributesBuilder();
        final var idsBuilder = ImmutableSet.builder();
        Long srgbFirstValue = null;
        Integer srgbRangeSize = null;
        if (na != null) {
            if (na.getIpv4RouterId() != null) {
                idsBuilder.add(new IpAddress(na.getIpv4RouterId()));
            }
            if (na.getIpv6RouterId() != null) {
                idsBuilder.add(new IpAddress(na.getIpv6RouterId()));
            }
            if (na.getDynamicHostname() != null) {
                inab.setName(new DomainName(na.getDynamicHostname()));
            }
            if (na.getSrCapabilities() != null) {
                final SidLabelIndex sidLabelIndex = na.getSrCapabilities().getSidLabelIndex();
                if (sidLabelIndex instanceof LocalLabelCase) {
                    srgbFirstValue = ((LocalLabelCase) sidLabelIndex).getLocalLabel().getValue().longValue();
                }
                srgbRangeSize = na.getSrCapabilities().getRangeSize() != null
                        ? na.getSrCapabilities().getRangeSize().getValue().intValue()
                        : null;
            }
        }
        final var ids = idsBuilder.build();
        if (!ids.isEmpty()) {
            inab.setRouterId(ids);
        }
        ProtocolUtil.augmentProtocolId(value, inab, na, nodeCase.getNodeDescriptors());

        final NodeId nid = buildNodeId(base, nodeCase.getNodeDescriptors());
        final NodeHolder nh = getNode(nid);
        /*
         *  Eventhough the the holder creates a dummy structure, we need to duplicate it here,
         *  as that is the API requirement. The reason for it is the possible presence of supporting
         *  node -- something which the holder does not track.
         */
        final NodeBuilder nb = new NodeBuilder();
        nb.setNodeId(nid);
        nb.withKey(new NodeKey(nb.getNodeId()));

        nh.advertized(nb, inab);
        if (srgbFirstValue != null && srgbRangeSize != null) {
            nh.createSrHolderIfRequired().addSrgb(trans, false, srgbFirstValue, srgbRangeSize);
        }
        putNode(trans, nh);
    }

    private void removeNode(final WriteTransaction trans, final UriBuilder base, final NodeCase nodeCase) {
        final NodeId id = buildNodeId(base, nodeCase.getNodeDescriptors());
        final NodeHolder nh = nodes.get(id);
        if (nh != null) {
            nh.unadvertized();
            nh.createSrHolderIfRequired().removeSrgb(trans);
            putNode(trans, nh);
        } else {
            LOG.warn("Node {} does not have a holder", id.getValue());
        }
    }

    private void createPrefix(final WriteTransaction trans, final UriBuilder base,
            final LinkstateRoute value, final PrefixCase prefixCase, final Attributes attributes) {
        final IpPrefix ippfx = prefixCase.getPrefixDescriptors().getIpReachabilityInformation();
        if (ippfx == null) {
            LOG.warn("IP reachability not present in prefix {} route {}, skipping it", prefixCase, value);
            return;
        }
        final PrefixBuilder pb = new PrefixBuilder();
        final PrefixKey pk = new PrefixKey(ippfx);
        pb.withKey(pk);
        pb.setPrefix(ippfx);

        final PrefixAttributes pa;
        // Very defensive lookup
        final Attributes1 attr = attributes.augmentation(Attributes1.class);
        if (attr != null) {
            final LinkStateAttribute attrType = attr.getLinkStateAttribute();
            if (attrType != null) {
                pa = ((PrefixAttributesCase)attrType).getPrefixAttributes();
            } else {
                LOG.debug("Missing attribute type in IP {} prefix {} route {}, skipping it", ippfx, prefixCase, value);
                pa = null;
            }
        } else {
            LOG.debug("Missing attributes in IP {} prefix {} route {}, skipping it", ippfx, prefixCase, value);
            pa = null;
        }
        SrPrefix srPrefix = null;
        if (pa != null) {
            if (pa.getPrefixMetric() != null) {
                pb.setMetric(pa.getPrefixMetric().getValue());
            }
            if (pa.getSrPrefix() != null) {
                srPrefix = pa.getSrPrefix();
            }
        }
        ProtocolUtil.augmentProtocolId(value, pa, pb);

        final Prefix pfx = pb.build();
        LOG.debug("Created prefix {} for {}", pfx, prefixCase);

        /*
         * All set, but... the hosting node may not exist, we may need to fake it.
         */
        final NodeId node = buildNodeId(base, prefixCase.getAdvertisingNodeDescriptors());
        NodeHolder nh = nodes.get(node);
        if (nh == null) {
            nh = getNode(node);
            nh.addPrefix(pfx);
            if (srPrefix != null) {
                nh.createSrHolderIfRequired().addSrPrefix(trans, false, ippfx, srPrefix);
            }
            putNode(trans, nh);
        } else {
            nh.addPrefix(pfx);
            if (srPrefix != null) {
                nh.createSrHolderIfRequired().addSrPrefix(trans, true, ippfx, srPrefix);
            }
            final InstanceIdentifier nid = getNodeInstanceIdentifier(new NodeKey(nh.getNodeId()));
            final InstanceIdentifier inaId = nid.builder().augmentation(Node1.class)
                    .child(IgpNodeAttributes.class).build();
            trans.put(LogicalDatastoreType.OPERATIONAL, inaId.child(Prefix.class, pk), pfx);
        }
    }

    private void removePrefix(final WriteTransaction trans, final UriBuilder base, final PrefixCase prefixCase) {
        final NodeId node = buildNodeId(base, prefixCase.getAdvertisingNodeDescriptors());
        final NodeHolder nh = nodes.get(node);
        if (nh != null) {
            LOG.debug("Removed prefix {}", prefixCase);
            final InstanceIdentifier nid = getNodeInstanceIdentifier(new NodeKey(nh.getNodeId()));
            final InstanceIdentifier inaId = nid.builder().augmentation(Node1.class)
                    .child(IgpNodeAttributes.class).build();
            final IpPrefix ippfx = prefixCase.getPrefixDescriptors().getIpReachabilityInformation();
            if (ippfx == null) {
                LOG.warn("IP reachability not present in prefix {}, skipping it", prefixCase);
                return;
            }
            final PrefixKey pk = new PrefixKey(ippfx);
            trans.delete(LogicalDatastoreType.OPERATIONAL, inaId.child(Prefix.class, pk));
            nh.removePrefix(prefixCase);
            nh.createSrHolderIfRequired().removeSrPrefix(trans, ippfx);
            checkNodeForRemoval(trans, nh);
        } else {
            LOG.warn("Removing prefix from non-existing node {}", node.getValue());
        }
    }

    private InstanceIdentifier getNodeInstanceIdentifier(final NodeKey nodeKey) {
        return getInstanceIdentifier().child(
                org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network
                        .topology.topology.Node.class, nodeKey);
    }

    protected void addSrAwareTopologyType(final WriteTransaction trans) {
        if (srAwareTopologyTypeAdded) {
            return;
        }
        LOG.debug("Adding SR-aware topology-type for topology {}",
                getInstanceIdentifier().firstKeyOf(Topology.class).getTopologyId().getValue());
        trans.put(LogicalDatastoreType.OPERATIONAL, getInstanceIdentifier().child(TopologyTypes.class),
                SR_AWARE_LINKSTATE_TOPOLOGY_TYPE);
        srAwareTopologyTypeAdded = true;
    }

    protected void removeSrAwareTopologyTypeIfRequired(final WriteTransaction trans) {
        if (!srAwareTopologyTypeAdded) {
            return;
        }
        final boolean isSidPresent = nodes.values().stream().filter(nh -> nh.getSrHolder() != null)
                .map(nh -> nh.getSrHolder().getSegmentCount()).anyMatch(cnt -> cnt != 0);
        if (isSidPresent) {
            return;
        }
        LOG.debug("Removing SR-aware topology-type from topology {}",
                getInstanceIdentifier().firstKeyOf(Topology.class).getTopologyId().getValue());
        trans.put(LogicalDatastoreType.OPERATIONAL, getInstanceIdentifier().child(TopologyTypes.class),
                LINKSTATE_TOPOLOGY_TYPE);
        srAwareTopologyTypeAdded = false;
    }

    @Override
    protected void createObject(final ReadWriteTransaction trans,
            final InstanceIdentifier id, final LinkstateRoute value) {
        final UriBuilder base = new UriBuilder(value);

        final ObjectType t = value.getObjectType();
        Preconditions.checkArgument(t != null, "Route %s value %s has null object type", id, value);

        if (t instanceof LinkCase) {
            createLink(trans, base, value, (LinkCase) t, value.getAttributes());
        } else if (t instanceof NodeCase) {
            createNode(trans, base, value, (NodeCase) t, value.getAttributes());
        } else if (t instanceof PrefixCase) {
            createPrefix(trans, base, value, (PrefixCase) t, value.getAttributes());
        } else {
            LOG.debug(UNHANDLED_OBJECT_CLASS, t.implementedInterface());
        }
    }

    @Override
    protected void removeObject(final ReadWriteTransaction trans,
            final InstanceIdentifier id, final LinkstateRoute value) {
        if (value == null) {
            LOG.error("Empty before-data received in delete data change notification for instance id {}", id);
            return;
        }

        final UriBuilder base = new UriBuilder(value);

        final ObjectType t = value.getObjectType();
        if (t instanceof LinkCase) {
            removeLink(trans, base, (LinkCase) t);
        } else if (t instanceof NodeCase) {
            removeNode(trans, base, (NodeCase) t);
        } else if (t instanceof PrefixCase) {
            removePrefix(trans, base, (PrefixCase) t);
        } else {
            LOG.debug(UNHANDLED_OBJECT_CLASS, t.implementedInterface());
        }
    }

    @Override
    protected InstanceIdentifier getRouteWildcard(final InstanceIdentifier tablesId) {
        return tablesId.child(LinkstateRoutesCase.class, LinkstateRoutes.class).child(LinkstateRoute.class);
    }

    @Override
    protected void clearTopology() {
        nodes.clear();
        srAwareTopologyTypeAdded = false;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy