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