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