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.CheckedFuture;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import java.util.ArrayList;
18 import java.util.HashSet;
19 import java.util.List;
21 import java.util.Map.Entry;
23 import javax.annotation.Nonnull;
24 import javax.annotation.concurrent.ThreadSafe;
25 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
28 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
29 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
30 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
31 import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
32 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
33 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
34 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
35 import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTreeFactory;
36 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
37 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
38 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
39 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
40 import org.opendaylight.protocol.bgp.mode.api.PathSelectionMode;
41 import org.opendaylight.protocol.bgp.mode.impl.base.BasePathSelectionModeFactory;
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.state.BGPRIBStateImpl;
49 import org.opendaylight.protocol.bgp.rib.impl.stats.rib.impl.BGPRenderStats;
50 import org.opendaylight.protocol.bgp.rib.impl.stats.rib.impl.RIBImplRuntimeMXBeanImpl;
51 import org.opendaylight.protocol.bgp.rib.spi.ExportPolicyPeerTracker;
52 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
53 import org.opendaylight.protocol.bgp.rib.spi.RibSupportUtils;
54 import org.opendaylight.protocol.bgp.rib.spi.util.ClusterSingletonServiceRegistrationHelper;
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 BGPRIBStateImpl implements ClusterSingletonService, RIB, TransactionChainListener,
87 SchemaContextListener, AutoCloseable {
88 private static final Logger LOG = LoggerFactory.getLogger(RIBImpl.class);
89 private static final QName RIB_ID_QNAME = QName.create(Rib.QNAME, "id").intern();
90 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 static final int MAX_REGISTRATION_ATTEMPTS = 10;
92 private static final int SLEEP_TIME = MAX_REGISTRATION_ATTEMPTS;
94 private final BGPDispatcher dispatcher;
95 private final AsNumber localAs;
96 private final BgpId bgpIdentifier;
97 private final Set<BgpTableType> localTables;
98 private final Set<TablesKey> localTablesKeys;
99 private final DOMDataBroker domDataBroker;
100 private final RIBExtensionConsumerContext extensions;
101 private final YangInstanceIdentifier yangRibId;
102 private final RIBSupportContextRegistryImpl ribContextRegistry;
103 private final CodecsRegistryImpl codecsRegistry;
104 private final ServiceGroupIdentifier serviceGroupIdentifier;
105 private final ClusterSingletonServiceProvider provider;
106 private final BgpDeployer.WriteConfiguration configurationWriter;
107 private ClusterSingletonServiceRegistration registration;
108 private final DOMDataBrokerExtension service;
109 private final List<LocRibWriter> locRibs = new ArrayList<>();
110 private final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies;
111 private final ImportPolicyPeerTracker importPolicyPeerTracker;
112 private final RIBImplRuntimeMXBeanImpl renderStats;
113 private final RibId ribId;
114 private final Map<TablesKey, ExportPolicyPeerTracker> exportPolicyPeerTrackerMap;
116 private DOMTransactionChain domChain;
118 public RIBImpl(final ClusterSingletonServiceProvider provider, final RibId ribId, final AsNumber localAs, final BgpId localBgpId,
119 final ClusterIdentifier clusterId, final RIBExtensionConsumerContext extensions, final BGPDispatcher dispatcher,
120 final BindingCodecTreeFactory codecFactory, final DOMDataBroker domDataBroker, final List<BgpTableType> localTables,
121 @Nonnull final Map<TablesKey, PathSelectionMode> bestPathSelectionStrategies, final GeneratedClassLoadingStrategy classStrategy,
122 final BgpDeployer.WriteConfiguration configurationWriter) {
123 super(InstanceIdentifier.create(BgpRib.class).child(Rib.class, new RibKey(Preconditions.checkNotNull(ribId))),
124 localBgpId, localAs);
125 this.localAs = Preconditions.checkNotNull(localAs);
126 this.bgpIdentifier = Preconditions.checkNotNull(localBgpId);
127 this.dispatcher = Preconditions.checkNotNull(dispatcher);
128 this.localTables = ImmutableSet.copyOf(localTables);
129 this.localTablesKeys = new HashSet<>();
130 this.domDataBroker = Preconditions.checkNotNull(domDataBroker);
131 this.service = this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class);
132 this.extensions = Preconditions.checkNotNull(extensions);
133 this.codecsRegistry = CodecsRegistryImpl.create(codecFactory, classStrategy);
134 this.ribContextRegistry = RIBSupportContextRegistryImpl.create(extensions, this.codecsRegistry);
135 final InstanceIdentifierBuilder yangRibIdBuilder = YangInstanceIdentifier.builder().node(BgpRib.QNAME).node(Rib.QNAME);
136 this.yangRibId = yangRibIdBuilder.nodeWithKey(Rib.QNAME, RIB_ID_QNAME, ribId.getValue()).build();
137 this.bestPathSelectionStrategies = Preconditions.checkNotNull(bestPathSelectionStrategies);
138 final ClusterIdentifier cId = (clusterId == null) ? new ClusterIdentifier(localBgpId) : clusterId;
140 final PolicyDatabase policyDatabase = new PolicyDatabase(this.localAs.getValue(), localBgpId, cId);
141 this.importPolicyPeerTracker = new ImportPolicyPeerTrackerImpl(policyDatabase);
142 this.serviceGroupIdentifier = ServiceGroupIdentifier.create(this.ribId.getValue() + "-service-group");
143 Preconditions.checkNotNull(provider, "ClusterSingletonServiceProvider is null");
144 this.provider = provider;
145 this.configurationWriter = configurationWriter;
147 final ImmutableMap.Builder<TablesKey, ExportPolicyPeerTracker> exportPolicies = new ImmutableMap.Builder<>();
148 for (final BgpTableType t : this.localTables) {
149 final TablesKey key = new TablesKey(t.getAfi(), t.getSafi());
150 this.localTablesKeys.add(key);
151 exportPolicies.put(key, new ExportPolicyPeerTrackerImpl(policyDatabase, key));
153 this.exportPolicyPeerTrackerMap = exportPolicies.build();
155 this.renderStats = new RIBImplRuntimeMXBeanImpl(localBgpId, ribId, localAs, cId, this, this.localTablesKeys);
156 LOG.info("RIB Singleton Service {} registered", getIdentifier());
157 //this need to be always the last step
158 this.registration = registerClusterSingletonService(this);
161 private void startLocRib(final TablesKey key) {
162 LOG.debug("Creating LocRib table for {}", key);
163 // create locRibWriter for each table
164 final DOMDataWriteTransaction tx = this.domChain.newWriteOnlyTransaction();
166 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> table = ImmutableNodes.mapEntryBuilder();
167 table.withNodeIdentifier(RibSupportUtils.toYangTablesKey(key));
168 table.withChild(EMPTY_TABLE_ATTRIBUTES);
170 final NodeIdentifierWithPredicates tableKey = RibSupportUtils.toYangTablesKey(key);
171 final InstanceIdentifierBuilder tableId = YangInstanceIdentifier.builder(this.yangRibId.node(LocRib.QNAME).node(Tables.QNAME));
172 tableId.nodeWithKey(tableKey.getNodeType(), tableKey.getKeyValues());
173 for (final Entry<QName, Object> e : tableKey.getKeyValues().entrySet()) {
174 table.withChild(ImmutableNodes.leafNode(e.getKey(), e.getValue()));
177 final ChoiceNode routes = this.ribContextRegistry.getRIBSupportContext(key).getRibSupport().emptyRoutes();
178 table.withChild(routes);
180 tx.put(LogicalDatastoreType.OPERATIONAL, tableId.build(), table.build());
182 tx.submit().checkedGet();
183 } catch (final TransactionCommitFailedException e1) {
184 LOG.error("Failed to initiate LocRIB for key {}", key, e1);
187 PathSelectionMode pathSelectionStrategy = this.bestPathSelectionStrategies.get(key);
188 if (pathSelectionStrategy == null) {
189 pathSelectionStrategy = BasePathSelectionModeFactory.createBestPathSelectionStrategy();
192 final LocRibWriter locRibWriter = LocRibWriter.create(this.ribContextRegistry, key, createPeerChain(this),
193 getYangRibId(), this.localAs, getService(), this.exportPolicyPeerTrackerMap.get(key), pathSelectionStrategy);
194 registerTotalPathCounter(key, locRibWriter);
195 registerTotalPrefixesCounter(key, locRibWriter);
196 this.locRibs.add(locRibWriter);
200 public String toString() {
201 return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
204 protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
205 return toStringHelper;
209 public synchronized void close() throws Exception {
210 if (this.registration != null) {
211 this.registration.close();
212 this.registration = null;
217 public AsNumber getLocalAs() {
222 public BgpId getBgpIdentifier() {
223 return this.bgpIdentifier;
228 public Set<? extends BgpTableType> getLocalTables() {
229 return this.localTables;
233 public BGPDispatcher getDispatcher() {
234 return this.dispatcher;
238 public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction, final Throwable cause) {
239 LOG.error("Broken chain in RIB {} transaction {}", getInstanceIdentifier(), transaction != null ? transaction.getIdentifier() : null, cause);
243 public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
244 LOG.info("RIB {} closed successfully", getInstanceIdentifier());
248 public Set<TablesKey> getLocalTablesKeys() {
249 return this.localTablesKeys;
253 public DOMDataTreeChangeService getService() {
254 return (DOMDataTreeChangeService) this.service;
258 public BGPRenderStats getRenderStats() {
259 return this.renderStats;
263 public YangInstanceIdentifier getYangRibId() {
264 return this.yangRibId;
268 public DOMTransactionChain createPeerChain(final TransactionChainListener listener) {
269 return this.domDataBroker.createTransactionChain(listener);
273 public RIBExtensionConsumerContext getRibExtensions() {
274 return this.extensions;
278 public RIBSupportContextRegistry getRibSupportContext() {
279 return this.ribContextRegistry;
283 public void onGlobalContextUpdated(final SchemaContext context) {
284 this.codecsRegistry.onSchemaContextUpdated(context);
288 public CodecsRegistry getCodecsRegistry() {
289 return this.codecsRegistry;
293 public ImportPolicyPeerTracker getImportPolicyPeerTracker() {
294 return this.importPolicyPeerTracker;
298 public ExportPolicyPeerTracker getExportPolicyPeerTracker(final TablesKey tablesKey) {
299 return this.exportPolicyPeerTrackerMap.get(tablesKey);
303 public void instantiateServiceInstance() {
304 this.domChain = this.domDataBroker.createTransactionChain(this);
305 if(this.configurationWriter != null) {
306 this.configurationWriter.apply();
308 LOG.info("RIB Singleton Service {} instantiated", getIdentifier());
309 LOG.debug("Instantiating RIB table {} at {}", this.ribId , this.yangRibId);
311 final ContainerNode bgpRib = Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(BgpRib.QNAME))
312 .addChild(ImmutableNodes.mapNodeBuilder(Rib.QNAME).build()).build();
314 final MapEntryNode ribInstance = Builders.mapEntryBuilder().withNodeIdentifier(
315 new NodeIdentifierWithPredicates(Rib.QNAME, RIB_ID_QNAME, this.ribId .getValue()))
316 .addChild(ImmutableNodes.leafNode(RIB_ID_QNAME, this.ribId .getValue()))
317 .addChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build())
318 .addChild(Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(LocRib.QNAME))
319 .addChild(ImmutableNodes.mapNodeBuilder(Tables.QNAME).build())
323 final DOMDataWriteTransaction trans = this.domChain.newWriteOnlyTransaction();
325 // merge empty BgpRib + Rib, to make sure the top-level parent structure is present
326 trans.merge(LogicalDatastoreType.OPERATIONAL, YangInstanceIdentifier.builder().node(BgpRib.QNAME).build(), bgpRib);
327 trans.put(LogicalDatastoreType.OPERATIONAL, this.yangRibId, ribInstance);
330 trans.submit().checkedGet();
331 } catch (final TransactionCommitFailedException e) {
332 LOG.error("Failed to initiate RIB {}", this.yangRibId, e);
335 LOG.debug("Effective RIB created.");
337 this.localTablesKeys.forEach(this::startLocRib);
341 public ListenableFuture<Void> closeServiceInstance() {
342 LOG.info("Close RIB Singleton Service {}", getIdentifier());
343 this.locRibs.forEach(LocRibWriter::close);
344 this.locRibs.clear();
346 final DOMDataWriteTransaction t = this.domChain.newWriteOnlyTransaction();
347 t.delete(LogicalDatastoreType.OPERATIONAL, getYangRibId());
348 final CheckedFuture<Void, TransactionCommitFailedException> cleanFuture = t.submit();
350 this.domChain.close();
355 public ServiceGroupIdentifier getIdentifier() {
356 return this.serviceGroupIdentifier;
360 public ClusterSingletonServiceRegistration registerClusterSingletonService(final ClusterSingletonService clusterSingletonService) {
361 return ClusterSingletonServiceRegistrationHelper.registerSingletonService(this.provider, clusterSingletonService, MAX_REGISTRATION_ATTEMPTS,
366 public ServiceGroupIdentifier getRibIServiceGroupIdentifier() {
367 return getIdentifier();