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