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