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.ListenableFuture;
18 import java.util.HashMap;
19 import java.util.HashSet;
20 import java.util.List;
22 import java.util.Map.Entry;
24 import javax.annotation.Nonnull;
25 import javax.annotation.Nullable;
26 import javax.annotation.concurrent.ThreadSafe;
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.TransactionChain;
30 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
31 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
32 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
33 import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
34 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
35 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
36 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
37 import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTreeFactory;
38 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
39 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
40 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
41 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
42 import org.opendaylight.protocol.bgp.mode.api.PathSelectionMode;
43 import org.opendaylight.protocol.bgp.mode.impl.base.BasePathSelectionModeFactory;
44 import org.opendaylight.protocol.bgp.openconfig.spi.BGPConfigModuleTracker;
45 import org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenConfigProvider;
46 import org.opendaylight.protocol.bgp.rib.DefaultRibReference;
47 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
48 import org.opendaylight.protocol.bgp.rib.impl.spi.BgpDeployer;
49 import org.opendaylight.protocol.bgp.rib.impl.spi.CodecsRegistry;
50 import org.opendaylight.protocol.bgp.rib.impl.spi.ImportPolicyPeerTracker;
51 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
52 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
53 import org.opendaylight.protocol.bgp.rib.impl.stats.rib.impl.BGPRenderStats;
54 import org.opendaylight.protocol.bgp.rib.impl.stats.rib.impl.RIBImplRuntimeMXBeanImpl;
55 import org.opendaylight.protocol.bgp.rib.spi.ExportPolicyPeerTracker;
56 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
57 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
58 import org.opendaylight.protocol.bgp.rib.spi.util.ClusterSingletonServiceRegistrationHelper;
59 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.BgpRib;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.RibId;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.Rib;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibKey;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.LocRib;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.Peer;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.BgpId;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier;
71 import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
72 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
73 import org.opendaylight.yangtools.yang.common.QName;
74 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
75 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
76 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
77 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
78 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
79 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
80 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
81 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
82 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
83 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
84 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
85 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
86 import org.slf4j.Logger;
87 import org.slf4j.LoggerFactory;
90 public final class RIBImpl extends DefaultRibReference implements ClusterSingletonService, AutoCloseable, RIB, TransactionChainListener, SchemaContextListener {
91 private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
92 private static final QName RIB_ID_QNAME = QName.create(Rib.QNAME, "id").intern();
93 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);
94 private static final int MAX_REGISTRATION_ATTEMPTS = 10;
95 private static final int SLEEP_TIME = MAX_REGISTRATION_ATTEMPTS;
97 private final BGPDispatcher dispatcher;
98 private final AsNumber localAs;
99 private final BgpId bgpIdentifier;
100 private final Set<BgpTableType> localTables;
101 private final Set<TablesKey> localTablesKeys;
102 private final DOMDataBroker domDataBroker;
103 private final RIBExtensionConsumerContext extensions;
104 private final YangInstanceIdentifier yangRibId;
105 private final RIBSupportContextRegistryImpl ribContextRegistry;
106 private final CodecsRegistryImpl codecsRegistry;
107 private final ServiceGroupIdentifier serviceGroupIdentifier;
108 private final ClusterSingletonServiceProvider provider;
109 private final BgpDeployer.WriteConfiguration configurationWriter;
110 private ClusterSingletonServiceRegistration registration;
111 private final DOMDataBrokerExtension service;
112 private final Map<TransactionChain, LocRibWriter> txChainToLocRibWriter = new HashMap<>();
113 private final BGPConfigModuleTracker configModuleTracker;
114 private final BGPOpenConfigProvider openConfigProvider;
115 private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
116 private final ImportPolicyPeerTracker importPolicyPeerTracker;
117 private final RIBImplRuntimeMXBeanImpl renderStats;
118 private final RibId ribId;
119 private final Map<TablesKey, ExportPolicyPeerTracker> exportPolicyPeerTrackerMap;
121 private DOMTransactionChain domChain;
123 public RIBImpl(final ClusterSingletonServiceProvider provider, final RibId ribId, final AsNumber localAs, final BgpId localBgpId,
124 final ClusterIdentifier clusterId, final RIBExtensionConsumerContext extensions, final BGPDispatcher dispatcher,
125 final BindingCodecTreeFactory codecFactory, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
126 @Nonnull final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies, final GeneratedClassLoadingStrategy classStrategy,
127 final BGPConfigModuleTracker moduleTracker, final BGPOpenConfigProvider openConfigProvider,
128 final BgpDeployer.WriteConfiguration configurationWriter) {
130 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId))));
131 this.localAs = Preconditions.checkNotNull(localAs);
132 this.bgpIdentifier = Preconditions.checkNotNull(localBgpId);
133 this.dispatcher = Preconditions.checkNotNull(dispatcher);
134 this.localTables = ImmutableSet.copyOf(localTables);
135 this.localTablesKeys = new HashSet<>();
136 this.domDataBroker = Preconditions.checkNotNull(domDataBroker);
137 this.service = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
138 this.extensions = Preconditions.checkNotNull(extensions);
139 this.codecsRegistry = CodecsRegistryImpl.create(codecFactory, classStrategy);
140 this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
141 final InstanceIdentifierBuilder yangRibIdBuilder = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME);
142 this.yangRibId = yangRibIdBuilder.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
143 this.configModuleTracker = moduleTracker;
144 this.openConfigProvider = openConfigProvider;
145 this.bestPathSelectionStrategies = Preconditions.checkNotNull(bestPathSelectionStrategies);
146 final ClusterIdentifier cId = (clusterId == null) ? new ClusterIdentifier(localBgpId) : clusterId;
147 this.renderStats = new RIBImplRuntimeMXBeanImpl(localBgpId, ribId, localAs, cId);
149 final PolicyDatabase policyDatabase = new PolicyDatabase(this.localAs.getValue(), localBgpId, cId);
150 this.importPolicyPeerTracker = new ImportPolicyPeerTrackerImpl(policyDatabase);
151 this.serviceGroupIdentifier = ServiceGroupIdentifier.create(this.ribId.getValue() + "-service-group");
152 Preconditions.checkNotNull(provider, "ClusterSingletonServiceProvider is null");
153 this.provider = provider;
154 this.configurationWriter = configurationWriter;
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));
162 this.exportPolicyPeerTrackerMap = exportPolicies.build();
164 LOG.info("RIB Singleton Service {} registered", getIdentifier());
165 //this need to be always the last step
166 this.registration = registerClusterSingletonService(this);
169 public RIBImpl(final ClusterSingletonServiceProvider provider, final RibId ribId, final AsNumber localAs, final BgpId localBgpId, @Nullable final ClusterIdentifier clusterId,
170 final RIBExtensionConsumerContext extensions, final BGPDispatcher dispatcher, final BindingCodecTreeFactory codecFactory,
171 final DOMDataBroker domDataBroker, final List<BgpTableType> localTables, final Map<TablesKey, PathSelectionMode> bestPathSelectionstrategies,
172 final GeneratedClassLoadingStrategy classStrategy, final BgpDeployer.WriteConfiguration configurationWriter) {
173 this(provider, ribId, localAs, localBgpId, clusterId, extensions, dispatcher, codecFactory,
174 domDataBroker, localTables, bestPathSelectionstrategies, classStrategy, null, null, configurationWriter);
177 private void startLocRib(final TablesKey key) {
178 LOG.debug("Creating LocRib table for {}", key);
179 // create locRibWriter for each table
180 final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
182 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
183 table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
184 table.withChild(EMPTY_TABLE_ATTRIBUTES);
186 final NodeIdentifierWithPredicates tableKey = RibSupportUtils.toYangTablesKey(key);
187 final InstanceIdentifierBuilder tableId = YangInstanceIdentifier.builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME));
188 tableId.nodeWithKey(tableKey.getNodeType(), tableKey.getKeyValues());
189 for (final Entry<QName, Object> e : tableKey.getKeyValues().entrySet()) {
190 table.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
193 final ChoiceNode routes = this.ribContextRegistry.getRIBSupportContext(key).getRibSupport().emptyRoutes();
194 table.withChild(routes);
196 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
198 tx.submit().checkedGet();
199 } catch (final TransactionCommitFailedException e1) {
200 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
202 createLocRibWriter(key);
205 private synchronized void createLocRibWriter(final TablesKey key) {
206 LOG.debug("Creating LocRIB writer for key {}", key);
207 final DOMTransactionChain txChain = createPeerChain(this);
208 PathSelectionMode pathSelectionStrategy = this.bestPathSelectionStrategies.get(key);
209 if (pathSelectionStrategy == null) {
210 pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy();
213 final LocRibWriter locRibWriter = LocRibWriter.create(this.ribContextRegistry, key, txChain,
214 getYangRibId(), this.localAs, getService(), this.exportPolicyPeerTrackerMap.get(key),
215 pathSelectionStrategy, this.renderStats.getLocRibRouteCounter().init(key));
216 this.txChainToLocRibWriter.put(txChain, locRibWriter);
220 public String toString() {
221 return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
224 protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
225 return toStringHelper;
229 public synchronized void close() throws Exception {
230 if (this.registration != null) {
231 this.registration.close();
232 this.registration = null;
237 public AsNumber getLocalAs() {
242 public BgpId getBgpIdentifier() {
243 return this.bgpIdentifier;
248 public Set<? extends BgpTableType> getLocalTables() {
249 return this.localTables;
253 public BGPDispatcher getDispatcher() {
254 return this.dispatcher;
258 public synchronized void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
259 LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
260 if (this.txChainToLocRibWriter.containsKey(chain)) {
261 final LocRibWriter locRibWriter = this.txChainToLocRibWriter.remove(chain);
262 final DOMTransactionChain newChain = createPeerChain(this);
263 locRibWriter.restart(newChain);
264 this.txChainToLocRibWriter.put(newChain, locRibWriter);
269 public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
270 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
274 public Set<TablesKey> getLocalTablesKeys() {
275 return this.localTablesKeys;
279 public DOMDataTreeChangeService getService() {
280 return (DOMDataTreeChangeService) this.service;
284 public BGPRenderStats getRenderStats() {
285 return this.renderStats;
289 public YangInstanceIdentifier getYangRibId() {
290 return this.yangRibId;
294 public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
295 return this.domDataBroker.createTransactionChain(listener);
299 public RIBExtensionConsumerContext getRibExtensions() {
300 return this.extensions;
304 public RIBSupportContextRegistry getRibSupportContext() {
305 return this.ribContextRegistry;
309 public void onGlobalContextUpdated(final SchemaContext context) {
310 this.codecsRegistry.onSchemaContextUpdated(context);
314 public CodecsRegistry getCodecsRegistry() {
315 return this.codecsRegistry;
319 public Optional<BGPOpenConfigProvider> getOpenConfigProvider() {
320 return Optional.fromNullable(this.openConfigProvider);
324 public ImportPolicyPeerTracker getImportPolicyPeerTracker() {
325 return this.importPolicyPeerTracker;
329 public ExportPolicyPeerTracker getExportPolicyPeerTracker(final TablesKey tablesKey) {
330 return this.exportPolicyPeerTrackerMap.get(tablesKey);
334 public void instantiateServiceInstance() {
335 this.domChain = this.domDataBroker.createTransactionChain(this);
336 if(this.configurationWriter != null) {
337 this.configurationWriter.apply();
339 LOG.info("RIB Singleton Service {} instantiated", getIdentifier());
340 LOG.debug("Instantiating RIB table {} at {}", this.ribId , this.yangRibId);
342 final ContainerNode bgpRib = Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
343 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
345 final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
346 new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, this.ribId .getValue()))
347 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, this.ribId .getValue()))
348 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
349 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
350 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
354 final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
356 // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
357 trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
358 trans.put(LogicalDatastoreType.OPERATIONAL, this.yangRibId, ribInstance);
361 trans.submit().checkedGet();
362 } catch (final TransactionCommitFailedException e) {
363 LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
366 LOG.debug("Effective RIB created.");
368 this.localTablesKeys.forEach(this::startLocRib);
369 if (this.configModuleTracker != null) {
370 this.configModuleTracker.onInstanceCreate();
375 public synchronized ListenableFuture<Void> closeServiceInstance() {
376 LOG.info("RIB {} closing instance", this.ribId.getValue());
377 this.txChainToLocRibWriter.values().forEach(LocRibWriter::close);
378 this.txChainToLocRibWriter.clear();
380 this.renderStats.getLocRibRouteCounter().resetAll();
382 if (this.configModuleTracker != null) {
383 this.configModuleTracker.onInstanceClose();
386 final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
387 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
388 final CheckedFuture<Void, TransactionCommitFailedException> cleanFuture = t.submit();
390 this.domChain.close();
396 public ServiceGroupIdentifier getIdentifier() {
397 return this.serviceGroupIdentifier;
401 public ClusterSingletonServiceRegistration registerClusterSingletonService(final ClusterSingletonService clusterSingletonService) {
402 return ClusterSingletonServiceRegistrationHelper.registerSingletonService(this.provider, clusterSingletonService, MAX_REGISTRATION_ATTEMPTS,
407 public ServiceGroupIdentifier getRibIServiceGroupIdentifier() {
408 return getIdentifier();