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.Preconditions;
13 import com.google.common.collect.ImmutableSet;
14 import com.google.common.util.concurrent.Futures;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import java.util.ArrayList;
17 import java.util.HashSet;
18 import java.util.List;
20 import java.util.Map.Entry;
22 import javax.annotation.Nonnull;
23 import javax.annotation.concurrent.ThreadSafe;
24 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
25 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
26 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
27 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
28 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
29 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
30 import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
31 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
32 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
33 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
34 import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTreeFactory;
35 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
36 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
37 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
38 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
39 import org.opendaylight.protocol.bgp.mode.api.PathSelectionMode;
40 import org.opendaylight.protocol.bgp.mode.impl.base.BasePathSelectionModeFactory;
41 import org.opendaylight.protocol.bgp.rib.DefaultRibReference;
42 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
43 import org.opendaylight.protocol.bgp.rib.impl.spi.BgpDeployer;
44 import org.opendaylight.protocol.bgp.rib.impl.spi.CodecsRegistry;
45 import org.opendaylight.protocol.bgp.rib.impl.spi.ImportPolicyPeerTracker;
46 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
47 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
48 import org.opendaylight.protocol.bgp.rib.impl.stats.rib.impl.BGPRenderStats;
49 import org.opendaylight.protocol.bgp.rib.impl.stats.rib.impl.RIBImplRuntimeMXBeanImpl;
50 import org.opendaylight.protocol.bgp.rib.spi.CacheDisconnectedPeers;
51 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
52 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.BgpRib;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.RibId;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.Rib;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibKey;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.LocRib;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.Peer;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.BgpId;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier;
65 import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
66 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
67 import org.opendaylight.yangtools.yang.common.QName;
68 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
69 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
70 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
71 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
72 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
73 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
74 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
75 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
76 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
77 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
78 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
79 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
80 import org.slf4j.Logger;
81 import org.slf4j.LoggerFactory;
84 public final class RIBImpl extends DefaultRibReference implements ClusterSingletonService, AutoCloseable, RIB, TransactionChainListener, SchemaContextListener {
85 private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
86 private static final QName RIB_ID_QNAME = QName.create(Rib.QNAME, "id").intern();
87 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);
89 private final BGPDispatcher dispatcher;
90 private final DOMTransactionChain domChain;
91 private final AsNumber localAs;
92 private final BgpId bgpIdentifier;
93 private final Set<BgpTableType> localTables;
94 private final Set<TablesKey> localTablesKeys;
95 private final DOMDataBroker domDataBroker;
96 private final RIBExtensionConsumerContext extensions;
97 private final YangInstanceIdentifier yangRibId;
98 private final RIBSupportContextRegistryImpl ribContextRegistry;
99 private final CodecsRegistryImpl codecsRegistry;
100 private final ServiceGroupIdentifier serviceGroupIdentifier;
101 private final ClusterSingletonServiceProvider provider;
102 private final PolicyDatabase policyDatabase;
103 private final BgpDeployer.WriteConfiguration configurationWriter;
104 private ClusterSingletonServiceRegistration registration;
105 private final DOMDataBrokerExtension service;
106 private final List<LocRibWriter> locRibs = new ArrayList<>();
107 private final CacheDisconnectedPeers cacheDisconnectedPeers;
108 private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
109 private final ImportPolicyPeerTracker importPolicyPeerTracker;
110 private final RIBImplRuntimeMXBeanImpl renderStats;
111 private final RibId ribId;
113 public RIBImpl(final ClusterSingletonServiceProvider provider, final RibId ribId, final AsNumber localAs, final BgpId localBgpId,
114 final ClusterIdentifier clusterId, final RIBExtensionConsumerContext extensions, final BGPDispatcher dispatcher,
115 final BindingCodecTreeFactory codecFactory, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
116 @Nonnull final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies, final GeneratedClassLoadingStrategy classStrategy,
117 final BgpDeployer.WriteConfiguration configurationWriter) {
119 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId))));
120 this.domChain = domDataBroker.createTransactionChain(this);
121 this.localAs = Preconditions.checkNotNull(localAs);
122 this.bgpIdentifier = Preconditions.checkNotNull(localBgpId);
123 this.dispatcher = Preconditions.checkNotNull(dispatcher);
124 this.localTables = ImmutableSet.copyOf(localTables);
125 this.localTablesKeys = new HashSet<>();
126 this.domDataBroker = Preconditions.checkNotNull(domDataBroker);
127 this.service = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
128 this.extensions = Preconditions.checkNotNull(extensions);
129 this.codecsRegistry = CodecsRegistryImpl.create(codecFactory, classStrategy);
130 this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
131 final InstanceIdentifierBuilder yangRibIdBuilder = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME);
132 this.yangRibId = yangRibIdBuilder.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
133 this.cacheDisconnectedPeers = new CacheDisconnectedPeersImpl();
134 this.bestPathSelectionStrategies = Preconditions.checkNotNull(bestPathSelectionStrategies);
135 final ClusterIdentifier cId = (clusterId == null) ? new ClusterIdentifier(localBgpId) : clusterId;
136 this.renderStats = new RIBImplRuntimeMXBeanImpl(localBgpId, ribId, localAs, cId);
138 this.policyDatabase = new PolicyDatabase(this.localAs.getValue(), localBgpId, cId);
139 this.importPolicyPeerTracker = new ImportPolicyPeerTrackerImpl( this.policyDatabase);
140 this.serviceGroupIdentifier = ServiceGroupIdentifier.create(this.ribId + "-service-group");
141 Preconditions.checkNotNull(provider, "ClusterSingletonServiceProvider is null");
142 this.provider = provider;
143 this.configurationWriter = configurationWriter;
144 LOG.info("RIB Singleton Service {} registered", getIdentifier());
145 //this need to be always the last step
146 this.registration = registerClusterSingletonService(this);
149 private void startLocRib(final TablesKey key, final PolicyDatabase pd) {
150 LOG.debug("Creating LocRib table for {}", key);
151 // create locRibWriter for each table
152 final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
154 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
155 table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
156 table.withChild(EMPTY_TABLE_ATTRIBUTES);
158 final NodeIdentifierWithPredicates tableKey = RibSupportUtils.toYangTablesKey(key);
159 final InstanceIdentifierBuilder tableId = YangInstanceIdentifier.builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME));
160 tableId.nodeWithKey(tableKey.getNodeType(), tableKey.getKeyValues());
161 for (final Entry<QName, Object> e : tableKey.getKeyValues().entrySet()) {
162 table.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
165 final ChoiceNode routes = this.ribContextRegistry.getRIBSupportContext(key).getRibSupport().emptyRoutes();
166 table.withChild(routes);
168 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
170 tx.submit().checkedGet();
171 } catch (final TransactionCommitFailedException e1) {
172 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
175 PathSelectionMode pathSelectionStrategy = this.bestPathSelectionStrategies.get(key);
176 if (pathSelectionStrategy == null) {
177 pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy();
180 this.locRibs.add(LocRibWriter.create(this.ribContextRegistry, key, createPeerChain(this), getYangRibId(), this.localAs, getService(), pd,
181 this.cacheDisconnectedPeers, pathSelectionStrategy, this.renderStats.getLocRibRouteCounter().init(key)));
185 public String toString() {
186 return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
189 protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
190 return toStringHelper;
194 public synchronized void close() throws Exception {
195 if (this.registration != null) {
196 this.registration.close();
197 this.registration = null;
199 if(this.domChain != null) {
200 this.domChain.close();
205 public AsNumber getLocalAs() {
210 public BgpId getBgpIdentifier() {
211 return this.bgpIdentifier;
216 public Set<? extends BgpTableType> getLocalTables() {
217 return this.localTables;
221 public BGPDispatcher getDispatcher() {
222 return this.dispatcher;
226 public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
227 LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
231 public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
232 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
236 public Set<TablesKey> getLocalTablesKeys() {
237 return this.localTablesKeys;
241 public DOMDataTreeChangeService getService() {
242 return (DOMDataTreeChangeService) this.service;
246 public BGPRenderStats getRenderStats() {
247 return this.renderStats;
251 public YangInstanceIdentifier getYangRibId() {
252 return this.yangRibId;
256 public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
257 return this.domDataBroker.createTransactionChain(listener);
261 public RIBExtensionConsumerContext getRibExtensions() {
262 return this.extensions;
266 public RIBSupportContextRegistry getRibSupportContext() {
267 return this.ribContextRegistry;
271 public void onGlobalContextUpdated(final SchemaContext context) {
272 this.codecsRegistry.onSchemaContextUpdated(context);
276 public CodecsRegistry getCodecsRegistry() {
277 return this.codecsRegistry;
280 public CacheDisconnectedPeers getCacheDisconnectedPeers() {
281 return this.cacheDisconnectedPeers;
285 public ImportPolicyPeerTracker getImportPolicyPeerTracker() {
286 return this.importPolicyPeerTracker;
290 public void instantiateServiceInstance() {
291 if(this.configurationWriter != null) {
292 this.configurationWriter.apply();
294 LOG.info("RIB Singleton Service {} instantiated", getIdentifier());
295 LOG.debug("Instantiating RIB table {} at {}", this.ribId , this.yangRibId);
297 final ContainerNode bgpRib = Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
298 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
300 final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
301 new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, this.ribId .getValue()))
302 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, this.ribId .getValue()))
303 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
304 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
305 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
309 final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
311 // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
312 trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
313 trans.put(LogicalDatastoreType.OPERATIONAL, this.yangRibId, ribInstance);
316 trans.submit().checkedGet();
317 } catch (final TransactionCommitFailedException e) {
318 LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
321 LOG.debug("Effective RIB created.");
323 for (final BgpTableType t : this.localTables) {
324 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
325 this.localTablesKeys.add(key);
326 startLocRib(key, this.policyDatabase);
331 public ListenableFuture<Void> closeServiceInstance() {
332 LOG.info("Close RIB Singleton Service {}", getIdentifier());
333 for (final LocRibWriter locRib : this.locRibs) {
336 } catch (final Exception e) {
337 LOG.warn("Could not close LocalRib reference: {}", locRib, e);
341 final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
342 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
343 t.submit().checkedGet();
344 } catch (final TransactionCommitFailedException e) {
345 LOG.warn("Failed to remove RIB instance {} from DS.", getYangRibId(), e);
347 this.renderStats.getLocRibRouteCounter().resetAll();
349 return Futures.immediateFuture(null);
353 public ServiceGroupIdentifier getIdentifier() {
354 return this.serviceGroupIdentifier;
358 public ClusterSingletonServiceRegistration registerClusterSingletonService(final ClusterSingletonService clusterSingletonService) {
359 return this.provider.registerClusterSingletonService(clusterSingletonService);
363 public ServiceGroupIdentifier getRibIServiceGroupIdentifier() {
364 return getIdentifier();