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