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.CheckedFuture;
17 import com.google.common.util.concurrent.ListenableFuture;
18 import java.util.ArrayList;
19 import java.util.HashSet;
20 import java.util.List;
22 import java.util.Map.Entry;
24 import javax.annotation.Nonnull;
25 import javax.annotation.Nullable;
26 import javax.annotation.concurrent.ThreadSafe;
27 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
28 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
29 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
30 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
31 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
32 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
33 import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
34 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
35 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
36 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
37 import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTreeFactory;
38 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
39 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
40 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
41 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
42 import org.opendaylight.protocol.bgp.mode.api.PathSelectionMode;
43 import org.opendaylight.protocol.bgp.mode.impl.base.BasePathSelectionModeFactory;
44 import org.opendaylight.protocol.bgp.openconfig.spi.BGPConfigModuleTracker;
45 import org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenConfigProvider;
46 import org.opendaylight.protocol.bgp.rib.DefaultRibReference;
47 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
48 import org.opendaylight.protocol.bgp.rib.impl.spi.BgpDeployer;
49 import org.opendaylight.protocol.bgp.rib.impl.spi.CodecsRegistry;
50 import org.opendaylight.protocol.bgp.rib.impl.spi.ImportPolicyPeerTracker;
51 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
52 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
53 import org.opendaylight.protocol.bgp.rib.impl.stats.rib.impl.BGPRenderStats;
54 import org.opendaylight.protocol.bgp.rib.impl.stats.rib.impl.RIBImplRuntimeMXBeanImpl;
55 import org.opendaylight.protocol.bgp.rib.spi.ExportPolicyPeerTracker;
56 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
57 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
58 import org.opendaylight.protocol.bgp.rib.spi.util.ClusterSingletonServiceRegistrationHelper;
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);
94 private static final int MAX_REGISTRATION_ATTEMPTS = 10;
95 private static final int SLEEP_TIME = MAX_REGISTRATION_ATTEMPTS;
97 private final BGPDispatcher dispatcher;
98 private final AsNumber localAs;
99 private final BgpId bgpIdentifier;
100 private final Set<BgpTableType> localTables;
101 private final Set<TablesKey> localTablesKeys;
102 private final DOMDataBroker domDataBroker;
103 private final RIBExtensionConsumerContext extensions;
104 private final YangInstanceIdentifier yangRibId;
105 private final RIBSupportContextRegistryImpl ribContextRegistry;
106 private final CodecsRegistryImpl codecsRegistry;
107 private final ServiceGroupIdentifier serviceGroupIdentifier;
108 private final ClusterSingletonServiceProvider provider;
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 Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
116 private final ImportPolicyPeerTracker importPolicyPeerTracker;
117 private final RIBImplRuntimeMXBeanImpl renderStats;
118 private final RibId ribId;
119 private final Map<TablesKey, ExportPolicyPeerTracker> exportPolicyPeerTrackerMap;
121 private DOMTransactionChain domChain;
123 public RIBImpl(final ClusterSingletonServiceProvider provider, final RibId ribId, final AsNumber localAs, final BgpId localBgpId,
124 final ClusterIdentifier clusterId, final RIBExtensionConsumerContext extensions, final BGPDispatcher dispatcher,
125 final BindingCodecTreeFactory codecFactory, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
126 @Nonnull final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies, final GeneratedClassLoadingStrategy classStrategy,
127 final BGPConfigModuleTracker moduleTracker, final BGPOpenConfigProvider openConfigProvider,
128 final BgpDeployer.WriteConfiguration configurationWriter) {
130 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId))));
131 this.localAs = Preconditions.checkNotNull(localAs);
132 this.bgpIdentifier = Preconditions.checkNotNull(localBgpId);
133 this.dispatcher = Preconditions.checkNotNull(dispatcher);
134 this.localTables = ImmutableSet.copyOf(localTables);
135 this.localTablesKeys = new HashSet<>();
136 this.domDataBroker = Preconditions.checkNotNull(domDataBroker);
137 this.service = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
138 this.extensions = Preconditions.checkNotNull(extensions);
139 this.codecsRegistry = CodecsRegistryImpl.create(codecFactory, classStrategy);
140 this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
141 final InstanceIdentifierBuilder yangRibIdBuilder = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME);
142 this.yangRibId = yangRibIdBuilder.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
143 this.configModuleTracker = moduleTracker;
144 this.openConfigProvider = openConfigProvider;
145 this.bestPathSelectionStrategies = Preconditions.checkNotNull(bestPathSelectionStrategies);
146 final ClusterIdentifier cId = (clusterId == null) ? new ClusterIdentifier(localBgpId) : clusterId;
147 this.renderStats = new RIBImplRuntimeMXBeanImpl(localBgpId, ribId, localAs, cId);
149 final PolicyDatabase policyDatabase = new PolicyDatabase(this.localAs.getValue(), localBgpId, cId);
150 this.importPolicyPeerTracker = new ImportPolicyPeerTrackerImpl(policyDatabase);
151 this.serviceGroupIdentifier = ServiceGroupIdentifier.create(this.ribId.getValue() + "-service-group");
152 Preconditions.checkNotNull(provider, "ClusterSingletonServiceProvider is null");
153 this.provider = provider;
154 this.configurationWriter = configurationWriter;
156 final ImmutableMap.Builder<TablesKey, ExportPolicyPeerTracker> exportPolicies = new ImmutableMap.Builder<>();
157 for (final BgpTableType t : this.localTables) {
158 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
159 this.localTablesKeys.add(key);
160 exportPolicies.put(key, new ExportPolicyPeerTrackerImpl(policyDatabase, key));
162 this.exportPolicyPeerTrackerMap = exportPolicies.build();
164 LOG.info("RIB Singleton Service {} registered", getIdentifier());
165 //this need to be always the last step
166 this.registration = registerClusterSingletonService(this);
169 public RIBImpl(final ClusterSingletonServiceProvider provider, final RibId ribId, final AsNumber localAs, final BgpId localBgpId, @Nullable final ClusterIdentifier clusterId,
170 final RIBExtensionConsumerContext extensions, final BGPDispatcher dispatcher, final BindingCodecTreeFactory codecFactory,
171 final DOMDataBroker domDataBroker, final List<BgpTableType> localTables, final Map<TablesKey, PathSelectionMode> bestPathSelectionstrategies,
172 final GeneratedClassLoadingStrategy classStrategy, final BgpDeployer.WriteConfiguration configurationWriter) {
173 this(provider, ribId, localAs, localBgpId, clusterId, extensions, dispatcher, codecFactory,
174 domDataBroker, localTables, bestPathSelectionstrategies, classStrategy, null, null, configurationWriter);
177 private void startLocRib(final TablesKey key) {
178 LOG.debug("Creating LocRib table for {}", key);
179 // create locRibWriter for each table
180 final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
182 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
183 table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
184 table.withChild(EMPTY_TABLE_ATTRIBUTES);
186 final NodeIdentifierWithPredicates tableKey = RibSupportUtils.toYangTablesKey(key);
187 final InstanceIdentifierBuilder tableId = YangInstanceIdentifier.builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME));
188 tableId.nodeWithKey(tableKey.getNodeType(), tableKey.getKeyValues());
189 for (final Entry<QName, Object> e : tableKey.getKeyValues().entrySet()) {
190 table.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
193 final ChoiceNode routes = this.ribContextRegistry.getRIBSupportContext(key).getRibSupport().emptyRoutes();
194 table.withChild(routes);
196 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
198 tx.submit().checkedGet();
199 } catch (final TransactionCommitFailedException e1) {
200 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
203 PathSelectionMode pathSelectionStrategy = this.bestPathSelectionStrategies.get(key);
204 if (pathSelectionStrategy == null) {
205 pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy();
208 this.locRibs.add(LocRibWriter.create(this.ribContextRegistry, key, createPeerChain(this), getYangRibId(), this.localAs, getService(),
209 this.exportPolicyPeerTrackerMap.get(key), pathSelectionStrategy, this.renderStats.getLocRibRouteCounter().init(key)));
213 public String toString() {
214 return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
217 protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
218 return toStringHelper;
222 public synchronized void close() throws Exception {
223 if (this.registration != null) {
224 this.registration.close();
225 this.registration = null;
230 public AsNumber getLocalAs() {
235 public BgpId getBgpIdentifier() {
236 return this.bgpIdentifier;
241 public Set<? extends BgpTableType> getLocalTables() {
242 return this.localTables;
246 public BGPDispatcher getDispatcher() {
247 return this.dispatcher;
251 public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
252 LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
256 public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
257 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
261 public Set<TablesKey> getLocalTablesKeys() {
262 return this.localTablesKeys;
266 public DOMDataTreeChangeService getService() {
267 return (DOMDataTreeChangeService) this.service;
271 public BGPRenderStats getRenderStats() {
272 return this.renderStats;
276 public YangInstanceIdentifier getYangRibId() {
277 return this.yangRibId;
281 public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
282 return this.domDataBroker.createTransactionChain(listener);
286 public RIBExtensionConsumerContext getRibExtensions() {
287 return this.extensions;
291 public RIBSupportContextRegistry getRibSupportContext() {
292 return this.ribContextRegistry;
296 public void onGlobalContextUpdated(final SchemaContext context) {
297 this.codecsRegistry.onSchemaContextUpdated(context);
301 public CodecsRegistry getCodecsRegistry() {
302 return this.codecsRegistry;
306 public Optional<BGPOpenConfigProvider> getOpenConfigProvider() {
307 return Optional.fromNullable(this.openConfigProvider);
311 public ImportPolicyPeerTracker getImportPolicyPeerTracker() {
312 return this.importPolicyPeerTracker;
316 public ExportPolicyPeerTracker getExportPolicyPeerTracker(final TablesKey tablesKey) {
317 return this.exportPolicyPeerTrackerMap.get(tablesKey);
321 public void instantiateServiceInstance() {
322 this.domChain = this.domDataBroker.createTransactionChain(this);
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 this.locRibs.forEach(LocRibWriter::close);
365 this.locRibs.clear();
367 this.renderStats.getLocRibRouteCounter().resetAll();
369 if (this.configModuleTracker != null) {
370 this.configModuleTracker.onInstanceClose();
373 final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
374 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
375 final CheckedFuture<Void, TransactionCommitFailedException> cleanFuture = t.submit();
377 this.domChain.close();
383 public ServiceGroupIdentifier getIdentifier() {
384 return this.serviceGroupIdentifier;
388 public ClusterSingletonServiceRegistration registerClusterSingletonService(final ClusterSingletonService clusterSingletonService) {
389 return ClusterSingletonServiceRegistrationHelper.registerSingletonService(this.provider, clusterSingletonService, MAX_REGISTRATION_ATTEMPTS,
394 public ServiceGroupIdentifier getRibIServiceGroupIdentifier() {
395 return getIdentifier();