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