13571b8a57a537f6687abf0ef4fc7d48db4e8fa1
[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         LocRibWriter.create(this.ribContextRegistry, key, this.createPeerChain(this), getYangRibId(), this.localAs, getService(), pd);
182     }
183
184     @Override
185     public String toString() {
186         return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
187     }
188
189     protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
190         return toStringHelper;
191     }
192
193     @Override
194     public synchronized void close() throws InterruptedException, ExecutionException {
195         final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
196         t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
197         t.submit().get();
198         this.domChain.close();
199         this.efWriter.close();
200     }
201
202     @Override
203     public AsNumber getLocalAs() {
204         return this.localAs;
205     }
206
207     @Override
208     public Ipv4Address getBgpIdentifier() {
209         return this.bgpIdentifier;
210     }
211
212     @Override
213     public Set<? extends BgpTableType> getLocalTables() {
214         return this.localTables;
215     }
216
217     @Override
218     public ReconnectStrategyFactory getTcpStrategyFactory() {
219         return this.tcpStrategyFactory;
220     }
221
222     @Override
223     public ReconnectStrategyFactory getSessionStrategyFactory() {
224         return this.sessionStrategyFactory;
225     }
226
227     @Override
228     public BGPDispatcher getDispatcher() {
229         return this.dispatcher;
230     }
231
232     @Override
233     public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
234         LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction.getIdentifier(), cause);
235     }
236
237     @Override
238     public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
239         LOG.info("RIB {} closed successfully", getInstanceIdentifier());
240     }
241
242     @Override
243     public long getRoutesCount(final TablesKey key) {
244         try (final ReadOnlyTransaction tx = this.dataBroker.newReadOnlyTransaction()) {
245             final Optional<Tables> tableMaybe = tx.read(LogicalDatastoreType.OPERATIONAL,
246                     getInstanceIdentifier().child(LocRib.class).child(Tables.class, key)).checkedGet();
247             if (tableMaybe.isPresent()) {
248                 final Tables table = tableMaybe.get();
249                 if (table.getRoutes() instanceof Ipv4RoutesCase) {
250                     final Ipv4RoutesCase routesCase = (Ipv4RoutesCase) table.getRoutes();
251                     if (routesCase.getIpv4Routes() != null && routesCase.getIpv4Routes().getIpv4Route() != null) {
252                         return routesCase.getIpv4Routes().getIpv4Route().size();
253                     }
254                 } else if (table.getRoutes() instanceof Ipv6RoutesCase) {
255                     final Ipv6RoutesCase routesCase = (Ipv6RoutesCase) table.getRoutes();
256                     if (routesCase.getIpv6Routes() != null && routesCase.getIpv6Routes().getIpv6Route() != null) {
257                         return routesCase.getIpv6Routes().getIpv6Route().size();
258                     }
259                 }
260             }
261         } catch (final ReadFailedException e) {
262             LOG.debug("Failed to read tables", e);
263         }
264         return 0;
265     }
266
267     public Set<TablesKey> getLocalTablesKeys() {
268         return this.localTablesKeys;
269     }
270
271     public DOMDataTreeChangeService getService() {
272         return (DOMDataTreeChangeService) this.service;
273     }
274
275     @Override
276     public YangInstanceIdentifier getYangRibId() {
277         return this.yangRibId;
278     }
279
280     @Override
281     public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
282         return this.domDataBroker.createTransactionChain(listener);
283     }
284
285     @Override
286     public RIBExtensionConsumerContext getRibExtensions() {
287         return this.extensions;
288     }
289
290     @Override
291     public RIBSupportContextRegistry getRibSupportContext() {
292         return this.ribContextRegistry;
293     }
294
295     @Override
296     public void onGlobalContextUpdated(final SchemaContext context) {
297         this.ribContextRegistry.onSchemaContextUpdated(context);
298     }
299 }