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 static java.util.Objects.requireNonNull;
12 import com.google.common.base.MoreObjects;
13 import com.google.common.base.MoreObjects.ToStringHelper;
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.Futures;
18 import com.google.common.util.concurrent.ListenableFuture;
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.concurrent.GuardedBy;
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.binding.generator.impl.GeneratedClassLoadingStrategy;
40 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
41 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
42 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
43 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
44 import org.opendaylight.protocol.bgp.mode.api.PathSelectionMode;
45 import org.opendaylight.protocol.bgp.mode.impl.base.BasePathSelectionModeFactory;
46 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
47 import org.opendaylight.protocol.bgp.rib.impl.spi.BgpDeployer;
48 import org.opendaylight.protocol.bgp.rib.impl.spi.CodecsRegistry;
49 import org.opendaylight.protocol.bgp.rib.impl.spi.ImportPolicyPeerTracker;
50 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
51 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
52 import org.opendaylight.protocol.bgp.rib.impl.state.BGPRIBStateImpl;
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.yang.binding.InstanceIdentifier;
72 import org.opendaylight.yangtools.yang.common.QName;
73 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
74 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
75 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
76 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
77 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
78 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
79 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
80 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
81 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
82 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
83 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
84 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
85 import org.slf4j.Logger;
86 import org.slf4j.LoggerFactory;
89 public final class RIBImpl extends BGPRIBStateImpl implements ClusterSingletonService, RIB, TransactionChainListener,
90 SchemaContextListener, AutoCloseable {
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 Map<TransactionChain<?, ?>, LocRibWriter> txChainToLocRibWriter = new HashMap<>();
113 private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
114 private final ImportPolicyPeerTracker importPolicyPeerTracker;
115 private final RIBImplRuntimeMXBeanImpl renderStats;
116 private final RibId ribId;
117 private final Map<TablesKey, ExportPolicyPeerTracker> exportPolicyPeerTrackerMap;
119 private DOMTransactionChain domChain;
121 private boolean isServiceInstantiated;
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 BgpDeployer.WriteConfiguration configurationWriter) {
128 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(requireNonNull(ribId))),
129 localBgpId, localAs);
130 this.localAs = requireNonNull(localAs);
131 this.bgpIdentifier = requireNonNull(localBgpId);
132 this.dispatcher = requireNonNull(dispatcher);
133 this.localTables = ImmutableSet.copyOf(localTables);
134 this.localTablesKeys = new HashSet<>();
135 this.domDataBroker = requireNonNull(domDataBroker);
136 this.service = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
137 this.extensions = requireNonNull(extensions);
138 this.codecsRegistry = CodecsRegistryImpl.create(codecFactory, classStrategy);
139 this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
140 final InstanceIdentifierBuilder yangRibIdBuilder = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME);
141 this.yangRibId = yangRibIdBuilder.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
142 this.bestPathSelectionStrategies = requireNonNull(bestPathSelectionStrategies);
143 final ClusterIdentifier cId = clusterId == null ? new ClusterIdentifier(localBgpId) : clusterId;
145 final PolicyDatabase policyDatabase = new PolicyDatabase(this.localAs.getValue(), localBgpId, cId);
146 this.importPolicyPeerTracker = new ImportPolicyPeerTrackerImpl(policyDatabase);
147 this.serviceGroupIdentifier = ServiceGroupIdentifier.create(this.ribId.getValue() + "-service-group");
148 requireNonNull(provider, "ClusterSingletonServiceProvider is null");
149 this.provider = provider;
150 this.configurationWriter = configurationWriter;
152 final ImmutableMap.Builder<TablesKey, ExportPolicyPeerTracker> exportPolicies = new ImmutableMap.Builder<>();
153 for (final BgpTableType t : this.localTables) {
154 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
155 this.localTablesKeys.add(key);
156 exportPolicies.put(key, new ExportPolicyPeerTrackerImpl(policyDatabase, key));
158 this.exportPolicyPeerTrackerMap = exportPolicies.build();
160 this.renderStats = new RIBImplRuntimeMXBeanImpl(localBgpId, ribId, localAs, cId, this, this.localTablesKeys);
161 LOG.info("RIB Singleton Service {} registered, RIB {}", getIdentifier().getValue(), this.ribId.getValue());
162 //this need to be always the last step
163 this.registration = registerClusterSingletonService(this);
166 private void startLocRib(final TablesKey key) {
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);
191 createLocRibWriter(key);
194 private synchronized void createLocRibWriter(final TablesKey key) {
195 LOG.debug("Creating LocRIB writer for key {}", key);
196 final DOMTransactionChain txChain = createPeerChain(this);
197 PathSelectionMode pathSelectionStrategy = this.bestPathSelectionStrategies.get(key);
198 if (pathSelectionStrategy == null) {
199 pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy();
202 final LocRibWriter locRibWriter = LocRibWriter.create(this.ribContextRegistry, key, txChain,
203 getYangRibId(), this.localAs, getService(), this.exportPolicyPeerTrackerMap.get(key), pathSelectionStrategy);
204 registerTotalPathCounter(key, locRibWriter);
205 registerTotalPrefixesCounter(key, locRibWriter);
206 this.txChainToLocRibWriter.put(txChain, locRibWriter);
210 public String toString() {
211 return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
214 protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
215 return toStringHelper;
219 public synchronized void close() throws Exception {
220 if (this.registration != null) {
221 this.registration.close();
222 this.registration = null;
227 public AsNumber getLocalAs() {
232 public BgpId getBgpIdentifier() {
233 return this.bgpIdentifier;
238 public Set<? extends BgpTableType> getLocalTables() {
239 return this.localTables;
243 public BGPDispatcher getDispatcher() {
244 return this.dispatcher;
248 public synchronized void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
249 LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
250 if (this.txChainToLocRibWriter.containsKey(chain)) {
251 final LocRibWriter locRibWriter = this.txChainToLocRibWriter.remove(chain);
252 final DOMTransactionChain newChain = createPeerChain(this);
253 locRibWriter.restart(newChain);
254 this.txChainToLocRibWriter.put(newChain, locRibWriter);
259 public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
260 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
264 public Set<TablesKey> getLocalTablesKeys() {
265 return this.localTablesKeys;
269 public DOMDataTreeChangeService getService() {
270 return (DOMDataTreeChangeService) this.service;
274 public BGPRenderStats getRenderStats() {
275 return this.renderStats;
279 public YangInstanceIdentifier getYangRibId() {
280 return this.yangRibId;
284 public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
285 return this.domDataBroker.createTransactionChain(listener);
289 public RIBExtensionConsumerContext getRibExtensions() {
290 return this.extensions;
294 public RIBSupportContextRegistry getRibSupportContext() {
295 return this.ribContextRegistry;
299 public void onGlobalContextUpdated(final SchemaContext context) {
300 this.codecsRegistry.onSchemaContextUpdated(context);
304 public CodecsRegistry getCodecsRegistry() {
305 return this.codecsRegistry;
309 public ImportPolicyPeerTracker getImportPolicyPeerTracker() {
310 return this.importPolicyPeerTracker;
314 public ExportPolicyPeerTracker getExportPolicyPeerTracker(final TablesKey tablesKey) {
315 return this.exportPolicyPeerTrackerMap.get(tablesKey);
319 public synchronized void instantiateServiceInstance() {
320 this.isServiceInstantiated = true;
321 this.domChain = this.domDataBroker.createTransactionChain(this);
322 if(this.configurationWriter != null) {
323 this.configurationWriter.apply();
325 LOG.info("RIB Singleton Service {} instantiated, RIB {}", getIdentifier().getValue(), this.ribId.getValue());
326 LOG.debug("Instantiating RIB table {} at {}", this.ribId , this.yangRibId);
328 final ContainerNode bgpRib = Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
329 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
331 final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
332 new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, this.ribId .getValue()))
333 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, this.ribId .getValue()))
334 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
335 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
336 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
340 final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
342 // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
343 trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
344 trans.put(LogicalDatastoreType.OPERATIONAL, this.yangRibId, ribInstance);
347 trans.submit().checkedGet();
348 } catch (final TransactionCommitFailedException e) {
349 LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
352 LOG.debug("Effective RIB created.");
354 this.localTablesKeys.forEach(this::startLocRib);
358 public synchronized ListenableFuture<Void> closeServiceInstance() {
359 if(!this.isServiceInstantiated) {
360 LOG.trace("RIB Singleton Service {} already closed, RIB {}", getIdentifier().getValue(),
361 this.ribId.getValue());
362 return Futures.immediateFuture(null);
364 LOG.info("Close RIB Singleton Service {}, RIB {}", getIdentifier().getValue(), this.ribId.getValue());
365 this.isServiceInstantiated = false;
367 this.txChainToLocRibWriter.values().forEach(LocRibWriter::close);
368 this.txChainToLocRibWriter.clear();
370 final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
371 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
372 final CheckedFuture<Void, TransactionCommitFailedException> cleanFuture = t.submit();
374 this.domChain.close();
379 public ServiceGroupIdentifier getIdentifier() {
380 return this.serviceGroupIdentifier;
384 public ClusterSingletonServiceRegistration registerClusterSingletonService(final ClusterSingletonService clusterSingletonService) {
385 return ClusterSingletonServiceRegistrationHelper.registerSingletonService(this.provider, clusterSingletonService, MAX_REGISTRATION_ATTEMPTS,
390 public ServiceGroupIdentifier getRibIServiceGroupIdentifier() {
391 return getIdentifier();