BGPCEP-701: Remove old statistics, keep only openconfig stats
[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 static java.util.Objects.requireNonNull;
11
12 import com.google.common.base.MoreObjects;
13 import com.google.common.base.MoreObjects.ToStringHelper;
14 import com.google.common.collect.ImmutableMap;
15 import com.google.common.collect.ImmutableSet;
16 import com.google.common.util.concurrent.CheckedFuture;
17 import com.google.common.util.concurrent.Futures;
18 import com.google.common.util.concurrent.ListenableFuture;
19 import java.util.HashMap;
20 import java.util.HashSet;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Map.Entry;
24 import java.util.Set;
25 import javax.annotation.Nonnull;
26 import javax.annotation.concurrent.GuardedBy;
27 import javax.annotation.concurrent.ThreadSafe;
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.binding.generator.impl.GeneratedClassLoadingStrategy;
40 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
41 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
42 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
43 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
44 import org.opendaylight.protocol.bgp.mode.api.PathSelectionMode;
45 import org.opendaylight.protocol.bgp.mode.impl.base.BasePathSelectionModeFactory;
46 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
47 import org.opendaylight.protocol.bgp.rib.impl.spi.BgpDeployer;
48 import org.opendaylight.protocol.bgp.rib.impl.spi.CodecsRegistry;
49 import org.opendaylight.protocol.bgp.rib.impl.spi.ImportPolicyPeerTracker;
50 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
51 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContext;
52 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
53 import org.opendaylight.protocol.bgp.rib.impl.state.BGPRIBStateImpl;
54 import org.opendaylight.protocol.bgp.rib.spi.ExportPolicyPeerTracker;
55 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
56 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
57 import org.opendaylight.protocol.bgp.rib.spi.util.ClusterSingletonServiceRegistrationHelper;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.BgpRib;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.RibId;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.Rib;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibKey;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.LocRib;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.Peer;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.BgpId;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier;
70 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
71 import org.opendaylight.yangtools.yang.common.QName;
72 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
73 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
74 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
75 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
76 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
77 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
78 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
79 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
80 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
81 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
82 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
83 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
84 import org.slf4j.Logger;
85 import org.slf4j.LoggerFactory;
86
87 @ThreadSafe
88 public final class RIBImpl extends BGPRIBStateImpl implements ClusterSingletonService, RIB, TransactionChainListener,
89         SchemaContextListener, AutoCloseable {
90     private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
91     private static final QName RIB_ID_QNAME = QName.create(Rib.QNAME, "id").intern();
92     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);
93
94     private final BGPDispatcher dispatcher;
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 ServiceGroupIdentifier serviceGroupIdentifier;
105     private final ClusterSingletonServiceProvider provider;
106     private final BgpDeployer.WriteConfiguration configurationWriter;
107     private ClusterSingletonServiceRegistration registration;
108     private final DOMDataBrokerExtension service;
109     private final Map<TransactionChain<?, ?>, LocRibWriter> txChainToLocRibWriter = new HashMap<>();
110     private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
111     private final ImportPolicyPeerTracker importPolicyPeerTracker;
112     private final RibId ribId;
113     private final Map<TablesKey, ExportPolicyPeerTracker> exportPolicyPeerTrackerMap;
114
115     private DOMTransactionChain domChain;
116     @GuardedBy("this")
117     private boolean isServiceInstantiated;
118
119     public RIBImpl(final ClusterSingletonServiceProvider provider, final RibId ribId, final AsNumber localAs, final BgpId localBgpId,
120             final ClusterIdentifier clusterId, final RIBExtensionConsumerContext extensions, final BGPDispatcher dispatcher,
121             final BindingCodecTreeFactory codecFactory, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
122             @Nonnull final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies, final GeneratedClassLoadingStrategy classStrategy,
123             final BgpDeployer.WriteConfiguration configurationWriter) {
124         super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(requireNonNull(ribId))),
125                 localBgpId, localAs);
126         this.localAs = requireNonNull(localAs);
127         this.bgpIdentifier = requireNonNull(localBgpId);
128         this.dispatcher = requireNonNull(dispatcher);
129         this.localTables = ImmutableSet.copyOf(localTables);
130         this.localTablesKeys = new HashSet<>();
131         this.domDataBroker = requireNonNull(domDataBroker);
132         this.service = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
133         this.extensions = requireNonNull(extensions);
134         this.codecsRegistry = CodecsRegistryImpl.create(codecFactory, classStrategy);
135         this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
136         final InstanceIdentifierBuilder yangRibIdBuilder = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME);
137         this.yangRibId = yangRibIdBuilder.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
138         this.bestPathSelectionStrategies = requireNonNull(bestPathSelectionStrategies);
139         final ClusterIdentifier cId = clusterId == null ? new ClusterIdentifier(localBgpId) : clusterId;
140         this.ribId = ribId;
141         final PolicyDatabase policyDatabase = new PolicyDatabase(this.localAs.getValue(), localBgpId, cId);
142         this.importPolicyPeerTracker = new ImportPolicyPeerTrackerImpl(policyDatabase);
143         this.serviceGroupIdentifier = ServiceGroupIdentifier.create(this.ribId.getValue() + "-service-group");
144         requireNonNull(provider, "ClusterSingletonServiceProvider is null");
145         this.provider = provider;
146         this.configurationWriter = configurationWriter;
147
148         final ImmutableMap.Builder<TablesKey, ExportPolicyPeerTracker> exportPolicies = new ImmutableMap.Builder<>();
149         for (final BgpTableType t : this.localTables) {
150             final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
151             this.localTablesKeys.add(key);
152             exportPolicies.put(key, new ExportPolicyPeerTrackerImpl(policyDatabase, key));
153         }
154         this.exportPolicyPeerTrackerMap = exportPolicies.build();
155         LOG.info("RIB Singleton Service {} registered, RIB {}", getIdentifier().getValue(), this.ribId.getValue());
156         //this need to be always the last step
157         this.registration = registerClusterSingletonService(this);
158     }
159
160     private void startLocRib(final TablesKey key) {
161         LOG.debug("Creating LocRib table for {}", key);
162         // create locRibWriter for each table
163         final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
164
165         final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
166         table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
167         table.withChild(EMPTY_TABLE_ATTRIBUTES);
168
169         final NodeIdentifierWithPredicates tableKey = RibSupportUtils.toYangTablesKey(key);
170         final InstanceIdentifierBuilder tableId = YangInstanceIdentifier.builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME));
171         tableId.nodeWithKey(tableKey.getNodeType(), tableKey.getKeyValues());
172         for (final Entry<QName, Object> e : tableKey.getKeyValues().entrySet()) {
173             table.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
174         }
175
176         final RIBSupportContext supportContext = this.ribContextRegistry.getRIBSupportContext(key);
177         if (supportContext != null) {
178             final ChoiceNode routes = supportContext.getRibSupport().emptyRoutes();
179             table.withChild(routes);
180
181             tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
182             try {
183                 tx.submit().checkedGet();
184             } catch (final TransactionCommitFailedException e1) {
185                 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
186             }
187             createLocRibWriter(key);
188         } else {
189             LOG.warn("There's no registered RIB Context for {}", key.getAfi());
190         }
191     }
192
193     private synchronized void createLocRibWriter(final TablesKey key) {
194         LOG.debug("Creating LocRIB writer for key {}", key);
195         final DOMTransactionChain txChain = createPeerChain(this);
196         PathSelectionMode pathSelectionStrategy = this.bestPathSelectionStrategies.get(key);
197         if (pathSelectionStrategy == null) {
198             pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy();
199         }
200
201         final LocRibWriter locRibWriter = LocRibWriter.create(this.ribContextRegistry, key, txChain,
202                 getYangRibId(), this.localAs, getService(), this.exportPolicyPeerTrackerMap.get(key), pathSelectionStrategy);
203         registerTotalPathCounter(key, locRibWriter);
204         registerTotalPrefixesCounter(key, locRibWriter);
205         this.txChainToLocRibWriter.put(txChain, locRibWriter);
206     }
207
208     @Override
209     public String toString() {
210         return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
211     }
212
213     protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
214         return toStringHelper;
215     }
216
217     @Override
218     public synchronized void close() throws Exception {
219         if (this.registration != null) {
220             this.registration.close();
221             this.registration = null;
222         }
223     }
224
225     @Override
226     public AsNumber getLocalAs() {
227         return this.localAs;
228     }
229
230     @Override
231     public BgpId getBgpIdentifier() {
232         return this.bgpIdentifier;
233     }
234
235     @Nonnull
236     @Override
237     public Set<? extends BgpTableType> getLocalTables() {
238         return this.localTables;
239     }
240
241     @Override
242     public BGPDispatcher getDispatcher() {
243         return this.dispatcher;
244     }
245
246     @Override
247     public synchronized void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
248         LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
249         if (this.txChainToLocRibWriter.containsKey(chain)) {
250             final LocRibWriter locRibWriter = this.txChainToLocRibWriter.remove(chain);
251             final DOMTransactionChain newChain = createPeerChain(this);
252             locRibWriter.restart(newChain);
253             this.txChainToLocRibWriter.put(newChain, locRibWriter);
254         }
255     }
256
257     @Override
258     public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
259         LOG.info("RIB {} closed successfully", getInstanceIdentifier());
260     }
261
262     @Override
263     public Set<TablesKey> getLocalTablesKeys() {
264         return this.localTablesKeys;
265     }
266
267     @Override
268     public DOMDataTreeChangeService getService() {
269         return (DOMDataTreeChangeService) this.service;
270     }
271
272     @Override
273     public YangInstanceIdentifier getYangRibId() {
274         return this.yangRibId;
275     }
276
277     @Override
278     public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
279         return this.domDataBroker.createTransactionChain(listener);
280     }
281
282     @Override
283     public RIBExtensionConsumerContext getRibExtensions() {
284         return this.extensions;
285     }
286
287     @Override
288     public RIBSupportContextRegistry getRibSupportContext() {
289         return this.ribContextRegistry;
290     }
291
292     @Override
293     public void onGlobalContextUpdated(final SchemaContext context) {
294         this.codecsRegistry.onSchemaContextUpdated(context);
295     }
296
297     @Override
298     public CodecsRegistry getCodecsRegistry() {
299         return this.codecsRegistry;
300     }
301
302     @Override
303     public ImportPolicyPeerTracker getImportPolicyPeerTracker() {
304         return this.importPolicyPeerTracker;
305     }
306
307     @Override
308     public ExportPolicyPeerTracker getExportPolicyPeerTracker(final TablesKey tablesKey) {
309         return this.exportPolicyPeerTrackerMap.get(tablesKey);
310     }
311
312     @Override
313     public synchronized void instantiateServiceInstance() {
314         this.isServiceInstantiated = true;
315         this.domChain = this.domDataBroker.createTransactionChain(this);
316         if (this.configurationWriter != null) {
317             this.configurationWriter.apply();
318         }
319         LOG.info("RIB Singleton Service {} instantiated, RIB {}", getIdentifier().getValue(), this.ribId.getValue());
320         LOG.debug("Instantiating RIB table {} at {}", this.ribId, this.yangRibId);
321
322         final ContainerNode bgpRib = Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
323                 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
324
325         final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
326                 new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, this.ribId.getValue()))
327                 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, this.ribId.getValue()))
328                 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
329                 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
330                         .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
331                         .build()).build();
332
333
334         final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
335
336         // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
337         trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
338         trans.put(LogicalDatastoreType.OPERATIONAL, this.yangRibId, ribInstance);
339
340         try {
341             trans.submit().checkedGet();
342         } catch (final TransactionCommitFailedException e) {
343             LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
344         }
345
346         LOG.debug("Effective RIB created.");
347
348         this.localTablesKeys.forEach(this::startLocRib);
349     }
350
351     @Override
352     public synchronized ListenableFuture<Void> closeServiceInstance() {
353         if (!this.isServiceInstantiated) {
354             LOG.trace("RIB Singleton Service {} already closed, RIB {}", getIdentifier().getValue(),
355                     this.ribId.getValue());
356             return Futures.immediateFuture(null);
357         }
358         LOG.info("Close RIB Singleton Service {}, RIB {}", getIdentifier().getValue(), this.ribId.getValue());
359         this.isServiceInstantiated = false;
360
361         this.txChainToLocRibWriter.values().forEach(LocRibWriter::close);
362         this.txChainToLocRibWriter.clear();
363
364         final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
365         t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
366         final CheckedFuture<Void, TransactionCommitFailedException> cleanFuture = t.submit();
367
368         this.domChain.close();
369         return cleanFuture;
370     }
371
372     @Override
373     public ServiceGroupIdentifier getIdentifier() {
374         return this.serviceGroupIdentifier;
375     }
376
377     @Override
378     public ClusterSingletonServiceRegistration registerClusterSingletonService(
379             final ClusterSingletonService clusterSingletonService) {
380         return ClusterSingletonServiceRegistrationHelper
381                 .registerSingletonService(this.provider, clusterSingletonService);
382     }
383
384     @Override
385     public ServiceGroupIdentifier getRibIServiceGroupIdentifier() {
386         return getIdentifier();
387     }
388 }