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 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.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.Nullable;
27 import javax.annotation.concurrent.GuardedBy;
28 import javax.annotation.concurrent.ThreadSafe;
29 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
30 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
31 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
32 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
33 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
34 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
35 import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
36 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
37 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
38 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
39 import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTreeFactory;
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.openconfig.spi.BGPConfigModuleTracker;
47 import org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenConfigProvider;
48 import org.opendaylight.protocol.bgp.rib.DefaultRibReference;
49 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
50 import org.opendaylight.protocol.bgp.rib.impl.spi.BgpDeployer;
51 import org.opendaylight.protocol.bgp.rib.impl.spi.CodecsRegistry;
52 import org.opendaylight.protocol.bgp.rib.impl.spi.ImportPolicyPeerTracker;
53 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
54 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
55 import org.opendaylight.protocol.bgp.rib.impl.stats.rib.impl.BGPRenderStats;
56 import org.opendaylight.protocol.bgp.rib.impl.stats.rib.impl.RIBImplRuntimeMXBeanImpl;
57 import org.opendaylight.protocol.bgp.rib.spi.ExportPolicyPeerTracker;
58 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
59 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
60 import org.opendaylight.protocol.bgp.rib.spi.util.ClusterSingletonServiceRegistrationHelper;
61 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.BgpRib;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.RibId;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.Rib;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibKey;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.LocRib;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.Peer;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.BgpId;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier;
73 import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
74 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
75 import org.opendaylight.yangtools.yang.common.QName;
76 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
77 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
78 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
79 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
80 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
81 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
82 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
83 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
84 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
85 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
86 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
87 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
88 import org.slf4j.Logger;
89 import org.slf4j.LoggerFactory;
92 public final class RIBImpl extends DefaultRibReference implements ClusterSingletonService, AutoCloseable, RIB, TransactionChainListener, SchemaContextListener {
93 private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
94 private static final QName RIB_ID_QNAME = QName.create(Rib.QNAME, "id").intern();
95 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);
96 private static final int MAX_REGISTRATION_ATTEMPTS = 10;
97 private static final int SLEEP_TIME = MAX_REGISTRATION_ATTEMPTS;
99 private final BGPDispatcher dispatcher;
100 private final AsNumber localAs;
101 private final BgpId bgpIdentifier;
102 private final Set<BgpTableType> localTables;
103 private final Set<TablesKey> localTablesKeys;
104 private final DOMDataBroker domDataBroker;
105 private final RIBExtensionConsumerContext extensions;
106 private final YangInstanceIdentifier yangRibId;
107 private final RIBSupportContextRegistryImpl ribContextRegistry;
108 private final CodecsRegistryImpl codecsRegistry;
109 private final ServiceGroupIdentifier serviceGroupIdentifier;
110 private final ClusterSingletonServiceProvider provider;
111 private final BgpDeployer.WriteConfiguration configurationWriter;
112 private ClusterSingletonServiceRegistration registration;
113 private final DOMDataBrokerExtension service;
114 private final Map<TransactionChain, LocRibWriter> txChainToLocRibWriter = new HashMap<>();
115 private final BGPConfigModuleTracker configModuleTracker;
116 private final BGPOpenConfigProvider openConfigProvider;
117 private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
118 private final ImportPolicyPeerTracker importPolicyPeerTracker;
119 private final RIBImplRuntimeMXBeanImpl renderStats;
120 private final RibId ribId;
121 private final Map<TablesKey, ExportPolicyPeerTracker> exportPolicyPeerTrackerMap;
123 private DOMTransactionChain domChain;
125 private boolean isServiceInstantiated;
127 public RIBImpl(final ClusterSingletonServiceProvider provider, final RibId ribId, final AsNumber localAs, final BgpId localBgpId,
128 final ClusterIdentifier clusterId, final RIBExtensionConsumerContext extensions, final BGPDispatcher dispatcher,
129 final BindingCodecTreeFactory codecFactory, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
130 @Nonnull final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies, final GeneratedClassLoadingStrategy classStrategy,
131 final BGPConfigModuleTracker moduleTracker, final BGPOpenConfigProvider openConfigProvider,
132 final BgpDeployer.WriteConfiguration configurationWriter) {
134 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId))));
135 this.localAs = Preconditions.checkNotNull(localAs);
136 this.bgpIdentifier = Preconditions.checkNotNull(localBgpId);
137 this.dispatcher = Preconditions.checkNotNull(dispatcher);
138 this.localTables = ImmutableSet.copyOf(localTables);
139 this.localTablesKeys = new HashSet<>();
140 this.domDataBroker = Preconditions.checkNotNull(domDataBroker);
141 this.service = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
142 this.extensions = Preconditions.checkNotNull(extensions);
143 this.codecsRegistry = CodecsRegistryImpl.create(codecFactory, classStrategy);
144 this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
145 final InstanceIdentifierBuilder yangRibIdBuilder = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME);
146 this.yangRibId = yangRibIdBuilder.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
147 this.configModuleTracker = moduleTracker;
148 this.openConfigProvider = openConfigProvider;
149 this.bestPathSelectionStrategies = Preconditions.checkNotNull(bestPathSelectionStrategies);
150 final ClusterIdentifier cId = (clusterId == null) ? new ClusterIdentifier(localBgpId) : clusterId;
151 this.renderStats = new RIBImplRuntimeMXBeanImpl(localBgpId, ribId, localAs, cId);
153 final PolicyDatabase policyDatabase = new PolicyDatabase(this.localAs.getValue(), localBgpId, cId);
154 this.importPolicyPeerTracker = new ImportPolicyPeerTrackerImpl(policyDatabase);
155 this.serviceGroupIdentifier = ServiceGroupIdentifier.create(this.ribId.getValue() + "-service-group");
156 Preconditions.checkNotNull(provider, "ClusterSingletonServiceProvider is null");
157 this.provider = provider;
158 this.configurationWriter = configurationWriter;
160 final ImmutableMap.Builder<TablesKey, ExportPolicyPeerTracker> exportPolicies = new ImmutableMap.Builder<>();
161 for (final BgpTableType t : this.localTables) {
162 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
163 this.localTablesKeys.add(key);
164 exportPolicies.put(key, new ExportPolicyPeerTrackerImpl(policyDatabase, key));
166 this.exportPolicyPeerTrackerMap = exportPolicies.build();
168 LOG.info("RIB Singleton Service {} registered, RIB {}", getIdentifier().getValue(), this.ribId.getValue());
169 //this need to be always the last step
170 this.registration = registerClusterSingletonService(this);
173 public RIBImpl(final ClusterSingletonServiceProvider provider, final RibId ribId, final AsNumber localAs, final BgpId localBgpId, @Nullable final ClusterIdentifier clusterId,
174 final RIBExtensionConsumerContext extensions, final BGPDispatcher dispatcher, final BindingCodecTreeFactory codecFactory,
175 final DOMDataBroker domDataBroker, final List<BgpTableType> localTables, final Map<TablesKey, PathSelectionMode> bestPathSelectionstrategies,
176 final GeneratedClassLoadingStrategy classStrategy, final BgpDeployer.WriteConfiguration configurationWriter) {
177 this(provider, ribId, localAs, localBgpId, clusterId, extensions, dispatcher, codecFactory,
178 domDataBroker, localTables, bestPathSelectionstrategies, classStrategy, null, null, configurationWriter);
181 private void startLocRib(final TablesKey key) {
182 LOG.debug("Creating LocRib table for {}", key);
183 // create locRibWriter for each table
184 final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
186 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
187 table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
188 table.withChild(EMPTY_TABLE_ATTRIBUTES);
190 final NodeIdentifierWithPredicates tableKey = RibSupportUtils.toYangTablesKey(key);
191 final InstanceIdentifierBuilder tableId = YangInstanceIdentifier.builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME));
192 tableId.nodeWithKey(tableKey.getNodeType(), tableKey.getKeyValues());
193 for (final Entry<QName, Object> e : tableKey.getKeyValues().entrySet()) {
194 table.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
197 final ChoiceNode routes = this.ribContextRegistry.getRIBSupportContext(key).getRibSupport().emptyRoutes();
198 table.withChild(routes);
200 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
202 tx.submit().checkedGet();
203 } catch (final TransactionCommitFailedException e1) {
204 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
206 createLocRibWriter(key);
209 private synchronized void createLocRibWriter(final TablesKey key) {
210 LOG.debug("Creating LocRIB writer for key {}", key);
211 final DOMTransactionChain txChain = createPeerChain(this);
212 PathSelectionMode pathSelectionStrategy = this.bestPathSelectionStrategies.get(key);
213 if (pathSelectionStrategy == null) {
214 pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy();
217 final LocRibWriter locRibWriter = LocRibWriter.create(this.ribContextRegistry, key, txChain,
218 getYangRibId(), this.localAs, getService(), this.exportPolicyPeerTrackerMap.get(key),
219 pathSelectionStrategy, this.renderStats.getLocRibRouteCounter().init(key));
220 this.txChainToLocRibWriter.put(txChain, locRibWriter);
224 public String toString() {
225 return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
228 protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
229 return toStringHelper;
233 public synchronized void close() throws Exception {
234 if (this.registration != null) {
235 this.registration.close();
236 this.registration = null;
241 public AsNumber getLocalAs() {
246 public BgpId getBgpIdentifier() {
247 return this.bgpIdentifier;
252 public Set<? extends BgpTableType> getLocalTables() {
253 return this.localTables;
257 public BGPDispatcher getDispatcher() {
258 return this.dispatcher;
262 public synchronized void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
263 LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
264 if (this.txChainToLocRibWriter.containsKey(chain)) {
265 final LocRibWriter locRibWriter = this.txChainToLocRibWriter.remove(chain);
266 final DOMTransactionChain newChain = createPeerChain(this);
267 locRibWriter.restart(newChain);
268 this.txChainToLocRibWriter.put(newChain, locRibWriter);
273 public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
274 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
278 public Set<TablesKey> getLocalTablesKeys() {
279 return this.localTablesKeys;
283 public DOMDataTreeChangeService getService() {
284 return (DOMDataTreeChangeService) this.service;
288 public BGPRenderStats getRenderStats() {
289 return this.renderStats;
293 public YangInstanceIdentifier getYangRibId() {
294 return this.yangRibId;
298 public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
299 return this.domDataBroker.createTransactionChain(listener);
303 public RIBExtensionConsumerContext getRibExtensions() {
304 return this.extensions;
308 public RIBSupportContextRegistry getRibSupportContext() {
309 return this.ribContextRegistry;
313 public void onGlobalContextUpdated(final SchemaContext context) {
314 this.codecsRegistry.onSchemaContextUpdated(context);
318 public CodecsRegistry getCodecsRegistry() {
319 return this.codecsRegistry;
323 public Optional<BGPOpenConfigProvider> getOpenConfigProvider() {
324 return Optional.fromNullable(this.openConfigProvider);
328 public ImportPolicyPeerTracker getImportPolicyPeerTracker() {
329 return this.importPolicyPeerTracker;
333 public ExportPolicyPeerTracker getExportPolicyPeerTracker(final TablesKey tablesKey) {
334 return this.exportPolicyPeerTrackerMap.get(tablesKey);
338 public synchronized void instantiateServiceInstance() {
339 this.isServiceInstantiated = true;
340 this.domChain = this.domDataBroker.createTransactionChain(this);
341 if(this.configurationWriter != null) {
342 this.configurationWriter.apply();
344 LOG.info("RIB Singleton Service {} instantiated, RIB {}", getIdentifier().getValue(), this.ribId.getValue());
345 LOG.debug("Instantiating RIB table {} at {}", this.ribId , this.yangRibId);
347 final ContainerNode bgpRib = Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
348 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
350 final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
351 new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, this.ribId .getValue()))
352 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, this.ribId .getValue()))
353 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
354 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
355 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
359 final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
361 // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
362 trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
363 trans.put(LogicalDatastoreType.OPERATIONAL, this.yangRibId, ribInstance);
366 trans.submit().checkedGet();
367 } catch (final TransactionCommitFailedException e) {
368 LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
371 LOG.debug("Effective RIB created.");
373 this.localTablesKeys.forEach(this::startLocRib);
374 if (this.configModuleTracker != null) {
375 this.configModuleTracker.onInstanceCreate();
380 public synchronized ListenableFuture<Void> closeServiceInstance() {
381 if(!this.isServiceInstantiated) {
382 LOG.trace("RIB Singleton Service {} already closed, RIB {}", getIdentifier().getValue(),
383 this.ribId.getValue());
384 return Futures.immediateFuture(null);
386 LOG.info("Close RIB Singleton Service {}, RIB {}", getIdentifier().getValue(), this.ribId.getValue());
387 this.isServiceInstantiated = false;
389 this.txChainToLocRibWriter.values().forEach(LocRibWriter::close);
390 this.txChainToLocRibWriter.clear();
392 this.renderStats.getLocRibRouteCounter().resetAll();
394 if (this.configModuleTracker != null) {
395 this.configModuleTracker.onInstanceClose();
398 final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
399 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
400 final CheckedFuture<Void, TransactionCommitFailedException> cleanFuture = t.submit();
402 this.domChain.close();
408 public ServiceGroupIdentifier getIdentifier() {
409 return this.serviceGroupIdentifier;
413 public ClusterSingletonServiceRegistration registerClusterSingletonService(final ClusterSingletonService clusterSingletonService) {
414 return ClusterSingletonServiceRegistrationHelper.registerSingletonService(this.provider, clusterSingletonService, MAX_REGISTRATION_ATTEMPTS,
419 public ServiceGroupIdentifier getRibIServiceGroupIdentifier() {
420 return getIdentifier();