9d708d0ec732c2e7ae175bf0141be7873e9e4850
[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.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;
20 import java.util.Map;
21 import java.util.Map.Entry;
22 import java.util.Set;
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;
88
89 @ThreadSafe
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);
94
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;
120
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) {
126
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);
147         this.ribId = ribId;
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;
156     }
157
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);
164     }
165
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();
170
171         final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
172         table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
173         table.withChild(EMPTY_TABLE_ATTRIBUTES);
174
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()));
180         }
181
182         final ChoiceNode routes = this.ribContextRegistry.getRIBSupportContext(key).getRibSupport().emptyRoutes();
183         table.withChild(routes);
184
185         tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
186         try {
187             tx.submit().checkedGet();
188         } catch (final TransactionCommitFailedException e1) {
189             LOG.error("Failed to initiate LocRIB for key {}", key, e1);
190         }
191
192         PathSelectionMode pathSelectionStrategy = this.bestPathSelectionStrategies.get(key);
193         if (pathSelectionStrategy == null) {
194             pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy();
195         }
196
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)));
199     }
200
201     @Override
202     public String toString() {
203         return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
204     }
205
206     protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
207         return toStringHelper;
208     }
209
210     @Override
211     public synchronized void close() throws Exception {
212         if (registration != null) {
213             registration.close();
214             registration = null;
215         }
216     }
217
218     @Override
219     public AsNumber getLocalAs() {
220         return this.localAs;
221     }
222
223     @Override
224     public BgpId getBgpIdentifier() {
225         return this.bgpIdentifier;
226     }
227
228     @Override
229     public Set<? extends BgpTableType> getLocalTables() {
230         return this.localTables;
231     }
232
233     @Override
234     public BGPDispatcher getDispatcher() {
235         return this.dispatcher;
236     }
237
238     @Override
239     public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
240         LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
241     }
242
243     @Override
244     public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
245         LOG.info("RIB {} closed successfully", getInstanceIdentifier());
246     }
247
248     @Override
249     public Set<TablesKey> getLocalTablesKeys() {
250         return this.localTablesKeys;
251     }
252
253     @Override
254     public DOMDataTreeChangeService getService() {
255         return (DOMDataTreeChangeService) this.service;
256     }
257
258     @Override
259     public BGPRenderStats getRenderStats() {
260         return this.renderStats;
261     }
262
263     @Override
264     public YangInstanceIdentifier getYangRibId() {
265         return this.yangRibId;
266     }
267
268     @Override
269     public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
270         return this.domDataBroker.createTransactionChain(listener);
271     }
272
273     @Override
274     public RIBExtensionConsumerContext getRibExtensions() {
275         return this.extensions;
276     }
277
278     @Override
279     public RIBSupportContextRegistry getRibSupportContext() {
280         return this.ribContextRegistry;
281     }
282
283     @Override
284     public void onGlobalContextUpdated(final SchemaContext context) {
285         this.codecsRegistry.onSchemaContextUpdated(context);
286     }
287
288     @Override
289     public CodecsRegistry getCodecsRegistry() {
290         return this.codecsRegistry;
291     }
292
293     @Override
294     public Optional<BGPOpenConfigProvider> getOpenConfigProvider() {
295         return Optional.fromNullable(this.openConfigProvider);
296     }
297
298     @Override
299     public CacheDisconnectedPeers getCacheDisconnectedPeers() {
300         return this.cacheDisconnectedPeers;
301     }
302
303     @Override
304     public ImportPolicyPeerTracker getImportPolicyPeerTracker() {
305         return this.importPolicyPeerTracker;
306     }
307
308     @Override
309     public void instantiateServiceInstance() {
310         if(this.configurationWriter != null) {
311             this.configurationWriter.apply();
312         }
313         LOG.info("RIB Singleton Service {} instantiated", this.getIdentifier());
314         LOG.debug("Instantiating RIB table {} at {}", this.ribId , this.yangRibId);
315
316         final ContainerNode bgpRib = Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
317             .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
318
319         final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
320             new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, this.ribId .getValue()))
321             .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, this.ribId .getValue()))
322             .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
323             .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
324                 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
325                 .build()).build();
326
327
328         final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
329
330         // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
331         trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
332         trans.put(LogicalDatastoreType.OPERATIONAL, this.yangRibId, ribInstance);
333
334         try {
335             trans.submit().checkedGet();
336         } catch (final TransactionCommitFailedException e) {
337             LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
338         }
339
340         LOG.debug("Effective RIB created.");
341
342         for (final BgpTableType t : this.localTables) {
343             final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
344             this.localTablesKeys.add(key);
345             startLocRib(key, policyDatabase);
346         }
347
348         if (this.configModuleTracker != null) {
349             this.configModuleTracker.onInstanceCreate();
350         }
351     }
352
353     @Override
354     public ListenableFuture<Void> closeServiceInstance() {
355         try {
356             final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
357             t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
358             t.submit().checkedGet();
359         } catch (final TransactionCommitFailedException e) {
360             LOG.warn("Failed to remove RIB instance {} from DS.", getYangRibId(), e);
361         }
362         this.domChain.close();
363         for (final LocRibWriter locRib : this.locRibs) {
364             try {
365                 locRib.close();
366             } catch (final Exception e) {
367                 LOG.warn("Could not close LocalRib reference: {}", locRib, e);
368             }
369         }
370
371         this.renderStats.getLocRibRouteCounter().resetAll();
372
373         if (this.configModuleTracker != null) {
374             this.configModuleTracker.onInstanceClose();
375         }
376         return Futures.immediateFuture(null);
377     }
378
379     @Override
380     public ServiceGroupIdentifier getIdentifier() {
381         return this.serviceGroupIdentifier;
382     }
383
384     @Override
385     public ClusterSingletonServiceRegistration registerClusterSingletonService(final ClusterSingletonService clusterSingletonService) {
386         return this.provider.registerClusterSingletonService(clusterSingletonService);
387     }
388
389     @Override
390     public ServiceGroupIdentifier getRibIServiceGroupIdentifier() {
391         return getIdentifier();
392     }
393 }