Keep internal API contract between RIB and BGPPeer/ApplicationPeer
[bgpcep.git] / bgp / rib-impl / src / main / java / org / opendaylight / protocol / bgp / rib / impl / RIBImpl.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.protocol.bgp.rib.impl;
9
10 import com.google.common.annotations.VisibleForTesting;
11 import com.google.common.base.MoreObjects;
12 import com.google.common.base.MoreObjects.ToStringHelper;
13 import com.google.common.base.Optional;
14 import com.google.common.base.Preconditions;
15 import com.google.common.collect.ImmutableSet;
16 import java.util.ArrayList;
17 import java.util.HashSet;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Map.Entry;
21 import java.util.Set;
22 import java.util.concurrent.ExecutionException;
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.protocol.bgp.mode.api.PathSelectionMode;
39 import org.opendaylight.protocol.bgp.mode.impl.base.BasePathSelectionModeFactory;
40 import org.opendaylight.protocol.bgp.openconfig.spi.BGPConfigModuleTracker;
41 import org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenConfigProvider;
42 import org.opendaylight.protocol.bgp.rib.DefaultRibReference;
43 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
44 import org.opendaylight.protocol.bgp.rib.impl.spi.CodecsRegistry;
45 import org.opendaylight.protocol.bgp.rib.impl.spi.ImportPolicyPeerTracker;
46 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
47 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
48 import org.opendaylight.protocol.bgp.rib.impl.stats.rib.impl.BGPRenderStats;
49 import org.opendaylight.protocol.bgp.rib.impl.stats.rib.impl.RIBImplRuntimeMXBeanImpl;
50 import org.opendaylight.protocol.bgp.rib.spi.CacheDisconnectedPeers;
51 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
52 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.BgpRib;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.RibId;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.Rib;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibKey;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.LocRib;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.Peer;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.BgpId;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier;
65 import org.opendaylight.yangtools.binding.data.codec.api.BindingCodecTreeFactory;
66 import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
67 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
68 import org.opendaylight.yangtools.yang.common.QName;
69 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
70 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
71 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
72 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
73 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
74 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
75 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
76 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
77 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
78 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
79 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
80 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
81 import org.slf4j.Logger;
82 import org.slf4j.LoggerFactory;
83
84 @ThreadSafe
85 public final class RIBImpl extends DefaultRibReference implements AutoCloseable, RIB, TransactionChainListener, SchemaContextListener {
86     private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
87     @VisibleForTesting
88     public static final QName RIB_ID_QNAME = QName.create(Rib.QNAME, "id").intern();
89     @VisibleForTesting
90     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);
91
92     private final BGPDispatcher dispatcher;
93     private final DOMTransactionChain domChain;
94     private final AsNumber localAs;
95     private final BgpId bgpIdentifier;
96     private final Set<BgpTableType> localTables;
97     private final Set<TablesKey> localTablesKeys;
98     private final DOMDataBroker domDataBroker;
99     private final RIBExtensionConsumerContext extensions;
100     private final YangInstanceIdentifier yangRibId;
101     private final RIBSupportContextRegistryImpl ribContextRegistry;
102     private final CodecsRegistryImpl codecsRegistry;
103     private final DOMDataBrokerExtension service;
104     private final List<LocRibWriter> locRibs = new ArrayList<>();
105     private final BGPConfigModuleTracker configModuleTracker;
106     private final BGPOpenConfigProvider openConfigProvider;
107     private final CacheDisconnectedPeers cacheDisconnectedPeers;
108     private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
109     private final ImportPolicyPeerTracker importPolicyPeerTracker;
110     private final RIBImplRuntimeMXBeanImpl renderStats;
111     private RIBImplRuntimeRegistrator registrator = null;
112     private RIBImplRuntimeRegistration runtimeReg = null;
113
114     public RIBImpl(final RibId ribId, final AsNumber localAs, final BgpId localBgpId, final ClusterIdentifier clusterId, final RIBExtensionConsumerContext extensions,
115             final BGPDispatcher dispatcher, final BindingCodecTreeFactory codecFactory,
116             final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
117             @Nonnull final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies, final GeneratedClassLoadingStrategy classStrategy,
118             final BGPConfigModuleTracker moduleTracker, final BGPOpenConfigProvider openConfigProvider) {
119         super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId))));
120         this.domChain = domDataBroker.createTransactionChain(this);
121         this.localAs = Preconditions.checkNotNull(localAs);
122         this.bgpIdentifier = Preconditions.checkNotNull(localBgpId);
123         this.dispatcher = Preconditions.checkNotNull(dispatcher);
124         this.localTables = ImmutableSet.copyOf(localTables);
125         this.localTablesKeys = new HashSet<>();
126         this.domDataBroker = Preconditions.checkNotNull(domDataBroker);
127         this.extensions = Preconditions.checkNotNull(extensions);
128         this.codecsRegistry = CodecsRegistryImpl.create(codecFactory, classStrategy);
129         this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
130         final InstanceIdentifierBuilder yangRibIdBuilder = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME);
131         this.yangRibId = yangRibIdBuilder.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
132         this.configModuleTracker = moduleTracker;
133         this.openConfigProvider = openConfigProvider;
134         this.cacheDisconnectedPeers = new CacheDisconnectedPeersImpl();
135         this.bestPathSelectionStrategies = Preconditions.checkNotNull(bestPathSelectionStrategies);
136         final ClusterIdentifier cId = (clusterId == null) ? new ClusterIdentifier(localBgpId) : clusterId;
137         this.renderStats = new RIBImplRuntimeMXBeanImpl(localBgpId, ribId, localAs, cId);
138
139         LOG.debug("Instantiating RIB table {} at {}", ribId, this.yangRibId);
140
141         final ContainerNode bgpRib = Builders.containerBuilder()
142                 .withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
143                 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
144
145         final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
146                 new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()))
147                 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, ribId.getValue()))
148                 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
149                 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
150                         .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
151                         .build()).build();
152
153
154         final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
155
156         // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
157         trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
158         trans.put(LogicalDatastoreType.OPERATIONAL, yangRibIdBuilder.build(), ribInstance);
159
160         try {
161             trans.submit().checkedGet();
162         } catch (final TransactionCommitFailedException e) {
163             LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
164         }
165         final PolicyDatabase policyDatabase  = new PolicyDatabase(localAs.getValue(), localBgpId, cId);
166         this.importPolicyPeerTracker = new ImportPolicyPeerTrackerImpl(policyDatabase);
167
168         final DOMDataBrokerExtension domDatatreeChangeService = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
169         this.service = domDatatreeChangeService;
170         LOG.debug("Effective RIB created.");
171
172         for (final BgpTableType t : this.localTables) {
173             final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
174             this.localTablesKeys.add(key);
175             startLocRib(key, policyDatabase);
176         }
177
178         if (this.configModuleTracker != null) {
179             this.configModuleTracker.onInstanceCreate();
180         }
181     }
182
183     public RIBImpl(final RibId ribId, final AsNumber localAs, final BgpId localBgpId, @Nullable final ClusterIdentifier clusterId, final RIBExtensionConsumerContext extensions,
184             final BGPDispatcher dispatcher, final BindingCodecTreeFactory codecFactory,
185             final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
186             final Map<TablesKey, PathSelectionMode> bestPathSelectionstrategies, final GeneratedClassLoadingStrategy classStrategy) {
187         this(ribId, localAs, localBgpId, clusterId, extensions, dispatcher, codecFactory,
188                 domDataBroker, localTables, bestPathSelectionstrategies, classStrategy, null, null);
189     }
190
191     public synchronized void registerRootRuntimeBean(final RIBImplRuntimeRegistrator registrator) {
192         this.registrator = registrator;
193
194         initStatsRuntimeBean();
195     }
196
197     /**
198      * Register the statistic runtime bean
199      */
200     private void initStatsRuntimeBean() {
201         if (this.registrator != null) {
202             LOG.debug("Initializing Render Status runtime bean..");
203             this.runtimeReg = this.registrator.register(this.renderStats);
204         }
205     }
206
207     private void stopStatsRuntimeBean() {
208         if (this.runtimeReg != null) {
209             LOG.debug("Destroying Render Status runtime bean..");
210             this.runtimeReg.close();
211             this.runtimeReg = null;
212         }
213         // reset all the stats
214         this.renderStats.getLocRibRouteCounter().resetAll();
215     }
216
217     private void startLocRib(final TablesKey key, final PolicyDatabase pd) {
218         LOG.debug("Creating LocRib table for {}", key);
219         // create locRibWriter for each table
220         final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
221
222         final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
223         table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
224         table.withChild(EMPTY_TABLE_ATTRIBUTES);
225
226         final NodeIdentifierWithPredicates tableKey = RibSupportUtils.toYangTablesKey(key);
227         final InstanceIdentifierBuilder tableId = YangInstanceIdentifier.builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME));
228         tableId.nodeWithKey(tableKey.getNodeType(), tableKey.getKeyValues());
229         for (final Entry<QName, Object> e : tableKey.getKeyValues().entrySet()) {
230             table.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
231         }
232
233         final ChoiceNode routes = this.ribContextRegistry.getRIBSupportContext(key).getRibSupport().emptyRoutes();
234         table.withChild(routes);
235
236         tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
237         try {
238             tx.submit().checkedGet();
239         } catch (final TransactionCommitFailedException e1) {
240             LOG.error("Failed to initiate LocRIB for key {}", key, e1);
241         }
242
243         PathSelectionMode pathSelectionStrategy = this.bestPathSelectionStrategies.get(key);
244         if (pathSelectionStrategy == null) {
245             pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy();
246         }
247
248         this.locRibs.add(LocRibWriter.create(this.ribContextRegistry, key, createPeerChain(this), getYangRibId(), this.localAs, getService(), pd,
249                 this.cacheDisconnectedPeers, pathSelectionStrategy, this.renderStats.getLocRibRouteCounter().init(key)));
250     }
251
252     @Override
253     public String toString() {
254         return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
255     }
256
257     protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
258         return toStringHelper;
259     }
260
261     @Override
262     public synchronized void close() throws InterruptedException, ExecutionException {
263         final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
264         t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
265         t.submit().get();
266         this.domChain.close();
267         for (final LocRibWriter locRib : this.locRibs) {
268             try {
269                 locRib.close();
270             } catch (final Exception e) {
271                 LOG.warn("Could not close LocalRib reference: {}", locRib, e);
272             }
273         }
274
275         stopStatsRuntimeBean();
276
277         if (this.configModuleTracker != null) {
278             this.configModuleTracker.onInstanceClose();
279         }
280     }
281
282     @Override
283     public AsNumber getLocalAs() {
284         return this.localAs;
285     }
286
287     @Override
288     public BgpId getBgpIdentifier() {
289         return this.bgpIdentifier;
290     }
291
292     @Override
293     public Set<? extends BgpTableType> getLocalTables() {
294         return this.localTables;
295     }
296
297     @Override
298     public BGPDispatcher getDispatcher() {
299         return this.dispatcher;
300     }
301
302     @Override
303     public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
304         LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
305     }
306
307     @Override
308     public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
309         LOG.info("RIB {} closed successfully", getInstanceIdentifier());
310     }
311
312     @Override
313     public Set<TablesKey> getLocalTablesKeys() {
314         return this.localTablesKeys;
315     }
316
317     @Override
318     public DOMDataTreeChangeService getService() {
319         return (DOMDataTreeChangeService) this.service;
320     }
321
322     @Override
323     public BGPRenderStats getRenderStats() {
324         return this.renderStats;
325     }
326
327     @Override
328     public YangInstanceIdentifier getYangRibId() {
329         return this.yangRibId;
330     }
331
332     @Override
333     public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
334         return this.domDataBroker.createTransactionChain(listener);
335     }
336
337     @Override
338     public RIBExtensionConsumerContext getRibExtensions() {
339         return this.extensions;
340     }
341
342     @Override
343     public RIBSupportContextRegistry getRibSupportContext() {
344         return this.ribContextRegistry;
345     }
346
347     @Override
348     public void onGlobalContextUpdated(final SchemaContext context) {
349         this.codecsRegistry.onSchemaContextUpdated(context);
350     }
351
352     @Override
353     public CodecsRegistry getCodecsRegistry() {
354         return this.codecsRegistry;
355     }
356
357     @Override
358     public Optional<BGPOpenConfigProvider> getOpenConfigProvider() {
359         return Optional.fromNullable(this.openConfigProvider);
360     }
361
362     @Override
363     public CacheDisconnectedPeers getCacheDisconnectedPeers() {
364         return this.cacheDisconnectedPeers;
365     }
366
367     @Override
368     public ImportPolicyPeerTracker getImportPolicyPeerTracker() {
369         return this.importPolicyPeerTracker;
370     }
371 }