Fix more rib-impl checkstyle
[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.collect.ImmutableSet;
14 import com.google.common.util.concurrent.FluentFuture;
15 import com.google.common.util.concurrent.FutureCallback;
16 import com.google.common.util.concurrent.MoreExecutors;
17 import java.util.HashMap;
18 import java.util.HashSet;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.Set;
22 import java.util.concurrent.ExecutionException;
23 import javax.annotation.Nonnull;
24 import javax.annotation.concurrent.GuardedBy;
25 import javax.annotation.concurrent.ThreadSafe;
26 import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
27 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
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.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.common.api.CommitInfo;
38 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
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.openconfig.spi.BGPTableTypeRegistryConsumer;
42 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
43 import org.opendaylight.protocol.bgp.rib.impl.spi.CodecsRegistry;
44 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
45 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
46 import org.opendaylight.protocol.bgp.rib.impl.spi.RibOutRefresh;
47 import org.opendaylight.protocol.bgp.rib.impl.state.BGPRIBStateImpl;
48 import org.opendaylight.protocol.bgp.rib.spi.BGPPeerTracker;
49 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
50 import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
51 import org.opendaylight.protocol.bgp.rib.spi.policy.BGPRibRoutingPolicy;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.BgpTableType;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.BgpRib;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.PeerId;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.RibId;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.Route;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.Rib;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.RibKey;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.LocRib;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.Peer;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.Tables;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesKey;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.tables.Routes;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.BgpId;
66 import org.opendaylight.yangtools.yang.binding.ChildOf;
67 import org.opendaylight.yangtools.yang.binding.ChoiceIn;
68 import org.opendaylight.yangtools.yang.binding.DataObject;
69 import org.opendaylight.yangtools.yang.binding.Identifiable;
70 import org.opendaylight.yangtools.yang.binding.Identifier;
71 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
72 import org.opendaylight.yangtools.yang.common.QName;
73 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
74 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
75 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
76 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
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.model.api.SchemaContext;
82 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
83 import org.slf4j.Logger;
84 import org.slf4j.LoggerFactory;
85
86 @ThreadSafe
87 public final class RIBImpl extends BGPRIBStateImpl implements RIB, TransactionChainListener,
88         SchemaContextListener, AutoCloseable {
89     private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
90     private static final QName RIB_ID_QNAME = QName.create(Rib.QNAME, "id").intern();
91
92     private final BGPDispatcher dispatcher;
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 DataBroker dataBroker;
99     private final RIBExtensionConsumerContext extensions;
100     private final YangInstanceIdentifier yangRibId;
101     private final RIBSupportContextRegistryImpl ribContextRegistry;
102     private final CodecsRegistryImpl codecsRegistry;
103     private final BGPTableTypeRegistryConsumer tableTypeRegistry;
104     private final DOMDataBrokerExtension domService;
105     private final Map<TransactionChain<?, ?>, LocRibWriter> txChainToLocRibWriter = new HashMap<>();
106     private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
107     private final RibId ribId;
108     private final BGPPeerTracker peerTracker = new BGPPeerTrackerImpl();
109     private final BGPRibRoutingPolicy ribPolicies;
110     @GuardedBy("this")
111     private ClusterSingletonServiceRegistration registration;
112     @GuardedBy("this")
113     private DOMTransactionChain domChain;
114     @GuardedBy("this")
115     private boolean isServiceInstantiated;
116     private final Map<TablesKey, RibOutRefresh> vpnTableRefresher = new HashMap<>();
117
118     public RIBImpl(
119             final BGPTableTypeRegistryConsumer tableTypeRegistry,
120             final RibId ribId,
121             final AsNumber localAs,
122             final BgpId localBgpId,
123             final RIBExtensionConsumerContext extensions,
124             final BGPDispatcher dispatcher,
125             final CodecsRegistryImpl codecsRegistry,
126             final DOMDataBroker domDataBroker,
127             final DataBroker dataBroker,
128             final BGPRibRoutingPolicy ribPolicies,
129             final List<BgpTableType> localTables,
130             final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies
131     ) {
132         super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(requireNonNull(ribId))),
133                 localBgpId, localAs);
134         this.tableTypeRegistry = requireNonNull(tableTypeRegistry);
135         this.localAs = requireNonNull(localAs);
136         this.bgpIdentifier = requireNonNull(localBgpId);
137         this.dispatcher = requireNonNull(dispatcher);
138         this.localTables = ImmutableSet.copyOf(localTables);
139         this.localTablesKeys = new HashSet<>();
140         this.domDataBroker = requireNonNull(domDataBroker);
141         this.dataBroker = requireNonNull(dataBroker);
142         this.domService = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
143         this.extensions = requireNonNull(extensions);
144         this.ribPolicies = requireNonNull(ribPolicies);
145         this.codecsRegistry = codecsRegistry;
146         this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
147         final InstanceIdentifierBuilder yangRibIdBuilder = YangInstanceIdentifier.builder().node(BgpRib.QNAME)
148                 .node(Rib.QNAME);
149         this.yangRibId = yangRibIdBuilder.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
150         this.bestPathSelectionStrategies = requireNonNull(bestPathSelectionStrategies);
151         this.ribId = ribId;
152
153         for (final BgpTableType t : this.localTables) {
154             final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
155             this.localTablesKeys.add(key);
156         }
157     }
158
159     private synchronized void startLocRib(final TablesKey key) {
160         LOG.debug("Creating LocRib table for {}", key);
161         // create locRibWriter for each table
162         final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
163
164         final RIBSupport<? extends Routes, ?, ?, ?> ribSupport = this.ribContextRegistry.getRIBSupport(key);
165         if (ribSupport != null) {
166             final MapEntryNode emptyTable = ribSupport.emptyTable();
167             final InstanceIdentifierBuilder tableId = YangInstanceIdentifier
168                     .builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME)).node(emptyTable.getIdentifier());
169
170             tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), emptyTable);
171             try {
172                 tx.commit().get();
173             } catch (final InterruptedException | ExecutionException e1) {
174                 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
175             }
176         } else {
177             LOG.warn("There's no registered RIB Context for {}", key.getAfi());
178         }
179     }
180
181     private synchronized <C extends Routes & DataObject & ChoiceIn<Tables>, S extends ChildOf<? super C>,
182             R extends Route & ChildOf<? super S> & Identifiable<I>, I extends Identifier<R>>
183             void createLocRibWriter(final TablesKey key) {
184         final RIBSupport<C, S, R, I> ribSupport = this.ribContextRegistry.getRIBSupport(key);
185         if (ribSupport == null) {
186             return;
187         }
188         LOG.debug("Creating LocRIB writer for key {}", key);
189         final BindingTransactionChain txChain = createPeerChain(this);
190         PathSelectionMode pathSelectionStrategy = this.bestPathSelectionStrategies.get(key);
191         if (pathSelectionStrategy == null) {
192             pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy();
193         }
194
195         final LocRibWriter locRibWriter = LocRibWriter.create(
196                 ribSupport,
197                 key,
198                 this.tableTypeRegistry.getAfiSafiType(key).get(),
199                 txChain,
200                 getInstanceIdentifier(),
201                 this.localAs,
202                 getDataBroker(),
203                 this.ribPolicies,
204                 this.peerTracker,
205                 pathSelectionStrategy);
206         this.vpnTableRefresher.put(key, locRibWriter);
207         registerTotalPathCounter(key, locRibWriter);
208         registerTotalPrefixesCounter(key, locRibWriter);
209         this.txChainToLocRibWriter.put(txChain, locRibWriter);
210     }
211
212     @Override
213     public String toString() {
214         return MoreObjects.toStringHelper(this).add("bgpId", bgpIdentifier).add("localTables", localTables).toString();
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,
248             final AsyncTransaction<?, ?> transaction, final Throwable cause) {
249         LOG.error("Broken chain in RIB {} transaction {}",
250                 getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
251         if (this.txChainToLocRibWriter.containsKey(chain)) {
252             final LocRibWriter locRibWriter = this.txChainToLocRibWriter.remove(chain);
253             final BindingTransactionChain newChain = createPeerChain(this);
254             startLocRib(locRibWriter.getTableKey());
255             locRibWriter.restart(newChain);
256             this.txChainToLocRibWriter.put(newChain, locRibWriter);
257         }
258     }
259
260     @Override
261     public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
262         LOG.info("RIB {} closed successfully", getInstanceIdentifier());
263     }
264
265     @Override
266     public Set<TablesKey> getLocalTablesKeys() {
267         return this.localTablesKeys;
268     }
269
270     @Override
271     public boolean supportsTable(final TablesKey tableKey) {
272         return this.localTablesKeys.contains(tableKey);
273     }
274
275     @Override
276     public BGPRibRoutingPolicy getRibPolicies() {
277         return this.ribPolicies;
278     }
279
280     @Override
281     public BGPPeerTracker getPeerTracker() {
282         return this.peerTracker;
283     }
284
285     @Override
286     public void refreshTable(final TablesKey tk, final PeerId peerId) {
287         final RibOutRefresh table = this.vpnTableRefresher.get(tk);
288         if (table != null) {
289             table.refreshTable(tk, peerId);
290         }
291     }
292
293     @Override
294     public DOMDataTreeChangeService getService() {
295         return (DOMDataTreeChangeService) this.domService;
296     }
297
298     @Override
299     public DataBroker getDataBroker() {
300         return this.dataBroker;
301     }
302
303     @Override
304     public YangInstanceIdentifier getYangRibId() {
305         return this.yangRibId;
306     }
307
308     @Override
309     public BindingTransactionChain createPeerChain(final TransactionChainListener listener) {
310         return this.dataBroker.createTransactionChain(listener);
311     }
312
313     @Override
314     public DOMTransactionChain createPeerDOMChain(final TransactionChainListener listener) {
315         return this.domDataBroker.createTransactionChain(listener);
316     }
317
318     @Override
319     public RIBExtensionConsumerContext getRibExtensions() {
320         return this.extensions;
321     }
322
323     @Override
324     public RIBSupportContextRegistry getRibSupportContext() {
325         return this.ribContextRegistry;
326     }
327
328     @Override
329     public void onGlobalContextUpdated(final SchemaContext context) {
330         this.codecsRegistry.onSchemaContextUpdated(context);
331     }
332
333     @Override
334     public CodecsRegistry getCodecsRegistry() {
335         return this.codecsRegistry;
336     }
337
338     public synchronized void instantiateServiceInstance() {
339         this.isServiceInstantiated = true;
340         setActive(true);
341         this.domChain = this.domDataBroker.createTransactionChain(this);
342         LOG.debug("Instantiating RIB table {} at {}", this.ribId, this.yangRibId);
343
344         final ContainerNode bgpRib = Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
345                 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
346
347         final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
348                 new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, this.ribId.getValue()))
349                 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, this.ribId.getValue()))
350                 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
351                 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
352                         .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
353                         .build()).build();
354
355         final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
356
357         // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
358         trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(),
359             bgpRib);
360         trans.put(LogicalDatastoreType.OPERATIONAL, this.yangRibId, ribInstance);
361
362         try {
363             trans.commit().get();
364         } catch (final InterruptedException | ExecutionException e) {
365             LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
366         }
367
368         LOG.debug("Effective RIB created.");
369
370         this.localTablesKeys.forEach(this::startLocRib);
371         this.localTablesKeys.forEach(this::createLocRibWriter);
372     }
373
374     public synchronized FluentFuture<? extends CommitInfo> closeServiceInstance() {
375         if (!this.isServiceInstantiated) {
376             LOG.trace("RIB {} already closed", this.ribId.getValue());
377             return CommitInfo.emptyFluentFuture();
378         }
379         LOG.info("Close RIB {}", this.ribId.getValue());
380         this.isServiceInstantiated = false;
381         setActive(false);
382
383         this.txChainToLocRibWriter.values().forEach(LocRibWriter::close);
384         this.txChainToLocRibWriter.clear();
385
386         final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
387         t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
388         final FluentFuture<? extends CommitInfo> cleanFuture = t.commit();
389         cleanFuture.addCallback(new FutureCallback<CommitInfo>() {
390             @Override
391             public void onSuccess(final CommitInfo result) {
392                 LOG.info("RIB cleaned {}", RIBImpl.this.ribId.getValue());
393             }
394
395             @Override
396             public void onFailure(final Throwable throwable) {
397                 LOG.error("Failed to clean RIB {}",
398                         RIBImpl.this.ribId.getValue(), throwable);
399             }
400         }, MoreExecutors.directExecutor());
401         this.domChain.close();
402         return cleanFuture;
403     }
404 }