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.Futures;
17 import com.google.common.util.concurrent.ListenableFuture;
18 import java.util.ArrayList;
19 import java.util.HashMap;
20 import java.util.HashSet;
21 import java.util.List;
23 import java.util.Map.Entry;
25 import javax.annotation.Nonnull;
26 import javax.annotation.Nullable;
27 import javax.annotation.concurrent.ThreadSafe;
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.ExportPolicyPeerTracker;
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 BgpDeployer.WriteConfiguration configurationWriter;
109 private ClusterSingletonServiceRegistration registration;
110 private final DOMDataBrokerExtension service;
111 private final List<LocRibWriter> locRibs = new ArrayList<>();
112 private final BGPConfigModuleTracker configModuleTracker;
113 private final BGPOpenConfigProvider openConfigProvider;
114 private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
115 private final ImportPolicyPeerTracker importPolicyPeerTracker;
116 private final RIBImplRuntimeMXBeanImpl renderStats;
117 private final RibId ribId;
118 private final Map<TablesKey, ExportPolicyPeerTracker> exportPolicyPeerTrackerMap;
120 public RIBImpl(final ClusterSingletonServiceProvider provider, final RibId ribId, final AsNumber localAs, final BgpId localBgpId,
121 final ClusterIdentifier clusterId, final RIBExtensionConsumerContext extensions, final BGPDispatcher dispatcher,
122 final BindingCodecTreeFactory codecFactory, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
123 @Nonnull final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies, final GeneratedClassLoadingStrategy classStrategy,
124 final BGPConfigModuleTracker moduleTracker, final BGPOpenConfigProvider openConfigProvider,
125 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.bestPathSelectionStrategies = Preconditions.checkNotNull(bestPathSelectionStrategies);
144 final ClusterIdentifier cId = (clusterId == null) ? new ClusterIdentifier(localBgpId) : clusterId;
145 this.renderStats = new RIBImplRuntimeMXBeanImpl(localBgpId, ribId, localAs, cId);
147 final PolicyDatabase policyDatabase = new PolicyDatabase(this.localAs.getValue(), localBgpId, cId);
148 this.importPolicyPeerTracker = new ImportPolicyPeerTrackerImpl(policyDatabase);
149 this.serviceGroupIdentifier = ServiceGroupIdentifier.create(this.ribId.getValue() + "-service-group");
150 Preconditions.checkNotNull(provider, "ClusterSingletonServiceProvider is null");
151 this.provider = provider;
152 this.configurationWriter = configurationWriter;
154 final ImmutableMap.Builder<TablesKey, ExportPolicyPeerTracker> exportPolicies = new ImmutableMap.Builder<>();
155 for (final BgpTableType t : this.localTables) {
156 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
157 this.localTablesKeys.add(key);
158 exportPolicies.put(key, new ExportPolicyPeerTrackerImpl(policyDatabase, key));
160 this.exportPolicyPeerTrackerMap = exportPolicies.build();
162 LOG.info("RIB Singleton Service {} registered", getIdentifier());
163 //this need to be always the last step
164 this.registration = registerClusterSingletonService(this);
167 public RIBImpl(final ClusterSingletonServiceProvider provider, final RibId ribId, final AsNumber localAs, final BgpId localBgpId, @Nullable final ClusterIdentifier clusterId,
168 final RIBExtensionConsumerContext extensions, final BGPDispatcher dispatcher, final BindingCodecTreeFactory codecFactory,
169 final DOMDataBroker domDataBroker, final List<BgpTableType> localTables, final Map<TablesKey, PathSelectionMode> bestPathSelectionstrategies,
170 final GeneratedClassLoadingStrategy classStrategy, final BgpDeployer.WriteConfiguration configurationWriter) {
171 this(provider, ribId, localAs, localBgpId, clusterId, extensions, dispatcher, codecFactory,
172 domDataBroker, localTables, bestPathSelectionstrategies, classStrategy, null, null, configurationWriter);
175 private void startLocRib(final TablesKey key) {
176 LOG.debug("Creating LocRib table for {}", key);
177 // create locRibWriter for each table
178 final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
180 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
181 table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
182 table.withChild(EMPTY_TABLE_ATTRIBUTES);
184 final NodeIdentifierWithPredicates tableKey = RibSupportUtils.toYangTablesKey(key);
185 final InstanceIdentifierBuilder tableId = YangInstanceIdentifier.builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME));
186 tableId.nodeWithKey(tableKey.getNodeType(), tableKey.getKeyValues());
187 for (final Entry<QName, Object> e : tableKey.getKeyValues().entrySet()) {
188 table.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
191 final ChoiceNode routes = this.ribContextRegistry.getRIBSupportContext(key).getRibSupport().emptyRoutes();
192 table.withChild(routes);
194 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
196 tx.submit().checkedGet();
197 } catch (final TransactionCommitFailedException e1) {
198 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
201 PathSelectionMode pathSelectionStrategy = this.bestPathSelectionStrategies.get(key);
202 if (pathSelectionStrategy == null) {
203 pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy();
206 this.locRibs.add(LocRibWriter.create(this.ribContextRegistry, key, createPeerChain(this), getYangRibId(), this.localAs, getService(),
207 this.exportPolicyPeerTrackerMap.get(key), pathSelectionStrategy, this.renderStats.getLocRibRouteCounter().init(key)));
211 public String toString() {
212 return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
215 protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
216 return toStringHelper;
220 public synchronized void close() throws Exception {
221 if (this.registration != null) {
222 this.registration.close();
223 this.registration = null;
225 if(this.domChain != null) {
226 this.domChain.close();
231 public AsNumber getLocalAs() {
236 public BgpId getBgpIdentifier() {
237 return this.bgpIdentifier;
242 public Set<? extends BgpTableType> getLocalTables() {
243 return this.localTables;
247 public BGPDispatcher getDispatcher() {
248 return this.dispatcher;
252 public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
253 LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
257 public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
258 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
262 public Set<TablesKey> getLocalTablesKeys() {
263 return this.localTablesKeys;
267 public DOMDataTreeChangeService getService() {
268 return (DOMDataTreeChangeService) this.service;
272 public BGPRenderStats getRenderStats() {
273 return this.renderStats;
277 public YangInstanceIdentifier getYangRibId() {
278 return this.yangRibId;
282 public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
283 return this.domDataBroker.createTransactionChain(listener);
287 public RIBExtensionConsumerContext getRibExtensions() {
288 return this.extensions;
292 public RIBSupportContextRegistry getRibSupportContext() {
293 return this.ribContextRegistry;
297 public void onGlobalContextUpdated(final SchemaContext context) {
298 this.codecsRegistry.onSchemaContextUpdated(context);
302 public CodecsRegistry getCodecsRegistry() {
303 return this.codecsRegistry;
307 public Optional<BGPOpenConfigProvider> getOpenConfigProvider() {
308 return Optional.fromNullable(this.openConfigProvider);
312 public ImportPolicyPeerTracker getImportPolicyPeerTracker() {
313 return this.importPolicyPeerTracker;
317 public ExportPolicyPeerTracker getExportPolicyPeerTracker(final TablesKey tablesKey) {
318 return this.exportPolicyPeerTrackerMap.get(tablesKey);
322 public void instantiateServiceInstance() {
323 if(this.configurationWriter != null) {
324 this.configurationWriter.apply();
326 LOG.info("RIB Singleton Service {} instantiated", getIdentifier());
327 LOG.debug("Instantiating RIB table {} at {}", this.ribId , this.yangRibId);
329 final ContainerNode bgpRib = Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
330 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
332 final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
333 new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, this.ribId .getValue()))
334 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, this.ribId .getValue()))
335 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
336 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
337 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
341 final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
343 // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
344 trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
345 trans.put(LogicalDatastoreType.OPERATIONAL, this.yangRibId, ribInstance);
348 trans.submit().checkedGet();
349 } catch (final TransactionCommitFailedException e) {
350 LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
353 LOG.debug("Effective RIB created.");
355 this.localTablesKeys.forEach(this::startLocRib);
356 if (this.configModuleTracker != null) {
357 this.configModuleTracker.onInstanceCreate();
362 public ListenableFuture<Void> closeServiceInstance() {
363 LOG.info("Close RIB Singleton Service {}", getIdentifier());
364 for (final LocRibWriter locRib : this.locRibs) {
367 } catch (final Exception e) {
368 LOG.warn("Could not close LocalRib reference: {}", locRib, e);
372 final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
373 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
374 t.submit().checkedGet();
375 } catch (final TransactionCommitFailedException e) {
376 LOG.warn("Failed to remove RIB instance {} from DS.", getYangRibId(), e);
378 this.renderStats.getLocRibRouteCounter().resetAll();
380 if (this.configModuleTracker != null) {
381 this.configModuleTracker.onInstanceClose();
383 return Futures.immediateFuture(null);
387 public ServiceGroupIdentifier getIdentifier() {
388 return this.serviceGroupIdentifier;
392 public ClusterSingletonServiceRegistration registerClusterSingletonService(final ClusterSingletonService clusterSingletonService) {
393 return this.provider.registerClusterSingletonService(clusterSingletonService);
397 public ServiceGroupIdentifier getRibIServiceGroupIdentifier() {
398 return getIdentifier();