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=d2531b3bb68b53370890f51f0fa15b8518f24d37;hb=abe034714f96d78714fc223fef80e5410a53919a;hp=3a3c1102cf739b1624a8190b126e187c6ebffe8a;hpb=5844de028bf11f45085d149949b49f60fd674eba;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 3a3c1102cf..d1bda15d14 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,109 +7,319 @@ */ package org.opendaylight.protocol.bgp.rib.impl; +import com.google.common.annotations.VisibleForTesting; +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 java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map.Entry; +import java.util.Set; import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; - import javax.annotation.concurrent.ThreadSafe; - -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.controller.sal.binding.api.data.DataProviderService; -import org.opendaylight.protocol.bgp.rib.spi.AdjRIBsIn; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +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.common.api.data.TransactionCommitFailedException; +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.DOMDataWriteTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain; +import org.opendaylight.protocol.bgp.rib.DefaultRibReference; +import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher; +import org.opendaylight.protocol.bgp.rib.impl.spi.CodecsRegistry; +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.RIBExtensionConsumerContext; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130918.Update; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130918.update.PathAttributes; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130918.PathAttributes1; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130918.PathAttributes2; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130918.update.path.attributes.MpReachNlri; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130918.update.path.attributes.MpUnreachNlri; +import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils; +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.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.multiprotocol.rev130919.BgpTableType; +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.bgp.rib.Rib; +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.Peer; +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.yangtools.yang.common.RpcResult; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.Routes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier; +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.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; +import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; +import org.opendaylight.yangtools.yang.data.impl.schema.Builders; +import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.base.Objects; -import com.google.common.base.Objects.ToStringHelper; -import com.google.common.base.Preconditions; - @ThreadSafe -public class RIBImpl { - private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class); - private final DataProviderService dps; - private final RIBTables tables; - - public RIBImpl(final RIBExtensionConsumerContext extensions, final DataProviderService dps) { - this.dps = Preconditions.checkNotNull(dps); - this.tables = new RIBTables(BGPObjectComparator.INSTANCE, extensions); - } - - synchronized void updateTables(final BGPPeer peer, final Update message) { - final DataModificationTransaction trans = this.dps.beginTransaction(); - - // FIXME: detect and handle end-of-RIB markers - - // remove(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class, - // trans, peer, message.getWithdrawnRoutes().getWithdrawnRoutes().iterator()); - - final PathAttributes attrs = message.getPathAttributes(); - final PathAttributes2 mpu = attrs.getAugmentation(PathAttributes2.class); - if (mpu != null) { - final MpUnreachNlri nlri = mpu.getMpUnreachNlri(); - - final AdjRIBsIn ari = this.tables.getOrCreate(new TablesKey(nlri.getAfi(), nlri.getSafi())); - if (ari != null) { - ari.removeRoutes(trans, peer, nlri); - } else { - LOG.debug("Not removing objects from unhandled NLRI {}", nlri); - } - } - - // add(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class, - // trans, peer, message.getNlri().getNlri().iterator(), attrs); - - final PathAttributes1 mpr = message.getPathAttributes().getAugmentation(PathAttributes1.class); - if (mpr != null) { - final MpReachNlri nlri = mpr.getMpReachNlri(); - - final AdjRIBsIn ari = this.tables.getOrCreate(new TablesKey(nlri.getAfi(), nlri.getSafi())); - if (ari != null) { - ari.addRoutes(trans, peer, nlri, attrs); - } else { - LOG.debug("Not adding objects from unhandled NLRI {}", nlri); - } - } - - // FIXME: we need to attach to this future for failures - final Future> f = trans.commit(); - try { - f.get(); - } catch (InterruptedException | ExecutionException e) { - LOG.error("Failed to commit RIB modification", e); - } - } - - synchronized void clearTable(final BGPPeer peer, final TablesKey key) { - final AdjRIBsIn ari = this.tables.get(key); - if (ari != null) { - final DataModificationTransaction trans = this.dps.beginTransaction(); - ari.clear(trans, peer); - - // FIXME: we need to attach to this future for failures - final Future> f = trans.commit(); - try { - f.get(); - } catch (InterruptedException | ExecutionException e) { - LOG.error("Failed to commit RIB modification", e); - } - } - } - - @Override - public String toString() { - return addToStringAttributes(Objects.toStringHelper(this)).toString(); - } - - protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) { - return toStringHelper; - } +public final class RIBImpl extends DefaultRibReference implements AutoCloseable, RIB, TransactionChainListener, SchemaContextListener { + private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class); + @VisibleForTesting + public static final QName RIB_ID_QNAME = QName.cachedReference(QName.create(Rib.QNAME, "id")); + @VisibleForTesting + public static final ContainerNode EMPTY_TABLE_ATTRIBUTES = ImmutableNodes.containerNode(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.tables.Attributes.QNAME); + + private final ReconnectStrategyFactory tcpStrategyFactory; + private final ReconnectStrategyFactory sessionStrategyFactory; + + private final BGPDispatcher dispatcher; + private final DOMTransactionChain domChain; + private final AsNumber localAs; + private final Ipv4Address bgpIdentifier; + private final Set localTables; + private final Set localTablesKeys; + private final DataBroker dataBroker; + private final DOMDataBroker domDataBroker; + private final RIBExtensionConsumerContext extensions; + private final YangInstanceIdentifier yangRibId; + private final RIBSupportContextRegistryImpl ribContextRegistry; + private final CodecsRegistryImpl codecsRegistry; + private final EffectiveRibInWriter efWriter; + private final DOMDataBrokerExtension service; + private final List locRibs = new ArrayList<>(); + + 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, final GeneratedClassLoadingStrategy classStrategy) { + super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId)))); + this.domChain = domDataBroker.createTransactionChain(this); + this.localAs = Preconditions.checkNotNull(localAs); + this.bgpIdentifier = Preconditions.checkNotNull(localBgpId); + this.dispatcher = Preconditions.checkNotNull(dispatcher); + this.sessionStrategyFactory = Preconditions.checkNotNull(sessionStrategyFactory); + this.tcpStrategyFactory = Preconditions.checkNotNull(tcpStrategyFactory); + this.localTables = ImmutableSet.copyOf(localTables); + this.localTablesKeys = new HashSet(); + this.dataBroker = dps; + this.domDataBroker = Preconditions.checkNotNull(domDataBroker); + this.extensions = Preconditions.checkNotNull(extensions); + this.codecsRegistry = CodecsRegistryImpl.create(codecFactory, classStrategy); + this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry); + 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, this.yangRibId); + + final ContainerNode rib = Builders.containerBuilder() + .withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME)) + .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME) + .addChild(ImmutableNodes.mapEntryBuilder(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()) + .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, ribId.getValue())) + .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build()) + .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME)) + .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build()) + .build()) + .build()) + .build()) + .build(); + + + final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction(); + + // put empty BgpRib if not exists + trans.put(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), rib); + + try { + trans.submit().checkedGet(); + } catch (final TransactionCommitFailedException e) { + LOG.error("Failed to initiate RIB {}", this.yangRibId, e); + } + final ClusterIdentifier cId = (clusterId == null) ? new ClusterIdentifier(localBgpId) : new ClusterIdentifier(clusterId); + final PolicyDatabase pd = new PolicyDatabase(localAs.getValue(), localBgpId, cId); + + final DOMDataBrokerExtension domDatatreeChangeService = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class); + this.service = domDatatreeChangeService; + this.efWriter = EffectiveRibInWriter.create(getService(), createPeerChain(this), getYangRibId(), pd, this.ribContextRegistry); + LOG.debug("Effective RIB created."); + + for (final BgpTableType t : this.localTables) { + final TablesKey key = new TablesKey(t.getAfi(), t.getSafi()); + this.localTablesKeys.add(key); + startLocRib(key, pd); + } + } + + private void startLocRib(final TablesKey key, final PolicyDatabase pd) { + LOG.debug("Creating LocRib table for {}", key); + // create locRibWriter for each table + final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction(); + + final DataContainerNodeBuilder table = ImmutableNodes.mapEntryBuilder(); + table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key)); + table.withChild(EMPTY_TABLE_ATTRIBUTES); + + final NodeIdentifierWithPredicates tableKey = RibSupportUtils.toYangTablesKey(key); + final InstanceIdentifierBuilder tableId = YangInstanceIdentifier.builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME)); + tableId.nodeWithKey(tableKey.getNodeType(), tableKey.getKeyValues()); + for (final Entry e : tableKey.getKeyValues().entrySet()) { + table.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue())); + } + + final ChoiceNode routes = this.ribContextRegistry.getRIBSupportContext(key).getRibSupport().emptyRoutes(); + table.withChild(routes); + + tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build()); + try { + tx.submit().checkedGet(); + } catch (final TransactionCommitFailedException e1) { + LOG.error("Failed to initiate LocRIB for key {}", key, e1); + } + this.locRibs.add(LocRibWriter.create(this.ribContextRegistry, key, createPeerChain(this), getYangRibId(), this.localAs, getService(), pd)); + } + + @Override + public String toString() { + return addToStringAttributes(MoreObjects.toStringHelper(this)).toString(); + } + + protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) { + return toStringHelper; + } + + @Override + public synchronized void close() throws InterruptedException, ExecutionException { + final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction(); + t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId()); + t.submit().get(); + this.domChain.close(); + this.efWriter.close(); + for (final LocRibWriter locRib : this.locRibs) { + try { + locRib.close(); + } catch (final Exception e) { + LOG.warn("Could not close LocalRib reference: {}", locRib, e); + } + } + } + + @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 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 ReadOnlyTransaction tx = this.dataBroker.newReadOnlyTransaction()) { + final Optional tableMaybe = tx.read(LogicalDatastoreType.OPERATIONAL, + getInstanceIdentifier().child(LocRib.class).child(Tables.class, key)).checkedGet(); + if (tableMaybe.isPresent()) { + final Tables table = tableMaybe.get(); + return countIpRoutes(table.getRoutes()); + } + } catch (final ReadFailedException e) { + LOG.debug("Failed to read tables", e); + } + return 0; + } + + private int countIpRoutes(final Routes routes) { + if (routes instanceof Ipv4RoutesCase) { + final Ipv4RoutesCase routesCase = (Ipv4RoutesCase) routes; + if (routesCase.getIpv4Routes() != null && routesCase.getIpv4Routes().getIpv4Route() != null) { + return routesCase.getIpv4Routes().getIpv4Route().size(); + } + } else if (routes instanceof Ipv6RoutesCase) { + final Ipv6RoutesCase routesCase = (Ipv6RoutesCase) routes; + if (routesCase.getIpv6Routes() != null && routesCase.getIpv6Routes().getIpv6Route() != null) { + return routesCase.getIpv6Routes().getIpv6Route().size(); + } + } + return 0; + } + + public Set getLocalTablesKeys() { + return this.localTablesKeys; + } + + public DOMDataTreeChangeService getService() { + return (DOMDataTreeChangeService) this.service; + } + + @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.codecsRegistry.onSchemaContextUpdated(context); + } + + @Override + public CodecsRegistry getCodecsRegistry() { + return this.codecsRegistry; + } }