BUG-5876 Enhance BGP Speaker and Peer Stats II
[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.RIB;
46 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
47 import org.opendaylight.protocol.bgp.rib.impl.stats.rib.impl.BGPRenderStats;
48 import org.opendaylight.protocol.bgp.rib.impl.stats.rib.impl.RIBImplRuntimeMXBeanImpl;
49 import org.opendaylight.protocol.bgp.rib.spi.CacheDisconnectedPeers;
50 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
51 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
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.rib.rev130925.rib.tables.Routes;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.BgpId;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier;
66 import org.opendaylight.yangtools.binding.data.codec.api.BindingCodecTreeFactory;
67 import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
68 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
69 import org.opendaylight.yangtools.yang.common.QName;
70 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
71 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
72 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
73 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
74 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
75 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
76 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
77 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
78 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
79 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
80 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
81 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
82 import org.slf4j.Logger;
83 import org.slf4j.LoggerFactory;
84
85 @ThreadSafe
86 public final class RIBImpl extends DefaultRibReference implements AutoCloseable, RIB, TransactionChainListener, SchemaContextListener {
87     private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
88     @VisibleForTesting
89     public static final QName RIB_ID_QNAME = QName.create(Rib.QNAME, "id").intern();
90     @VisibleForTesting
91     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);
92
93     private final BGPDispatcher dispatcher;
94     private final DOMTransactionChain domChain;
95     private final AsNumber localAs;
96     private final BgpId bgpIdentifier;
97     private final Set<BgpTableType> localTables;
98     private final Set<TablesKey> localTablesKeys;
99     private final DOMDataBroker domDataBroker;
100     private final RIBExtensionConsumerContext extensions;
101     private final YangInstanceIdentifier yangRibId;
102     private final RIBSupportContextRegistryImpl ribContextRegistry;
103     private final CodecsRegistryImpl codecsRegistry;
104     private final DOMDataBrokerExtension service;
105     private final List<LocRibWriter> locRibs = new ArrayList<>();
106     private final BGPConfigModuleTracker configModuleTracker;
107     private final BGPOpenConfigProvider openConfigProvider;
108     private final CacheDisconnectedPeers cacheDisconnectedPeers;
109     private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
110     private final ImportPolicyPeerTracker importPolicyPeerTracker;
111     private final RIBImplRuntimeMXBeanImpl renderStats;
112     private RIBImplRuntimeRegistrator registrator = null;
113     private RIBImplRuntimeRegistration runtimeReg = null;
114
115     public RIBImpl(final RibId ribId, final AsNumber localAs, final BgpId localBgpId, final ClusterIdentifier clusterId, final RIBExtensionConsumerContext extensions,
116         final BGPDispatcher dispatcher, final BindingCodecTreeFactory codecFactory,
117         final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
118         @Nonnull final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies, final GeneratedClassLoadingStrategy classStrategy,
119         final BGPConfigModuleTracker moduleTracker, final BGPOpenConfigProvider openConfigProvider) {
120         super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId))));
121         this.domChain = domDataBroker.createTransactionChain(this);
122         this.localAs = Preconditions.checkNotNull(localAs);
123         this.bgpIdentifier = Preconditions.checkNotNull(localBgpId);
124         this.dispatcher = Preconditions.checkNotNull(dispatcher);
125         this.localTables = ImmutableSet.copyOf(localTables);
126         this.localTablesKeys = new HashSet<>();
127         this.domDataBroker = Preconditions.checkNotNull(domDataBroker);
128         this.extensions = Preconditions.checkNotNull(extensions);
129         this.codecsRegistry = CodecsRegistryImpl.create(codecFactory, classStrategy);
130         this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
131         final InstanceIdentifierBuilder yangRibIdBuilder = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME);
132         this.yangRibId = yangRibIdBuilder.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
133         this.configModuleTracker = moduleTracker;
134         this.openConfigProvider = openConfigProvider;
135         this.cacheDisconnectedPeers = new CacheDisconnectedPeersImpl();
136         this.bestPathSelectionStrategies = Preconditions.checkNotNull(bestPathSelectionStrategies);
137         final ClusterIdentifier cId = (clusterId == null) ? new ClusterIdentifier(localBgpId) : clusterId;
138         this.renderStats = new RIBImplRuntimeMXBeanImpl(localBgpId, ribId, localAs, cId);
139
140         LOG.debug("Instantiating RIB table {} at {}", ribId, this.yangRibId);
141
142         final ContainerNode bgpRib = Builders.containerBuilder()
143             .withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
144                 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
145
146         final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
147                 new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()))
148                     .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, ribId.getValue()))
149                     .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
150                     .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
151                     .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
152                     .build()).build();
153
154
155         final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
156
157         // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
158         trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
159         trans.put(LogicalDatastoreType.OPERATIONAL, yangRibIdBuilder.build(), ribInstance);
160
161         try {
162             trans.submit().checkedGet();
163         } catch (final TransactionCommitFailedException e) {
164             LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
165         }
166         final PolicyDatabase policyDatabase  = new PolicyDatabase(localAs.getValue(), localBgpId, cId);
167         this.importPolicyPeerTracker = new ImportPolicyPeerTracker(policyDatabase);
168
169         final DOMDataBrokerExtension domDatatreeChangeService = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
170         this.service = domDatatreeChangeService;
171         LOG.debug("Effective RIB created.");
172
173         for (final BgpTableType t : this.localTables) {
174             final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
175             this.localTablesKeys.add(key);
176             startLocRib(key, policyDatabase);
177         }
178
179         if (this.configModuleTracker != null) {
180             this.configModuleTracker.onInstanceCreate();
181         }
182     }
183
184     public RIBImpl(final RibId ribId, final AsNumber localAs, final BgpId localBgpId, @Nullable final ClusterIdentifier clusterId, final RIBExtensionConsumerContext extensions,
185                    final BGPDispatcher dispatcher, final BindingCodecTreeFactory codecFactory,
186                    final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
187                    final Map<TablesKey, PathSelectionMode> bestPathSelectionstrategies, final GeneratedClassLoadingStrategy classStrategy) {
188         this(ribId, localAs, localBgpId, clusterId, extensions, dispatcher, codecFactory,
189             domDataBroker, localTables, bestPathSelectionstrategies, classStrategy, null, null);
190     }
191
192     public synchronized void registerRootRuntimeBean(final RIBImplRuntimeRegistrator registrator) {
193         this.registrator = registrator;
194
195         initStatsRuntimeBean();
196     }
197
198     /**
199      * Register the statistic runtime bean
200      */
201     private void initStatsRuntimeBean() {
202         if (this.registrator != null) {
203             LOG.debug("Initializing Render Status runtime bean..");
204             this.runtimeReg = this.registrator.register(renderStats);
205         }
206     }
207
208     private void stopStatsRuntimeBean() {
209         if (this.runtimeReg != null) {
210             LOG.debug("Destroying Render Status runtime bean..");
211             this.runtimeReg.close();
212             this.runtimeReg = null;
213         }
214         // reset all the stats
215         renderStats.getLocRibRouteCounter().resetAll();
216     }
217
218     private void startLocRib(final TablesKey key, final PolicyDatabase pd) {
219         LOG.debug("Creating LocRib table for {}", key);
220         // create locRibWriter for each table
221         final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
222
223         final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
224         table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
225         table.withChild(EMPTY_TABLE_ATTRIBUTES);
226
227         final NodeIdentifierWithPredicates tableKey = RibSupportUtils.toYangTablesKey(key);
228         final InstanceIdentifierBuilder tableId = YangInstanceIdentifier.builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME));
229         tableId.nodeWithKey(tableKey.getNodeType(), tableKey.getKeyValues());
230         for (final Entry<QName, Object> e : tableKey.getKeyValues().entrySet()) {
231             table.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
232         }
233
234         final ChoiceNode routes = this.ribContextRegistry.getRIBSupportContext(key).getRibSupport().emptyRoutes();
235         table.withChild(routes);
236
237         tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
238         try {
239             tx.submit().checkedGet();
240         } catch (final TransactionCommitFailedException e1) {
241             LOG.error("Failed to initiate LocRIB for key {}", key, e1);
242         }
243
244         PathSelectionMode pathSelectionStrategy = this.bestPathSelectionStrategies.get(key);
245         if (pathSelectionStrategy == null) {
246             pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy();
247         }
248
249         this.locRibs.add(LocRibWriter.create(this.ribContextRegistry, key, createPeerChain(this), getYangRibId(), this.localAs, getService(), pd,
250             this.cacheDisconnectedPeers, pathSelectionStrategy, this.renderStats.getLocRibRouteCounter().init(key)));
251     }
252
253     @Override
254     public String toString() {
255         return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
256     }
257
258     protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
259         return toStringHelper;
260     }
261
262     @Override
263     public synchronized void close() throws InterruptedException, ExecutionException {
264         final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
265         t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
266         t.submit().get();
267         this.domChain.close();
268         for (final LocRibWriter locRib : this.locRibs) {
269             try {
270                 locRib.close();
271             } catch (final Exception e) {
272                 LOG.warn("Could not close LocalRib reference: {}", locRib, e);
273             }
274         }
275
276         stopStatsRuntimeBean();
277
278         if (this.configModuleTracker != null) {
279             this.configModuleTracker.onInstanceClose();
280         }
281     }
282
283     @Override
284     public AsNumber getLocalAs() {
285         return this.localAs;
286     }
287
288     @Override
289     public BgpId getBgpIdentifier() {
290         return this.bgpIdentifier;
291     }
292
293     @Override
294     public Set<? extends BgpTableType> getLocalTables() {
295         return this.localTables;
296     }
297
298     @Override
299     public BGPDispatcher getDispatcher() {
300         return this.dispatcher;
301     }
302
303     @Override
304     public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
305         LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
306     }
307
308     @Override
309     public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
310         LOG.info("RIB {} closed successfully", getInstanceIdentifier());
311     }
312
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     public ImportPolicyPeerTracker getImportPolicyPeerTracker() {
368         return this.importPolicyPeerTracker;
369     }
370 }