2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.protocol.bgp.rib.impl;
10 import com.google.common.base.MoreObjects;
11 import com.google.common.base.MoreObjects.ToStringHelper;
12 import com.google.common.base.Optional;
13 import com.google.common.base.Preconditions;
14 import com.google.common.collect.ImmutableSet;
15 import com.google.common.util.concurrent.Futures;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import java.util.ArrayList;
18 import java.util.HashSet;
19 import java.util.List;
21 import java.util.Map.Entry;
23 import javax.annotation.Nonnull;
24 import javax.annotation.Nullable;
25 import javax.annotation.concurrent.ThreadSafe;
26 import org.opendaylight.controller.config.yang.bgp.rib.impl.RIBImplRuntimeRegistration;
27 import org.opendaylight.controller.config.yang.bgp.rib.impl.RIBImplRuntimeRegistrator;
28 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
29 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
30 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
31 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
32 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
33 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
34 import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
35 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
36 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
37 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
38 import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTreeFactory;
39 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
40 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
41 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
42 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
43 import org.opendaylight.protocol.bgp.mode.api.PathSelectionMode;
44 import org.opendaylight.protocol.bgp.mode.impl.base.BasePathSelectionModeFactory;
45 import org.opendaylight.protocol.bgp.openconfig.spi.BGPConfigModuleTracker;
46 import org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenConfigProvider;
47 import org.opendaylight.protocol.bgp.rib.DefaultRibReference;
48 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
49 import org.opendaylight.protocol.bgp.rib.impl.spi.BgpDeployer;
50 import org.opendaylight.protocol.bgp.rib.impl.spi.CodecsRegistry;
51 import org.opendaylight.protocol.bgp.rib.impl.spi.ImportPolicyPeerTracker;
52 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
53 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
54 import org.opendaylight.protocol.bgp.rib.impl.stats.rib.impl.BGPRenderStats;
55 import org.opendaylight.protocol.bgp.rib.impl.stats.rib.impl.RIBImplRuntimeMXBeanImpl;
56 import org.opendaylight.protocol.bgp.rib.spi.CacheDisconnectedPeers;
57 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
58 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
59 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.BgpRib;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.RibId;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.Rib;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibKey;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.LocRib;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.Peer;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.BgpId;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier;
71 import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
72 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
73 import org.opendaylight.yangtools.yang.common.QName;
74 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
75 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
76 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
77 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
78 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
79 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
80 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
81 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
82 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
83 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
84 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
85 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
86 import org.slf4j.Logger;
87 import org.slf4j.LoggerFactory;
90 public final class RIBImpl extends DefaultRibReference implements ClusterSingletonService, AutoCloseable, RIB, TransactionChainListener, SchemaContextListener {
91 private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
92 private static final QName RIB_ID_QNAME = QName.create(Rib.QNAME, "id").intern();
93 private 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);
95 private final BGPDispatcher dispatcher;
96 private final DOMTransactionChain domChain;
97 private final AsNumber localAs;
98 private final BgpId bgpIdentifier;
99 private final Set<BgpTableType> localTables;
100 private final Set<TablesKey> localTablesKeys;
101 private final DOMDataBroker domDataBroker;
102 private final RIBExtensionConsumerContext extensions;
103 private final YangInstanceIdentifier yangRibId;
104 private final RIBSupportContextRegistryImpl ribContextRegistry;
105 private final CodecsRegistryImpl codecsRegistry;
106 private final ServiceGroupIdentifier serviceGroupIdentifier;
107 private final ClusterSingletonServiceProvider provider;
108 private final PolicyDatabase policyDatabase;
109 private final BgpDeployer.WriteConfiguration configurationWriter;
110 private ClusterSingletonServiceRegistration registration;
111 private final DOMDataBrokerExtension service;
112 private final List<LocRibWriter> locRibs = new ArrayList<>();
113 private final BGPConfigModuleTracker configModuleTracker;
114 private final BGPOpenConfigProvider openConfigProvider;
115 private final CacheDisconnectedPeers cacheDisconnectedPeers;
116 private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
117 private final ImportPolicyPeerTracker importPolicyPeerTracker;
118 private final RIBImplRuntimeMXBeanImpl renderStats;
119 private final RibId ribId;
121 public RIBImpl(final ClusterSingletonServiceProvider provider, final RibId ribId, final AsNumber localAs, final BgpId localBgpId,
122 final ClusterIdentifier clusterId, final RIBExtensionConsumerContext extensions, final BGPDispatcher dispatcher,
123 final BindingCodecTreeFactory codecFactory, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
124 @Nonnull final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies, final GeneratedClassLoadingStrategy classStrategy,
125 final BGPConfigModuleTracker moduleTracker, final BGPOpenConfigProvider openConfigProvider, final BgpDeployer.WriteConfiguration configurationWriter) {
127 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId))));
128 this.domChain = domDataBroker.createTransactionChain(this);
129 this.localAs = Preconditions.checkNotNull(localAs);
130 this.bgpIdentifier = Preconditions.checkNotNull(localBgpId);
131 this.dispatcher = Preconditions.checkNotNull(dispatcher);
132 this.localTables = ImmutableSet.copyOf(localTables);
133 this.localTablesKeys = new HashSet<>();
134 this.domDataBroker = Preconditions.checkNotNull(domDataBroker);
135 this.service = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
136 this.extensions = Preconditions.checkNotNull(extensions);
137 this.codecsRegistry = CodecsRegistryImpl.create(codecFactory, classStrategy);
138 this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
139 final InstanceIdentifierBuilder yangRibIdBuilder = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME);
140 this.yangRibId = yangRibIdBuilder.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
141 this.configModuleTracker = moduleTracker;
142 this.openConfigProvider = openConfigProvider;
143 this.cacheDisconnectedPeers = new CacheDisconnectedPeersImpl();
144 this.bestPathSelectionStrategies = Preconditions.checkNotNull(bestPathSelectionStrategies);
145 final ClusterIdentifier cId = (clusterId == null) ? new ClusterIdentifier(localBgpId) : clusterId;
146 this.renderStats = new RIBImplRuntimeMXBeanImpl(localBgpId, ribId, localAs, cId);
148 this.policyDatabase = new PolicyDatabase(this.localAs.getValue(), localBgpId, cId);
149 this.importPolicyPeerTracker = new ImportPolicyPeerTrackerImpl( this.policyDatabase);
150 this.serviceGroupIdentifier = ServiceGroupIdentifier.create(this.ribId + "-service-group");
151 Preconditions.checkNotNull(provider, "ClusterSingletonServiceProvider is null");
152 this.provider = provider;
153 LOG.info("RIB Singleton Service {} registered", this.getIdentifier());
154 this.registration = registerClusterSingletonService(this);
155 this.configurationWriter = configurationWriter;
158 public RIBImpl(final ClusterSingletonServiceProvider provider, final RibId ribId, final AsNumber localAs, final BgpId localBgpId, @Nullable final ClusterIdentifier clusterId,
159 final RIBExtensionConsumerContext extensions, final BGPDispatcher dispatcher, final BindingCodecTreeFactory codecFactory,
160 final DOMDataBroker domDataBroker, final List<BgpTableType> localTables, final Map<TablesKey, PathSelectionMode> bestPathSelectionstrategies,
161 final GeneratedClassLoadingStrategy classStrategy, final BgpDeployer.WriteConfiguration configurationWriter) {
162 this(provider, ribId, localAs, localBgpId, clusterId, extensions, dispatcher, codecFactory,
163 domDataBroker, localTables, bestPathSelectionstrategies, classStrategy, null, null, configurationWriter);
166 private void startLocRib(final TablesKey key, final PolicyDatabase pd) {
167 LOG.debug("Creating LocRib table for {}", key);
168 // create locRibWriter for each table
169 final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
171 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
172 table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
173 table.withChild(EMPTY_TABLE_ATTRIBUTES);
175 final NodeIdentifierWithPredicates tableKey = RibSupportUtils.toYangTablesKey(key);
176 final InstanceIdentifierBuilder tableId = YangInstanceIdentifier.builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME));
177 tableId.nodeWithKey(tableKey.getNodeType(), tableKey.getKeyValues());
178 for (final Entry<QName, Object> e : tableKey.getKeyValues().entrySet()) {
179 table.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
182 final ChoiceNode routes = this.ribContextRegistry.getRIBSupportContext(key).getRibSupport().emptyRoutes();
183 table.withChild(routes);
185 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
187 tx.submit().checkedGet();
188 } catch (final TransactionCommitFailedException e1) {
189 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
192 PathSelectionMode pathSelectionStrategy = this.bestPathSelectionStrategies.get(key);
193 if (pathSelectionStrategy == null) {
194 pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy();
197 this.locRibs.add(LocRibWriter.create(this.ribContextRegistry, key, createPeerChain(this), getYangRibId(), this.localAs, getService(), pd,
198 this.cacheDisconnectedPeers, pathSelectionStrategy, this.renderStats.getLocRibRouteCounter().init(key)));
202 public String toString() {
203 return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
206 protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
207 return toStringHelper;
211 public synchronized void close() throws Exception {
212 this.domChain.close();
213 if (registration != null) {
214 registration.close();
220 public AsNumber getLocalAs() {
225 public BgpId getBgpIdentifier() {
226 return this.bgpIdentifier;
230 public Set<? extends BgpTableType> getLocalTables() {
231 return this.localTables;
235 public BGPDispatcher getDispatcher() {
236 return this.dispatcher;
240 public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
241 LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
245 public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
246 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
250 public Set<TablesKey> getLocalTablesKeys() {
251 return this.localTablesKeys;
255 public DOMDataTreeChangeService getService() {
256 return (DOMDataTreeChangeService) this.service;
260 public BGPRenderStats getRenderStats() {
261 return this.renderStats;
265 public YangInstanceIdentifier getYangRibId() {
266 return this.yangRibId;
270 public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
271 return this.domDataBroker.createTransactionChain(listener);
275 public RIBExtensionConsumerContext getRibExtensions() {
276 return this.extensions;
280 public RIBSupportContextRegistry getRibSupportContext() {
281 return this.ribContextRegistry;
285 public void onGlobalContextUpdated(final SchemaContext context) {
286 this.codecsRegistry.onSchemaContextUpdated(context);
290 public CodecsRegistry getCodecsRegistry() {
291 return this.codecsRegistry;
295 public Optional<BGPOpenConfigProvider> getOpenConfigProvider() {
296 return Optional.fromNullable(this.openConfigProvider);
300 public CacheDisconnectedPeers getCacheDisconnectedPeers() {
301 return this.cacheDisconnectedPeers;
305 public ImportPolicyPeerTracker getImportPolicyPeerTracker() {
306 return this.importPolicyPeerTracker;
310 public void instantiateServiceInstance() {
311 if(this.configurationWriter != null) {
312 this.configurationWriter.apply();
314 LOG.info("RIB Singleton Service {} instantiated", this.getIdentifier());
315 LOG.debug("Instantiating RIB table {} at {}", this.ribId , this.yangRibId);
317 final ContainerNode bgpRib = Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
318 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
320 final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
321 new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, this.ribId .getValue()))
322 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, this.ribId .getValue()))
323 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
324 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
325 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
329 final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
331 // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
332 trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
333 trans.put(LogicalDatastoreType.OPERATIONAL, this.yangRibId, ribInstance);
336 trans.submit().checkedGet();
337 } catch (final TransactionCommitFailedException e) {
338 LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
341 LOG.debug("Effective RIB created.");
343 for (final BgpTableType t : this.localTables) {
344 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
345 this.localTablesKeys.add(key);
346 startLocRib(key, policyDatabase);
349 if (this.configModuleTracker != null) {
350 this.configModuleTracker.onInstanceCreate();
355 public ListenableFuture<Void> closeServiceInstance() {
356 LOG.info("Close RIB Singleton Service {}", this.getIdentifier());
357 for (final LocRibWriter locRib : this.locRibs) {
360 } catch (final Exception e) {
361 LOG.warn("Could not close LocalRib reference: {}", locRib, e);
365 final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
366 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
367 t.submit().checkedGet();
368 } catch (final TransactionCommitFailedException e) {
369 LOG.warn("Failed to remove RIB instance {} from DS.", getYangRibId(), e);
371 this.renderStats.getLocRibRouteCounter().resetAll();
373 if (this.configModuleTracker != null) {
374 this.configModuleTracker.onInstanceClose();
376 return Futures.immediateFuture(null);
380 public ServiceGroupIdentifier getIdentifier() {
381 return this.serviceGroupIdentifier;
385 public ClusterSingletonServiceRegistration registerClusterSingletonService(final ClusterSingletonService clusterSingletonService) {
386 return this.provider.registerClusterSingletonService(clusterSingletonService);
390 public ServiceGroupIdentifier getRibIServiceGroupIdentifier() {
391 return getIdentifier();