X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=bgp%2Frib-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fprotocol%2Fbgp%2Frib%2Fimpl%2FRIBImpl.java;h=a4615e91a715f7faee35a781088a512427c732d7;hb=ae404ec02460b97afd1414e8490c04a592786fcc;hp=ee4b1c861da5cd675f60adc3a94cc950ef944e9f;hpb=d5e71f8927346fad10c3d721e9b4ac5fd6199803;p=bgpcep.git diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/RIBImpl.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/RIBImpl.java index ee4b1c861d..a4615e91a7 100644 --- a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/RIBImpl.java +++ b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/RIBImpl.java @@ -7,104 +7,506 @@ */ package org.opendaylight.protocol.bgp.rib.impl; -import java.util.HashMap; -import java.util.Map; +import com.google.common.base.MoreObjects; +import com.google.common.base.MoreObjects.ToStringHelper; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableSet; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.Set; - +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.LinkedBlockingQueue; import javax.annotation.concurrent.ThreadSafe; - -import org.opendaylight.protocol.bgp.concepts.BGPObject; -import org.opendaylight.protocol.bgp.concepts.BGPTableType; -import org.opendaylight.protocol.bgp.linkstate.LinkIdentifier; -import org.opendaylight.protocol.bgp.linkstate.NodeIdentifier; -import org.opendaylight.protocol.bgp.linkstate.PrefixIdentifier; -import org.opendaylight.protocol.bgp.parser.BGPLink; -import org.opendaylight.protocol.bgp.parser.BGPLinkState; -import org.opendaylight.protocol.bgp.parser.BGPNode; -import org.opendaylight.protocol.bgp.parser.BGPNodeState; -import org.opendaylight.protocol.bgp.parser.BGPPrefix; -import org.opendaylight.protocol.bgp.parser.BGPPrefixState; -import org.opendaylight.protocol.bgp.parser.BGPRoute; -import org.opendaylight.protocol.bgp.parser.BGPRouteState; -import org.opendaylight.protocol.concepts.Prefix; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.LinkstateAddressFamily; +import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.sal.common.api.data.TransactionChain; +import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension; +import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService; +import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain; +import org.opendaylight.protocol.bgp.rib.DefaultRibReference; +import org.opendaylight.protocol.bgp.rib.impl.spi.AdjRIBsOut; +import org.opendaylight.protocol.bgp.rib.impl.spi.AdjRIBsOutRegistration; +import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher; +import org.opendaylight.protocol.bgp.rib.impl.spi.RIB; +import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry; +import org.opendaylight.protocol.bgp.rib.spi.AbstractAdjRIBs; +import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsIn; +import org.opendaylight.protocol.bgp.rib.spi.BGPObjectComparator; +import org.opendaylight.protocol.bgp.rib.spi.Peer; +import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext; +import org.opendaylight.protocol.framework.ReconnectStrategyFactory; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.bgp.rib.rib.loc.rib.tables.routes.Ipv4RoutesCase; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.bgp.rib.rib.loc.rib.tables.routes.Ipv6RoutesCase; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.ipv4.prefixes.DestinationIpv4Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.ipv4.prefixes.destination.ipv4.Ipv4Prefixes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.ipv4.prefixes.destination.ipv4.Ipv4PrefixesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.update.path.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationIpv4CaseBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.Update; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.UpdateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.Nlri; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.PathAttributes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.WithdrawnRoutes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.PathAttributes1; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.PathAttributes2; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpReachNlri; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpReachNlriBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpUnreachNlri; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.MpUnreachNlriBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.mp.reach.nlri.AdvertizedRoutesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.path.attributes.mp.unreach.nlri.WithdrawnRoutesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.BgpRib; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.RibId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.Route; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.Rib; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.LocRib; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.LocRibBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.Ipv4AddressFamily; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.Ipv6AddressFamily; - -import com.google.common.base.Objects; -import com.google.common.base.Objects.ToStringHelper; -import com.google.common.base.Preconditions; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.UnicastSubsequentAddressFamily; +import org.opendaylight.yangtools.binding.data.codec.api.BindingCodecTreeFactory; +import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; @ThreadSafe -public final class RIBImpl { - private final RIBTable links = new RIBTable<>(); - private final RIBTable nodes = new RIBTable<>(); - private final RIBTable, BGPPrefixState> prefixes = new RIBTable<>(); - private final RIBTable, BGPRouteState> routes = new RIBTable<>(); - private final String name; - - public RIBImpl(final String name) { - this.name = Preconditions.checkNotNull(name); - } - - synchronized void updateTables(final BGPPeer peer, final Set addedObjects, final Set removedObjects) { - final Map l = new HashMap<>(); - final Map n = new HashMap<>(); - final Map, BGPPrefixState> p = new HashMap<>(); - final Map, BGPRouteState> r = new HashMap<>(); - - for (final Object id : removedObjects) { - if (id instanceof Prefix) { - this.routes.remove(r, peer, (Prefix) id); - } else if (id instanceof LinkIdentifier) { - this.links.remove(l, peer, (LinkIdentifier) id); - } else if (id instanceof NodeIdentifier) { - this.nodes.remove(n, peer, (NodeIdentifier) id); - } else if (id instanceof PrefixIdentifier) { - this.prefixes.remove(p, peer, (PrefixIdentifier) id); - } else { - throw new IllegalArgumentException("Unsupported identifier " + id.getClass()); - } - } - - for (final BGPObject o : addedObjects) { - if (o instanceof BGPLink) { - final BGPLink link = (BGPLink) o; - this.links.add(l, peer, link.getLinkIdentifier(), link.currentState()); - } else if (o instanceof BGPNode) { - final BGPNode node = (BGPNode) o; - this.nodes.add(n, peer, node.getNodeIdentifier(), node.currentState()); - } else if (o instanceof BGPPrefix) { - final BGPPrefix prefix = (BGPPrefix) o; - this.prefixes.add(p, peer, prefix.getPrefixIdentifier(), prefix.currentState()); - } else if (o instanceof BGPRoute) { - final BGPRoute route = (BGPRoute) o; - this.routes.add(r, peer, route.getName(), route.currentState()); - } else { - throw new IllegalArgumentException("Unsupported identifier " + o.getClass()); - } - } - - // FIXME: push into MD SAL - } - - synchronized void clearTable(final BGPPeer peer, final BGPTableType t) { - if (Ipv4AddressFamily.class == t.getAddressFamily() || Ipv6AddressFamily.class == t.getAddressFamily()) { - this.routes.clear(peer); - } else if (LinkstateAddressFamily.class == t.getAddressFamily()) { - this.links.clear(peer); - this.nodes.clear(peer); - this.prefixes.clear(peer); - } - } - - @Override - public final String toString() { - return addToStringAttributes(Objects.toStringHelper(this)).toString(); - } - - protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) { - toStringHelper.add("name", this.name); - return toStringHelper; - } +public final class RIBImpl extends DefaultRibReference implements AutoCloseable, RIB, TransactionChainListener, SchemaContextListener { + private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class); + private static final Update EOR = new UpdateBuilder().build(); + private static final TablesKey IPV4_UNICAST_TABLE = new TablesKey(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class); + private static final QName RIB_ID_QNAME = QName.cachedReference(QName.create(Rib.QNAME, "id")); + + /* + * FIXME: performance: this needs to be turned into a Peer->offset map. + * The offset is used to locate a the per-peer state entry in the + * RIB tables. + * + * For the first release, that map is updated whenever configuration + * changes and remains constant on peer flaps. On re-configuration + * a resize task is scheduled, so large tables may take some time + * before they continue reacting to updates. + * + * For subsequent releases, if we make the reformat process concurrent, + * we can trigger reformats when Graceful Restart Time expires for a + * particular peer. + */ + private final ConcurrentMap ribOuts = new ConcurrentHashMap<>(); + private final ReconnectStrategyFactory tcpStrategyFactory; + private final ReconnectStrategyFactory sessionStrategyFactory; + + /** + * BGP Best Path selection comparator for ingress best path selection. + */ + private final BGPObjectComparator comparator; + private final BGPDispatcher dispatcher; + private final BindingTransactionChain chain; + private final AsNumber localAs; + private final Ipv4Address bgpIdentifier; + private final Ipv4Address clusterId; + private final Set localTables; + private final RIBTables tables; + private final BlockingQueue peers; + private final DataBroker dataBroker; + private final DOMDataBroker domDataBroker; + private final RIBExtensionConsumerContext extensions; + private final YangInstanceIdentifier yangRibId; + private final RIBSupportContextRegistryImpl ribContextRegistry; + private final Runnable scheduler = new Runnable() { + @Override + public void run() { + try { + final Peer peer = RIBImpl.this.peers.take(); + LOG.debug("Advertizing loc-rib to new peer {}.", peer); + for (final BgpTableType key : RIBImpl.this.localTables) { + + synchronized (RIBImpl.this) { + final AdjRIBsTransactionImpl trans = new AdjRIBsTransactionImpl(RIBImpl.this.ribOuts, RIBImpl.this.comparator, RIBImpl.this.chain.newWriteOnlyTransaction()); + final AbstractAdjRIBs adj = (AbstractAdjRIBs) RIBImpl.this.tables.get(new TablesKey(key.getAfi(), key.getSafi())); + adj.addAllEntries(trans); + Futures.addCallback(trans.commit(), new FutureCallback() { + @Override + public void onSuccess(final Void result) { + LOG.trace("Advertizing {} to peer {} committed successfully", key.getAfi(), peer); + } + @Override + public void onFailure(final Throwable t) { + LOG.error("Failed to update peer {} with RIB {}", peer, t); + } + }); + } + } + } catch (final InterruptedException e) { + LOG.info("Scheduler thread was interrupted.", e); + } + } + }; + + public RIBImpl(final RibId ribId, final AsNumber localAs, final Ipv4Address localBgpId, final Ipv4Address clusterId, final RIBExtensionConsumerContext extensions, + final BGPDispatcher dispatcher, final ReconnectStrategyFactory tcpStrategyFactory, final BindingCodecTreeFactory codecFactory, + final ReconnectStrategyFactory sessionStrategyFactory, final DataBroker dps, final DOMDataBroker domDataBroker, final List localTables, GeneratedClassLoadingStrategy classStrategy) { + super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId)))); + this.chain = dps.createTransactionChain(this); + this.localAs = Preconditions.checkNotNull(localAs); + this.comparator = new BGPObjectComparator(localAs); + this.bgpIdentifier = Preconditions.checkNotNull(localBgpId); + this.clusterId = clusterId == null ? localBgpId : clusterId; + this.dispatcher = Preconditions.checkNotNull(dispatcher); + this.sessionStrategyFactory = Preconditions.checkNotNull(sessionStrategyFactory); + this.tcpStrategyFactory = Preconditions.checkNotNull(tcpStrategyFactory); + this.localTables = ImmutableSet.copyOf(localTables); + this.tables = new RIBTables(extensions); + this.peers = new LinkedBlockingQueue<>(); + this.dataBroker = dps; + this.domDataBroker = Preconditions.checkNotNull(domDataBroker); + this.extensions = Preconditions.checkNotNull(extensions); + this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, codecFactory, classStrategy); + this.yangRibId = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME).nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build(); + + LOG.debug("Instantiating RIB table {} at {}", ribId, getInstanceIdentifier()); + + final WriteTransaction trans = this.chain.newWriteOnlyTransaction(); + + final PolicyDatabase pd = new PolicyDatabase(localAs.getValue(), localBgpId, new ClusterIdentifier(localBgpId)); + /*if (clusterId == null) { + clusterId is not present, fallback to bgpId + pd = new PolicyDatabase(localAs.getValue(), localBgpId, new ClusterIdentifier(localBgpId)); + } else { + pd = new PolicyDatabase(as, bgpId, clusterId); + } */ + + final DOMDataBrokerExtension service = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class); + final DOMTransactionChain domChain = this.createPeerChain(this); + // put clusterId + EffectiveRibInWriter.create((DOMDataTreeChangeService) service, domChain, getYangRibId(), pd, this.ribContextRegistry); + + // put empty BgpRib if not exists + trans.put(LogicalDatastoreType.OPERATIONAL, getInstanceIdentifier(), + new RibBuilder().setKey(new RibKey(ribId)).setPeer(Collections. emptyList()).setId(ribId).setLocRib( + new LocRibBuilder().setTables(Collections. emptyList()).build()).build(), true); + + for (final BgpTableType t : localTables) { + final TablesKey key = new TablesKey(t.getAfi(), t.getSafi()); + if (this.tables.create(trans, this, key) == null) { + LOG.debug("Did not create local table for unhandled table type {}", t); + } + + // reusing the for cycle + // create locRibWriter for each table + // FIXME: temporary create writer only for Ipv4 + if (key.getAfi().equals(Ipv4AddressFamily.class)) { + LocRibWriter.create(this.ribContextRegistry.getRIBSupportContext(key).getRibSupport(), domChain, getYangRibId(), localAs, (DOMDataTreeChangeService) service, pd); + } + } + + Futures.addCallback(trans.submit(), new FutureCallback() { + @Override + public void onSuccess(final Void result) { + LOG.trace("Change committed successfully"); + } + + @Override + public void onFailure(final Throwable t) { + LOG.error("Failed to initiate RIB {}", getInstanceIdentifier(), t); + } + + }); + } + + synchronized void initTables(final byte[] remoteBgpId) { + } + + @Override + public synchronized void updateTables(final Peer peer, final Update message) { + final AdjRIBsTransactionImpl trans = new AdjRIBsTransactionImpl(this.ribOuts, this.comparator, this.chain.newWriteOnlyTransaction()); + + if (!EOR.equals(message)) { + final WithdrawnRoutes wr = message.getWithdrawnRoutes(); + if (wr != null) { + final AdjRIBsIn ari = this.tables.get(IPV4_UNICAST_TABLE); + if (ari != null) { + /* + * create MPUnreach for the routes to be handled in the same way as linkstate routes + */ + final List prefixes = new ArrayList<>(); + for (final Ipv4Prefix p : wr.getWithdrawnRoutes()) { + prefixes.add(new Ipv4PrefixesBuilder().setPrefix(p).build()); + } + ari.removeRoutes( + trans, + peer, + new MpUnreachNlriBuilder().setAfi(Ipv4AddressFamily.class).setSafi(UnicastSubsequentAddressFamily.class).setWithdrawnRoutes( + new WithdrawnRoutesBuilder().setDestinationType( + new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.update.path.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationIpv4CaseBuilder().setDestinationIpv4( + new DestinationIpv4Builder().setIpv4Prefixes(prefixes).build()).build()).build()).build()); + } else { + LOG.debug("Not removing objects from unhandled IPv4 Unicast"); + } + } + + final PathAttributes attrs = message.getPathAttributes(); + if (attrs != null) { + final PathAttributes2 mpu = attrs.getAugmentation(PathAttributes2.class); + if (mpu != null) { + final MpUnreachNlri nlri = mpu.getMpUnreachNlri(); + final AdjRIBsIn ari = this.tables.get(new TablesKey(nlri.getAfi(), nlri.getSafi())); + // EOR messages do not contain withdrawn routes + if (nlri.getWithdrawnRoutes() != null) { + if (ari != null) { + ari.removeRoutes(trans, peer, nlri); + } else { + LOG.debug("Not removing objects from unhandled NLRI {}", nlri); + } + } else { + ari.markUptodate(trans, peer); + } + } + } + + final Nlri ar = message.getNlri(); + if (ar != null) { + final AdjRIBsIn ari = this.tables.get(IPV4_UNICAST_TABLE); + if (ari != null) { + /* + * create MPReach for the routes to be handled in the same way as linkstate routes + */ + final List prefixes = new ArrayList<>(); + for (final Ipv4Prefix p : ar.getNlri()) { + prefixes.add(new Ipv4PrefixesBuilder().setPrefix(p).build()); + } + final MpReachNlriBuilder b = new MpReachNlriBuilder().setAfi(Ipv4AddressFamily.class).setSafi( + UnicastSubsequentAddressFamily.class).setAdvertizedRoutes( + new AdvertizedRoutesBuilder().setDestinationType( + new DestinationIpv4CaseBuilder().setDestinationIpv4( + new DestinationIpv4Builder().setIpv4Prefixes(prefixes).build()).build()).build()); + if (attrs != null) { + b.setCNextHop(attrs.getCNextHop()); + } + + ari.addRoutes(trans, peer, b.build(), attrs); + } else { + LOG.debug("Not adding objects from unhandled IPv4 Unicast"); + } + } + + if (attrs != null) { + final PathAttributes1 mpr = attrs.getAugmentation(PathAttributes1.class); + if (mpr != null) { + final MpReachNlri nlri = mpr.getMpReachNlri(); + + final AdjRIBsIn ari = this.tables.get(new TablesKey(nlri.getAfi(), nlri.getSafi())); + if (ari != null) { + if (message.equals(ari.endOfRib())) { + ari.markUptodate(trans, peer); + } else { + ari.addRoutes(trans, peer, nlri, attrs); + } + } else { + LOG.debug("Not adding objects from unhandled NLRI {}", nlri); + } + } + } + } else { + final AdjRIBsIn ari = this.tables.get(IPV4_UNICAST_TABLE); + if (ari != null) { + ari.markUptodate(trans, peer); + } else { + LOG.debug("End-of-RIB for IPv4 Unicast ignored"); + } + } + + Futures.addCallback(trans.commit(), new FutureCallback() { + @Override + public void onSuccess(final Void result) { + LOG.debug("RIB modification successfully committed."); + } + + @Override + public void onFailure(final Throwable t) { + LOG.error("Failed to commit RIB modification", t); + } + }); + } + + @Override + public synchronized void clearTable(final Peer peer, final TablesKey key) { + final AdjRIBsIn ari = this.tables.get(key); + if (ari != null) { + final AdjRIBsTransactionImpl trans = new AdjRIBsTransactionImpl(this.ribOuts, this.comparator, this.chain.newWriteOnlyTransaction()); + ari.clear(trans, peer); + + Futures.addCallback(trans.commit(), new FutureCallback() { + @Override + public void onSuccess(final Void result) { + LOG.trace("Table {} cleared successfully", key); + } + + @Override + public void onFailure(final Throwable t) { + LOG.error("Failed to clear table {}", key, t); + } + }); + } + } + + @Override + public String toString() { + return addToStringAttributes(MoreObjects.toStringHelper(this)).toString(); + } + + protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) { + return toStringHelper; + } + + @SuppressWarnings("unchecked") + protected AdjRIBsIn getTable(final TablesKey key) { + return (AdjRIBsIn) this.tables.get(key); + } + + @Override + public synchronized void close() throws InterruptedException, ExecutionException { + final WriteTransaction t = this.chain.newWriteOnlyTransaction(); + t.delete(LogicalDatastoreType.OPERATIONAL, getInstanceIdentifier()); + t.submit().get(); + this.chain.close(); + } + + @Override + public AsNumber getLocalAs() { + return this.localAs; + } + + @Override + public Ipv4Address getBgpIdentifier() { + return this.bgpIdentifier; + } + + @Override + public Set getLocalTables() { + return this.localTables; + } + + @Override + public ReconnectStrategyFactory getTcpStrategyFactory() { + return this.tcpStrategyFactory; + } + + @Override + public ReconnectStrategyFactory getSessionStrategyFactory() { + return this.sessionStrategyFactory; + } + + @Override + public BGPDispatcher getDispatcher() { + return this.dispatcher; + } + + @Override + public void initTable(final Peer bgpPeer, final TablesKey key) { + // FIXME: BUG-196: support graceful restart + } + + @Override + public AdjRIBsOutRegistration registerRIBsOut(final Peer peer, final AdjRIBsOut aro) { + final AdjRIBsOutRegistration reg = new AdjRIBsOutRegistration(aro) { + @Override + protected void removeRegistration() { + RIBImpl.this.ribOuts.remove(peer, aro); + } + }; + + this.ribOuts.put(peer, aro); + LOG.debug("Registering this peer {} to RIB-Out {}", peer, this.ribOuts); + try { + this.peers.put(peer); + new Thread(this.scheduler).start(); + } catch (final InterruptedException e) { + // + } + return reg; + } + + @Override + public void onTransactionChainFailed(final TransactionChain chain, final AsyncTransaction transaction, final Throwable cause) { + LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction.getIdentifier(), cause); + } + + @Override + public void onTransactionChainSuccessful(final TransactionChain chain) { + LOG.info("RIB {} closed successfully", getInstanceIdentifier()); + } + + @Override + public long getRoutesCount(final TablesKey key) { + try { + final Optional tableMaybe = this.dataBroker.newReadOnlyTransaction().read(LogicalDatastoreType.OPERATIONAL, + getInstanceIdentifier().child(LocRib.class).child(Tables.class, key)).checkedGet(); + if (tableMaybe.isPresent()) { + final Tables table = tableMaybe.get(); + if (table.getRoutes() instanceof Ipv4RoutesCase) { + final Ipv4RoutesCase routesCase = (Ipv4RoutesCase) table.getRoutes(); + if (routesCase.getIpv4Routes() != null && routesCase.getIpv4Routes().getIpv4Route() != null) { + return routesCase.getIpv4Routes().getIpv4Route().size(); + } + } else if (table.getRoutes() instanceof Ipv6RoutesCase) { + final Ipv6RoutesCase routesCase = (Ipv6RoutesCase) table.getRoutes(); + if (routesCase.getIpv6Routes() != null && routesCase.getIpv6Routes().getIpv6Route() != null) { + return routesCase.getIpv6Routes().getIpv6Route().size(); + } + } + } + } catch (final ReadFailedException e) { + //no-op + } + return 0; + } + + @Override + public YangInstanceIdentifier getYangRibId() { + return this.yangRibId; + } + + @Override + public DOMTransactionChain createPeerChain(final TransactionChainListener listener) { + return this.domDataBroker.createTransactionChain(listener); + } + + @Override + public RIBExtensionConsumerContext getRibExtensions() { + return this.extensions; + } + + @Override + public RIBSupportContextRegistry getRibSupportContext() { + return this.ribContextRegistry; + } + + @Override + public void onGlobalContextUpdated(final SchemaContext context) { + this.ribContextRegistry.onSchemaContextUpdated(context); + } }