2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.protocol.bgp.rib.impl;
10 import static java.util.Objects.requireNonNull;
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.CheckedFuture;
17 import com.google.common.util.concurrent.Futures;
18 import com.google.common.util.concurrent.ListenableFuture;
19 import java.util.HashMap;
20 import java.util.HashSet;
21 import java.util.List;
23 import java.util.Map.Entry;
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.BindingCodecTreeFactory;
39 import org.opendaylight.mdsal.binding.generator.impl.GeneratedClassLoadingStrategy;
40 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
41 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
42 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
43 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
44 import org.opendaylight.protocol.bgp.mode.api.PathSelectionMode;
45 import org.opendaylight.protocol.bgp.mode.impl.base.BasePathSelectionModeFactory;
46 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
47 import org.opendaylight.protocol.bgp.rib.impl.spi.CodecsRegistry;
48 import org.opendaylight.protocol.bgp.rib.impl.spi.ImportPolicyPeerTracker;
49 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
50 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContext;
51 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
52 import org.opendaylight.protocol.bgp.rib.impl.state.BGPRIBStateImpl;
53 import org.opendaylight.protocol.bgp.rib.spi.ExportPolicyPeerTracker;
54 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
55 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
56 import org.opendaylight.protocol.bgp.rib.spi.util.ClusterSingletonServiceRegistrationHelper;
57 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.BgpRib;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.RibId;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.Rib;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibKey;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.LocRib;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.Peer;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.BgpId;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier;
69 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
70 import org.opendaylight.yangtools.yang.common.QName;
71 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
72 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
73 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
74 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
75 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
76 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
77 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
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;
87 public final class RIBImpl extends BGPRIBStateImpl implements ClusterSingletonService, 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.rev130925.rib.tables.Attributes.QNAME);
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 RIBSupportContextRegistryImpl ribContextRegistry;
102 private final CodecsRegistryImpl codecsRegistry;
103 private final ServiceGroupIdentifier serviceGroupIdentifier;
104 private final ClusterSingletonServiceProvider provider;
105 private final DOMDataBrokerExtension service;
106 private final Map<TransactionChain<?, ?>, LocRibWriter> txChainToLocRibWriter = new HashMap<>();
107 private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
108 private final ImportPolicyPeerTracker importPolicyPeerTracker;
109 private final RibId ribId;
110 private final Map<TablesKey, ExportPolicyPeerTracker> exportPolicyPeerTrackerMap;
111 private ClusterSingletonServiceRegistration registration;
112 private DOMTransactionChain domChain;
114 private boolean isServiceInstantiated;
116 public RIBImpl(final ClusterSingletonServiceProvider provider, final RibId ribId, final AsNumber localAs, final BgpId localBgpId,
117 final ClusterIdentifier clusterId, final RIBExtensionConsumerContext extensions, final BGPDispatcher dispatcher,
118 final BindingCodecTreeFactory codecFactory, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
119 @Nonnull final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies,
120 final GeneratedClassLoadingStrategy classStrategy) {
121 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(requireNonNull(ribId))),
122 localBgpId, localAs);
123 this.localAs = requireNonNull(localAs);
124 this.bgpIdentifier = requireNonNull(localBgpId);
125 this.dispatcher = requireNonNull(dispatcher);
126 this.localTables = ImmutableSet.copyOf(localTables);
127 this.localTablesKeys = new HashSet<>();
128 this.domDataBroker = requireNonNull(domDataBroker);
129 this.service = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
130 this.extensions = requireNonNull(extensions);
131 this.codecsRegistry = CodecsRegistryImpl.create(codecFactory, classStrategy);
132 this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
133 final InstanceIdentifierBuilder yangRibIdBuilder = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME);
134 this.yangRibId = yangRibIdBuilder.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
135 this.bestPathSelectionStrategies = requireNonNull(bestPathSelectionStrategies);
136 final ClusterIdentifier cId = clusterId == null ? new ClusterIdentifier(localBgpId) : clusterId;
138 final PolicyDatabase policyDatabase = new PolicyDatabase(this.localAs.getValue(), localBgpId, cId);
139 this.importPolicyPeerTracker = new ImportPolicyPeerTrackerImpl(policyDatabase);
140 this.serviceGroupIdentifier = ServiceGroupIdentifier.create(this.ribId.getValue() + "-service-group");
141 requireNonNull(provider, "ClusterSingletonServiceProvider is null");
142 this.provider = provider;
144 final ImmutableMap.Builder<TablesKey, ExportPolicyPeerTracker> exportPolicies = new ImmutableMap.Builder<>();
145 for (final BgpTableType t : this.localTables) {
146 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
147 this.localTablesKeys.add(key);
148 exportPolicies.put(key, new ExportPolicyPeerTrackerImpl(policyDatabase, key));
150 this.exportPolicyPeerTrackerMap = exportPolicies.build();
151 LOG.info("RIB Singleton Service {} registered, RIB {}", getIdentifier().getValue(), this.ribId.getValue());
152 //this need to be always the last step
153 this.registration = registerClusterSingletonService(this);
156 private void startLocRib(final TablesKey key) {
157 LOG.debug("Creating LocRib table for {}", key);
158 // create locRibWriter for each table
159 final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
161 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
162 table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
163 table.withChild(EMPTY_TABLE_ATTRIBUTES);
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()));
172 final RIBSupportContext supportContext = this.ribContextRegistry.getRIBSupportContext(key);
173 if (supportContext != null) {
174 final ChoiceNode routes = supportContext.getRibSupport().emptyRoutes();
175 table.withChild(routes);
177 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
179 tx.submit().checkedGet();
180 } catch (final TransactionCommitFailedException e1) {
181 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
183 createLocRibWriter(key);
185 LOG.warn("There's no registered RIB Context for {}", key.getAfi());
189 private synchronized void createLocRibWriter(final TablesKey key) {
190 LOG.debug("Creating LocRIB writer for key {}", key);
191 final DOMTransactionChain txChain = createPeerChain(this);
192 PathSelectionMode pathSelectionStrategy = this.bestPathSelectionStrategies.get(key);
193 if (pathSelectionStrategy == null) {
194 pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy();
197 final LocRibWriter locRibWriter = LocRibWriter.create(this.ribContextRegistry, key, txChain,
198 getYangRibId(), this.localAs, getService(), this.exportPolicyPeerTrackerMap.get(key), pathSelectionStrategy);
199 registerTotalPathCounter(key, locRibWriter);
200 registerTotalPrefixesCounter(key, locRibWriter);
201 this.txChainToLocRibWriter.put(txChain, locRibWriter);
205 public String toString() {
206 return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
209 protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
210 return toStringHelper;
214 public synchronized void close() throws Exception {
215 if (this.registration != null) {
216 this.registration.close();
217 this.registration = null;
222 public AsNumber getLocalAs() {
227 public BgpId getBgpIdentifier() {
228 return this.bgpIdentifier;
233 public Set<? extends BgpTableType> getLocalTables() {
234 return this.localTables;
238 public BGPDispatcher getDispatcher() {
239 return this.dispatcher;
243 public synchronized void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
244 LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
245 if (this.txChainToLocRibWriter.containsKey(chain)) {
246 final LocRibWriter locRibWriter = this.txChainToLocRibWriter.remove(chain);
247 final DOMTransactionChain newChain = createPeerChain(this);
248 locRibWriter.restart(newChain);
249 this.txChainToLocRibWriter.put(newChain, locRibWriter);
254 public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
255 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
259 public Set<TablesKey> getLocalTablesKeys() {
260 return this.localTablesKeys;
264 public DOMDataTreeChangeService getService() {
265 return (DOMDataTreeChangeService) this.service;
269 public YangInstanceIdentifier getYangRibId() {
270 return this.yangRibId;
274 public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
275 return this.domDataBroker.createTransactionChain(listener);
279 public RIBExtensionConsumerContext getRibExtensions() {
280 return this.extensions;
284 public RIBSupportContextRegistry getRibSupportContext() {
285 return this.ribContextRegistry;
289 public void onGlobalContextUpdated(final SchemaContext context) {
290 this.codecsRegistry.onSchemaContextUpdated(context);
294 public CodecsRegistry getCodecsRegistry() {
295 return this.codecsRegistry;
299 public ImportPolicyPeerTracker getImportPolicyPeerTracker() {
300 return this.importPolicyPeerTracker;
304 public ExportPolicyPeerTracker getExportPolicyPeerTracker(final TablesKey tablesKey) {
305 return this.exportPolicyPeerTrackerMap.get(tablesKey);
309 public synchronized void instantiateServiceInstance() {
310 this.isServiceInstantiated = true;
312 this.domChain = this.domDataBroker.createTransactionChain(this);
313 LOG.info("RIB Singleton Service {} instantiated, RIB {}", getIdentifier().getValue(), this.ribId.getValue());
314 LOG.debug("Instantiating RIB table {} at {}", this.ribId, this.yangRibId);
316 final ContainerNode bgpRib = Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
317 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
319 final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
320 new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, this.ribId.getValue()))
321 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, this.ribId.getValue()))
322 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
323 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
324 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
328 final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
330 // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
331 trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
332 trans.put(LogicalDatastoreType.OPERATIONAL, this.yangRibId, ribInstance);
335 trans.submit().checkedGet();
336 } catch (final TransactionCommitFailedException e) {
337 LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
340 LOG.debug("Effective RIB created.");
342 this.localTablesKeys.forEach(this::startLocRib);
346 public synchronized ListenableFuture<Void> closeServiceInstance() {
347 if (!this.isServiceInstantiated) {
348 LOG.trace("RIB Singleton Service {} already closed, RIB {}", getIdentifier().getValue(),
349 this.ribId.getValue());
350 return Futures.immediateFuture(null);
352 LOG.info("Close RIB Singleton Service {}, RIB {}", getIdentifier().getValue(), this.ribId.getValue());
353 this.isServiceInstantiated = false;
356 this.txChainToLocRibWriter.values().forEach(LocRibWriter::close);
357 this.txChainToLocRibWriter.clear();
359 final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
360 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
361 final CheckedFuture<Void, TransactionCommitFailedException> cleanFuture = t.submit();
363 this.domChain.close();
368 public ServiceGroupIdentifier getIdentifier() {
369 return this.serviceGroupIdentifier;
373 public ClusterSingletonServiceRegistration registerClusterSingletonService(
374 final ClusterSingletonService clusterSingletonService) {
375 return ClusterSingletonServiceRegistrationHelper
376 .registerSingletonService(this.provider, clusterSingletonService);
380 public ServiceGroupIdentifier getRibIServiceGroupIdentifier() {
381 return getIdentifier();