Sonar Warning Fix: RIBImpl - log exception
[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.annotations.VisibleForTesting;
11 import com.google.common.base.MoreObjects;
12 import com.google.common.base.MoreObjects.ToStringHelper;
13 import com.google.common.base.Optional;
14 import com.google.common.base.Preconditions;
15 import com.google.common.collect.ImmutableSet;
16 import java.util.ArrayList;
17 import java.util.HashSet;
18 import java.util.List;
19 import java.util.Map.Entry;
20 import java.util.Set;
21 import java.util.concurrent.ExecutionException;
22 import javax.annotation.concurrent.ThreadSafe;
23 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
24 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
25 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
28 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
29 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
30 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
31 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
32 import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
33 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
34 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
35 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
36 import org.opendaylight.protocol.bgp.rib.DefaultRibReference;
37 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
38 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
39 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
40 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
41 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
42 import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.bgp.rib.rib.loc.rib.tables.routes.Ipv4RoutesCase;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.bgp.rib.rib.loc.rib.tables.routes.Ipv6RoutesCase;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.BgpRib;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.RibId;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.Rib;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibKey;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.LocRib;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.Peer;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier;
57 import org.opendaylight.yangtools.binding.data.codec.api.BindingCodecTreeFactory;
58 import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
59 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
60 import org.opendaylight.yangtools.yang.common.QName;
61 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
62 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
63 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
64 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
65 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
66 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
67 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
68 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
69 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
70 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
71 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
72 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
73 import org.slf4j.Logger;
74 import org.slf4j.LoggerFactory;
75
76 @ThreadSafe
77 public final class RIBImpl extends DefaultRibReference implements AutoCloseable, RIB, TransactionChainListener, SchemaContextListener {
78     private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
79     @VisibleForTesting
80     public static final QName RIB_ID_QNAME = QName.cachedReference(QName.create(Rib.QNAME, "id"));
81     @VisibleForTesting
82     public 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);
83
84     private final ReconnectStrategyFactory tcpStrategyFactory;
85     private final ReconnectStrategyFactory sessionStrategyFactory;
86
87     private final BGPDispatcher dispatcher;
88     private final DOMTransactionChain domChain;
89     private final AsNumber localAs;
90     private final Ipv4Address bgpIdentifier;
91     private final Set<BgpTableType> localTables;
92     private final Set<TablesKey> localTablesKeys;
93     private final DataBroker dataBroker;
94     private final DOMDataBroker domDataBroker;
95     private final RIBExtensionConsumerContext extensions;
96     private final YangInstanceIdentifier yangRibId;
97     private final RIBSupportContextRegistryImpl ribContextRegistry;
98     private final EffectiveRibInWriter efWriter;
99     private final DOMDataBrokerExtension service;
100     private final List<LocRibWriter> locRibs = new ArrayList<>();
101
102     public RIBImpl(final RibId ribId, final AsNumber localAs, final Ipv4Address localBgpId, final Ipv4Address clusterId, final RIBExtensionConsumerContext extensions,
103         final BGPDispatcher dispatcher, final ReconnectStrategyFactory tcpStrategyFactory, final BindingCodecTreeFactory codecFactory,
104         final ReconnectStrategyFactory sessionStrategyFactory, final DataBroker dps, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables, final GeneratedClassLoadingStrategy classStrategy) {
105         super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId))));
106         this.domChain = domDataBroker.createTransactionChain(this);
107         this.localAs = Preconditions.checkNotNull(localAs);
108         this.bgpIdentifier = Preconditions.checkNotNull(localBgpId);
109         this.dispatcher = Preconditions.checkNotNull(dispatcher);
110         this.sessionStrategyFactory = Preconditions.checkNotNull(sessionStrategyFactory);
111         this.tcpStrategyFactory = Preconditions.checkNotNull(tcpStrategyFactory);
112         this.localTables = ImmutableSet.copyOf(localTables);
113         this.localTablesKeys = new HashSet<TablesKey>();
114         this.dataBroker = dps;
115         this.domDataBroker = Preconditions.checkNotNull(domDataBroker);
116         this.extensions = Preconditions.checkNotNull(extensions);
117         this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, codecFactory, classStrategy);
118         this.yangRibId = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME).nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
119
120         LOG.debug("Instantiating RIB table {} at {}", ribId, this.yangRibId);
121
122         final ContainerNode rib = Builders.containerBuilder()
123             .withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
124             .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME)
125                 .addChild(ImmutableNodes.mapEntryBuilder(Rib.QNAME, RIB_ID_QNAME, ribId.getValue())
126                     .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, ribId.getValue()))
127                     .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
128                     .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
129                         .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
130                         .build())
131                     .build())
132                     .build())
133             .build();
134
135
136         final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
137
138         // put empty BgpRib if not exists
139         trans.put(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), rib);
140
141         try {
142             trans.submit().checkedGet();
143         } catch (final TransactionCommitFailedException e) {
144             LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
145         }
146         final ClusterIdentifier cId = (clusterId == null) ? new ClusterIdentifier(localBgpId) : new ClusterIdentifier(clusterId);
147         final PolicyDatabase pd  = new PolicyDatabase(localAs.getValue(), localBgpId, cId);
148
149         final DOMDataBrokerExtension domDatatreeChangeService = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
150         this.service = domDatatreeChangeService;
151         this.efWriter = EffectiveRibInWriter.create(getService(), this.createPeerChain(this), getYangRibId(), pd, this.ribContextRegistry);
152         LOG.debug("Effective RIB created.");
153
154         for (final BgpTableType t : this.localTables) {
155             final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
156             this.localTablesKeys.add(key);
157             startLocRib(key, pd);
158         }
159     }
160
161     private void startLocRib(final TablesKey key, final PolicyDatabase pd) {
162         LOG.debug("Creating LocRib table for {}", key);
163         // create locRibWriter for each table
164         final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
165
166         final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
167         table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
168         table.withChild(EMPTY_TABLE_ATTRIBUTES);
169
170         final NodeIdentifierWithPredicates tableKey = RibSupportUtils.toYangTablesKey(key);
171         final InstanceIdentifierBuilder tableId = YangInstanceIdentifier.builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME));
172         tableId.nodeWithKey(tableKey.getNodeType(), tableKey.getKeyValues());
173         for (final Entry<QName, Object> e : tableKey.getKeyValues().entrySet()) {
174             table.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
175         }
176
177         final ChoiceNode routes = this.ribContextRegistry.getRIBSupportContext(key).getRibSupport().emptyRoutes();
178         table.withChild(routes);
179
180         tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
181         try {
182             tx.submit().checkedGet();
183         } catch (final TransactionCommitFailedException e1) {
184             LOG.error("Failed to initiate LocRIB for key {}", key, e1);
185         }
186         this.locRibs.add(LocRibWriter.create(this.ribContextRegistry, key, this.createPeerChain(this), getYangRibId(), this.localAs, getService(), pd));
187     }
188
189     @Override
190     public String toString() {
191         return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
192     }
193
194     protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
195         return toStringHelper;
196     }
197
198     @Override
199     public synchronized void close() throws InterruptedException, ExecutionException {
200         final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
201         t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
202         t.submit().get();
203         this.domChain.close();
204         this.efWriter.close();
205         for (final LocRibWriter locRib : this.locRibs) {
206             try {
207                 locRib.close();
208             } catch (final Exception e) {
209                 LOG.warn("Could not close LocalRib reference: {}", locRib, e);
210             }
211         }
212     }
213
214     @Override
215     public AsNumber getLocalAs() {
216         return this.localAs;
217     }
218
219     @Override
220     public Ipv4Address getBgpIdentifier() {
221         return this.bgpIdentifier;
222     }
223
224     @Override
225     public Set<? extends BgpTableType> getLocalTables() {
226         return this.localTables;
227     }
228
229     @Override
230     public ReconnectStrategyFactory getTcpStrategyFactory() {
231         return this.tcpStrategyFactory;
232     }
233
234     @Override
235     public ReconnectStrategyFactory getSessionStrategyFactory() {
236         return this.sessionStrategyFactory;
237     }
238
239     @Override
240     public BGPDispatcher getDispatcher() {
241         return this.dispatcher;
242     }
243
244     @Override
245     public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
246         LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction.getIdentifier(), cause);
247     }
248
249     @Override
250     public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
251         LOG.info("RIB {} closed successfully", getInstanceIdentifier());
252     }
253
254     @Override
255     public long getRoutesCount(final TablesKey key) {
256         try (final ReadOnlyTransaction tx = this.dataBroker.newReadOnlyTransaction()) {
257             final Optional<Tables> tableMaybe = tx.read(LogicalDatastoreType.OPERATIONAL,
258                     getInstanceIdentifier().child(LocRib.class).child(Tables.class, key)).checkedGet();
259             if (tableMaybe.isPresent()) {
260                 final Tables table = tableMaybe.get();
261                 if (table.getRoutes() instanceof Ipv4RoutesCase) {
262                     final Ipv4RoutesCase routesCase = (Ipv4RoutesCase) table.getRoutes();
263                     if (routesCase.getIpv4Routes() != null && routesCase.getIpv4Routes().getIpv4Route() != null) {
264                         return routesCase.getIpv4Routes().getIpv4Route().size();
265                     }
266                 } else if (table.getRoutes() instanceof Ipv6RoutesCase) {
267                     final Ipv6RoutesCase routesCase = (Ipv6RoutesCase) table.getRoutes();
268                     if (routesCase.getIpv6Routes() != null && routesCase.getIpv6Routes().getIpv6Route() != null) {
269                         return routesCase.getIpv6Routes().getIpv6Route().size();
270                     }
271                 }
272             }
273         } catch (final ReadFailedException e) {
274             LOG.debug("Failed to read tables", e);
275         }
276         return 0;
277     }
278
279     public Set<TablesKey> getLocalTablesKeys() {
280         return this.localTablesKeys;
281     }
282
283     public DOMDataTreeChangeService getService() {
284         return (DOMDataTreeChangeService) this.service;
285     }
286
287     @Override
288     public YangInstanceIdentifier getYangRibId() {
289         return this.yangRibId;
290     }
291
292     @Override
293     public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
294         return this.domDataBroker.createTransactionChain(listener);
295     }
296
297     @Override
298     public RIBExtensionConsumerContext getRibExtensions() {
299         return this.extensions;
300     }
301
302     @Override
303     public RIBSupportContextRegistry getRibSupportContext() {
304         return this.ribContextRegistry;
305     }
306
307     @Override
308     public void onGlobalContextUpdated(final SchemaContext context) {
309         this.ribContextRegistry.onSchemaContextUpdated(context);
310     }
311 }