842e92c4b49d35d5da5bba8de41fab34839d1514
[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.Preconditions;
13 import com.google.common.collect.ImmutableSet;
14 import com.google.common.util.concurrent.Futures;
15 import com.google.common.util.concurrent.ListenableFuture;
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.concurrent.ThreadSafe;
24 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
25 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
26 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
27 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
28 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
29 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
30 import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
31 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
32 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
33 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
34 import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTreeFactory;
35 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
36 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
37 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
38 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
39 import org.opendaylight.protocol.bgp.mode.api.PathSelectionMode;
40 import org.opendaylight.protocol.bgp.mode.impl.base.BasePathSelectionModeFactory;
41 import org.opendaylight.protocol.bgp.rib.DefaultRibReference;
42 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
43 import org.opendaylight.protocol.bgp.rib.impl.spi.BgpDeployer;
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 ClusterSingletonService, AutoCloseable, RIB, TransactionChainListener, SchemaContextListener {
85     private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
86     private static final QName RIB_ID_QNAME = QName.create(Rib.QNAME, "id").intern();
87     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);
88
89     private final BGPDispatcher dispatcher;
90     private final DOMTransactionChain domChain;
91     private final AsNumber localAs;
92     private final BgpId bgpIdentifier;
93     private final Set<BgpTableType> localTables;
94     private final Set<TablesKey> localTablesKeys;
95     private final DOMDataBroker domDataBroker;
96     private final RIBExtensionConsumerContext extensions;
97     private final YangInstanceIdentifier yangRibId;
98     private final RIBSupportContextRegistryImpl ribContextRegistry;
99     private final CodecsRegistryImpl codecsRegistry;
100     private final ServiceGroupIdentifier serviceGroupIdentifier;
101     private final ClusterSingletonServiceProvider provider;
102     private final PolicyDatabase policyDatabase;
103     private final BgpDeployer.WriteConfiguration configurationWriter;
104     private ClusterSingletonServiceRegistration registration;
105     private final DOMDataBrokerExtension service;
106     private final List<LocRibWriter> locRibs = new ArrayList<>();
107     private final CacheDisconnectedPeers cacheDisconnectedPeers;
108     private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
109     private final ImportPolicyPeerTracker importPolicyPeerTracker;
110     private final RIBImplRuntimeMXBeanImpl renderStats;
111     private final RibId ribId;
112
113     public RIBImpl(final ClusterSingletonServiceProvider provider, final RibId ribId, final AsNumber localAs, final BgpId localBgpId,
114         final ClusterIdentifier clusterId, final RIBExtensionConsumerContext extensions, final BGPDispatcher dispatcher,
115         final BindingCodecTreeFactory codecFactory, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
116         @Nonnull final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies, final GeneratedClassLoadingStrategy classStrategy,
117         final BgpDeployer.WriteConfiguration configurationWriter) {
118
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.service = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
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.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         this.ribId = ribId;
138         this.policyDatabase  = new PolicyDatabase(this.localAs.getValue(), localBgpId, cId);
139         this.importPolicyPeerTracker = new ImportPolicyPeerTrackerImpl( this.policyDatabase);
140         this.serviceGroupIdentifier = ServiceGroupIdentifier.create(this.ribId + "-service-group");
141         Preconditions.checkNotNull(provider, "ClusterSingletonServiceProvider is null");
142         this.provider = provider;
143         this.configurationWriter = configurationWriter;
144         LOG.info("RIB Singleton Service {} registered", getIdentifier());
145         //this need to be always the last step
146         this.registration = registerClusterSingletonService(this);
147     }
148
149     private void startLocRib(final TablesKey key, final PolicyDatabase pd) {
150         LOG.debug("Creating LocRib table for {}", key);
151         // create locRibWriter for each table
152         final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
153
154         final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
155         table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
156         table.withChild(EMPTY_TABLE_ATTRIBUTES);
157
158         final NodeIdentifierWithPredicates tableKey = RibSupportUtils.toYangTablesKey(key);
159         final InstanceIdentifierBuilder tableId = YangInstanceIdentifier.builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME));
160         tableId.nodeWithKey(tableKey.getNodeType(), tableKey.getKeyValues());
161         for (final Entry<QName, Object> e : tableKey.getKeyValues().entrySet()) {
162             table.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
163         }
164
165         final ChoiceNode routes = this.ribContextRegistry.getRIBSupportContext(key).getRibSupport().emptyRoutes();
166         table.withChild(routes);
167
168         tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
169         try {
170             tx.submit().checkedGet();
171         } catch (final TransactionCommitFailedException e1) {
172             LOG.error("Failed to initiate LocRIB for key {}", key, e1);
173         }
174
175         PathSelectionMode pathSelectionStrategy = this.bestPathSelectionStrategies.get(key);
176         if (pathSelectionStrategy == null) {
177             pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy();
178         }
179
180         this.locRibs.add(LocRibWriter.create(this.ribContextRegistry, key, createPeerChain(this), getYangRibId(), this.localAs, getService(), pd,
181                 this.cacheDisconnectedPeers, pathSelectionStrategy, this.renderStats.getLocRibRouteCounter().init(key)));
182     }
183
184     @Override
185     public String toString() {
186         return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
187     }
188
189     protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
190         return toStringHelper;
191     }
192
193     @Override
194     public synchronized void close() throws Exception {
195         if (this.registration != null) {
196             this.registration.close();
197             this.registration = null;
198         }
199         if(this.domChain != null) {
200             this.domChain.close();
201         }
202     }
203
204     @Override
205     public AsNumber getLocalAs() {
206         return this.localAs;
207     }
208
209     @Override
210     public BgpId getBgpIdentifier() {
211         return this.bgpIdentifier;
212     }
213
214     @Nonnull
215     @Override
216     public Set<? extends BgpTableType> getLocalTables() {
217         return this.localTables;
218     }
219
220     @Override
221     public BGPDispatcher getDispatcher() {
222         return this.dispatcher;
223     }
224
225     @Override
226     public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
227         LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
228     }
229
230     @Override
231     public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
232         LOG.info("RIB {} closed successfully", getInstanceIdentifier());
233     }
234
235     @Override
236     public Set<TablesKey> getLocalTablesKeys() {
237         return this.localTablesKeys;
238     }
239
240     @Override
241     public DOMDataTreeChangeService getService() {
242         return (DOMDataTreeChangeService) this.service;
243     }
244
245     @Override
246     public BGPRenderStats getRenderStats() {
247         return this.renderStats;
248     }
249
250     @Override
251     public YangInstanceIdentifier getYangRibId() {
252         return this.yangRibId;
253     }
254
255     @Override
256     public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
257         return this.domDataBroker.createTransactionChain(listener);
258     }
259
260     @Override
261     public RIBExtensionConsumerContext getRibExtensions() {
262         return this.extensions;
263     }
264
265     @Override
266     public RIBSupportContextRegistry getRibSupportContext() {
267         return this.ribContextRegistry;
268     }
269
270     @Override
271     public void onGlobalContextUpdated(final SchemaContext context) {
272         this.codecsRegistry.onSchemaContextUpdated(context);
273     }
274
275     @Override
276     public CodecsRegistry getCodecsRegistry() {
277         return this.codecsRegistry;
278     }
279     @Override
280     public CacheDisconnectedPeers getCacheDisconnectedPeers() {
281         return this.cacheDisconnectedPeers;
282     }
283
284     @Override
285     public ImportPolicyPeerTracker getImportPolicyPeerTracker() {
286         return this.importPolicyPeerTracker;
287     }
288
289     @Override
290     public void instantiateServiceInstance() {
291         if(this.configurationWriter != null) {
292             this.configurationWriter.apply();
293         }
294         LOG.info("RIB Singleton Service {} instantiated", getIdentifier());
295         LOG.debug("Instantiating RIB table {} at {}", this.ribId , this.yangRibId);
296
297         final ContainerNode bgpRib = Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
298             .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
299
300         final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
301             new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, this.ribId .getValue()))
302             .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, this.ribId .getValue()))
303             .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
304             .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
305                 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
306                 .build()).build();
307
308
309         final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
310
311         // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
312         trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
313         trans.put(LogicalDatastoreType.OPERATIONAL, this.yangRibId, ribInstance);
314
315         try {
316             trans.submit().checkedGet();
317         } catch (final TransactionCommitFailedException e) {
318             LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
319         }
320
321         LOG.debug("Effective RIB created.");
322
323         for (final BgpTableType t : this.localTables) {
324             final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
325             this.localTablesKeys.add(key);
326             startLocRib(key, this.policyDatabase);
327         }
328     }
329
330     @Override
331     public ListenableFuture<Void> closeServiceInstance() {
332         LOG.info("Close RIB Singleton Service {}", getIdentifier());
333         for (final LocRibWriter locRib : this.locRibs) {
334             try {
335                 locRib.close();
336             } catch (final Exception e) {
337                 LOG.warn("Could not close LocalRib reference: {}", locRib, e);
338             }
339         }
340         try {
341             final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
342             t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
343             t.submit().checkedGet();
344         } catch (final TransactionCommitFailedException e) {
345             LOG.warn("Failed to remove RIB instance {} from DS.", getYangRibId(), e);
346         }
347         this.renderStats.getLocRibRouteCounter().resetAll();
348
349         return Futures.immediateFuture(null);
350     }
351
352     @Override
353     public ServiceGroupIdentifier getIdentifier() {
354         return this.serviceGroupIdentifier;
355     }
356
357     @Override
358     public ClusterSingletonServiceRegistration registerClusterSingletonService(final ClusterSingletonService clusterSingletonService) {
359         return this.provider.registerClusterSingletonService(clusterSingletonService);
360     }
361
362     @Override
363     public ServiceGroupIdentifier getRibIServiceGroupIdentifier() {
364         return getIdentifier();
365     }
366 }