BGPCEP-574: Remove old ImportPolicyPeerTracker
[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 static java.util.Objects.requireNonNull;
11
12 import com.google.common.base.MoreObjects;
13 import com.google.common.base.MoreObjects.ToStringHelper;
14 import com.google.common.collect.ImmutableMap;
15 import com.google.common.collect.ImmutableSet;
16 import com.google.common.util.concurrent.Futures;
17 import com.google.common.util.concurrent.ListenableFuture;
18 import java.util.HashMap;
19 import java.util.HashSet;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.Map.Entry;
23 import java.util.Optional;
24 import java.util.Set;
25 import javax.annotation.Nonnull;
26 import javax.annotation.concurrent.GuardedBy;
27 import javax.annotation.concurrent.ThreadSafe;
28 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
29 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
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.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
39 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
40 import org.opendaylight.protocol.bgp.mode.api.PathSelectionMode;
41 import org.opendaylight.protocol.bgp.mode.impl.base.BasePathSelectionModeFactory;
42 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
43 import org.opendaylight.protocol.bgp.rib.impl.spi.CodecsRegistry;
44 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
45 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContext;
46 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
47 import org.opendaylight.protocol.bgp.rib.impl.state.BGPRIBStateImpl;
48 import org.opendaylight.protocol.bgp.rib.spi.BGPPeerTracker;
49 import org.opendaylight.protocol.bgp.rib.spi.ExportPolicyPeerTracker;
50 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
51 import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
52 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
53 import org.opendaylight.protocol.bgp.rib.spi.policy.BGPRibRoutingPolicy;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev171207.path.attributes.Attributes;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev171207.BgpTableType;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.BgpRib;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.RibId;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.bgp.rib.Rib;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.bgp.rib.RibKey;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.bgp.rib.rib.LocRib;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.bgp.rib.rib.Peer;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.rib.Tables;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.rib.TablesKey;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.BgpId;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier;
67 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
68 import org.opendaylight.yangtools.yang.common.QName;
69 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
70 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
71 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
72 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
73 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
74 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
75 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
76 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
77 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
78 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
79 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
80 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
81 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
82 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
83 import org.slf4j.Logger;
84 import org.slf4j.LoggerFactory;
85
86 @ThreadSafe
87 public final class RIBImpl extends BGPRIBStateImpl implements RIB, TransactionChainListener,
88         SchemaContextListener, AutoCloseable {
89     private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
90     private static final QName RIB_ID_QNAME = QName.create(Rib.QNAME, "id").intern();
91     private static final ContainerNode EMPTY_TABLE_ATTRIBUTES = ImmutableNodes.containerNode(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.rib.tables.Attributes.QNAME);
92
93     private final BGPDispatcher dispatcher;
94     private final AsNumber localAs;
95     private final BgpId bgpIdentifier;
96     private final Set<BgpTableType> localTables;
97     private final Set<TablesKey> localTablesKeys;
98     private final DOMDataBroker domDataBroker;
99     private final RIBExtensionConsumerContext extensions;
100     private final YangInstanceIdentifier yangRibId;
101     private final YangInstanceIdentifier yangTables;
102     private final RIBSupportContextRegistryImpl ribContextRegistry;
103     private final CodecsRegistryImpl codecsRegistry;
104     @GuardedBy("this")
105     private ClusterSingletonServiceRegistration registration;
106     private final DOMDataBrokerExtension service;
107     private final Map<TransactionChain<?, ?>, LocRibWriter> txChainToLocRibWriter = new HashMap<>();
108     private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
109     private final RibId ribId;
110     private final BGPPeerTracker peerTracker;
111     private final BGPRibRoutingPolicy ribPolicies;
112     private final Map<TablesKey, ExportPolicyPeerTracker> exportPolicyPeerTrackerMap;
113     private final BindingNormalizedNodeSerializer bindingSerializer;
114
115     @GuardedBy("this")
116     private DOMTransactionChain domChain;
117     @GuardedBy("this")
118     private boolean isServiceInstantiated;
119
120     public RIBImpl(final RibId ribId,
121             final AsNumber localAs,
122             final BgpId localBgpId,
123             final ClusterIdentifier clusterId,
124             final RIBExtensionConsumerContext extensions,
125             final BGPDispatcher dispatcher,
126             final CodecsRegistryImpl codecsRegistry,
127             final DOMDataBroker domDataBroker,
128             final BGPRibRoutingPolicy ribPolicies,
129             final BGPPeerTracker bgpPeerTracker,
130             final List<BgpTableType> localTables,
131             final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies,
132             final BindingNormalizedNodeSerializer bindingSerializer
133     ) {
134         super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(requireNonNull(ribId))),
135                 localBgpId, localAs);
136         this.localAs = requireNonNull(localAs);
137         this.bgpIdentifier = requireNonNull(localBgpId);
138         this.dispatcher = requireNonNull(dispatcher);
139         this.localTables = ImmutableSet.copyOf(localTables);
140         this.localTablesKeys = new HashSet<>();
141         this.domDataBroker = requireNonNull(domDataBroker);
142         this.service = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
143         this.extensions = requireNonNull(extensions);
144         this.ribPolicies = requireNonNull(ribPolicies);
145         this.peerTracker = requireNonNull(bgpPeerTracker);
146         this.codecsRegistry = codecsRegistry;
147         this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
148         final InstanceIdentifierBuilder yangRibIdBuilder = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME);
149         this.yangRibId = yangRibIdBuilder.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
150         this.yangTables = this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME);
151         this.bestPathSelectionStrategies = requireNonNull(bestPathSelectionStrategies);
152         final ClusterIdentifier cId = clusterId == null ? new ClusterIdentifier(localBgpId) : clusterId;
153         this.ribId = ribId;
154         final PolicyDatabase policyDatabase = new PolicyDatabase(this.localAs.getValue(), localBgpId, cId);
155
156         final ImmutableMap.Builder<TablesKey, ExportPolicyPeerTracker> exportPolicies = new ImmutableMap.Builder<>();
157         for (final BgpTableType t : this.localTables) {
158             final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
159             this.localTablesKeys.add(key);
160             exportPolicies.put(key, new ExportPolicyPeerTrackerImpl(policyDatabase, key));
161         }
162         this.exportPolicyPeerTrackerMap = exportPolicies.build();
163         this.bindingSerializer = requireNonNull(bindingSerializer);
164     }
165
166     private synchronized void startLocRib(final TablesKey key) {
167         LOG.debug("Creating LocRib table for {}", key);
168         // create locRibWriter for each table
169         final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
170
171         final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
172         table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
173         table.withChild(EMPTY_TABLE_ATTRIBUTES);
174
175         final NodeIdentifierWithPredicates tableKey = RibSupportUtils.toYangTablesKey(key);
176         final InstanceIdentifierBuilder tableId = YangInstanceIdentifier.builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME));
177         tableId.nodeWithKey(tableKey.getNodeType(), tableKey.getKeyValues());
178         for (final Entry<QName, Object> e : tableKey.getKeyValues().entrySet()) {
179             table.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
180         }
181
182         final RIBSupportContext supportContext = this.ribContextRegistry.getRIBSupportContext(key);
183         if (supportContext != null) {
184             final ChoiceNode routes = supportContext.getRibSupport().emptyRoutes();
185             table.withChild(routes);
186
187             tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
188             try {
189                 tx.submit().checkedGet();
190             } catch (final TransactionCommitFailedException e1) {
191                 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
192             }
193             createLocRibWriter(key);
194         } else {
195             LOG.warn("There's no registered RIB Context for {}", key.getAfi());
196         }
197     }
198
199     private synchronized void createLocRibWriter(final TablesKey key) {
200         LOG.debug("Creating LocRIB writer for key {}", key);
201         final DOMTransactionChain txChain = createPeerChain(this);
202         PathSelectionMode pathSelectionStrategy = this.bestPathSelectionStrategies.get(key);
203         if (pathSelectionStrategy == null) {
204             pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy(this.peerTracker);
205         }
206
207         final LocRibWriter locRibWriter = LocRibWriter.create(this.ribContextRegistry, key, txChain,
208                 getYangRibId(), this.localAs, getService(), this.exportPolicyPeerTrackerMap.get(key), pathSelectionStrategy);
209         registerTotalPathCounter(key, locRibWriter);
210         registerTotalPrefixesCounter(key, locRibWriter);
211         this.txChainToLocRibWriter.put(txChain, locRibWriter);
212     }
213
214     @Override
215     public String toString() {
216         return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
217     }
218
219     protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
220         return toStringHelper;
221     }
222
223     @Override
224     public synchronized void close() throws Exception {
225         if (this.registration != null) {
226             this.registration.close();
227             this.registration = null;
228         }
229     }
230
231     @Override
232     public AsNumber getLocalAs() {
233         return this.localAs;
234     }
235
236     @Override
237     public BgpId getBgpIdentifier() {
238         return this.bgpIdentifier;
239     }
240
241     @Nonnull
242     @Override
243     public Set<? extends BgpTableType> getLocalTables() {
244         return this.localTables;
245     }
246
247     @Override
248     public BGPDispatcher getDispatcher() {
249         return this.dispatcher;
250     }
251
252     @Override
253     public synchronized void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
254         LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
255         if (this.txChainToLocRibWriter.containsKey(chain)) {
256             final LocRibWriter locRibWriter = this.txChainToLocRibWriter.remove(chain);
257             final DOMTransactionChain newChain = createPeerChain(this);
258             locRibWriter.restart(newChain);
259             this.txChainToLocRibWriter.put(newChain, locRibWriter);
260         }
261     }
262
263     @Override
264     public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
265         LOG.info("RIB {} closed successfully", getInstanceIdentifier());
266     }
267
268     @Override
269     public Set<TablesKey> getLocalTablesKeys() {
270         return this.localTablesKeys;
271     }
272
273     @Override
274     public boolean supportsTable(final TablesKey tableKey) {
275         return this.localTablesKeys.contains(tableKey);
276     }
277
278     @Override
279     public BGPRibRoutingPolicy getRibPolicies() {
280         return this.ribPolicies;
281     }
282
283     @Override
284     public BGPPeerTracker getPeerTracker() {
285         return this.peerTracker;
286     }
287
288     @Override
289     public DOMDataTreeChangeService getService() {
290         return (DOMDataTreeChangeService) this.service;
291     }
292
293     @Override
294     public YangInstanceIdentifier getYangRibId() {
295         return this.yangRibId;
296     }
297
298     @Override
299     public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
300         return this.domDataBroker.createTransactionChain(listener);
301     }
302
303     @Override
304     public RIBExtensionConsumerContext getRibExtensions() {
305         return this.extensions;
306     }
307
308     @Override
309     public RIBSupportContextRegistry getRibSupportContext() {
310         return this.ribContextRegistry;
311     }
312
313     @Override
314     public void onGlobalContextUpdated(final SchemaContext context) {
315         this.codecsRegistry.onSchemaContextUpdated(context);
316     }
317
318     @Override
319     public CodecsRegistry getCodecsRegistry() {
320         return this.codecsRegistry;
321     }
322
323     @Override
324     public ExportPolicyPeerTracker getExportPolicyPeerTracker(final TablesKey tablesKey) {
325         return this.exportPolicyPeerTrackerMap.get(tablesKey);
326     }
327
328     public synchronized void instantiateServiceInstance() {
329         this.isServiceInstantiated = true;
330         setActive(true);
331         this.domChain = this.domDataBroker.createTransactionChain(this);
332         LOG.debug("Instantiating RIB table {} at {}", this.ribId, this.yangRibId);
333
334         final ContainerNode bgpRib = Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
335                 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
336
337         final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
338                 new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, this.ribId.getValue()))
339                 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, this.ribId.getValue()))
340                 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
341                 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
342                         .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
343                         .build()).build();
344
345
346         final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
347
348         // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
349         trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
350         trans.put(LogicalDatastoreType.OPERATIONAL, this.yangRibId, ribInstance);
351
352         try {
353             trans.submit().checkedGet();
354         } catch (final TransactionCommitFailedException e) {
355             LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
356         }
357
358         LOG.debug("Effective RIB created.");
359
360         this.localTablesKeys.forEach(this::startLocRib);
361     }
362
363     public synchronized ListenableFuture<Void> closeServiceInstance() {
364         if (!this.isServiceInstantiated) {
365             LOG.trace("RIB {} already closed", this.ribId.getValue());
366             return Futures.immediateFuture(null);
367         }
368         LOG.info("Close RIB {}", this.ribId.getValue());
369         this.isServiceInstantiated = false;
370         setActive(false);
371
372         this.txChainToLocRibWriter.values().forEach(LocRibWriter::close);
373         this.txChainToLocRibWriter.clear();
374
375         final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
376         t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
377         final ListenableFuture<Void> cleanFuture = t.submit();
378
379         this.domChain.close();
380         return cleanFuture;
381     }
382
383
384     @Override
385     @SuppressWarnings("unchecked")
386     public final Optional<ContainerNode> toNormalizedNodeAttribute(
387             final RIBSupport ribSupport,
388             final NodeIdentifierWithPredicates routeIdentifier,
389             final Optional<Attributes> attributes) {
390         if (!attributes.isPresent()) {
391             return Optional.empty();
392         }
393         final InstanceIdentifier<Attributes> yii
394                 = (InstanceIdentifier<Attributes>) this.bindingSerializer
395                 .fromYangInstanceIdentifier(ribSupport.buildRouteAttributeYii(this.yangTables, routeIdentifier));
396         return Optional.of((ContainerNode) this.bindingSerializer.toNormalizedNode(yii, attributes.get()).getValue());
397     }
398
399     @Override
400     public final Optional<Attributes> getAttributes(
401             final RIBSupport ribSupport,
402             final NodeIdentifierWithPredicates routeIdentifier,
403             final NormalizedNode<?, ?> route) {
404         final ContainerNode advertisedAttrs = (ContainerNode) NormalizedNodes
405                 .findNode(route, ribSupport.routeAttributesIdentifier()).orElse(null);
406         if (advertisedAttrs == null) {
407             return Optional.empty();
408         }
409
410         return Optional.ofNullable((Attributes) this.bindingSerializer
411                 .fromNormalizedNode(ribSupport.buildRouteAttributeYii(this.yangTables, routeIdentifier),
412                         advertisedAttrs).getValue());
413     }
414 }