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