7b30f0b3b2ec84d0b1b97d61e05795b3a5f3f575
[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         this.domChain.close();
196         if (this.registration != null) {
197             this.registration.close();
198             this.registration = null;
199         }
200     }
201
202     @Override
203     public AsNumber getLocalAs() {
204         return this.localAs;
205     }
206
207     @Override
208     public BgpId getBgpIdentifier() {
209         return this.bgpIdentifier;
210     }
211
212     @Override
213     public Set<? extends BgpTableType> getLocalTables() {
214         return this.localTables;
215     }
216
217     @Override
218     public BGPDispatcher getDispatcher() {
219         return this.dispatcher;
220     }
221
222     @Override
223     public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
224         LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
225     }
226
227     @Override
228     public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
229         LOG.info("RIB {} closed successfully", getInstanceIdentifier());
230     }
231
232     @Override
233     public Set<TablesKey> getLocalTablesKeys() {
234         return this.localTablesKeys;
235     }
236
237     @Override
238     public DOMDataTreeChangeService getService() {
239         return (DOMDataTreeChangeService) this.service;
240     }
241
242     @Override
243     public BGPRenderStats getRenderStats() {
244         return this.renderStats;
245     }
246
247     @Override
248     public YangInstanceIdentifier getYangRibId() {
249         return this.yangRibId;
250     }
251
252     @Override
253     public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
254         return this.domDataBroker.createTransactionChain(listener);
255     }
256
257     @Override
258     public RIBExtensionConsumerContext getRibExtensions() {
259         return this.extensions;
260     }
261
262     @Override
263     public RIBSupportContextRegistry getRibSupportContext() {
264         return this.ribContextRegistry;
265     }
266
267     @Override
268     public void onGlobalContextUpdated(final SchemaContext context) {
269         this.codecsRegistry.onSchemaContextUpdated(context);
270     }
271
272     @Override
273     public CodecsRegistry getCodecsRegistry() {
274         return this.codecsRegistry;
275     }
276     @Override
277     public CacheDisconnectedPeers getCacheDisconnectedPeers() {
278         return this.cacheDisconnectedPeers;
279     }
280
281     @Override
282     public ImportPolicyPeerTracker getImportPolicyPeerTracker() {
283         return this.importPolicyPeerTracker;
284     }
285
286     @Override
287     public void instantiateServiceInstance() {
288         if(this.configurationWriter != null) {
289             this.configurationWriter.apply();
290         }
291         LOG.info("RIB Singleton Service {} instantiated", getIdentifier());
292         LOG.debug("Instantiating RIB table {} at {}", this.ribId , this.yangRibId);
293
294         final ContainerNode bgpRib = Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
295             .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
296
297         final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
298             new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, this.ribId .getValue()))
299             .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, this.ribId .getValue()))
300             .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
301             .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
302                 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
303                 .build()).build();
304
305
306         final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
307
308         // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
309         trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
310         trans.put(LogicalDatastoreType.OPERATIONAL, this.yangRibId, ribInstance);
311
312         try {
313             trans.submit().checkedGet();
314         } catch (final TransactionCommitFailedException e) {
315             LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
316         }
317
318         LOG.debug("Effective RIB created.");
319
320         for (final BgpTableType t : this.localTables) {
321             final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
322             this.localTablesKeys.add(key);
323             startLocRib(key, this.policyDatabase);
324         }
325     }
326
327     @Override
328     public ListenableFuture<Void> closeServiceInstance() {
329         LOG.info("Close RIB Singleton Service {}", getIdentifier());
330         for (final LocRibWriter locRib : this.locRibs) {
331             try {
332                 locRib.close();
333             } catch (final Exception e) {
334                 LOG.warn("Could not close LocalRib reference: {}", locRib, e);
335             }
336         }
337         try {
338             final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
339             t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
340             t.submit().checkedGet();
341         } catch (final TransactionCommitFailedException e) {
342             LOG.warn("Failed to remove RIB instance {} from DS.", getYangRibId(), e);
343         }
344         this.renderStats.getLocRibRouteCounter().resetAll();
345
346         return Futures.immediateFuture(null);
347     }
348
349     @Override
350     public ServiceGroupIdentifier getIdentifier() {
351         return this.serviceGroupIdentifier;
352     }
353
354     @Override
355     public ClusterSingletonServiceRegistration registerClusterSingletonService(final ClusterSingletonService clusterSingletonService) {
356         return this.provider.registerClusterSingletonService(clusterSingletonService);
357     }
358
359     @Override
360     public ServiceGroupIdentifier getRibIServiceGroupIdentifier() {
361         return getIdentifier();
362     }
363 }