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 this.domChain.close();
196 if (this.registration != null) {
197 this.registration.close();
198 this.registration = null;
203 public AsNumber getLocalAs() {
208 public BgpId getBgpIdentifier() {
209 return this.bgpIdentifier;
213 public Set<? extends BgpTableType> getLocalTables() {
214 return this.localTables;
218 public BGPDispatcher getDispatcher() {
219 return this.dispatcher;
223 public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
224 LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
228 public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
229 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
233 public Set<TablesKey> getLocalTablesKeys() {
234 return this.localTablesKeys;
238 public DOMDataTreeChangeService getService() {
239 return (DOMDataTreeChangeService) this.service;
243 public BGPRenderStats getRenderStats() {
244 return this.renderStats;
248 public YangInstanceIdentifier getYangRibId() {
249 return this.yangRibId;
253 public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
254 return this.domDataBroker.createTransactionChain(listener);
258 public RIBExtensionConsumerContext getRibExtensions() {
259 return this.extensions;
263 public RIBSupportContextRegistry getRibSupportContext() {
264 return this.ribContextRegistry;
268 public void onGlobalContextUpdated(final SchemaContext context) {
269 this.codecsRegistry.onSchemaContextUpdated(context);
273 public CodecsRegistry getCodecsRegistry() {
274 return this.codecsRegistry;
277 public CacheDisconnectedPeers getCacheDisconnectedPeers() {
278 return this.cacheDisconnectedPeers;
282 public ImportPolicyPeerTracker getImportPolicyPeerTracker() {
283 return this.importPolicyPeerTracker;
287 public void instantiateServiceInstance() {
288 if(this.configurationWriter != null) {
289 this.configurationWriter.apply();
291 LOG.info("RIB Singleton Service {} instantiated", getIdentifier());
292 LOG.debug("Instantiating RIB table {} at {}", this.ribId , this.yangRibId);
294 final ContainerNode bgpRib = Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
295 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
297 final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
298 new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, this.ribId .getValue()))
299 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, this.ribId .getValue()))
300 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
301 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
302 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
306 final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
308 // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
309 trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
310 trans.put(LogicalDatastoreType.OPERATIONAL, this.yangRibId, ribInstance);
313 trans.submit().checkedGet();
314 } catch (final TransactionCommitFailedException e) {
315 LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
318 LOG.debug("Effective RIB created.");
320 for (final BgpTableType t : this.localTables) {
321 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
322 this.localTablesKeys.add(key);
323 startLocRib(key, this.policyDatabase);
328 public ListenableFuture<Void> closeServiceInstance() {
329 LOG.info("Close RIB Singleton Service {}", getIdentifier());
330 for (final LocRibWriter locRib : this.locRibs) {
333 } catch (final Exception e) {
334 LOG.warn("Could not close LocalRib reference: {}", locRib, e);
338 final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
339 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
340 t.submit().checkedGet();
341 } catch (final TransactionCommitFailedException e) {
342 LOG.warn("Failed to remove RIB instance {} from DS.", getYangRibId(), e);
344 this.renderStats.getLocRibRouteCounter().resetAll();
346 return Futures.immediateFuture(null);
350 public ServiceGroupIdentifier getIdentifier() {
351 return this.serviceGroupIdentifier;
355 public ClusterSingletonServiceRegistration registerClusterSingletonService(final ClusterSingletonService clusterSingletonService) {
356 return this.provider.registerClusterSingletonService(clusterSingletonService);
360 public ServiceGroupIdentifier getRibIServiceGroupIdentifier() {
361 return getIdentifier();