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.config.yang.bgp.rib.impl.RIBImplRuntimeRegistration;
27 import org.opendaylight.controller.config.yang.bgp.rib.impl.RIBImplRuntimeRegistrator;
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.singleton.common.api.ClusterSingletonService;
40 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
41 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
42 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
43 import org.opendaylight.protocol.bgp.mode.api.PathSelectionMode;
44 import org.opendaylight.protocol.bgp.mode.impl.base.BasePathSelectionModeFactory;
45 import org.opendaylight.protocol.bgp.openconfig.spi.BGPConfigModuleTracker;
46 import org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenConfigProvider;
47 import org.opendaylight.protocol.bgp.rib.DefaultRibReference;
48 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
49 import org.opendaylight.protocol.bgp.rib.impl.spi.BgpDeployer;
50 import org.opendaylight.protocol.bgp.rib.impl.spi.CodecsRegistry;
51 import org.opendaylight.protocol.bgp.rib.impl.spi.ImportPolicyPeerTracker;
52 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
53 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
54 import org.opendaylight.protocol.bgp.rib.impl.stats.rib.impl.BGPRenderStats;
55 import org.opendaylight.protocol.bgp.rib.impl.stats.rib.impl.RIBImplRuntimeMXBeanImpl;
56 import org.opendaylight.protocol.bgp.rib.spi.CacheDisconnectedPeers;
57 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
58 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
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);
95 private final BGPDispatcher dispatcher;
96 private final DOMTransactionChain domChain;
97 private final AsNumber localAs;
98 private final BgpId bgpIdentifier;
99 private final Set<BgpTableType> localTables;
100 private final Set<TablesKey> localTablesKeys;
101 private final DOMDataBroker domDataBroker;
102 private final RIBExtensionConsumerContext extensions;
103 private final YangInstanceIdentifier yangRibId;
104 private final RIBSupportContextRegistryImpl ribContextRegistry;
105 private final CodecsRegistryImpl codecsRegistry;
106 private final ServiceGroupIdentifier serviceGroupIdentifier;
107 private final ClusterSingletonServiceProvider provider;
108 private final PolicyDatabase policyDatabase;
109 private final BgpDeployer.WriteConfiguration configurationWriter;
110 private ClusterSingletonServiceRegistration registration;
111 private final DOMDataBrokerExtension service;
112 private final List<LocRibWriter> locRibs = new ArrayList<>();
113 private final BGPConfigModuleTracker configModuleTracker;
114 private final BGPOpenConfigProvider openConfigProvider;
115 private final CacheDisconnectedPeers cacheDisconnectedPeers;
116 private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
117 private final ImportPolicyPeerTracker importPolicyPeerTracker;
118 private final RIBImplRuntimeMXBeanImpl renderStats;
119 private final RibId ribId;
121 public RIBImpl(final ClusterSingletonServiceProvider provider, final RibId ribId, final AsNumber localAs, final BgpId localBgpId,
122 final ClusterIdentifier clusterId, final RIBExtensionConsumerContext extensions, final BGPDispatcher dispatcher,
123 final BindingCodecTreeFactory codecFactory, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
124 @Nonnull final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies, final GeneratedClassLoadingStrategy classStrategy,
125 final BGPConfigModuleTracker moduleTracker, final BGPOpenConfigProvider openConfigProvider, final BgpDeployer.WriteConfiguration configurationWriter) {
127 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId))));
128 this.domChain = domDataBroker.createTransactionChain(this);
129 this.localAs = Preconditions.checkNotNull(localAs);
130 this.bgpIdentifier = Preconditions.checkNotNull(localBgpId);
131 this.dispatcher = Preconditions.checkNotNull(dispatcher);
132 this.localTables = ImmutableSet.copyOf(localTables);
133 this.localTablesKeys = new HashSet<>();
134 this.domDataBroker = Preconditions.checkNotNull(domDataBroker);
135 this.service = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
136 this.extensions = Preconditions.checkNotNull(extensions);
137 this.codecsRegistry = CodecsRegistryImpl.create(codecFactory, classStrategy);
138 this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
139 final InstanceIdentifierBuilder yangRibIdBuilder = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME);
140 this.yangRibId = yangRibIdBuilder.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
141 this.configModuleTracker = moduleTracker;
142 this.openConfigProvider = openConfigProvider;
143 this.cacheDisconnectedPeers = new CacheDisconnectedPeersImpl();
144 this.bestPathSelectionStrategies = Preconditions.checkNotNull(bestPathSelectionStrategies);
145 final ClusterIdentifier cId = (clusterId == null) ? new ClusterIdentifier(localBgpId) : clusterId;
146 this.renderStats = new RIBImplRuntimeMXBeanImpl(localBgpId, ribId, localAs, cId);
148 this.policyDatabase = new PolicyDatabase(this.localAs.getValue(), localBgpId, cId);
149 this.importPolicyPeerTracker = new ImportPolicyPeerTrackerImpl( this.policyDatabase);
150 this.serviceGroupIdentifier = ServiceGroupIdentifier.create(this.ribId + "-service-group");
151 Preconditions.checkNotNull(provider, "ClusterSingletonServiceProvider is null");
152 this.provider = provider;
153 LOG.info("RIB Singleton Service {} registered", this.getIdentifier());
154 this.registration = registerClusterSingletonService(this);
155 this.configurationWriter = configurationWriter;
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 (registration != null) {
213 registration.close();
219 public AsNumber getLocalAs() {
224 public BgpId getBgpIdentifier() {
225 return this.bgpIdentifier;
229 public Set<? extends BgpTableType> getLocalTables() {
230 return this.localTables;
234 public BGPDispatcher getDispatcher() {
235 return this.dispatcher;
239 public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
240 LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
244 public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
245 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
249 public Set<TablesKey> getLocalTablesKeys() {
250 return this.localTablesKeys;
254 public DOMDataTreeChangeService getService() {
255 return (DOMDataTreeChangeService) this.service;
259 public BGPRenderStats getRenderStats() {
260 return this.renderStats;
264 public YangInstanceIdentifier getYangRibId() {
265 return this.yangRibId;
269 public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
270 return this.domDataBroker.createTransactionChain(listener);
274 public RIBExtensionConsumerContext getRibExtensions() {
275 return this.extensions;
279 public RIBSupportContextRegistry getRibSupportContext() {
280 return this.ribContextRegistry;
284 public void onGlobalContextUpdated(final SchemaContext context) {
285 this.codecsRegistry.onSchemaContextUpdated(context);
289 public CodecsRegistry getCodecsRegistry() {
290 return this.codecsRegistry;
294 public Optional<BGPOpenConfigProvider> getOpenConfigProvider() {
295 return Optional.fromNullable(this.openConfigProvider);
299 public CacheDisconnectedPeers getCacheDisconnectedPeers() {
300 return this.cacheDisconnectedPeers;
304 public ImportPolicyPeerTracker getImportPolicyPeerTracker() {
305 return this.importPolicyPeerTracker;
309 public void instantiateServiceInstance() {
310 if(this.configurationWriter != null) {
311 this.configurationWriter.apply();
313 LOG.info("RIB Singleton Service {} instantiated", this.getIdentifier());
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 for (final BgpTableType t : this.localTables) {
343 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
344 this.localTablesKeys.add(key);
345 startLocRib(key, policyDatabase);
348 if (this.configModuleTracker != null) {
349 this.configModuleTracker.onInstanceCreate();
354 public ListenableFuture<Void> closeServiceInstance() {
356 final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
357 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
358 t.submit().checkedGet();
359 } catch (final TransactionCommitFailedException e) {
360 LOG.warn("Failed to remove RIB instance {} from DS.", getYangRibId(), e);
362 this.domChain.close();
363 for (final LocRibWriter locRib : this.locRibs) {
366 } catch (final Exception e) {
367 LOG.warn("Could not close LocalRib reference: {}", locRib, e);
371 this.renderStats.getLocRibRouteCounter().resetAll();
373 if (this.configModuleTracker != null) {
374 this.configModuleTracker.onInstanceClose();
376 return Futures.immediateFuture(null);
380 public ServiceGroupIdentifier getIdentifier() {
381 return this.serviceGroupIdentifier;
385 public ClusterSingletonServiceRegistration registerClusterSingletonService(final ClusterSingletonService clusterSingletonService) {
386 return this.provider.registerClusterSingletonService(clusterSingletonService);
390 public ServiceGroupIdentifier getRibIServiceGroupIdentifier() {
391 return getIdentifier();