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