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.ImmutableSet;
15 import com.google.common.util.concurrent.Futures;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import java.util.ArrayList;
18 import java.util.HashSet;
19 import java.util.List;
21 import java.util.Map.Entry;
23 import javax.annotation.Nonnull;
24 import javax.annotation.Nullable;
25 import javax.annotation.concurrent.ThreadSafe;
26 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
27 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
28 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
29 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
30 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
31 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
32 import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
33 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
34 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
35 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
36 import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTreeFactory;
37 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
38 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
39 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
40 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
41 import org.opendaylight.protocol.bgp.mode.api.PathSelectionMode;
42 import org.opendaylight.protocol.bgp.mode.impl.base.BasePathSelectionModeFactory;
43 import org.opendaylight.protocol.bgp.openconfig.spi.BGPConfigModuleTracker;
44 import org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenConfigProvider;
45 import org.opendaylight.protocol.bgp.rib.DefaultRibReference;
46 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
47 import org.opendaylight.protocol.bgp.rib.impl.spi.BgpDeployer;
48 import org.opendaylight.protocol.bgp.rib.impl.spi.CodecsRegistry;
49 import org.opendaylight.protocol.bgp.rib.impl.spi.ImportPolicyPeerTracker;
50 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
51 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
52 import org.opendaylight.protocol.bgp.rib.impl.stats.rib.impl.BGPRenderStats;
53 import org.opendaylight.protocol.bgp.rib.impl.stats.rib.impl.RIBImplRuntimeMXBeanImpl;
54 import org.opendaylight.protocol.bgp.rib.spi.CacheDisconnectedPeers;
55 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
56 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
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.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
70 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
71 import org.opendaylight.yangtools.yang.common.QName;
72 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
73 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
74 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
75 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
76 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
77 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
78 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
79 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
80 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
81 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
82 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
83 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
84 import org.slf4j.Logger;
85 import org.slf4j.LoggerFactory;
88 public final class RIBImpl extends DefaultRibReference implements ClusterSingletonService, AutoCloseable, RIB, TransactionChainListener, SchemaContextListener {
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 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 DOMDataBroker domDataBroker;
100 private final RIBExtensionConsumerContext extensions;
101 private final YangInstanceIdentifier yangRibId;
102 private final RIBSupportContextRegistryImpl ribContextRegistry;
103 private final CodecsRegistryImpl codecsRegistry;
104 private final ServiceGroupIdentifier serviceGroupIdentifier;
105 private final ClusterSingletonServiceProvider provider;
106 private final PolicyDatabase policyDatabase;
107 private final BgpDeployer.WriteConfiguration configurationWriter;
108 private ClusterSingletonServiceRegistration registration;
109 private final DOMDataBrokerExtension service;
110 private final List<LocRibWriter> locRibs = new ArrayList<>();
111 private final BGPConfigModuleTracker configModuleTracker;
112 private final BGPOpenConfigProvider openConfigProvider;
113 private final CacheDisconnectedPeers cacheDisconnectedPeers;
114 private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
115 private final ImportPolicyPeerTracker importPolicyPeerTracker;
116 private final RIBImplRuntimeMXBeanImpl renderStats;
117 private final RibId ribId;
119 public RIBImpl(final ClusterSingletonServiceProvider provider, final RibId ribId, final AsNumber localAs, final BgpId localBgpId,
120 final ClusterIdentifier clusterId, final RIBExtensionConsumerContext extensions, final BGPDispatcher dispatcher,
121 final BindingCodecTreeFactory codecFactory, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
122 @Nonnull final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies, final GeneratedClassLoadingStrategy classStrategy,
123 final BGPConfigModuleTracker moduleTracker, final BGPOpenConfigProvider openConfigProvider,
124 final BgpDeployer.WriteConfiguration configurationWriter) {
126 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId))));
127 this.domChain = domDataBroker.createTransactionChain(this);
128 this.localAs = Preconditions.checkNotNull(localAs);
129 this.bgpIdentifier = Preconditions.checkNotNull(localBgpId);
130 this.dispatcher = Preconditions.checkNotNull(dispatcher);
131 this.localTables = ImmutableSet.copyOf(localTables);
132 this.localTablesKeys = new HashSet<>();
133 this.domDataBroker = Preconditions.checkNotNull(domDataBroker);
134 this.service = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
135 this.extensions = Preconditions.checkNotNull(extensions);
136 this.codecsRegistry = CodecsRegistryImpl.create(codecFactory, classStrategy);
137 this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
138 final InstanceIdentifierBuilder yangRibIdBuilder = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME);
139 this.yangRibId = yangRibIdBuilder.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
140 this.configModuleTracker = moduleTracker;
141 this.openConfigProvider = openConfigProvider;
142 this.cacheDisconnectedPeers = new CacheDisconnectedPeersImpl();
143 this.bestPathSelectionStrategies = Preconditions.checkNotNull(bestPathSelectionStrategies);
144 final ClusterIdentifier cId = (clusterId == null) ? new ClusterIdentifier(localBgpId) : clusterId;
145 this.renderStats = new RIBImplRuntimeMXBeanImpl(localBgpId, ribId, localAs, cId);
147 this.policyDatabase = new PolicyDatabase(this.localAs.getValue(), localBgpId, cId);
148 this.importPolicyPeerTracker = new ImportPolicyPeerTrackerImpl( this.policyDatabase);
149 this.serviceGroupIdentifier = ServiceGroupIdentifier.create(this.ribId + "-service-group");
150 Preconditions.checkNotNull(provider, "ClusterSingletonServiceProvider is null");
151 this.provider = provider;
152 this.configurationWriter = configurationWriter;
153 LOG.info("RIB Singleton Service {} registered", getIdentifier());
154 //this need to be always the last step
155 this.registration = registerClusterSingletonService(this);
158 public RIBImpl(final ClusterSingletonServiceProvider provider, final RibId ribId, final AsNumber localAs, final BgpId localBgpId, @Nullable final ClusterIdentifier clusterId,
159 final RIBExtensionConsumerContext extensions, final BGPDispatcher dispatcher, final BindingCodecTreeFactory codecFactory,
160 final DOMDataBroker domDataBroker, final List<BgpTableType> localTables, final Map<TablesKey, PathSelectionMode> bestPathSelectionstrategies,
161 final GeneratedClassLoadingStrategy classStrategy, final BgpDeployer.WriteConfiguration configurationWriter) {
162 this(provider, ribId, localAs, localBgpId, clusterId, extensions, dispatcher, codecFactory,
163 domDataBroker, localTables, bestPathSelectionstrategies, classStrategy, null, null, configurationWriter);
166 private void startLocRib(final TablesKey key, final PolicyDatabase pd) {
167 LOG.debug("Creating LocRib table for {}", key);
168 // create locRibWriter for each table
169 final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
171 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
172 table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
173 table.withChild(EMPTY_TABLE_ATTRIBUTES);
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()));
182 final ChoiceNode routes = this.ribContextRegistry.getRIBSupportContext(key).getRibSupport().emptyRoutes();
183 table.withChild(routes);
185 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
187 tx.submit().checkedGet();
188 } catch (final TransactionCommitFailedException e1) {
189 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
192 PathSelectionMode pathSelectionStrategy = this.bestPathSelectionStrategies.get(key);
193 if (pathSelectionStrategy == null) {
194 pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy();
197 this.locRibs.add(LocRibWriter.create(this.ribContextRegistry, key, createPeerChain(this), getYangRibId(), this.localAs, getService(), pd,
198 this.cacheDisconnectedPeers, pathSelectionStrategy, this.renderStats.getLocRibRouteCounter().init(key)));
202 public String toString() {
203 return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
206 protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
207 return toStringHelper;
211 public synchronized void close() throws Exception {
212 if (this.registration != null) {
213 this.registration.close();
214 this.registration = null;
216 if(this.domChain != null) {
217 this.domChain.close();
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 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);
248 public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
249 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
253 public Set<TablesKey> getLocalTablesKeys() {
254 return this.localTablesKeys;
258 public DOMDataTreeChangeService getService() {
259 return (DOMDataTreeChangeService) this.service;
263 public BGPRenderStats getRenderStats() {
264 return this.renderStats;
268 public YangInstanceIdentifier getYangRibId() {
269 return this.yangRibId;
273 public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
274 return this.domDataBroker.createTransactionChain(listener);
278 public RIBExtensionConsumerContext getRibExtensions() {
279 return this.extensions;
283 public RIBSupportContextRegistry getRibSupportContext() {
284 return this.ribContextRegistry;
288 public void onGlobalContextUpdated(final SchemaContext context) {
289 this.codecsRegistry.onSchemaContextUpdated(context);
293 public CodecsRegistry getCodecsRegistry() {
294 return this.codecsRegistry;
298 public Optional<BGPOpenConfigProvider> getOpenConfigProvider() {
299 return Optional.fromNullable(this.openConfigProvider);
303 public CacheDisconnectedPeers getCacheDisconnectedPeers() {
304 return this.cacheDisconnectedPeers;
308 public ImportPolicyPeerTracker getImportPolicyPeerTracker() {
309 return this.importPolicyPeerTracker;
313 public void instantiateServiceInstance() {
314 if(this.configurationWriter != null) {
315 this.configurationWriter.apply();
317 LOG.info("RIB Singleton Service {} instantiated", getIdentifier());
318 LOG.debug("Instantiating RIB table {} at {}", this.ribId , this.yangRibId);
320 final ContainerNode bgpRib = Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
321 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
323 final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
324 new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, this.ribId .getValue()))
325 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, this.ribId .getValue()))
326 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
327 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
328 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
332 final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
334 // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
335 trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
336 trans.put(LogicalDatastoreType.OPERATIONAL, this.yangRibId, ribInstance);
339 trans.submit().checkedGet();
340 } catch (final TransactionCommitFailedException e) {
341 LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
344 LOG.debug("Effective RIB created.");
346 for (final BgpTableType t : this.localTables) {
347 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
348 this.localTablesKeys.add(key);
349 startLocRib(key, this.policyDatabase);
352 if (this.configModuleTracker != null) {
353 this.configModuleTracker.onInstanceCreate();
358 public ListenableFuture<Void> closeServiceInstance() {
359 LOG.info("Close RIB Singleton Service {}", getIdentifier());
360 for (final LocRibWriter locRib : this.locRibs) {
363 } catch (final Exception e) {
364 LOG.warn("Could not close LocalRib reference: {}", locRib, e);
368 final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
369 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
370 t.submit().checkedGet();
371 } catch (final TransactionCommitFailedException e) {
372 LOG.warn("Failed to remove RIB instance {} from DS.", getYangRibId(), e);
374 this.renderStats.getLocRibRouteCounter().resetAll();
376 if (this.configModuleTracker != null) {
377 this.configModuleTracker.onInstanceClose();
379 return Futures.immediateFuture(null);
383 public ServiceGroupIdentifier getIdentifier() {
384 return this.serviceGroupIdentifier;
388 public ClusterSingletonServiceRegistration registerClusterSingletonService(final ClusterSingletonService clusterSingletonService) {
389 return this.provider.registerClusterSingletonService(clusterSingletonService);
393 public ServiceGroupIdentifier getRibIServiceGroupIdentifier() {
394 return getIdentifier();