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.ImmutableMap;
14 import com.google.common.collect.ImmutableSet;
15 import com.google.common.util.concurrent.Futures;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import java.util.ArrayList;
18 import java.util.HashMap;
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.concurrent.ThreadSafe;
26 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
27 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
28 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
29 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
30 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
31 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
32 import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
33 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
34 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
35 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
36 import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTreeFactory;
37 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
38 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
39 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
40 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
41 import org.opendaylight.protocol.bgp.mode.api.PathSelectionMode;
42 import org.opendaylight.protocol.bgp.mode.impl.base.BasePathSelectionModeFactory;
43 import org.opendaylight.protocol.bgp.rib.DefaultRibReference;
44 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
45 import org.opendaylight.protocol.bgp.rib.impl.spi.BgpDeployer;
46 import org.opendaylight.protocol.bgp.rib.impl.spi.CodecsRegistry;
47 import org.opendaylight.protocol.bgp.rib.impl.spi.ImportPolicyPeerTracker;
48 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
49 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
50 import org.opendaylight.protocol.bgp.rib.impl.stats.rib.impl.BGPRenderStats;
51 import org.opendaylight.protocol.bgp.rib.impl.stats.rib.impl.RIBImplRuntimeMXBeanImpl;
52 import org.opendaylight.protocol.bgp.rib.spi.ExportPolicyPeerTracker;
53 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
54 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.BgpRib;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.RibId;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.Rib;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibKey;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.LocRib;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.Peer;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.BgpId;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier;
67 import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
68 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
69 import org.opendaylight.yangtools.yang.common.QName;
70 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
71 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
72 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
73 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
74 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
75 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
76 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
77 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
78 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
79 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
80 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
81 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
82 import org.slf4j.Logger;
83 import org.slf4j.LoggerFactory;
86 public final class RIBImpl extends DefaultRibReference implements ClusterSingletonService, AutoCloseable, RIB, TransactionChainListener, SchemaContextListener {
87 private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
88 private static final QName RIB_ID_QNAME = QName.create(Rib.QNAME, "id").intern();
89 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);
91 private final BGPDispatcher dispatcher;
92 private final DOMTransactionChain domChain;
93 private final AsNumber localAs;
94 private final BgpId bgpIdentifier;
95 private final Set<BgpTableType> localTables;
96 private final Set<TablesKey> localTablesKeys;
97 private final DOMDataBroker domDataBroker;
98 private final RIBExtensionConsumerContext extensions;
99 private final YangInstanceIdentifier yangRibId;
100 private final RIBSupportContextRegistryImpl ribContextRegistry;
101 private final CodecsRegistryImpl codecsRegistry;
102 private final ServiceGroupIdentifier serviceGroupIdentifier;
103 private final ClusterSingletonServiceProvider provider;
104 private final BgpDeployer.WriteConfiguration configurationWriter;
105 private ClusterSingletonServiceRegistration registration;
106 private final DOMDataBrokerExtension service;
107 private final List<LocRibWriter> locRibs = new ArrayList<>();
108 private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
109 private final ImportPolicyPeerTracker importPolicyPeerTracker;
110 private final RIBImplRuntimeMXBeanImpl renderStats;
111 private final RibId ribId;
112 private final Map<TablesKey, ExportPolicyPeerTracker> exportPolicyPeerTrackerMap;
114 public RIBImpl(final ClusterSingletonServiceProvider provider, final RibId ribId, final AsNumber localAs, final BgpId localBgpId,
115 final ClusterIdentifier clusterId, final RIBExtensionConsumerContext extensions, final BGPDispatcher dispatcher,
116 final BindingCodecTreeFactory codecFactory, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
117 @Nonnull final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies, final GeneratedClassLoadingStrategy classStrategy,
118 final BgpDeployer.WriteConfiguration configurationWriter) {
120 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId))));
121 this.domChain = domDataBroker.createTransactionChain(this);
122 this.localAs = Preconditions.checkNotNull(localAs);
123 this.bgpIdentifier = Preconditions.checkNotNull(localBgpId);
124 this.dispatcher = Preconditions.checkNotNull(dispatcher);
125 this.localTables = ImmutableSet.copyOf(localTables);
126 this.localTablesKeys = new HashSet<>();
127 this.domDataBroker = Preconditions.checkNotNull(domDataBroker);
128 this.service = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
129 this.extensions = Preconditions.checkNotNull(extensions);
130 this.codecsRegistry = CodecsRegistryImpl.create(codecFactory, classStrategy);
131 this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
132 final InstanceIdentifierBuilder yangRibIdBuilder = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME);
133 this.yangRibId = yangRibIdBuilder.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
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 final PolicyDatabase policyDatabase = new PolicyDatabase(this.localAs.getValue(), localBgpId, cId);
139 this.importPolicyPeerTracker = new ImportPolicyPeerTrackerImpl(policyDatabase);
140 this.serviceGroupIdentifier = ServiceGroupIdentifier.create(this.ribId.getValue() + "-service-group");
141 Preconditions.checkNotNull(provider, "ClusterSingletonServiceProvider is null");
142 this.provider = provider;
143 this.configurationWriter = configurationWriter;
145 final ImmutableMap.Builder<TablesKey, ExportPolicyPeerTracker> exportPolicies = new ImmutableMap.Builder<>();
146 for (final BgpTableType t : this.localTables) {
147 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
148 this.localTablesKeys.add(key);
149 exportPolicies.put(key, new ExportPolicyPeerTrackerImpl(policyDatabase, key));
151 this.exportPolicyPeerTrackerMap = exportPolicies.build();
153 LOG.info("RIB Singleton Service {} registered", getIdentifier());
154 //this need to be always the last step
155 this.registration = registerClusterSingletonService(this);
158 private void startLocRib(final TablesKey key) {
159 LOG.debug("Creating LocRib table for {}", key);
160 // create locRibWriter for each table
161 final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
163 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
164 table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
165 table.withChild(EMPTY_TABLE_ATTRIBUTES);
167 final NodeIdentifierWithPredicates tableKey = RibSupportUtils.toYangTablesKey(key);
168 final InstanceIdentifierBuilder tableId = YangInstanceIdentifier.builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME));
169 tableId.nodeWithKey(tableKey.getNodeType(), tableKey.getKeyValues());
170 for (final Entry<QName, Object> e : tableKey.getKeyValues().entrySet()) {
171 table.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
174 final ChoiceNode routes = this.ribContextRegistry.getRIBSupportContext(key).getRibSupport().emptyRoutes();
175 table.withChild(routes);
177 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
179 tx.submit().checkedGet();
180 } catch (final TransactionCommitFailedException e1) {
181 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
184 PathSelectionMode pathSelectionStrategy = this.bestPathSelectionStrategies.get(key);
185 if (pathSelectionStrategy == null) {
186 pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy();
189 this.locRibs.add(LocRibWriter.create(this.ribContextRegistry, key, createPeerChain(this), getYangRibId(), this.localAs, getService(),
190 this.exportPolicyPeerTrackerMap.get(key), pathSelectionStrategy, this.renderStats.getLocRibRouteCounter().init(key)));
194 public String toString() {
195 return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
198 protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
199 return toStringHelper;
203 public synchronized void close() throws Exception {
204 if (this.registration != null) {
205 this.registration.close();
206 this.registration = null;
208 if(this.domChain != null) {
209 this.domChain.close();
214 public AsNumber getLocalAs() {
219 public BgpId getBgpIdentifier() {
220 return this.bgpIdentifier;
225 public Set<? extends BgpTableType> getLocalTables() {
226 return this.localTables;
230 public BGPDispatcher getDispatcher() {
231 return this.dispatcher;
235 public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
236 LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
240 public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
241 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
245 public Set<TablesKey> getLocalTablesKeys() {
246 return this.localTablesKeys;
250 public DOMDataTreeChangeService getService() {
251 return (DOMDataTreeChangeService) this.service;
255 public BGPRenderStats getRenderStats() {
256 return this.renderStats;
260 public YangInstanceIdentifier getYangRibId() {
261 return this.yangRibId;
265 public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
266 return this.domDataBroker.createTransactionChain(listener);
270 public RIBExtensionConsumerContext getRibExtensions() {
271 return this.extensions;
275 public RIBSupportContextRegistry getRibSupportContext() {
276 return this.ribContextRegistry;
280 public void onGlobalContextUpdated(final SchemaContext context) {
281 this.codecsRegistry.onSchemaContextUpdated(context);
285 public CodecsRegistry getCodecsRegistry() {
286 return this.codecsRegistry;
290 public ImportPolicyPeerTracker getImportPolicyPeerTracker() {
291 return this.importPolicyPeerTracker;
295 public ExportPolicyPeerTracker getExportPolicyPeerTracker(final TablesKey tablesKey) {
296 return this.exportPolicyPeerTrackerMap.get(tablesKey);
300 public void instantiateServiceInstance() {
301 if(this.configurationWriter != null) {
302 this.configurationWriter.apply();
304 LOG.info("RIB Singleton Service {} instantiated", getIdentifier());
305 LOG.debug("Instantiating RIB table {} at {}", this.ribId , this.yangRibId);
307 final ContainerNode bgpRib = Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
308 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
310 final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
311 new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, this.ribId .getValue()))
312 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, this.ribId .getValue()))
313 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
314 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
315 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
319 final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
321 // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
322 trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
323 trans.put(LogicalDatastoreType.OPERATIONAL, this.yangRibId, ribInstance);
326 trans.submit().checkedGet();
327 } catch (final TransactionCommitFailedException e) {
328 LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
331 LOG.debug("Effective RIB created.");
333 this.localTablesKeys.forEach(this::startLocRib);
337 public ListenableFuture<Void> closeServiceInstance() {
338 LOG.info("Close RIB Singleton Service {}", getIdentifier());
339 for (final LocRibWriter locRib : this.locRibs) {
342 } catch (final Exception e) {
343 LOG.warn("Could not close LocalRib reference: {}", locRib, e);
347 final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
348 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
349 t.submit().checkedGet();
350 } catch (final TransactionCommitFailedException e) {
351 LOG.warn("Failed to remove RIB instance {} from DS.", getYangRibId(), e);
353 this.renderStats.getLocRibRouteCounter().resetAll();
355 return Futures.immediateFuture(null);
359 public ServiceGroupIdentifier getIdentifier() {
360 return this.serviceGroupIdentifier;
364 public ClusterSingletonServiceRegistration registerClusterSingletonService(final ClusterSingletonService clusterSingletonService) {
365 return this.provider.registerClusterSingletonService(clusterSingletonService);
369 public ServiceGroupIdentifier getRibIServiceGroupIdentifier() {
370 return getIdentifier();